cleanup Name and deprecate some interfaces

This commit is contained in:
Benjamin Fry
2017-07-28 08:11:02 -07:00
parent dee0a33c5e
commit 90db66c6ea
13 changed files with 811 additions and 476 deletions

4
.markdownlint.json Normal file
View File

@@ -0,0 +1,4 @@
{
"MD013": false,
"MD024": false
}

View File

@@ -1,81 +1,109 @@
# Change Log: TRust-DNS
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 0.11.0
### Added
- `Name::FromStr` for simpler parsing, specify trailing `.` for FQDN
- `Name::append_label` for clearer usage while appending labels to a Name
- `Name::append_name` for clearer usage while appending one name to another
- `Name::append_domain` alias for append_name and marking as FQDN
### Changed
- *breaking* all `&mut self` methods on `Name` deprecated as unsafe, Name is now immutable.
- *breaking* All `ClientHandle` traits now take `&Handle` instead of `Handle` (@rushmorem)
- *warning* `Name` now tracks if it is a fully qualified domain name, slightly changes name parsing rules, allowing `www.example.com` without the trailing `.`, which means that FQDN names are not enforced.
### Removed
- deprecated `Name::with_labels` see `Name::from_labels`
- *deprecated* `Name::with_labels` see `Name::from_labels`
- *deprecated* `Name::append` wasn't clean, see `Name::append_name`
- *deprecated* `Name::add_label` exposed internal data structure, see `Name::append_label`
- *deprecated* `Name::label` unclear usage/name, see `Name::append_label`
- *deprecated* `Name::prepend_label` exposed internal data structure, unclear usage (no replacement)
- *deprecated* `Record::add_name` unclear usage (no replacement)
## 0.10.5
### Added
- Library documentation, examples for client query and update
### Changed
- ServerFuture now Accepts generic RequestHandler (@Antti)
## 0.10.4
### Added
- Allow more options with Key and KeyUsage
- Initial Resolver implementation
### Fixed
- NSEC coverage bitmap overflow in nightly
- Name::zone_of panic (@SAPikachu)
## 0.10.3
### Fixed
- Proper TCP connection timeout
- Fixed signature format of ECDSA (@SAPikachu) #141
## 0.10.2
### Fixed
- Fixed format of ED25519 keys (@briansmith) #129
### Changed
- Revamped signer and keypair to better deal with public key (possible breaking change)
- Upgraded *ring* to 0.9.x series, requires pkcs8 for key storage
- Dropped support for dangerous private key byte access (possible breaking change)
- Upgraded tokio-rustls and rustls dependencies to support *ring* updates
### Added
- PublicKey and Verifier for verifying with zero copy from KEY and DNSKEY (possible breaking change)
- Pkcs8 as a supported KeyFormat for storage (possible breaking change)
## 0.10.1
### Added
- Added `From<IpAddr>` for Name (reverse DNS) #105
- Added `From<IpAddr>` for Name (reverse DNS) #105
- AppVeyor support #103
- rustls client tls support (seperate crate)
- rustls client tls support (separate crate)
- full support for KEY RR in client
- compatibility tests with BIND for SIG0 updates
- Added full implementation of KEY type
### Changed
- Updated TLS documentation, added more elsewhere, docs required; fixes #102
- Upgraded tokio-core and moved to tokio-io
- *Important* Some `Server` types have been migrated to [RFC#344](https://github.com/aturon/rfcs/blob/conventions-galore/active/0000-conventions-galore.md#gettersetter-apis) style. `get_field()` -> `field()`; `field()` -> `set_field()`
- Moved native-tls client impl to seperate crate
- Moved native-tls client impl to separate crate
- Defaulted to OpenSSL for tls implementation
### Fixed
- key_tag calculation for DNSKEY and KEY now correct #118 (@jannic)
- SIG0 signing fixed to match RFC and BIND #120 (@jannic)
## 0.10.0
### Changed
- *Important* Possible breaking API change, the original Client has been renamed
- *Important* Possible breaking API change, the original Client has been renamed.
In an attempt to reduce the overhead of managing the project. The original
Client has now been revamped to essentially be a synchronous Client over the
ClientFuture implementation. The ClientFuture has proven to be a more stable
@@ -83,17 +111,21 @@ and reliable implementation. It was attempted to make the move seamless,
but two new types were introduced, `SyncClient` and `SecureSyncClient`, which
are both synchronous implementations of the old Client function interfaces.
Please read those docs on those new types and the Client trait.
- When EDNS option is present, return only the digest understood matching RRSETs
- All code reformatted with rustfmt
- *Important* breaking change, all `Record` and associated types have been migrated to [RFC#344](https://github.com/aturon/rfcs/blob/conventions-galore/active/0000-conventions-galore.md#gettersetter-apis) style. `get_field()` -> `field()`; `field()` -> `set_field()`
### Removed
- *Important* The original Server implementation was removed entirely. Please
use the ServerFuture implementation from now on. Sorry for the inconvenience,
- *Important* The original Server implementation was removed entirely.
Please use the ServerFuture implementation from now on. Sorry for the inconvenience,
but this is necessary to make sure that the software remains at a high quality
and there is no easy way to migrate the original Server to use ServerFuture.
### Added
- Initial support for ECDSAP256SHA256, ECDSAP384SHA384 and ED25519 (client and server)
- additional config options for keys to named, see `tests/named_test_configs/example.toml`
- Added DNS over TLS support, RFC 7858, #38
@@ -101,20 +133,28 @@ and there is no easy way to migrate the original Server to use ServerFuture.
- matrixed tests for all features to Travis
## 0.9.3
### Changed
- updated to rust-openssl 0.9.x series
- restructured dnssec code to better support alternate key formats
## 0.9.2
### Changed
- mio_client is now an optional feature in favor of the futures-rs ClientFuture
## 0.9.1
### Changed
- OpenSSL is now an optional feature for the client
## 0.9.0
### Added
- new ServerFuture tokio and futures based server, #61
- UdpStream & TcpSteam to support stream of messages with src address
- TimeoutStream to wrap TcpStreams to help guard against malicious clients
@@ -122,6 +162,7 @@ and there is no easy way to migrate the original Server to use ServerFuture.
- Added IntoRecordSet and conversion impls for RecordSet and Record
### Changed
- Split Server and Client into separate crates, #43
- Moved many integration tests to `tests` from `src`, #52
- Migrated all handles to new futures::sync::mpsc impls
@@ -129,59 +170,78 @@ and there is no easy way to migrate the original Server to use ServerFuture.
- All client methods now support multiple records per query, update, notify and delete
### Fixed
- Flush TcpStream after fully sending Message
- Recognize no bytes read as closed TcpStream
## 0.8.1
### Fixed
- Fix build on rustc 1.11, #66
## 0.8.0
### Added
- SecureClientHandle, for future based DNSSec validation.
- ClientFuture, futures based client implementation, #32
### Fixed
- Randomized ports for client connections and message ids, #23
- OpCode::From for u8 removed, added OpCode::from_u8(), #36
- Fix for named startup related to ipv6, #56
### Changed
- Upgraded OpenSSL to 0.8.* #50
- Cleaned up the Server implementation to isolate connection handlers
- Deprecated old Client will possibly remove in the future
## 0.7.3 2016-08-12
### Fixed
- Issue #27: label case sensitivity revisited for RRSIG signing, RFC 6840
- TCP reregister on would-block errors
## 0.7.2 2016-08-10
### Fixed
- Issue #28: RRSIG validation of wildcards, label length > wildcard length
## 0.7.1 2016-08-09
### Fixed
- Issue #27: remove implicit case conversion of labels (fixes NSEC validation)
## 0.7.0 2016-06-20
### Added
- Added recovery from journal to named startup
- SQLite journal for dynamic update persistence
- Private Key generation during startup, for dnssec zones
- Read private key from filesystem during start and registers to zone
### Changed
- Removed many of the unwraps in named binary
- Reworked all errors to use error-chain
- Adjusted interface for Signer to use duration
- All `#[cfg(ftest)]` tests now `#[ignore]`
### Fixed
- TXT record case sensitivity
## 0.6.0 2016-06-01
### Added
- Documentation on all modules, and many standard RFC types
- Authority zone signing now complete, still need to load/save private keys
- DNSKEYs auto inserted for added private keys
@@ -192,12 +252,14 @@ and there is no easy way to migrate the original Server to use ServerFuture.
- Client compare_and_swap operation... atomics are here!
### Fixed
- Added loop on TCP accept requests
- Added loop on UDP reads
- Upgraded to mio 0.5.1 for some bug fixes
- Not returning RRSIGs with SOA records on authoritative answers
### Changed
- Internal representation of record sets now a full data structure
- Better rrset keys for fewer clones
- Removed many excessive clones (should make requests even faster)
@@ -208,15 +270,20 @@ and there is no easy way to migrate the original Server to use ServerFuture.
- Improved ENDS and SIG0 parsing on Message deserialization
## 0.5.3 2016-04-07
### Fixed
- [Linux TCP server mio issues](https://github.com/bluejekyll/trust-dns/issues/9)
### Changed
- combined the TCP client and server handlers
- reusing buffer in TCP handler between send and receive (performance)
## 0.5.2 2016-04-04
### Changed
- updated mio to 0.5.0
- updated chrono to 0.2.21
- updated docopt to 0.6.78
@@ -227,16 +294,21 @@ and there is no easy way to migrate the original Server to use ServerFuture.
- updated toml to 0.1.28
## 0.5.1 2016-03-30
### Added
- NSEC3 resolver validation
- data-ecoding as a dependency (base32hex)
- trust-dns banner on boot of server
### Changed
- Changed the bin.rs to named.rs, more accurate, allow for other binaries
## 0.5.0 2016-03-22
### Added
- Updated rust-openssl to 0.7.8 which include new RSA creation bindings
- NSEC resolver validation
- NSEC3 parsing support
@@ -249,45 +321,60 @@ and there is no easy way to migrate the original Server to use ServerFuture.
- SRV record support
### Changed
- Dual licensed with MIT (and Apache 2.0)
- Abstracted Client over TCP and UDP for common implementation of queries
### Fixed
- Binary Serialization and Deserialization of NSEC3
- AXFR SOA ordering
- Travis build failing
### Deprecated
- See updated trust_dns::client::Client API
## 0.4.0 2015-10-17
### Added
- Added AXFR support
- Dynamic update support
### Fixed
- Name pointer support
## 0.3.1 2015-10-04
### Fixed
- Removed buffer clone during label pointer decoding (speed/memory)
- Removed a lot of unnecessary clones, heavier use of Rc
- Binary server bugs (fully functional)
## 0.3.0 2015-09-27
### Added
- Master zone files support BIND time formats, e.g. #h#d
- Toml config file support (not compatible with BIND)
## 0.2.1 2015-09-17
### Added
- Functional tests to verify against other DNS servers
### Changed
- mio replaced std::net operators
## 0.2.0 2015-09-07
### Added
- Server support with catalog and tests for example.com
- Parsing example rfc1035 master file
- new lexer for master zone files with simplified FSM
@@ -299,12 +386,16 @@ and there is no easy way to migrate the original Server to use ServerFuture.
- DNS Class and RecordType enums
### Fixed
- Crates.io keywords, etc.
### Changed
- Cleaned up binary encoders and decoders with objects
## 0.1.0 2015-08-07
### Added
- Started parsing resource records
- Initial Commit!

View File

@@ -248,10 +248,10 @@ pub fn determine_name(name: &Name, num_labels: u8) -> Option<Name> {
// name = "*." | the rightmost rrsig_label labels of the
// fqdn
if num_labels < fqdn_labels {
let mut star_name: Name = Name::new().label("*");
let mut star_name: Name = Name::from_labels(vec!["*"]);
let rightmost = name.trim_to(num_labels as usize);
if !rightmost.is_root() {
star_name.append(&rightmost);
star_name = star_name.append_name(&rightmost);
return Some(star_name);
}
return Some(star_name);

View File

@@ -168,7 +168,11 @@ impl Nsec3HashAlgorithm {
/// until there is another supported algorithm, just hardcoded to this.
#[cfg(feature = "openssl")]
fn sha1_recursive_hash(salt: &[u8], bytes: Vec<u8>, iterations: u16) -> DnsSecResult<DigestBytes> {
fn sha1_recursive_hash(
salt: &[u8],
bytes: Vec<u8>,
iterations: u16,
) -> DnsSecResult<DigestBytes> {
let digest_type = try!(DigestType::SHA1.to_openssl_digest());
hash::Hasher::new(digest_type)
.map_err(|e| e.into())
@@ -197,72 +201,100 @@ impl From<Nsec3HashAlgorithm> for u8 {
#[cfg(feature = "openssl")]
fn test_hash() {
let name = Name::new().label("www").label("example").label("com");
let name = Name::from_labels(vec!["www", "example", "com"]);
let salt: Vec<u8> = vec![1, 2, 3, 4];
assert_eq!(Nsec3HashAlgorithm::SHA1
.hash(&salt, &name, 0)
.unwrap()
.len(),
20);
assert_eq!(Nsec3HashAlgorithm::SHA1
.hash(&salt, &name, 1)
.unwrap()
.len(),
20);
assert_eq!(Nsec3HashAlgorithm::SHA1
.hash(&salt, &name, 3)
.unwrap()
.len(),
20);
assert_eq!(
Nsec3HashAlgorithm::SHA1
.hash(&salt, &name, 0)
.unwrap()
.len(),
20
);
assert_eq!(
Nsec3HashAlgorithm::SHA1
.hash(&salt, &name, 1)
.unwrap()
.len(),
20
);
assert_eq!(
Nsec3HashAlgorithm::SHA1
.hash(&salt, &name, 3)
.unwrap()
.len(),
20
);
}
#[test]
#[cfg(feature = "openssl")]
fn test_known_hashes() {
// H(example) = 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom
assert_eq!(hash_with_base32("example"),
"0p9mhaveqvm6t7vbl5lop2u3t2rp3tom");
assert_eq!(
hash_with_base32("example"),
"0p9mhaveqvm6t7vbl5lop2u3t2rp3tom"
);
// H(a.example) = 35mthgpgcu1qg68fab165klnsnk3dpvl
assert_eq!(hash_with_base32("a.example"),
"35mthgpgcu1qg68fab165klnsnk3dpvl");
assert_eq!(
hash_with_base32("a.example"),
"35mthgpgcu1qg68fab165klnsnk3dpvl"
);
// H(ai.example) = gjeqe526plbf1g8mklp59enfd789njgi
assert_eq!(hash_with_base32("ai.example"),
"gjeqe526plbf1g8mklp59enfd789njgi");
assert_eq!(
hash_with_base32("ai.example"),
"gjeqe526plbf1g8mklp59enfd789njgi"
);
// H(ns1.example) = 2t7b4g4vsa5smi47k61mv5bv1a22bojr
assert_eq!(hash_with_base32("ns1.example"),
"2t7b4g4vsa5smi47k61mv5bv1a22bojr");
assert_eq!(
hash_with_base32("ns1.example"),
"2t7b4g4vsa5smi47k61mv5bv1a22bojr"
);
// H(ns2.example) = q04jkcevqvmu85r014c7dkba38o0ji5r
assert_eq!(hash_with_base32("ns2.example"),
"q04jkcevqvmu85r014c7dkba38o0ji5r");
assert_eq!(
hash_with_base32("ns2.example"),
"q04jkcevqvmu85r014c7dkba38o0ji5r"
);
// H(w.example) = k8udemvp1j2f7eg6jebps17vp3n8i58h
assert_eq!(hash_with_base32("w.example"),
"k8udemvp1j2f7eg6jebps17vp3n8i58h");
assert_eq!(
hash_with_base32("w.example"),
"k8udemvp1j2f7eg6jebps17vp3n8i58h"
);
// H(*.w.example) = r53bq7cc2uvmubfu5ocmm6pers9tk9en
assert_eq!(hash_with_base32("*.w.example"),
"r53bq7cc2uvmubfu5ocmm6pers9tk9en");
assert_eq!(
hash_with_base32("*.w.example"),
"r53bq7cc2uvmubfu5ocmm6pers9tk9en"
);
// H(x.w.example) = b4um86eghhds6nea196smvmlo4ors995
assert_eq!(hash_with_base32("x.w.example"),
"b4um86eghhds6nea196smvmlo4ors995");
assert_eq!(
hash_with_base32("x.w.example"),
"b4um86eghhds6nea196smvmlo4ors995"
);
// H(y.w.example) = ji6neoaepv8b5o6k4ev33abha8ht9fgc
assert_eq!(hash_with_base32("y.w.example"),
"ji6neoaepv8b5o6k4ev33abha8ht9fgc");
assert_eq!(
hash_with_base32("y.w.example"),
"ji6neoaepv8b5o6k4ev33abha8ht9fgc"
);
// H(x.y.w.example) = 2vptu5timamqttgl4luu9kg21e0aor3s
assert_eq!(hash_with_base32("x.y.w.example"),
"2vptu5timamqttgl4luu9kg21e0aor3s");
assert_eq!(
hash_with_base32("x.y.w.example"),
"2vptu5timamqttgl4luu9kg21e0aor3s"
);
// H(xx.example) = t644ebqk9bibcna874givr6joj62mlhv
assert_eq!(hash_with_base32("xx.example"),
"t644ebqk9bibcna874givr6joj62mlhv");
assert_eq!(
hash_with_base32("xx.example"),
"t644ebqk9bibcna874givr6joj62mlhv"
);
}
#[cfg(test)]

View File

@@ -34,7 +34,7 @@ use error::*;
#[derive(Debug, Eq, Clone)]
pub struct Name {
is_fqdn: bool,
labels: Rc<Vec<Rc<String>>>,
labels: Vec<Rc<String>>,
}
impl Name {
@@ -42,13 +42,14 @@ impl Name {
pub fn new() -> Self {
Name {
is_fqdn: false,
labels: Rc::new(Vec::new()),
labels: Vec::new(),
}
}
/// Returns the root label, i.e. no labels, can probably make this better in the future.
pub fn root() -> Self {
let mut this = Self::new();
// FIXME: what does FQDN mean in the context of appends/prepends?
this.is_fqdn = true;
this
}
@@ -71,6 +72,9 @@ impl Name {
/// Returns true if the name is a fully qualified domain name.
///
/// If this is true, it has effects like only querying for this single name, as opposed to building
/// up a search list in resolvers.
///
/// # Examples
///
/// ```
@@ -96,15 +100,34 @@ impl Name {
}
/// inline builder
#[deprecated]
pub fn label(mut self, label: &'static str) -> Self {
// TODO get_mut() on Arc was unstable when this was written
let mut new_labels: Vec<Rc<String>> = (*self.labels).clone();
let mut new_labels: Vec<Rc<String>> = self.labels;
new_labels.push(Rc::new(label.into()));
self.labels = Rc::new(new_labels);
self.labels = new_labels;
assert!(self.labels.len() < 256); // this should be an error
self
}
/// Appends the label to the end of this name
///
/// # Example
///
/// ```rust
/// use std::str::FromStr;
/// use trust_dns::rr::domain::Name;
///
/// let name = Name::from_str("www.example").unwrap();
/// let name = name.append_label("com");
/// assert_eq!(name, Name::from_str("www.example.com").unwrap());
/// ```
pub fn append_label<S: Into<String>>(mut self, label: S) -> Self {
self.labels.push(Rc::new(label.into()));
assert!(self.labels.len() < 256); // TODO: should this be an Error?
self
}
/// Creates a new Name from the specified labels
///
/// # Arguments
@@ -127,7 +150,7 @@ impl Name {
assert!(labels.len() < 256); // this should be an error
Name {
is_fqdn: false,
labels: Rc::new(labels.into_iter().map(|s| Rc::new(s.into())).collect()),
labels: labels.into_iter().map(|s| Rc::new(s.into())).collect(),
}
}
@@ -137,7 +160,8 @@ impl Name {
Self::from_labels(labels)
}
/// prepend the String to the label
/// Prepends the label to this Name, returning a new name
#[deprecated]
pub fn prepend_label(&self, label: Rc<String>) -> Self {
let mut new_labels: Vec<Rc<String>> = Vec::with_capacity(self.labels.len() + 1);
new_labels.push(label);
@@ -149,21 +173,22 @@ impl Name {
assert!(new_labels.len() < 256); // this should be an error
Name {
is_fqdn: self.is_fqdn,
labels: Rc::new(new_labels),
labels: new_labels,
}
}
/// appends the String to this label at the end
#[deprecated]
pub fn add_label(&mut self, label: Rc<String>) -> &mut Self {
// TODO get_mut() on Arc was unstable when this was written
let mut new_labels: Vec<Rc<String>> = (*self.labels).clone();
new_labels.push(label);
self.labels = Rc::new(new_labels);
self.labels.push(label);
assert!(self.labels.len() < 256); // this should be an error
self
}
/// appends the other to this name
#[deprecated]
#[allow(deprecated)]
pub fn append(&mut self, other: &Self) -> &mut Self {
for rcs in &*other.labels {
self.add_label(rcs.clone());
@@ -172,6 +197,52 @@ impl Name {
self
}
/// Appends other Name to self, returning a new Name
///
/// # Examples
///
/// ```rust
/// use std::str::FromStr;
/// use trust_dns::rr::domain::Name;
///
/// let local = Name::from_str("www").unwrap();
/// let domain = Name::from_str("example.com").unwrap();
/// let name = local.append_name(&domain);
/// assert_eq!(name, Name::from_str("www.example.com").unwrap());
/// assert!(!name.is_fqdn())
/// ```
pub fn append_name(mut self, other: &Self) -> Self {
self.labels.reserve_exact(other.labels.len());
for label in other.labels.iter() {
self.labels.push(label.clone());
}
self
}
/// Appends the domain name to this name, making the new name an FQDN
///
/// This is an alias for append_name with the added effect of marking the new Name as
/// a fully-qualified-domain-name.
///
/// # Examples
///
/// ```rust
/// use std::str::FromStr;
/// use trust_dns::rr::domain::Name;
///
/// let local = Name::from_str("www").unwrap();
/// let domain = Name::from_str("example.com").unwrap();
/// let name = local.append_domain(&domain);
/// assert_eq!(name, Name::from_str("www.example.com").unwrap());
/// assert!(name.is_fqdn())
/// ```
pub fn append_domain(self, domain: &Self) -> Self {
let mut this = self.append_name(domain);
this.set_fqdn(true);
this
}
/// Creates a new Name with all labels lowercased
///
/// # Examples
@@ -232,7 +303,7 @@ impl Name {
let trim = self.labels.len() - num_labels;
Name {
is_fqdn: self.is_fqdn,
labels: Rc::new(self.labels[trim..].to_vec()),
labels: self.labels[trim..].to_vec(),
}
} else {
Self::root()
@@ -335,7 +406,7 @@ impl Name {
ParseState::Label => {
match ch {
'.' => {
name.add_label(Rc::new(label.clone()));
name.labels.push(Rc::new(label.clone()));
label.clear();
}
'\\' => state = ParseState::Escape1,
@@ -397,7 +468,7 @@ impl Name {
}
if !label.is_empty() {
name.add_label(Rc::new(label));
name.labels.push(Rc::new(label));
}
// TODO: this should be a real lexer, to varify all data is legal name...
@@ -407,13 +478,11 @@ impl Name {
// }
// }
// FIXME: mark as FQDN or not_FQDN
if local.ends_with('.') {
name.set_fqdn(true);
} else {
if let Some(other) = origin {
name.append(other);
name.set_fqdn(true);
return Ok(name.append_domain(other));
}
}
@@ -492,13 +561,11 @@ impl Name {
return Ordering::Equal;
}
let mut self_labels: Vec<_> = (*self.labels).clone();
let mut other_labels: Vec<_> = (*other.labels).clone();
// we reverse the iters so that we are comparing from the root/domain to the local...
let self_labels = self.labels.iter().rev();
let other_labels = other.labels.iter().rev();
self_labels.reverse();
other_labels.reverse();
for (l, r) in self_labels.iter().zip(other_labels.iter()) {
for (l, r) in self_labels.zip(other_labels) {
if ignore_case {
match (*l).to_lowercase().cmp(&(*r).to_lowercase()) {
o @ Ordering::Less |
@@ -678,7 +745,7 @@ impl BinSerializable<Name> for Name {
Ok(Name {
is_fqdn: true,
labels: Rc::new(labels),
labels: labels,
})
}
@@ -771,9 +838,11 @@ impl FromStr for Name {
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc as Rc;
use std::cmp::Ordering;
use std::str::FromStr;
use std::sync::Arc as Rc;
use super::*;
use serialize::binary::bin_tests::{test_read_data_set, test_emit_data_set};
#[allow(unused)]
@@ -782,20 +851,20 @@ mod tests {
fn get_data() -> Vec<(Name, Vec<u8>)> {
vec![
(Name::new(), vec![0]), // base case, only the root
(Name::new().label("a"), vec![1,b'a',0]), // a single 'a' label
(Name::new().label("a").label("bc"), vec![1,b'a',2,b'b',b'c',0]), // two labels, 'a.bc'
(Name::new().label("a").label(""), vec![1,b'a',3,0xE2,0x99,0xA5,0]), // two labels utf8, 'a.♥'
(Name::from_labels(vec!["a"]), vec![1,b'a',0]), // a single 'a' label
(Name::from_labels(vec!["a","bc"]), vec![1,b'a',2,b'b',b'c',0]), // two labels, 'a.bc'
(Name::from_labels(vec!["a",""]), vec![1,b'a',3,0xE2,0x99,0xA5,0]), // two labels utf8, 'a.♥'
]
}
#[test]
fn test_num_labels() {
assert_eq!(Name::new().label("*").num_labels(), 0);
assert_eq!(Name::new().label("a").num_labels(), 1);
assert_eq!(Name::new().label("*").label("b").num_labels(), 1);
assert_eq!(Name::new().label("a").label("b").num_labels(), 2);
assert_eq!(Name::new().label("*").label("b").label("c").num_labels(), 2);
assert_eq!(Name::new().label("a").label("b").label("c").num_labels(), 3);
assert_eq!(Name::from_labels(vec!["*"]).num_labels(), 0);
assert_eq!(Name::from_labels(vec!["a"]).num_labels(), 1);
assert_eq!(Name::from_labels(vec!["*", "b"]).num_labels(), 1);
assert_eq!(Name::from_labels(vec!["a", "b"]).num_labels(), 2);
assert_eq!(Name::from_labels(vec!["*", "b", "c"]).num_labels(), 2);
assert_eq!(Name::from_labels(vec!["a", "b", "c"]).num_labels(), 3);
}
#[test]
@@ -812,10 +881,10 @@ mod tests {
fn test_pointer() {
let mut bytes: Vec<u8> = Vec::with_capacity(512);
let first = Name::new().label("ra").label("rb").label("rc");
let second = Name::new().label("rb").label("rc");
let third = Name::new().label("rc");
let fourth = Name::new().label("z").label("ra").label("rb").label("rc");
let first = Name::from_labels(vec!["ra", "rb", "rc"]);
let second = Name::from_labels(vec!["rb", "rc"]);
let third = Name::from_labels(vec!["rc"]);
let fourth = Name::from_labels(vec!["z", "ra", "rb", "rc"]);
{
let mut e = BinEncoder::new(&mut bytes);
@@ -852,26 +921,27 @@ mod tests {
#[test]
fn test_base_name() {
let zone = Name::new().label("example").label("com");
let zone = Name::from_labels(vec!["example", "com"]);
assert_eq!(zone.base_name(), Name::new().label("com"));
assert_eq!(zone.base_name(), Name::from_labels(vec!["com"]));
assert!(zone.base_name().base_name().is_root());
assert!(zone.base_name().base_name().base_name().is_root());
}
#[test]
#[allow(deprecated)]
fn test_prepend() {
let zone = Name::new().label("example").label("com");
let zone = Name::from_labels(vec!["example", "com"]);
let www = zone.prepend_label(Rc::new("www".to_string()));
assert_eq!(www, Name::new().label("www").label("example").label("com"));
assert_eq!(www, Name::from_labels(vec!["www", "example", "com"]));
}
#[test]
fn test_zone_of() {
let zone = Name::new().label("example").label("com");
let www = Name::new().label("www").label("example").label("com");
let none = Name::new().label("none").label("com");
let zone = Name::from_labels(vec!["example", "com"]);
let www = Name::from_labels(vec!["www", "example", "com"]);
let none = Name::from_labels(vec!["none", "com"]);
let root = Name::root();
assert!(zone.zone_of(&zone));
@@ -883,9 +953,9 @@ mod tests {
#[test]
fn test_zone_of_case() {
let zone = Name::new().label("examplE").label("cOm");
let www = Name::new().label("www").label("example").label("com");
let none = Name::new().label("none").label("com");
let zone = Name::from_labels(vec!["examplE", "cOm"]);
let www = Name::from_labels(vec!["www", "example", "com"]);
let none = Name::from_labels(vec!["none", "com"]);
assert!(zone.zone_of(&zone));
assert!(zone.zone_of(&www));
@@ -977,13 +1047,7 @@ mod tests {
#[test]
fn test_from_ipv4() {
let ip = IpAddr::V4(Ipv4Addr::new(26, 3, 0, 103));
let name = Name::new()
.label("103")
.label("0")
.label("3")
.label("26")
.label("in-addr")
.label("arpa");
let name = Name::from_labels(vec!["103", "0", "3", "26", "in-addr", "arpa"]);
assert_eq!(Into::<Name>::into(ip), name);
}
@@ -991,41 +1055,42 @@ mod tests {
#[test]
fn test_from_ipv6() {
let ip = IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0x1));
let name = Name::new()
.label("1")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("0")
.label("8")
.label("b")
.label("d")
.label("0")
.label("1")
.label("0")
.label("0")
.label("2")
.label("ip6")
.label("arpa");
let name = Name::from_labels(vec![
"1",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"8",
"b",
"d",
"0",
"1",
"0",
"0",
"2",
"ip6",
"arpa",
]);
assert_eq!(Into::<Name>::into(ip), name);
}
@@ -1036,7 +1101,10 @@ mod tests {
Name::from_str("www.example.com.").unwrap(),
Name::from_labels(vec!["www", "example", "com"])
);
assert_eq!(Name::from_str(".").unwrap(), Name::from_labels(Vec::<String>::new()));
assert_eq!(
Name::from_str(".").unwrap(),
Name::from_labels(Vec::<String>::new())
);
}
#[test]

View File

@@ -136,7 +136,7 @@ pub fn parse(tokens: &Vec<Token>, origin: Option<&Name>) -> ParseResult<MX> {
#[test]
pub fn test() {
let rdata = MX::new(16, Name::new().label("mail").label("example").label("com"));
let rdata = MX::new(16, Name::from_labels(vec!["mail","example","com"]));
let mut bytes = Vec::new();
let mut encoder: BinEncoder = BinEncoder::new(&mut bytes);

View File

@@ -39,9 +39,9 @@
//! the description of name server logic in [RFC-1034] for details.
//! ```
use ::serialize::txt::*;
use ::serialize::binary::*;
use ::error::*;
use serialize::txt::*;
use serialize::binary::*;
use error::*;
use rr::domain::Name;
/// Read the RData from the given Decoder
@@ -77,20 +77,23 @@ pub fn emit(encoder: &mut BinEncoder, name_data: &Name) -> EncodeResult {
pub fn parse(tokens: &Vec<Token>, origin: Option<&Name>) -> ParseResult<Name> {
let mut token = tokens.iter();
let name: Name = try!(token.next()
.ok_or(ParseErrorKind::MissingToken("name".to_string()).into())
.and_then(|t| if let &Token::CharData(ref s) = t {
Name::parse(s, origin)
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
}));
let name: Name = try!(
token
.next()
.ok_or(ParseErrorKind::MissingToken("name".to_string()).into())
.and_then(|t| if let &Token::CharData(ref s) = t {
Name::parse(s, origin)
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
})
);
Ok(name)
}
#[test]
pub fn test() {
let rdata = Name::new().label("WWW").label("example").label("com");
let rdata = Name::from_labels(vec!["WWW", "example", "com"]);
let mut bytes = Vec::new();
let mut encoder: BinEncoder = BinEncoder::new(&mut bytes);
@@ -101,7 +104,9 @@ pub fn test() {
let mut decoder: BinDecoder = BinDecoder::new(bytes);
let read_rdata = read(&mut decoder);
assert!(read_rdata.is_ok(),
format!("error decoding: {:?}", read_rdata.unwrap_err()));
assert!(
read_rdata.is_ok(),
format!("error decoding: {:?}", read_rdata.unwrap_err())
);
assert_eq!(rdata, read_rdata.unwrap());
}

View File

@@ -146,11 +146,15 @@ pub fn emit(encoder: &mut BinEncoder, rdata: &NSEC) -> EncodeResult {
pub fn test() {
use rr::RecordType;
let rdata = NSEC::new(Name::new().label("www").label("example").label("com"),
vec![RecordType::A,
RecordType::AAAA,
RecordType::DS,
RecordType::RRSIG]);
let rdata = NSEC::new(
Name::from_labels(vec!["www", "example", "com"]),
vec![
RecordType::A,
RecordType::AAAA,
RecordType::DS,
RecordType::RRSIG,
],
);
let mut bytes = Vec::new();
let mut encoder: BinEncoder = BinEncoder::new(&mut bytes);
@@ -161,7 +165,9 @@ pub fn test() {
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!(
read_rdata.is_ok(),
format!("error decoding: {:?}", read_rdata.unwrap_err())
);
assert_eq!(rdata, read_rdata.unwrap());
}

View File

@@ -16,8 +16,8 @@
//! signature record for signing queries, updates, and responses
use ::serialize::binary::*;
use ::error::*;
use serialize::binary::*;
use error::*;
use rr::{Name, RecordType};
use rr::dnssec::Algorithm;
@@ -212,16 +212,17 @@ impl SIG {
/// # Return value
///
/// The new SIG record data.
pub fn new(type_covered: RecordType,
algorithm: Algorithm,
num_labels: u8,
original_ttl: u32,
sig_expiration: u32,
sig_inception: u32,
key_tag: u16,
signer_name: Name,
sig: Vec<u8>)
-> SIG {
pub fn new(
type_covered: RecordType,
algorithm: Algorithm,
num_labels: u8,
original_ttl: u32,
sig_expiration: u32,
sig_inception: u32,
key_tag: u16,
signer_name: Name,
sig: Vec<u8>,
) -> SIG {
SIG {
type_covered: type_covered,
algorithm: algorithm,
@@ -465,15 +466,17 @@ pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<SIG> {
let bytes_read = decoder.index() - start_idx;
let sig = try!(decoder.read_vec(rdata_length as usize - bytes_read));
Ok(SIG::new(type_covered,
algorithm,
num_labels,
original_ttl,
sig_expiration,
sig_inception,
key_tag,
signer_name,
sig))
Ok(SIG::new(
type_covered,
algorithm,
num_labels,
original_ttl,
sig_expiration,
sig_inception,
key_tag,
signer_name,
sig,
))
}
/// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-6), DNSSEC Resource Records, March 2005
@@ -504,22 +507,26 @@ pub fn emit(encoder: &mut BinEncoder, sig: &SIG) -> EncodeResult {
try!(encoder.emit_u32(sig.sig_expiration()));
try!(encoder.emit_u32(sig.sig_inception()));
try!(encoder.emit_u16(sig.key_tag()));
try!(sig.signer_name().emit_with_lowercase(encoder, is_canonical_names));
try!(sig.signer_name().emit_with_lowercase(
encoder,
is_canonical_names,
));
try!(encoder.emit_vec(sig.sig()));
Ok(())
}
/// specifically for outputing the RData for an RRSIG, with signer_name in canonical form
pub fn emit_pre_sig(encoder: &mut BinEncoder,
type_covered: RecordType,
algorithm: Algorithm,
num_labels: u8,
original_ttl: u32,
sig_expiration: u32,
sig_inception: u32,
key_tag: u16,
signer_name: &Name)
-> EncodeResult {
pub fn emit_pre_sig(
encoder: &mut BinEncoder,
type_covered: RecordType,
algorithm: Algorithm,
num_labels: u8,
original_ttl: u32,
sig_expiration: u32,
sig_inception: u32,
key_tag: u16,
signer_name: &Name,
) -> EncodeResult {
try!(type_covered.emit(encoder));
try!(algorithm.emit(encoder));
try!(encoder.emit(num_labels));
@@ -533,11 +540,50 @@ pub fn emit_pre_sig(encoder: &mut BinEncoder,
#[test]
fn test() {
let rdata = SIG::new(RecordType::NULL, Algorithm::RSASHA256, 0, 0, 2, 1, 5,
Name::new().label("www").label("example").label("com"),
vec![ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15
,16,17,18,19,20,21,22,23,24,25,26,27,28,29,29,31], // 32 bytes for SHA256
);
let rdata = SIG::new(
RecordType::NULL,
Algorithm::RSASHA256,
0,
0,
2,
1,
5,
Name::from_labels(vec!["www", "example", "com"]),
vec![
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
29,
31,
], // 32 bytes for SHA256
);
let mut bytes = Vec::new();
let mut encoder: BinEncoder = BinEncoder::new(&mut bytes);
@@ -548,7 +594,9 @@ fn test() {
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!(
read_rdata.is_ok(),
format!("error decoding: {:?}", read_rdata.unwrap_err())
);
assert_eq!(rdata, read_rdata.unwrap());
}

View File

@@ -16,9 +16,9 @@
//! start of authority record defining ownership and defaults for the zone
use ::serialize::txt::*;
use ::serialize::binary::*;
use ::error::*;
use serialize::txt::*;
use serialize::binary::*;
use error::*;
use rr::domain::Name;
/// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987](https://tools.ietf.org/html/rfc1035)
@@ -92,14 +92,15 @@ impl SOA {
/// # Return value
///
/// The newly created SOA record data.
pub fn new(mname: Name,
rname: Name,
serial: u32,
refresh: i32,
retry: i32,
expire: i32,
minimum: u32)
-> Self {
pub fn new(
mname: Name,
rname: Name,
serial: u32,
refresh: i32,
retry: i32,
expire: i32,
minimum: u32,
) -> Self {
SOA {
mname: mname,
rname: rname,
@@ -257,44 +258,74 @@ pub fn emit(encoder: &mut BinEncoder, soa: &SOA) -> EncodeResult {
pub fn parse(tokens: &Vec<Token>, origin: Option<&Name>) -> ParseResult<SOA> {
let mut token = tokens.iter();
let mname: Name = try!(token.next()
.ok_or(ParseErrorKind::MissingToken("mname".to_string()).into())
.and_then(|t| if let &Token::CharData(ref s) = t {
Name::parse(s, origin)
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
}));
let rname: Name = try!(token.next()
.ok_or(ParseErrorKind::MissingToken("rname".to_string()).into())
.and_then(|t| if let &Token::CharData(ref s) = t {
Name::parse(s, origin)
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
}));
let mut list = try!(token.next()
.ok_or(ParseError::from(ParseErrorKind::MissingToken("List".to_string())))
let mname: Name = try!(
token
.next()
.ok_or(ParseErrorKind::MissingToken("mname".to_string()).into())
.and_then(|t| if let &Token::CharData(ref s) = t {
Name::parse(s, origin)
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
})
);
let rname: Name = try!(
token
.next()
.ok_or(ParseErrorKind::MissingToken("rname".to_string()).into())
.and_then(|t| if let &Token::CharData(ref s) = t {
Name::parse(s, origin)
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
})
);
let mut list = try!(
token
.next()
.ok_or(ParseError::from(
ParseErrorKind::MissingToken("List".to_string()),
))
.and_then(|t| if let &Token::List(ref v) = t {
Ok(v)
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
}))
.iter();
})
).iter();
let serial: u32 = try!(list.next()
.ok_or(ParseError::from(ParseErrorKind::MissingToken("serial".to_string())))
.and_then(|s| Ok(try!(s.parse()))));
let refresh: i32 = try!(list.next()
.ok_or(ParseError::from(ParseErrorKind::MissingToken("refresh".to_string())))
.and_then(|s| Ok(try!(s.parse()))));
let retry: i32 = try!(list.next()
.ok_or(ParseError::from(ParseErrorKind::MissingToken("retry".to_string())))
.and_then(|s| Ok(try!(s.parse()))));
let expire: i32 = try!(list.next()
.ok_or(ParseError::from(ParseErrorKind::MissingToken("expire".to_string())))
.and_then(|s| Ok(try!(s.parse()))));
let minimum: u32 = try!(list.next()
.ok_or(ParseError::from(ParseErrorKind::MissingToken("minimum".to_string())))
.and_then(|s| Ok(try!(s.parse()))));
let serial: u32 = try!(
list.next()
.ok_or(ParseError::from(
ParseErrorKind::MissingToken("serial".to_string()),
))
.and_then(|s| Ok(try!(s.parse())))
);
let refresh: i32 = try!(
list.next()
.ok_or(ParseError::from(
ParseErrorKind::MissingToken("refresh".to_string()),
))
.and_then(|s| Ok(try!(s.parse())))
);
let retry: i32 = try!(
list.next()
.ok_or(ParseError::from(
ParseErrorKind::MissingToken("retry".to_string()),
))
.and_then(|s| Ok(try!(s.parse())))
);
let expire: i32 = try!(
list.next()
.ok_or(ParseError::from(
ParseErrorKind::MissingToken("expire".to_string()),
))
.and_then(|s| Ok(try!(s.parse())))
);
let minimum: u32 = try!(
list.next()
.ok_or(ParseError::from(
ParseErrorKind::MissingToken("minimum".to_string()),
))
.and_then(|s| Ok(try!(s.parse())))
);
// let serial: u32 = try!(token.next().ok_or(ParseError::MissingToken("serial".to_string())).and_then(|t| if let &Token::CharData(ref s) = t {Ok(try!(s.parse()))} else {Err(ParseError::UnexpectedToken(t.clone()))} ));
@@ -303,18 +334,28 @@ pub fn parse(tokens: &Vec<Token>, origin: Option<&Name>) -> ParseResult<SOA> {
// let expire: i32 = try!(token.next().ok_or(ParseError::MissingToken("expire".to_string())).and_then(|t| if let &Token::CharData(ref s) = t {Ok(try!(s.parse()))} else {Err(ParseError::UnexpectedToken(t.clone()))} ));
// let minimum: u32 = try!(token.next().ok_or(ParseError::MissingToken("minimum".to_string())).and_then(|t| if let &Token::CharData(ref s) = t {Ok(try!(s.parse()))} else {Err(ParseError::UnexpectedToken(t.clone()))} ));
Ok(SOA::new(mname, rname, serial, refresh, retry, expire, minimum))
Ok(SOA::new(
mname,
rname,
serial,
refresh,
retry,
expire,
minimum,
))
}
#[test]
fn test() {
let rdata = SOA::new(Name::new().label("m").label("example").label("com"),
Name::new().label("r").label("example").label("com"),
1,
2,
3,
4,
5);
let rdata = SOA::new(
Name::from_labels(vec!["m", "example", "com"]),
Name::from_labels(vec!["r", "example", "com"]),
1,
2,
3,
4,
5,
);
let mut bytes = Vec::new();
let mut encoder: BinEncoder = BinEncoder::new(&mut bytes);
@@ -325,7 +366,9 @@ fn test() {
let mut decoder: BinDecoder = BinDecoder::new(bytes);
let read_rdata = read(&mut decoder);
assert!(read_rdata.is_ok(),
format!("error decoding: {:?}", read_rdata.unwrap_err()));
assert!(
read_rdata.is_ok(),
format!("error decoding: {:?}", read_rdata.unwrap_err())
);
assert_eq!(rdata, read_rdata.unwrap());
}

View File

@@ -16,9 +16,9 @@
//! service records for identify port mapping for specific services on a host
use ::serialize::txt::*;
use ::serialize::binary::*;
use ::error::*;
use serialize::txt::*;
use serialize::binary::*;
use error::*;
use rr::domain::Name;
/// [RFC 2782, DNS SRV RR, February 2000](https://tools.ietf.org/html/rfc2782)
@@ -195,10 +195,12 @@ impl SRV {
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder) -> DecodeResult<SRV> {
// SRV { priority: u16, weight: u16, port: u16, target: Name, },
Ok(SRV::new(try!(decoder.read_u16()),
try!(decoder.read_u16()),
try!(decoder.read_u16()),
try!(Name::read(decoder))))
Ok(SRV::new(
try!(decoder.read_u16()),
try!(decoder.read_u16()),
try!(decoder.read_u16()),
try!(Name::read(decoder)),
))
}
/// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-6), DNSSEC Resource Records, March 2005
@@ -225,7 +227,10 @@ pub fn emit(encoder: &mut BinEncoder, srv: &SRV) -> EncodeResult {
try!(encoder.emit_u16(srv.priority()));
try!(encoder.emit_u16(srv.weight()));
try!(encoder.emit_u16(srv.port()));
try!(srv.target().emit_with_lowercase(encoder, is_canonical_names));
try!(srv.target().emit_with_lowercase(
encoder,
is_canonical_names,
));
Ok(())
}
@@ -233,44 +238,66 @@ pub fn emit(encoder: &mut BinEncoder, srv: &SRV) -> EncodeResult {
pub fn parse(tokens: &Vec<Token>, origin: Option<&Name>) -> ParseResult<SRV> {
let mut token = tokens.iter();
let priority: u16 = try!(token.next()
.ok_or(ParseError::from(ParseErrorKind::MissingToken("priority".to_string())))
.and_then(|t| if let &Token::CharData(ref s) = t {
Ok(try!(s.parse()))
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
}));
let weight: u16 = try!(token.next()
.ok_or(ParseError::from(ParseErrorKind::MissingToken("weight".to_string())))
.and_then(|t| if let &Token::CharData(ref s) = t {
Ok(try!(s.parse()))
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
}));
let port: u16 = try!(token.next()
.ok_or(ParseError::from(ParseErrorKind::MissingToken("port".to_string())))
.and_then(|t| if let &Token::CharData(ref s) = t {
Ok(try!(s.parse()))
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
}));
let target: Name = try!(token.next()
.ok_or(ParseError::from(ParseErrorKind::MissingToken("target".to_string())))
.and_then(|t| if let &Token::CharData(ref s) = t {
Name::parse(s, origin)
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
}));
let priority: u16 = try!(
token
.next()
.ok_or(ParseError::from(
ParseErrorKind::MissingToken("priority".to_string()),
))
.and_then(|t| if let &Token::CharData(ref s) = t {
Ok(try!(s.parse()))
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
})
);
let weight: u16 = try!(
token
.next()
.ok_or(ParseError::from(
ParseErrorKind::MissingToken("weight".to_string()),
))
.and_then(|t| if let &Token::CharData(ref s) = t {
Ok(try!(s.parse()))
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
})
);
let port: u16 = try!(
token
.next()
.ok_or(ParseError::from(
ParseErrorKind::MissingToken("port".to_string()),
))
.and_then(|t| if let &Token::CharData(ref s) = t {
Ok(try!(s.parse()))
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
})
);
let target: Name = try!(
token
.next()
.ok_or(ParseError::from(
ParseErrorKind::MissingToken("target".to_string()),
))
.and_then(|t| if let &Token::CharData(ref s) = t {
Name::parse(s, origin)
} else {
Err(ParseErrorKind::UnexpectedToken(t.clone()).into())
})
);
Ok(SRV::new(priority, weight, port, target))
}
#[test]
fn test() {
let rdata = SRV::new(1,
2,
3,
Name::new().label("_dns_tcp").label("example").label("com"));
let rdata = SRV::new(
1,
2,
3,
Name::from_labels(vec!["_dns_tcp", "example", "com"]),
);
let mut bytes = Vec::new();
let mut encoder: BinEncoder = BinEncoder::new(&mut bytes);
@@ -281,7 +308,9 @@ fn test() {
let mut decoder: BinDecoder = BinDecoder::new(bytes);
let read_rdata = read(&mut decoder);
assert!(read_rdata.is_ok(),
format!("error decoding: {:?}", read_rdata.unwrap_err()));
assert!(
read_rdata.is_ok(),
format!("error decoding: {:?}", read_rdata.unwrap_err())
);
assert_eq!(rdata, read_rdata.unwrap());
}

View File

@@ -16,7 +16,6 @@
//! resource record implementation
use std::sync::Arc as Rc;
use std::cmp::Ordering;
use serialize::binary::*;
@@ -112,11 +111,12 @@ impl Record {
/// * `rr_type` - the record type
/// * `ttl` - time-to-live is the amount of time this record should be cached before refreshing
/// * `rdata` - record data to associate with the Record
pub fn from_rdata(name: domain::Name,
ttl: u32,
record_type: RecordType,
rdata: RData)
-> Record {
pub fn from_rdata(
name: domain::Name,
ttl: u32,
record_type: RecordType,
rdata: RData,
) -> Record {
Record {
name_labels: name,
rr_type: record_type,
@@ -135,8 +135,10 @@ impl Record {
}
/// Appends a label to a name
#[deprecated]
pub fn add_name(&mut self, label: String) -> &mut Self {
self.name_labels.add_label(Rc::new(label));
let name = self.name_labels.clone();
self.name_labels = name.append_label(label);
self
}
@@ -192,7 +194,7 @@ impl Record {
pub fn rr_type(&self) -> RecordType {
self.rr_type
}
/// Returns the DNSClass of the Record, generally IN fro internet
pub fn dns_class(&self) -> DNSClass {
self.dns_class
@@ -277,12 +279,12 @@ impl BinSerializable<Record> for Record {
};
Ok(Record {
name_labels: name_labels,
rr_type: record_type,
dns_class: class,
ttl: ttl,
rdata: rdata,
})
name_labels: name_labels,
rr_type: record_type,
dns_class: class,
ttl: ttl,
rdata: rdata,
})
}
fn emit(&self, encoder: &mut BinEncoder) -> EncodeResult {
@@ -295,9 +297,11 @@ impl BinSerializable<Record> for Record {
// TODO: should we skip the fixed size header and write the rdata first? then write the header?
let mut tmp_buf: Vec<u8> = Vec::with_capacity(512);
{
let mut tmp_encoder: BinEncoder = BinEncoder::with_offset(&mut tmp_buf,
encoder.offset() + 2, /*for u16 len*/
EncodeMode::Normal);
let mut tmp_encoder: BinEncoder = BinEncoder::with_offset(
&mut tmp_buf,
encoder.offset() + 2, /*for u16 len*/
EncodeMode::Normal,
);
try!(self.rdata.emit(&mut tmp_encoder));
}
@@ -330,7 +334,7 @@ impl PartialEq for Record {
fn eq(&self, other: &Self) -> bool {
// self == other && // the same pointer
self.name_labels == other.name_labels && self.rr_type == other.rr_type &&
self.dns_class == other.dns_class && self.rdata == other.rdata
self.dns_class == other.dns_class && self.rdata == other.rdata
}
fn ne(&self, other: &Self) -> bool {
@@ -399,8 +403,9 @@ impl PartialOrd<Record> for Record {
#[cfg(test)]
mod tests {
use std::net::Ipv4Addr;
use std::cmp::Ordering;
use std::net::Ipv4Addr;
use std::str::FromStr;
use super::*;
#[allow(unused)]
@@ -415,9 +420,7 @@ mod tests {
fn test_emit_and_read() {
let mut record = Record::new();
record
.add_name("www".to_string())
.add_name("example".to_string())
.add_name("com".to_string())
.set_name(Name::from_str("www.example.com").unwrap())
.set_rr_type(RecordType::A)
.set_dns_class(DNSClass::IN)
.set_ttl(5)
@@ -440,16 +443,14 @@ mod tests {
fn test_order() {
let mut record = Record::new();
record
.add_name("www".to_string())
.add_name("example".to_string())
.add_name("com".to_string())
.set_name(Name::from_str("www.example.com").unwrap())
.set_rr_type(RecordType::A)
.set_dns_class(DNSClass::IN)
.set_ttl(5)
.set_rdata(RData::A(Ipv4Addr::new(192, 168, 0, 1)));
let mut greater_name = record.clone();
greater_name.set_name(Name::new().label("zzz").label("example").label("com"));
greater_name.set_name(Name::from_str("zzz.example.com").unwrap());
let mut greater_type = record.clone();
greater_type.set_rr_type(RecordType::AAAA);
@@ -460,10 +461,12 @@ mod tests {
let mut greater_rdata = record.clone();
greater_rdata.set_rdata(RData::A(Ipv4Addr::new(192, 168, 0, 255)));
let compares = vec![(&record, &greater_name),
(&record, &greater_type),
(&record, &greater_class),
(&record, &greater_rdata)];
let compares = vec![
(&record, &greater_name),
(&record, &greater_type),
(&record, &greater_class),
(&record, &greater_rdata),
];
assert_eq!(record.clone(), record.clone());
for (r, g) in compares {

View File

@@ -152,23 +152,24 @@ impl RecordSet {
/// * `and_rrsigs` - if true, RRSIGs will be returned if they exist
/// * `supported_algorithms` - the RRSIGs will be filtered by the set of supported_algorithms,
/// and then only the maximal RRSIG algorithm will be returned.
pub fn records(&self,
and_rrsigs: bool,
supported_algorithms: SupportedAlgorithms)
-> Vec<&Record> {
pub fn records(
&self,
and_rrsigs: bool,
supported_algorithms: SupportedAlgorithms,
) -> Vec<&Record> {
if and_rrsigs {
let rrsigs = self.rrsigs
.iter()
.filter(|record| if let &RData::SIG(ref rrsig) = record.rdata() {
supported_algorithms.has(rrsig.algorithm())
} else {
false
})
supported_algorithms.has(rrsig.algorithm())
} else {
false
})
.max_by_key(|record| if let &RData::SIG(ref rrsig) = record.rdata() {
rrsig.algorithm()
} else {
Algorithm::RSASHA1
});
rrsig.algorithm()
} else {
Algorithm::RSASHA1
});
self.records.iter().chain(rrsigs).collect()
} else {
self.records.iter().collect()
@@ -224,10 +225,9 @@ impl RecordSet {
record.set_rdata(rdata.clone()); // TODO: remove clone()? this is only needed for the record return
self.insert(record, 0);
self.records
.iter()
.find(|r| *r.rdata() == rdata)
.expect("insert failed? 172")
self.records.iter().find(|r| *r.rdata() == rdata).expect(
"insert failed? 172",
)
}
/// Inserts a new Resource Record into the Set.
@@ -284,9 +284,11 @@ impl RecordSet {
&RData::SOA(ref existing_soa) => {
if let &RData::SOA(ref new_soa) = record.rdata() {
if new_soa.serial() <= existing_soa.serial() {
info!("update ignored serial out of data: {:?} <= {:?}",
new_soa,
existing_soa);
info!(
"update ignored serial out of data: {:?} <= {:?}",
new_soa,
existing_soa
);
return false;
}
} else {
@@ -420,13 +422,15 @@ impl IntoIterator for RecordSet {
#[cfg(test)]
mod test {
use std::str::FromStr;
use std::net::Ipv4Addr;
use rr::*;
use rr::rdata::SOA;
#[test]
fn test_insert() {
let name = Name::new().label("www").label("example").label("com");
let name = Name::from_str("www.example.com.").unwrap();
let record_type = RecordType::A;
let mut rr_set = RecordSet::new(&name, record_type, 0);
@@ -440,16 +444,12 @@ mod test {
assert!(rr_set.insert(insert.clone(), 0));
assert_eq!(rr_set.records(false, Default::default()).len(), 1);
assert!(rr_set
.records(false, Default::default())
.contains(&&insert));
assert!(rr_set.records(false, Default::default()).contains(&&insert));
// dups ignored
assert!(!rr_set.insert(insert.clone(), 0));
assert_eq!(rr_set.records(false, Default::default()).len(), 1);
assert!(rr_set
.records(false, Default::default())
.contains(&&insert));
assert!(rr_set.records(false, Default::default()).contains(&&insert));
// add one
let insert1 = Record::new()
@@ -461,17 +461,15 @@ mod test {
.clone();
assert!(rr_set.insert(insert1.clone(), 0));
assert_eq!(rr_set.records(false, Default::default()).len(), 2);
assert!(rr_set
.records(false, Default::default())
.contains(&&insert));
assert!(rr_set
.records(false, Default::default())
.contains(&&insert1));
assert!(rr_set.records(false, Default::default()).contains(&&insert));
assert!(rr_set.records(false, Default::default()).contains(
&&insert1,
));
}
#[test]
fn test_insert_soa() {
let name = Name::new().label("example").label("com");
let name = Name::from_str("example.com.").unwrap();
let record_type = RecordType::SOA;
let mut rr_set = RecordSet::new(&name, record_type, 0);
@@ -480,74 +478,76 @@ mod test {
.set_ttl(3600)
.set_rr_type(RecordType::SOA)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(),
Name::parse("noc.dns.icann.org.", None).unwrap(),
2015082403,
7200,
3600,
1209600,
3600)))
.set_rdata(RData::SOA(SOA::new(
Name::from_str("sns.dns.icann.org.").unwrap(),
Name::from_str("noc.dns.icann.org.").unwrap(),
2015082403,
7200,
3600,
1209600,
3600,
)))
.clone();
let same_serial = Record::new()
.set_name(name.clone())
.set_ttl(3600)
.set_rr_type(RecordType::SOA)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.net.", None).unwrap(),
Name::parse("noc.dns.icann.net.", None).unwrap(),
2015082403,
7200,
3600,
1209600,
3600)))
.set_rdata(RData::SOA(SOA::new(
Name::from_str("sns.dns.icann.net.").unwrap(),
Name::from_str("noc.dns.icann.net.").unwrap(),
2015082403,
7200,
3600,
1209600,
3600,
)))
.clone();
let new_serial = Record::new()
.set_name(name.clone())
.set_ttl(3600)
.set_rr_type(RecordType::SOA)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.net.", None).unwrap(),
Name::parse("noc.dns.icann.net.", None).unwrap(),
2015082404,
7200,
3600,
1209600,
3600)))
.set_rdata(RData::SOA(SOA::new(
Name::from_str("sns.dns.icann.net.").unwrap(),
Name::from_str("noc.dns.icann.net.").unwrap(),
2015082404,
7200,
3600,
1209600,
3600,
)))
.clone();
assert!(rr_set.insert(insert.clone(), 0));
assert!(rr_set
.records(false, Default::default())
.contains(&&insert));
assert!(rr_set.records(false, Default::default()).contains(&&insert));
// same serial number
assert!(!rr_set.insert(same_serial.clone(), 0));
assert!(rr_set
.records(false, Default::default())
.contains(&&insert));
assert!(!rr_set
.records(false, Default::default())
.contains(&&same_serial));
assert!(rr_set.records(false, Default::default()).contains(&&insert));
assert!(!rr_set.records(false, Default::default()).contains(
&&same_serial,
));
assert!(rr_set.insert(new_serial.clone(), 0));
assert!(!rr_set.insert(same_serial.clone(), 0));
assert!(!rr_set.insert(insert.clone(), 0));
assert!(rr_set
.records(false, Default::default())
.contains(&&new_serial));
assert!(!rr_set
.records(false, Default::default())
.contains(&&insert));
assert!(!rr_set
.records(false, Default::default())
.contains(&&same_serial));
assert!(rr_set.records(false, Default::default()).contains(
&&new_serial,
));
assert!(!rr_set.records(false, Default::default()).contains(
&&insert,
));
assert!(!rr_set.records(false, Default::default()).contains(
&&same_serial,
));
}
#[test]
fn test_insert_cname() {
let name = Name::new().label("web").label("example").label("com");
let cname = Name::new().label("www").label("example").label("com");
let new_cname = Name::new().label("w2").label("example").label("com");
let name = Name::from_str("web.example.com.").unwrap();
let cname = Name::from_str("www.example.com.").unwrap();
let new_cname = Name::from_str("w2.example.com.").unwrap();
let record_type = RecordType::CNAME;
let mut rr_set = RecordSet::new(&name, record_type, 0);
@@ -568,23 +568,21 @@ mod test {
.clone();
assert!(rr_set.insert(insert.clone(), 0));
assert!(rr_set
.records(false, Default::default())
.contains(&&insert));
assert!(rr_set.records(false, Default::default()).contains(&&insert));
// update the record
assert!(rr_set.insert(new_record.clone(), 0));
assert!(!rr_set
.records(false, Default::default())
.contains(&&insert));
assert!(rr_set
.records(false, Default::default())
.contains(&&new_record));
assert!(!rr_set.records(false, Default::default()).contains(
&&insert,
));
assert!(rr_set.records(false, Default::default()).contains(
&&new_record,
));
}
#[test]
fn test_remove() {
let name = Name::new().label("www").label("example").label("com");
let name = Name::from_str("www.example.com.").unwrap();
let record_type = RecordType::A;
let mut rr_set = RecordSet::new(&name, record_type, 0);
@@ -614,7 +612,7 @@ mod test {
#[test]
fn test_remove_soa() {
let name = Name::new().label("example").label("com");
let name = Name::from_str("www.example.com.").unwrap();
let record_type = RecordType::SOA;
let mut rr_set = RecordSet::new(&name, record_type, 0);
@@ -623,25 +621,25 @@ mod test {
.set_ttl(3600)
.set_rr_type(RecordType::SOA)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(),
Name::parse("noc.dns.icann.org.", None).unwrap(),
2015082403,
7200,
3600,
1209600,
3600)))
.set_rdata(RData::SOA(SOA::new(
Name::from_str("sns.dns.icann.org.").unwrap(),
Name::from_str("noc.dns.icann.org.").unwrap(),
2015082403,
7200,
3600,
1209600,
3600,
)))
.clone();
assert!(rr_set.insert(insert.clone(), 0));
assert!(!rr_set.remove(&insert, 0));
assert!(rr_set
.records(false, Default::default())
.contains(&&insert));
assert!(rr_set.records(false, Default::default()).contains(&&insert));
}
#[test]
fn test_remove_ns() {
let name = Name::new().label("example").label("com");
let name = Name::from_str("example.com.").unwrap();
let record_type = RecordType::NS;
let mut rr_set = RecordSet::new(&name, record_type, 0);
@@ -650,14 +648,14 @@ mod test {
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()))
.set_rdata(RData::NS(Name::from_str("a.iana-servers.net.").unwrap()))
.clone();
let ns2 = Record::new()
.set_name(name.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()))
.set_rdata(RData::NS(Name::from_str("b.iana-servers.net.").unwrap()))
.clone();
assert!(rr_set.insert(ns1.clone(), 0));
@@ -680,42 +678,50 @@ mod test {
use rr::dnssec::{Algorithm, SupportedAlgorithms};
let name = Name::root();
let rsasha256 = SIG::new(RecordType::A,
Algorithm::RSASHA256,
0,
0,
0,
0,
0,
Name::root(),
vec![]);
let ecp256 = SIG::new(RecordType::A,
Algorithm::ECDSAP256SHA256,
0,
0,
0,
0,
0,
Name::root(),
vec![]);
let ecp384 = SIG::new(RecordType::A,
Algorithm::ECDSAP384SHA384,
0,
0,
0,
0,
0,
Name::root(),
vec![]);
let ed25519 = SIG::new(RecordType::A,
Algorithm::ED25519,
0,
0,
0,
0,
0,
Name::root(),
vec![]);
let rsasha256 = SIG::new(
RecordType::A,
Algorithm::RSASHA256,
0,
0,
0,
0,
0,
Name::root(),
vec![],
);
let ecp256 = SIG::new(
RecordType::A,
Algorithm::ECDSAP256SHA256,
0,
0,
0,
0,
0,
Name::root(),
vec![],
);
let ecp384 = SIG::new(
RecordType::A,
Algorithm::ECDSAP384SHA384,
0,
0,
0,
0,
0,
Name::root(),
vec![],
);
let ed25519 = SIG::new(
RecordType::A,
Algorithm::ED25519,
0,
0,
0,
0,
0,
Name::root(),
vec![],
);
let rrsig_rsa = Record::new()
.set_name(name.clone())
@@ -760,24 +766,24 @@ mod test {
rrset.insert_rrsig(rrsig_ecp384);
rrset.insert_rrsig(rrsig_ed25519);
assert!(rrset
.records(true, SupportedAlgorithms::all())
.iter()
.any(|r| if let &RData::SIG(ref sig) = r.rdata() {
sig.algorithm() == Algorithm::ED25519
} else {
false
}));
assert!(rrset.records(true, SupportedAlgorithms::all()).iter().any(
|r| {
if let &RData::SIG(ref sig) = r.rdata() {
sig.algorithm() == Algorithm::ED25519
} else {
false
}
},
));
let mut supported_algorithms = SupportedAlgorithms::new();
supported_algorithms.set(Algorithm::ECDSAP384SHA384);
assert!(rrset
.records(true, supported_algorithms)
.iter()
.any(|r| if let &RData::SIG(ref sig) = r.rdata() {
sig.algorithm() == Algorithm::ECDSAP384SHA384
} else {
false
}));
assert!(rrset.records(true, supported_algorithms).iter().any(|r| {
if let &RData::SIG(ref sig) = r.rdata() {
sig.algorithm() == Algorithm::ECDSAP384SHA384
} else {
false
}
}));
}
}