support KEY flags

fix Signer to use RData for key_tag
This commit is contained in:
Benjamin Fry 2017-04-23 15:38:43 -07:00
parent 63c473ff78
commit 80ad0e221b
11 changed files with 1341 additions and 314 deletions

View File

@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Added `From<IpAddr>` for Name (reverse DNS) #105
- AppVeyor support #103
- rustls client tls support (seperate crate)
- full support for KEY RR in client
### Changed
- Fixed TLS documentation, added more elsewhere, docs required; fixes #102

View File

@ -103,10 +103,7 @@ impl<H> ClientHandle for SecureClientHandle<H>
if let OpCode::Query = message.op_code() {
// This will panic on no queries, that is a very odd type of request, isn't it?
// TODO: there should only be one
let query = message.queries()
.first()
.cloned()
.unwrap();
let query = message.queries().first().cloned().unwrap();
let client: SecureClientHandle<H> = self.clone_with_context();
// TODO: cache response of the server about understood algorithms
@ -136,22 +133,27 @@ impl<H> ClientHandle for SecureClientHandle<H>
message.set_authentic_data(true);
message.set_checking_disabled(false);
let dns_class = message.queries().first().map_or(DNSClass::IN, |q| q.query_class());
let dns_class = message
.queries()
.first()
.map_or(DNSClass::IN, |q| q.query_class());
return Box::new(self.client
.send(message)
.and_then(move |message_response| {
// group the record sets by name and type
// each rrset type needs to validated independently
debug!("validating message_response: {}", message_response.id());
verify_rrsets(client, message_response, dns_class)
})
// group the record sets by name and type
// each rrset type needs to validated independently
debug!("validating message_response: {}",
message_response.id());
verify_rrsets(client, message_response, dns_class)
})
.and_then(move |verified_message| {
// at this point all of the message is verified.
// This is where NSEC (and possibly NSEC3) validation occurs
// As of now, only NSEC is supported.
if verified_message.answers().is_empty() {
let nsecs = verified_message.name_servers()
let nsecs = verified_message
.name_servers()
.iter()
.filter(|rr| rr.rr_type() == RecordType::NSEC)
.collect::<Vec<_>>();
@ -223,7 +225,8 @@ fn verify_rrsets<H>(client: SecureClientHandle<H>,
Vec::with_capacity(rrset_types.len());
for (name, record_type) in rrset_types {
// TODO: should we evaluate the different sections (answers and name_servers) separately?
let rrset: Vec<Record> = message_result.answers()
let rrset: Vec<Record> = message_result
.answers()
.iter()
.chain(message_result.name_servers())
.chain(message_result.additionals())
@ -231,7 +234,8 @@ fn verify_rrsets<H>(client: SecureClientHandle<H>,
.cloned()
.collect();
let rrsigs: Vec<Record> = message_result.answers()
let rrsigs: Vec<Record> = message_result
.answers()
.iter()
.chain(message_result.name_servers())
.chain(message_result.additionals())
@ -292,7 +296,8 @@ impl Future for VerifyRrsetsFuture {
debug!("an rrset was verified: {}, {:?}",
rrset.name,
rrset.record_type);
self.verified_rrsets.insert((rrset.name, rrset.record_type));
self.verified_rrsets
.insert((rrset.name, rrset.record_type));
remaining
}
// TODO, should we return the Message on errors? Allow the consumer to decide what to do
@ -318,27 +323,30 @@ impl Future for VerifyRrsetsFuture {
// TODO: does the section in the message matter here?
// we could probably end up with record_types in any section.
// track the section in the rrset evaluation?
let answers = message_result.take_answers()
let answers = message_result
.take_answers()
.into_iter()
.filter(|record| {
self.verified_rrsets.contains(&(record.name().clone(),
record.rr_type()))
self.verified_rrsets
.contains(&(record.name().clone(), record.rr_type()))
})
.collect::<Vec<Record>>();
let name_servers = message_result.take_name_servers()
let name_servers = message_result
.take_name_servers()
.into_iter()
.filter(|record| {
self.verified_rrsets.contains(&(record.name().clone(),
record.rr_type()))
self.verified_rrsets
.contains(&(record.name().clone(), record.rr_type()))
})
.collect::<Vec<Record>>();
let additionals = message_result.take_additionals()
let additionals = message_result
.take_additionals()
.into_iter()
.filter(|record| {
self.verified_rrsets.contains(&(record.name().clone(),
record.rr_type()))
self.verified_rrsets
.contains(&(record.name().clone(), record.rr_type()))
})
.collect::<Vec<Record>>();
@ -413,7 +421,8 @@ fn verify_dnskey_rrset<H>(mut client: SecureClientHandle<H>,
// check the DNSKEYS against the trust_anchor, if it's approved allow it.
{
let anchored_keys = rrset.records
let anchored_keys = rrset
.records
.iter()
.enumerate()
.filter(|&(_, rr)| rr.rr_type() == RecordType::DNSKEY)
@ -442,9 +451,11 @@ fn verify_dnskey_rrset<H>(mut client: SecureClientHandle<H>,
}
// need to get DS records for each DNSKEY
let valid_dnskey = client.query(rrset.name.clone(), rrset.record_class, RecordType::DS)
let valid_dnskey = client
.query(rrset.name.clone(), rrset.record_class, RecordType::DS)
.and_then(move |ds_message| {
let valid_keys = rrset.records
let valid_keys = rrset
.records
.iter()
.enumerate()
.filter(|&(_, rr)| rr.rr_type() == RecordType::DNSKEY)
@ -559,13 +570,15 @@ fn verify_default_rrset<H>(client: SecureClientHandle<H>,
rrset.record_type);
// Special case for self-signed DNSKEYS, validate with itself...
if rrsigs.iter().filter(|rrsig| rrsig.rr_type() == RecordType::RRSIG).any(|rrsig| {
if let &RData::SIG(ref sig) = rrsig.rdata() {
return RecordType::DNSKEY == rrset.record_type && sig.signer_name() == &rrset.name;
} else {
panic!("expected a SIG here");
}
}) {
if rrsigs
.iter()
.filter(|rrsig| rrsig.rr_type() == RecordType::RRSIG)
.any(|rrsig| if let &RData::SIG(ref sig) = rrsig.rdata() {
return RecordType::DNSKEY == rrset.record_type &&
sig.signer_name() == &rrset.name;
} else {
panic!("expected a SIG here");
}) {
// in this case it was looks like a self-signed key, first validate the signature
// then return rrset. Like the standard case below, the DNSKEY is validated
// after this function. This function is only responsible for validating the signature
@ -689,16 +702,19 @@ fn verify_rrset_with_dnskey(dnskey: &DNSKEY, sig: &SIG, rrset: &Rrset) -> Client
}
let pkey = pkey.unwrap();
let signer: Signer = Signer::new_verifier(*dnskey.algorithm(),
pkey,
sig.signer_name().clone(),
dnskey.zone_key(),
false);
let signer: Signer = Signer::dnssec_verifier(dnskey.clone(),
*dnskey.algorithm(),
pkey,
sig.signer_name().clone(),
dnskey.zone_key(),
false);
signer.hash_rrset_with_sig(&rrset.name, rrset.record_class, sig, &rrset.records)
signer
.hash_rrset_with_sig(&rrset.name, rrset.record_class, sig, &rrset.records)
.map_err(|e| e.into())
.and_then(|rrset_hash| {
signer.verify(&rrset_hash, sig.sig())
signer
.verify(&rrset_hash, sig.sig())
.map(|_| {
debug!("verified rrset: {}, type: {:?}",
rrset.name,
@ -773,7 +789,9 @@ fn verify_nsec(query: &Query, nsecs: Vec<&Record>) -> bool {
// if they are, then the query_type should not exist in the NSEC record.
// if we got an NSEC record of the same name, but it is listed in the NSEC types,
// WTF? is that bad server, bad record
if nsecs.iter().any(|r| {
if nsecs
.iter()
.any(|r| {
query.name() == r.name() &&
{
if let &RData::NSEC(ref rdata) = r.rdata() {
@ -787,7 +805,10 @@ fn verify_nsec(query: &Query, nsecs: Vec<&Record>) -> bool {
}
// based on the WTF? above, we will ignore any NSEC records of the same name
if nsecs.iter().filter(|r| query.name() != r.name()).any(|r| {
if nsecs
.iter()
.filter(|r| query.name() != r.name())
.any(|r| {
query.name() > r.name() &&
{
if let &RData::NSEC(ref rdata) = r.rdata() {

View File

@ -24,6 +24,8 @@ use ring::error::Unspecified;
#[cfg(not(feature = "ring"))]
use self::not_ring::Unspecified;
use error::{EncodeError, EncodeErrorKind};
error_chain! {
// The type defined for this error. These are the conventional
// and recommended names, but they can be arbitrarily chosen.
@ -39,6 +41,7 @@ error_chain! {
//
// This section can be empty.
links {
EncodeError, EncodeErrorKind, Encode;
}
// Automatic conversions between this error chain and other

View File

@ -26,7 +26,7 @@ use rr::{DNSClass, Name, Record, RecordType, RData};
use rr::dnssec::{Algorithm, DigestType, DnsSecErrorKind, DnsSecResult};
use rr::dnssec::KeyPair;
#[cfg(any(feature = "openssl", feature = "ring"))]
use rr::rdata::{sig, SIG};
use rr::rdata::{DNSKEY, KEY, sig, SIG};
#[cfg(any(feature = "openssl", feature = "ring"))]
use serialize::binary::{BinEncoder, BinSerializable, EncodeMode};
@ -231,6 +231,8 @@ use serialize::binary::{BinEncoder, BinSerializable, EncodeMode};
/// ```
#[cfg(any(feature = "openssl", feature = "ring"))]
pub struct Signer {
// TODO: this should really be a trait and generic struct over KEY and DNSKEY
key_rdata: RData,
key: KeyPair,
algorithm: Algorithm,
signer_name: Name,
@ -246,13 +248,34 @@ pub struct Signer;
#[cfg(any(feature = "openssl", feature = "ring"))]
impl Signer {
/// Version of Signer for verifying RRSIGs and SIG0 records.
pub fn new_verifier(algorithm: Algorithm,
key: KeyPair,
signer_name: Name,
is_zone_signing_key: bool,
is_zone_update_auth: bool)
-> Self {
pub fn dnssec_verifier(key_rdata: DNSKEY,
algorithm: Algorithm,
key: KeyPair,
signer_name: Name,
is_zone_signing_key: bool,
is_zone_update_auth: bool)
-> Self {
Signer {
key_rdata: key_rdata.into(),
key: key,
algorithm: algorithm,
signer_name: signer_name,
sig_duration: Duration::zero(),
is_zone_signing_key: is_zone_signing_key,
is_zone_update_auth: is_zone_update_auth,
}
}
/// Version of Signer for verifying RRSIGs and SIG0 records.
pub fn sig0_verifier(key_rdata: KEY,
algorithm: Algorithm,
key: KeyPair,
signer_name: Name,
is_zone_signing_key: bool,
is_zone_update_auth: bool)
-> Self {
Signer {
key_rdata: key_rdata.into(),
key: key,
algorithm: algorithm,
signer_name: signer_name,
@ -263,6 +286,7 @@ impl Signer {
}
/// Version of Signer for signing RRSIGs and SIG0 records.
#[deprecated="use SIG0 or DNSSec constructors"]
pub fn new(algorithm: Algorithm,
key: KeyPair,
signer_name: Name,
@ -270,7 +294,12 @@ impl Signer {
is_zone_signing_key: bool,
is_zone_update_auth: bool)
-> Self {
let dnskey =
key.to_dnskey(algorithm)
.expect("something went wrong, use one of the SIG0 or DNSSec constructors");
Signer {
key_rdata: dnskey.into(),
key: key,
algorithm: algorithm,
signer_name: signer_name,
@ -368,7 +397,14 @@ impl Signer {
pub fn calculate_key_tag(&self) -> DnsSecResult<u16> {
let mut ac: usize = 0;
for (i, k) in try!(self.key.to_public_bytes()).iter().enumerate() {
// TODO:
let mut bytes: Vec<u8> = Vec::with_capacity(512);
{
let mut e = BinEncoder::new(&mut bytes);
try!(self.key_rdata.emit(&mut e));
}
for (i, k) in bytes.iter().enumerate() {
ac += if i & 0x0001 == 0x0001 {
*k as usize
} else {

View File

@ -20,6 +20,7 @@ use ::serialize::binary::*;
use ::error::*;
use rr::dnssec::{Algorithm, DigestType};
use rr::Name;
use rr::record_data::RData;
/// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-2), DNSSEC Resource Records, March 2005
///
@ -229,6 +230,12 @@ impl DNSKEY {
}
}
impl From<DNSKEY> for RData {
fn from(key: DNSKEY) -> RData {
RData::DNSKEY(key)
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<DNSKEY> {
let flags: u16 = try!(decoder.read_u16());
@ -282,25 +289,26 @@ pub fn emit(encoder: &mut BinEncoder, rdata: &DNSKEY) -> EncodeResult {
Ok(())
}
// / 2.2. The DNSKEY RR Presentation Format
// /
// / The presentation format of the RDATA portion is as follows:
// /
// / The Flag field MUST be represented as an unsigned decimal integer.
// / Given the currently defined flags, the possible values are: 0, 256,
// / and 257.
// /
// / The Protocol Field MUST be represented as an unsigned decimal integer
// / with a value of 3.
// /
// / The Algorithm field MUST be represented either as an unsigned decimal
// / integer or as an algorithm mnemonic as specified in Appendix A.1.
// /
// / The Public Key field MUST be represented as a Base64 encoding of the
// / Public Key. Whitespace is allowed within the Base64 text. For a
// / definition of Base64 encoding, see [RFC3548].
// /
// / TODO: to_string()
// /// ```text
// /// 2.2. The DNSKEY RR Presentation Format
// ///
// /// The presentation format of the RDATA portion is as follows:
// ///
// /// The Flag field MUST be represented as an unsigned decimal integer.
// /// Given the currently defined flags, the possible values are: 0, 256,
// /// and 257.
// ///
// /// The Protocol Field MUST be represented as an unsigned decimal integer
// /// with a value of 3.
// ///
// /// The Algorithm field MUST be represented either as an unsigned decimal
// /// integer or as an algorithm mnemonic as specified in Appendix A.1.
// ///
// /// The Public Key field MUST be represented as a Base64 encoding of the
// /// Public Key. Whitespace is allowed within the Base64 text. For a
// /// definition of Base64 encoding, see [RFC3548].
// /// ```
// fn to_string()
#[test]
pub fn test() {

805
client/src/rr/rdata/key.rs Normal file
View File

@ -0,0 +1,805 @@
/*
* Copyright (C) 2016 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! public key record data for signing zone records
use serialize::binary::*;
use error::*;
use rr::dnssec::Algorithm;
use rr::record_data::RData;
/// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-3), Domain Name System Security Extensions, March 1999
///
/// ```text
/// 3. The KEY Resource Record
///
/// The KEY resource record (RR) is used to store a public key that is
/// associated with a Domain Name System (DNS) name. This can be the
/// public key of a zone, a user, or a host or other end entity. Security
/// aware DNS implementations MUST be designed to handle at least two
/// simultaneously valid keys of the same type associated with the same
/// name.
///
/// The type number for the KEY RR is 25.
///
/// A KEY RR is, like any other RR, authenticated by a SIG RR. KEY RRs
/// must be signed by a zone level key.
///
/// 3.1 KEY RDATA format
///
/// The RDATA for a KEY RR consists of flags, a protocol octet, the
/// algorithm number octet, and the public key itself. The format is as
/// follows:
///
/// 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | flags | protocol | algorithm |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | /
/// / public key /
/// / /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
///
/// The KEY RR is not intended for storage of certificates and a separate
/// certificate RR has been developed for that purpose, defined in [RFC
/// 2538].
///
/// The meaning of the KEY RR owner name, flags, and protocol octet are
/// described in Sections 3.1.1 through 3.1.5 below. The flags and
/// algorithm must be examined before any data following the algorithm
/// octet as they control the existence and format of any following data.
/// The algorithm and public key fields are described in Section 3.2.
/// The format of the public key is algorithm dependent.
///
/// KEY RRs do not specify their validity period but their authenticating
/// SIG RR(s) do as described in Section 4 below.
///
/// 3.1.1 Object Types, DNS Names, and Keys
///
/// The public key in a KEY RR is for the object named in the owner name.
///
/// A DNS name may refer to three different categories of things. For
/// example, foo.host.example could be (1) a zone, (2) a host or other
/// end entity , or (3) the mapping into a DNS name of the user or
/// account foo@host.example. Thus, there are flag bits, as described
/// below, in the KEY RR to indicate with which of these roles the owner
/// name and public key are associated. Note that an appropriate zone
/// KEY RR MUST occur at the apex node of a secure zone and zone KEY RRs
/// occur only at delegation points.
///
/// 3.1.2 The KEY RR Flag Field
///
/// In the "flags" field:
///
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
/// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
/// | A/C | Z | XT| Z | Z | NAMTYP| Z | Z | Z | Z | SIG |
/// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
///
/// Bit 0 and 1 are the key "type" bits whose values have the following
/// meanings:
///
/// 10: Use of the key is prohibited for authentication.
/// 01: Use of the key is prohibited for confidentiality.
/// 00: Use of the key for authentication and/or confidentiality
/// is permitted. Note that DNS security makes use of keys
/// for authentication only. Confidentiality use flagging is
/// provided for use of keys in other protocols.
/// Implementations not intended to support key distribution
/// for confidentiality MAY require that the confidentiality
/// use prohibited bit be on for keys they serve.
/// 11: If both bits are one, the "no key" value, there is no key
/// information and the RR stops after the algorithm octet.
/// By the use of this "no key" value, a signed KEY RR can
/// authenticatably assert that, for example, a zone is not
/// secured. See section 3.4 below.
///
/// Bits 2 is reserved and must be zero.
///
/// Bits 3 is reserved as a flag extension bit. If it is a one, a second
/// 16 bit flag field is added after the algorithm octet and
/// before the key data. This bit MUST NOT be set unless one or
/// more such additional bits have been defined and are non-zero.
///
/// Bits 4-5 are reserved and must be zero.
///
/// Bits 6 and 7 form a field that encodes the name type. Field values
/// have the following meanings:
///
/// 00: indicates that this is a key associated with a "user" or
/// "account" at an end entity, usually a host. The coding
/// of the owner name is that used for the responsible
/// individual mailbox in the SOA and RP RRs: The owner name
/// is the user name as the name of a node under the entity
/// name. For example, "j_random_user" on
/// host.subdomain.example could have a public key associated
/// through a KEY RR with name
/// j_random_user.host.subdomain.example. It could be used
/// in a security protocol where authentication of a user was
/// desired. This key might be useful in IP or other
/// security for a user level service such a telnet, ftp,
/// rlogin, etc.
/// 01: indicates that this is a zone key for the zone whose name
/// is the KEY RR owner name. This is the public key used
/// for the primary DNS security feature of data origin
/// authentication. Zone KEY RRs occur only at delegation
/// points.
/// 10: indicates that this is a key associated with the non-zone
/// "entity" whose name is the RR owner name. This will
/// commonly be a host but could, in some parts of the DNS
/// tree, be some other type of entity such as a telephone
/// number [RFC 1530] or numeric IP address. This is the
/// public key used in connection with DNS request and
/// transaction authentication services. It could also be
/// used in an IP-security protocol where authentication at
/// the host, rather than user, level was desired, such as
/// routing, NTP, etc.
/// 11: reserved.
///
/// Bits 8-11 are reserved and must be zero.
///
/// Bits 12-15 are the "signatory" field. If non-zero, they indicate
/// that the key can validly sign things as specified in DNS
/// dynamic update [RFC 2137]. Note that zone keys (see bits
/// 6 and 7 above) always have authority to sign any RRs in
/// the zone regardless of the value of the signatory field.
/// ```
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct KEY {
key_trust: KeyTrust,
key_usage: KeyUsage,
signatory: UpdateScope,
protocol: Protocol,
algorithm: Algorithm,
public_key: Vec<u8>,
}
/// Specifies in what contexts this key may be trusted for use
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum KeyTrust {
/// Use of the key is prohibited for authentication
NotAuth,
/// Use of the key is prohibited for confidentiality
NotPrivate,
/// Use of the key for authentication and/or confidentiality is permitted
AuthOrPrivate,
/// If both bits are one, the "no key" value, (revocation?)
DoNotTrust,
}
impl Default for KeyTrust {
fn default() -> Self {
KeyTrust::NotPrivate
}
}
impl From<u16> for KeyTrust {
fn from(flags: u16) -> Self {
// we only care about the first two bits, zero out the rest
match flags & 0b1100_0000_0000_0000 {
// 10: Use of the key is prohibited for authentication.
0b1000_0000_0000_0000 => KeyTrust::NotAuth,
// 01: Use of the key is prohibited for confidentiality.
0b0100_0000_0000_0000 => KeyTrust::NotPrivate,
// 00: Use of the key for authentication and/or confidentiality
0b0000_0000_0000_0000 => KeyTrust::AuthOrPrivate,
// 11: If both bits are one, the "no key" value, there is no key
0b1100_0000_0000_0000 => KeyTrust::DoNotTrust,
_ => panic!("All other bit fields should have been cleared"),
}
}
}
impl From<KeyTrust> for u16 {
fn from(key_trust: KeyTrust) -> Self {
match key_trust {
// 10: Use of the key is prohibited for authentication.
KeyTrust::NotAuth => 0b1000_0000_0000_0000,
// 01: Use of the key is prohibited for confidentiality.
KeyTrust::NotPrivate => 0b0100_0000_0000_0000,
// 00: Use of the key for authentication and/or confidentiality
KeyTrust::AuthOrPrivate => 0b0000_0000_0000_0000,
// 11: If both bits are one, the "no key" value, there is no key
KeyTrust::DoNotTrust => 0b1100_0000_0000_0000,
}
}
}
#[test]
fn test_key_trust() {
assert_eq!(KeyTrust::NotAuth,
KeyTrust::from(u16::from(KeyTrust::NotAuth)));
assert_eq!(KeyTrust::NotPrivate,
KeyTrust::from(u16::from(KeyTrust::NotPrivate)));
assert_eq!(KeyTrust::AuthOrPrivate,
KeyTrust::from(u16::from(KeyTrust::AuthOrPrivate)));
assert_eq!(KeyTrust::DoNotTrust,
KeyTrust::from(u16::from(KeyTrust::DoNotTrust)));
}
/// Declares what this key is for
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum KeyUsage {
/// key associated with a "user" or "account" at an end entity, usually a host
UserAccount,
/// zone key for the zone whose name is the KEY RR owner name
#[deprecated = "For Zone signing DNSKEY should be used"]
Zone,
/// associated with the non-zone "entity" whose name is the RR owner name
Entity,
/// Reserved
Reserved,
}
impl Default for KeyUsage {
fn default() -> Self {
KeyUsage::Entity
}
}
impl From<u16> for KeyUsage {
#[allow(deprecated)]
fn from(flags: u16) -> Self {
// we only care about the 6&7 two bits, zero out the rest
match flags & 0b0000_0011_0000_0000 {
// 00: indicates that this is a key associated with a "user" or
0b0000_0000_0000_0000 => KeyUsage::UserAccount,
// 01: indicates that this is a zone key for the zone whose name
0b0000_0001_0000_0000 => KeyUsage::Zone,
// 10: indicates that this is a key associated with the non-zone
0b0000_0010_0000_0000 => KeyUsage::Entity,
// 11: reserved.
0b0000_0011_0000_0000 => KeyUsage::Reserved,
_ => panic!("All other bit fields should have been cleared"),
}
}
}
impl From<KeyUsage> for u16 {
#[allow(deprecated)]
fn from(key_usage: KeyUsage) -> Self {
match key_usage {
// 00: indicates that this is a key associated with a "user" or
KeyUsage::UserAccount => 0b0000_0000_0000_0000,
// 01: indicates that this is a zone key for the zone whose name
KeyUsage::Zone => 0b0000_0001_0000_0000,
// 10: indicates that this is a key associated with the non-zone
KeyUsage::Entity => 0b0000_0010_0000_0000,
// 11: reserved.
KeyUsage::Reserved => 0b0000_0011_0000_0000,
}
}
}
#[test]
#[allow(deprecated)]
fn test_key_usage() {
assert_eq!(KeyUsage::UserAccount,
KeyUsage::from(u16::from(KeyUsage::UserAccount)));
assert_eq!(KeyUsage::Zone, KeyUsage::from(u16::from(KeyUsage::Zone)));
assert_eq!(KeyUsage::Entity,
KeyUsage::from(u16::from(KeyUsage::Entity)));
assert_eq!(KeyUsage::Reserved,
KeyUsage::from(u16::from(KeyUsage::Reserved)));
}
/// [RFC 2137](https://tools.ietf.org/html/rfc2137#section-3.1), Secure Domain Name System Dynamic Update, April 1997
///
/// ```text
/// 3.1.1 Update Key Name Scope
///
/// The owner name of any update authorizing KEY RR must (1) be the same
/// as the owner name of any RRs being added or deleted or (2) a wildcard
/// name including within its extended scope (see section 3.3) the name
/// of any RRs being added or deleted and those RRs must be in the same
/// zone.
///
/// 3.1.2 Update Key Class Scope
///
/// The class of any update authorizing KEY RR must be the same as the
/// class of any RR's being added or deleted.
///
/// 3.1.3 Update Key Signatory Field
///
/// The four bit "signatory field" (see RFC 2065) of any update
/// authorizing KEY RR must be non-zero. The bits have the meanings
/// described below for non-zone keys (see section 3.2 for zone type
/// keys).
///
/// UPDATE KEY RR SIGNATORY FIELD BITS
///
/// 0 1 2 3
/// +-----------+-----------+-----------+-----------+
/// | zone | strong | unique | general |
/// +-----------+-----------+-----------+-----------+
///
/// Bit 0, zone control - If nonzero, this key is authorized to attach,
/// detach, and move zones by creating and deleting NS, glue A, and
/// zone KEY RR(s). If zero, the key can not authorize any update
/// that would effect such RRs. This bit is meaningful for both
/// type A and type B dynamic secure zones.
///
/// NOTE: do not confuse the "zone" signatory field bit with the
/// "zone" key type bit.
///
/// Bit 1, strong update - If nonzero, this key is authorized to add and
/// delete RRs even if there are other RRs with the same owner name
/// and class that are authenticated by a SIG signed with a
/// different dynamic update KEY. If zero, the key can only
/// authorize updates where any existing RRs of the same owner and
/// class are authenticated by a SIG using the same key. This bit
/// is meaningful only for type A dynamic zones and is ignored in
/// type B dynamic zones.
///
/// Keeping this bit zero on multiple KEY RRs with the same or
/// nested wild card owner names permits multiple entities to exist
/// that can create and delete names but can not effect RRs with
/// different owner names from any they created. In effect, this
/// creates two levels of dynamic update key, strong and weak, where
/// weak keys are limited in interfering with each other but a
/// strong key can interfere with any weak keys or other strong
/// keys.
///
/// Bit 2, unique name update - If nonzero, this key is authorized to add
/// and update RRs for only a single owner name. If there already
/// exist RRs with one or more names signed by this key, they may be
/// updated but no new name created until the number of existing
/// names is reduced to zero. This bit is meaningful only for mode
/// A dynamic zones and is ignored in mode B dynamic zones. This bit
/// is meaningful only if the owner name is a wildcard. (Any
/// dynamic update KEY with a non-wildcard name is, in effect, a
/// unique name update key.)
///
/// This bit can be used to restrict a KEY from flooding a zone with
/// new names. In conjunction with a local administratively imposed
/// limit on the number of dynamic RRs with a particular name, it
/// can completely restrict a KEY from flooding a zone with RRs.
///
/// Bit 3, general update - The general update signatory field bit has no
/// special meaning. If the other three bits are all zero, it must
/// be one so that the field is non-zero to designate that the key
/// is an update key. The meaning of all values of the signatory
/// field with the general bit and one or more other signatory field
/// bits on is reserved.
///
/// All the signatory bit update authorizations described above only
/// apply if the update is within the name and class scope as per
/// sections 3.1.1 and 3.1.2.
/// ```
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct UpdateScope {
/// this key is authorized to attach,
/// detach, and move zones by creating and deleting NS, glue A, and
/// zone KEY RR(s)
pub zone: bool,
/// this key is authorized to add and
/// delete RRs even if there are other RRs with the same owner name
/// and class that are authenticated by a SIG signed with a
/// different dynamic update KEY
pub strong: bool,
/// this key is authorized to add and update RRs for only a single owner name
pub unique: bool,
/// The general update signatory field bit has no special meaning, (true if the others are false)
pub general: bool,
}
impl Default for UpdateScope {
fn default() -> Self {
UpdateScope {
zone: false,
strong: false,
unique: false,
general: true,
}
}
}
impl From<u16> for UpdateScope {
fn from(flags: u16) -> Self {
// we only care about the final four bits, zero out the rest
UpdateScope {
// Bit 0, zone control - If nonzero, this key is authorized to attach,
zone: flags & 0b0000_0000_0000_1000 != 0,
// Bit 1, strong update - If nonzero, this key is authorized to add and
strong: flags & 0b0000_0000_0000_0100 != 0,
// Bit 2, unique name update - If nonzero, this key is authorized to add
unique: flags & 0b0000_0000_0000_0010 != 0,
// Bit 3, general update - The general update signatory field bit has no
general: flags & 0b0000_0000_0000_0001 != 0,
}
}
}
impl From<UpdateScope> for u16 {
fn from(update_scope: UpdateScope) -> Self {
let mut flags = 0_u16;
if update_scope.zone {
flags |= 0b0000_0000_0000_1000;
}
if update_scope.strong {
flags |= 0b0000_0000_0000_0100;
}
if update_scope.unique {
flags |= 0b0000_0000_0000_0010;
}
if update_scope.general {
flags |= 0b0000_0000_0000_0001;
}
flags
}
}
#[test]
fn test_update_scope() {
assert_eq!(UpdateScope::default(),
UpdateScope::from(u16::from(UpdateScope::default())));
let update_scope = UpdateScope {
zone: true,
strong: true,
unique: true,
general: true,
};
assert_eq!(update_scope, UpdateScope::from(u16::from(update_scope)));
let update_scope = UpdateScope {
zone: true,
strong: false,
unique: true,
general: false,
};
assert_eq!(update_scope, UpdateScope::from(u16::from(update_scope)));
let update_scope = UpdateScope {
zone: false,
strong: true,
unique: false,
general: true,
};
assert_eq!(update_scope, UpdateScope::from(u16::from(update_scope)));
let update_scope = UpdateScope {
zone: false,
strong: true,
unique: true,
general: false,
};
assert_eq!(update_scope, UpdateScope::from(u16::from(update_scope)));
let update_scope = UpdateScope {
zone: true,
strong: false,
unique: false,
general: true,
};
assert_eq!(update_scope, UpdateScope::from(u16::from(update_scope)));
}
/// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-3.1.3), Domain Name System Security Extensions, March 1999
///
/// ```text
/// 3.1.3 The Protocol Octet
///
/// It is anticipated that keys stored in DNS will be used in conjunction
/// with a variety of Internet protocols. It is intended that the
/// protocol octet and possibly some of the currently unused (must be
/// zero) bits in the KEY RR flags as specified in the future will be
/// used to indicate a key's validity for different protocols.
///
/// The following values of the Protocol Octet are reserved as indicated:
///
/// VALUE Protocol
///
/// 0 -reserved
/// 1 TLS
/// 2 email
/// 3 dnssec
/// 4 IPSEC
/// 5-254 - available for assignment by IANA
/// 255 All
///
/// In more detail:
/// 1 is reserved for use in connection with TLS.
/// 2 is reserved for use in connection with email.
/// 3 is used for DNS security. The protocol field SHOULD be set to
/// this value for zone keys and other keys used in DNS security.
/// Implementations that can determine that a key is a DNS
/// security key by the fact that flags label it a zone key or the
/// signatory flag field is non-zero are NOT REQUIRED to check the
/// protocol field.
/// 4 is reserved to refer to the Oakley/IPSEC [RFC 2401] protocol
/// and indicates that this key is valid for use in conjunction
/// with that security standard. This key could be used in
/// connection with secured communication on behalf of an end
/// entity or user whose name is the owner name of the KEY RR if
/// the entity or user flag bits are set. The presence of a KEY
/// resource with this protocol value is an assertion that the
/// host speaks Oakley/IPSEC.
/// 255 indicates that the key can be used in connection with any
/// protocol for which KEY RR protocol octet values have been
/// defined. The use of this value is discouraged and the use of
/// different keys for different protocols is encouraged.
/// ```
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Protocol {
/// Not in use
Reserved,
/// Reserved for use with TLS
TLS,
/// Reserved for use with email
Email,
/// Reserved for use with DNSSec (TRust-DNS only supports DNSKEY with DNSSec)
#[deprecated = "For Zone signing DNSKEY should be used"]
DNSSec,
/// Reserved to refer to the Oakley/IPSEC
IPSec,
/// Undefined
Other(u8),
/// the key can be used in connection with any protocol
All,
}
impl Default for Protocol {
fn default() -> Self {
Protocol::All
}
}
impl From<u8> for Protocol {
#[allow(deprecated)]
fn from(field: u8) -> Self {
match field {
0 => Protocol::Reserved,
1 => Protocol::TLS,
2 => Protocol::Email,
3 => Protocol::DNSSec,
4 => Protocol::IPSec,
255 => Protocol::All,
_ => Protocol::Other(field),
}
}
}
impl From<Protocol> for u8 {
#[allow(deprecated)]
fn from(protocol: Protocol) -> Self {
match protocol {
Protocol::Reserved => 0,
Protocol::TLS => 1,
Protocol::Email => 2,
Protocol::DNSSec => 3,
Protocol::IPSec => 4,
Protocol::All => 255,
Protocol::Other(field) => field,
}
}
}
impl KEY {
/// Construct a new KEY RData
///
/// # Arguments
///
/// * `key_trust` - declare the security level of this key
/// * `key_usage` - what type of thing is this key associated to
/// * `revoke` - this key has been revoked
/// * `algorithm` - specifies the algorithm which this Key uses to sign records
/// * `public_key` - the public key material, in native endian, the emitter will perform any necessary conversion
///
/// # Return
///
/// A new KEY RData for use in a Resource Record
pub fn new(key_trust: KeyTrust,
key_usage: KeyUsage,
signatory: UpdateScope,
protocol: Protocol,
algorithm: Algorithm,
public_key: Vec<u8>)
-> KEY {
KEY {
key_trust: key_trust,
key_usage: key_usage,
signatory: signatory,
protocol: protocol,
algorithm: algorithm,
public_key: public_key,
}
}
/// Returns the trust level of the key
pub fn key_trust(&self) -> KeyTrust {
self.key_trust
}
/// Returns the entity type using this key
pub fn key_usage(&self) -> KeyUsage {
self.key_usage
}
/// Returns true if the key_trust is DoNotTrust
pub fn revoke(&self) -> bool {
self.key_trust == KeyTrust::DoNotTrust
}
/// Returns the protocol which this key can be used with
pub fn protocol(&self) -> Protocol {
self.protocol
}
/// [RFC 4034, DNSSEC Resource Records, March 2005](https://tools.ietf.org/html/rfc4034#section-2.1.3)
///
/// ```text
/// 2.1.3. The Algorithm Field
///
/// The Algorithm field identifies the public key's cryptographic
/// algorithm and determines the format of the Public Key field. A list
/// of DNSSEC algorithm types can be found in Appendix A.1
/// ```
pub fn algorithm(&self) -> &Algorithm {
&self.algorithm
}
/// [RFC 4034, DNSSEC Resource Records, March 2005](https://tools.ietf.org/html/rfc4034#section-2.1.4)
///
/// ```text
/// 2.1.4. The Public Key Field
///
/// The Public Key Field holds the public key material. The format
/// depends on the algorithm of the key being stored and is described in
/// separate documents.
/// ```
pub fn public_key(&self) -> &[u8] {
&self.public_key
}
// /// Creates a message digest for this KEY record.
// ///
// /// ```text
// /// 5.1.4. The Digest Field
// ///
// /// The DS record refers to a KEY RR by including a digest of that
// /// KEY RR.
// ///
// /// The digest is calculated by concatenating the canonical form of the
// /// fully qualified owner name of the KEY RR with the KEY RDATA,
// /// and then applying the digest algorithm.
// ///
// /// digest = digest_algorithm( KEY owner name | KEY RDATA);
// ///
// /// "|" denotes concatenation
// ///
// /// KEY RDATA = Flags | Protocol | Algorithm | Public Key.
// ///
// /// The size of the digest may vary depending on the digest algorithm and
// /// KEY RR size. As of the time of this writing, the only defined
// /// digest algorithm is SHA-1, which produces a 20 octet digest.
// /// ```
// ///
// /// # Arguments
// ///
// /// * `name` - the label of of the KEY record.
// /// * `digest_type` - the `DigestType` with which to create the message digest.
// pub fn to_digest(&self, name: &Name, digest_type: DigestType) -> DnsSecResult<Vec<u8>> {
// let mut buf: Vec<u8> = Vec::new();
// {
// let mut encoder: BinEncoder = BinEncoder::new(&mut buf);
// encoder.set_canonical_names(true);
// if let Err(e) = name.emit(&mut encoder)
// .and_then(|_| emit(&mut encoder, self)) {
// warn!("error serializing KEY: {}", e);
// return Err(DnsSecErrorKind::Msg(format!("error serializing KEY: {}", e)).into());
// }
// }
// digest_type.hash(&buf).map_err(|e| e.into())
// }
}
impl From<KEY> for RData {
fn from(key: KEY) -> RData {
RData::KEY(key)
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<KEY> {
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// | A/C | Z | XT| Z | Z | NAMTYP| Z | Z | Z | Z | SIG |
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
let flags: u16 = try!(decoder.read_u16());
// Bits 2 is reserved and must be zero.
// Bits 4-5 are reserved and must be zero.
// Bits 8-11 are reserved and must be zero.
if flags & 0b0010_1100_1111_0000 != 0 {
return Err("flag 2, 4-5, and 8-11 are reserved, must be zero".into());
}
let key_trust = KeyTrust::from(flags);
let extended_flags: bool = flags & 0b0001_0000_0000_0000 != 0;
let key_usage = KeyUsage::from(flags);
let signatory = UpdateScope::from(flags);
if extended_flags {
// TODO: add an optional field to return the raw u16?
return Err("extended flags currently not supported".into());
}
let protocol = Protocol::from(try!(decoder.read_u8()));
let algorithm: Algorithm = try!(Algorithm::read(decoder));
// the public key is the left-over bytes minus 4 for the first fields
// TODO: decode the key here?
let public_key: Vec<u8> = try!(decoder.read_vec((rdata_length - 4) as usize));
Ok(KEY::new(key_trust,
key_usage,
signatory,
protocol,
algorithm,
public_key))
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder, rdata: &KEY) -> EncodeResult {
let mut flags: u16 = 0;
flags |= u16::from(rdata.key_trust);
flags |= u16::from(rdata.key_usage);
flags |= u16::from(rdata.signatory);
try!(encoder.emit_u16(flags));
try!(encoder.emit(u8::from(rdata.protocol)));
try!(rdata.algorithm().emit(encoder));
try!(encoder.emit_vec(rdata.public_key()));
Ok(())
}
#[test]
pub fn test() {
let rdata = KEY::new(Default::default(),
Default::default(),
Default::default(),
Default::default(),
Algorithm::RSASHA256,
vec![0, 1, 2, 3, 4, 5, 6, 7]);
let mut bytes = Vec::new();
let mut encoder: BinEncoder = BinEncoder::new(&mut bytes);
assert!(emit(&mut encoder, &rdata).is_ok());
let bytes = encoder.as_bytes();
println!("bytes: {:?}", bytes);
let mut decoder: BinDecoder = BinDecoder::new(bytes);
let read_rdata = read(&mut decoder, bytes.len() as u16);
assert!(read_rdata.is_ok(),
format!("error decoding: {:?}", read_rdata.unwrap_err()));
assert_eq!(rdata, read_rdata.unwrap());
// #[cfg(feature = "openssl")]
// assert!(rdata
// .to_digest(&Name::parse("www.example.com.", None).unwrap(),
// DigestType::SHA256)
// .is_ok());
}

View File

@ -21,8 +21,9 @@
// each of these module's has the parser for that rdata embedded, to keep the file sizes down...
pub mod a;
pub mod aaaa;
pub mod ds;
pub mod dnskey;
pub mod ds;
pub mod key;
pub mod mx;
pub mod name;
pub mod null;
@ -37,6 +38,7 @@ pub mod txt;
pub use self::dnskey::DNSKEY;
pub use self::ds::DS;
pub use self::key::KEY;
pub use self::mx::MX;
pub use self::nsec::NSEC;
pub use self::nsec3::NSEC3;

View File

@ -27,7 +27,7 @@ use serialize::txt::*;
use super::domain::Name;
use super::record_type::RecordType;
use super::rdata;
use super::rdata::{DNSKEY, DS, MX, NSEC, NSEC3, NSEC3PARAM, NULL, OPT, SIG, SOA, SRV, TXT};
use super::rdata::{DNSKEY, DS, KEY, MX, NSEC, NSEC3, NSEC3PARAM, NULL, OPT, SIG, SOA, SRV, TXT};
/// Record data enum variants
///
@ -238,18 +238,6 @@ pub enum RData {
/// algorithm number octet, and the public key itself. The format is as
/// follows:
///
///
///
///
///
///
///
///
///
///
///
///
///
/// 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -274,7 +262,7 @@ pub enum RData {
/// KEY RRs do not specify their validity period but their authenticating
/// SIG RR(s) do as described in Section 4 below.
/// ```
KEY(DNSKEY),
KEY(KEY),
/// ```text
/// 3.3.9. MX RDATA format
@ -742,10 +730,6 @@ impl RData {
debug!("reading CNAME");
RData::CNAME(try!(rdata::name::read(decoder)))
}
RecordType::KEY => {
debug!("reading KEY");
RData::KEY(try!(rdata::dnskey::read(decoder, rdata_length)))
}
RecordType::DNSKEY => {
debug!("reading DNSKEY");
RData::DNSKEY(try!(rdata::dnskey::read(decoder, rdata_length)))
@ -757,6 +741,10 @@ impl RData {
rt @ RecordType::IXFR => {
return Err(DecodeErrorKind::UnknownRecordTypeValue(rt.into()).into())
}
RecordType::KEY => {
debug!("reading KEY");
RData::KEY(try!(rdata::key::read(decoder, rdata_length)))
}
RecordType::MX => {
debug!("reading MX");
RData::MX(try!(rdata::mx::read(decoder)))
@ -843,7 +831,7 @@ impl RData {
// to_lowercase for rfc4034 and rfc6840
RData::CNAME(ref name) => rdata::name::emit(encoder, name),
RData::DS(ref ds) => rdata::ds::emit(encoder, ds),
RData::KEY(ref key) => rdata::dnskey::emit(encoder, key),
RData::KEY(ref key) => rdata::key::emit(encoder, key),
RData::DNSKEY(ref dnskey) => rdata::dnskey::emit(encoder, dnskey),
// to_lowercase for rfc4034 and rfc6840
RData::MX(ref mx) => rdata::mx::emit(encoder, mx),

View File

@ -494,6 +494,7 @@ impl Authority {
let name = sig.signer_name();
let keys = self.lookup(name, RecordType::KEY, false, SupportedAlgorithms::new());
debug!("found keys {:?}", keys);
// FIXME: check key usage flags and restrictions
keys.iter()
.filter_map(|rr_set| if let &RData::KEY(ref key) = rr_set.rdata() {
Some(key)
@ -511,7 +512,8 @@ impl Authority {
}
let pkey = pkey.unwrap();
let signer: Signer = Signer::new_verifier(*key.algorithm(),
let signer: Signer = Signer::sig0_verifier(key.clone(),
*key.algorithm(),
pkey,
sig.signer_name().clone(),
false,

View File

@ -56,7 +56,11 @@ fn test_query_udp_ipv4() {
use tokio_core::reactor::Core;
let mut io_loop = Core::new().unwrap();
let addr: SocketAddr = ("8.8.8.8", 53).to_socket_addrs().unwrap().next().unwrap();
let addr: SocketAddr = ("8.8.8.8", 53)
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
let (stream, sender) = UdpClientStream::new(addr, io_loop.handle());
let mut client = ClientFuture::new(stream, sender, io_loop.handle(), None);
@ -72,7 +76,11 @@ fn test_query_udp_ipv6() {
use tokio_core::reactor::Core;
let mut io_loop = Core::new().unwrap();
let addr: SocketAddr = ("2001:4860:4860::8888", 53).to_socket_addrs().unwrap().next().unwrap();
let addr: SocketAddr = ("2001:4860:4860::8888", 53)
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
let (stream, sender) = UdpClientStream::new(addr, io_loop.handle());
let mut client = ClientFuture::new(stream, sender, io_loop.handle(), None);
@ -88,7 +96,11 @@ fn test_query_tcp_ipv4() {
use tokio_core::reactor::Core;
let mut io_loop = Core::new().unwrap();
let addr: SocketAddr = ("8.8.8.8", 53).to_socket_addrs().unwrap().next().unwrap();
let addr: SocketAddr = ("8.8.8.8", 53)
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
let (stream, sender) = TcpClientStream::new(addr, io_loop.handle());
let mut client = ClientFuture::new(stream, sender, io_loop.handle(), None);
@ -104,7 +116,11 @@ fn test_query_tcp_ipv6() {
use tokio_core::reactor::Core;
let mut io_loop = Core::new().unwrap();
let addr: SocketAddr = ("2001:4860:4860::8888", 53).to_socket_addrs().unwrap().next().unwrap();
let addr: SocketAddr = ("2001:4860:4860::8888", 53)
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
let (stream, sender) = TcpClientStream::new(addr, io_loop.handle());
let mut client = ClientFuture::new(stream, sender, io_loop.handle(), None);
@ -119,30 +135,32 @@ fn test_query(client: &mut BasicClientHandle) -> Box<Future<Item = (), Error = (
"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.queries()
.first()
.expect("expected query")
.name()
.cmp_with_case(&name, false),
Ordering::Equal);
Box::new(client
.query(name.clone(), DNSClass::IN, RecordType::A)
.map(move |response| {
println!("response records: {:?}", response);
assert_eq!(response
.queries()
.first()
.expect("expected query")
.name()
.cmp_with_case(&name, false),
Ordering::Equal);
let record = &response.answers()[0];
assert_eq!(record.name(), &name);
assert_eq!(record.rr_type(), RecordType::A);
assert_eq!(record.dns_class(), DNSClass::IN);
let record = &response.answers()[0];
assert_eq!(record.name(), &name);
assert_eq!(record.rr_type(), RecordType::A);
assert_eq!(record.dns_class(), DNSClass::IN);
if let &RData::A(ref address) = record.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.rdata() {
assert_eq!(address, &Ipv4Addr::new(93, 184, 216, 34))
} else {
assert!(false);
}
})
.map_err(|e| {
assert!(false, "query failed: {}", e);
}))
}
#[test]
@ -195,13 +213,13 @@ fn create_sig0_ready_client(io_loop: &Core) -> (BasicClientHandle, domain::Name)
"com".to_string()]),
RecordType::KEY,
Duration::minutes(5).num_seconds() as u32);
auth_key.set_rdata(RData::KEY(DNSKEY::new(false,
false,
false,
signer.algorithm(),
signer.key()
.to_public_bytes()
.expect("to_vec failed"))));
auth_key
.set_rdata(RData::KEY(KEY::new(Default::default(),
Default::default(),
Default::default(),
Default::default(),
signer.algorithm(),
signer.key().to_public_bytes().expect("to_vec failed"))));
authority.upsert(auth_key, 0);
// setup the catalog
@ -229,11 +247,12 @@ fn test_create() {
let record = record;
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
let result = io_loop
.run(client.create(record.clone(), origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.name().clone(),
record.dns_class(),
record.rr_type()))
let result = io_loop
.run(client.query(record.name().clone(), record.dns_class(), record.rr_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 1);
@ -241,14 +260,18 @@ fn test_create() {
// 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");
let result = io_loop
.run(client.create(record.clone(), origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::YXRRSet);
// will fail if already set and not the same value.
let mut record = record.clone();
record.set_rdata(RData::A(Ipv4Addr::new(101, 11, 101, 11)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
let result = io_loop
.run(client.create(record.clone(), origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::YXRRSet);
}
@ -274,11 +297,12 @@ fn test_create_multi() {
rrset.insert(record2.clone(), 0);
let rrset = rrset;
let result = io_loop.run(client.create(rrset.clone(), origin.clone())).expect("create failed");
let result = io_loop
.run(client.create(rrset.clone(), origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.name().clone(),
record.dns_class(),
record.rr_type()))
let result = io_loop
.run(client.query(record.name().clone(), record.dns_class(), record.rr_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 2);
@ -288,14 +312,18 @@ fn test_create_multi() {
// 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");
let result = io_loop
.run(client.create(rrset, origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::YXRRSet);
// will fail if already set and not the same value.
let mut record = record.clone();
record.set_rdata(RData::A(Ipv4Addr::new(101, 11, 101, 12)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
let result = io_loop
.run(client.create(record.clone(), origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::YXRRSet);
}
@ -314,19 +342,20 @@ fn test_append() {
let record = record;
// first check the must_exist option
let result = io_loop.run(client.append(record.clone(), origin.clone(), true))
let result = io_loop
.run(client.append(record.clone(), origin.clone(), true))
.expect("append failed");
assert_eq!(result.response_code(), ResponseCode::NXRRSet);
// next append to a non-existent RRset
let result = io_loop.run(client.append(record.clone(), origin.clone(), false))
let result = io_loop
.run(client.append(record.clone(), origin.clone(), false))
.expect("append failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.query(record.name().clone(),
record.dns_class(),
record.rr_type()))
let result = io_loop
.run(client.query(record.name().clone(), record.dns_class(), record.rr_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 1);
@ -337,13 +366,13 @@ fn test_append() {
record2.set_rdata(RData::A(Ipv4Addr::new(101, 11, 101, 11)));
let record2 = record2;
let result = io_loop.run(client.append(record2.clone(), origin.clone(), true))
let result = io_loop
.run(client.append(record2.clone(), origin.clone(), true))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.name().clone(),
record.dns_class(),
record.rr_type()))
let result = io_loop
.run(client.query(record.name().clone(), record.dns_class(), record.rr_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 2);
@ -352,13 +381,13 @@ fn test_append() {
assert!(result.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))
let result = io_loop
.run(client.append(record.clone(), origin.clone(), true))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.name().clone(),
record.dns_class(),
record.rr_type()))
let result = io_loop
.run(client.query(record.name().clone(), record.dns_class(), record.rr_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 2);
@ -378,19 +407,20 @@ fn test_append_multi() {
record.set_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))
let result = io_loop
.run(client.append(record.clone(), origin.clone(), true))
.expect("append failed");
assert_eq!(result.response_code(), ResponseCode::NXRRSet);
// next append to a non-existent RRset
let result = io_loop.run(client.append(record.clone(), origin.clone(), false))
let result = io_loop
.run(client.append(record.clone(), origin.clone(), false))
.expect("append failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.query(record.name().clone(),
record.dns_class(),
record.rr_type()))
let result = io_loop
.run(client.query(record.name().clone(), record.dns_class(), record.rr_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 1);
@ -406,12 +436,13 @@ fn test_append_multi() {
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");
let result = io_loop
.run(client.append(rrset, origin.clone(), true))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.name().clone(),
record.dns_class(),
record.rr_type()))
let result = io_loop
.run(client.query(record.name().clone(), record.dns_class(), record.rr_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 3);
@ -422,13 +453,13 @@ fn test_append_multi() {
// 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))
let result = io_loop
.run(client.append(record.clone(), origin.clone(), true))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.name().clone(),
record.dns_class(),
record.rr_type()))
let result = io_loop
.run(client.query(record.name().clone(), record.dns_class(), record.rr_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 3);
@ -452,7 +483,9 @@ fn test_compare_and_swap() {
record.set_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");
let result = io_loop
.run(client.create(record.clone(), origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let current = record;
@ -460,13 +493,13 @@ fn test_compare_and_swap() {
new.set_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()))
let result = io_loop
.run(client.compare_and_swap(current.clone(), new.clone(), origin.clone()))
.expect("compare_and_swap failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(new.name().clone(),
new.dns_class(),
new.rr_type()))
let result = io_loop
.run(client.query(new.name().clone(), new.dns_class(), new.rr_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 1);
@ -478,13 +511,13 @@ fn test_compare_and_swap() {
not.set_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()))
let result = io_loop
.run(client.compare_and_swap(current, not.clone(), origin.clone()))
.expect("compare_and_swap failed");
assert_eq!(result.response_code(), ResponseCode::NXRRSet);
let result = io_loop.run(client.query(new.name().clone(),
new.dns_class(),
new.rr_type()))
let result = io_loop
.run(client.query(new.name().clone(), new.dns_class(), new.rr_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 1);
@ -508,28 +541,33 @@ fn test_compare_and_swap_multi() {
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 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()))
let result = io_loop
.run(client.create(current.clone(), origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let mut new = RecordSet::with_ttl(current.name().clone(),
current.record_type(),
current.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 mut new = RecordSet::with_ttl(current.name().clone(), current.record_type(), current.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()))
let result = io_loop
.run(client.compare_and_swap(current.clone(), new.clone(), origin.clone()))
.expect("compare_and_swap failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(new.name().clone(),
new.dns_class(),
new.record_type()))
let result = io_loop
.run(client.query(new.name().clone(), new.dns_class(), new.record_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 2);
@ -543,13 +581,13 @@ fn test_compare_and_swap_multi() {
not.set_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()))
let result = io_loop
.run(client.compare_and_swap(current, not.clone(), origin.clone()))
.expect("compare_and_swap failed");
assert_eq!(result.response_code(), ResponseCode::NXRRSet);
let result = io_loop.run(client.query(new.name().clone(),
new.dns_class(),
new.record_type()))
let result = io_loop
.run(client.query(new.name().clone(), new.dns_class(), new.record_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 2);
@ -571,29 +609,34 @@ fn test_delete_by_rdata() {
record1.set_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()))
let result = io_loop
.run(client.delete_by_rdata(record1.clone(), origin.clone()))
.expect("delete failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record1.clone(), origin.clone()))
let result = io_loop
.run(client.create(record1.clone(), origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let mut record2 = record1.clone();
record2.set_rdata(RData::A(Ipv4Addr::new(101, 11, 101, 11)));
let result = io_loop.run(client.append(record2.clone(), origin.clone(), true))
let result = io_loop
.run(client.append(record2.clone(), origin.clone(), true))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_by_rdata(record2.clone(), origin.clone()))
let result = io_loop
.run(client.delete_by_rdata(record2.clone(), origin.clone()))
.expect("delete failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record1.name().clone(),
record1.dns_class(),
record1.rr_type()))
let result = io_loop
.run(client.query(record1.name().clone(),
record1.dns_class(),
record1.rr_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 1);
@ -612,19 +655,30 @@ fn test_delete_by_rdata_multi() {
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 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()))
let result = io_loop
.run(client.delete_by_rdata(rrset.clone(), origin.clone()))
.expect("delete failed");
assert_eq!(result.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");
let result = io_loop
.run(client.create(rrset.clone(), origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// append a record
@ -638,16 +692,19 @@ fn test_delete_by_rdata_multi() {
let record3 = rrset.new_record(record3.rdata().clone()).clone();
let rrset = rrset;
let result = io_loop.run(client.append(rrset.clone(), origin.clone(), true))
let result = io_loop
.run(client.append(rrset.clone(), origin.clone(), true))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_by_rdata(rrset.clone(), origin.clone()))
let result = io_loop
.run(client.delete_by_rdata(rrset.clone(), origin.clone()))
.expect("delete failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record1.name().clone(),
let result = io_loop
.run(client.query(record1.name().clone(),
record1.dns_class(),
record1.rr_type()))
.expect("query failed");
@ -673,28 +730,32 @@ fn test_delete_rrset() {
record.set_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()))
let result = io_loop
.run(client.delete_rrset(record.clone(), origin.clone()))
.expect("delete failed");
assert_eq!(result.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");
let result = io_loop
.run(client.create(record.clone(), origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.set_rdata(RData::A(Ipv4Addr::new(101, 11, 101, 11)));
let result = io_loop.run(client.append(record.clone(), origin.clone(), true))
let result = io_loop
.run(client.append(record.clone(), origin.clone(), true))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_rrset(record.clone(), origin.clone()))
let result = io_loop
.run(client.delete_rrset(record.clone(), origin.clone()))
.expect("delete failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.name().clone(),
record.dns_class(),
record.rr_type()))
let result = io_loop
.run(client.query(record.name().clone(), record.dns_class(), record.rr_type()))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NXDomain);
assert_eq!(result.answers().len(), 0);
@ -714,37 +775,39 @@ fn test_delete_all() {
record.set_rdata(RData::A(Ipv4Addr::new(100, 10, 100, 10)));
// first check the must_exist option
let result =
io_loop.run(client.delete_all(record.name().clone(), origin.clone(), DNSClass::IN))
.expect("delete failed");
let result = io_loop
.run(client.delete_all(record.name().clone(), origin.clone(), DNSClass::IN))
.expect("delete failed");
assert_eq!(result.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");
let result = io_loop
.run(client.create(record.clone(), origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.set_rr_type(RecordType::AAAA);
record.set_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");
let result = io_loop
.run(client.create(record.clone(), origin.clone()))
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// verify record contents
let result =
io_loop.run(client.delete_all(record.name().clone(), origin.clone(), DNSClass::IN))
.expect("delete failed");
let result = io_loop
.run(client.delete_all(record.name().clone(), origin.clone(), DNSClass::IN))
.expect("delete failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.name().clone(),
record.dns_class(),
RecordType::A))
let result = io_loop
.run(client.query(record.name().clone(), record.dns_class(), RecordType::A))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NXDomain);
assert_eq!(result.answers().len(), 0);
let result = io_loop.run(client.query(record.name().clone(),
record.dns_class(),
RecordType::AAAA))
let result = io_loop
.run(client.query(record.name().clone(), record.dns_class(), RecordType::AAAA))
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NXDomain);
assert_eq!(result.answers().len(), 0);
@ -763,8 +826,8 @@ impl NeverReturnsClientStream {
let stream: Box<Future<Item = NeverReturnsClientStream, Error = io::Error>> =
Box::new(finished(NeverReturnsClientStream {
outbound_messages: outbound_messages.fuse(),
}));
outbound_messages: outbound_messages.fuse(),
}));
(stream, Box::new(message_sender))
}
@ -806,7 +869,10 @@ fn test_timeout_query_nonet() {
"com".to_string()]);
if let &ClientErrorKind::Timeout =
io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A)).unwrap_err().kind() {
io_loop
.run(client.query(name.clone(), DNSClass::IN, RecordType::A))
.unwrap_err()
.kind() {
()
} else {
assert!(false);
@ -815,7 +881,10 @@ fn test_timeout_query_nonet() {
// 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() {
io_loop
.run(client.query(name.clone(), DNSClass::IN, RecordType::AAAA))
.unwrap_err()
.kind() {
()
} else {
assert!(false);

View File

@ -41,7 +41,11 @@ impl TestClientConnection {
impl ClientConnection for TestClientConnection {
type MessageStream = TestClientStream;
fn unwrap(self) -> (Core, Box<Future<Item=Self::MessageStream, Error=io::Error>>, Box<ClientStreamHandle>) {
fn unwrap
(self)
-> (Core,
Box<Future<Item = Self::MessageStream, Error = io::Error>>,
Box<ClientStreamHandle>) {
let io_loop = Core::new().unwrap();
let (stream, handle) = TestClientStream::new(self.catalog);
(io_loop, stream, handle)
@ -64,7 +68,11 @@ fn test_query_nonet() {
#[ignore]
#[allow(deprecated)]
fn test_query_udp() {
let addr: SocketAddr = ("8.8.8.8", 53).to_socket_addrs().unwrap().next().unwrap();
let addr: SocketAddr = ("8.8.8.8", 53)
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
let conn = UdpClientConnection::new(addr).unwrap();
let client = SyncClient::new(conn);
@ -75,7 +83,11 @@ fn test_query_udp() {
#[ignore]
#[allow(deprecated)]
fn test_query_tcp() {
let addr: SocketAddr = ("8.8.8.8", 53).to_socket_addrs().unwrap().next().unwrap();
let addr: SocketAddr = ("8.8.8.8", 53)
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
let conn = TcpClientConnection::new(addr).unwrap();
let client = SyncClient::new(conn);
@ -95,7 +107,8 @@ fn test_query(client: SyncClient) {
let response = response.unwrap();
println!("response records: {:?}", response);
assert_eq!(response.queries()
assert_eq!(response
.queries()
.first()
.expect("expected query")
.name()
@ -121,7 +134,10 @@ fn test_secure_query_example_nonet() {
let trust_anchor = {
let signers = authority.secure_keys();
let public_key = signers.first().expect("expected a key in the authority").key();
let public_key = signers
.first()
.expect("expected a key in the authority")
.key();
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key.to_public_bytes().expect("to_vec failed"));
@ -143,7 +159,11 @@ fn test_secure_query_example_nonet() {
#[ignore]
#[allow(deprecated)]
fn test_secure_query_example_udp() {
let addr: SocketAddr = ("8.8.8.8", 53).to_socket_addrs().unwrap().next().unwrap();
let addr: SocketAddr = ("8.8.8.8", 53)
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
let conn = UdpClientConnection::new(addr).unwrap();
let client = SecureSyncClient::new(conn).build();
@ -154,7 +174,11 @@ fn test_secure_query_example_udp() {
#[ignore]
#[allow(deprecated)]
fn test_secure_query_example_tcp() {
let addr: SocketAddr = ("8.8.8.8", 53).to_socket_addrs().unwrap().next().unwrap();
let addr: SocketAddr = ("8.8.8.8", 53)
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
let conn = TcpClientConnection::new(addr).unwrap();
let client = SecureSyncClient::new(conn).build();
@ -233,7 +257,10 @@ fn test_nsec_query_example_nonet() {
let trust_anchor = {
let signers = authority.secure_keys();
let public_key = signers.first().expect("expected a key in the authority").key();
let public_key = signers
.first()
.expect("expected a key in the authority")
.key();
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key.to_public_bytes().expect("to_vec failed"));
@ -254,7 +281,11 @@ fn test_nsec_query_example_nonet() {
#[ignore]
#[allow(deprecated)]
fn test_nsec_query_example_udp() {
let addr: SocketAddr = ("8.8.8.8", 53).to_socket_addrs().unwrap().next().unwrap();
let addr: SocketAddr = ("8.8.8.8", 53)
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
let conn = UdpClientConnection::new(addr).unwrap();
let client = SecureSyncClient::new(conn).build();
test_nsec_query_example::<UdpClientConnection>(client);
@ -264,7 +295,11 @@ fn test_nsec_query_example_udp() {
#[ignore]
#[allow(deprecated)]
fn test_nsec_query_example_tcp() {
let addr: SocketAddr = ("8.8.8.8", 53).to_socket_addrs().unwrap().next().unwrap();
let addr: SocketAddr = ("8.8.8.8", 53)
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
let conn = TcpClientConnection::new(addr).unwrap();
let client = SecureSyncClient::new(conn).build();
test_nsec_query_example::<TcpClientConnection>(client);
@ -292,7 +327,11 @@ fn test_nsec_query_type() {
"example".to_string(),
"com".to_string()]);
let addr: SocketAddr = ("8.8.8.8", 53).to_socket_addrs().unwrap().next().unwrap();
let addr: SocketAddr = ("8.8.8.8", 53)
.to_socket_addrs()
.unwrap()
.next()
.unwrap();
let conn = TcpClientConnection::new(addr).unwrap();
let client = SecureSyncClient::new(conn).build();
@ -364,13 +403,13 @@ fn create_sig0_ready_client(mut catalog: Catalog) -> (SyncClient, domain::Name)
"com".to_string()]),
RecordType::KEY,
Duration::minutes(5).num_seconds() as u32);
auth_key.set_rdata(RData::KEY(DNSKEY::new(false,
false,
false,
signer.algorithm(),
signer.key()
.to_public_bytes()
.expect("to_vec failed"))));
auth_key
.set_rdata(RData::KEY(KEY::new(Default::default(),
Default::default(),
Default::default(),
Default::default(),
signer.algorithm(),
signer.key().to_public_bytes().expect("to_vec failed"))));
authority.upsert(auth_key, 0);
catalog.upsert(authority.origin().clone(), authority);
@ -393,11 +432,12 @@ fn test_create() {
record.set_rdata(RData::A(Ipv4Addr::new(100, 10, 100, 10)));
let result = client.create(record.clone(), origin.clone()).expect("create failed");
let result = client
.create(record.clone(), origin.clone())
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = client.query(record.name(),
record.dns_class(),
record.rr_type())
let result = client
.query(record.name(), record.dns_class(), record.rr_type())
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 1);
@ -405,14 +445,18 @@ fn test_create() {
// trying to create again should error
// TODO: it would be cool to make this
let result = client.create(record.clone(), origin.clone()).expect("create failed");
let result = client
.create(record.clone(), origin.clone())
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::YXRRSet);
// will fail if already set and not the same value.
let mut record = record.clone();
record.set_rdata(RData::A(Ipv4Addr::new(101, 11, 101, 11)));
let result = client.create(record.clone(), origin.clone()).expect("create failed");
let result = client
.create(record.clone(), origin.clone())
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::YXRRSet);
}
@ -431,17 +475,20 @@ fn test_append() {
record.set_rdata(RData::A(Ipv4Addr::new(100, 10, 100, 10)));
// first check the must_exist option
let result = client.append(record.clone(), origin.clone(), true).expect("append failed");
let result = client
.append(record.clone(), origin.clone(), true)
.expect("append failed");
assert_eq!(result.response_code(), ResponseCode::NXRRSet);
// next append to a non-existent RRset
let result = client.append(record.clone(), origin.clone(), false).expect("append failed");
let result = client
.append(record.clone(), origin.clone(), false)
.expect("append failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// verify record contents
let result = client.query(record.name(),
record.dns_class(),
record.rr_type())
let result = client
.query(record.name(), record.dns_class(), record.rr_type())
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 1);
@ -451,34 +498,42 @@ fn test_append() {
let mut record = record.clone();
record.set_rdata(RData::A(Ipv4Addr::new(101, 11, 101, 11)));
let result = client.append(record.clone(), origin.clone(), true).expect("create failed");
let result = client
.append(record.clone(), origin.clone(), true)
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = client.query(record.name(),
record.dns_class(),
record.rr_type())
let result = client
.query(record.name(), record.dns_class(), record.rr_type())
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 2);
assert!(result.answers().iter().any(|rr| if let &RData::A(ref ip) = rr.rdata() {
*ip == Ipv4Addr::new(100, 10, 100, 10)
} else {
false
}));
assert!(result.answers().iter().any(|rr| if let &RData::A(ref ip) = rr.rdata() {
*ip == Ipv4Addr::new(101, 11, 101, 11)
} else {
false
}));
assert!(result
.answers()
.iter()
.any(|rr| if let &RData::A(ref ip) = rr.rdata() {
*ip == Ipv4Addr::new(100, 10, 100, 10)
} else {
false
}));
assert!(result
.answers()
.iter()
.any(|rr| if let &RData::A(ref ip) = rr.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 = client.append(record.clone(), origin.clone(), true).expect("create failed");
let result = client
.append(record.clone(), origin.clone(), true)
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = client.query(record.name(),
record.dns_class(),
record.rr_type())
let result = client
.query(record.name(), record.dns_class(), record.rr_type())
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 2);
@ -497,44 +552,56 @@ fn test_compare_and_swap() {
Duration::minutes(5).num_seconds() as u32);
record.set_rdata(RData::A(Ipv4Addr::new(100, 10, 100, 10)));
let result = client.create(record.clone(), origin.clone()).expect("create failed");
let result = client
.create(record.clone(), origin.clone())
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let current = record;
let mut new = current.clone();
new.set_rdata(RData::A(Ipv4Addr::new(101, 11, 101, 11)));
let result = client.compare_and_swap(current.clone(), new.clone(), origin.clone())
let result = client
.compare_and_swap(current.clone(), new.clone(), origin.clone())
.expect("compare_and_swap failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = client.query(new.name(), new.dns_class(), new.rr_type())
let result = client
.query(new.name(), new.dns_class(), new.rr_type())
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 1);
assert!(result.answers().iter().any(|rr| if let &RData::A(ref ip) = rr.rdata() {
*ip == Ipv4Addr::new(101, 11, 101, 11)
} else {
false
}));
assert!(result
.answers()
.iter()
.any(|rr| if let &RData::A(ref ip) = rr.rdata() {
*ip == Ipv4Addr::new(101, 11, 101, 11)
} else {
false
}));
// check the it fails if tried again.
let mut new = new;
new.set_rdata(RData::A(Ipv4Addr::new(102, 12, 102, 12)));
let result = client.compare_and_swap(current, new.clone(), origin.clone())
let result = client
.compare_and_swap(current, new.clone(), origin.clone())
.expect("compare_and_swap failed");
assert_eq!(result.response_code(), ResponseCode::NXRRSet);
let result = client.query(new.name(), new.dns_class(), new.rr_type())
let result = client
.query(new.name(), new.dns_class(), new.rr_type())
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 1);
assert!(result.answers().iter().any(|rr| if let &RData::A(ref ip) = rr.rdata() {
*ip == Ipv4Addr::new(101, 11, 101, 11)
} else {
false
}));
assert!(result
.answers()
.iter()
.any(|rr| if let &RData::A(ref ip) = rr.rdata() {
*ip == Ipv4Addr::new(101, 11, 101, 11)
} else {
false
}));
}
#[test]
@ -551,33 +618,43 @@ fn test_delete_by_rdata() {
record.set_rdata(RData::A(Ipv4Addr::new(100, 10, 100, 10)));
// first check the must_exist option
let result = client.delete_by_rdata(record.clone(), origin.clone()).expect("delete failed");
let result = client
.delete_by_rdata(record.clone(), origin.clone())
.expect("delete failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = client.create(record.clone(), origin.clone()).expect("create failed");
let result = client
.create(record.clone(), origin.clone())
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.set_rdata(RData::A(Ipv4Addr::new(101, 11, 101, 11)));
let result = client.append(record.clone(), origin.clone(), true).expect("create failed");
let result = client
.append(record.clone(), origin.clone(), true)
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// verify record contents
let result = client.delete_by_rdata(record.clone(), origin.clone()).expect("delete failed");
let result = client
.delete_by_rdata(record.clone(), origin.clone())
.expect("delete failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = client.query(record.name(),
record.dns_class(),
record.rr_type())
let result = client
.query(record.name(), record.dns_class(), record.rr_type())
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
assert_eq!(result.answers().len(), 1);
assert!(result.answers().iter().any(|rr| if let &RData::A(ref ip) = rr.rdata() {
*ip == Ipv4Addr::new(100, 10, 100, 10)
} else {
false
}));
assert!(result
.answers()
.iter()
.any(|rr| if let &RData::A(ref ip) = rr.rdata() {
*ip == Ipv4Addr::new(100, 10, 100, 10)
} else {
false
}));
}
#[test]
@ -594,25 +671,32 @@ fn test_delete_rrset() {
record.set_rdata(RData::A(Ipv4Addr::new(100, 10, 100, 10)));
// first check the must_exist option
let result = client.delete_rrset(record.clone(), origin.clone()).expect("delete failed");
let result = client
.delete_rrset(record.clone(), origin.clone())
.expect("delete failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = client.create(record.clone(), origin.clone()).expect("create failed");
let result = client
.create(record.clone(), origin.clone())
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.set_rdata(RData::A(Ipv4Addr::new(101, 11, 101, 11)));
let result = client.append(record.clone(), origin.clone(), true).expect("create failed");
let result = client
.append(record.clone(), origin.clone(), true)
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// verify record contents
let result = client.delete_rrset(record.clone(), origin.clone()).expect("delete failed");
let result = client
.delete_rrset(record.clone(), origin.clone())
.expect("delete failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = client.query(record.name(),
record.dns_class(),
record.rr_type())
let result = client
.query(record.name(), record.dns_class(), record.rr_type())
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NXDomain);
assert_eq!(result.answers().len(), 0);
@ -632,31 +716,39 @@ fn test_delete_all() {
record.set_rdata(RData::A(Ipv4Addr::new(100, 10, 100, 10)));
// first check the must_exist option
let result = client.delete_all(record.name().clone(), origin.clone(), DNSClass::IN)
let result = client
.delete_all(record.name().clone(), origin.clone(), DNSClass::IN)
.expect("delete failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = client.create(record.clone(), origin.clone()).expect("create failed");
let result = client
.create(record.clone(), origin.clone())
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.set_rr_type(RecordType::AAAA);
record.set_rdata(RData::AAAA(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)));
let result = client.create(record.clone(), origin.clone()).expect("create failed");
let result = client
.create(record.clone(), origin.clone())
.expect("create failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
// verify record contents
let result = client.delete_all(record.name().clone(), origin.clone(), DNSClass::IN)
let result = client
.delete_all(record.name().clone(), origin.clone(), DNSClass::IN)
.expect("delete failed");
assert_eq!(result.response_code(), ResponseCode::NoError);
let result = client.query(record.name(), record.dns_class(), RecordType::A)
let result = client
.query(record.name(), record.dns_class(), RecordType::A)
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NXDomain);
assert_eq!(result.answers().len(), 0);
let result = client.query(record.name(), record.dns_class(), RecordType::AAAA)
let result = client
.query(record.name(), record.dns_class(), RecordType::AAAA)
.expect("query failed");
assert_eq!(result.response_code(), ResponseCode::NXDomain);
assert_eq!(result.answers().len(), 0);