RRSIG validation back to the root
This commit is contained in:
BIN
Kjqmt7v.csr
Normal file
BIN
Kjqmt7v.csr
Normal file
Binary file not shown.
38
README.md
38
README.md
@@ -20,16 +20,28 @@ ground up.
|
||||
|
||||
# Status:
|
||||
|
||||
WARNING!!! Under active development!
|
||||
|
||||
The client now supports timeouts (thanks mio!). Currently hardcoded to 5 seconds,
|
||||
I'll make this configurable if people ask for that, but this allows me to move on.
|
||||
Using the client should be safe. The client is currently hardcoded to a 5 second,
|
||||
timeout. I'll make this configurable if people ask for that, but this allows me
|
||||
to move on. Please send feedback! It currently does not cache responses, if
|
||||
this is a feature you'd like earlier rather than later, post a request. The
|
||||
validation of DNSSec is complete, but negative responses are not yet.
|
||||
The plan is to support NSEC3 primarily, but allow NSEC records to be validated.
|
||||
|
||||
The server code is complete, the daemon supports IPv4 and IPv6, UDP and TCP.
|
||||
There currently is no way to limit TCP and AXFR operations, so it is still not
|
||||
recommended to put into production as TCP can be used to DOS the service.
|
||||
Master file parsing is complete and supported. There is currently no forking
|
||||
option, and the server is not yet threaded.
|
||||
option, and the server is not yet threaded. There is still a lot of work to do
|
||||
before a server can be trusted with this externally. Running it behind a firewall
|
||||
on a private network would be safe.
|
||||
|
||||
## DNSSec status
|
||||
|
||||
Currently the root key is hardcoded into the system. This gives validation of
|
||||
DNSKEY and DS records back to the root. NSEC and NSEC3 are not yet implemented.
|
||||
Because caching is not yet enabled, it has been noticed that some DNS servers
|
||||
appear to rate limit the connections, validating RRSIG records back to the root
|
||||
can require a significant number of additional queries for those records.
|
||||
|
||||
## RFC's implemented
|
||||
|
||||
@@ -42,6 +54,15 @@ option, and the server is not yet threaded.
|
||||
### Update operations
|
||||
- [RFC 2136](https://tools.ietf.org/html/rfc2136): Dynamic Update
|
||||
|
||||
### Secure DNS operations
|
||||
- [RFC 3007](https://tools.ietf.org/html/rfc3007): Secure Dynamic Update
|
||||
- [RFC 4034](https://tools.ietf.org/html/rfc4034): DNSSEC Resource Records
|
||||
- [RFC 4035](https://tools.ietf.org/html/rfc4035): Protocol Modifications for DNSSEC
|
||||
- [RFC 4509](https://tools.ietf.org/html/rfc4509): SHA-256 in DNSSEC Delegation Signer
|
||||
- [RFC 5702](https://tools.ietf.org/html/rfc5702): SHA-2 Algorithms with RSA in DNSKEY and RRSIG for DNSSEC
|
||||
- [RFC 6840](https://tools.ietf.org/html/rfc6840): Clarifications and Implementation Notes for DNSSEC
|
||||
- [RFC 6944](https://tools.ietf.org/html/rfc6944): DNSKEY Algorithm Implementation Status
|
||||
|
||||
## RFC's in progress or not yet implemented
|
||||
|
||||
### Basic operations
|
||||
@@ -55,14 +76,7 @@ option, and the server is not yet threaded.
|
||||
- [Long-Lived Queries](http://tools.ietf.org/html/draft-sekar-dns-llq-01): Notify with bells
|
||||
|
||||
### Secure DNS operations
|
||||
- [RFC 3007](https://tools.ietf.org/html/rfc3007): Secure Dynamic Update
|
||||
- [RFC 4034](https://tools.ietf.org/html/rfc4034): DNSSEC Resource Records
|
||||
- [RFC 4035](https://tools.ietf.org/html/rfc4035): Protocol Modifications for DNSSEC
|
||||
- [RFC 4509](https://tools.ietf.org/html/rfc4509): SHA-256 in DNSSEC Delegation Signer
|
||||
- [RFC 5155](https://tools.ietf.org/html/rfc5155): DNSSEC Hashed Authenticated Denial of Existence
|
||||
- [RFC 5702](https://tools.ietf.org/html/rfc5702): SHA-2 Algorithms with RSA in DNSKEY and RRSIG for DNSSEC
|
||||
- [RFC 6840](https://tools.ietf.org/html/rfc6840): Clarifications and Implementation Notes for DNSSEC
|
||||
- [RFC 6944](https://tools.ietf.org/html/rfc6944): DNSKEY Algorithm Implementation Status
|
||||
- [RFC 6975](https://tools.ietf.org/html/rfc6975): Signaling Cryptographic Algorithm Understanding
|
||||
- [DNSCrypt](https://dnscrypt.org): Trusted DNS queries
|
||||
- [S/MIME](https://tools.ietf.org/html/draft-ietf-dane-smime-09): Domain Names For S/MIME
|
||||
|
3
root_key.sh
Executable file
3
root_key.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
openssl req -text -noout -verify -in Kjqmt7v.csr -inform DER -pubkey -out src/rr/dnssec/Kjqmt7v.pem
|
54
src/rr/dnssec/Kjqmt7v.pem
Normal file
54
src/rr/dnssec/Kjqmt7v.pem
Normal file
@@ -0,0 +1,54 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqAAgqVVmukLohruATNqE
|
||||
5H71bb167GEmFVUs7JBtIRbQ7yBwKMUVVBRN/q/nx8uPAF3RgjQTOsBxCoEYLOH9
|
||||
FK0ig7yDQ1+d8vYxMlGTGhdt8NpR5U9C5gSGDfs1lYAlD1WcxUPE/9Ucvj3oz9Bn
|
||||
GSN/n8R+5ynaBoNfpFLoJemhjrwuy89WNHRlLDPPVqkDO8312XMSF5fsgIkEG24D
|
||||
obctCnNbmE4DaHMJMyMk8nwtuoXp2xXoOgFDOC6XSwYhwY5iXs7JB1d9nnut6VJB
|
||||
qB676KkB1NMnbkCxFMCi5vw40ZwuaqsCZEsoE/V1/CFgHg3uSc2e6WpDED5STWKH
|
||||
PQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
Certificate Request:
|
||||
Data:
|
||||
Version: 0 (0x0)
|
||||
Subject: O=ICANN, OU=IANA, CN=Root Zone KSK 2010-06-16T21:19:24+00:00/1.3.6.1.4.1.1000.53=. IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:a8:00:20:a9:55:66:ba:42:e8:86:bb:80:4c:da:
|
||||
84:e4:7e:f5:6d:bd:7a:ec:61:26:15:55:2c:ec:90:
|
||||
6d:21:16:d0:ef:20:70:28:c5:15:54:14:4d:fe:af:
|
||||
e7:c7:cb:8f:00:5d:d1:82:34:13:3a:c0:71:0a:81:
|
||||
18:2c:e1:fd:14:ad:22:83:bc:83:43:5f:9d:f2:f6:
|
||||
31:32:51:93:1a:17:6d:f0:da:51:e5:4f:42:e6:04:
|
||||
86:0d:fb:35:95:80:25:0f:55:9c:c5:43:c4:ff:d5:
|
||||
1c:be:3d:e8:cf:d0:67:19:23:7f:9f:c4:7e:e7:29:
|
||||
da:06:83:5f:a4:52:e8:25:e9:a1:8e:bc:2e:cb:cf:
|
||||
56:34:74:65:2c:33:cf:56:a9:03:3b:cd:f5:d9:73:
|
||||
12:17:97:ec:80:89:04:1b:6e:03:a1:b7:2d:0a:73:
|
||||
5b:98:4e:03:68:73:09:33:23:24:f2:7c:2d:ba:85:
|
||||
e9:db:15:e8:3a:01:43:38:2e:97:4b:06:21:c1:8e:
|
||||
62:5e:ce:c9:07:57:7d:9e:7b:ad:e9:52:41:a8:1e:
|
||||
bb:e8:a9:01:d4:d3:27:6e:40:b1:14:c0:a2:e6:fc:
|
||||
38:d1:9c:2e:6a:ab:02:64:4b:28:13:f5:75:fc:21:
|
||||
60:1e:0d:ee:49:cd:9e:e9:6a:43:10:3e:52:4d:62:
|
||||
87:3d
|
||||
Exponent: 65537 (0x10001)
|
||||
Attributes:
|
||||
a0:00
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
10:92:6a:79:8f:e9:e4:90:86:8c:d0:51:ac:2d:c9:9f:53:d3:
|
||||
3a:79:e9:15:e8:ca:26:de:08:bd:d2:cd:83:da:ac:d3:e6:bc:
|
||||
54:8b:f9:09:d9:27:b1:6a:ec:fa:b4:7a:4a:f6:97:80:a4:25:
|
||||
80:b6:55:b2:1c:6a:a7:8f:5d:21:a8:57:ad:2e:bd:c9:37:50:
|
||||
70:b7:8b:e0:1b:60:ed:a4:83:0d:d4:d6:13:0f:c9:cb:0a:8f:
|
||||
76:80:eb:23:6f:01:0f:ba:09:20:2b:79:57:e1:18:8f:9a:dc:
|
||||
72:18:6d:76:84:e7:71:72:f1:49:d7:ac:15:2a:51:27:e9:b4:
|
||||
cd:47:ae:18:36:21:fc:88:d6:78:1e:3d:95:eb:81:d4:ad:24:
|
||||
f7:cc:87:d0:73:91:41:f2:44:cd:a3:35:20:0a:07:a4:f0:de:
|
||||
10:04:de:24:b7:9e:1d:1c:24:0a:ee:ca:71:da:ff:2c:f6:4f:
|
||||
c3:f8:0f:57:6d:33:cb:8b:c1:45:73:8f:bb:f9:4c:71:0f:80:
|
||||
c9:b8:15:51:51:17:03:fb:9b:b2:ea:ec:ae:31:a3:ce:0e:7b:
|
||||
c9:d6:ac:65:b9:ec:8e:90:c8:94:e3:37:30:eb:fc:7f:cf:3a:
|
||||
fd:59:7a:d7:7c:9e:0e:01:79:4e:52:0b:78:00:6f:fd:08:eb:
|
||||
8c:56:1c:8f
|
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
use openssl::crypto::pkey::{PKey, Role};
|
||||
use openssl::crypto::rsa::RSA;
|
||||
use openssl::crypto::hash;
|
||||
use openssl::bn::BigNum;
|
||||
|
||||
use ::rr::dnssec::DigestType;
|
||||
|
@@ -18,9 +18,11 @@ mod digest_type;
|
||||
mod nsec3;
|
||||
mod signer;
|
||||
mod supported_algorithm;
|
||||
mod trust_anchor;
|
||||
|
||||
pub use self::algorithm::Algorithm;
|
||||
pub use self::digest_type::DigestType;
|
||||
pub use self::nsec3::Nsec3HashAlgorithm;
|
||||
pub use self::signer::Signer;
|
||||
pub use self::supported_algorithm::SupportedAlgorithms;
|
||||
pub use self::trust_anchor::TrustAnchor;
|
||||
|
40
src/rr/dnssec/trust_anchor.rs
Normal file
40
src/rr/dnssec/trust_anchor.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
use std::io::Cursor;
|
||||
|
||||
use openssl::crypto::pkey::{PKey, Role};
|
||||
|
||||
use ::rr::dnssec::Algorithm;
|
||||
|
||||
const ROOT_ANCHOR: &'static str = include_str!("Kjqmt7v.pem");
|
||||
|
||||
pub struct TrustAnchor {
|
||||
pkey: Vec<u8>
|
||||
}
|
||||
|
||||
impl TrustAnchor {
|
||||
pub fn new() -> TrustAnchor {
|
||||
let mut cursor = Cursor::new(ROOT_ANCHOR);
|
||||
let pkey = PKey::public_key_from_pem(&mut cursor).expect("Error parsing Kjqmt7v.pem");
|
||||
let alg = Algorithm::RSASHA256;
|
||||
|
||||
TrustAnchor{ pkey: alg.public_key_to_vec(&pkey) }
|
||||
}
|
||||
|
||||
pub fn contains(&self, other_key: &[u8]) -> bool {
|
||||
self.pkey == other_key
|
||||
}
|
||||
}
|
@@ -26,7 +26,7 @@ use openssl::crypto::pkey::Role;
|
||||
use ::error::*;
|
||||
use ::rr::{DNSClass, RecordType, Record, RData};
|
||||
use ::rr::domain;
|
||||
use ::rr::dnssec::Signer;
|
||||
use ::rr::dnssec::{Signer, TrustAnchor};
|
||||
use ::op::{ Message, MessageType, OpCode, Query, Edns, ResponseCode };
|
||||
use ::serialize::binary::*;
|
||||
|
||||
@@ -72,41 +72,44 @@ impl<A: ToSocketAddrs + Copy> Client<A> {
|
||||
// the RRSIG is signed by the DNSKEY, the DNSKEY is signed by the DS record in the Parent
|
||||
// zone. The key_tag is the DS record is assigned to the DNSKEY.
|
||||
let record_response = try!(self.inner_query(name, query_class, query_type, true));
|
||||
let rrsigs: Vec<&Record> = record_response.get_answers().iter().filter(|rr| rr.get_rr_type() == RecordType::RRSIG).collect();
|
||||
{
|
||||
let rrsigs: Vec<&Record> = record_response.get_answers().iter().filter(|rr| rr.get_rr_type() == RecordType::RRSIG).collect();
|
||||
|
||||
if rrsigs.is_empty() {
|
||||
return Err(ClientError::NoRRSIG);
|
||||
if rrsigs.is_empty() {
|
||||
return Err(ClientError::NoRRSIG);
|
||||
}
|
||||
|
||||
// group the record sets by name and type
|
||||
let mut rrset_types: HashSet<(domain::Name, RecordType)> = HashSet::new();
|
||||
for rrset in record_response.get_answers().iter()
|
||||
.filter(|rr| rr.get_rr_type() != RecordType::RRSIG)
|
||||
.map(|rr| (rr.get_name().clone(), rr.get_rr_type())) {
|
||||
rrset_types.insert(rrset);
|
||||
}
|
||||
|
||||
// verify all returned rrsets
|
||||
for (name, rrset_type) in rrset_types {
|
||||
let rrset: Vec<&Record> = record_response.get_answers().iter().filter(|rr| rr.get_rr_type() == rrset_type && rr.get_name() == &name).collect();
|
||||
|
||||
// '. DNSKEY' -> 'com. DS' -> 'com. DNSKEY' -> 'examle.com. DS' -> 'example.com. DNSKEY'
|
||||
// 'com. DS' is signed by '. DNSKEY' which produces 'com. RRSIG', all are in the same zone, '.'
|
||||
// the '.' DNSKEY is signed by the well known root certificate.
|
||||
// TODO fix rrsigs clone()
|
||||
let proof = try!(self.recursive_query_verify(&name, rrset, rrsigs.clone(), query_type, query_class));
|
||||
|
||||
// TODO return this, also make a prettier print
|
||||
debug!("proved existance through: {:?}", proof);
|
||||
}
|
||||
}
|
||||
|
||||
// group the record sets by name and type
|
||||
let mut rrset_types: HashSet<(domain::Name, RecordType)> = HashSet::new();
|
||||
for rrset in record_response.get_answers().iter()
|
||||
.filter(|rr| rr.get_rr_type() != RecordType::RRSIG)
|
||||
.map(|rr| (rr.get_name().clone(), rr.get_rr_type())) {
|
||||
rrset_types.insert(rrset);
|
||||
}
|
||||
|
||||
// verify all returned rrsets
|
||||
for (name, rrset_type) in rrset_types {
|
||||
let rrset: Vec<&Record> = record_response.get_answers().iter().filter(|rr| rr.get_rr_type() == rrset_type && rr.get_name() == &name).collect();
|
||||
|
||||
// '. DNSKEY' -> 'com. DS' -> 'com. DNSKEY' -> 'examle.com. DS' -> 'example.com. DNSKEY'
|
||||
// 'com. DS' is signed by '. DNSKEY' which produces 'com. RRSIG', all are in the same zone, '.'
|
||||
// the '.' DNSKEY is signed by the well known root certificate.
|
||||
// TODO fix rrsigs clone()
|
||||
let proof = try!(self.recursive_query_verify(&name, rrset, rrsigs.clone(), query_type, query_class));
|
||||
debug!("proved existance through: {:?}", proof);
|
||||
}
|
||||
|
||||
// verify each RRSIG...
|
||||
unimplemented!()
|
||||
// getting here means that we looped through all records with validation
|
||||
Ok(record_response)
|
||||
}
|
||||
|
||||
/// Verifies a record set against the supplied signatures, looking up the DNSKey chain.
|
||||
/// returns the chain of proof or an error if there is none.
|
||||
fn recursive_query_verify(&self, name: &domain::Name, rrset: Vec<&Record>, rrsigs: Vec<&Record>,
|
||||
query_type: RecordType, query_class: DNSClass) -> ClientResult<Vec<Record>> {
|
||||
debug!("verifying: {} type: {:?}", name, query_type);
|
||||
|
||||
// TODO: this is ugly, what reference do I want?
|
||||
let rrset: Vec<Record> = rrset.iter().map(|rr|rr.clone()).cloned().collect();
|
||||
@@ -119,6 +122,7 @@ impl<A: ToSocketAddrs + Copy> Client<A> {
|
||||
// but how do you know which needs to be validated with the DS in the parent zone?
|
||||
if zone_key && secure_entry_point {
|
||||
let mut proof = try!(self.verify_dnskey(record));
|
||||
// TODO: this is verified, it can be cached
|
||||
proof.push(record.clone());
|
||||
return Ok(proof);
|
||||
}
|
||||
@@ -138,26 +142,26 @@ impl<A: ToSocketAddrs + Copy> Client<A> {
|
||||
|
||||
for dnskey in key_rrset.iter() {
|
||||
if let &RData::DNSKEY{zone_key, algorithm, revoke, ref public_key, ..} = dnskey.get_rdata() {
|
||||
if revoke { debug!("revoked"); continue } // TODO: does this need to be validated? RFC 5011
|
||||
if !zone_key { debug!("not a zone_key, can't use"); continue }
|
||||
if algorithm != sig_alg { debug!("algorithms don't match"); continue }
|
||||
if revoke { debug!("revoked: {}", dnskey.get_name()); continue } // TODO: does this need to be validated? RFC 5011
|
||||
if !zone_key { continue }
|
||||
if algorithm != sig_alg { continue }
|
||||
|
||||
let pkey = try!(algorithm.public_key_from_vec(public_key));
|
||||
if !pkey.can(Role::Verify) { debug!("pkey can't verify"); continue }
|
||||
if !pkey.can(Role::Verify) { debug!("pkey can't verify, {:?}", dnskey.get_name()); continue }
|
||||
|
||||
let signer: Signer = Signer::new(algorithm, pkey, signer_name.clone());
|
||||
let rrset_hash: Vec<u8> = signer.hash_rrset(rrsig, &rrset);
|
||||
|
||||
if signer.verify(&rrset_hash, sig) {
|
||||
debug!("verified: {} with: {}", name, dnskey.get_name());
|
||||
|
||||
if signer_name == name && query_type == RecordType::DNSKEY {
|
||||
// this is self signed... let's skip to DS validation
|
||||
let mut proof: Vec<Record> = try!(self.verify_dnskey(dnskey));
|
||||
// TODO: this is verified, cache it
|
||||
proof.push((*dnskey).clone());
|
||||
return Ok(proof);
|
||||
} else {
|
||||
let mut proof = try!(self.recursive_query_verify(&signer_name, key_rrset.clone(), key_rrsigs, RecordType::DNSKEY, query_class));
|
||||
// TODO: this is verified, cache it
|
||||
proof.push((*dnskey).clone());
|
||||
return Ok(proof);
|
||||
}
|
||||
@@ -179,9 +183,16 @@ impl<A: ToSocketAddrs + Copy> Client<A> {
|
||||
/// attempts to verify the DNSKey against the DS of the parent.
|
||||
/// returns the chain of proof or an error if there is none.
|
||||
fn verify_dnskey(&self, dnskey: &Record) -> ClientResult<Vec<Record>> {
|
||||
debug!("verifying dnskey");
|
||||
let name: &domain::Name = dnskey.get_name();
|
||||
|
||||
if dnskey.get_name().is_root() {
|
||||
if let &RData::DNSKEY{ ref public_key, .. } = dnskey.get_rdata() {
|
||||
if TrustAnchor::new().contains(public_key) {
|
||||
return Ok(vec![dnskey.clone()])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ds_response = try!(self.inner_query(&name, dnskey.get_dns_class(), RecordType::DS, true));
|
||||
let ds_rrset: Vec<&Record> = ds_response.get_answers().iter().filter(|rr| rr.get_rr_type() == RecordType::DS).collect();
|
||||
let ds_rrsigs: Vec<&Record> = ds_response.get_answers().iter().filter(|rr| rr.get_rr_type() == RecordType::RRSIG).collect();
|
||||
@@ -217,7 +228,9 @@ impl<A: ToSocketAddrs + Copy> Client<A> {
|
||||
let hash: Vec<u8> = digest_type.hash(&buf);
|
||||
if &hash == digest {
|
||||
// continue to verify the chain...
|
||||
return self.recursive_query_verify(&name, ds_rrset.clone(), ds_rrsigs, RecordType::DNSKEY, dnskey.get_dns_class());
|
||||
let mut proof: Vec<Record> = try!(self.recursive_query_verify(&name, ds_rrset.clone(), ds_rrsigs, RecordType::DNSKEY, dnskey.get_dns_class()));
|
||||
proof.push(dnskey.clone());
|
||||
return Ok(proof)
|
||||
}
|
||||
} else {
|
||||
panic!("expected DS: {:?}", ds.get_rr_type());
|
||||
@@ -488,36 +501,36 @@ fn test_secure_query_example() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use this site for verifying nsec3
|
||||
#[test]
|
||||
#[cfg(feature = "ftest")]
|
||||
fn test_secure_query_sdsmt() {
|
||||
use std::net::*;
|
||||
|
||||
use ::rr::dns_class::DNSClass;
|
||||
use ::rr::record_type::RecordType;
|
||||
use ::rr::domain;
|
||||
use ::rr::record_data::RData;
|
||||
use ::udp::Client;
|
||||
|
||||
let name = domain::Name::with_labels(vec!["www".to_string(), "sdsmt".to_string(), "edu".to_string()]);
|
||||
let client = Client::new(("8.8.8.8").parse().unwrap()).unwrap();
|
||||
|
||||
let response = client.secure_query(&name, DNSClass::IN, RecordType::A);
|
||||
assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
|
||||
|
||||
let response = response.unwrap();
|
||||
|
||||
println!("response records: {:?}", response);
|
||||
|
||||
let record = &response.get_answers()[0];
|
||||
assert_eq!(record.get_name(), &name);
|
||||
assert_eq!(record.get_rr_type(), RecordType::A);
|
||||
assert_eq!(record.get_dns_class(), DNSClass::IN);
|
||||
|
||||
if let &RData::A{ ref address } = record.get_rdata() {
|
||||
assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
|
||||
} else {
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
// // TODO: use this site for verifying nsec3
|
||||
// #[test]
|
||||
// #[cfg(feature = "ftest")]
|
||||
// fn test_secure_query_sdsmt() {
|
||||
// use std::net::*;
|
||||
//
|
||||
// use ::rr::dns_class::DNSClass;
|
||||
// use ::rr::record_type::RecordType;
|
||||
// use ::rr::domain;
|
||||
// use ::rr::record_data::RData;
|
||||
// use ::udp::Client;
|
||||
//
|
||||
// let name = domain::Name::with_labels(vec!["www".to_string(), "sdsmt".to_string(), "edu".to_string()]);
|
||||
// let client = Client::new(("8.8.8.8").parse().unwrap()).unwrap();
|
||||
//
|
||||
// let response = client.secure_query(&name, DNSClass::IN, RecordType::A);
|
||||
// assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
|
||||
//
|
||||
// let response = response.unwrap();
|
||||
//
|
||||
// println!("response records: {:?}", response);
|
||||
//
|
||||
// let record = &response.get_answers()[0];
|
||||
// assert_eq!(record.get_name(), &name);
|
||||
// assert_eq!(record.get_rr_type(), RecordType::A);
|
||||
// assert_eq!(record.get_dns_class(), DNSClass::IN);
|
||||
//
|
||||
// if let &RData::A{ ref address } = record.get_rdata() {
|
||||
// assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
|
||||
// } else {
|
||||
// assert!(false);
|
||||
// }
|
||||
// }
|
||||
|
Reference in New Issue
Block a user