added delete_all

This commit is contained in:
Benjamin Fry 2016-05-30 23:26:50 -07:00
parent 4a295b4777
commit 0e2d3ef5d4
3 changed files with 122 additions and 7 deletions

View File

@ -10,7 +10,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- New mocked network client tests, to verify zone signing
- NSEC record creation for zone, with tests
- SIG0 validation for Authentication on for dynamic updates
- Client CRUD operations
- Client CRUDDD operations, delete_by_rdata, delete_rrset, delete_all
### Fixed
- Added loop on TCP accept requests

View File

@ -183,8 +183,13 @@ impl Catalog {
let zones: &[Query] = update.get_zones();
// TODO: allow SOA updates to create subzones more easily... (not RFC compliant)
if zones.len() != 1 || zones[0].get_query_type() == RecordType::SOA {
// 2.3 - Zone Section
//
// All records to be updated must be in the same zone, and
// therefore the Zone Section is allowed to contain exactly one record.
// The ZNAME is the zone name, the ZTYPE must be SOA, and the ZCLASS is
// the zone's class.
if zones.len() != 1 || zones[0].get_query_type() != RecordType::SOA {
response.response_code(ResponseCode::FormErr);
return response;
}

View File

@ -554,7 +554,7 @@ impl<C: ClientConnection> Client<C> {
// for updates, the query section is used for the zone
let mut zone: Query = Query::new();
zone.name(zone_origin).query_class(record.get_dns_class()).query_type(record.get_rr_type());
zone.name(zone_origin).query_class(record.get_dns_class()).query_type(RecordType::SOA);
// build the message
let mut message: Message = Message::new();
@ -629,7 +629,7 @@ impl<C: ClientConnection> Client<C> {
// for updates, the query section is used for the zone
let mut zone: Query = Query::new();
zone.name(zone_origin).query_class(record.get_dns_class()).query_type(record.get_rr_type());
zone.name(zone_origin).query_class(record.get_dns_class()).query_type(RecordType::SOA);
// build the message
let mut message: Message = Message::new();
@ -710,7 +710,7 @@ impl<C: ClientConnection> Client<C> {
// for updates, the query section is used for the zone
let mut zone: Query = Query::new();
zone.name(zone_origin).query_class(record.get_dns_class()).query_type(record.get_rr_type());
zone.name(zone_origin).query_class(record.get_dns_class()).query_type(RecordType::SOA);
// build the message
let mut message: Message = Message::new();
@ -795,7 +795,7 @@ impl<C: ClientConnection> Client<C> {
// for updates, the query section is used for the zone
let mut zone: Query = Query::new();
zone.name(zone_origin).query_class(record.get_dns_class()).query_type(record.get_rr_type());
zone.name(zone_origin).query_class(record.get_dns_class()).query_type(RecordType::SOA);
// build the message
let mut message: Message = Message::new();
@ -836,6 +836,78 @@ impl<C: ClientConnection> Client<C> {
self.send_message(&message)
}
/// Deletes all records at the specified name
///
/// [RFC 2136](https://tools.ietf.org/html/rfc2136), DNS Update, April 1997
///
/// ```text
/// 2.5.3 - Delete All RRsets From A Name
///
/// One RR is added to the Update Section whose NAME is that of the name
/// to be cleansed of RRsets. TYPE must be specified as ANY. TTL must
/// be specified as zero (0) and is otherwise not used by the primary
/// master. CLASS must be specified as ANY. RDLENGTH must be zero (0)
/// and RDATA must therefore be empty. If no such RRsets exist, then
/// this Update RR will be silently ignored by the primary master.
/// ```
///
/// # Arguments
///
/// * `record` - the record to delete from a RRSet, the name, and type must match the
/// record set to delete
/// * `zone` - the zone name (must match an SOA) to update
/// * `must_exist` - if true, the request will fail if the record does not exist
/// * `signer` - the signer with private key to use to sign the request
///
/// The update must go to a zone authority (i.e. the server used in the ClientConnection). This
/// operation attempts to delete all resource record sets the the specified name reguardless of
/// the record type.
pub fn delete_all(&self,
name_of_records: domain::Name,
zone_origin: domain::Name,
dns_class: DNSClass,
signer: &Signer) -> ClientResult<Message> {
assert!(zone_origin.zone_of(&name_of_records));
// for updates, the query section is used for the zone
let mut zone: Query = Query::new();
zone.name(zone_origin).query_class(dns_class).query_type(RecordType::SOA);
// build the message
let mut message: Message = Message::new();
message.id(self.next_id()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.add_zone(zone);
// the TTL shoudl be 0
// the rdata must be null to delete all rrsets
// the record type must be any
let mut record = Record::with(name_of_records, RecordType::ANY, 0);
// the class must be none for an rrset delete
record.dns_class(DNSClass::ANY);
message.add_update(record);
// Extended dns
let mut edns: Edns = Edns::new();
// if secure {
// edns.set_dnssec_ok(true);
// message.authentic_data(true);
// message.checking_disabled(false);
// }
edns.set_max_payload(1500);
edns.set_version(0);
message.set_edns(edns);
// after all other updates to the message, sign it.
message.sign(signer, UTC::now().timestamp() as u32);
self.send_message(&message)
}
/// Sends a message to the server for which this client was defined
///
/// # Arguments
@ -1289,4 +1361,42 @@ mod test {
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
#[test]
fn test_delete_all() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN, &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rr_type(RecordType::AAAA);
record.rdata(RData::AAAA(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)));
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN, &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), RecordType::A).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
let result = client.query(record.get_name(), record.get_dns_class(), RecordType::AAAA).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
}