zone signing complete

This commit is contained in:
Benjamin Fry 2016-05-15 01:15:34 -07:00
parent 7b271c468d
commit aab326f9fd
5 changed files with 165 additions and 84 deletions

View File

@ -4,7 +4,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## unreleased
### Added
- Documentation on all modules
- Documentation on all modules, and many standard RFC types
- Authority zone signing now complete, still need to load/save private keys
### Fixed
- Added loop on TCP accept requests

View File

@ -81,6 +81,10 @@ impl Authority {
allow_update: allow_update, secure_keys: Vec::new() }
}
pub fn add_secure_key(&mut self, signer: Signer) {
self.secure_keys.push(signer);
}
#[cfg(test)]
fn set_allow_update(&mut self, allow_update: bool) {
self.allow_update = allow_update;
@ -94,13 +98,28 @@ impl Authority {
self.zone_type
}
pub fn get_soa(&self) -> Option<&Record> {
pub fn get_soa(&self, is_secure: bool) -> Option<&Record> {
// SOA should be origin|SOA
self.lookup(&self.origin, RecordType::SOA).and_then(|v|v.first().map(|v| *v))
self.lookup(&self.origin, RecordType::SOA, is_secure).and_then(|v|v.first().map(|v| *v))
}
fn get_serial(&self) -> u32 {
let soa = if let Some(ref soa_record) = self.get_soa(false) {
soa_record.clone()
} else {
warn!("no soa record found for zone: {}", self.origin);
return 0;
};
if let &RData::SOA(ref soa_rdata) = soa.get_rdata() {
soa_rdata.get_serial()
} else {
panic!("This was not an SOA record");
}
}
fn increment_soa_serial(&mut self) -> u32 {
let mut soa = if let Some(ref mut soa_record) = self.get_soa() {
let mut soa = if let Some(ref mut soa_record) = self.get_soa(false) {
soa_record.clone()
} else {
warn!("no soa record found for zone: {}", self.origin);
@ -118,8 +137,8 @@ impl Authority {
return serial;
}
pub fn get_ns(&self) -> Option<Vec<&Record>> {
self.lookup(&self.origin, RecordType::NS)
pub fn get_ns(&self, is_secure: bool) -> Option<Vec<&Record>> {
self.lookup(&self.origin, RecordType::NS, is_secure)
}
/// ```text
@ -221,7 +240,7 @@ impl Authority {
match require.get_rr_type() {
// ANY ANY empty Name is in use
RecordType::ANY => {
if let None = self.lookup(require.get_name(), RecordType::ANY) {
if let None = self.lookup(require.get_name(), RecordType::ANY, false) {
return Err(ResponseCode::NXDomain);
} else {
continue;
@ -229,7 +248,7 @@ impl Authority {
},
// ANY rrset empty RRset exists (value independent)
rrset @ _ => {
if let None = self.lookup(require.get_name(), rrset) {
if let None = self.lookup(require.get_name(), rrset, false) {
return Err(ResponseCode::NXRRSet);
} else {
continue;
@ -245,7 +264,7 @@ impl Authority {
match require.get_rr_type() {
// NONE ANY empty Name is not in use
RecordType::ANY => {
if let Some(..) = self.lookup(require.get_name(), RecordType::ANY) {
if let Some(..) = self.lookup(require.get_name(), RecordType::ANY, false) {
return Err(ResponseCode::YXDomain);
} else {
continue;
@ -253,7 +272,7 @@ impl Authority {
},
// NONE rrset empty RRset does not exist
rrset @ _ => {
if let Some(..) = self.lookup(require.get_name(), rrset) {
if let Some(..) = self.lookup(require.get_name(), rrset, false) {
return Err(ResponseCode::YXRRSet);
} else {
continue;
@ -266,7 +285,7 @@ impl Authority {
,
class @ _ if class == self.class =>
// zone rrset rr RRset exists (value dependent)
if let Some(rrset) = self.lookup(require.get_name(), require.get_rr_type()) {
if let Some(rrset) = self.lookup(require.get_name(), require.get_rr_type(), false) {
if rrset.iter().filter(|rr| *rr == &require).next().is_none() {
return Err(ResponseCode::NXRRSet);
} else {
@ -428,8 +447,10 @@ impl Authority {
/// NONE rrset rr Delete an RR from an RRset
/// zone rrset rr Add to an RRset
/// ```
fn update_records(&mut self, records: &[Record], serial: u32) -> UpdateResult<bool> {
fn update_records(&mut self, records: &[Record]) -> UpdateResult<bool> {
let mut updated = false;
let serial: u32 = self.get_serial();
// 3.4.2.7 - Pseudocode For Update Section Processing
//
@ -527,6 +548,7 @@ impl Authority {
if let &RData::NULL( .. ) = rr.get_rdata() {
let deleted = self.records.remove(&rr_key);
info!("deleted rrset: {:?}", deleted);
updated = updated || deleted.is_some();
} else {
info!("expected empty rdata: {:?}", rr);
return Err(ResponseCode::FormErr)
@ -552,6 +574,17 @@ impl Authority {
}
}
// update the serial...
if updated {
// need to resign any records at the current serial number and bump the number.
// first bump the serial number on the SOA, so that it is resigned with the new serial.
self.increment_soa_serial();
// TODO: should we auto sign here? or maybe up a level...
self.sign_zone();
}
Ok(updated)
}
@ -630,24 +663,15 @@ impl Authority {
///
/// # Return value
///
/// Ok() on success or Err() with the `ResponseCode` associated with the error.
pub fn update(&mut self, update: &UpdateMessage) -> UpdateResult<()> {
/// true if any of additions, updates or deletes were made to the zone, false otherwise. Err is
/// returned in the case of bad data, etc.
pub fn update(&mut self, update: &UpdateMessage) -> UpdateResult<bool> {
// the spec says to authorize after prereqs, seems better to auth first.
try!(self.authorize(update));
try!(self.verify_prerequisites(update.get_pre_requisites()));
try!(self.pre_scan(update.get_updates()));
let serial: u32 = self.get_soa().map_or(0, |r| if let &RData::SOA (ref soa) = r.get_rdata() { soa.get_serial() } else { 0 });
// TODO at this point, we've accepted the updates, we should write
// to a write-ahead-log (journal) and then commit to memory.
if try!(self.update_records(update.get_updates(), serial)) {
// need to resign any records at the current serial number and bump the number.
// first bump the serial number on the SOA, so that it is resigned with the new serial.
self.increment_soa_serial();
self.sign_zone();
}
Ok(())
self.update_records(update.get_updates())
}
/// Looks up all Resource Records matching the giving `Name` and `RecordType`.
@ -659,11 +683,12 @@ impl Authority {
/// `name`. `RecordType::AXFR` will return all record types except `RecordType::SOA`
/// due to the requirements that on zone transfers the `RecordType::SOA` must both
/// preceed and follow all other records.
/// * `is_secure` - If the DO bit is set on the EDNS OPT record, then return RRSIGs as well.
///
/// # Return value
///
/// None if there are no matching records, otherwise a `Vec` containing the found records.
pub fn lookup(&self, name: &Name, rtype: RecordType) -> Option<Vec<&Record>> {
pub fn lookup(&self, name: &Name, rtype: RecordType, is_secure: bool) -> Option<Vec<&Record>> {
// on an SOA request always return the SOA, regardless of the name
let name: &Name = if rtype == RecordType::SOA { &self.origin } else { name };
let rr_key = RrKey::new(name, rtype);
@ -674,12 +699,12 @@ impl Authority {
self.records.values().filter(|rr_set| rtype == RecordType::ANY || rr_set.get_record_type() != RecordType::SOA)
.filter(|rr_set| rtype == RecordType::AXFR || rr_set.get_name() == name)
.fold(Vec::<&Record>::new(), |mut vec, rr_set| {
vec.append(&mut rr_set.get_records().into_iter().collect());
vec.append(&mut rr_set.get_records(is_secure));
vec
})
},
_ => {
self.records.get(&rr_key).map_or(vec![], |rr_set| rr_set.get_records().into_iter().collect())
self.records.get(&rr_key).map_or(vec![], |rr_set| rr_set.get_records(is_secure).into_iter().collect())
}
};
@ -695,13 +720,16 @@ impl Authority {
/// record set serial is greater than or equal to the `serial`, then it will be
/// resigned.
pub fn sign_zone(&mut self) {
debug!("signing zone: {}", self.origin);
let now = UTC::now().timestamp() as u32;
let zone_ttl = self.get_soa()
let zone_ttl = self.get_soa(false)
.map_or(0, |soa_rec| if let &RData::SOA(ref soa) = soa_rec.get_rdata() { soa.get_minimum() }
else { panic!("SOA has no RDATA: {}", self.origin) } );
for rr_set in self.records.iter_mut().filter_map(|(_, rr_set)| { rr_set.get_rrsigs().is_empty();
Some(rr_set) } ) {
debug!("signing rr_set: {}", rr_set.get_name());
rr_set.clear_rrsigs();
let rrsig_temp = Record::with(rr_set.get_name().clone(), RecordType::RRSIG, zone_ttl);
for signer in self.secure_keys.iter() {
@ -715,7 +743,9 @@ impl Authority {
now,
signer.calculate_key_tag(),
signer.get_signer_name(),
rr_set.get_records());
// TODO: this is a nasty clone... the issue is that the vec
// from get_records is of Vec<&R>, but we really want &[R]
&rr_set.get_records(false).into_iter().cloned().collect::<Vec<Record>>());
let signature = signer.sign(&hash);
let mut rrsig = rrsig_temp.clone();
rrsig.rdata(RData::SIG(SIG::new(
@ -738,6 +768,9 @@ impl Authority {
// sig: Vec<u8>
signature,
)));
rr_set.insert_rrsig(rrsig);
debug!("signed rr_set: {}", rr_set.get_name());
}
}
}
@ -813,25 +846,25 @@ pub mod authority_tests {
fn test_authority() {
let authority: Authority = create_example();
assert!(authority.get_soa().is_some());
assert_eq!(authority.get_soa().unwrap().get_dns_class(), DNSClass::IN);
assert!(authority.get_soa(false).is_some());
assert_eq!(authority.get_soa(false).unwrap().get_dns_class(), DNSClass::IN);
assert!(authority.lookup(authority.get_origin(), RecordType::NS).is_some());
assert!(authority.lookup(authority.get_origin(), RecordType::NS, false).is_some());
let mut lookup: Vec<_> = authority.get_ns().unwrap();
let mut lookup: Vec<_> = authority.get_ns(false).unwrap();
lookup.sort();
assert_eq!(**lookup.first().unwrap(), Record::new().name(authority.get_origin().clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()) ).clone());
assert_eq!(**lookup.last().unwrap(), Record::new().name(authority.get_origin().clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()) ).clone());
assert!(authority.lookup(authority.get_origin(), RecordType::TXT).is_some());
assert!(authority.lookup(authority.get_origin(), RecordType::TXT, false).is_some());
let mut lookup: Vec<_> = authority.lookup(authority.get_origin(), RecordType::TXT).unwrap();
let mut lookup: Vec<_> = authority.lookup(authority.get_origin(), RecordType::TXT, false).unwrap();
lookup.sort();
assert_eq!(**lookup.first().unwrap(), Record::new().name(authority.get_origin().clone()).ttl(60).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["$Id: example.com 4415 2015-08-24 20:12:23Z davids $".to_string()]))).clone());
assert_eq!(**authority.lookup(authority.get_origin(), RecordType::A).unwrap().first().unwrap(), Record::new().name(authority.get_origin().clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone());
assert_eq!(**authority.lookup(authority.get_origin(), RecordType::A, false).unwrap().first().unwrap(), Record::new().name(authority.get_origin().clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone());
}
#[test]
@ -923,6 +956,8 @@ pub mod authority_tests {
let new_name = Name::new().label("new").label("example").label("com");
let www_name = Name::new().label("www").label("example").label("com");
let mut authority: Authority = create_example();
let serial = authority.get_serial();
authority.set_allow_update(true);
let mut original_vec: Vec<Record> = vec![
@ -935,26 +970,28 @@ pub mod authority_tests {
{
// assert that the correct set of records is there.
let mut www_rrset: Vec<&Record> = authority.lookup(&www_name, RecordType::ANY).unwrap();
let mut www_rrset: Vec<&Record> = authority.lookup(&www_name, RecordType::ANY, false).unwrap();
www_rrset.sort();
assert_eq!(www_rrset, original_vec.iter().collect::<Vec<&Record>>());
// assert new record doesn't exist
assert!(authority.lookup(&new_name, RecordType::ANY).is_none());
assert!(authority.lookup(&new_name, RecordType::ANY, false).is_none());
}
//
// zone rrset rr Add to an RRset
let add_record = &[Record::new().name(new_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone()];
assert!(authority.update_records(add_record, 0).is_ok());
assert_eq!(authority.lookup(&new_name, RecordType::ANY).unwrap_or(vec![]), add_record.iter().collect::<Vec<&Record>>());
assert!(authority.update_records(add_record).expect("update failed"));
assert_eq!(authority.lookup(&new_name, RecordType::ANY, false).unwrap_or(vec![]), add_record.iter().collect::<Vec<&Record>>());
assert_eq!(serial + 1, authority.get_serial());
let add_www_record = &[Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(10,0,0,1))).clone()];
assert!(authority.update_records(add_www_record, 0).is_ok());
assert!(authority.update_records(add_www_record).expect("update failed"));
assert_eq!(serial + 2, authority.get_serial());
{
let mut www_rrset = authority.lookup(&www_name, RecordType::ANY).unwrap_or(vec![]);
let mut www_rrset = authority.lookup(&www_name, RecordType::ANY, false).unwrap_or(vec![]);
www_rrset.sort();
let mut plus_10 = original_vec.clone();
@ -966,17 +1003,19 @@ pub mod authority_tests {
//
// NONE rrset rr Delete an RR from an RRset
let del_record = &[Record::new().name(new_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::NONE).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone()];
assert!(authority.update_records(del_record, 0).is_ok());
assert!(authority.update_records(del_record).expect("update failed"));
assert_eq!(serial + 3, authority.get_serial());
{
println!("after delete of specific record: {:?}", authority.lookup(&new_name, RecordType::ANY));
assert!(authority.lookup(&new_name, RecordType::ANY).is_none());
println!("after delete of specific record: {:?}", authority.lookup(&new_name, RecordType::ANY, false));
assert!(authority.lookup(&new_name, RecordType::ANY, false).is_none(), false);
}
// remove one from www
let del_record = &[Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::NONE).rdata(RData::A(Ipv4Addr::new(10,0,0,1))).clone()];
assert!(authority.update_records(del_record, 0).is_ok());
assert!(authority.update_records(del_record).expect("update failed"));
assert_eq!(serial + 4, authority.get_serial());
{
let mut www_rrset = authority.lookup(&www_name, RecordType::ANY).unwrap_or(vec![]);
let mut www_rrset = authority.lookup(&www_name, RecordType::ANY, false).unwrap_or(vec![]);
www_rrset.sort();
assert_eq!(www_rrset, original_vec.iter().collect::<Vec<&Record>>());
@ -985,7 +1024,8 @@ pub mod authority_tests {
//
// ANY rrset empty Delete an RRset
let del_record = &[Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::ANY).rdata(RData::NULL(NULL::new())).clone()];
assert!(authority.update_records(del_record, 0).is_ok());
assert!(authority.update_records(del_record).expect("update failed"));
assert_eq!(serial + 5, authority.get_serial());
let mut removed_a_vec: Vec<_> = vec![
Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["v=spf1 -all".to_string()]))).clone(),
Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(),
@ -993,7 +1033,7 @@ pub mod authority_tests {
removed_a_vec.sort();
{
let mut www_rrset = authority.lookup(&www_name, RecordType::ANY).unwrap_or(vec![]);
let mut www_rrset = authority.lookup(&www_name, RecordType::ANY, false).unwrap_or(vec![]);
www_rrset.sort();
assert_eq!(www_rrset, removed_a_vec.iter().collect::<Vec<&Record>>());
@ -1003,7 +1043,38 @@ pub mod authority_tests {
// ANY ANY empty Delete all RRsets from a name
println!("deleting all records");
let del_record = &[Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::ANY).dns_class(DNSClass::ANY).rdata(RData::NULL(NULL::new())).clone()];
assert!(authority.update_records(del_record, 0).is_ok());
assert_eq!(authority.lookup(&www_name, RecordType::ANY), None);
assert!(authority.update_records(del_record).expect("update failed"));
assert_eq!(authority.lookup(&www_name, RecordType::ANY, false), None);
assert_eq!(serial + 6, authority.get_serial());
}
#[test]
fn test_zone_signing() {
use openssl::crypto::pkey::PKey;
use ::rr::dnssec::{Algorithm, Signer};
use ::rr::{RData};
let mut authority: Authority = create_example();
let mut pkey = PKey::new();
pkey.gen(512);
let signer = Signer::new(Algorithm::RSASHA256, pkey, Name::root(), u32::max_value(), 0);
authority.add_secure_key(signer);
authority.sign_zone();
let results = authority.lookup(&authority.get_origin(), RecordType::AXFR, true).expect("AXFR broken");
for record in results.iter() {
if record.get_rr_type() == RecordType::RRSIG { continue }
// validate all records have associated RRSIGs after signing
assert!(results.iter().any(|r| r.get_rr_type() == RecordType::RRSIG &&
r.get_name() == record.get_name() &&
if let &RData::SIG(ref rrsig) = r.get_rdata() {
rrsig.get_type_covered() == record.get_rr_type()
} else {
false
} ), "record type not covered: {:?}", record);
}
}
}

View File

@ -224,7 +224,7 @@ impl Catalog {
response.add_all_answers(&records);
// get the NS records
let ns = authority.get_ns();
let ns = authority.get_ns(false);
if ns.is_none() { warn!("there are no NS records for: {:?}", authority.get_origin()); }
else {
response.add_all_name_servers(&ns.unwrap());
@ -233,7 +233,7 @@ impl Catalog {
// in the not found case it's standard to return the SOA in the authority section
response.response_code(ResponseCode::NXDomain);
let soa = authority.get_soa();
let soa = authority.get_soa(false);
if soa.is_none() { warn!("there is no SOA record for: {:?}", authority.get_origin()); }
else {
response.add_name_server(soa.unwrap().clone());
@ -266,10 +266,10 @@ impl Catalog {
// it would be better to stream this back, rather than packaging everything up in an array
// though for UDP it would still need to be bundled
let mut query_result: Option<Vec<_>> = authority.lookup(query.get_name(), record_type);
let mut query_result: Option<Vec<_>> = authority.lookup(query.get_name(), record_type, false);
if RecordType::AXFR == record_type {
if let Some(soa) = authority.get_soa() {
if let Some(soa) = authority.get_soa(false) {
let mut xfr: Vec<&Record> = query_result.unwrap_or(Vec::with_capacity(2));
// TODO: probably make Records Rc or Arc, to remove the clone
xfr.insert(0, soa);

View File

@ -15,6 +15,7 @@
*/
use ::rr::{Name, Record, RecordType, RData};
/// Set of resource records associated to a name and type
#[derive(Debug)]
pub struct RRSet {
@ -69,8 +70,12 @@ impl RRSet {
/// # Return value
///
/// Slice of all records in the set
pub fn get_records(&self) -> &[Record] {
&self.records
pub fn get_records(&self, and_rrsigs: bool) -> Vec<&Record> {
if and_rrsigs {
self.records.iter().chain(self.rrsigs.iter()).collect()
} else {
self.records.iter().collect()
}
}
/// # Return value
@ -95,6 +100,10 @@ impl RRSet {
self.rrsigs.push(rrsig)
}
pub fn clear_rrsigs(&mut self) {
self.rrsigs.clear()
}
fn updated(&mut self, serial: u32) {
self.serial = serial;
self.rrsigs.clear(); // on updates, the rrsigs are invalid
@ -275,20 +284,20 @@ mod test {
let insert = Record::new().name(name.clone()).ttl(86400).rr_type(record_type).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone();
assert!(rr_set.insert(insert.clone(), 0));
assert_eq!(rr_set.get_records().len(), 1);
assert!(rr_set.get_records().contains(&insert));
assert_eq!(rr_set.get_records(false).len(), 1);
assert!(rr_set.get_records(false).contains(&&insert));
// dups ignored
assert!(!rr_set.insert(insert.clone(), 0));
assert_eq!(rr_set.get_records().len(), 1);
assert!(rr_set.get_records().contains(&insert));
assert_eq!(rr_set.get_records(false).len(), 1);
assert!(rr_set.get_records(false).contains(&&insert));
// add one
let insert1 = Record::new().name(name.clone()).ttl(86400).rr_type(record_type).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,25))).clone();
assert!(rr_set.insert(insert1.clone(), 0));
assert_eq!(rr_set.get_records().len(), 2);
assert!(rr_set.get_records().contains(&insert));
assert!(rr_set.get_records().contains(&insert1));
assert_eq!(rr_set.get_records(false).len(), 2);
assert!(rr_set.get_records(false).contains(&&insert));
assert!(rr_set.get_records(false).contains(&&insert1));
}
#[test]
@ -302,19 +311,19 @@ mod test {
let new_serial = Record::new().name(name.clone()).ttl(3600).rr_type(RecordType::SOA).dns_class(DNSClass::IN).rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.net.", None).unwrap(), Name::parse("noc.dns.icann.net.", None).unwrap(), 2015082404, 7200, 3600, 1209600, 3600 ))).clone();
assert!(rr_set.insert(insert.clone(), 0));
assert!(rr_set.get_records().contains(&insert));
assert!(rr_set.get_records(false).contains(&&insert));
// same serial number
assert!(!rr_set.insert(same_serial.clone(), 0));
assert!(rr_set.get_records().contains(&insert));
assert!(!rr_set.get_records().contains(&same_serial));
assert!(rr_set.get_records(false).contains(&&insert));
assert!(!rr_set.get_records(false).contains(&&same_serial));
assert!(rr_set.insert(new_serial.clone(), 0));
assert!(!rr_set.insert(same_serial.clone(), 0));
assert!(!rr_set.insert(insert.clone(), 0));
assert!(rr_set.get_records().contains(&new_serial));
assert!(!rr_set.get_records().contains(&insert));
assert!(!rr_set.get_records().contains(&same_serial));
assert!(rr_set.get_records(false).contains(&&new_serial));
assert!(!rr_set.get_records(false).contains(&&insert));
assert!(!rr_set.get_records(false).contains(&&same_serial));
}
#[test]
@ -330,12 +339,12 @@ mod test {
let new_record = Record::new().name(name.clone()).ttl(3600).rr_type(RecordType::CNAME).dns_class(DNSClass::IN).rdata(RData::CNAME(new_cname.clone()) ).clone();
assert!(rr_set.insert(insert.clone(), 0));
assert!(rr_set.get_records().contains(&insert));
assert!(rr_set.get_records(false).contains(&&insert));
// update the record
assert!(rr_set.insert(new_record.clone(), 0));
assert!(!rr_set.get_records().contains(&insert));
assert!(rr_set.get_records().contains(&new_record));
assert!(!rr_set.get_records(false).contains(&&insert));
assert!(rr_set.get_records(false).contains(&&new_record));
}
#[test]
@ -366,7 +375,7 @@ mod test {
assert!(rr_set.insert(insert.clone(), 0));
assert!(!rr_set.remove(&insert, 0));
assert!(rr_set.get_records().contains(&insert));
assert!(rr_set.get_records(false).contains(&&insert));
}
#[test]

View File

@ -46,7 +46,7 @@ VENERA A 10.1.0.52
// not validating everything, just one of each...
// SOA
let soa_record = authority.get_soa().unwrap();
let soa_record = authority.get_soa(false).unwrap();
assert_eq!(RecordType::SOA, soa_record.get_rr_type());
assert_eq!(&Name::new().label("isi").label("edu"), soa_record.get_name()); // i.e. the origin or domain
assert_eq!(3600000, soa_record.get_ttl());
@ -65,7 +65,7 @@ VENERA A 10.1.0.52
}
// NS
let mut ns_records: Vec<&Record> = authority.lookup(&Name::with_labels(vec!["isi".into(),"edu".into()]), RecordType::NS).unwrap();
let mut ns_records: Vec<&Record> = authority.lookup(&Name::with_labels(vec!["isi".into(),"edu".into()]), RecordType::NS, false).unwrap();
let mut compare = vec![ // this is cool, zip up the expected results... works as long as the order is good.
Name::new().label("a").label("isi").label("edu"),
Name::new().label("venera").label("isi").label("edu"),
@ -89,7 +89,7 @@ VENERA A 10.1.0.52
}
// MX
let mut mx_records: Vec<&Record> = authority.lookup(&Name::new().label("isi").label("edu"), RecordType::MX).unwrap();
let mut mx_records: Vec<&Record> = authority.lookup(&Name::new().label("isi").label("edu"), RecordType::MX, false).unwrap();
let mut compare = vec![
(10, Name::new().label("venera").label("isi").label("edu")),
(20, Name::new().label("vaxa").label("isi").label("edu")),
@ -114,7 +114,7 @@ VENERA A 10.1.0.52
}
// A
let a_record: &Record = authority.lookup(&Name::new().label("a").label("isi").label("edu"), RecordType::A).unwrap().first().cloned().unwrap();
let a_record: &Record = authority.lookup(&Name::new().label("a").label("isi").label("edu"), RecordType::A, false).unwrap().first().cloned().unwrap();
assert_eq!(&Name::new().label("a").label("isi").label("edu"), a_record.get_name());
assert_eq!(60, a_record.get_ttl()); // TODO: should this be minimum or expire?
assert_eq!(DNSClass::IN, a_record.get_dns_class());
@ -126,7 +126,7 @@ VENERA A 10.1.0.52
}
// AAAA
let aaaa_record: &Record = authority.lookup(&Name::new().label("aaaa").label("isi").label("edu"), RecordType::AAAA).unwrap().first().cloned().unwrap();
let aaaa_record: &Record = authority.lookup(&Name::new().label("aaaa").label("isi").label("edu"), RecordType::AAAA, false).unwrap().first().cloned().unwrap();
assert_eq!(&Name::new().label("aaaa").label("isi").label("edu"), aaaa_record.get_name());
if let RData::AAAA(ref address) = *aaaa_record.get_rdata() {
assert_eq!(&Ipv6Addr::from_str("4321:0:1:2:3:4:567:89ab").unwrap(), address);
@ -135,7 +135,7 @@ VENERA A 10.1.0.52
}
// SHORT
let short_record: &Record = authority.lookup(&Name::new().label("short").label("isi").label("edu"), RecordType::A).unwrap().first().cloned().unwrap();
let short_record: &Record = authority.lookup(&Name::new().label("short").label("isi").label("edu"), RecordType::A, false).unwrap().first().cloned().unwrap();
assert_eq!(&Name::new().label("short").label("isi").label("edu"), short_record.get_name());
assert_eq!(70, short_record.get_ttl());
if let RData::A(ref address) = *short_record.get_rdata() {
@ -145,7 +145,7 @@ VENERA A 10.1.0.52
}
// TXT
let mut txt_records: Vec<&Record> = authority.lookup(&Name::new().label("a").label("isi").label("edu"), RecordType::TXT).unwrap();
let mut txt_records: Vec<&Record> = authority.lookup(&Name::new().label("a").label("isi").label("edu"), RecordType::TXT, false).unwrap();
let compare = vec![
vec!["I".to_string(), "am".to_string(), "a".to_string(), "txt".to_string(), "record".to_string()],
vec!["I".to_string(), "am".to_string(), "another".to_string(), "txt".to_string(), "record".to_string()],
@ -170,7 +170,7 @@ VENERA A 10.1.0.52
}
// PTR
let ptr_record: &Record = authority.lookup(&Name::new().label("103").label("0").label("3").label("26").label("in-addr").label("arpa"), RecordType::PTR).unwrap().first().cloned().unwrap();
let ptr_record: &Record = authority.lookup(&Name::new().label("103").label("0").label("3").label("26").label("in-addr").label("arpa"), RecordType::PTR, false).unwrap().first().cloned().unwrap();
if let RData::PTR( ref ptrdname ) = *ptr_record.get_rdata() {
assert_eq!(&Name::new().label("a").label("isi").label("edu"), ptrdname);
} else {
@ -178,7 +178,7 @@ VENERA A 10.1.0.52
}
// SRV
let srv_record: &Record = authority.lookup(&Name::new().label("_ldap").label("_tcp").label("service").label("isi").label("edu"), RecordType::SRV).unwrap().first().cloned().unwrap();
let srv_record: &Record = authority.lookup(&Name::new().label("_ldap").label("_tcp").label("service").label("isi").label("edu"), RecordType::SRV, false).unwrap().first().cloned().unwrap();
if let RData::SRV(ref rdata) = *srv_record.get_rdata() {
assert_eq!(rdata.get_priority(), 1);
assert_eq!(rdata.get_weight(), 2);