support KEY flags
fix Signer to use RData for key_tag
This commit is contained in:
parent
63c473ff78
commit
80ad0e221b
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
805
client/src/rr/rdata/key.rs
Normal 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());
|
||||
}
|
@ -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;
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user