cleanup Name and deprecate some interfaces
This commit is contained in:
4
.markdownlint.json
Normal file
4
.markdownlint.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"MD013": false,
|
||||
"MD024": false
|
||||
}
|
105
CHANGELOG.md
105
CHANGELOG.md
@@ -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!
|
||||
|
@@ -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);
|
||||
|
@@ -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)]
|
||||
|
@@ -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]
|
||||
|
@@ -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);
|
||||
|
@@ -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());
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user