NameUsage with trie for all zones and ancestor search

This commit is contained in:
Benjamin Fry 2018-01-18 00:23:03 -08:00
parent d829820e63
commit 539e8280da
7 changed files with 639 additions and 3 deletions

23
Cargo.lock generated
View File

@ -269,6 +269,11 @@ name = "ena"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "endian-type"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "env_logger"
version = "0.4.3"
@ -589,6 +594,11 @@ dependencies = [
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nibble_vec"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num"
version = "0.1.41"
@ -694,6 +704,15 @@ name = "quote"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "radix_trie"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"nibble_vec 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.3.19"
@ -1142,6 +1161,7 @@ dependencies = [
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)",
"radix_trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1382,6 +1402,7 @@ dependencies = [
"checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8"
"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3"
"checksum ena 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe5a5078ac8c506d3e4430763b1ba9b609b1286913e7d08e581d1c2de9b7e5"
"checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
"checksum error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faa976b4fd2e4c2b2f3f486874b19e61944d3de3de8b61c9fcf835d583871bcc"
"checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46"
@ -1419,6 +1440,7 @@ dependencies = [
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04b781c9134a954c84f0594b9ab3f5606abc516030388e8511887ef4c204a1e5"
"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
"checksum nibble_vec 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "62e678237a4c70c5f2b917cefd7d080dfbf800421f06e8a59d4e28ef5130fd9e"
"checksum num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4083e14b542ea3eb9b5f33ff48bd373a92d78687e74f4cc0a30caeb754f0ca"
"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba"
"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01"
@ -1433,6 +1455,7 @@ dependencies = [
"checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0"
"checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum radix_trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "211c49b6a9995cac0fd1dd9ca60b42cf3a51e151a12eb954b3a9e75513426ee8"
"checksum rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7944d95d25ace8f377da3ac7068ce517e4c646754c43a1b1849177bbf72e59"
"checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8"
"checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53"

View File

@ -1,6 +1,7 @@
// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
// Copyright 2015-2018 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

View File

@ -55,6 +55,7 @@ idna = "^0.1.4"
lazy_static = "^1.0"
log = "^0.3.5"
openssl = { version = "^0.9.8", features = ["v102", "v110"], optional = true }
radix_trie = "0.1.2"
rand = "^0.3"
ring = { version = "^0.12", optional = true }
tokio-core = "^0.1"

View File

@ -11,6 +11,7 @@
//! TRust-DNS Protocol library
extern crate byteorder;
#[cfg(feature = "dnssec")]
extern crate data_encoding;
#[macro_use]
@ -19,9 +20,12 @@ extern crate error_chain;
extern crate futures;
extern crate idna;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[cfg(feature = "openssl")]
extern crate openssl;
extern crate radix_trie;
extern crate rand;
#[cfg(feature = "ring")]
extern crate ring;
@ -31,7 +35,6 @@ extern crate tokio_io;
#[cfg(feature = "ring")]
extern crate untrusted;
extern crate url;
extern crate byteorder;
use std::marker::PhantomData;
use std::net::SocketAddr;

View File

@ -9,8 +9,9 @@
//! Domain name associated types, suchas Name and Label.
pub mod label;
mod label;
mod name;
pub mod usage;
pub use self::name::{IntoName, Name};
pub use self::label::{IntoLabel, Label};

View File

@ -16,6 +16,8 @@ use std::ops::Index;
use std::slice::Iter;
use std::str::FromStr;
use radix_trie::TrieKey;
use rr::domain::label::{CaseInsensitive, CaseSensitive, IntoLabel, Label, LabelCmp};
use serialize::binary::*;
use error::*;
@ -1006,6 +1008,19 @@ impl IntoName for String {
}
}
impl TrieKey for Name {
/// Returns this name in byte form, reversed for searching from zone to local label
///
/// # Panics
///
/// This will panic on bad names
fn encode_bytes(&self) -> Vec<u8> {
let mut bytes = self.to_bytes().expect("bad name for trie");
bytes.reverse();
bytes
}
}
#[cfg(test)]
mod tests {
use std::cmp::Ordering;

View File

@ -0,0 +1,592 @@
// Copyright 2015-2018 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! Reserved zone names.
//!
//! see [Special-Use Domain Names](https://tools.ietf.org/html/rfc6761), RFC 6761 February, 2013
use std::ops::Deref;
use radix_trie::Trie;
use rr::domain::{Label, Name};
lazy_static!{
/// Default Name usage, everything is normal...
pub static ref DEFAULT: NameUsage = NameUsage::default();
}
/// Reserved reverse IPs
///
/// [Special-Use Domain Names](https://tools.ietf.org/html/rfc6761), RFC 6761 February, 2013
///
/// ```text
/// 6.1. Domain Name Reservation Considerations for Private Addresses
///
/// The private-address [RFC1918] reverse-mapping domains listed below,
/// and any names falling within those domains, are Special-Use Domain
/// Names:
///
/// 10.in-addr.arpa. 21.172.in-addr.arpa. 26.172.in-addr.arpa.
/// 16.172.in-addr.arpa. 22.172.in-addr.arpa. 27.172.in-addr.arpa.
/// 17.172.in-addr.arpa. 30.172.in-addr.arpa. 28.172.in-addr.arpa.
/// 18.172.in-addr.arpa. 23.172.in-addr.arpa. 29.172.in-addr.arpa.
/// 19.172.in-addr.arpa. 24.172.in-addr.arpa. 31.172.in-addr.arpa.
/// 20.172.in-addr.arpa. 25.172.in-addr.arpa. 168.192.in-addr.arpa.
/// ```
lazy_static! {
static ref ARPA: Name = Name::from_ascii("arpa.").unwrap();
static ref IN_ADDR_ARPA: Name = Name::from_ascii("in-addr").unwrap().append_domain(&*ARPA);
// static ref IP6_ARPA: Name = Name::from_ascii("ip6").unwrap().append_domain(&*ARPA);
/// 10.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_10: NameUsage = NameUsage::reverse(Name::from_ascii("10").unwrap().append_domain(&*IN_ADDR_ARPA));
static ref IN_ADDR_ARPA_172: Name = Name::from_ascii("172").unwrap().append_domain(&*IN_ADDR_ARPA);
/// 16.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_16: NameUsage = NameUsage::reverse(Name::from_ascii("16").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 17.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_17: NameUsage = NameUsage::reverse(Name::from_ascii("17").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 18.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_18: NameUsage = NameUsage::reverse(Name::from_ascii("18").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 19.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_19: NameUsage = NameUsage::reverse(Name::from_ascii("19").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 20.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_20: NameUsage = NameUsage::reverse(Name::from_ascii("20").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 21.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_21: NameUsage = NameUsage::reverse(Name::from_ascii("21").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 22.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_22: NameUsage = NameUsage::reverse(Name::from_ascii("22").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 23.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_23: NameUsage = NameUsage::reverse(Name::from_ascii("23").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 24.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_24: NameUsage = NameUsage::reverse(Name::from_ascii("24").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 25.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_25: NameUsage = NameUsage::reverse(Name::from_ascii("25").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 26.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_26: NameUsage = NameUsage::reverse(Name::from_ascii("26").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 27.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_27: NameUsage = NameUsage::reverse(Name::from_ascii("27").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 28.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_28: NameUsage = NameUsage::reverse(Name::from_ascii("28").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 29.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_29: NameUsage = NameUsage::reverse(Name::from_ascii("29").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 30.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_30: NameUsage = NameUsage::reverse(Name::from_ascii("30").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 31.172.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_172_31: NameUsage = NameUsage::reverse(Name::from_ascii("31").unwrap().append_domain(&*IN_ADDR_ARPA_172));
/// 168.192.in-addr.arpa. usage
pub static ref IN_ADDR_ARPA_192_168: NameUsage = NameUsage::reverse(Name::from_ascii("168.192").unwrap().append_domain(&*IN_ADDR_ARPA));
}
/// test.
///
/// [Special-Use Domain Names](https://tools.ietf.org/html/rfc6761), RFC 6761 February, 2013
///
/// ```text
/// 6.2. Domain Name Reservation Considerations for "test."
///
/// The domain "test.", and any names falling within ".test.", are
/// special in the following ways:
/// ```
lazy_static! {
/// test. usage
pub static ref TEST: NameUsage = NameUsage::test(Name::from_ascii("test.").unwrap());
}
/// localhost.
///
/// [Special-Use Domain Names](https://tools.ietf.org/html/rfc6761), RFC 6761 February, 2013
///
/// ```text
/// 6.3. Domain Name Reservation Considerations for "localhost."
///
/// The domain "localhost." and any names falling within ".localhost."
/// are special in the following ways:
/// ```
lazy_static! {
/// localhost. usage
pub static ref LOCALHOST: NameUsage = NameUsage::localhost(Name::from_ascii("localhost.").unwrap());
}
/// invalid.
///
/// [Special-Use Domain Names](https://tools.ietf.org/html/rfc6761), RFC 6761 February, 2013
///
/// ```text
/// 6.4. Domain Name Reservation Considerations for "invalid."
///
/// The domain "invalid." and any names falling within ".invalid." are
/// special in the ways listed below. In the text below, the term
/// "invalid" is used in quotes to signify such names, as opposed to
/// names that may be invalid for other reasons (e.g., being too long).
/// ```
lazy_static! {
/// invalid. name usage
pub static ref INVALID: NameUsage = NameUsage::invalid(Name::from_ascii("invalid.").unwrap());
}
/// example., example.com., example.net., and example.org.
///
/// [Special-Use Domain Names](https://tools.ietf.org/html/rfc6761), RFC 6761 February, 2013
///
/// ```text
/// 6.5. Domain Name Reservation Considerations for Example Domains
///
/// The domains "example.", "example.com.", "example.net.",
/// "example.org.", and any names falling within those domains, are
/// special in the following ways:
/// ```
lazy_static! {
static ref COM: Label = Label::from_ascii("com").unwrap();
static ref NET: Label = Label::from_ascii("net").unwrap();
static ref ORG: Label = Label::from_ascii("org").unwrap();
static ref EXAMPLE_L: Label = Label::from_ascii("example").unwrap();
/// example. usage
pub static ref EXAMPLE: NameUsage = NameUsage::example(Name::from_labels(vec![EXAMPLE_L.clone()]).unwrap());
/// example.com. usage
pub static ref EXAMPLE_COM: NameUsage = NameUsage::example(Name::from_labels(vec![EXAMPLE_L.clone(), COM.clone()]).unwrap());
/// example.com. usage
pub static ref EXAMPLE_NET: NameUsage = NameUsage::example(Name::from_labels(vec![EXAMPLE_L.clone(), NET.clone()]).unwrap());
/// example.com. usage
pub static ref EXAMPLE_ORG: NameUsage = NameUsage::example(Name::from_labels(vec![EXAMPLE_L.clone(), ORG.clone()]).unwrap());
}
/// Users:
///
/// Are human users expected to recognize these names as special and
/// use them differently? In what way?
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum UserUsage {
/// Users are free to use these names as they would any other
/// reverse-mapping names. However, since there is no central
/// authority responsible for use of private addresses, users SHOULD
/// be aware that these names are likely to yield different results
/// on different networks.
Normal,
/// Users are free to use localhost names as they would any other
/// domain names. Users may assume that IPv4 and IPv6 address
/// queries for localhost names will always resolve to the respective
/// IP loopback address.
Loopback,
/// Users are free to use "invalid" names as they would any other
/// domain names. Users MAY assume that queries for "invalid" names
/// will always return NXDOMAIN responses.
NxDomain,
}
/// Application Software:
///
/// Are writers of application software expected to make their
/// software recognize these names as special and treat them
/// differently? In what way? (For example, if a human user enters
/// such a name, should the application software reject it with an
/// error message?)
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum AppUsage {
/// Application software SHOULD NOT recognize these names as special,
/// and SHOULD use these names as they would other reverse-mapping
/// names.
///
/// Application software SHOULD NOT recognize test names as special,
/// and SHOULD use test names as they would other domain names.
///
/// Application software SHOULD NOT recognize example names as
/// special and SHOULD use example names as they would other domain
/// names.
Normal,
/// Application software MAY recognize localhost names as special, or
/// MAY pass them to name resolution APIs as they would for other
/// domain names.
Loopback,
/// Application software MAY recognize "invalid" names as special or
/// MAY pass them to name resolution APIs as they would for other
/// domain names.
NxDomain,
}
/// Name Resolution APIs and Libraries:
///
/// Are writers of name resolution APIs and libraries expected to
/// make their software recognize these names as special and treat
/// them differently? If so, how?
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum ResolveUsage {
/// Name resolution APIs and libraries SHOULD NOT recognize these
/// names as special and SHOULD NOT treat them differently. Name
/// resolution APIs SHOULD send queries for these names to their
/// configured caching DNS server(s).
///
/// Name resolution APIs and libraries SHOULD NOT recognize test
/// names as special and SHOULD NOT treat them differently. Name
/// resolution APIs SHOULD send queries for test names to their
/// configured caching DNS server(s).
///
/// Name resolution APIs and libraries SHOULD NOT recognize example
/// names as special and SHOULD NOT treat them differently. Name
/// resolution APIs SHOULD send queries for example names to their
/// configured caching DNS server(s).
Normal,
/// Name resolution APIs and libraries SHOULD recognize localhost
/// names as special and SHOULD always return the IP loopback address
/// for address queries and negative responses for all other query
/// types. Name resolution APIs SHOULD NOT send queries for
/// localhost names to their configured caching DNS server(s).
Loopback,
/// Name resolution APIs and libraries SHOULD recognize "invalid"
/// names as special and SHOULD always return immediate negative
/// responses. Name resolution APIs SHOULD NOT send queries for
/// "invalid" names to their configured caching DNS server(s).
NxDomain,
}
/// Caching DNS Servers:
///
/// Are developers of caching domain name servers expected to make
/// their implementations recognize these names as special and treat
/// them differently? If so, how?
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum CacheUsage{
/// Caching DNS servers SHOULD recognize these names as special and
/// SHOULD NOT, by default, attempt to look up NS records for them,
/// or otherwise query authoritative DNS servers in an attempt to
/// resolve these names. Instead, caching DNS servers SHOULD, by
/// default, generate immediate (positive or negative) responses for
/// all such queries. This is to avoid unnecessary load on the root
/// name servers and other name servers. Caching DNS servers SHOULD
/// offer a configuration option (disabled by default) to enable
/// upstream resolution of such names, for use in private networks
/// where private-address reverse-mapping names are known to be
/// handled by an authoritative DNS server in said private network.
NonRecursive,
/// Caching DNS servers SHOULD recognize "invalid" names as special
/// and SHOULD NOT attempt to look up NS records for them, or
/// otherwise query authoritative DNS servers in an attempt to
/// resolve "invalid" names. Instead, caching DNS servers SHOULD
/// generate immediate NXDOMAIN responses for all such queries. This
/// is to avoid unnecessary load on the root name servers and other
/// name servers.
NxDomain,
/// Caching DNS servers SHOULD recognize localhost names as special
/// and SHOULD NOT attempt to look up NS records for them, or
/// otherwise query authoritative DNS servers in an attempt to
/// resolve localhost names. Instead, caching DNS servers SHOULD,
/// for all such address queries, generate an immediate positive
/// response giving the IP loopback address, and for all other query
/// types, generate an immediate negative response. This is to avoid
/// unnecessary load on the root name servers and other name servers.
Loopback,
/// Caching DNS servers SHOULD NOT recognize example names as special
/// and SHOULD resolve them normally.
Normal,
}
/// Authoritative DNS Servers:
///
/// Are developers of authoritative domain name servers expected to
/// make their implementations recognize these names as special and
/// treat them differently? If so, how?
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum AuthUsage{
/// Authoritative DNS servers SHOULD recognize these names as special
/// and SHOULD, by default, generate immediate negative responses for
/// all such queries, unless explicitly configured by the
/// administrator to give positive answers for private-address
/// reverse-mapping names.
NxOrLocal,
/// Authoritative DNS servers SHOULD recognize these names as special
/// and SHOULD, by default, generate immediate negative responses for
/// all such queries, unless explicitly configured by the
/// administrator to give positive answers for private-address
/// reverse-mapping names.
NxDomain,
/// Authoritative DNS servers SHOULD recognize localhost names as
/// special and handle them as described above for caching DNS
/// servers.
Loopback,
/// Authoritative DNS servers SHOULD NOT recognize example names as
/// special.
Normal,
}
/// DNS Server Operators:
///
/// Does this reserved Special-Use Domain Name have any potential
/// impact on DNS server operators? If they try to configure their
/// authoritative DNS server as authoritative for this reserved name,
/// will compliant name server software reject it as invalid? Do DNS
/// server operators need to know about that and understand why?
/// Even if the name server software doesn't prevent them from using
/// this reserved name, are there other ways that it may not work as
/// expected, of which the DNS server operator should be aware?
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum OpUsage {
/// DNS server operators SHOULD, if they are using private addresses,
/// configure their authoritative DNS servers to act as authoritative
/// for these names.
///
/// DNS server operators SHOULD, if they are using test names,
/// configure their authoritative DNS servers to act as authoritative
/// for test names.
Normal,
/// DNS server operators SHOULD be aware that the effective RDATA for
/// localhost names is defined by protocol specification and cannot
/// be modified by local configuration.
Loopback,
/// DNS server operators SHOULD be aware that the effective RDATA for
/// "invalid" names is defined by protocol specification to be
/// nonexistent and cannot be modified by local configuration.
NxDomain,
}
/// DNS Registries/Registrars:
///
/// How should DNS Registries/Registrars treat requests to register
/// this reserved domain name? Should such requests be denied?
/// Should such requests be allowed, but only to a specially-
/// designated entity? (For example, the name "www.example.org" is
/// reserved for documentation examples and is not available for
/// registration; however, the name is in fact registered; and there
/// is even a web site at that name, which states circularly that the
/// name is reserved for use in documentation and cannot be
/// registered!)
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum RegistryUsage{
/// Stanard checks apply
Normal,
/// DNS Registries/Registrars MUST NOT grant requests to register
/// test names in the normal way to any person or entity. Test names
/// are reserved for use in private networks and fall outside the set
/// of names available for allocation by registries/registrars.
/// Attempting to allocate a test name as if it were a normal DNS
/// domain name will probably not work as desired, for reasons 4, 5,
/// and 6 above.
///
/// DNS Registries/Registrars MUST NOT grant requests to register
/// localhost names in the normal way to any person or entity.
/// Localhost names are defined by protocol specification and fall
/// outside the set of names available for allocation by registries/
/// registrars. Attempting to allocate a localhost name as if it
/// were a normal DNS domain name will probably not work as desired,
/// for reasons 2, 3, 4, and 5 above.
///
/// DNS Registries/Registrars MUST NOT grant requests to register
/// "invalid" names in the normal way to any person or entity. These
/// "invalid" names are defined by protocol specification to be
/// nonexistent, and they fall outside the set of names available for
/// allocation by registries/registrars. Attempting to allocate a
/// "invalid" name as if it were a normal DNS domain name will
/// probably not work as desired, for reasons 2, 3, 4, and 5 above.
///
/// DNS Registries/Registrars MUST NOT grant requests to register
/// example names in the normal way to any person or entity. All
/// example names are registered in perpetuity to IANA:
Reserved,
}
/// NameUsage represents information about how a name falling in a given zone should be treated
pub struct NameUsage {
name: Name,
user: UserUsage,
app: AppUsage,
resolve: ResolveUsage,
cache: CacheUsage,
auth: AuthUsage,
op: OpUsage,
registry: RegistryUsage,
}
impl NameUsage {
fn new(name: Name, user: UserUsage, app: AppUsage, resolve: ResolveUsage, cache: CacheUsage, auth: AuthUsage, op: OpUsage, registry: RegistryUsage) -> Self {
NameUsage {name, user, app, resolve, cache, auth, op, registry}
}
fn default() -> Self {
Self::new(Name::root(), UserUsage::Normal, AppUsage::Normal, ResolveUsage::Normal, CacheUsage::Normal, AuthUsage::Normal, OpUsage::Normal, RegistryUsage::Normal)
}
fn reverse(name: Name) -> Self {
Self::new(name, UserUsage::Normal, AppUsage::Normal, ResolveUsage::Normal, CacheUsage::NonRecursive, AuthUsage::NxOrLocal, OpUsage::Normal, RegistryUsage::Reserved)
}
fn test(name: Name) -> Self {
Self::new(name, UserUsage::Normal, AppUsage::Normal, ResolveUsage::Normal, CacheUsage::NonRecursive, AuthUsage::NxOrLocal, OpUsage::Normal, RegistryUsage::Reserved)
}
fn localhost(name: Name) -> Self {
Self::new(name, UserUsage::Loopback, AppUsage::Loopback, ResolveUsage::Loopback, CacheUsage::Loopback, AuthUsage::Loopback, OpUsage::Loopback, RegistryUsage::Reserved)
}
fn invalid(name: Name) -> Self {
Self::new(name, UserUsage::NxDomain, AppUsage::NxDomain, ResolveUsage::NxDomain, CacheUsage::NxDomain, AuthUsage::NxDomain, OpUsage::NxDomain, RegistryUsage::Reserved)
}
fn example(name: Name) -> Self {
Self::new(name, UserUsage::Normal, AppUsage::Normal, ResolveUsage::Normal, CacheUsage::Normal, AuthUsage::Normal, OpUsage::Normal, RegistryUsage::Reserved)
}
}
impl Deref for NameUsage {
type Target = Name;
fn deref(&self) -> &Self::Target {
&self.name
}
}
pub struct UsageTrie(Trie<Name, &'static NameUsage>);
impl UsageTrie {
fn default() -> Self {
let mut trie: Trie<Name, &'static NameUsage> = Trie::new();
assert!(trie.insert(DEFAULT.clone(), &DEFAULT).is_none());
assert!(trie.insert(IN_ADDR_ARPA_10.clone(), &IN_ADDR_ARPA_10).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_16.clone(), &IN_ADDR_ARPA_172_16).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_17.clone(), &IN_ADDR_ARPA_172_17).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_18.clone(), &IN_ADDR_ARPA_172_18).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_19.clone(), &IN_ADDR_ARPA_172_19).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_20.clone(), &IN_ADDR_ARPA_172_20).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_21.clone(), &IN_ADDR_ARPA_172_21).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_22.clone(), &IN_ADDR_ARPA_172_22).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_23.clone(), &IN_ADDR_ARPA_172_23).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_24.clone(), &IN_ADDR_ARPA_172_24).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_25.clone(), &IN_ADDR_ARPA_172_25).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_26.clone(), &IN_ADDR_ARPA_172_26).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_27.clone(), &IN_ADDR_ARPA_172_27).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_28.clone(), &IN_ADDR_ARPA_172_28).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_29.clone(), &IN_ADDR_ARPA_172_29).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_30.clone(), &IN_ADDR_ARPA_172_30).is_none());
assert!(trie.insert(IN_ADDR_ARPA_172_31.clone(), &IN_ADDR_ARPA_172_31).is_none());
assert!(trie.insert(IN_ADDR_ARPA_192_168.clone(), &IN_ADDR_ARPA_192_168).is_none());
assert!(trie.insert(TEST.clone(), &TEST).is_none());
assert!(trie.insert(LOCALHOST.clone(), &LOCALHOST).is_none());
assert!(trie.insert(INVALID.clone(), &INVALID).is_none());
assert!(trie.insert(EXAMPLE.clone(), &EXAMPLE).is_none());
assert!(trie.insert(EXAMPLE_COM.clone(), &EXAMPLE_COM).is_none());
assert!(trie.insert(EXAMPLE_NET.clone(), &EXAMPLE_NET).is_none());
assert!(trie.insert(EXAMPLE_ORG.clone(), &EXAMPLE_ORG).is_none());
UsageTrie(trie)
}
/// Fetches the NameUsage
///
/// # Returns
///
/// Matches the closest zone encapsulating `name`, at a minimum the default root zone usage will be returned
pub fn get(&self, name: &Name) -> &'static NameUsage {
self.0.get_ancestor_value(name).expect("DEFAULT root NameUsage should have been returned")
}
}
lazy_static!{
/// All default usage mappings
pub static ref USAGE: UsageTrie = UsageTrie::default();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_root() {
let name = Name::from_ascii("com.").unwrap();
let usage = USAGE.get(&name);
assert!(usage.is_root());
}
#[test]
fn test_example() {
let name = Name::from_ascii("example.").unwrap();
let usage = USAGE.get(&name);
assert_eq!(usage.name, EXAMPLE.name);
let name = Name::from_ascii("example.com.").unwrap();
let usage = USAGE.get(&name);
assert_eq!(usage.name, EXAMPLE_COM.name);
let name = Name::from_ascii("example.net.").unwrap();
let usage = USAGE.get(&name);
assert_eq!(usage.name, EXAMPLE_NET.name);
let name = Name::from_ascii("example.org.").unwrap();
let usage = USAGE.get(&name);
assert_eq!(usage.name, EXAMPLE_ORG.name);
let name = Name::from_ascii("www.example.org.").unwrap();
let usage = USAGE.get(&name);
assert_eq!(usage.name, EXAMPLE_ORG.name);
}
#[test]
fn test_localhost() {
let name = Name::from_ascii("localhost.").unwrap();
let usage = USAGE.get(&name);
assert_eq!(usage.name, LOCALHOST.name);
let name = Name::from_ascii("this.localhost.").unwrap();
let usage = USAGE.get(&name);
assert_eq!(usage.name, LOCALHOST.name);
}
#[test]
fn test_invalid() {
let name = Name::from_ascii("invalid.").unwrap();
let usage = USAGE.get(&name);
assert_eq!(usage.name, INVALID.name);
let name = Name::from_ascii("something.invalid.").unwrap();
let usage = USAGE.get(&name);
assert_eq!(usage.name, INVALID.name);
}
#[test]
fn test_test() {
let name = Name::from_ascii("test.").unwrap();
let usage = USAGE.get(&name);
assert_eq!(usage.name, TEST.name);
let name = Name::from_ascii("foo.bar.test.").unwrap();
let usage = USAGE.get(&name);
assert_eq!(usage.name, TEST.name);
}
}