Merge branch 'master' into 0.9.0_release

This commit is contained in:
Benjamin Fry 2016-12-11 01:11:57 -08:00
commit 1f8ede233b
14 changed files with 939 additions and 413 deletions

View File

@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- new ServerFuture tokio and futures based server, #61
- UdpStream & TcpSteam to support stream of messages with src address
- TimeoutStream to wrap TcpStreams to help guard against malicious clients
- Added Notify support to ClientFuture
### Changed
- Split Server and Client into separate crates, #43

View File

@ -22,7 +22,7 @@ use tokio_core::reactor::{Handle, Timeout};
use ::error::*;
use ::op::{Message, MessageType, OpCode, Query, UpdateMessage};
use ::rr::{domain, DNSClass, RData, Record, RecordType};
use ::rr::{domain, DNSClass, IntoRecordSet, RData, Record, RecordType};
use ::rr::dnssec::Signer;
use ::rr::rdata::NULL;
@ -376,6 +376,101 @@ pub trait ClientHandle: Clone {
self.send(message)
}
/// Sends a NOTIFY message to the remote system
///
/// [RFC 1996](https://tools.ietf.org/html/rfc1996), DNS NOTIFY, August 1996
///
///
/// ```text
/// 1. Rationale and Scope
///
/// 1.1. Slow propagation of new and changed data in a DNS zone can be
/// due to a zone's relatively long refresh times. Longer refresh times
/// are beneficial in that they reduce load on the master servers, but
/// that benefit comes at the cost of long intervals of incoherence among
/// authority servers whenever the zone is updated.
///
/// 1.2. The DNS NOTIFY transaction allows master servers to inform slave
/// servers when the zone has changed -- an interrupt as opposed to poll
/// model -- which it is hoped will reduce propagation delay while not
/// unduly increasing the masters' load. This specification only allows
/// slaves to be notified of SOA RR changes, but the architechture of
/// NOTIFY is intended to be extensible to other RR types.
///
/// 1.3. This document intentionally gives more definition to the roles
/// of "Master," "Slave" and "Stealth" servers, their enumeration in NS
/// RRs, and the SOA MNAME field. In that sense, this document can be
/// considered an addendum to [RFC1035].
///
/// ```
///
/// The below section describes how the Notify message should be constructed. The function
/// implmentation accepts a Record, but the actual data of the record should be ignored by the
/// server, i.e. the server should make a request subsequent to receiving this Notification for
/// the authority record, but could be used to decide to request an update or not:
///
/// ```text
/// 3.7. A NOTIFY request has QDCOUNT>0, ANCOUNT>=0, AUCOUNT>=0,
/// ADCOUNT>=0. If ANCOUNT>0, then the answer section represents an
/// unsecure hint at the new RRset for this <QNAME,QCLASS,QTYPE>. A
/// slave receiving such a hint is free to treat equivilence of this
/// answer section with its local data as a "no further work needs to be
/// done" indication. If ANCOUNT=0, or ANCOUNT>0 and the answer section
/// differs from the slave's local data, then the slave should query its
/// known masters to retrieve the new data.
/// ```
///
/// Client's should be ready to handle, or be aware of, a server response of NOTIMP:
///
/// ```text
/// 3.12. If a NOTIFY request is received by a slave who does not
/// implement the NOTIFY opcode, it will respond with a NOTIMP
/// (unimplemented feature error) message. A master server who receives
/// such a NOTIMP should consider the NOTIFY transaction complete for
/// that slave.
/// ```
///
/// # Arguments
///
/// * `name` - the label which is being notified
/// * `query_class` - most likely this should always be DNSClass::IN
/// * `query_type` - record type which has been updated
/// * `rrset` - the new version of the record(s) being notified
fn notify<R>(&mut self, name: domain::Name, query_class: DNSClass, query_type: RecordType, rrset: Option<R>)
-> Box<Future<Item=Message, Error=ClientError>> where R: IntoRecordSet {
debug!("notifying: {} {:?}", name, query_type);
// build the message
let mut message: Message = Message::new();
let id: u16 = rand::random();
message.id(id)
// 3.3. NOTIFY is similar to QUERY in that it has a request message with
// the header QR flag "clear" and a response message with QR "set". The
// response message contains no useful information, but its reception by
// the master is an indication that the slave has received the NOTIFY
// and that the master can remove the slave from any retry queue for
// this NOTIFY event.
.message_type(MessageType::Query)
.op_code(OpCode::Notify);
// Extended dns
{
let edns = message.get_edns_mut();
edns.set_max_payload(1500);
edns.set_version(0);
}
// add the query
let mut query: Query = Query::new();
query.name(name.clone()).query_class(query_class).query_type(query_type);
message.add_query(query);
// add the notify message, see https://tools.ietf.org/html/rfc1996, section 3.7
if let Some(rrset) = rrset { message.add_answers(rrset.into_record_set()); }
self.send(message)
}
/// Sends a record to create on the server, this will fail if the record exists (atomicity
/// depends on the server)
///
@ -405,29 +500,32 @@ pub trait ClientHandle: Clone {
///
/// # Arguments
///
/// * `record` - the name of the record to create
/// * `rrset` - the record(s) to create
/// * `zone_origin` - the zone name to update, i.e. SOA name
///
/// The update must go to a zone authority (i.e. the server used in the ClientConnection)
fn create(&mut self,
record: Record,
zone_origin: domain::Name)
-> Box<Future<Item=Message, Error=ClientError>> {
assert!(zone_origin.zone_of(record.get_name()));
fn create<R>(&mut self,
rrset: R,
zone_origin: domain::Name)
-> Box<Future<Item=Message, Error=ClientError>>
where R: IntoRecordSet {
// TODO: assert non-empty rrset?
let rrset = rrset.into_record_set();
assert!(zone_origin.zone_of(rrset.get_name()));
// 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(RecordType::SOA);
zone.name(zone_origin).query_class(rrset.get_dns_class()).query_type(RecordType::SOA);
// build the message
let mut message: Message = Message::new();
message.id(rand::random()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.add_zone(zone);
let mut prerequisite = Record::with(record.get_name().clone(), record.get_rr_type(), 0);
let mut prerequisite = Record::with(rrset.get_name().clone(), rrset.get_record_type(), 0);
prerequisite.dns_class(DNSClass::NONE);
message.add_pre_requisite(prerequisite);
message.add_update(record);
message.add_updates(rrset);
// Extended dns
{
@ -467,22 +565,24 @@ pub trait ClientHandle: Clone {
///
/// # Arguments
///
/// * `record` - the record to append to an RRSet
/// * `rrset` - the record(s) to append to an RRSet
/// * `zone_origin` - the zone name to update, i.e. SOA name
/// * `must_exist` - if true, the request will fail if the record does not exist
///
/// The update must go to a zone authority (i.e. the server used in the ClientConnection). If
/// the rrset does not exist and must_exist is false, then the RRSet will be created.
fn append(&mut self,
record: Record,
zone_origin: domain::Name,
must_exist: bool)
-> Box<Future<Item=Message, Error=ClientError>> {
assert!(zone_origin.zone_of(record.get_name()));
fn append<R>(&mut self,
rrset: R,
zone_origin: domain::Name,
must_exist: bool)
-> Box<Future<Item=Message, Error=ClientError>>
where R: IntoRecordSet {
let rrset = rrset.into_record_set();
assert!(zone_origin.zone_of(rrset.get_name()));
// 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(RecordType::SOA);
zone.name(zone_origin).query_class(rrset.get_dns_class()).query_type(RecordType::SOA);
// build the message
let mut message: Message = Message::new();
@ -490,12 +590,12 @@ pub trait ClientHandle: Clone {
message.add_zone(zone);
if must_exist {
let mut prerequisite = Record::with(record.get_name().clone(), record.get_rr_type(), 0);
let mut prerequisite = Record::with(rrset.get_name().clone(), rrset.get_record_type(), 0);
prerequisite.dns_class(DNSClass::ANY);
message.add_pre_requisite(prerequisite);
}
message.add_update(record);
message.add_updates(rrset);
// Extended dns
{
@ -543,16 +643,21 @@ pub trait ClientHandle: Clone {
///
/// # Arguements
///
/// * `current` - the current current which must exist for the swap to complete
/// * `new` - the new record with which to replace the current record
/// * `current` - the current rrset which must exist for the swap to complete
/// * `new` - the new rrset with which to replace the current rrset
/// * `zone_origin` - the zone name to update, i.e. SOA name
///
/// The update must go to a zone authority (i.e. the server used in the ClientConnection).
fn compare_and_swap(&mut self,
current: Record,
new: Record,
zone_origin: domain::Name)
-> Box<Future<Item=Message, Error=ClientError>> {
fn compare_and_swap<C,N>(&mut self,
current: C,
new: N,
zone_origin: domain::Name)
-> Box<Future<Item=Message, Error=ClientError>>
where C: IntoRecordSet,
N: IntoRecordSet {
let current = current.into_record_set();
let new = new.into_record_set();
assert!(zone_origin.zone_of(current.get_name()));
assert!(zone_origin.zone_of(new.get_name()));
@ -567,19 +672,19 @@ pub trait ClientHandle: Clone {
// make sure the record is what is expected
let mut prerequisite = current.clone();
prerequisite.ttl(0);
message.add_pre_requisite(prerequisite);
prerequisite.set_ttl(0);
message.add_pre_requisites(prerequisite);
// add the delete for the old record
let mut delete = current;
// the class must be none for delete
delete.dns_class(DNSClass::NONE);
// the TTL shoudl be 0
delete.ttl(0);
message.add_update(delete);
delete.set_dns_class(DNSClass::NONE);
// the TTL should be 0
delete.set_ttl(0);
message.add_updates(delete);
// insert the new record...
message.add_update(new);
message.add_updates(new);
// Extended dns
{
@ -620,22 +725,24 @@ pub trait ClientHandle: Clone {
///
/// # Arguments
///
/// * `record` - the record to delete from a RRSet, the name, type and rdata must match the
/// * `rrset` - the record(s) to delete from a RRSet, the name, type and rdata must match the
/// record to delete
/// * `zone_origin` - the zone name to update, i.e. SOA name
/// * `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). If
/// the rrset does not exist and must_exist is false, then the RRSet will be deleted.
fn delete_by_rdata(&mut self,
mut record: Record,
zone_origin: domain::Name)
-> Box<Future<Item=Message, Error=ClientError>> {
assert!(zone_origin.zone_of(record.get_name()));
fn delete_by_rdata<R>(&mut self,
rrset: R,
zone_origin: domain::Name)
-> Box<Future<Item=Message, Error=ClientError>>
where R: IntoRecordSet {
let mut rrset = rrset.into_record_set();
assert!(zone_origin.zone_of(rrset.get_name()));
// 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(RecordType::SOA);
zone.name(zone_origin).query_class(rrset.get_dns_class()).query_type(RecordType::SOA);
// build the message
let mut message: Message = Message::new();
@ -643,10 +750,10 @@ pub trait ClientHandle: Clone {
message.add_zone(zone);
// the class must be none for delete
record.dns_class(DNSClass::NONE);
rrset.set_dns_class(DNSClass::NONE);
// the TTL shoudl be 0
record.ttl(0);
message.add_update(record);
rrset.set_ttl(0);
message.add_updates(rrset);
// Extended dns
{
@ -687,8 +794,7 @@ pub trait ClientHandle: Clone {
///
/// # Arguments
///
/// * `record` - the record to delete from a RRSet, the name, and type must match the
/// record set to delete
/// * `record` - The name, class and record_type will be used to match and delete the RecordSet
/// * `zone_origin` - the zone name to update, i.e. SOA name
/// * `signer` - the signer, with private key, to use to sign the request
///

View File

@ -123,6 +123,7 @@ impl Message {
/// it's unclear how it could be useful to have more than one here? change this to set
/// a single query?
pub fn add_query(&mut self, query: Query) -> &mut Self { self.queries.push(query); self }
#[deprecated = "will be removed post 0.9.x"]
pub fn add_all_queries(&mut self, queries: &[Query]) -> &mut Self {
for q in queries {
// TODO: the clone here should really be performed (or not) by the caller
@ -130,7 +131,18 @@ impl Message {
}
self
}
pub fn add_queries<Q, I>(&mut self, queries: Q) -> &mut Self
where Q: IntoIterator<Item=Query, IntoIter=I>,
I: Iterator<Item=Query> {
for query in queries {
self.add_query(query);
}
self
}
pub fn add_answer(&mut self, record: Record) -> &mut Self { self.answers.push(record); self }
#[deprecated = "will be removed post 0.9.x"]
pub fn add_all_answers(&mut self, vector: &[&Record]) -> &mut Self {
for &r in vector {
// TODO: in order to get rid of this clone, we need an owned Message for decoding, and a
@ -139,6 +151,15 @@ impl Message {
}
self
}
pub fn add_answers<R, I>(&mut self, records: R) -> &mut Self
where R: IntoIterator<Item=Record, IntoIter=I>,
I: Iterator<Item=Record> {
for record in records {
self.add_answer(record);
}
self
}
/// Sets the answers to the specified set of Records.
///
@ -151,6 +172,7 @@ impl Message {
}
pub fn add_name_server(&mut self, record: Record) -> &mut Self { self.name_servers.push(record); self }
#[deprecated = "will be removed post 0.9.x"]
pub fn add_all_name_servers(&mut self, vector: &[&Record]) -> &mut Self {
for &r in vector {
// TODO: in order to get rid of this clone, we need an owned Message for decoding, and a
@ -159,6 +181,15 @@ impl Message {
}
self
}
pub fn add_name_servers<R, I>(&mut self, records: R) -> &mut Self
where R: IntoIterator<Item=Record, IntoIter=I>,
I: Iterator<Item=Record> {
for record in records {
self.add_name_server(record);
}
self
}
/// Sets the name_servers to the specified set of Records.
///
@ -464,9 +495,17 @@ pub trait UpdateMessage: Debug {
fn get_id(&self) -> u16;
fn add_zone(&mut self, query: Query);
fn add_pre_requisite(&mut self, record: Record);
#[deprecated = "will be removed post 0.9.x"]
fn add_all_pre_requisites(&mut self, vector: &[&Record]);
fn add_pre_requisites<R,I>(&mut self, records: R)
where R: IntoIterator<Item=Record, IntoIter=I>,
I: Iterator<Item=Record>;
fn add_update(&mut self, record: Record);
#[deprecated = "will be removed post 0.9.x"]
fn add_all_updates(&mut self, vector: &[&Record]);
fn add_updates<R,I>(&mut self, records: R)
where R: IntoIterator<Item=Record, IntoIter=I>,
I: Iterator<Item=Record>;
fn add_additional(&mut self, record: Record);
fn get_zones(&self) -> &[Query];
@ -488,9 +527,19 @@ impl UpdateMessage for Message {
fn get_id(&self) -> u16 { self.get_id() }
fn add_zone(&mut self, query: Query) { self.add_query(query); }
fn add_pre_requisite(&mut self, record: Record) { self.add_answer(record); }
fn add_all_pre_requisites(&mut self, vector: &[&Record]) { self.add_all_answers(vector); }
fn add_all_pre_requisites(&mut self, vector: &[&Record]) { self.add_answers(vector.into_iter().map(|r| (*r).clone())); }
fn add_pre_requisites<R,I>(&mut self, records: R)
where R: IntoIterator<Item=Record, IntoIter=I>,
I: Iterator<Item=Record> {
self.add_answers(records);
}
fn add_update(&mut self, record: Record) { self.add_name_server(record); }
fn add_all_updates(&mut self, vector: &[&Record]) { self.add_all_name_servers(vector); }
fn add_all_updates(&mut self, vector: &[&Record]) { self.add_name_servers(vector.into_iter().map(|r| (*r).clone())); }
fn add_updates<R,I>(&mut self, records: R)
where R: IntoIterator<Item=Record, IntoIter=I>,
I: Iterator<Item=Record> {
self.add_name_servers(records);
}
fn add_additional(&mut self, record: Record) { self.add_additional(record); }
fn get_zones(&self) -> &[Query] { self.get_queries() }

View File

@ -519,6 +519,7 @@ mod tests {
use std::cmp::Ordering;
use ::serialize::binary::bin_tests::{test_read_data_set, test_emit_data_set};
#[allow(unused)]
use ::serialize::binary::*;
fn get_data() -> Vec<(Name, Vec<u8>)> {

View File

@ -32,4 +32,8 @@ pub use self::record_data::RData;
pub use self::record_type::RecordType;
pub use self::resource::Record;
pub use self::rr_key::RrKey;
pub use self::rr_set::RrSet;
pub use self::rr_set::IntoRecordSet;
pub use self::rr_set::RecordSet;
#[deprecated = "will be removed post 0.9.x, use RecordSet"]
pub type RrSet = RecordSet;

View File

@ -758,9 +758,33 @@ impl RData {
RData::TXT(ref txt) => rdata::txt::emit(encoder, txt),
}
}
pub fn to_record_type(&self) -> RecordType {
match *self {
RData::A(..) => RecordType::A,
RData::AAAA(..) => RecordType::AAAA,
RData::CNAME(..) => RecordType::CNAME,
RData::DS(..) => RecordType::DS,
RData::KEY(..) => RecordType::KEY,
RData::DNSKEY(..) => RecordType::DNSKEY,
RData::MX(..) => RecordType::MX,
RData::NS(..) => RecordType::NS,
RData::NSEC(..) => RecordType::NSEC,
RData::NSEC3(..) => RecordType::NSEC3,
RData::NSEC3PARAM(..) => RecordType::NSEC3PARAM,
RData::NULL(..) => RecordType::NULL,
RData::OPT(..) => RecordType::OPT,
RData::PTR(..) => RecordType::PTR,
RData::SIG(..) => RecordType::SIG,
RData::SOA(..) => RecordType::SOA,
RData::SRV(..) => RecordType::SRV,
RData::TXT(..) => RecordType::TXT,
}
}
}
// TODO: this is kinda broken right now since it can't cover all types.
#[deprecated]
#[cfg(test)]
impl<'a> From<&'a RData> for RecordType {
fn from(rdata: &'a RData) -> Self {
@ -826,6 +850,7 @@ mod tests {
use std::str::FromStr;
use super::*;
#[allow(unused)]
use ::serialize::binary::*;
use ::serialize::binary::bin_tests::test_emit_data_set;
use ::rr::domain::Name;

View File

@ -21,12 +21,13 @@ use std::cmp::Ordering;
use ::serialize::binary::*;
use ::error::*;
use ::rr::dns_class::DNSClass;
use ::rr::domain;
use ::rr::IntoRecordSet;
use ::rr::rdata::NULL;
use super::record_data::RData;
use super::record_type::RecordType;
use super::dns_class::DNSClass;
use super::domain;
use ::rr::RData;
use ::rr::RecordType;
use ::rr::RecordSet;
/// Resource records are storage value in DNS, into which all key/value pair data is stored.
///
@ -149,6 +150,12 @@ impl Record {
pub fn unwrap_rdata(self) -> RData { self.rdata }
}
impl IntoRecordSet for Record {
fn into_record_set(self) -> RecordSet {
RecordSet::from(self)
}
}
impl BinSerializable<Record> for Record {
/// parse a resource record line example:
/// WARNING: the record_bytes is 100% consumed and destroyed in this parsing process
@ -321,7 +328,7 @@ mod tests {
use std::cmp::Ordering;
use super::*;
#[allow(unused)]
use ::serialize::binary::*;
use ::rr::record_data::RData;
use ::rr::record_type::RecordType;

View File

@ -4,28 +4,31 @@
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use std::slice::Iter;
use std::iter::Chain;
use std::slice::Iter;
use std::vec;
use ::rr::{Name, Record, RecordType, RData};
use ::rr::{DNSClass, Name, Record, RecordType, RData};
/// Set of resource records associated to a name and type
#[derive(Debug, PartialEq)]
pub struct RrSet {
#[derive(Clone, Debug, PartialEq)]
pub struct RecordSet {
name: Name,
record_type: RecordType,
dns_class: DNSClass,
ttl: u32,
records: Vec<Record>,
rrsigs: Vec<Record>,
serial: u32, // serial number at which this record was modified
}
impl RrSet {
impl RecordSet {
/// Creates a new Resource Record Set.
///
/// # Arguments
///
/// * `name` - The label for the `RrSet`
/// * `record_type` - `RecordType` of this `RrSet`, all records in the `RrSet` must be of the
/// * `name` - The label for the `RecordSet`
/// * `record_type` - `RecordType` of this `RecordSet`, all records in the `RecordSet` must be of the
/// specified `RecordType`.
/// * `serial` - current serial number of the `SOA` record, this is to be used for `IXFR` and
/// signing for DNSSec after updates.
@ -34,8 +37,48 @@ impl RrSet {
///
/// The newly created Resource Record Set
/// TODO: make all cloned params pass by value
pub fn new(name: &Name, record_type: RecordType, serial: u32) -> RrSet {
RrSet{name: name.clone(), record_type: record_type, ttl: 0, records: Vec::new(), rrsigs: Vec::new(), serial: serial}
pub fn new(name: &Name, record_type: RecordType, serial: u32) -> Self {
RecordSet{name: name.clone(), record_type: record_type, dns_class: DNSClass::IN,
ttl: 0, records: Vec::new(), rrsigs: Vec::new(), serial: serial}
}
/// Creates a new Resource Record Set.
///
/// # Arguments
///
/// * `name` - The label for the `RecordSet`
/// * `record_type` - `RecordType` of this `RecordSet`, all records in the `RecordSet` must be of the
/// specified `RecordType`.
/// * `ttl` - time-to-live for the `RecordSet` in seconds.
///
/// # Return value
///
/// The newly created Resource Record Set
/// TODO: make all cloned params pass by value
pub fn with_ttl(name: Name, record_type: RecordType, ttl: u32) -> Self {
RecordSet{name: name, record_type: record_type, dns_class: DNSClass::IN,
ttl: ttl, records: Vec::new(), rrsigs: Vec::new(), serial: 0}
}
/// Creates a new Resource Record Set from a Record
///
/// # Arguments
///
/// * `record` - initializes a record set with a single record
///
/// # Return value
///
/// The newly created Resource Record Set
pub fn from(record: Record) -> Self {
RecordSet {
name: record.get_name().clone(),
record_type: record.get_rr_type(),
dns_class: record.get_dns_class(),
ttl: record.get_ttl(),
records: vec![record],
rrsigs: vec![],
serial: 0,
}
}
/// # Return value
@ -52,10 +95,37 @@ impl RrSet {
self.record_type
}
/// Sets the DNSClass to the specified value
///
/// This will traverse every record and associate with it the specified dns_class
pub fn set_dns_class(&mut self, dns_class: DNSClass) {
self.dns_class = dns_class;
for r in self.records.iter_mut() {
r.dns_class(dns_class);
}
}
/// # Return value
///
/// `DNSClass` of the RecordSet
pub fn get_dns_class(&self) -> DNSClass {
self.dns_class
}
/// Sets the TTL, in seconds, to the specified value
///
/// This will traverse every record and associate with it the specified ttl
pub fn set_ttl(&mut self, ttl: u32) {
self.ttl = ttl;
for r in self.records.iter_mut() {
r.ttl(ttl);
}
}
/// # Return value
///
/// TTL, time-to-live, of the Resource Record Set, this is the maximum length of time that an
/// RrSet should be cached.
/// RecordSet should be cached.
pub fn get_ttl(&self) -> u32 {
self.ttl
}
@ -107,6 +177,19 @@ impl RrSet {
self.rrsigs.clear(); // on updates, the rrsigs are invalid
}
/// creates a new Record as part of this RecordSet, adding the associated RData
pub fn new_record(&mut self, rdata: RData) -> &Record {
assert_eq!(self.record_type, rdata.to_record_type());
let mut record = Record::with(self.name.clone(),
self.record_type,
self.ttl);
record.rdata(rdata.clone()); // TODO: remove clone()? this is only needed for the record return
self.insert(record, 0);
self.records.iter().find(|r| *r.get_rdata() == rdata).expect("insert failed? 172")
}
/// Inserts a new Resource Record into the Set.
///
/// If the record is inserted, the ttl for the most recent record will be used for the ttl of
@ -130,7 +213,7 @@ impl RrSet {
///
/// # Arguments
///
/// * `record` - `Record` asserts that the `name` and `record_type` match the `RrSet`.
/// * `record` - `Record` asserts that the `name` and `record_type` match the `RecordSet`.
/// * `serial` - current serial number of the `SOA` record, this is to be used for `IXFR` and
/// signing for DNSSec after updates. The serial will only be updated if the
/// record was added.
@ -138,6 +221,8 @@ impl RrSet {
/// # Return value
///
/// True if the record was inserted.
///
/// FIXME: make a default add without serial number for basic usage
pub fn insert(&mut self, record: Record, serial: u32) -> bool {
assert_eq!(record.get_name(), &self.name);
assert_eq!(record.get_rr_type(), self.record_type);
@ -178,7 +263,7 @@ impl RrSet {
// CNAME compare only NAME, CLASS, and TYPE -- it is not possible
// to have more than one CNAME RR, even if their data fields
// differ.
RecordType::CNAME => {
RecordType::CNAME => {
assert!(self.records.len() <= 1);
self.records.clear();
},
@ -220,7 +305,7 @@ impl RrSet {
///
/// # Arguments
///
/// * `record` - `Record` asserts that the `name` and `record_type` match the `RrSet`. Removes
/// * `record` - `Record` asserts that the `name` and `record_type` match the `RecordSet`. Removes
/// any `record` if the record data, `RData`, match.
/// * `serial` - current serial number of the `SOA` record, this is to be used for `IXFR` and
/// signing for DNSSec after updates. The serial will only be updated if the
@ -266,6 +351,23 @@ impl RrSet {
}
}
pub trait IntoRecordSet: Sized {
fn into_record_set(self) -> RecordSet;
}
impl IntoRecordSet for RecordSet {
fn into_record_set(self) -> Self { self }
}
impl IntoIterator for RecordSet {
type Item = Record;
type IntoIter = Chain<vec::IntoIter<Record>, vec::IntoIter<Record>>;
fn into_iter(self) -> Self::IntoIter {
self.records.into_iter().chain(self.rrsigs.into_iter())
}
}
#[cfg(test)]
mod test {
use std::net::Ipv4Addr;
@ -276,7 +378,7 @@ mod test {
fn test_insert() {
let name = Name::new().label("www").label("example").label("com");
let record_type = RecordType::A;
let mut rr_set = RrSet::new(&name, record_type, 0);
let mut rr_set = RecordSet::new(&name, record_type, 0);
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();
@ -301,7 +403,7 @@ mod test {
fn test_insert_soa() {
let name = Name::new().label("example").label("com");
let record_type = RecordType::SOA;
let mut rr_set = RrSet::new(&name, record_type, 0);
let mut rr_set = RecordSet::new(&name, record_type, 0);
let insert = 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.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone();
let same_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(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone();
@ -330,7 +432,7 @@ mod test {
let new_cname = Name::new().label("w2").label("example").label("com");
let record_type = RecordType::CNAME;
let mut rr_set = RrSet::new(&name, record_type, 0);
let mut rr_set = RecordSet::new(&name, record_type, 0);
let insert = Record::new().name(name.clone()).ttl(3600).rr_type(RecordType::CNAME).dns_class(DNSClass::IN).rdata(RData::CNAME(cname.clone()) ).clone();
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();
@ -348,7 +450,7 @@ mod test {
fn test_remove() {
let name = Name::new().label("www").label("example").label("com");
let record_type = RecordType::A;
let mut rr_set = RrSet::new(&name, record_type, 0);
let mut rr_set = RecordSet::new(&name, record_type, 0);
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();
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();
@ -366,7 +468,7 @@ mod test {
fn test_remove_soa() {
let name = Name::new().label("example").label("com");
let record_type = RecordType::SOA;
let mut rr_set = RrSet::new(&name, record_type, 0);
let mut rr_set = RecordSet::new(&name, record_type, 0);
let insert = 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.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone();
@ -379,7 +481,7 @@ mod test {
fn test_remove_ns() {
let name = Name::new().label("example").label("com");
let record_type = RecordType::NS;
let mut rr_set = RrSet::new(&name, record_type, 0);
let mut rr_set = RecordSet::new(&name, record_type, 0);
let ns1 = Record::new().name(name.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()) ).clone();
let ns2 = Record::new().name(name.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()) ).clone();

View File

@ -16,7 +16,7 @@
use std::collections::BTreeMap;
use ::error::*;
use ::rr::{ Name, RecordType, Record, DNSClass, RData, RrKey, RrSet};
use ::rr::{ Name, IntoRecordSet, RecordType, Record, DNSClass, RData, RrKey, RecordSet };
use super::master_lex::{Lexer, Token};
@ -128,9 +128,9 @@ impl Parser {
}
// TODO: change this function to load into an Authority, using the update_records() method
pub fn parse(&mut self, lexer: Lexer, origin: Option<Name>) -> ParseResult<(Name, BTreeMap<RrKey, RrSet>)> {
pub fn parse(&mut self, lexer: Lexer, origin: Option<Name>) -> ParseResult<(Name, BTreeMap<RrKey, RecordSet>)> {
let mut lexer = lexer;
let mut records: BTreeMap<RrKey, RrSet> = BTreeMap::new();
let mut records: BTreeMap<RrKey, RecordSet> = BTreeMap::new();
let mut origin: Option<Name> = origin;
let mut current_name: Option<Name> = None;
@ -269,15 +269,14 @@ impl Parser {
match rtype.unwrap() {
RecordType::SOA => {
let mut set = RrSet::new(record.get_name(), record.get_rr_type(), 0);
set.insert(record, 0);
let set = record.into_record_set();
if records.insert(key, set).is_some() {
return Err(ParseErrorKind::Message("SOA is already specified").into());
}
},
_ => {
// add a Vec if it's not there, then add the record to the list
let mut set = records.entry(key).or_insert(RrSet::new(record.get_name(), record.get_rr_type(), 0));
let mut set = records.entry(key).or_insert(RecordSet::new(record.get_name(), record.get_rr_type(), 0));
set.insert(record, 0);
},
}

View File

@ -1,5 +1,6 @@
extern crate chrono;
extern crate futures;
extern crate log;
extern crate openssl;
extern crate tokio_core;
extern crate trust_dns;
@ -22,7 +23,7 @@ use trust_dns::client::{ClientFuture, BasicClientHandle, ClientHandle, ClientStr
use trust_dns::error::*;
use trust_dns::op::ResponseCode;
use trust_dns::rr::domain;
use trust_dns::rr::{DNSClass, RData, Record, RecordType};
use trust_dns::rr::{DNSClass, IntoRecordSet, RData, Record, RecordType, RecordSet};
use trust_dns::rr::dnssec::{Algorithm, Signer};
use trust_dns::rr::rdata::*;
use trust_dns::udp::UdpClientStream;
@ -116,25 +117,43 @@ fn test_query(client: &mut BasicClientHandle) -> Box<Future<Item=(), Error=()>>
let name = domain::Name::with_labels(vec!["WWW".to_string(), "example".to_string(), "com".to_string()]);
Box::new(client.query(name.clone(), DNSClass::IN, RecordType::A)
.map(move |response| {
println!("response records: {:?}", response);
assert_eq!(response.get_queries().first().expect("expected query").get_name().cmp_with_case(&name, false), Ordering::Equal);
.map(move |response| {
println!("response records: {:?}", response);
assert_eq!(response.get_queries().first().expect("expected query").get_name().cmp_with_case(&name, false), Ordering::Equal);
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);
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);
}
})
.map_err(|e| {
assert!(false, "query failed: {}", e);
})
)
if let &RData::A(ref address) = record.get_rdata() {
assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
} else {
assert!(false);
}
})
.map_err(|e| {
assert!(false, "query failed: {}", e);
})
)
}
#[test]
fn test_notify() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut io_loop = Core::new().unwrap();
let (stream, sender) = TestClientStream::new(catalog);
let mut client = ClientFuture::new(stream, sender, io_loop.handle(), None);
let name = domain::Name::with_labels(vec!["ping".to_string(), "example".to_string(), "com".to_string()]);
let message = io_loop.run(client.notify(name.clone(), DNSClass::IN, RecordType::A, None::<RecordSet>));
assert!(message.is_ok());
let message = message.unwrap();
assert_eq!(message.get_response_code(), ResponseCode::NotImp, "the catalog must support Notify now, update this");
}
// update tests
@ -149,313 +168,523 @@ fn create_sig0_ready_client(io_loop: &Core) -> (BasicClientHandle, domain::Name)
let rsa = RSA::generate(512).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
rsa,
domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
Duration::max_value());
rsa,
domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
Duration::max_value());
// insert the KEY for the trusted.example.com
let mut auth_key = Record::with(domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
RecordType::KEY,
Duration::minutes(5).num_seconds() as u32);
auth_key.rdata(RData::KEY(DNSKEY::new(false, false, false, signer.get_algorithm(), signer.get_public_key())));
authority.upsert(auth_key, 0);
// insert the KEY for the trusted.example.com
let mut auth_key = Record::with(domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
RecordType::KEY,
Duration::minutes(5).num_seconds() as u32);
auth_key.rdata(RData::KEY(DNSKEY::new(false, false, false, signer.get_algorithm(), signer.get_public_key())));
authority.upsert(auth_key, 0);
// setup the catalog
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
// setup the catalog
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let (stream, sender) = TestClientStream::new(catalog);
let client = ClientFuture::new(stream, sender, io_loop.handle(), Some(signer));
let (stream, sender) = TestClientStream::new(catalog);
let client = ClientFuture::new(stream, sender, io_loop.handle(), Some(signer));
(client, origin)
(client, origin)
}
#[test]
fn test_create() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// create 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)));
let record = record;
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// trying to create again should error
// TODO: it would be cool to make this
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
// will fail if already set and not the same value.
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
}
#[test]
fn test_create_multi() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// create 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)));
let record = record;
let mut record2 = record.clone();
record2.rdata(RData::A(Ipv4Addr::new(100,10,100,11)));
let record2 = record2;
let mut rrset = record.clone().into_record_set();
rrset.insert(record2.clone(), 0);
let rrset = rrset;
let result = io_loop.run(client.create(rrset.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
assert!(result.get_answers().iter().any(|rr| *rr == record));
assert!(result.get_answers().iter().any(|rr| *rr == record2));
// trying to create again should error
// TODO: it would be cool to make this
let result = io_loop.run(client.create(rrset, origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
// will fail if already set and not the same value.
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,12)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
}
#[test]
fn test_append() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// 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)));
let record = record;
// first check the must_exist option
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
// next append to a non-existent RRset
let result = io_loop.run(client.append(record.clone(), origin.clone(), false)).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// will fail if already set and not the same value.
let mut record2 = record.clone();
record2.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let record2 = record2;
let result = io_loop.run(client.append(record2.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
assert!(result.get_answers().iter().any(|rr| *rr == record));
assert!(result.get_answers().iter().any(|rr| *rr == record2));
// show that appending the same thing again is ok, but doesn't add any records
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
}
#[test]
fn test_append_multi() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// 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 = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
// next append to a non-existent RRset
let result = io_loop.run(client.append(record.clone(), origin.clone(), false)).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// will fail if already set and not the same value.
let mut record2 = record.clone();
record2.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let mut record3 = record.clone();
record3.rdata(RData::A(Ipv4Addr::new(101,11,101,12)));
// build the append set
let mut rrset = record2.clone().into_record_set();
rrset.insert(record3.clone(), 0);
let result = io_loop.run(client.append(rrset, origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 3);
assert!(result.get_answers().iter().any(|rr| *rr == record));
assert!(result.get_answers().iter().any(|rr| *rr == record2));
assert!(result.get_answers().iter().any(|rr| *rr == record3));
// show that appending the same thing again is ok, but doesn't add any records
// TODO: technically this is a test for the Server, not client...
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 3);
}
#[test]
fn test_compare_and_swap() {
use log::LogLevel;
use trust_dns;
trust_dns::logger::TrustDnsLogger::enable_logging(LogLevel::Debug);
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// create 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)));
let record = record;
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let current = record;
let mut new = current.clone();
new.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let new = new;
let result = io_loop.run(client.compare_and_swap(current.clone(), new.clone(), origin.clone())).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(new.get_name().clone(), new.get_dns_class(), new.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| *rr == new));
assert!(!result.get_answers().iter().any(|rr| *rr == current));
// check the it fails if tried again.
let mut not = new.clone();
not.rdata(RData::A(Ipv4Addr::new(102,12,102,12)));
let not = not;
let result = io_loop.run(client.compare_and_swap(current, not.clone(), origin.clone())).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
let result = io_loop.run(client.query(new.get_name().clone(), new.get_dns_class(), new.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| *rr == new));
assert!(!result.get_answers().iter().any(|rr| *rr == not));
}
#[test]
fn test_compare_and_swap_multi() {
use log::LogLevel;
use trust_dns;
trust_dns::logger::TrustDnsLogger::enable_logging(LogLevel::Debug);
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// create a record
let mut current = RecordSet::with_ttl(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
let current1 = current.new_record(RData::A(Ipv4Addr::new(100,10,100,10))).clone();
let current2 = current.new_record(RData::A(Ipv4Addr::new(100,10,100,11))).clone();
let current = current;
let result = io_loop.run(client.create(current.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut new = RecordSet::with_ttl(current.get_name().clone(), current.get_record_type(), current.get_ttl());
let new1 = new.new_record(RData::A(Ipv4Addr::new(100,10,101,10))).clone();
let new2 = new.new_record(RData::A(Ipv4Addr::new(100,10,101,11))).clone();
let new = new;
let result = io_loop.run(client.compare_and_swap(current.clone(), new.clone(), origin.clone())).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(new.get_name().clone(), new.get_dns_class(), new.get_record_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
assert!(result.get_answers().iter().any(|rr| *rr == new1));
assert!(result.get_answers().iter().any(|rr| *rr == new2));
assert!(!result.get_answers().iter().any(|rr| *rr == current1));
assert!(!result.get_answers().iter().any(|rr| *rr == current2));
// check the it fails if tried again.
let mut not = new1.clone();
not.rdata(RData::A(Ipv4Addr::new(102,12,102,12)));
let not = not;
let result = io_loop.run(client.compare_and_swap(current, not.clone(), origin.clone())).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
let result = io_loop.run(client.query(new.get_name().clone(), new.get_dns_class(), new.get_record_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
assert!(result.get_answers().iter().any(|rr| *rr == new1));
assert!(!result.get_answers().iter().any(|rr| *rr == not));
}
#[test]
fn test_delete_by_rdata() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// append a record
let mut record1 = 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);
record1.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = io_loop.run(client.delete_by_rdata(record1.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record1.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record2 = record1.clone();
record2.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.append(record2.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_by_rdata(record2.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record1.get_name().clone(), record1.get_dns_class(), record1.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| *rr == record1));
}
#[test]
fn test_delete_by_rdata_multi() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// append a record
let mut rrset = RecordSet::with_ttl(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
let record1 = rrset.new_record(RData::A(Ipv4Addr::new(100,10,100,10))).clone();
let record2 = rrset.new_record(RData::A(Ipv4Addr::new(100,10,100,11))).clone();
let record3 = rrset.new_record(RData::A(Ipv4Addr::new(100,10,100,12))).clone();
let record4 = rrset.new_record(RData::A(Ipv4Addr::new(100,10,100,13))).clone();
let rrset = rrset;
// first check the must_exist option
let result = io_loop.run(client.delete_by_rdata(rrset.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(rrset.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// append a record
let mut rrset = RecordSet::with_ttl(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
let record1 = rrset.new_record(record1.get_rdata().clone()).clone();
let record3 = rrset.new_record(record3.get_rdata().clone()).clone();
let rrset = rrset;
let result = io_loop.run(client.append(rrset.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_by_rdata(rrset.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record1.get_name().clone(), record1.get_dns_class(), record1.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
assert!(!result.get_answers().iter().any(|rr| *rr == record1));
assert!(result.get_answers().iter().any(|rr| *rr == record2));
assert!(!result.get_answers().iter().any(|rr| *rr == record3));
assert!(result.get_answers().iter().any(|rr| *rr == record4));
}
#[test]
fn test_delete_rrset() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// 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 = io_loop.run(client.delete_rrset(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_rrset(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
#[test]
fn test_delete_all() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// 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 = io_loop.run(client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN)).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record.clone(), origin.clone())).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 = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN)).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), 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 = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), RecordType::AAAA)).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
// need to do something with the message channel, otherwise the ClientFuture will think there
// is no one listening to messages and shutdown...
#[allow(dead_code)]
pub struct NeverReturnsClientStream {
outbound_messages: Fuse<UnboundedReceiver<Vec<u8>>>,
}
impl NeverReturnsClientStream {
pub fn new() -> (Box<Future<Item=Self, Error=io::Error>>, Box<ClientStreamHandle>) {
let (message_sender, outbound_messages) = unbounded();
let stream: Box<Future<Item=NeverReturnsClientStream, Error=io::Error>> = Box::new(finished(
NeverReturnsClientStream {
outbound_messages: outbound_messages.fuse()
}
));
(stream, Box::new(message_sender))
}
}
impl Stream for NeverReturnsClientStream {
type Item = Vec<u8>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
// always not ready...
park().unpark();
Ok(Async::NotReady)
}
}
impl fmt::Debug for NeverReturnsClientStream {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TestClientStream catalog")
}
}
#[test]
fn test_timeout_query_nonet() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut io_loop = Core::new().unwrap();
let (stream, sender) = NeverReturnsClientStream::new();
let mut client = ClientFuture::with_timeout(stream, sender, io_loop.handle(),
std::time::Duration::from_millis(1), None);
let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
if let &ClientErrorKind::Timeout = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A)).unwrap_err().kind() {
()
} else {
assert!(false);
}
#[test]
fn test_create() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// create 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)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// trying to create again should error
// TODO: it would be cool to make this
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
// will fail if already set and not the same value.
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
}
#[test]
fn test_append() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// 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 = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
// next append to a non-existent RRset
let result = io_loop.run(client.append(record.clone(), origin.clone(), false)).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// will fail if already set and not the same value.
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(100,10,100,10) } else { false }));
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
// show that appending the same thing again is ok, but doesn't add any records
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
}
#[test]
fn test_compare_and_swap() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// create 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)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let current = record;
let mut new = current.clone();
new.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.compare_and_swap(current.clone(), new.clone(), origin.clone())).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(new.get_name().clone(), new.get_dns_class(), new.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
// check the it fails if tried again.
let mut new = new;
new.rdata(RData::A(Ipv4Addr::new(102,12,102,12)));
let result = io_loop.run(client.compare_and_swap(current, new.clone(), origin.clone())).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
let result = io_loop.run(client.query(new.get_name().clone(), new.get_dns_class(), new.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
}
#[test]
fn test_delete_by_rdata() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// 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 = io_loop.run(client.delete_by_rdata(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_by_rdata(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(100,10,100,10) } else { false }));
}
#[test]
fn test_delete_rrset() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// 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 = io_loop.run(client.delete_rrset(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_rrset(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
#[test]
fn test_delete_all() {
let mut io_loop = Core::new().unwrap();
let (mut client, origin) = create_sig0_ready_client(&io_loop);
// 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 = io_loop.run(client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN)).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record.clone(), origin.clone())).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 = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN)).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), 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 = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), RecordType::AAAA)).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
// need to do something with the message channel, otherwise the ClientFuture will think there
// is no one listening to messages and shutdown...
#[allow(dead_code)]
pub struct NeverReturnsClientStream {
outbound_messages: Fuse<UnboundedReceiver<Vec<u8>>>,
}
impl NeverReturnsClientStream {
pub fn new() -> (Box<Future<Item=Self, Error=io::Error>>, Box<ClientStreamHandle>) {
let (message_sender, outbound_messages) = unbounded();
let stream: Box<Future<Item=NeverReturnsClientStream, Error=io::Error>> = Box::new(finished(
NeverReturnsClientStream {
outbound_messages: outbound_messages.fuse()
}
));
(stream, Box::new(message_sender))
}
}
impl Stream for NeverReturnsClientStream {
type Item = Vec<u8>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
// always not ready...
park().unpark();
Ok(Async::NotReady)
}
}
impl fmt::Debug for NeverReturnsClientStream {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TestClientStream catalog")
}
}
#[test]
fn test_timeout_query_nonet() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut io_loop = Core::new().unwrap();
let (stream, sender) = NeverReturnsClientStream::new();
let mut client = ClientFuture::with_timeout(stream, sender, io_loop.handle(),
std::time::Duration::from_millis(1), None);
let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
if let &ClientErrorKind::Timeout = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A)).unwrap_err().kind() {
()
} else {
assert!(false);
}
// test that we don't have any thing funky with registering new timeouts, etc...
if let &ClientErrorKind::Timeout = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::AAAA)).unwrap_err().kind() {
()
} else {
assert!(false);
}
// test that we don't have any thing funky with registering new timeouts, etc...
if let &ClientErrorKind::Timeout = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::AAAA)).unwrap_err().kind() {
()
} else {
assert!(false);
}
}

View File

@ -192,6 +192,7 @@ fn bind_process() -> (NamedProcess, u16) {
}
#[bench]
#[ignore]
fn bind_udp_bench(b: &mut Bencher) {
let (named, server_port) = bind_process();
@ -207,6 +208,7 @@ fn bind_udp_bench(b: &mut Bencher) {
}
#[bench]
#[ignore]
fn bind_tcp_bench(b: &mut Bencher) {
let (named, server_port) = bind_process();

View File

@ -18,7 +18,7 @@ use std::collections::BTreeMap;
use chrono::UTC;
use trust_dns::op::{Message, UpdateMessage, ResponseCode, Query};
use trust_dns::rr::{DNSClass, Name, RData, Record, RecordType, RrKey, RrSet};
use trust_dns::rr::{DNSClass, Name, RData, Record, RecordType, RrKey, RecordSet};
use trust_dns::rr::rdata::{NSEC, SIG};
use trust_dns::rr::dnssec::Signer;
@ -34,7 +34,7 @@ pub struct Authority {
origin: Name,
class: DNSClass,
journal: Option<Journal>,
records: BTreeMap<RrKey, RrSet>,
records: BTreeMap<RrKey, RecordSet>,
zone_type: ZoneType,
allow_update: bool,
// Private key mapped to the Record of the DNSKey
@ -59,7 +59,7 @@ impl Authority {
/// # Return value
///
/// The new `Authority`.
pub fn new(origin: Name, records: BTreeMap<RrKey, RrSet>, zone_type: ZoneType, allow_update: bool) -> Authority {
pub fn new(origin: Name, records: BTreeMap<RrKey, RecordSet>, zone_type: ZoneType, allow_update: bool) -> Authority {
Authority{ origin: origin, class: DNSClass::IN, journal: None, records: records, zone_type: zone_type,
allow_update: allow_update, secure_keys: Vec::new() }
}
@ -163,7 +163,7 @@ impl Authority {
}
/// Get all the
pub fn get_records(&self) -> &BTreeMap<RrKey, RrSet> {
pub fn get_records(&self) -> &BTreeMap<RrKey, RecordSet> {
&self.records
}
@ -310,12 +310,12 @@ impl Authority {
// return (NXRRSET)
for require in pre_requisites {
if require.get_ttl() != 0 {
debug!("ttl must be 0 for: {:?}", require);
warn!("ttl must be 0 for: {:?}", require);
return Err(ResponseCode::FormErr);
}
if !self.origin.zone_of(require.get_name()) {
debug!("{} is not a zone_of {}", require.get_name(), self.origin);
warn!("{} is not a zone_of {}", require.get_name(), self.origin);
return Err(ResponseCode::NotZone);
}
@ -727,7 +727,7 @@ impl Authority {
assert_eq!(self.class, record.get_dns_class());
let rr_key = RrKey::new(record.get_name(), record.get_rr_type());
let records: &mut RrSet = self.records.entry(rr_key).or_insert(RrSet::new(record.get_name(), record.get_rr_type(), serial));
let records: &mut RecordSet = self.records.entry(rr_key).or_insert(RecordSet::new(record.get_name(), record.get_rr_type(), serial));
records.insert(record, serial)
}

View File

@ -225,7 +225,7 @@ impl Catalog {
response.id(request.get_id());
response.op_code(OpCode::Query);
response.message_type(MessageType::Response);
response.add_all_queries(request.get_queries());
response.add_queries(request.get_queries().into_iter().cloned());
// TODO: the spec is very unclear on what to do with multiple queries
// we will search for each, in the future, maybe make this threaded to respond even faster.
@ -239,18 +239,19 @@ impl Catalog {
if !records.is_empty() {
response.response_code(ResponseCode::NoError);
response.authoritative(true);
response.add_all_answers(&records);
response.add_answers(records.into_iter().cloned());
// get the NS records
let ns = authority.get_ns(is_dnssec);
if ns.is_empty() { warn!("there are no NS records for: {:?}", authority.get_origin()); }
else {
response.add_all_name_servers(&ns);
response.add_name_servers(ns.into_iter().cloned());
}
} else {
if is_dnssec {
// get NSEC records
response.add_all_name_servers(&authority.get_nsec_records(query.get_name(), is_dnssec));
let nsecs = authority.get_nsec_records(query.get_name(), is_dnssec);
response.add_name_servers(nsecs.into_iter().cloned());
}
// in the not found case it's standard to return the SOA in the authority section
@ -259,7 +260,7 @@ impl Catalog {
let soa = authority.get_soa_secure(is_dnssec);
if soa.is_empty() { warn!("there is no SOA record for: {:?}", authority.get_origin()); }
else {
response.add_all_name_servers(&soa);
response.add_name_servers(soa.into_iter().cloned());
}
}
} else {

View File

@ -31,7 +31,7 @@ use trust_dns::udp::{UdpHandler, UdpState};
use ::authority::Catalog;
// TODO, might be cool to store buffers for later usage...
#[deprecated]
#[deprecated = "will be removed post 0.9.x"]
pub struct Server {
handlers: HashMap<Token, DnsHandlerType>,
next_token: Cell<usize>,