require docs (#116)

* partial docs

* documentation for message.rs

* more docs

* all rdata documented

* all client interfaces documented

* get all Server public interfaces documented

* add missed docs for Server

* fix renamed method
This commit is contained in:
Benjamin Fry 2017-04-15 22:05:00 -07:00 committed by GitHub
parent 2843420bd5
commit e8cf649c4f
89 changed files with 2177 additions and 1347 deletions

View File

@ -5,9 +5,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## 0.10.1 (unreleased)
### Added
- Added `From<IpAddr>` for Name (reverse DNS) #105
- AppVeyor support #103
### Changed
- Fixed TLS documentation, and add more elsewhere; 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()`
## 0.10.0
### Changed

View File

@ -1,4 +1,5 @@
[![Build Status](https://travis-ci.org/bluejekyll/trust-dns.svg?branch=master)](https://travis-ci.org/bluejekyll/trust-dns)
[![Build status](https://ci.appveyor.com/api/projects/status/tmlih8wdt7628vyl/branch/master?svg=true)](https://ci.appveyor.com/project/bluejekyll/trust-dns/branch/master)
[![Coverage Status](https://coveralls.io/repos/github/bluejekyll/trust-dns/badge.svg?branch=master)](https://coveralls.io/github/bluejekyll/trust-dns?branch=master)
[![](http://meritbadge.herokuapp.com/trust-dns)](https://crates.io/crates/trust-dns)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE-MIT)

View File

@ -19,14 +19,14 @@ use std::io::Write;
use std::path::Path;
fn main() {
// write out a version file to link against for version information
let out_dir = env::var("OUT_DIR").unwrap();
let version = env::var("CARGO_PKG_VERSION").unwrap();
let dest_path = Path::new(&out_dir).join("version.rs");
let mut f = File::create(&dest_path).unwrap();
// write out a version file to link against for version information
let out_dir = env::var("OUT_DIR").unwrap();
let version = env::var("CARGO_PKG_VERSION").unwrap();
let dest_path = Path::new(&out_dir).join("version.rs");
let mut f = File::create(&dest_path).unwrap();
f.write_all(b"pub fn version() -> &'static str {").unwrap();
write!(f, " \"{}\" ", version).unwrap();
f.write_all(b" }").unwrap();
f.write_all(b"/// Get the version of this application as specified in the Cargo.toml\n").unwrap();
f.write_all(b"pub fn version() -> &'static str {").unwrap();
write!(f, " \"{}\" ", version).unwrap();
f.write_all(b" }").unwrap();
}

View File

@ -40,7 +40,10 @@ use op::Message;
/// signer which can be optionally associated to the Client. This replaces the previous per-function
/// parameter, and it will sign all update requests (this matches the `ClientFuture` API).
pub trait Client<C: ClientHandle> {
/// get a mutable reference to the tokio Core associated to the Client
fn get_io_loop(&self) -> RefMut<Core>;
/// Get a mutable handle reference tot the Core assiated to the Client
fn get_client_handle(&self) -> RefMut<C>;
/// A *classic* DNS query, i.e. does not perform and DNSSec operations

View File

@ -23,7 +23,11 @@ use client::ClientStreamHandle;
/// Trait for client connections
pub trait ClientConnection: Sized {
/// The associated DNS Message stream type.
type MessageStream;
/// Return the inner Futures items
///
/// Consumes the connection and allows for future based operations afterward.
fn unwrap(self) -> (Core, Box<Future<Item=Self::MessageStream, Error=io::Error>>, Box<ClientStreamHandle>);
}

View File

@ -33,6 +33,7 @@ pub type StreamHandle = UnboundedSender<Vec<u8>>;
/// Implementations of Sinks for sending DNS messages
pub trait ClientStreamHandle {
/// Sends a message to the Handle for delivery to the server.
fn send(&mut self, buffer: Vec<u8>) -> io::Result<()>;
}

View File

@ -8,7 +8,7 @@
use futures::{Future, Poll};
use client::ClientHandle;
use ::error::*;
use error::*;
use op::Message;
/// Can be used to reattempt a queries if they fail
@ -24,6 +24,12 @@ pub struct RetryClientHandle<H: ClientHandle> {
impl<H> RetryClientHandle<H>
where H: ClientHandle
{
/// Creates a new Client handler for reattempting requests on failures.
///
/// # Arguments
///
/// * `client` - handle to the client connection
/// * `attempts` - number of attempts before failing
pub fn new(client: H, attempts: usize) -> RetryClientHandle<H> {
RetryClientHandle {
client: client,
@ -41,11 +47,11 @@ impl<H> ClientHandle for RetryClientHandle<H>
let future = self.client.send(message.clone());
return Box::new(RetrySendFuture {
message: message,
client: self.client.clone(),
future: future,
remaining_attempts: self.attempts,
});
message: message,
client: self.client.clone(),
future: future,
remaining_attempts: self.attempts,
});
}
}
@ -87,9 +93,9 @@ impl<H> Future for RetrySendFuture<H>
#[cfg(test)]
mod test {
use std::cell::Cell;
use ::client::*;
use ::error::*;
use ::op::*;
use client::*;
use error::*;
use op::*;
use futures::*;
#[derive(Clone)]
@ -125,7 +131,10 @@ mod test {
},
2);
let test1 = Message::new();
let result = client.send(test1).wait().ok().expect("should have succeeded");
let result = client.send(test1)
.wait()
.ok()
.expect("should have succeeded");
assert_eq!(result.id(), 1); // this is checking the number of iterations the TestCient ran
}

View File

@ -24,6 +24,7 @@ use error::{DnsSecError, DnsSecErrorKind};
use rr::Name;
/// Errors while decoding DNS messages
error_chain! {
// The type defined for this error. These are the conventional
// and recommended names, but they can be arbitrarily chosen.

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#![allow(missing_docs)]
//! All defined errors for Trust-DNS

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#![deny(missing_docs)]
#![recursion_limit = "1024"]
//! Trust-DNS is intended to be a fully compliant domain name server and client library.
@ -91,12 +92,19 @@ pub type MessageStream = Stream<Item = Message, Error = io::Error>;
/// A sender to which a Message can be sent
pub type MessageStreamHandle = UnboundedSender<Message>;
/// A buffering stream bound to a `SocketAddr`
pub struct BufClientStreamHandle {
name_server: SocketAddr,
sender: BufStreamHandle,
}
impl BufClientStreamHandle {
/// Constructs a new Buffered Stream Handle, used for sending data to the DNS peer.
///
/// # Arguments
///
/// * `name_server` - the address of the DNS server
/// * `sender` - the handle being used to send data to the server
pub fn new(name_server: SocketAddr, sender: BufStreamHandle) -> Self {
BufClientStreamHandle {
name_server: name_server,

View File

@ -1,28 +1,34 @@
//! Logging configuration
use log;
use log::{LogLevel, SetLoggerError, LogMetadata, LogRecord};
use chrono::*;
/// The logging manager for the system
#[allow(unused)]
pub struct TrustDnsLogger {
level: LogLevel,
}
impl TrustDnsLogger {
/// Configure a logger with the given log level
pub fn new(level: LogLevel) -> TrustDnsLogger {
TrustDnsLogger { level: level }
}
/// Initializes the logger.
pub fn init(self) -> Result<(), SetLoggerError> {
let result = log::set_logger(|max_log_level| {
max_log_level.set(self.level.to_log_level_filter());
Box::new(self)
});
max_log_level.set(self.level.to_log_level_filter());
Box::new(self)
});
info!("logging initialized");
result
}
/// Enables the logger with the given `LogLevel`
pub fn enable_logging(log_level: LogLevel) {
Self::new(log_level).init().is_ok();
}

View File

@ -20,7 +20,7 @@ use rr::{DNSClass, Name, Record, RecordType, RData};
use rr::rdata::OPT;
use rr::rdata::opt::{EdnsCode, EdnsOption};
/// Edns implements the higher level concepts for working with Edns as it is used to create or be
/// Edns implements the higher level concepts for working with extended dns as it is used to create or be
/// created from OPT record data.
#[derive(Debug, PartialEq, Clone)]
pub struct Edns {
@ -38,6 +38,7 @@ pub struct Edns {
}
impl Edns {
/// Creates a new extended DNS object.
pub fn new() -> Self {
Edns {
rcode_high: 0,
@ -48,37 +49,57 @@ impl Edns {
}
}
/// The high order bytes for the response code in the DNS Message
pub fn rcode_high(&self) -> u8 {
self.rcode_high
}
/// Returns the EDNS version
pub fn version(&self) -> u8 {
self.version
}
/// Specifies that DNSSec is supported for this Client or Server
pub fn dnssec_ok(&self) -> bool {
self.dnssec_ok
}
/// Maximum supported size of the DNS payload
pub fn max_payload(&self) -> u16 {
self.max_payload
}
/// Returns the Option associated with the code
pub fn option(&self, code: &EdnsCode) -> Option<&EdnsOption> {
self.options.get(code)
}
/// Returns the options portion of EDNS
pub fn options(&self) -> &OPT {
&self.options
}
/// Set the high order bits for the result code.
pub fn set_rcode_high(&mut self, rcode_high: u8) {
self.rcode_high = rcode_high
}
/// Set the EDNS version
pub fn set_version(&mut self, version: u8) {
self.version = version
}
/// Set to true if DNSSec is supported
pub fn set_dnssec_ok(&mut self, dnssec_ok: bool) {
self.dnssec_ok = dnssec_ok
}
/// Set the maximum payload which can be supported
pub fn set_max_payload(&mut self, max_payload: u16) {
self.max_payload = max_payload
}
/// Set the specified EDNS option
pub fn set_option(&mut self, option: EdnsOption) {
self.options.insert(option);
}

View File

@ -18,8 +18,8 @@
use std::convert::From;
use ::serialize::binary::*;
use ::error::*;
use serialize::binary::*;
use error::*;
use super::op_code::OpCode;
use super::response_code::ResponseCode;
@ -73,9 +73,12 @@ pub struct Header {
additional_count: u16,
}
/// Message types are either Query (also Update) or Response
#[derive(Debug, PartialEq, PartialOrd, Copy, Clone)]
pub enum MessageType {
/// Queries are Client requests, these are either Queries or Updates
Query,
/// Response message from the Server or upstream Resolver
Response,
}
@ -101,63 +104,93 @@ impl Header {
}
}
/// Length of the header, always 12 bytes
#[inline(always)]
pub fn len() -> usize {
12 /* this is always 12 bytes */
}
/// Sets the id of the message, for queries this shoudl be random.
pub fn set_id(&mut self, id: u16) -> &mut Self {
self.id = id;
self
}
/// Sets the message type, Queries and Updates both use Query.
pub fn set_message_type(&mut self, message_type: MessageType) -> &mut Self {
self.message_type = message_type;
self
}
/// Set the operation code for the message
pub fn set_op_code(&mut self, op_code: OpCode) -> &mut Self {
self.op_code = op_code;
self
}
/// From the server is specifies that it is an authoritative reqponse.
pub fn set_authoritative(&mut self, authoritative: bool) -> &mut Self {
self.authoritative = authoritative;
self
}
/// Specifies that the records were too large for the payload.
///
/// See EDNS or TCP for resolutions to truncation.
pub fn set_truncated(&mut self, truncated: bool) -> &mut Self {
self.truncation = truncated;
self
}
/// Specify that the resolver should recursiviley request data from upstream DNS nodes
pub fn set_recursion_desired(&mut self, recursion_desired: bool) -> &mut Self {
self.recursion_desired = recursion_desired;
self
}
/// Specifies that recursion is available from this or the remote resolver
pub fn set_recursion_available(&mut self, recursion_available: bool) -> &mut Self {
self.recursion_available = recursion_available;
self
}
/// Specifies that the data is authnetic, i.e. the resolver believes all data to be valid through DNSSec
pub fn set_authentic_data(&mut self, authentic_data: bool) -> &mut Self {
self.authentic_data = authentic_data;
self
}
/// Used during recursive resolution to specified if a resolver should or should not validate DNSSec signatures
pub fn set_checking_disabled(&mut self, checking_disabled: bool) -> &mut Self {
self.checking_disabled = checking_disabled;
self
}
/// The low responsed code (original response codes before EDNS extensions)
pub fn set_response_code(&mut self, response_code: ResponseCode) -> &mut Self {
self.response_code = response_code.low();
self
}
/// Number or query records in the message
pub fn set_query_count(&mut self, query_count: u16) -> &mut Self {
self.query_count = query_count;
self
}
/// Number of answer records in the message
pub fn set_answer_count(&mut self, answer_count: u16) -> &mut Self {
self.answer_count = answer_count;
self
}
/// Number of name server records in the message
pub fn set_name_server_count(&mut self, name_server_count: u16) -> &mut Self {
self.name_server_count = name_server_count;
self
}
/// Number of additional records in the message
pub fn set_additional_count(&mut self, additional_count: u16) -> &mut Self {
self.additional_count = additional_count;
self
@ -383,21 +416,21 @@ impl BinSerializable<Header> for Header {
// TODO: question, should this use the builder pattern instead? might be cleaner code, but
// this guarantees that the Header is fully instantiated with all values...
Ok(Header {
id: id,
message_type: message_type,
op_code: op_code,
authoritative: authoritative,
truncation: truncation,
recursion_desired: recursion_desired,
recursion_available: recursion_available,
authentic_data: authentic_data,
checking_disabled: checking_disabled,
response_code: response_code,
query_count: query_count,
answer_count: answer_count,
name_server_count: name_server_count,
additional_count: additional_count,
})
id: id,
message_type: message_type,
op_code: op_code,
authoritative: authoritative,
truncation: truncation,
recursion_desired: recursion_desired,
recursion_available: recursion_available,
authentic_data: authentic_data,
checking_disabled: checking_disabled,
response_code: response_code,
query_count: query_count,
answer_count: answer_count,
name_server_count: name_server_count,
additional_count: additional_count,
})
}
fn emit(&self, encoder: &mut BinEncoder) -> EncodeResult {

View File

@ -19,7 +19,7 @@
use std::fmt::Debug;
use std::mem;
use ::error::*;
use error::*;
use rr::{Record, RecordType};
#[cfg(feature = "openssl")]
use rr::{DNSClass, Name, RData};
@ -83,6 +83,7 @@ pub struct Message {
}
impl Message {
/// Returns a new "empty" Message
pub fn new() -> Self {
Message {
header: Header::new(),
@ -95,6 +96,13 @@ impl Message {
}
}
/// Returns a Message constructed with error details to return to a client
///
/// # Arguments
///
/// * `id` - message id should match the request message id
/// * `op_code` - operation of the request
/// * `response_code` - the error code for the response
pub fn error_msg(id: u16, op_code: OpCode, response_code: ResponseCode) -> Message {
let mut message: Message = Message::new();
message.set_message_type(MessageType::Response);
@ -105,6 +113,7 @@ impl Message {
message
}
/// Truncates a Message, this blindly removes all response fields and sets trucation to `true`
pub fn truncate(&self) -> Self {
let mut truncated: Message = Message::new();
truncated.set_id(self.id());
@ -123,54 +132,73 @@ impl Message {
truncated
}
/// see `Header::set_id`
pub fn set_id(&mut self, id: u16) -> &mut Self {
self.header.set_id(id);
self
}
/// see `Header::set_message_type`
pub fn set_message_type(&mut self, message_type: MessageType) -> &mut Self {
self.header.set_message_type(message_type);
self
}
/// see `Header::set_op_code`
pub fn set_op_code(&mut self, op_code: OpCode) -> &mut Self {
self.header.set_op_code(op_code);
self
}
/// see `Header::set_authoritative`
pub fn set_authoritative(&mut self, authoritative: bool) -> &mut Self {
self.header.set_authoritative(authoritative);
self
}
/// see `Header::set_truncated`
pub fn set_truncated(&mut self, truncated: bool) -> &mut Self {
self.header.set_truncated(truncated);
self
}
/// see `Header::set_recursion_desired`
pub fn set_recursion_desired(&mut self, recursion_desired: bool) -> &mut Self {
self.header.set_recursion_desired(recursion_desired);
self
}
/// see `Header::set_recursion_available`
pub fn set_recursion_available(&mut self, recursion_available: bool) -> &mut Self {
self.header.set_recursion_available(recursion_available);
self
}
/// see `Header::set_authentic_data`
pub fn set_authentic_data(&mut self, authentic_data: bool) -> &mut Self {
self.header.set_authentic_data(authentic_data);
self
}
/// see `Header::set_checking_disabled`
pub fn set_checking_disabled(&mut self, checking_disabled: bool) -> &mut Self {
self.header.set_checking_disabled(checking_disabled);
self
}
/// see `Header::set_response_code`
pub fn set_response_code(&mut self, response_code: ResponseCode) -> &mut Self {
self.header.set_response_code(response_code);
self
}
/// TODO: given that only a single query is ever accepted by almost all DNS servers,
/// it's unclear how it could be useful to have more than one here? change this to set
/// a single query?
/// Add a query to the Message, either the query response from the server, or the request Query.
pub fn add_query(&mut self, query: Query) -> &mut Self {
self.queries.push(query);
self
}
/// Adds a slice of Queries to the message
#[deprecated = "will be removed post 0.9.x"]
pub fn add_all_queries(&mut self, queries: &[Query]) -> &mut Self {
for q in queries {
@ -179,6 +207,8 @@ impl Message {
}
self
}
/// Adds an iterator over a set of Queries to be added to the message
pub fn add_queries<Q, I>(&mut self, queries: Q) -> &mut Self
where Q: IntoIterator<Item = Query, IntoIter = I>,
I: Iterator<Item = Query>
@ -190,10 +220,13 @@ impl Message {
self
}
/// Add an answer to the Message
pub fn add_answer(&mut self, record: Record) -> &mut Self {
self.answers.push(record);
self
}
/// Add an entire set of Answers
#[deprecated = "will be removed post 0.9.x"]
pub fn add_all_answers(&mut self, vector: &[&Record]) -> &mut Self {
for &r in vector {
@ -203,6 +236,8 @@ impl Message {
}
self
}
/// Add all the records from the iterator to the answers section of the Message
pub fn add_answers<R, I>(&mut self, records: R) -> &mut Self
where R: IntoIterator<Item = Record, IntoIter = I>,
I: Iterator<Item = Record>
@ -224,10 +259,13 @@ impl Message {
self.answers = records;
}
/// Add a name server record to the Message
pub fn add_name_server(&mut self, record: Record) -> &mut Self {
self.name_servers.push(record);
self
}
/// Adds a set of name server records to the message
#[deprecated = "will be removed post 0.9.x"]
pub fn add_all_name_servers(&mut self, vector: &[&Record]) -> &mut Self {
for &r in vector {
@ -237,6 +275,8 @@ impl Message {
}
self
}
/// Add all the records in the Iterator to the name server section of the message
pub fn add_name_servers<R, I>(&mut self, records: R) -> &mut Self
where R: IntoIterator<Item = Record, IntoIter = I>,
I: Iterator<Item = Record>
@ -258,6 +298,7 @@ impl Message {
self.name_servers = records;
}
/// A an addtional Record to the message
pub fn add_additional(&mut self, record: Record) -> &mut Self {
self.additionals.push(record);
self
@ -273,11 +314,15 @@ impl Message {
self.additionals = records;
}
/// Add the EDNS section the the Message
pub fn set_edns(&mut self, edns: Edns) -> &mut Self {
self.edns = Some(edns);
self
}
/// Add a SIG0 record, i.e. sign this message
///
/// This must be don't only after all records have been associated. Generally this will be handled by the client and not need to be used directly
pub fn add_sig0(&mut self, record: Record) -> &mut Self {
assert_eq!(RecordType::SIG, record.rr_type());
self.sig0.push(record);
@ -352,6 +397,7 @@ impl Message {
&self.answers
}
/// Removes all the answers from the Message
pub fn take_answers(&mut self) -> Vec<Record> {
mem::replace(&mut self.answers, vec![])
}
@ -365,6 +411,7 @@ impl Message {
&self.name_servers
}
/// Remove the name servers from the Message
pub fn take_name_servers(&mut self) -> Vec<Record> {
mem::replace(&mut self.name_servers, vec![])
}
@ -377,6 +424,7 @@ impl Message {
&self.additionals
}
/// Remove the additional Records from the Message
pub fn take_additionals(&mut self) -> Vec<Record> {
mem::replace(&mut self.additionals, vec![])
}
@ -480,10 +528,11 @@ impl Message {
additional_count += self.sig0.len()
};
self.header.clone(self.queries.len() as u16,
self.answers.len() as u16,
self.name_servers.len() as u16,
additional_count as u16)
self.header
.clone(self.queries.len() as u16,
self.answers.len() as u16,
self.name_servers.len() as u16,
additional_count as u16)
}
fn read_records(decoder: &mut BinDecoder,
@ -502,7 +551,7 @@ impl Message {
if !is_additional {
if saw_sig0 {
return Err(DecodeErrorKind::Message("sig0 must be final resource record")
.into());
.into());
} // SIG0 must be last
records.push(record)
} else {
@ -515,12 +564,12 @@ impl Message {
if saw_sig0 {
return Err(DecodeErrorKind::Message("sig0 must be final resource \
record")
.into());
.into());
} // SIG0 must be last
if edns.is_some() {
return Err(DecodeErrorKind::Message("more than one edns record \
present")
.into());
.into());
}
edns = Some((&record).into());
}
@ -528,7 +577,7 @@ impl Message {
if saw_sig0 {
return Err(DecodeErrorKind::Message("sig0 must be final resource \
record")
.into());
.into());
} // SIG0 must be last
records.push(record);
}
@ -546,11 +595,13 @@ impl Message {
Ok(())
}
/// Decodes a message from the buffer.
pub fn from_vec(buffer: &[u8]) -> DecodeResult<Message> {
let mut decoder = BinDecoder::new(buffer);
Message::read(&mut decoder)
}
/// Encodes the Message into a buffer
pub fn to_vec(&self) -> Result<Vec<u8>, EncodeError> {
let mut buffer = Vec::with_capacity(512);
{
@ -561,7 +612,9 @@ impl Message {
Ok(buffer)
}
// TODO: where's the 'right' spot for this function
/// Sign the message, i.e. add a SIG0 record to this Message.
///
/// Subsequent to calling this, the Message should not change.
#[cfg(feature = "openssl")]
pub fn sign(&mut self, signer: &Signer, inception_time: u32) -> DnsSecResult<()> {
debug!("signing message: {:?}", self);
@ -588,24 +641,24 @@ impl Message {
sig0.set_rr_type(RecordType::SIG);
sig0.set_rdata(
RData::SIG(SIG::new(
// type covered in SIG(0) is 0 which is what makes this SIG0 vs a standard SIG
RecordType::NULL,
signer.algorithm(),
num_labels,
// see above, original_ttl is meaningless, The TTL fields SHOULD be zero
0,
// recommended time is +5 minutes from now, to prevent timing attacks, 2 is probably good
expiration_time,
// current time, this should be UTC
// unsigned numbers of seconds since the start of 1 January 1970, GMT
inception_time,
key_tag,
// can probably get rid of this clone if the owndership is correct
signer.signer_name().clone(),
signature,
)
));
RData::SIG(SIG::new(
// type covered in SIG(0) is 0 which is what makes this SIG0 vs a standard SIG
RecordType::NULL,
signer.algorithm(),
num_labels,
// see above, original_ttl is meaningless, The TTL fields SHOULD be zero
0,
// recommended time is +5 minutes from now, to prevent timing attacks, 2 is probably good
expiration_time,
// current time, this should be UTC
// unsigned numbers of seconds since the start of 1 January 1970, GMT
inception_time,
key_tag,
// can probably get rid of this clone if the owndership is correct
signer.signer_name().clone(),
signature,
)
));
debug!("sig0: {:?}", sig0);
@ -613,34 +666,63 @@ impl Message {
Ok(())
}
/// Always returns an error; enable OpenSSL for signing support
#[cfg(not(feature = "openssl"))]
pub fn sign(&mut self, _: &Signer, _: u32) -> DnsSecResult<()> {
Err(DnsSecErrorKind::Message("openssl feature not enabled").into())
}
}
/// to reduce errors in using the Message struct as an Update, this will do the call throughs
/// To reduce errors in using the Message struct as an Update, this will do the call throughs
/// to properly do that.
///
/// Generally rather than constructin this by hand, see the update methods on `Client`
pub trait UpdateMessage: Debug {
/// see `Header::id`
fn id(&self) -> u16;
/// Adds the zone section, i.e. name.example.com would be example.com
fn add_zone(&mut self, query: Query);
/// Add the pre-requisite records
///
/// These must exist, or not, for the Update request to go through.
fn add_pre_requisite(&mut self, record: Record);
/// Add all pre-requisites to the UpdateMessage
#[deprecated = "will be removed post 0.9.x"]
fn add_all_pre_requisites(&mut self, vector: &[&Record]);
/// Add all the Records from the Iterator to the pre-reqisites section
fn add_pre_requisites<R, I>(&mut self, records: R)
where R: IntoIterator<Item = Record, IntoIter = I>,
I: Iterator<Item = Record>;
/// Add the Record to be updated
fn add_update(&mut self, record: Record);
/// Add the set of Records to be updated
#[deprecated = "will be removed post 0.9.x"]
fn add_all_updates(&mut self, vector: &[&Record]);
/// Add the Records from the Iterator to the updates section
fn add_updates<R, I>(&mut self, records: R)
where R: IntoIterator<Item = Record, IntoIter = I>,
I: Iterator<Item = Record>;
/// Add Records to the additional Section of hte UpdateMessage
fn add_additional(&mut self, record: Record);
/// Returns the Zones to be updated, generally should only be one.
fn zones(&self) -> &[Query];
/// Returns the pre-requisites
fn prerequisites(&self) -> &[Record];
/// Returns the records to be updated
fn updates(&self) -> &[Record];
/// Returns the additonal records
fn additionals(&self) -> &[Record];
/// This is used to authenticate update messages.
@ -648,6 +730,7 @@ pub trait UpdateMessage: Debug {
/// see `Message::sig0()` for more information.
fn sig0(&self) -> &[Record];
/// Signs the UpdateMessage, used to validate the authenticity and authorization of UpdateMessage
fn sign(&mut self, signer: &Signer, inception_time: u32) -> DnsSecResult<()>;
}
@ -736,14 +819,14 @@ impl BinSerializable<Message> for Message {
let (additionals, edns, sig0) = try!(Self::read_records(decoder, additional_count, true));
Ok(Message {
header: header,
queries: queries,
answers: answers,
name_servers: name_servers,
additionals: additionals,
sig0: sig0,
edns: edns,
})
header: header,
queries: queries,
answers: answers,
name_servers: name_servers,
additionals: additionals,
sig0: sig0,
edns: edns,
})
}
fn emit(&self, encoder: &mut BinEncoder) -> EncodeResult {
@ -780,7 +863,8 @@ impl BinSerializable<Message> for Message {
#[test]
fn test_emit_and_read_header() {
let mut message = Message::new();
message.set_id(10)
message
.set_id(10)
.set_message_type(MessageType::Response)
.set_op_code(OpCode::Update)
.set_authoritative(true)
@ -795,7 +879,8 @@ fn test_emit_and_read_header() {
#[test]
fn test_emit_and_read_query() {
let mut message = Message::new();
message.set_id(10)
message
.set_id(10)
.set_message_type(MessageType::Response)
.set_op_code(OpCode::Update)
.set_authoritative(true)
@ -812,7 +897,8 @@ fn test_emit_and_read_query() {
#[test]
fn test_emit_and_read_records() {
let mut message = Message::new();
message.set_id(10)
message
.set_id(10)
.set_message_type(MessageType::Response)
.set_op_code(OpCode::Update)
.set_authoritative(true)

View File

@ -89,6 +89,7 @@ impl From<OpCode> for u8 {
/// assert_eq!(OpCode::Query, var);
/// ```
impl OpCode {
/// Decodes the binary value of the OpCode
pub fn from_u8(value: u8) -> DecodeResult<Self> {
match value {
0 => Ok(OpCode::Query),

View File

@ -68,10 +68,14 @@ impl Query {
self.name = name;
self
}
/// Specify the RecordType being queried
pub fn set_query_type(&mut self, query_type: RecordType) -> &mut Self {
self.query_type = query_type;
self
}
/// Specify÷ the DNS class of the Query, almost always IN
pub fn set_query_class(&mut self, query_class: DNSClass) -> &mut Self {
self.query_class = query_class;
self

View File

@ -1,3 +1,12 @@
// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! Request Handler for incoming requests
use op::Message;
/// Trait for handling incoming requests, and providing a message response.

View File

@ -117,7 +117,7 @@ pub enum ResponseCode {
BADTRUNC,
/// Bad/missing server cookie [draft-ietf-dnsop-cookies](https://tools.ietf.org/html/draft-ietf-dnsop-cookies-10)
BADCOOKIE,
BADCOOKIE,
// 24-3840 Unassigned
// 3841-4095 Reserved for Private Use [RFC6895]
// 4096-65534 Unassigned
@ -135,10 +135,12 @@ impl ResponseCode {
(u16::from(*self) & 0x0FF0) >> 4;
}
/// Combines the EDNS high and low from the Header to produce the Extended ResponseCode
pub fn from(high: u8, low: u8) -> ResponseCode {
(((high as u16) << 4) | ((low as u16) & 0x000F)).into()
}
/// Transforms the response code into the human message
pub fn to_str(&self) -> &'static str {
match *self {
ResponseCode::NoError => "No Error",
@ -165,20 +167,18 @@ impl ResponseCode {
}
}
/**
* Convert from ResponseCode to u16
*
* ```
* use std::convert::From;
* use trust_dns::op::response_code::ResponseCode;
*
* let var: ResponseCode = From::from(0);
* assert_eq!(ResponseCode::NoError, var);
*
* let var: ResponseCode = 0.into();
* assert_eq!(ResponseCode::NoError, var);
* ```
*/
/// Convert from ResponseCode to u16
///
/// ```
/// use std::convert::From;
/// use trust_dns::op::response_code::ResponseCode;
///
/// let var: ResponseCode = From::from(0);
/// assert_eq!(ResponseCode::NoError, var);
///
/// let var: ResponseCode = 0.into();
/// assert_eq!(ResponseCode::NoError, var);
/// ```
impl From<ResponseCode> for u16 {
fn from(rt: ResponseCode) -> Self {
match rt {
@ -207,20 +207,18 @@ impl From<ResponseCode> for u16 {
}
}
/**
* Convert from u16 to ResponseCode
*
* ```
* use std::convert::From;
* use trust_dns::op::response_code::ResponseCode;
*
* let var: u16 = From::from(ResponseCode::NoError);
* assert_eq!(0, var);
*
* let var: u16 = ResponseCode::NoError.into();
* assert_eq!(0, var);
* ```
*/
/// Convert from u16 to ResponseCode
///
/// ```
/// use std::convert::From;
/// use trust_dns::op::response_code::ResponseCode;
///
/// let var: u16 = From::from(ResponseCode::NoError);
/// assert_eq!(0, var);
///
/// let var: u16 = ResponseCode::NoError.into();
/// assert_eq!(0, var);
/// ```
impl From<u16> for ResponseCode {
fn from(value: u16) -> Self {
match value {

View File

@ -19,18 +19,25 @@
use std::convert::From;
use std::cmp::Ordering;
use ::serialize::binary::*;
use ::error::*;
use serialize::binary::*;
use error::*;
/// The DNS Record class
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
#[allow(dead_code)]
pub enum DNSClass {
IN, // 1 RFC 1035 Internet (IN)
CH, // 3 Chaos (CH)
HS, // 4 Hesiod (HS)
NONE, // 254 QCLASS NONE
ANY, // 255 QCLASS * (ANY)
OPT(u16), // Special class for OPT Version, it was overloaded for EDNS - RFC 6891
/// Internet
IN,
/// Chaos
CH,
/// Hesiod
HS,
/// QCLASS NONE
NONE,
/// QCLASS * (ANY)
ANY,
/// Special class for OPT Version, it was overloaded for EDNS - RFC 6891
OPT(u16),
}
impl DNSClass {
@ -73,6 +80,7 @@ impl DNSClass {
}
}
/// Return the OPT version from value
pub fn for_opt(value: u16) -> Self {
DNSClass::OPT(value)
}
@ -147,9 +155,16 @@ impl Ord for DNSClass {
#[test]
fn test_order() {
let ordered = vec![DNSClass::IN, DNSClass::CH, DNSClass::HS, DNSClass::NONE, DNSClass::ANY];
let mut unordered =
vec![DNSClass::NONE, DNSClass::HS, DNSClass::CH, DNSClass::IN, DNSClass::ANY];
let ordered = vec![DNSClass::IN,
DNSClass::CH,
DNSClass::HS,
DNSClass::NONE,
DNSClass::ANY];
let mut unordered = vec![DNSClass::NONE,
DNSClass::HS,
DNSClass::CH,
DNSClass::IN,
DNSClass::ANY];
unordered.sort();

View File

@ -15,8 +15,8 @@
*/
use std::str::FromStr;
use ::serialize::binary::*;
use ::error::*;
use serialize::binary::*;
use error::*;
/// DNSSec signing and validation algorithms.
///
@ -105,7 +105,9 @@ pub enum Algorithm {
RSASHA1,
/// DO NOT USE, SHA1 is a compromised hashing function, it is here for backward compatability
RSASHA1NSEC3SHA1,
/// RSA public key with SHA256 hash
RSASHA256,
/// RSA public key with SHA512 hash
RSASHA512,
/// [rfc6605](https://tools.ietf.org/html/rfc6605)
ECDSAP256SHA256,
@ -143,6 +145,7 @@ impl Algorithm {
}
}
/// Convert to string form
pub fn to_str(&self) -> &'static str {
match *self {
Algorithm::RSASHA1 => "RSASHA1",
@ -231,14 +234,16 @@ fn test_order() {
algorithms.sort();
for (got, expect) in algorithms.iter().zip([Algorithm::RSASHA1,
Algorithm::RSASHA1NSEC3SHA1,
Algorithm::RSASHA256,
Algorithm::RSASHA512,
Algorithm::ECDSAP256SHA256,
Algorithm::ECDSAP384SHA384,
Algorithm::ED25519]
.iter()) {
for (got, expect) in algorithms
.iter()
.zip([Algorithm::RSASHA1,
Algorithm::RSASHA1NSEC3SHA1,
Algorithm::RSASHA256,
Algorithm::RSASHA512,
Algorithm::ECDSAP256SHA256,
Algorithm::ECDSAP384SHA384,
Algorithm::ED25519]
.iter()) {
assert_eq!(got, expect);
}
}

View File

@ -19,7 +19,7 @@ use openssl::hash;
use openssl::hash::MessageDigest;
use rr::dnssec::Algorithm;
use ::error::*;
use error::*;
/// This is the digest format for the
///
@ -34,12 +34,17 @@ use ::error::*;
/// ```
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub enum DigestType {
SHA1, // [RFC3658]
/// [RFC3658]
SHA1,
/// [RFC4509]
SHA256, // [RFC4509]
// GOSTR34_11_94, // [RFC5933]
SHA384, // [RFC6605]
/// [RFC6605]
SHA384,
/// Undefined
SHA512,
ED25519, // this is a passthrough digest as ED25519 is self-packaged
/// This is a passthrough digest as ED25519 is self-packaged
ED25519,
}
impl DigestType {
@ -55,6 +60,7 @@ impl DigestType {
}
}
/// The OpenSSL counterpart for the digest
#[cfg(feature = "openssl")]
pub fn to_openssl_digest(&self) -> DnsSecResult<MessageDigest> {
match *self {
@ -64,16 +70,18 @@ impl DigestType {
DigestType::SHA512 => Ok(MessageDigest::sha512()),
_ => {
Err(DnsSecErrorKind::Msg(format!("digest not supported by openssl: {:?}", self))
.into())
.into())
}
}
}
/// Hash the data
#[cfg(feature = "openssl")]
pub fn hash(&self, data: &[u8]) -> DnsSecResult<Vec<u8>> {
hash::hash(try!(self.to_openssl_digest()), data).map_err(|e| e.into())
}
/// This will always error, enable openssl feature at compile time
#[cfg(not(feature = "openssl"))]
pub fn hash(&self, _: &[u8]) -> DnsSecResult<Vec<u8>> {
Err(DnsSecErrorKind::Message("openssl feature not enabled").into())

View File

@ -9,10 +9,14 @@ use ::error::*;
use rr::dnssec::Algorithm;
use rr::dnssec::KeyPair;
/// The format of the binary key
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum KeyFormat {
/// A der encoded key
Der,
/// A pem encoded key, the default of OpenSSL
Pem,
/// Raw bytes unformatted
Raw,
}

View File

@ -25,7 +25,7 @@ use ring::signature::{Ed25519KeyPair, Ed25519KeyPairBytes, EdDSAParameters, Veri
#[cfg(feature = "ring")]
use untrusted::Input;
use ::error::*;
use error::*;
use rr::Name;
use rr::dnssec::{Algorithm, DigestType};
use rr::rdata::{DNSKEY, DS};
@ -36,10 +36,13 @@ use rr::rdata::{DNSKEY, DS};
/// differing features, some key types may not be available. The `openssl` will enable RSA and EC
/// (P256 and P384). `ring` enables ED25519.
pub enum KeyPair {
/// RSA keypair, supported by OpenSSL
#[cfg(feature = "openssl")]
RSA(PKey),
/// Ellyptic curve keypair, supported by OpenSSL
#[cfg(feature = "openssl")]
EC(PKey),
/// ED25519 ecryption and hash defined keypair
#[cfg(feature = "ring")]
ED25519(Ed25519KeyPairBytes),
}
@ -49,9 +52,12 @@ impl KeyPair {
/// Creates an RSA type keypair.
#[cfg(feature = "openssl")]
pub fn from_rsa(rsa: OpenSslRsa) -> DnsSecResult<Self> {
PKey::from_rsa(rsa).map(|pkey| KeyPair::RSA(pkey)).map_err(|e| e.into())
PKey::from_rsa(rsa)
.map(|pkey| KeyPair::RSA(pkey))
.map_err(|e| e.into())
}
/// Given a know pkey of an RSA key, return the wrapped keypair
#[cfg(feature = "openssl")]
pub fn from_rsa_pkey(pkey: PKey) -> Self {
KeyPair::RSA(pkey)
@ -60,9 +66,12 @@ impl KeyPair {
/// Creates an EC, elliptic curve, type keypair, only P256 or P384 are supported.
#[cfg(feature = "openssl")]
pub fn from_ec_key(ec_key: EcKey) -> DnsSecResult<Self> {
PKey::from_ec_key(ec_key).map(|pkey| KeyPair::EC(pkey)).map_err(|e| e.into())
PKey::from_ec_key(ec_key)
.map(|pkey| KeyPair::EC(pkey))
.map_err(|e| e.into())
}
/// Given a know pkey of an EC key, return the wrapped keypair
#[cfg(feature = "openssl")]
pub fn from_ec_pkey(pkey: PKey) -> Self {
KeyPair::EC(pkey)
@ -207,7 +216,7 @@ impl KeyPair {
if public_key.len() != 32 {
return Err(DnsSecErrorKind::Msg(format!("expected 32 byte public_key: {}",
public_key.len()))
.into());
.into());
}
// these are LittleEndian encoded bytes... we need to special case
@ -244,9 +253,13 @@ impl KeyPair {
// this is to get us access to the exponent and the modulus
// TODO: make these expects a try! and Err()
let e: Vec<u8> = rsa.e().expect("RSA should have been initialized").to_vec();
let e: Vec<u8> = rsa.e()
.expect("RSA should have been initialized")
.to_vec();
// TODO: make these expects a try! and Err()
let n: Vec<u8> = rsa.n().expect("RSA should have been initialized").to_vec();
let n: Vec<u8> = rsa.n()
.expect("RSA should have been initialized")
.to_vec();
if e.len() > 255 {
bytes.push(0);
@ -267,14 +280,17 @@ impl KeyPair {
// TODO: make these expects a try! and Err()
let ec_key: EcKey = pkey.ec_key()
.expect("pkey should have been initialized with EC");
ec_key.group()
ec_key
.group()
.and_then(|group| ec_key.public_key().map(|point| (group, point)))
.ok_or(DnsSecErrorKind::Message("missing group or point on ec_key").into())
.and_then(|(group, point)| {
BigNumContext::new()
.and_then(|mut ctx| {
point.to_bytes(group, POINT_CONVERSION_UNCOMPRESSED, &mut ctx)
})
point.to_bytes(group,
POINT_CONVERSION_UNCOMPRESSED,
&mut ctx)
})
.map_err(|e| e.into())
})
}
@ -390,8 +406,10 @@ impl KeyPair {
self.to_dnskey(algorithm)
.and_then(|dnskey| self.key_tag().map(|key_tag| (key_tag, dnskey)))
.and_then(|(key_tag, dnskey)| {
dnskey.to_digest(name, digest_type).map(|digest| (key_tag, digest))
})
dnskey
.to_digest(name, digest_type)
.map(|digest| (key_tag, digest))
})
.map(|(key_tag, digest)| DS::new(key_tag, algorithm, digest_type, digest))
}
@ -420,8 +438,8 @@ impl KeyPair {
KeyPair::ED25519(ref ed_key) => {
Ed25519KeyPair::from_bytes(&ed_key.private_key, &ed_key.public_key)
.map_err(|_| {
DnsSecErrorKind::Message("something is wrong with the keys").into()
})
DnsSecErrorKind::Message("something is wrong with the keys").into()
})
.map(|ed_key| ed_key.sign(message).as_slice().to_vec())
}
#[cfg(not(any(feature = "openssl", feature = "ring")))]
@ -453,20 +471,23 @@ impl KeyPair {
let digest_type = try!(DigestType::from(algorithm).to_openssl_digest());
let mut verifier = Verifier::new(digest_type, &pkey).unwrap();
try!(verifier.update(message));
verifier.finish(signature)
verifier
.finish(signature)
.map_err(|e| e.into())
.and_then(|b| if b {
Ok(())
} else {
Err(DnsSecErrorKind::Message("could not verify").into())
})
Ok(())
} else {
Err(DnsSecErrorKind::Message("could not verify").into())
})
}
#[cfg(feature = "ring")]
KeyPair::ED25519(ref ed_key) => {
let public_key = Input::from(&ed_key.public_key);
let message = Input::from(message);
let signature = Input::from(signature);
EdDSAParameters {}.verify(public_key, message, signature).map_err(|e| e.into())
EdDSAParameters {}
.verify(public_key, message, signature)
.map_err(|e| e.into())
}
#[cfg(not(any(feature = "openssl", feature = "ring")))]
_ => Err(DnsSecErrorKind::Message("openssl nor ring feature(s) not enabled").into()),
@ -523,16 +544,16 @@ impl KeyPair {
if bytes.len() != 64 {
return Err(DnsSecErrorKind::Msg(format!("expected 64 bytes: {}", bytes.len()))
.into());
.into());
}
private_key.copy_from_slice(&bytes[..32]);
public_key.copy_from_slice(&bytes[32..]);
Ok(KeyPair::from_ed25519(Ed25519KeyPairBytes {
private_key: private_key,
public_key: public_key,
}))
private_key: private_key,
public_key: public_key,
}))
}
#[cfg(not(all(feature = "openssl", feature = "ring")))]
_ => Err(DnsSecErrorKind::Message("openssl nor ring feature(s) not enabled").into()),
@ -651,8 +672,8 @@ fn to_from_public_key_test(algorithm: Algorithm) {
let key = KeyPair::generate(algorithm).unwrap();
assert!(key.to_public_bytes()
.and_then(|bytes| KeyPair::from_public_bytes(&bytes, algorithm))
.is_ok());
.and_then(|bytes| KeyPair::from_public_bytes(&bytes, algorithm))
.is_ok());
}
#[cfg(feature = "openssl")]

View File

@ -18,7 +18,7 @@ use std::io::Write;
#[cfg(feature = "openssl")]
use openssl::hash;
use ::error::*;
use error::*;
#[cfg(feature = "openssl")]
use rr::dnssec::DigestType;
#[cfg(feature = "openssl")]
@ -26,79 +26,82 @@ use rr::Name;
#[cfg(feature = "openssl")]
use serialize::binary::{BinEncoder, BinSerializable};
// RFC 5155 NSEC3 March 2008
//
// 11. IANA Considerations
//
// Although the NSEC3 and NSEC3PARAM RR formats include a hash algorithm
// parameter, this document does not define a particular mechanism for
// safely transitioning from one NSEC3 hash algorithm to another. When
// specifying a new hash algorithm for use with NSEC3, a transition
// mechanism MUST also be defined.
//
// This document updates the IANA registry "DOMAIN NAME SYSTEM
// PARAMETERS" (http://www.iana.org/assignments/dns-parameters) in sub-
// registry "TYPES", by defining two new types. Section 3 defines the
// NSEC3 RR type 50. Section 4 defines the NSEC3PARAM RR type 51.
//
// This document updates the IANA registry "DNS SECURITY ALGORITHM
// NUMBERS -- per [RFC4035]"
// (http://www.iana.org/assignments/dns-sec-alg-numbers). Section 2
// defines the aliases DSA-NSEC3-SHA1 (6) and RSASHA1-NSEC3-SHA1 (7) for
// respectively existing registrations DSA and RSASHA1 in combination
// with NSEC3 hash algorithm SHA1.
//
// Since these algorithm numbers are aliases for existing DNSKEY
// algorithm numbers, the flags that exist for the original algorithm
// are valid for the alias algorithm.
//
// This document creates a new IANA registry for NSEC3 flags. This
// registry is named "DNSSEC NSEC3 Flags". The initial contents of this
// registry are:
//
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | | | | | | | |Opt|
// | | | | | | | |Out|
// +---+---+---+---+---+---+---+---+
//
// bit 7 is the Opt-Out flag.
//
// bits 0 - 6 are available for assignment.
//
// Assignment of additional NSEC3 Flags in this registry requires IETF
// Standards Action [RFC2434].
//
// This document creates a new IANA registry for NSEC3PARAM flags. This
// registry is named "DNSSEC NSEC3PARAM Flags". The initial contents of
// this registry are:
//
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | | | | | | | | 0 |
// +---+---+---+---+---+---+---+---+
//
// bit 7 is reserved and must be 0.
//
// bits 0 - 6 are available for assignment.
//
// Assignment of additional NSEC3PARAM Flags in this registry requires
// IETF Standards Action [RFC2434].
//
// Finally, this document creates a new IANA registry for NSEC3 hash
// algorithms. This registry is named "DNSSEC NSEC3 Hash Algorithms".
// The initial contents of this registry are:
//
// 0 is Reserved.
//
// 1 is SHA-1.
//
// 2-255 Available for assignment.
//
// Assignment of additional NSEC3 hash algorithms in this registry
// requires IETF Standards Action [RFC2434].
/// ```text
/// RFC 5155 NSEC3 March 2008
///
/// 11. IANA Considerations
///
/// Although the NSEC3 and NSEC3PARAM RR formats include a hash algorithm
/// parameter, this document does not define a particular mechanism for
/// safely transitioning from one NSEC3 hash algorithm to another. When
/// specifying a new hash algorithm for use with NSEC3, a transition
/// mechanism MUST also be defined.
///
/// This document updates the IANA registry "DOMAIN NAME SYSTEM
/// PARAMETERS" (http://www.iana.org/assignments/dns-parameters) in sub-
/// registry "TYPES", by defining two new types. Section 3 defines the
/// NSEC3 RR type 50. Section 4 defines the NSEC3PARAM RR type 51.
///
/// This document updates the IANA registry "DNS SECURITY ALGORITHM
/// NUMBERS -- per [RFC4035]"
/// (http://www.iana.org/assignments/dns-sec-alg-numbers). Section 2
/// defines the aliases DSA-NSEC3-SHA1 (6) and RSASHA1-NSEC3-SHA1 (7) for
/// respectively existing registrations DSA and RSASHA1 in combination
/// with NSEC3 hash algorithm SHA1.
///
/// Since these algorithm numbers are aliases for existing DNSKEY
/// algorithm numbers, the flags that exist for the original algorithm
/// are valid for the alias algorithm.
///
/// This document creates a new IANA registry for NSEC3 flags. This
/// registry is named "DNSSEC NSEC3 Flags". The initial contents of this
/// registry are:
///
/// 0 1 2 3 4 5 6 7
/// +---+---+---+---+---+---+---+---+
/// | | | | | | | |Opt|
/// | | | | | | | |Out|
/// +---+---+---+---+---+---+---+---+
///
/// bit 7 is the Opt-Out flag.
///
/// bits 0 - 6 are available for assignment.
///
/// Assignment of additional NSEC3 Flags in this registry requires IETF
/// Standards Action [RFC2434].
///
/// This document creates a new IANA registry for NSEC3PARAM flags. This
/// registry is named "DNSSEC NSEC3PARAM Flags". The initial contents of
/// this registry are:
///
/// 0 1 2 3 4 5 6 7
/// +---+---+---+---+---+---+---+---+
/// | | | | | | | | 0 |
/// +---+---+---+---+---+---+---+---+
///
/// bit 7 is reserved and must be 0.
///
/// bits 0 - 6 are available for assignment.
///
/// Assignment of additional NSEC3PARAM Flags in this registry requires
/// IETF Standards Action [RFC2434].
///
/// Finally, this document creates a new IANA registry for NSEC3 hash
/// algorithms. This registry is named "DNSSEC NSEC3 Hash Algorithms".
/// The initial contents of this registry are:
///
/// 0 is Reserved.
///
/// 1 is SHA-1.
///
/// 2-255 Available for assignment.
///
/// Assignment of additional NSEC3 hash algorithms in this registry
/// requires IETF Standards Action [RFC2434].
/// ```
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Nsec3HashAlgorithm {
/// Hash for the Nsec3 records
SHA1,
}
@ -112,35 +115,37 @@ impl Nsec3HashAlgorithm {
}
}
// Laurie, et al. Standards Track [Page 14]
//
// RFC 5155 NSEC3 March 2008
//
// Define H(x) to be the hash of x using the Hash Algorithm selected by
// the NSEC3 RR, k to be the number of Iterations, and || to indicate
// concatenation. Then define:
//
// IH(salt, x, 0) = H(x || salt), and
//
// IH(salt, x, k) = H(IH(salt, x, k-1) || salt), if k > 0
//
// Then the calculated hash of an owner name is
//
// IH(salt, owner name, iterations),
//
// where the owner name is in the canonical form, defined as:
//
// The wire format of the owner name where:
//
// 1. The owner name is fully expanded (no DNS name compression) and
// fully qualified;
//
// 2. All uppercase US-ASCII letters are replaced by the corresponding
// lowercase US-ASCII letters;
//
// 3. If the owner name is a wildcard name, the owner name is in its
// original unexpanded form, including the "*" label (no wildcard
// substitution);
/// ```text
/// Laurie, et al. Standards Track [Page 14]
///
/// RFC 5155 NSEC3 March 2008
///
/// Define H(x) to be the hash of x using the Hash Algorithm selected by
/// the NSEC3 RR, k to be the number of Iterations, and || to indicate
/// concatenation. Then define:
///
/// IH(salt, x, 0) = H(x || salt), and
///
/// IH(salt, x, k) = H(IH(salt, x, k-1) || salt), if k > 0
///
/// Then the calculated hash of an owner name is
///
/// IH(salt, owner name, iterations),
///
/// where the owner name is in the canonical form, defined as:
///
/// The wire format of the owner name where:
///
/// 1. The owner name is fully expanded (no DNS name compression) and
/// fully qualified;
///
/// 2. All uppercase US-ASCII letters are replaced by the corresponding
/// lowercase US-ASCII letters;
///
/// 3. If the owner name is a wildcard name, the owner name is in its
/// original unexpanded form, including the "*" label (no wildcard
/// substitution);
/// ```
#[cfg(feature = "openssl")]
pub fn hash(&self, salt: &[u8], name: &Name, iterations: u16) -> DnsSecResult<Vec<u8>> {
match *self {
@ -158,7 +163,7 @@ impl Nsec3HashAlgorithm {
}
}
// until there is another supported algorithm, just hardcoded to this.
/// 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<Vec<u8>> {
let digest_type = try!(DigestType::SHA1.to_openssl_digest());
@ -192,11 +197,20 @@ fn test_hash() {
let name = Name::new().label("www").label("example").label("com");
let salt: Vec<u8> = vec![1, 2, 3, 4];
assert_eq!(Nsec3HashAlgorithm::SHA1.hash(&salt, &name, 0).unwrap().len(),
assert_eq!(Nsec3HashAlgorithm::SHA1
.hash(&salt, &name, 0)
.unwrap()
.len(),
20);
assert_eq!(Nsec3HashAlgorithm::SHA1.hash(&salt, &name, 1).unwrap().len(),
assert_eq!(Nsec3HashAlgorithm::SHA1
.hash(&salt, &name, 1)
.unwrap()
.len(),
20);
assert_eq!(Nsec3HashAlgorithm::SHA1.hash(&salt, &name, 3).unwrap().len(),
assert_eq!(Nsec3HashAlgorithm::SHA1
.hash(&salt, &name, 3)
.unwrap()
.len(),
20);
}
@ -256,6 +270,8 @@ fn hash_with_base32(name: &str) -> String {
// NSEC3PARAM 1 0 12 aabbccdd
let known_name = Name::parse(name, Some(&Name::new())).unwrap();
let known_salt = [0xAAu8, 0xBBu8, 0xCCu8, 0xDDu8];
let hash = Nsec3HashAlgorithm::SHA1.hash(&known_salt, &known_name, 12).unwrap();
let hash = Nsec3HashAlgorithm::SHA1
.hash(&known_salt, &known_name, 12)
.unwrap();
base32hex::encode(&hash).to_lowercase()
}

View File

@ -239,6 +239,7 @@ pub struct Signer {
is_zone_update_auth: bool,
}
/// Placeholder type for when OpenSSL and *ring* are disabled; enable OpenSSL and Ring for support
#[cfg(not(any(feature = "openssl", feature = "ring")))]
pub struct Signer;
@ -279,21 +280,34 @@ impl Signer {
}
}
/// Returns the algorithm this Signer will use to either sign or validate a signature
pub fn algorithm(&self) -> Algorithm {
self.algorithm
}
/// Return the key used for validateion/signing
pub fn key(&self) -> &KeyPair {
&self.key
}
/// Returns the duration that this signature is valid for
pub fn sig_duration(&self) -> Duration {
self.sig_duration
}
/// The name of the signing entity, e.g. the DNS server name.
///
/// This should match the name on key in the zone.
pub fn signer_name(&self) -> &Name {
&self.signer_name
}
/// A hint to the DNSKey associated with this Signer can be used to sign/validate records in the zone
pub fn is_zone_signing_key(&self) -> bool {
self.is_zone_signing_key
}
/// The associated key can be used for dynamic updates
pub fn is_zone_update_auth(&self) -> bool {
self.is_zone_update_auth
}
@ -504,7 +518,7 @@ impl Signer {
name
} else {
return Err(DnsSecErrorKind::Msg(format!("could not determine name from {}", name))
.into());
.into());
};
// TODO: rather than buffering here, use the Signer/Verifier? might mean fewer allocations...
@ -530,14 +544,16 @@ impl Signer {
sig_inception,
key_tag,
&signer_name)
.is_ok());
.is_ok());
// construct the rrset signing data
for record in rrset {
// RR(i) = name | type | class | OrigTTL | RDATA length | RDATA
//
// name is calculated according to the function in the RFC 4035
assert!(name.to_lowercase().emit_as_canonical(&mut encoder, true).is_ok());
assert!(name.to_lowercase()
.emit_as_canonical(&mut encoder, true)
.is_ok());
//
// type is the RRset type and all RRs in the class
assert!(type_covered.emit(&mut encoder).is_ok());
@ -587,7 +603,7 @@ impl Signer {
} else {
return Err(DnsSecErrorKind::Msg(format!("could not determine name from {}",
rrsig.name()))
.into());
.into());
}
}
@ -670,7 +686,9 @@ impl Signer {
///
/// The signature, ready to be stored in an `RData::RRSIG`.
pub fn sign(&self, hash: &[u8]) -> DnsSecResult<Vec<u8>> {
self.key.sign(self.algorithm, &hash).map_err(|e| e.into())
self.key
.sign(self.algorithm, &hash)
.map_err(|e| e.into())
}
/// Verifies the hash matches the signature with the current `key`.
@ -686,7 +704,9 @@ impl Signer {
/// True if and only if the signature is valid for the hash. This will always return
/// false if the `key`.
pub fn verify(&self, hash: &[u8], signature: &[u8]) -> DnsSecResult<()> {
self.key.verify(self.algorithm, hash, signature).map_err(|e| e.into())
self.key
.verify(self.algorithm, hash, signature)
.map_err(|e| e.into())
}
}
@ -790,7 +810,8 @@ mod tests {
.set_ttl(86400)
.set_rr_type(RecordType::CNAME)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::CNAME(Name::parse("a.iana-servers.net.", None).unwrap()))
.set_rdata(RData::CNAME(Name::parse("a.iana-servers.net.", None)
.unwrap()))
.clone(), // different type
Record::new()
.set_name(Name::parse("www.example.com.", None).unwrap())

View File

@ -20,6 +20,7 @@ use std::convert::From;
use rr::dnssec::Algorithm;
/// Used to specify the set of SupportedAlgorithms between a client and server
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
pub struct SupportedAlgorithms {
// right now the number of Algorithms supported are fewer than 16..
@ -27,14 +28,17 @@ pub struct SupportedAlgorithms {
}
impl SupportedAlgorithms {
/// Return a new set of Supported algorithms
pub fn new() -> Self {
SupportedAlgorithms { bit_map: 0 }
}
/// Specify the entire set is supported
pub fn all() -> Self {
SupportedAlgorithms { bit_map: 0b01111111 }
}
/// Based on the set of Algorithms, return the supported set
pub fn from_vec(algorithms: &[Algorithm]) -> Self {
let mut supported = SupportedAlgorithms::new();
@ -75,20 +79,24 @@ impl SupportedAlgorithms {
}
}
/// Set the specified algorithm as supported
pub fn set(&mut self, algorithm: Algorithm) {
let bit_pos: u8 = Self::pos(algorithm);
self.bit_map |= bit_pos;
}
/// Returns true if the algorithm is supported
pub fn has(&self, algorithm: Algorithm) -> bool {
let bit_pos: u8 = Self::pos(algorithm);
(bit_pos & self.bit_map) == bit_pos
}
/// Return an Iterator over the supported set.
pub fn iter(&self) -> SupportedAlgorithmsIter {
SupportedAlgorithmsIter::new(self)
}
/// Return the count of supported algorithms
pub fn len(&self) -> u16 {
// this is pretty much guaranteed to be less that u16::max_value()
self.iter().count() as u16

View File

@ -26,20 +26,24 @@ use rr::dnssec::KeyPair;
#[cfg(feature = "openssl")]
const ROOT_ANCHOR: &'static str = include_str!("Kjqmt7v.pem");
// TODO: these should also store some information, or more specifically, metadata from the signed
// public certificate.
/// The root set of trust anchors for validating DNSSec, anything in this set will be trusted
pub struct TrustAnchor {
// TODO: these should also store some information, or more specifically, metadata from the signed
// public certificate.
pkeys: Vec<Vec<u8>>,
}
impl Default for TrustAnchor {
#[cfg(feature = "openssl")]
fn default() -> TrustAnchor {
let rsa = Rsa::public_key_from_pem(ROOT_ANCHOR.as_bytes())
.expect("Error parsing Kjqmt7v.pem");
let rsa =
Rsa::public_key_from_pem(ROOT_ANCHOR.as_bytes()).expect("Error parsing Kjqmt7v.pem");
let key = KeyPair::from_rsa(rsa).expect("Error creating KeyPair from RSA key");
TrustAnchor { pkeys: vec![key.to_public_bytes().expect("could not convert key to bytes")] }
TrustAnchor {
pkeys: vec![key.to_public_bytes()
.expect("could not convert key to bytes")],
}
}
#[cfg(not(feature = "openssl"))]
@ -49,10 +53,12 @@ impl Default for TrustAnchor {
}
impl TrustAnchor {
/// Creates a new empty trust anchor set
pub fn new() -> TrustAnchor {
TrustAnchor { pkeys: vec![] }
}
/// determines if the key is in the trust anchor set
pub fn contains(&self, other_key: &[u8]) -> bool {
self.pkeys.iter().any(|k| other_key == k as &[u8])
}
@ -64,6 +70,7 @@ impl TrustAnchor {
}
}
/// get the trust anchor at the specified index
pub fn get(&self, idx: usize) -> &[u8] {
&self.pkeys[idx]
}

View File

@ -36,11 +36,12 @@ pub struct Name {
}
impl Name {
/// Create a new domain::Name, i.e. label
pub fn new() -> Self {
Name { labels: Rc::new(Vec::new()) }
}
// this is the root label, i.e. no labels, can probably make this better in the future.
/// Returns the root label, i.e. no labels, can probably make this better in the future.
pub fn root() -> Self {
Self::new()
}
@ -224,7 +225,9 @@ impl Name {
} else {
1
};
self.labels.iter().fold(dots, |acc, item| acc + item.len())
self.labels
.iter()
.fold(dots, |acc, item| acc + item.len())
}
/// attempts to parse a name such as `"example.com."` or `"subdomain.example.com."`
@ -372,10 +375,12 @@ impl Name {
Ok(())
}
/// Writes the labels, as lower case, to the encoder
pub fn emit_with_lowercase(&self, encoder: &mut BinEncoder, lowercase: bool) -> EncodeResult {
let is_canonical_names = encoder.is_canonical_names();
if lowercase {
self.to_lowercase().emit_as_canonical(encoder, is_canonical_names)
self.to_lowercase()
.emit_as_canonical(encoder, is_canonical_names)
} else {
self.emit_as_canonical(encoder, is_canonical_names)
}
@ -435,10 +440,13 @@ impl From<Ipv4Addr> for Name {
fn from(addr: Ipv4Addr) -> Name {
let octets = addr.octets();
let mut labels = octets.iter().rev().fold(Vec::with_capacity(6), |mut labels, o| {
labels.push(format!("{}", o));
labels
});
let mut labels = octets
.iter()
.rev()
.fold(Vec::with_capacity(6), |mut labels, o| {
labels.push(format!("{}", o));
labels
});
labels.push("in-addr".to_string());
labels.push("arpa".to_string());
@ -451,13 +459,16 @@ impl From<Ipv6Addr> for Name {
fn from(addr: Ipv6Addr) -> Name {
let segments = addr.segments();
let mut labels = segments.iter().rev().fold(Vec::with_capacity(34), |mut labels, o| {
labels.push(format!("{:x}", (*o & 0x000F) as u8));
labels.push(format!("{:x}", (*o >> 4 & 0x000F) as u8));
labels.push(format!("{:x}", (*o >> 8 & 0x000F) as u8));
labels.push(format!("{:x}", (*o >> 12 & 0x000F) as u8));
labels
});
let mut labels = segments
.iter()
.rev()
.fold(Vec::with_capacity(34), |mut labels, o| {
labels.push(format!("{:x}", (*o & 0x000F) as u8));
labels.push(format!("{:x}", (*o >> 4 & 0x000F) as u8));
labels.push(format!("{:x}", (*o >> 8 & 0x000F) as u8));
labels.push(format!("{:x}", (*o >> 12 & 0x000F) as u8));
labels
});
labels.push("ip6".to_string());
labels.push("arpa".to_string());
@ -748,10 +759,7 @@ mod tests {
assert_eq!(zone.base_name(), Name::new().label("com"));
assert!(zone.base_name().base_name().is_root());
assert!(zone.base_name()
.base_name()
.base_name()
.is_root());
assert!(zone.base_name().base_name().base_name().is_root());
}
#[test]

View File

@ -35,5 +35,6 @@ pub use self::rr_key::RrKey;
pub use self::rr_set::IntoRecordSet;
pub use self::rr_set::RecordSet;
/// A RecordSet is a set of Records whose types all match, but data do not
#[deprecated = "will be removed post 0.9.x, use RecordSet"]
pub type RrSet = RecordSet;

View File

@ -46,6 +46,7 @@ use ::serialize::txt::*;
use ::serialize::binary::*;
use ::error::*;
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder) -> DecodeResult<Ipv4Addr> {
Ok(Ipv4Addr::new(try!(decoder.pop()),
try!(decoder.pop()),
@ -53,6 +54,7 @@ pub fn read(decoder: &mut BinDecoder) -> DecodeResult<Ipv4Addr> {
try!(decoder.pop())))
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder, address: &Ipv4Addr) -> EncodeResult {
let segments = address.octets();
@ -63,6 +65,7 @@ pub fn emit(encoder: &mut BinEncoder, address: &Ipv4Addr) -> EncodeResult {
Ok(())
}
/// Parse the RData from a set of Tokens
pub fn parse(tokens: &Vec<Token>) -> ParseResult<Ipv4Addr> {
let mut token = tokens.iter();

View File

@ -38,8 +38,7 @@ use ::serialize::txt::*;
use ::serialize::binary::*;
use ::error::*;
//
// AAAA { address: Ipv6Addr }
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder) -> DecodeResult<Ipv6Addr> {
let a: u16 = try!(decoder.read_u16());
let b: u16 = try!(decoder.read_u16());
@ -53,6 +52,7 @@ pub fn read(decoder: &mut BinDecoder) -> DecodeResult<Ipv6Addr> {
Ok(Ipv6Addr::new(a, b, c, d, e, f, g, h))
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder, address: &Ipv6Addr) -> EncodeResult {
let segments = address.segments();
@ -67,6 +67,7 @@ pub fn emit(encoder: &mut BinEncoder, address: &Ipv6Addr) -> EncodeResult {
Ok(())
}
/// Parse the RData from a set of Tokens
pub fn parse(tokens: &Vec<Token>) -> ParseResult<Ipv6Addr> {
let mut token = tokens.iter();

View File

@ -77,6 +77,19 @@ pub struct DNSKEY {
}
impl DNSKEY {
/// Construct a new DNSKey RData
///
/// # Arguments
///
/// * `zone_key` - this key is used to sign Zone resource records
/// * `secure_entry_point` - this key is used to sign DNSKeys that sign the Zone records
/// * `revoke` - this key has been revoked
/// * `algorithm` - specifies the algorithm which this Key uses to sign records
/// * `public_key` - the public key material, in native endian, the emitter will perform any necessary conversion
///
/// # Return
///
/// A new DNSKEY RData for use in a Resource Record
pub fn new(zone_key: bool,
secure_entry_point: bool,
revoke: bool,
@ -216,6 +229,7 @@ impl DNSKEY {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<DNSKEY> {
let flags: u16 = try!(decoder.read_u16());
@ -248,6 +262,7 @@ pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<DNSKEY>
Ok(DNSKEY::new(zone_key, secure_entry_point, revoke, algorithm, public_key))
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder, rdata: &DNSKEY) -> EncodeResult {
let mut flags: u16 = 0;
if rdata.zone_key() {

View File

@ -74,6 +74,18 @@ pub struct DS {
}
impl DS {
/// Constructs a new DS RData
///
/// # Arguments
///
/// * `key_tag` - the key_tag associated to the DNSKEY
/// * `algorithm` - algorithm as specified in the DNSKEY
/// * `digest_type` - hash algorithm used to validate the DNSKEY
/// * `digest` - hash of the DNSKEY
///
/// # Returns
///
/// the DS RDATA for use in a Resource Record
pub fn new(key_tag: u16, algorithm: Algorithm, digest_type: DigestType, digest: Vec<u8>) -> DS {
DS {
key_tag: key_tag,
@ -169,6 +181,7 @@ impl DS {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<DS> {
let start_idx = decoder.index();
@ -182,6 +195,7 @@ pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<DS> {
Ok(DS::new(key_tag, algorithm, digest_type, digest))
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder, rdata: &DS) -> EncodeResult {
try!(encoder.emit_u16(rdata.key_tag()));
try!(rdata.algorithm().emit(encoder)); // always 3 for now

View File

@ -45,6 +45,16 @@ pub struct MX {
}
impl MX {
/// Constructs a new MX RData
///
/// # Arguments
///
/// * `preference` - weight of this MX record as opposed to others, lower values have the higher preference
/// * `exchange` - Name labels for the mail server
///
/// # Returns
///
/// A new MX RData for use in a Resource Record
pub fn new(preference: u16, exchange: Name) -> MX {
MX {
preference: preference,
@ -74,6 +84,7 @@ impl MX {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder) -> DecodeResult<MX> {
Ok(MX::new(try!(decoder.read_u16()), try!(Name::read(decoder))))
}
@ -101,6 +112,7 @@ pub fn emit(encoder: &mut BinEncoder, mx: &MX) -> EncodeResult {
Ok(())
}
/// Parse the RData from a set of Tokens
pub fn parse(tokens: &Vec<Token>, origin: Option<&Name>) -> ParseResult<MX> {
let mut token = tokens.iter();

View File

@ -44,7 +44,7 @@ use ::serialize::binary::*;
use ::error::*;
use rr::domain::Name;
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder) -> DecodeResult<Name> {
Name::read(decoder)
}
@ -73,6 +73,7 @@ pub fn emit(encoder: &mut BinEncoder, name_data: &Name) -> EncodeResult {
Ok(())
}
/// Parse the RData from a set of Tokens
pub fn parse(tokens: &Vec<Token>, origin: Option<&Name>) -> ParseResult<Name> {
let mut token = tokens.iter();

View File

@ -16,8 +16,8 @@
//! negative cache proof for non-existence
use ::serialize::binary::*;
use ::error::*;
use serialize::binary::*;
use error::*;
use rr::{Name, RecordType};
use rr::rdata::nsec3;
@ -52,6 +52,16 @@ pub struct NSEC {
}
impl NSEC {
/// Constructs a new NSET RData
///
/// # Arguments
///
/// * `next_domain_name` - the name labels of the next ordered name in the zone
/// * `type_bit_maps` - a bit map of the types that don't exist at this name
///
/// # Returns
///
/// An NSEC RData for use in a Resource Record
pub fn new(next_domain_name: Name, type_bit_maps: Vec<RecordType>) -> NSEC {
NSEC {
next_domain_name: next_domain_name,
@ -100,6 +110,7 @@ impl NSEC {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<NSEC> {
let start_idx = decoder.index();
@ -136,7 +147,10 @@ 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]);
vec![RecordType::A,
RecordType::AAAA,
RecordType::DS,
RecordType::RRSIG]);
let mut bytes = Vec::new();
let mut encoder: BinEncoder = BinEncoder::new(&mut bytes);

View File

@ -119,6 +119,7 @@ pub struct NSEC3 {
}
impl NSEC3 {
/// Constructs a new NSEC3 record
pub fn new(hash_algorithm: Nsec3HashAlgorithm,
opt_out: bool,
iterations: u16,
@ -237,6 +238,7 @@ impl NSEC3 {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<NSEC3> {
let start_idx = decoder.index();
@ -264,6 +266,16 @@ pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<NSEC3>
record_types))
}
/// Decodes the array of RecordTypes covered by this NSEC record
///
/// # Arguments
///
/// * `decoder` - decoder to read from
/// * `bit_map_len` - the number bytes in the bit map
///
/// # Returns
///
/// The Array of covered types
pub fn decode_type_bit_maps(decoder: &mut BinDecoder,
bit_map_len: usize)
-> DecodeResult<Vec<RecordType>> {
@ -373,6 +385,7 @@ enum BitMapState {
ReadType { window: u8, len: u8, left: u8 },
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder, rdata: &NSEC3) -> EncodeResult {
try!(encoder.emit(rdata.hash_algorithm().into()));
let mut flags: u8 = 0;
@ -390,6 +403,12 @@ pub fn emit(encoder: &mut BinEncoder, rdata: &NSEC3) -> EncodeResult {
Ok(())
}
/// Encode the bit map
///
/// # Arguments
///
/// * `encoder` - the encoder to write to
/// * `type_bit_maps` - types to encode into the bitmap
pub fn encode_bit_maps(encoder: &mut BinEncoder, type_bit_maps: &[RecordType]) -> EncodeResult {
let mut hash: HashMap<u8, Vec<u8>> = HashMap::new();

View File

@ -85,6 +85,7 @@ pub struct NSEC3PARAM {
}
impl NSEC3PARAM {
/// Constructs a new NSEC3PARAM RData for use in a Resource Record
pub fn new(hash_algorithm: Nsec3HashAlgorithm,
opt_out: bool,
iterations: u16,
@ -156,6 +157,7 @@ impl NSEC3PARAM {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder) -> DecodeResult<NSEC3PARAM> {
let hash_algorithm = try!(Nsec3HashAlgorithm::from_u8(try!(decoder.read_u8())));
let flags: u8 = try!(decoder.read_u8());
@ -171,6 +173,7 @@ pub fn read(decoder: &mut BinDecoder) -> DecodeResult<NSEC3PARAM> {
Ok(NSEC3PARAM::new(hash_algorithm, opt_out, iterations, salt))
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder, rdata: &NSEC3PARAM) -> EncodeResult {
try!(encoder.emit(rdata.hash_algorithm().into()));
let mut flags: u8 = 0;

View File

@ -16,9 +16,9 @@
//! null record type, generally not used except as an internal tool for representing null data
use ::serialize::txt::*;
use ::serialize::binary::*;
use ::error::*;
use serialize::txt::*;
use serialize::binary::*;
use error::*;
/// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987](https://tools.ietf.org/html/rfc1035)
///
@ -43,21 +43,23 @@ pub struct NULL {
}
impl NULL {
/// Construct a new NULL RData
pub fn new() -> NULL {
NULL { anything: None }
}
/// Constructs a new NULL RData with the associated data
pub fn with(anything: Vec<u8>) -> NULL {
NULL { anything: Some(anything) }
}
/// Returns the buffer stored in the NULL
pub fn anything(&self) -> Option<&Vec<u8>> {
self.anything.as_ref()
}
}
// TODO: length should be stored in the decoder, and guaranteed everywhere, right?
// TODO: use this for unknown record types in caching...
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<NULL> {
if rdata_length > 0 {
let mut anything: Vec<u8> = Vec::with_capacity(rdata_length as usize);
@ -75,6 +77,7 @@ pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<NULL> {
}
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder, nil: &NULL) -> EncodeResult {
if let Some(ref anything) = nil.anything() {
for b in anything.iter() {
@ -85,6 +88,7 @@ pub fn emit(encoder: &mut BinEncoder, nil: &NULL) -> EncodeResult {
Ok(())
}
/// Parse the RData from a set of Tokens
#[allow(unused)]
pub fn parse(tokens: &Vec<Token>) -> ParseResult<NULL> {
unimplemented!()

View File

@ -193,7 +193,7 @@ impl OPT {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<OPT> {
let mut state: OptReadState = OptReadState::ReadCode;
let mut options: HashMap<EdnsCode, EdnsOption> = HashMap::new();
@ -240,6 +240,7 @@ pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<OPT> {
Ok(OPT::new(options))
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder, opt: &OPT) -> EncodeResult {
for (ref edns_code, ref edns_option) in opt.options().iter() {
try!(encoder.emit_u16(u16::from(**edns_code)));
@ -262,6 +263,7 @@ enum OptReadState {
}, // expect the data for the option
}
/// The code of the EDNS data option
#[derive(Hash, Debug, Copy, Clone, PartialEq, Eq)]
pub enum EdnsCode {
/// [RFC 6891, Reserved](https://tools.ietf.org/html/rfc6891)
@ -373,6 +375,7 @@ pub enum EdnsOption {
}
impl EdnsOption {
/// Returns the length in bytes of the EdnsOption
pub fn len(&self) -> u16 {
match *self {
EdnsOption::DAU(ref algorithms) |

View File

@ -424,6 +424,7 @@ impl SIG {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<SIG> {
let start_idx = decoder.index();

View File

@ -209,7 +209,7 @@ impl SOA {
}
}
// SOA { mname: Name, rname: Name, serial: u32, refresh: i32, retry: i32, expire: i32, minimum: u32, },
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder) -> DecodeResult<SOA> {
Ok(SOA {
mname: try!(Name::read(decoder)),
@ -253,12 +253,7 @@ pub fn emit(encoder: &mut BinEncoder, soa: &SOA) -> EncodeResult {
Ok(())
}
// VENERA Action\.domains (
// 20 ; SERIAL
// 7200 ; REFRESH
// 600 ; RETRY
// 3600000; EXPIRE
// 60) ; MINIMUM
/// Parse the RData from a set of Tokens
pub fn parse(tokens: &Vec<Token>, origin: Option<&Name>) -> ParseResult<SOA> {
let mut token = tokens.iter();

View File

@ -192,6 +192,7 @@ 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()),
@ -228,7 +229,7 @@ pub fn emit(encoder: &mut BinEncoder, srv: &SRV) -> EncodeResult {
Ok(())
}
// _foobar._tcp SRV 0 1 9 old-slow-box.example.com.
/// Parse the RData from a set of Tokens
pub fn parse(tokens: &Vec<Token>, origin: Option<&Name>) -> ParseResult<SRV> {
let mut token = tokens.iter();

View File

@ -60,6 +60,7 @@ impl TXT {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<TXT> {
let data_len = decoder.len();
let mut strings = Vec::with_capacity(1);
@ -70,6 +71,7 @@ pub fn read(decoder: &mut BinDecoder, rdata_length: u16) -> DecodeResult<TXT> {
Ok(TXT::new(strings))
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder, txt: &TXT) -> EncodeResult {
for s in txt.txt_data() {
try!(encoder.emit_character_data(s));
@ -78,6 +80,7 @@ pub fn emit(encoder: &mut BinEncoder, txt: &TXT) -> EncodeResult {
Ok(())
}
/// Parse the RData from a set of Tokens
pub fn parse(tokens: &Vec<Token>) -> ParseResult<TXT> {
let mut txt_data: Vec<String> = Vec::with_capacity(tokens.len());
for t in tokens {

File diff suppressed because it is too large Load Diff

View File

@ -22,51 +22,76 @@ use std::cmp::Ordering;
use ::serialize::binary::*;
use ::error::*;
/// The type of the resource record.
///
/// This specifies the type of data in the RData field of the Resource Record
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
#[allow(dead_code)]
pub enum RecordType {
A, // 1 RFC 1035[1] IPv4 Address record
AAAA, // 28 RFC 3596[2] IPv6 address record
/// RFC 1035[1] IPv4 Address record
A,
/// RFC 3596[2] IPv6 address record
AAAA,
// AFSDB, // 18 RFC 1183 AFS database record
ANY, // * 255 RFC 1035[1] All cached records, aka ANY
/// RFC 1035[1] All cached records, aka ANY
ANY,
// APL, // 42 RFC 3123 Address Prefix List
AXFR, // 252 RFC 1035[1] Authoritative Zone Transfer
/// RFC 1035[1] Authoritative Zone Transfer
AXFR,
// CAA, // 257 RFC 6844 Certification Authority Authorization
// CDNSKEY, // 60 RFC 7344 Child DNSKEY
// CDS, // 59 RFC 7344 Child DS
// CERT, // 37 RFC 4398 Certificate record
CNAME, // 5 RFC 1035[1] Canonical name record
/// RFC 1035[1] Canonical name record
CNAME,
// DHCID, // 49 RFC 4701 DHCP identifier
// DLV, // 32769 RFC 4431 DNSSEC Lookaside Validation record
// DNAME, // 39 RFC 2672 Delegation Name
DNSKEY, // 48 RFC 4034 DNS Key record: RSASHA256 and RSASHA512, RFC5702
DS, // 43 RFC 4034 Delegation signer: RSASHA256 and RSASHA512, RFC5702
/// RFC 4034 DNS Key record: RSASHA256 and RSASHA512, RFC5702
DNSKEY,
/// RFC 4034 Delegation signer: RSASHA256 and RSASHA512, RFC5702
DS,
// HIP, // 55 RFC 5205 Host Identity Protocol
// IPSECKEY, // 45 RFC 4025 IPsec Key
IXFR, // 251 RFC 1996 Incremental Zone Transfer
KEY, // 25 RFC 2535[3] and RFC 2930[4] Key record
/// RFC 1996 Incremental Zone Transfer
IXFR,
/// RFC 2535[3] and RFC 2930[4] Key record
KEY,
// KX, // 36 RFC 2230 Key eXchanger record
// LOC, // 29 RFC 1876 Location record
MX, // 15 RFC 1035[1] Mail exchange record
/// RFC 1035[1] Mail exchange record
MX,
// NAPTR, // 35 RFC 3403 Naming Authority Pointer
NS, // 2 RFC 1035[1] Name server record
NULL, // 0 RFC 1035[1] Null server record, for testing
NSEC, // 47 RFC 4034 Next-Secure record
NSEC3, // 50 RFC 5155 NSEC record version 3
NSEC3PARAM, // 51 RFC 5155 NSEC3 parameters
OPT, // 41 RFC 6891 Option
PTR, // 12 RFC 1035[1] Pointer record
RRSIG, // 46 RFC 4034 DNSSEC signature: RSASHA256 and RSASHA512, RFC5702
/// RFC 1035[1] Name server record
NS,
/// RFC 1035[1] Null server record, for testing
NULL,
/// RFC 4034 Next-Secure record
NSEC,
/// RFC 5155 NSEC record version 3
NSEC3,
/// RFC 5155 NSEC3 parameters
NSEC3PARAM,
/// RFC 6891 Option
OPT,
/// RFC 1035[1] Pointer record
PTR,
/// RFC 4034 DNSSEC signature: RSASHA256 and RSASHA512, RFC5702
RRSIG,
// RP, // 17 RFC 1183 Responsible person
SIG, // 24 RFC 2535 (2931) Signature, to support 2137 Update
SOA, // 6 RFC 1035[1] and RFC 2308[9] Start of [a zone of] authority record
SRV, // 33 RFC 2782 Service locator
/// RFC 2535 (2931) Signature, to support 2137 Update
SIG,
/// RFC 1035[1] and RFC 2308[9] Start of [a zone of] authority record
SOA,
/// RFC 2782 Service locator
SRV,
// SSHFP, // 44 RFC 4255 SSH Public Key Fingerprint
// TA, // 32768 N/A DNSSEC Trust Authorities
// TKEY, // 249 RFC 2930 Secret key record
// TLSA, // 52 RFC 6698 TLSA certificate association
// TSIG, // 250 RFC 2845 Transaction Signature
TXT, // 16 RFC 1035[1] Text record
/// RFC 1035[1] Text record
TXT,
}
impl RecordType {

View File

@ -19,8 +19,8 @@
use std::sync::Arc as Rc;
use std::cmp::Ordering;
use ::serialize::binary::*;
use ::error::*;
use serialize::binary::*;
use error::*;
use rr::dns_class::DNSClass;
use rr::domain;
use rr::IntoRecordSet;
@ -133,6 +133,8 @@ impl Record {
self.name_labels = name;
self
}
/// Appends a label to a name
pub fn add_name(&mut self, label: String) -> &mut Self {
self.name_labels.add_label(Rc::new(label));
self
@ -181,24 +183,37 @@ impl Record {
self
}
/// Returns the name of the record
pub fn name(&self) -> &domain::Name {
&self.name_labels
}
/// Returns the type of the RData in the 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
}
/// Returns the time-to-live of the record, for caching purposes
pub fn ttl(&self) -> u32 {
self.ttl
}
/// Returns the Record Data, i.e. the record information
pub fn rdata(&self) -> &RData {
&self.rdata
}
/// Returns a mutable reference to the Record Data
pub fn rdata_mut(&mut self) -> &mut RData {
&mut self.rdata
}
/// Returns the RData consuming the Record
pub fn unwrap_rdata(self) -> RData {
self.rdata
}
@ -262,12 +277,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 {
@ -389,7 +404,7 @@ mod tests {
use super::*;
#[allow(unused)]
use ::serialize::binary::*;
use serialize::binary::*;
use rr::record_data::RData;
use rr::record_type::RecordType;
use rr::dns_class::DNSClass;
@ -399,7 +414,8 @@ mod tests {
#[test]
fn test_emit_and_read() {
let mut record = Record::new();
record.add_name("www".to_string())
record
.add_name("www".to_string())
.add_name("example".to_string())
.add_name("com".to_string())
.set_rr_type(RecordType::A)
@ -423,7 +439,8 @@ mod tests {
#[test]
fn test_order() {
let mut record = Record::new();
record.add_name("www".to_string())
record
.add_name("www".to_string())
.add_name("example".to_string())
.add_name("com".to_string())
.set_rr_type(RecordType::A)

View File

@ -5,7 +5,9 @@ use rr::{Name, RecordType};
/// Accessor key for RRSets in the Authority.
#[derive(Eq, PartialEq, Debug, Hash, Clone)]
pub struct RrKey {
/// Matches the name in the Record of this key
pub name: Name,
/// Matches the type of the Record of this key
pub record_type: RecordType,
}

View File

@ -160,15 +160,15 @@ impl RecordSet {
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()
@ -190,14 +190,23 @@ impl RecordSet {
self.serial
}
/// Returns a slice of all the Records signatures in the RecordSet
pub fn rrsigs(&self) -> &[Record] {
&self.rrsigs
}
/// Inserts a Signature for the Record set
///
/// Many can be associated with the RecordSet. Once added, the RecordSet should not be changed
///
/// # Arguments
///
/// * `rrsig` - A signature which covers the RecordSet.
pub fn insert_rrsig(&mut self, rrsig: Record) {
self.rrsigs.push(rrsig)
}
/// Useful for clearing all signatures when the RecordSet is updated, or keys are rotated.
pub fn clear_rrsigs(&mut self) {
self.rrsigs.clear()
}
@ -215,7 +224,10 @@ 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.
@ -348,8 +360,7 @@ impl RecordSet {
/// True if a record was removed.
pub fn remove(&mut self, record: &Record, serial: u32) -> bool {
assert_eq!(record.name(), &self.name);
assert!(record.rr_type() == self.record_type ||
record.rr_type() == RecordType::ANY);
assert!(record.rr_type() == self.record_type || record.rr_type() == RecordType::ANY);
match record.rr_type() {
// never delete the last NS record
@ -386,7 +397,9 @@ impl RecordSet {
}
}
/// Types which implement this can be converted into a RecordSet
pub trait IntoRecordSet: Sized {
/// Performs the conversion to a RecordSet
fn into_record_set(self) -> RecordSet;
}
@ -408,7 +421,7 @@ impl IntoIterator for RecordSet {
#[cfg(test)]
mod test {
use std::net::Ipv4Addr;
use ::rr::*;
use rr::*;
use rr::rdata::SOA;
#[test]
@ -427,12 +440,16 @@ 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()
@ -444,8 +461,12 @@ 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]
@ -495,19 +516,31 @@ 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));
// 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]
@ -535,12 +568,18 @@ 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]
@ -595,7 +634,9 @@ mod test {
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]
@ -719,22 +760,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
}));
}
}

View File

@ -18,16 +18,21 @@ use error::{DecodeErrorKind, DecodeResult};
/// This is non-destructive to the inner buffer, b/c for pointer types we need to perform a reverse
/// seek to lookup names
///
/// A note on serialization, there was a thought to have this implement the rustc-serialization,
/// A note on serialization, there was a thought to have this implement the Serde deserializer,
/// but given that this is such a small subset of all the serialization which that performs
/// this is a simpler implementation without the cruft, at least for serializing to/from the
/// binary DNS protocols. rustc-serialization will be used for other coms, e.g. json over http
/// binary DNS protocols.
pub struct BinDecoder<'a> {
buffer: &'a [u8],
index: usize,
}
impl<'a> BinDecoder<'a> {
/// Creates a new BinDecoder
///
/// # Arguments
///
/// * `buffer` - buffer from which all data will be read
pub fn new(buffer: &'a [u8]) -> Self {
BinDecoder {
buffer: buffer,
@ -35,6 +40,7 @@ impl<'a> BinDecoder<'a> {
}
}
/// Pop one byte from the buffer
pub fn pop(&mut self) -> DecodeResult<u8> {
if self.index < self.buffer.len() {
let byte = self.buffer[self.index];
@ -45,10 +51,12 @@ impl<'a> BinDecoder<'a> {
}
}
/// Returns the number of bytes in the buffer
pub fn len(&self) -> usize {
self.buffer.len() - self.index
}
/// Peed one byte forward, without moving the current index forward
pub fn peek(&self) -> Option<u8> {
if self.index < self.buffer.len() {
Some(self.buffer[self.index])
@ -57,6 +65,7 @@ impl<'a> BinDecoder<'a> {
}
}
/// Returns the current index in the buffer
pub fn index(&self) -> usize {
return self.index;
}
@ -70,12 +79,18 @@ impl<'a> BinDecoder<'a> {
}
}
///<character-string> is a single
/// Reads a String from the buffer
///
/// ```text
/// <character-string> is a single
/// length octet followed by that number of characters. <character-string>
/// is treated as binary information, and can be up to 256 characters in
/// length (including the length octet).
/// ```
///
/// the vector should be reversed before calling.
/// # Returns
///
/// A String version of the character data
pub fn read_character_data(&mut self) -> DecodeResult<String> {
let length: u8 = try!(self.pop());
@ -88,6 +103,15 @@ impl<'a> BinDecoder<'a> {
Ok(data)
}
/// Reads a Vec out of the buffer
///
/// # Arguments
///
/// * `len` - number of bytes to read from the buffer
///
/// # Returns
///
/// The Vec of the specified length, otherwise an error
pub fn read_vec(&mut self, len: usize) -> DecodeResult<Vec<u8>> {
// TODO once Drain stabalizes on Vec, this should be replaced...
let mut vec: Vec<u8> = Vec::with_capacity(len);
@ -98,14 +122,19 @@ impl<'a> BinDecoder<'a> {
Ok(vec)
}
/// Reads a byte from the buffer, equivalent to `Self::pop()`
pub fn read_u8(&mut self) -> DecodeResult<u8> {
self.pop()
}
/// parses the next 2 bytes into u16. This performs a byte-by-byte manipulation, there
/// Reads the next 2 bytes into u16
///
/// This performs a byte-by-byte manipulation, there
/// which means endianness is implicitly handled (i.e. no network to little endian (intel), issues)
///
/// the vector should be reversed before calling.
/// # Return
///
/// Return the u16 from the buffer
pub fn read_u16(&mut self) -> DecodeResult<u16> {
let b1: u8 = try!(self.pop());
let b2: u8 = try!(self.pop());
@ -114,10 +143,14 @@ impl<'a> BinDecoder<'a> {
Ok(((b1 as u16) << 8) + (b2 as u16))
}
/// parses the next four bytes into i32. This performs a byte-by-byte manipulation, there
/// Reads the next four bytes into i32.
///
/// This performs a byte-by-byte manipulation, there
/// which means endianness is implicitly handled (i.e. no network to little endian (intel), issues)
///
/// the vector should be reversed before calling.
/// # Return
///
/// Return the i32 from the buffer
pub fn read_i32(&mut self) -> DecodeResult<i32> {
// TODO should this use a default rather than the panic! that will happen in the None case?
let b1: u8 = try!(self.pop());
@ -129,10 +162,14 @@ impl<'a> BinDecoder<'a> {
Ok(((b1 as i32) << 24) + ((b2 as i32) << 16) + ((b3 as i32) << 8) + (b4 as i32))
}
/// parses the next four bytes into u32. This performs a byte-by-byte manipulation, there
/// Reads the next four bytes into u32.
///
/// This performs a byte-by-byte manipulation, there
/// which means endianness is implicitly handled (i.e. no network to little endian (intel), issues)
///
/// the vector should be reversed before calling.
/// # Return
///
/// Return the u32 from the buffer
pub fn read_u32(&mut self) -> DecodeResult<u32> {
// TODO should this use a default rather than the panic! that will happen in the None case?
let b1: u8 = try!(self.pop());

View File

@ -30,17 +30,29 @@ pub struct BinEncoder<'a> {
}
impl<'a> BinEncoder<'a> {
/// Create a new encoder with the Vec to fill
pub fn new(buf: &'a mut Vec<u8>) -> Self {
Self::with_offset(buf, 0, EncodeMode::Normal)
}
/// Specify the mode for encoding
///
/// # Arguments
///
/// * `mode` - In Signing mode, it canonical forms of all data are encoded, otherwise format matches the source form
pub fn with_mode(buf: &'a mut Vec<u8>, mode: EncodeMode) -> Self {
Self::with_offset(buf, 0, mode)
}
/// offset is used mainly for pointers. If this encoder is starting at some point further in
/// Begins the encoder at the given offset
///
/// This is used for pointers. If this encoder is starting at some point further in
/// the sequence of bytes, for the proper offset of the pointer, the offset accounts for that
/// by using the offset to add to the pointer location being written.
///
/// # Arguments
///
/// * `offset` - index at which to start writing into the buffer
pub fn with_offset(buf: &'a mut Vec<u8>, offset: u32, mode: EncodeMode) -> Self {
BinEncoder {
offset: offset,
@ -51,48 +63,59 @@ impl<'a> BinEncoder<'a> {
}
}
/// Returns a reference to the internal buffer
pub fn as_bytes(self) -> &'a Vec<u8> {
self.buffer
}
/// Returns the length of the buffer
pub fn len(&self) -> usize {
self.buffer.len()
}
/// Returns the current offset into the buffer
pub fn offset(&self) -> u32 {
self.offset
}
/// Returns the current Encoding mode
pub fn mode(&self) -> EncodeMode {
self.mode
}
/// If set to true, then names will be written into the buffer in canonical form
pub fn set_canonical_names(&mut self, canonical_names: bool) {
self.canonical_names = canonical_names;
}
/// Returns true if then encoder is writing in canonical form
pub fn is_canonical_names(&self) -> bool {
self.canonical_names
}
/// Reserve specified length in the internal buffer
pub fn reserve(&mut self, extra: usize) {
self.buffer.reserve(extra);
}
/// Emit one byte into the buffer
pub fn emit(&mut self, b: u8) -> EncodeResult {
self.offset += 1;
self.buffer.push(b);
Ok(())
}
/// store the label pointer, the location is the current position in the buffer
/// implicitly, it is expected that the name will be written to the stream after this.
/// Stores a label pointer to an already written label
///
/// The location is the current position in the buffer
/// implicitly, it is expected that the name will be written to the stream after the current index.
pub fn store_label_pointer(&mut self, labels: Vec<Rc<String>>) {
if self.offset < 0x3FFFu32 {
self.name_pointers.insert(labels, self.offset as u16); // the next char will be at the len() location
}
}
/// Looks up the index of an already written label
pub fn get_label_pointer(&self, labels: &[Rc<String>]) -> Option<u16> {
self.name_pointers.get(labels).map(|i| *i)
}
@ -128,6 +151,7 @@ impl<'a> BinEncoder<'a> {
Ok(())
}
/// Writes a u16 in network byte order to the buffer
pub fn emit_u16(&mut self, data: u16) -> EncodeResult {
self.buffer.reserve(2); // two bytes coming
@ -140,7 +164,7 @@ impl<'a> BinEncoder<'a> {
Ok(())
}
/// Writes an i32 in network byte order to the buffer
pub fn emit_i32(&mut self, data: i32) -> EncodeResult {
self.buffer.reserve(4); // four bytes coming...
@ -157,7 +181,7 @@ impl<'a> BinEncoder<'a> {
Ok(())
}
/// Writes an u32 in network byte order to the buffer
pub fn emit_u32(&mut self, data: u32) -> EncodeResult {
self.buffer.reserve(4); // four bytes coming...
@ -174,6 +198,7 @@ impl<'a> BinEncoder<'a> {
Ok(())
}
/// Writes the byte slice to the stream
pub fn emit_vec(&mut self, data: &[u8]) -> EncodeResult {
self.buffer.reserve(data.len());
@ -189,6 +214,8 @@ impl<'a> BinEncoder<'a> {
/// should not be included in the additional count and not in the encoded data when in Verify
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum EncodeMode {
/// In signing mode records are written in canonical form
Signing,
/// Write records in standard format
Normal,
}

View File

@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! Binary serialization types
mod decoder;
mod encoder;
@ -25,8 +28,12 @@ pub mod bin_tests;
use ::error::*;
/// A trait for types which are serializable
pub trait BinSerializable<S: Sized> {
/// Read the type from the stream
fn read(decoder: &mut BinDecoder) -> DecodeResult<S>;
/// Write the type to the stream
fn emit(&self, encoder: &mut BinEncoder) -> EncodeResult;
}

View File

@ -15,7 +15,7 @@
*/
use std::collections::BTreeMap;
use ::error::*;
use error::*;
use rr::{Name, IntoRecordSet, RecordType, Record, DNSClass, RData, RrKey, RecordSet};
use super::master_lex::{Lexer, Token};
@ -123,11 +123,16 @@ use super::master_lex::{Lexer, Token};
pub struct Parser;
impl Parser {
/// Returns a new Zone file parser
pub fn new() -> Self {
Parser
}
// TODO: change this function to load into an Authority, using the update_records() method
/// Parse a file from the Lexer
///
/// # Return
///
/// A pair of the Zone origin name and a map of all Keys to RecordSets
pub fn parse(&mut self,
lexer: Lexer,
origin: Option<Name>)
@ -280,12 +285,13 @@ impl Parser {
if records.insert(key, set).is_some() {
return Err(ParseErrorKind::Message("SOA is already \
specified")
.into());
.into());
}
}
_ => {
// add a Vec if it's not there, then add the record to the list
let mut set = records.entry(key)
let mut set = records
.entry(key)
.or_insert(RecordSet::new(record.name(),
record.rr_type(),
0));

View File

@ -11,12 +11,14 @@ use std::char;
use error::{LexerResult, LexerError, LexerErrorKind};
/// A Lexer for Zone files
pub struct Lexer<'a> {
txt: Peekable<Chars<'a>>,
state: State,
}
impl<'a> Lexer<'a> {
/// Creates a new lexer with the given data to parse
pub fn new(txt: &str) -> Lexer {
Lexer {
txt: txt.chars().peekable(),
@ -24,6 +26,7 @@ impl<'a> Lexer<'a> {
}
}
/// Return the next Token in the string
pub fn next_token(&mut self) -> LexerResult<Option<Token>> {
let mut char_data_vec: Option<Vec<String>> = None;
let mut char_data: Option<String> = None;
@ -122,7 +125,9 @@ impl<'a> Lexer<'a> {
Some('"') => {
self.state = State::RestOfLine;
self.txt.next();
return Ok(Some(Token::CharData(char_data.take().unwrap_or("".into()))));
return Ok(Some(Token::CharData(char_data
.take()
.unwrap_or("".into()))));
}
Some('\\') => {
try!(Self::push_to_str(&mut char_data, try!(self.escape_seq())));
@ -144,7 +149,8 @@ impl<'a> Lexer<'a> {
// finishes the Dollar...
Some(_) | None => {
self.state = State::RestOfLine;
let dollar: String = try!(char_data.take()
let dollar: String =
try!(char_data.take()
.ok_or(LexerError::from(LexerErrorKind::IllegalState("char_data \
is None"))));
@ -171,10 +177,11 @@ impl<'a> Lexer<'a> {
Some(')') => {
self.txt.next();
self.state = State::RestOfLine;
return char_data_vec.take()
.ok_or(LexerErrorKind::IllegalState("char_data_vec is None")
.into())
.map(|v| Some(Token::List(v)));
return char_data_vec
.take()
.ok_or(LexerErrorKind::IllegalState("char_data_vec is None")
.into())
.map(|v| Some(Token::List(v)));
}
Some(ch) if ch.is_whitespace() => {
self.txt.next();
@ -198,9 +205,10 @@ impl<'a> Lexer<'a> {
self.state = State::List;
} else {
self.state = State::RestOfLine;
let result = char_data.take()
let result = char_data
.take()
.ok_or(LexerErrorKind::IllegalState("char_data is None")
.into());
.into());
let opt = result.map(|s| Some(Token::CharData(s)));
return opt;
}
@ -214,9 +222,11 @@ impl<'a> Lexer<'a> {
Some(ch) => return Err(LexerErrorKind::UnrecognizedChar(ch).into()),
None => {
self.state = State::EOF;
return char_data.take()
.ok_or(LexerErrorKind::IllegalState("char_data is None").into())
.map(|s| Some(Token::CharData(s)));
return char_data
.take()
.ok_or(LexerErrorKind::IllegalState("char_data is None")
.into())
.map(|s| Some(Token::CharData(s)));
}
}
}
@ -252,7 +262,8 @@ impl<'a> Lexer<'a> {
}
fn push_to_str(collect: &mut Option<String>, ch: char) -> LexerResult<()> {
collect.as_mut()
collect
.as_mut()
.ok_or(LexerErrorKind::IllegalState("collect is None").into())
.and_then(|s| Ok(s.push(ch)))
}
@ -285,8 +296,9 @@ impl<'a> Lexer<'a> {
}))); // gobble
let val: u32 = (d1 << 16) + (d2 << 8) + d3;
let ch: char = try!(char::from_u32(val)
.ok_or(LexerError::from(LexerErrorKind::UnrecognizedOctet(val))));
let ch: char =
try!(char::from_u32(val)
.ok_or(LexerError::from(LexerErrorKind::UnrecognizedOctet(val))));
return Ok(ch);
} else {
@ -321,16 +333,25 @@ pub enum State {
EOF,
}
/// Tokens emited from each Lexer pass
#[derive(PartialEq, Debug, Clone)]
pub enum Token {
Blank, // only if the first part of the line
List(Vec<String>), // (..) TODO, this is probably wrong, List maybe should just skip line endings
CharData(String), // [a-zA-Z, non-control utf8, ., -, 0-9]+, ".*"
At, // @
Include, // $INCLUDE
Origin, // $ORIGIN
Ttl, // $TTL
EOL, // \n or \r\n
/// only if the first part of the line
Blank,
/// (..) TODO, this is probably wrong, List maybe should just skip line endings
List(Vec<String>),
/// [a-zA-Z, non-control utf8, ., -, 0-9]+, ".*"
CharData(String),
/// @
At,
/// $INCLUDE
Include,
/// $ORIGIN
Origin,
/// $TTL
Ttl,
/// \n or \r\n
EOL,
}
#[cfg(test)]
@ -401,7 +422,10 @@ mod lex_test {
Token::CharData("Quoted".to_string()));
assert_eq!(Lexer::new("\";@$\"").next_token().unwrap().unwrap(),
Token::CharData(";@$".to_string()));
assert_eq!(Lexer::new("\"some \\A\"").next_token().unwrap().unwrap(),
assert_eq!(Lexer::new("\"some \\A\"")
.next_token()
.unwrap()
.unwrap(),
Token::CharData("some A".to_string()));
assert_eq!(Lexer::new("\"a\\Aa\"").next_token().unwrap().unwrap(),
Token::CharData("aAa".to_string()));
@ -495,8 +519,7 @@ mod lex_test {
#[test]
fn soa() {
let mut lexer =
Lexer::new("@ IN SOA VENERA Action\\.domains (
let mut lexer = Lexer::new("@ IN SOA VENERA Action\\.domains (
\
20 ; SERIAL
7200 ; REFRESH

View File

@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! Text serialization types
mod master_lex;
mod master;

View File

@ -50,6 +50,7 @@ impl TcpClientStream<TokioTcpStream> {
}
impl<S> TcpClientStream<S> {
/// Wraps the TcpStream in TcpClientStream
pub fn from_stream(tcp_stream: TcpStream<S>) -> Self {
TcpClientStream { tcp_stream: tcp_stream }
}

View File

@ -5,6 +5,8 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! This module contains all the TCP structures for demuxing TCP into streams of DNS packets.
use std::mem;
use std::net::SocketAddr;
use std::io;
@ -18,21 +20,48 @@ use tokio_core::reactor::Handle;
use BufStreamHandle;
/// Current state while writing to the remote of the TCP connection
enum WriteTcpState {
/// Currently writing the length of bytes to of the buffer.
LenBytes {
/// Current position in the length buffer being written
pos: usize,
/// Length of the buffer
length: [u8; 2],
/// Buffer to write after the length
bytes: Vec<u8>,
},
Bytes { pos: usize, bytes: Vec<u8> },
/// Currently writing the buffer to the remote
Bytes {
/// Current position in the buffer written
pos: usize,
/// Buffer to write to the remote
bytes: Vec<u8>,
},
/// Currently flushing the bytes to the remote
Flushing,
}
/// Current state of a TCP stream as it's being read.
pub enum ReadTcpState {
LenBytes { pos: usize, bytes: [u8; 2] },
Bytes { pos: usize, bytes: Vec<u8> },
/// Currently reading the length of the TCP packet
LenBytes {
/// Current position in the buffer
pos: usize,
/// Buffer of the length to read
bytes: [u8; 2],
},
/// Currently reading the byts of the DNS packet
Bytes {
/// Current position while reading the buffer
pos: usize,
/// buffer being read into
bytes: Vec<u8>,
},
}
/// A Stream used for sending data to and from a remote DNS endpoint (client or server).
#[must_use = "futures do nothing unless polled"]
pub struct TcpStream<S> {
socket: S,
@ -43,6 +72,7 @@ pub struct TcpStream<S> {
}
impl<S> TcpStream<S> {
/// Returns the address of the peer connection.
pub fn peer_addr(&self) -> SocketAddr {
self.peer_addr
}
@ -130,11 +160,18 @@ impl<S: AsyncRead + AsyncWrite> Stream for TcpStream<S> {
if self.send_state.is_some() {
// sending...
match self.send_state {
Some(WriteTcpState::LenBytes { ref mut pos, ref length, .. }) => {
Some(WriteTcpState::LenBytes {
ref mut pos,
ref length,
..
}) => {
let wrote = try_nb!(self.socket.write(&length[*pos..]));
*pos += wrote;
}
Some(WriteTcpState::Bytes { ref mut pos, ref bytes }) => {
Some(WriteTcpState::Bytes {
ref mut pos,
ref bytes,
}) => {
let wrote = try_nb!(self.socket.write(&bytes[*pos..]));
*pos += wrote;
}
@ -153,25 +190,25 @@ impl<S: AsyncRead + AsyncWrite> Stream for TcpStream<S> {
if pos < length.len() {
mem::replace(&mut self.send_state,
Some(WriteTcpState::LenBytes {
pos: pos,
length: length,
bytes: bytes,
}));
pos: pos,
length: length,
bytes: bytes,
}));
} else {
mem::replace(&mut self.send_state,
Some(WriteTcpState::Bytes {
pos: 0,
bytes: bytes,
}));
pos: 0,
bytes: bytes,
}));
}
}
Some(WriteTcpState::Bytes { pos, bytes }) => {
if pos < bytes.len() {
mem::replace(&mut self.send_state,
Some(WriteTcpState::Bytes {
pos: pos,
bytes: bytes,
}));
pos: pos,
bytes: bytes,
}));
} else {
// At this point we successfully delivered the entire message.
// flush
@ -220,7 +257,10 @@ impl<S: AsyncRead + AsyncWrite> Stream for TcpStream<S> {
// Evaluates the next state. If None is the result, then no state change occurs,
// if Some(_) is returned, then that will be used as the next state.
let new_state: Option<ReadTcpState> = match self.read_state {
ReadTcpState::LenBytes { ref mut pos, ref mut bytes } => {
ReadTcpState::LenBytes {
ref mut pos,
ref mut bytes,
} => {
// debug!("reading length {}", bytes.len());
let read = try_nb!(self.socket.read(&mut bytes[*pos..]));
if read == 0 {
@ -250,12 +290,15 @@ impl<S: AsyncRead + AsyncWrite> Stream for TcpStream<S> {
debug!("move ReadTcpState::Bytes: {}", bytes.len());
Some(ReadTcpState::Bytes {
pos: 0,
bytes: bytes,
})
pos: 0,
bytes: bytes,
})
}
}
ReadTcpState::Bytes { ref mut pos, ref mut bytes } => {
ReadTcpState::Bytes {
ref mut pos,
ref mut bytes,
} => {
let read = try_nb!(self.socket.read(&mut bytes[*pos..]));
if read == 0 {
// the Stream was closed!
@ -276,9 +319,9 @@ impl<S: AsyncRead + AsyncWrite> Stream for TcpStream<S> {
} else {
debug!("reset ReadTcpState::LenBytes: {}", 0);
Some(ReadTcpState::LenBytes {
pos: 0,
bytes: [0u8; 2],
})
pos: 0,
bytes: [0u8; 2],
})
}
}
};
@ -367,32 +410,45 @@ fn tcp_client_stream_test(server_addr: IpAddr) {
let send_recv_times = 4;
// an in and out server
let server_handle = std::thread::Builder::new().name("test_tcp_client_stream:server".to_string()).spawn(move || {
let (mut socket, _) = server.accept().expect("accept failed");
let server_handle = std::thread::Builder::new()
.name("test_tcp_client_stream:server".to_string())
.spawn(move || {
let (mut socket, _) = server.accept().expect("accept failed");
socket.set_read_timeout(Some(std::time::Duration::from_secs(5))).unwrap(); // should recieve something within 5 seconds...
socket.set_write_timeout(Some(std::time::Duration::from_secs(5))).unwrap(); // should recieve something within 5 seconds...
socket
.set_read_timeout(Some(std::time::Duration::from_secs(5)))
.unwrap(); // should recieve something within 5 seconds...
socket
.set_write_timeout(Some(std::time::Duration::from_secs(5)))
.unwrap(); // should recieve something within 5 seconds...
for _ in 0..send_recv_times {
// wait for some bytes...
let mut len_bytes = [0_u8; 2];
socket.read_exact(&mut len_bytes).expect("SERVER: receive failed");
let length = (len_bytes[0] as u16) << 8 & 0xFF00 | len_bytes[1] as u16 & 0x00FF;
assert_eq!(length as usize, TEST_BYTES_LEN);
for _ in 0..send_recv_times {
// wait for some bytes...
let mut len_bytes = [0_u8; 2];
socket
.read_exact(&mut len_bytes)
.expect("SERVER: receive failed");
let length = (len_bytes[0] as u16) << 8 & 0xFF00 | len_bytes[1] as u16 & 0x00FF;
assert_eq!(length as usize, TEST_BYTES_LEN);
let mut buffer = [0_u8; TEST_BYTES_LEN];
socket.read_exact(&mut buffer).unwrap();
let mut buffer = [0_u8; TEST_BYTES_LEN];
socket.read_exact(&mut buffer).unwrap();
// println!("read bytes iter: {}", i);
assert_eq!(&buffer, TEST_BYTES);
// println!("read bytes iter: {}", i);
assert_eq!(&buffer, TEST_BYTES);
// bounce them right back...
socket.write_all(&len_bytes).expect("SERVER: send length failed");
socket.write_all(&buffer).expect("SERVER: send buffer failed");
// println!("wrote bytes iter: {}", i);
std::thread::yield_now();
}
}).unwrap();
// bounce them right back...
socket
.write_all(&len_bytes)
.expect("SERVER: send length failed");
socket
.write_all(&buffer)
.expect("SERVER: send buffer failed");
// println!("wrote bytes iter: {}", i);
std::thread::yield_now();
}
})
.unwrap();
// setup the client, which is going to run on the testing thread...
let mut io_loop = Core::new().unwrap();
@ -402,13 +458,20 @@ fn tcp_client_stream_test(server_addr: IpAddr) {
// let timeout = Timeout::new(Duration::from_secs(5), &io_loop.handle());
let (stream, sender) = TcpStream::new(server_addr, io_loop.handle());
let mut stream = io_loop.run(stream).ok().expect("run failed to get stream");
let mut stream = io_loop
.run(stream)
.ok()
.expect("run failed to get stream");
for _ in 0..send_recv_times {
// test once
sender.send((TEST_BYTES.to_vec(), server_addr)).expect("send failed");
let (buffer, stream_tmp) =
io_loop.run(stream.into_future()).ok().expect("future iteration run failed");
sender
.send((TEST_BYTES.to_vec(), server_addr))
.expect("send failed");
let (buffer, stream_tmp) = io_loop
.run(stream.into_future())
.ok()
.expect("future iteration run failed");
stream = stream_tmp;
let (buffer, _) = buffer.expect("no buffer received");
assert_eq!(&buffer, TEST_BYTES);

View File

@ -35,6 +35,7 @@ pub struct TlsClientConnection {
}
impl TlsClientConnection {
/// Creates a new builder for the construction of a TlsClientConnection.
pub fn builder() -> TlsClientConnectionBuilder {
TlsClientConnectionBuilder(TlsClientStream::builder())
}
@ -43,11 +44,16 @@ impl TlsClientConnection {
impl ClientConnection for TlsClientConnection {
type MessageStream = TlsClientStream;
fn unwrap(self) -> (Core, Box<Future<Item=Self::MessageStream, Error=io::Error>>, Box<ClientStreamHandle>){
fn unwrap
(self)
-> (Core,
Box<Future<Item = Self::MessageStream, Error = io::Error>>,
Box<ClientStreamHandle>) {
(self.io_loop, self.tls_client_stream, self.client_stream_handle)
}
}
/// A builder for the TlsClientStream.
pub struct TlsClientConnectionBuilder(TlsClientStreamBuilder);
impl TlsClientConnectionBuilder {

View File

@ -21,14 +21,17 @@ use tcp::TcpClientStream;
use tls::{TlsStream, TlsStreamBuilder};
use client::ClientStreamHandle;
/// A Type definition for the TLS stream
pub type TlsClientStream = TcpClientStream<TokioTlsStream<TokioTcpStream>>;
impl TlsClientStream {
/// Creates a builder fo the construction of a TlsClientStream
pub fn builder() -> TlsClientStreamBuilder {
TlsClientStreamBuilder(TlsStream::builder())
}
}
/// A Builder for the TlsClientStream
pub struct TlsClientStreamBuilder(TlsStreamBuilder);
impl TlsClientStreamBuilder {

View File

@ -52,6 +52,7 @@ impl TlsIdentityExt for SslContextBuilder {
}
}
/// A TlsStream counterpart to the TcpStream which embeds a secure TlsStream
pub type TlsStream = TcpStream<TokioTlsStream<TokioTcpStream>>;
impl TlsStream {
@ -121,6 +122,7 @@ impl TlsStream {
}
}
/// A builder for the TlsStream
pub struct TlsStreamBuilder {
ca_chain: Vec<X509>,
identity: Option<ParsedPkcs12>,

View File

@ -15,6 +15,7 @@ use BufClientStreamHandle;
use client::ClientStreamHandle;
use udp::UdpStream;
/// A UDP client stream of DNS binary packets
#[must_use = "futures do nothing unless polled"]
pub struct UdpClientStream {
name_server: SocketAddr,

View File

@ -25,6 +25,7 @@ lazy_static!{
static ref IPV6_ZERO: Ipv6Addr = Ipv6Addr::new(0,0,0,0,0,0,0,0);
}
/// A UDP stream of DNS binary packets
#[must_use = "futures do nothing unless polled"]
pub struct UdpStream {
socket: tokio_core::net::UdpSocket,

View File

@ -1,4 +1,4 @@
// Copyright 2015-2016 Benjamin Fry <benjaminfry@me.com>
// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or

View File

@ -16,6 +16,8 @@
//! TLS protocol related components for DNS over TLS
#![deny(missing_docs)]
extern crate futures;
extern crate native_tls;
extern crate tokio_core;

View File

@ -37,6 +37,7 @@ pub struct TlsClientConnection {
}
impl TlsClientConnection {
/// Creates a new builder for the construction of a TlsClientConnection.
pub fn builder() -> TlsClientConnectionBuilder {
TlsClientConnectionBuilder(TlsClientStreamBuilder::new())
}
@ -45,11 +46,16 @@ impl TlsClientConnection {
impl ClientConnection for TlsClientConnection {
type MessageStream = TlsClientStream;
fn unwrap(self) -> (Core, Box<Future<Item=Self::MessageStream, Error=io::Error>>, Box<ClientStreamHandle>){
fn unwrap
(self)
-> (Core,
Box<Future<Item = Self::MessageStream, Error = io::Error>>,
Box<ClientStreamHandle>) {
(self.io_loop, self.tls_client_stream, self.client_stream_handle)
}
}
/// A builder for the TlsClientStream.
pub struct TlsClientConnectionBuilder(TlsClientStreamBuilder);
impl TlsClientConnectionBuilder {

View File

@ -5,6 +5,8 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! TlsClientStream for DNS over TLS
use std::net::SocketAddr;
use std::io;
@ -22,11 +24,16 @@ use trust_dns::client::ClientStreamHandle;
use TlsStreamBuilder;
/// TlsClientStream secure DNS over TCP stream
///
/// See TlsClientStreamBuilder::new()
pub type TlsClientStream = TcpClientStream<TokioTlsStream<TokioTcpStream>>;
/// Builder for TlsClientStream
pub struct TlsClientStreamBuilder(TlsStreamBuilder);
impl TlsClientStreamBuilder {
/// Creates a builder fo the construction of a TlsClientStream
pub fn new() -> TlsClientStreamBuilder {
TlsClientStreamBuilder(TlsStreamBuilder::new())
}

View File

@ -5,6 +5,8 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! Base TlsStream
use std::net::SocketAddr;
use std::io;
@ -19,6 +21,7 @@ use tokio_tls::{TlsConnectorExt, TlsStream as TokioTlsStream};
use trust_dns::BufStreamHandle;
use trust_dns::tcp::TcpStream;
/// A TlsStream counterpart to the TcpStream which embeds a secure TlsStream
pub type TlsStream = TcpStream<TokioTlsStream<TokioTcpStream>>;
fn tls_new(certs: Vec<Certificate>, pkcs12: Option<Pkcs12>) -> io::Result<TlsConnector> {
@ -71,6 +74,7 @@ pub fn tls_from_stream(stream: TokioTlsStream<TokioTcpStream>,
(stream, message_sender)
}
/// A builder for the TlsStream
pub struct TlsStreamBuilder {
ca_chain: Vec<Certificate>,
identity: Option<Pkcs12>,

View File

@ -26,6 +26,7 @@ fn main() {
let mut f = File::create(&dest_path).unwrap();
f.write_all(b"/// Returns the current version of TRust-DNS\n").unwrap();
f.write_all(b"pub fn version() -> &'static str {").unwrap();
write!(f, " \"{}\" ", version).unwrap();
f.write_all(b" }").unwrap();

View File

@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! All authority related types
use std::collections::BTreeMap;
use chrono::UTC;
@ -88,7 +90,7 @@ impl Authority {
/// * `signer` - Signer with associated private key
pub fn add_secure_key(&mut self, signer: Signer) -> DnsSecResult<()> {
// also add the key to the zone
let zone_ttl = self.get_minimum_ttl();
let zone_ttl = self.minimum_ttl();
let dnskey = try!(signer.key().to_dnskey(signer.algorithm()));
let dnskey = Record::from_rdata(self.origin.clone(),
zone_ttl,
@ -96,7 +98,7 @@ impl Authority {
RData::DNSKEY(dnskey));
// TODO: also generate the CDS and CDNSKEY
let serial = self.get_serial();
let serial = self.serial();
self.upsert(dnskey, serial);
self.secure_keys.push(signer);
Ok(())
@ -142,7 +144,7 @@ impl Authority {
/// Returns an error if there was an issue writing to the persistence layer.
pub fn persist_to_journal(&self) -> PersistenceResult<()> {
if let Some(journal) = self.journal.as_ref() {
let serial = self.get_serial();
let serial = self.serial();
info!("persisting zone to journal at SOA.serial: {}", serial);
@ -162,11 +164,13 @@ impl Authority {
Ok(())
}
pub fn journal(&mut self, journal: Journal) {
/// Associate a backing Journal with this Authority for Updatable zones
pub fn set_journal(&mut self, journal: Journal) {
self.journal = Some(journal);
}
pub fn get_journal(&self) -> Option<&Journal> {
/// Returns the associated Journal
pub fn journal(&self) -> Option<&Journal> {
self.journal.as_ref()
}
@ -176,30 +180,30 @@ impl Authority {
}
/// Retrieve the Signer, which contains the private keys, for this zone
pub fn get_secure_keys(&self) -> &[Signer] {
pub fn secure_keys(&self) -> &[Signer] {
&self.secure_keys
}
/// Get the origin of this zone, i.e. example.com is the origin for www.example.com
pub fn get_origin(&self) -> &Name {
pub fn origin(&self) -> &Name {
&self.origin
}
/// What type is this zone
pub fn get_zone_type(&self) -> ZoneType {
pub fn zone_type(&self) -> ZoneType {
self.zone_type
}
/// Get all the
pub fn get_records(&self) -> &BTreeMap<RrKey, RecordSet> {
pub fn records(&self) -> &BTreeMap<RrKey, RecordSet> {
&self.records
}
/// Returns the SOA of the authority.
///
/// *Note*: This will only return the SOA, if this is fullfilling a request, a standard lookup
/// should be used, see `get_soa_secure()`, which will optionally return RRSIGs.
pub fn get_soa(&self) -> Option<&Record> {
/// should be used, see `soa_secure()`, which will optionally return RRSIGs.
pub fn soa(&self) -> Option<&Record> {
// SOA should be origin|SOA
self.lookup(&self.origin,
RecordType::SOA,
@ -210,10 +214,10 @@ impl Authority {
}
/// Returns the SOA record for the zone
pub fn get_soa_secure(&self,
is_secure: bool,
supported_algorithms: SupportedAlgorithms)
-> Vec<&Record> {
pub fn soa_secure(&self,
is_secure: bool,
supported_algorithms: SupportedAlgorithms)
-> Vec<&Record> {
self.lookup(&self.origin,
RecordType::SOA,
is_secure,
@ -221,17 +225,18 @@ impl Authority {
}
/// Returns the minimum ttl (as used in the SOA record)
pub fn get_minimum_ttl(&self) -> u32 {
self.get_soa().map_or(0, |soa| if let &RData::SOA(ref rdata) = soa.rdata() {
rdata.minimum()
} else {
0
})
pub fn minimum_ttl(&self) -> u32 {
self.soa()
.map_or(0, |soa| if let &RData::SOA(ref rdata) = soa.rdata() {
rdata.minimum()
} else {
0
})
}
/// get the current serial number for the zone.
pub fn get_serial(&self) -> u32 {
let soa = if let Some(ref soa_record) = self.get_soa() {
pub fn serial(&self) -> u32 {
let soa = if let Some(ref soa_record) = self.soa() {
soa_record.clone()
} else {
warn!("no soa record found for zone: {}", self.origin);
@ -246,7 +251,7 @@ impl Authority {
}
fn increment_soa_serial(&mut self) -> u32 {
let mut soa = if let Some(ref mut soa_record) = self.get_soa() {
let mut soa = if let Some(ref mut soa_record) = self.soa() {
soa_record.clone()
} else {
warn!("no soa record found for zone: {}", self.origin);
@ -264,10 +269,8 @@ impl Authority {
return serial;
}
pub fn get_ns(&self,
is_secure: bool,
supported_algorithms: SupportedAlgorithms)
-> Vec<&Record> {
/// Get the NS, NameServer, record for the zone
pub fn ns(&self, is_secure: bool, supported_algorithms: SupportedAlgorithms) -> Vec<&Record> {
self.lookup(&self.origin,
RecordType::NS,
is_secure,
@ -480,51 +483,54 @@ impl Authority {
let sig0s: &[Record] = update_message.sig0();
debug!("authorizing with: {:?}", sig0s);
if !sig0s.is_empty() &&
sig0s.iter()
.filter_map(|sig0| if let &RData::SIG(ref sig) = sig0.rdata() {
Some(sig)
} else {
None
})
.any(|sig| {
let name = sig.signer_name();
let keys = self.lookup(name, RecordType::KEY, false, SupportedAlgorithms::new());
debug!("found keys {:?}", keys);
keys.iter()
.filter_map(|rr_set| if let &RData::KEY(ref key) = rr_set.rdata() {
Some(key)
} else {
None
})
.any(|key| {
let pkey = KeyPair::from_public_bytes(key.public_key(),
*key.algorithm());
if let Err(error) = pkey {
warn!("public key {:?} of {} could not be used: {}",
key,
name,
error);
return false;
}
let pkey = pkey.unwrap();
let signer: Signer = Signer::new_verifier(*key.algorithm(),
pkey,
sig.signer_name().clone(),
false,
true);
signer.verify_message(update_message, sig.sig())
.map(|_| {
info!("verified sig: {:?} with key: {:?}", sig, key);
true
sig0s
.iter()
.filter_map(|sig0| if let &RData::SIG(ref sig) = sig0.rdata() {
Some(sig)
} else {
None
})
.any(|sig| {
let name = sig.signer_name();
let keys = self.lookup(name, RecordType::KEY, false, SupportedAlgorithms::new());
debug!("found keys {:?}", keys);
keys.iter()
.filter_map(|rr_set| if let &RData::KEY(ref key) = rr_set.rdata() {
Some(key)
} else {
None
})
.unwrap_or_else(|_| {
debug!("did not verify sig: {:?} with key: {:?}", sig, key);
false
})
})
}) {
.any(|key| {
let pkey = KeyPair::from_public_bytes(key.public_key(), *key.algorithm());
if let Err(error) = pkey {
warn!("public key {:?} of {} could not be used: {}",
key,
name,
error);
return false;
}
let pkey = pkey.unwrap();
let signer: Signer = Signer::new_verifier(*key.algorithm(),
pkey,
sig.signer_name().clone(),
false,
true);
signer
.verify_message(update_message, sig.sig())
.map(|_| {
info!("verified sig: {:?} with key: {:?}", sig, key);
true
})
.unwrap_or_else(|_| {
debug!("did not verify sig: {:?} with key: {:?}",
sig,
key);
false
})
})
}) {
return Ok(());
} else {
warn!("no sig0 matched registered records: id {}",
@ -581,7 +587,7 @@ impl Authority {
// else
// return (FORMERR)
for rr in records {
if !self.get_origin().zone_of(rr.name()) {
if !self.origin().zone_of(rr.name()) {
return Err(ResponseCode::NotZone);
}
@ -656,7 +662,7 @@ impl Authority {
auto_signing_and_increment: bool)
-> UpdateResult<bool> {
let mut updated = false;
let serial: u32 = self.get_serial();
let serial: u32 = self.serial();
// the persistence act as a write-ahead log. The WAL will also be used for recovery of a zone
// subsequent to a failure of the server.
@ -747,10 +753,10 @@ impl Authority {
let to_delete = self.records
.keys()
.filter(|k| {
!((k.record_type == RecordType::SOA ||
k.record_type == RecordType::NS) &&
k.name != self.origin)
})
!((k.record_type == RecordType::SOA ||
k.record_type == RecordType::NS) &&
k.name != self.origin)
})
.filter(|k| &k.name == rr.name())
.cloned()
.collect::<Vec<RrKey>>();
@ -796,10 +802,11 @@ impl Authority {
// update the serial...
if updated && auto_signing_and_increment {
if self.is_dnssec_enabled {
try!(self.secure_zone().map_err(|e| {
error!("failure securing zone: {}", e);
ResponseCode::ServFail
}))
try!(self.secure_zone()
.map_err(|e| {
error!("failure securing zone: {}", e);
ResponseCode::ServFail
}))
} else {
// the secure_zone() function increments the SOA during it's operation, if we're not
// dnssec, then we need to do it here...
@ -826,9 +833,10 @@ impl Authority {
assert_eq!(self.class, record.dns_class());
let rr_key = RrKey::new(record.name(), record.rr_type());
let records: &mut RecordSet = self.records
.entry(rr_key)
.or_insert(RecordSet::new(record.name(), record.rr_type(), serial));
let records: &mut RecordSet =
self.records
.entry(rr_key)
.or_insert(RecordSet::new(record.name(), record.rr_type(), serial));
records.insert(record, serial)
}
@ -920,7 +928,7 @@ impl Authority {
// if this is an AXFR zone transfer, verify that this is either the slave or master
// for AXFR the first and last record must be the SOA
if RecordType::AXFR == record_type {
match self.get_zone_type() {
match self.zone_type() {
ZoneType::Master | ZoneType::Slave => (),
// TODO Forward?
_ => return vec![], // TODO this sould be an error.
@ -929,13 +937,11 @@ impl Authority {
// it would be better to stream this back, rather than packaging everything up in an array
// though for UDP it would still need to be bundled
let mut query_result: Vec<_> = self.lookup(query.name(),
record_type,
is_secure,
supported_algorithms);
let mut query_result: Vec<_> =
self.lookup(query.name(), record_type, is_secure, supported_algorithms);
if RecordType::AXFR == record_type {
if let Some(soa) = self.get_soa() {
if let Some(soa) = self.soa() {
let mut xfr: Vec<&Record> = query_result;
// TODO: probably make Records Rc or Arc, to remove the clone
xfr.insert(0, soa);
@ -984,8 +990,8 @@ impl Authority {
self.records
.values()
.filter(|rr_set| {
rtype == RecordType::ANY || rr_set.record_type() != RecordType::SOA
})
rtype == RecordType::ANY || rr_set.record_type() != RecordType::SOA
})
.filter(|rr_set| rtype == RecordType::AXFR || rr_set.name() == name)
.fold(Vec::<&Record>::new(), |mut vec, rr_set| {
vec.append(&mut rr_set.records(is_secure, supported_algorithms));
@ -993,9 +999,14 @@ impl Authority {
})
}
_ => {
self.records.get(&rr_key).map_or(vec![], |rr_set| {
rr_set.records(is_secure, supported_algorithms).into_iter().collect()
})
self.records
.get(&rr_key)
.map_or(vec![], |rr_set| {
rr_set
.records(is_secure, supported_algorithms)
.into_iter()
.collect()
})
}
};
@ -1020,7 +1031,10 @@ impl Authority {
.skip_while(|rr_set| name < rr_set.name())
.next()
.map_or(vec![], |rr_set| {
rr_set.records(is_secure, supported_algorithms).into_iter().collect()
rr_set
.records(is_secure, supported_algorithms)
.into_iter()
.collect()
})
}
@ -1058,8 +1072,8 @@ impl Authority {
}
// now go through and generate the nsec records
let ttl = self.get_minimum_ttl();
let serial = self.get_serial();
let ttl = self.minimum_ttl();
let serial = self.serial();
let mut records: Vec<Record> = vec![];
{
@ -1085,7 +1099,7 @@ impl Authority {
if let Some((name, vec)) = nsec_info {
// names aren't equal, create the NSEC record
let mut record = Record::with(name.clone(), RecordType::NSEC, ttl);
let rdata = NSEC::new(self.get_origin().clone(), vec);
let rdata = NSEC::new(self.origin().clone(), vec);
record.set_rdata(RData::NSEC(rdata));
records.push(record);
}
@ -1101,21 +1115,23 @@ impl Authority {
fn sign_zone(&mut self) -> DnsSecResult<()> {
debug!("signing zone: {}", self.origin);
let inception = UTC::now();
let zone_ttl = self.get_minimum_ttl();
let zone_ttl = self.minimum_ttl();
// TODO: should this be an error?
if self.secure_keys.is_empty() {
warn!("attempt to sign_zone for dnssec, but no keys available!")
}
for rr_set in self.records.iter_mut().filter_map(|(_, rr_set)| {
// do not sign zone DNSKEY's that's the job of the parent zone
if rr_set.record_type() == RecordType::DNSKEY {
return None;
}
rr_set.rrsigs().is_empty();
Some(rr_set)
}) {
for rr_set in self.records
.iter_mut()
.filter_map(|(_, rr_set)| {
// do not sign zone DNSKEY's that's the job of the parent zone
if rr_set.record_type() == RecordType::DNSKEY {
return None;
}
rr_set.rrsigs().is_empty();
Some(rr_set)
}) {
debug!("signing rr_set: {}", rr_set.name());
rr_set.clear_rrsigs();
@ -1136,11 +1152,12 @@ impl Authority {
try!(signer.calculate_key_tag()),
signer.signer_name(),
// TODO: this is a nasty clone... the issue is that the vec
// from get_records is of Vec<&R>, but we really want &[R]
&rr_set.records(false, SupportedAlgorithms::new())
.into_iter()
.cloned()
.collect::<Vec<Record>>());
// from records is of Vec<&R>, but we really want &[R]
&rr_set
.records(false, SupportedAlgorithms::new())
.into_iter()
.cloned()
.collect::<Vec<Record>>());
// TODO, maybe chain these with some ETL operations instead?
if hash.is_err() {
@ -1159,23 +1176,23 @@ impl Authority {
let mut rrsig = rrsig_temp.clone();
rrsig.set_rdata(RData::SIG(SIG::new(// type_covered: RecordType,
rr_set.record_type(),
// algorithm: Algorithm,
signer.algorithm(),
// num_labels: u8,
rr_set.name().num_labels(),
// original_ttl: u32,
rr_set.ttl(),
// sig_expiration: u32,
expiration.timestamp() as u32,
// sig_inception: u32,
inception.timestamp() as u32,
// key_tag: u16,
try!(signer.calculate_key_tag()),
// signer_name: Name,
signer.signer_name().clone(),
// sig: Vec<u8>
signature)));
rr_set.record_type(),
// algorithm: Algorithm,
signer.algorithm(),
// num_labels: u8,
rr_set.name().num_labels(),
// original_ttl: u32,
rr_set.ttl(),
// sig_expiration: u32,
expiration.timestamp() as u32,
// sig_inception: u32,
inception.timestamp() as u32,
// key_tag: u16,
try!(signer.calculate_key_tag()),
// signer_name: Name,
signer.signer_name().clone(),
// sig: Vec<u8>
signature)));
rr_set.insert_rrsig(rrsig);
debug!("signed rr_set: {}", rr_set.name());

View File

@ -59,10 +59,10 @@ impl RequestHandler for Catalog {
let our_version = 0;
resp_edns.set_dnssec_ok(true);
resp_edns.set_max_payload(if req_edns.max_payload() < 512 {
512
} else {
req_edns.max_payload()
});
512
} else {
req_edns.max_payload()
});
resp_edns.set_version(our_version);
if req_edns.version() > our_version {
@ -100,17 +100,13 @@ impl RequestHandler for Catalog {
}
c @ _ => {
error!("unimplemented op_code: {:?}", c);
Message::error_msg(request.id(),
request.op_code(),
ResponseCode::NotImp)
Message::error_msg(request.id(), request.op_code(), ResponseCode::NotImp)
}
}
}
MessageType::Response => {
warn!("got a response as a request from id: {}", request.id());
Message::error_msg(request.id(),
request.op_code(),
ResponseCode::NotImp)
Message::error_msg(request.id(), request.op_code(), ResponseCode::NotImp)
}
};
@ -140,10 +136,17 @@ impl RequestHandler for Catalog {
}
impl Catalog {
/// Constructs a new Catalog
pub fn new() -> Self {
Catalog { authorities: HashMap::new() }
}
/// Insert or update a zone authority
///
/// # Arguments
///
/// * `name` - zone name, e.g. example.com.
/// * `authority` - the zone data
pub fn upsert(&mut self, name: Name, authority: Authority) {
self.authorities.insert(name, RwLock::new(authority));
}
@ -217,7 +220,7 @@ impl Catalog {
if let Some(authority) = self.find_auth_recurse(zones[0].name()) {
let mut authority = authority.write().unwrap(); // poison errors should panic...
match authority.get_zone_type() {
match authority.zone_type() {
ZoneType::Slave => {
error!("slave forwarding for update not yet implemented");
response.set_response_code(ResponseCode::NotImp);
@ -264,8 +267,9 @@ impl Catalog {
for query in request.queries() {
if let Some(ref_authority) = self.find_auth_recurse(query.name()) {
let authority = &ref_authority.read().unwrap(); // poison errors should panic
debug!("found authority: {:?}", authority.get_origin());
let (is_dnssec, supported_algorithms) = request.edns()
debug!("found authority: {:?}", authority.origin());
let (is_dnssec, supported_algorithms) = request
.edns()
.map_or((false, SupportedAlgorithms::new()), |edns| {
let supported_algorithms = if let Some(&EdnsOption::DAU(algs)) =
edns.option(&EdnsCode::DAU) {
@ -284,28 +288,27 @@ impl Catalog {
response.add_answers(records.into_iter().cloned());
// get the NS records
let ns = authority.get_ns(is_dnssec, supported_algorithms);
let ns = authority.ns(is_dnssec, supported_algorithms);
if ns.is_empty() {
warn!("there are no NS records for: {:?}", authority.get_origin());
warn!("there are no NS records for: {:?}", authority.origin());
} else {
response.add_name_servers(ns.into_iter().cloned());
}
} else {
if is_dnssec {
// get NSEC records
let nsecs =
authority.get_nsec_records(query.name(),
is_dnssec,
supported_algorithms);
let nsecs = authority.get_nsec_records(query.name(),
is_dnssec,
supported_algorithms);
response.add_name_servers(nsecs.into_iter().cloned());
}
// in the not found case it's standard to return the SOA in the authority section
response.set_response_code(ResponseCode::NXDomain);
let soa = authority.get_soa_secure(is_dnssec, supported_algorithms);
let soa = authority.soa_secure(is_dnssec, supported_algorithms);
if soa.is_empty() {
warn!("there is no SOA record for: {:?}", authority.get_origin());
warn!("there is no SOA record for: {:?}", authority.origin());
} else {
response.add_name_servers(soa.into_iter().cloned());
}

View File

@ -18,13 +18,19 @@
use trust_dns::op::ResponseCode;
/// Result of an Update operation
pub type UpdateResult<T> = Result<T, ResponseCode>;
/// The type of zone stored in a Catalog
#[derive(RustcDecodable, PartialEq, Eq, Debug, Clone, Copy)]
pub enum ZoneType {
/// This authority for a zone, i.e. the Primary
Master,
/// A secondary, i.e. replicated from the Master
Slave,
/// A cached zone with recursive resolver abilities
Hint,
/// A cached zone where all requests are forwarded to another Resolver
Forward,
}

View File

@ -4,6 +4,9 @@
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! All zone persistence related types
use std::iter::Iterator;
use std::path::Path;
@ -16,6 +19,7 @@ use trust_dns::serialize::binary::{BinDecoder, BinEncoder, BinSerializable};
use error::{PersistenceErrorKind, PersistenceResult};
/// The current Journal version of the application
pub const CURRENT_VERSION: i64 = 1;
/// The Journal is the audit log of all changes to a zone after initial creation.
@ -25,14 +29,16 @@ pub struct Journal {
}
impl Journal {
/// Constructs a new Journal, attaching to the specified Sqlite Connection
pub fn new(conn: Connection) -> PersistenceResult<Journal> {
let version = Self::select_schema_version(&conn);
Ok(Journal {
conn: conn,
version: try!(version),
})
conn: conn,
version: try!(version),
})
}
/// Constructs a new Journal opening a Sqlite connection to the file at the specified path
pub fn from_file(journal_file: &Path) -> PersistenceResult<Journal> {
let result = Self::new(try!(Connection::open(journal_file)));
match result {
@ -44,12 +50,13 @@ impl Journal {
}
}
pub fn get_conn(&self) -> &Connection {
/// Returns a reference to the Sqlite Connection
pub fn conn(&self) -> &Connection {
&self.conn
}
/// gets the current schema version of the journal
pub fn get_schema_version(&self) -> i64 {
/// Returns the current schema version of the journal
pub fn schema_version(&self) -> i64 {
self.version
}
@ -81,13 +88,14 @@ impl Journal {
let client_id: i64 = 0; // TODO: we need better id information about the client, like pub_key
let soa_serial: i64 = soa_serial as i64;
let count = try!(self.conn.execute("INSERT
let count = try!(self.conn
.execute("INSERT
\
INTO records (client_id, soa_serial, timestamp, \
record)
\
VALUES ($1, $2, $3, $4)",
&[&client_id, &soa_serial, &timestamp, &serial_record]));
&[&client_id, &soa_serial, &timestamp, &serial_record]));
//
if count != 1 {
return Err(PersistenceErrorKind::WrongInsertCount(count, 1).into());
@ -119,7 +127,8 @@ impl Journal {
assert!(self.version == CURRENT_VERSION,
"schema version mismatch, schema_up() resolves this");
let mut stmt = try!(self.conn.prepare("SELECT _rowid_, record
let mut stmt = try!(self.conn
.prepare("SELECT _rowid_, record
\
FROM records
\
@ -127,8 +136,7 @@ impl Journal {
\
LIMIT 1"));
let record_opt: Option<Result<(i64, Record), rusqlite::Error>> =
try!(stmt.query_and_then(&[&row_id],
let record_opt: Option<Result<(i64, Record), rusqlite::Error>> = try!(stmt.query_and_then(&[&row_id],
|row| -> Result<(i64, Record), rusqlite::Error> {
let row_id: i64 = try!(row.get_checked(0));
let record_bytes: Vec<u8> = try!(row.get_checked(1));
@ -194,7 +202,8 @@ impl Journal {
// validate the versions of all the schemas...
assert!(new_version <= CURRENT_VERSION);
let count = try!(self.conn.execute("UPDATE tdns_schema SET version = $1", &[&new_version]));
let count = try!(self.conn
.execute("UPDATE tdns_schema SET version = $1", &[&new_version]));
//
assert_eq!(count, 1);
@ -218,16 +227,18 @@ impl Journal {
/// initial schema, include the tdns_schema table for tracking the Journal version
fn init_up(&self) -> PersistenceResult<i64> {
let count = try!(self.conn.execute("CREATE TABLE tdns_schema (
let count = try!(self.conn
.execute("CREATE TABLE tdns_schema (
\
version INTEGER NOT NULL
\
)",
&[]));
&[]));
//
assert_eq!(count, 0);
let count = try!(self.conn.execute("INSERT INTO tdns_schema (version) VALUES (0)", &[]));
let count = try!(self.conn
.execute("INSERT INTO tdns_schema (version) VALUES (0)", &[]));
//
assert_eq!(count, 1);
@ -238,7 +249,8 @@ impl Journal {
/// authority. Each record is expected to be in the format of an update record
fn records_up(&self) -> PersistenceResult<i64> {
// we'll be using rowid for our primary key, basically: `rowid INTEGER PRIMARY KEY ASC`
let count = try!(self.conn.execute("CREATE TABLE records (
let count = try!(self.conn
.execute("CREATE TABLE records (
\
client_id INTEGER NOT NULL,
\
@ -249,7 +261,7 @@ impl Journal {
record BLOB NOT NULL
\
)",
&[]));
&[]));
//
assert_eq!(count, 1);
@ -257,6 +269,9 @@ impl Journal {
}
}
/// Returns an iterator over all items in a Journal
///
/// Useful for replaying an entire journal into memory to reconstruct a zone from disk
pub struct JournalIter<'j> {
current_row_id: i64,
journal: &'j Journal,
@ -275,8 +290,8 @@ impl<'j> Iterator for JournalIter<'j> {
type Item = Record;
fn next(&mut self) -> Option<Self::Item> {
let next: PersistenceResult<Option<(i64, Record)>> = self.journal
.select_record(self.current_row_id + 1);
let next: PersistenceResult<Option<(i64, Record)>> =
self.journal.select_record(self.current_row_id + 1);
match next {
Ok(Some((row_id, record))) => {

View File

@ -39,16 +39,26 @@ static DEFAULT_PORT: u16 = 53;
static DEFAULT_TLS_PORT: u16 = 853;
static DEFAULT_TCP_REQUEST_TIMEOUT: u64 = 5;
/// Server configuration
#[derive(RustcDecodable, Debug)]
pub struct Config {
/// The list of IPv4 addresses to listen on
listen_addrs_ipv4: Vec<String>,
/// This list of IPv6 addresses to listen on
listen_addrs_ipv6: Vec<String>,
/// Port on which to listen (associated to all IPs)
listen_port: Option<u16>,
/// Secure port to listen on
tls_listen_port: Option<u16>,
/// Timeout associated to a request before it is closed.
tcp_request_timeout: Option<u64>,
/// Level at which to log, default is INFO
log_level: Option<String>,
/// Base configuration directory, i.e. root path for zones
directory: Option<String>,
/// List of configurations for zones
zones: Vec<ZoneConfig>,
/// Certificate to associate to TLS connections
tls_cert: Option<TlsCertConfig>,
}
@ -63,11 +73,17 @@ impl Config {
/// set of listening ipv4 addresses (for TCP and UDP)
pub fn get_listen_addrs_ipv4(&self) -> Vec<Ipv4Addr> {
self.listen_addrs_ipv4.iter().map(|s| s.parse().unwrap()).collect()
self.listen_addrs_ipv4
.iter()
.map(|s| s.parse().unwrap())
.collect()
}
/// set of listening ipv6 addresses (for TCP and UDP)
pub fn get_listen_addrs_ipv6(&self) -> Vec<Ipv6Addr> {
self.listen_addrs_ipv6.iter().map(|s| s.parse().unwrap()).collect()
self.listen_addrs_ipv6
.iter()
.map(|s| s.parse().unwrap())
.collect()
}
/// port on which to listen for connections on specified addresses
pub fn get_listen_port(&self) -> u16 {
@ -79,7 +95,8 @@ impl Config {
}
/// default timeout for all TCP connections before forceably shutdown
pub fn get_tcp_request_timeout(&self) -> Duration {
Duration::from_secs(self.tcp_request_timeout.unwrap_or(DEFAULT_TCP_REQUEST_TIMEOUT))
Duration::from_secs(self.tcp_request_timeout
.unwrap_or(DEFAULT_TCP_REQUEST_TIMEOUT))
}
// TODO: also support env_logger
@ -100,7 +117,9 @@ impl Config {
}
/// the path for all zone configurations, defaults to `/var/named`
pub fn get_directory(&self) -> &Path {
self.directory.as_ref().map_or(Path::new(DEFAULT_PATH), |s| Path::new(s))
self.directory
.as_ref()
.map_or(Path::new(DEFAULT_PATH), |s| Path::new(s))
}
/// the set of zones which should be loaded
pub fn get_zones(&self) -> &[ZoneConfig] {
@ -116,12 +135,14 @@ impl FromStr for Config {
type Err = ConfigError;
fn from_str(toml: &str) -> ConfigResult<Config> {
let value: Value = try!(toml.parse().map_err(|vec| ConfigErrorKind::VecParserError(vec)));
let value: Value = try!(toml.parse()
.map_err(|vec| ConfigErrorKind::VecParserError(vec)));
let mut decoder: Decoder = Decoder::new(value);
Ok(try!(Self::decode(&mut decoder)))
}
}
/// Configuration for a zone
#[derive(RustcDecodable, PartialEq, Debug)]
pub struct ZoneConfig {
zone: String, // TODO: make Domain::Name decodable
@ -133,6 +154,16 @@ pub struct ZoneConfig {
}
impl ZoneConfig {
/// Return a new zone configuration
///
/// # Arguments
///
/// * `zone` - name of a zone, e.g. example.com
/// * `zone_type` - Type of zone, e.g. Master
/// * `file` - relative to Config base path, to the zone file
/// * `allow_update` - enable dynamic updates
/// * `enable_dnssec` - enable signing of the zone for DNSSec
/// * `keys` - list of private and public keys used to sign a zone
pub fn new(zone: String,
zone_type: ZoneType,
file: String,
@ -185,6 +216,7 @@ impl ZoneConfig {
}
}
/// Key pair configuration for DNSSec keys for signing a zone
#[derive(RustcDecodable, PartialEq, Debug)]
pub struct KeyConfig {
key_path: String,
@ -197,6 +229,17 @@ pub struct KeyConfig {
}
impl KeyConfig {
/// Return a new KeyConfig
///
/// # Arguments
///
/// * `key_path` - file path to the key
/// * `password` - password to use to read the key
/// * `algorithm` - the type of key stored, see `Algorithm`
/// * `signer_name` - the name to use when signing records, e.g. ns.example.com
/// * `is_zone_signing_key` - specify that this key should be used for signing a zone
/// * `is_zone_update_auth` - specifies that this key can be used for dynamic updates in the zone
/// * `do_auto_generate` - if the key does not exist, generate a new one (it will need to be signed)
pub fn new(key_path: String,
password: Option<String>,
algorithm: Algorithm,
@ -217,16 +260,16 @@ impl KeyConfig {
}
/// path to the key file, either relative to the zone file, or a explicit from the root.
pub fn get_key_path(&self) -> &Path {
pub fn key_path(&self) -> &Path {
Path::new(&self.key_path)
}
/// Converts key into
pub fn get_format(&self) -> ParseResult<KeyFormat> {
let extension = try!(self.get_key_path()
pub fn format(&self) -> ParseResult<KeyFormat> {
let extension = try!(self.key_path()
.extension()
.ok_or(ParseErrorKind::Msg(format!("file lacks extension, e.g. '.p12': {:?}",
self.get_key_path())
self.key_path())
.into())));
match extension.to_str() {
@ -237,23 +280,24 @@ impl KeyConfig {
e @ _ => {
Err(ParseErrorKind::Msg(format!("extension not understood, '{:?}': {:?}",
e,
self.get_key_path()))
.into())
self.key_path()))
.into())
}
}
}
pub fn get_password(&self) -> Option<&str> {
/// Returns the password used to read the key
pub fn password(&self) -> Option<&str> {
self.password.as_ref().map(|s| s.as_str())
}
/// algorithm for for the key, see `Algorithm` for supported algorithms.
pub fn get_algorithm(&self) -> ParseResult<Algorithm> {
pub fn algorithm(&self) -> ParseResult<Algorithm> {
Algorithm::from_str(&self.algorithm).map_err(|e| e.into())
}
/// the signer name for the key, this defaults to the $ORIGIN aka zone name.
pub fn get_signer_name(&self) -> ParseResult<Option<Name>> {
pub fn signer_name(&self) -> ParseResult<Option<Name>> {
if let Some(ref signer_name) = self.signer_name.as_ref() {
let name = try!(Name::parse(signer_name, None));
return Ok(Some(name));

View File

@ -16,6 +16,9 @@
//! All defined errors for Trust-DNS
// TODO figure out how to doc error_chain!
#![allow(missing_docs)]
mod config_error;
mod persistence_error;

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#![deny(missing_docs)]
#![recursion_limit = "1024"]
//! Trust-DNS is intended to be a fully compliant domain name server and client library.

View File

@ -139,7 +139,7 @@ fn load_zone(zone_dir: &Path, zone_config: &ZoneConfig) -> Result<Authority, Str
.recover_with_journal(&journal)
.map_err(|e| format!("error recovering from journal: {}", e)));
authority.journal(journal);
authority.set_journal(journal);
info!("recovered zone: {}", zone_name);
authority
@ -169,7 +169,7 @@ fn load_zone(zone_dir: &Path, zone_config: &ZoneConfig) -> Result<Authority, Str
try!(Journal::from_file(&journal_path)
.map_err(|e| format!("error creating journal {:?}: {}", journal_path, e)));
authority.journal(journal);
authority.set_journal(journal);
// preserve to the new journal, i.e. we just loaded the zone from disk, start the journal
try!(authority
@ -199,11 +199,11 @@ fn load_zone(zone_dir: &Path, zone_config: &ZoneConfig) -> Result<Authority, Str
true);
let signer = try!(load_key(zone_name, &key_config).map_err(|e| {
format!("failed to load key: {:?} msg: {}",
key_config.get_key_path(),
key_config.key_path(),
e)
}));
info!("adding key to zone: {:?}, is_zsk: {}, is_auth: {}",
key_config.get_key_path(),
key_config.key_path(),
key_config.is_zone_signing_key(),
key_config.is_zone_update_auth());
authority
@ -213,11 +213,11 @@ fn load_zone(zone_dir: &Path, zone_config: &ZoneConfig) -> Result<Authority, Str
for key_config in zone_config.get_keys() {
let signer = try!(load_key(zone_name.clone(), &key_config).map_err(|e| {
format!("failed to load key: {:?} msg: {}",
key_config.get_key_path(),
key_config.key_path(),
e)
}));
info!("adding key to zone: {:?}, is_zsk: {}, is_auth: {}",
key_config.get_key_path(),
key_config.key_path(),
key_config.is_zone_signing_key(),
key_config.is_zone_update_auth());
authority
@ -245,12 +245,12 @@ fn load_zone(zone_dir: &Path, zone_config: &ZoneConfig) -> Result<Authority, Str
/// same directory has the zone $file:
/// keys = [ "my_rsa_2048|RSASHA256", "/path/to/my_ed25519|ED25519" ]
fn load_key(zone_name: Name, key_config: &KeyConfig) -> Result<Signer, String> {
let key_path = key_config.get_key_path();
let key_path = key_config.key_path();
let algorithm = try!(key_config
.get_algorithm()
.algorithm()
.map_err(|e| format!("bad algorithm: {}", e)));
let format = try!(key_config
.get_format()
.format()
.map_err(|e| format!("bad key format: {}", e)));
let key: KeyPair = if key_path.exists() {
@ -265,7 +265,7 @@ fn load_key(zone_name: Name, key_config: &KeyConfig) -> Result<Signer, String> {
.map_err(|e| format!("could not read key from: {:?}: {}", key_path, e)));
try!(format
.decode_key(&key_bytes, key_config.get_password(), algorithm)
.decode_key(&key_bytes, key_config.password(), algorithm)
.map_err(|e| format!("could not decode key: {}", e)))
} else if key_config.create_if_absent() {
info!("creating key: {:?}", key_path);
@ -279,7 +279,7 @@ fn load_key(zone_name: Name, key_config: &KeyConfig) -> Result<Signer, String> {
.map_err(|e| format!("could not generate key: {}", e)));
let key_bytes: Vec<u8> =
try!(format
.encode_key(&key, key_config.get_password())
.encode_key(&key, key_config.password())
.map_err(|e| format!("could not get key bytes: {}", e)));
try!(file.write_all(&key_bytes)
@ -294,7 +294,7 @@ fn load_key(zone_name: Name, key_config: &KeyConfig) -> Result<Signer, String> {
};
let name = try!(key_config
.get_signer_name()
.signer_name()
.map_err(|e| format!("error reading name: {}", e)))
.unwrap_or(zone_name);

View File

@ -7,8 +7,11 @@ use trust_dns::BufStreamHandle;
use trust_dns::op::Message;
use trust_dns::serialize::binary::{BinDecoder, BinEncoder, BinSerializable};
/// An incoming request to the DNS catalog
pub struct Request {
/// Message with the associated query or update data
pub message: Message,
/// Source address of the Client
pub src: SocketAddr,
}

View File

@ -26,6 +26,8 @@ use server::{Request, RequestStream, ResponseHandle, TimeoutStream};
use authority::Catalog;
// TODO, would be nice to have a Slab for buffers here...
/// A Futures based implementation of a DNS catalog server
pub struct ServerFuture {
io_loop: Core,
catalog: Arc<Catalog>, // should the catalog just be static?
@ -207,6 +209,7 @@ impl ServerFuture {
"Server stopping due to interruption"))
}
/// Returns a reference to the tokio core loop driving this Server instance
pub fn tokio_core(&mut self) -> &mut Core {
&mut self.io_loop
}

View File

@ -16,6 +16,13 @@ pub struct TimeoutStream<S> {
}
impl<S> TimeoutStream<S> {
/// Returns a new TimeoutStream
///
/// # Arguments
///
/// * `stream` - stream to wrap
/// * `timeout_duration` - timeout between each request, once exceed the connection is killed
/// * `reactor_handle` - reactor used for registering new timeouts
pub fn new(stream: S, timeout_duration: Duration, reactor_handle: Handle) -> io::Result<Self> {
// store a Timeout for this message before sending

View File

@ -23,7 +23,7 @@ use common::authority::{create_example, create_secure_example};
#[test]
fn test_search() {
let example = create_example();
let origin = example.get_origin().clone();
let origin = example.origin().clone();
let mut query: Query = Query::new();
query.set_name(origin.clone());
@ -63,21 +63,21 @@ fn test_search_www() {
fn test_authority() {
let authority: Authority = create_example();
assert!(authority.get_soa().is_some());
assert_eq!(authority.get_soa().unwrap().dns_class(), DNSClass::IN);
assert!(authority.soa().is_some());
assert_eq!(authority.soa().unwrap().dns_class(), DNSClass::IN);
assert!(!authority.lookup(authority.get_origin(),
assert!(!authority.lookup(authority.origin(),
RecordType::NS,
false,
SupportedAlgorithms::new())
.is_empty());
let mut lookup: Vec<_> = authority.get_ns(false, SupportedAlgorithms::new());
let mut lookup: Vec<_> = authority.ns(false, SupportedAlgorithms::new());
lookup.sort();
assert_eq!(**lookup.first().unwrap(),
Record::new()
.set_name(authority.get_origin().clone())
.set_name(authority.origin().clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
@ -85,20 +85,20 @@ fn test_authority() {
.clone());
assert_eq!(**lookup.last().unwrap(),
Record::new()
.set_name(authority.get_origin().clone())
.set_name(authority.origin().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()))
.clone());
assert!(!authority.lookup(authority.get_origin(),
assert!(!authority.lookup(authority.origin(),
RecordType::TXT,
false,
SupportedAlgorithms::new())
.is_empty());
let mut lookup: Vec<_> = authority.lookup(authority.get_origin(),
let mut lookup: Vec<_> = authority.lookup(authority.origin(),
RecordType::TXT,
false,
SupportedAlgorithms::new());
@ -106,7 +106,7 @@ fn test_authority() {
assert_eq!(**lookup.first().unwrap(),
Record::new()
.set_name(authority.get_origin().clone())
.set_name(authority.origin().clone())
.set_ttl(60)
.set_rr_type(RecordType::TXT)
.set_dns_class(DNSClass::IN)
@ -115,14 +115,14 @@ fn test_authority() {
.to_string()])))
.clone());
assert_eq!(**authority.lookup(authority.get_origin(),
assert_eq!(**authority.lookup(authority.origin(),
RecordType::A,
false,
SupportedAlgorithms::new())
.first()
.unwrap(),
Record::new()
.set_name(authority.get_origin().clone())
.set_name(authority.origin().clone())
.set_ttl(86400)
.set_rr_type(RecordType::A)
.set_dns_class(DNSClass::IN)
@ -172,7 +172,7 @@ fn test_prerequisites() {
// * ANY ANY empty Name is in use
assert!(authority.verify_prerequisites(&[Record::new()
.set_name(authority.get_origin().clone())
.set_name(authority.origin().clone())
.set_ttl(0)
.set_dns_class(DNSClass::ANY)
.set_rr_type(RecordType::ANY)
@ -190,7 +190,7 @@ fn test_prerequisites() {
// * ANY rrset empty RRset exists (value independent)
assert!(authority.verify_prerequisites(&[Record::new()
.set_name(authority.get_origin().clone())
.set_name(authority.origin().clone())
.set_ttl(0)
.set_dns_class(DNSClass::ANY)
.set_rr_type(RecordType::A)
@ -216,7 +216,7 @@ fn test_prerequisites() {
.clone()])
.is_ok());
assert_eq!(authority.verify_prerequisites(&[Record::new()
.set_name(authority.get_origin().clone())
.set_name(authority.origin().clone())
.set_ttl(0)
.set_dns_class(DNSClass::NONE)
.set_rr_type(RecordType::ANY)
@ -234,7 +234,7 @@ fn test_prerequisites() {
.clone()])
.is_ok());
assert_eq!(authority.verify_prerequisites(&[Record::new()
.set_name(authority.get_origin().clone())
.set_name(authority.origin().clone())
.set_ttl(0)
.set_dns_class(DNSClass::NONE)
.set_rr_type(RecordType::A)
@ -244,7 +244,7 @@ fn test_prerequisites() {
// * zone rrset rr RRset exists (value dependent)
assert!(authority.verify_prerequisites(&[Record::new()
.set_name(authority.get_origin().clone())
.set_name(authority.origin().clone())
.set_ttl(0)
.set_dns_class(DNSClass::IN)
.set_rr_type(RecordType::A)
@ -253,7 +253,7 @@ fn test_prerequisites() {
.is_ok());
// wrong class
assert_eq!(authority.verify_prerequisites(&[Record::new()
.set_name(authority.get_origin().clone())
.set_name(authority.origin().clone())
.set_ttl(0)
.set_dns_class(DNSClass::CH)
.set_rr_type(RecordType::A)
@ -277,7 +277,7 @@ fn test_prerequisites() {
Err(ResponseCode::NXRRSet));
// wrong IP
assert_eq!(authority.verify_prerequisites(&[Record::new()
.set_name(authority.get_origin().clone())
.set_name(authority.origin().clone())
.set_ttl(0)
.set_dns_class(DNSClass::IN)
.set_rr_type(RecordType::A)
@ -459,7 +459,7 @@ fn test_update() {
let new_name = Name::new().label("new").label("example").label("com");
let www_name = Name::new().label("www").label("example").label("com");
let mut authority: Authority = create_example();
let serial = authority.get_serial();
let serial = authority.serial();
authority.set_allow_update(true);
@ -527,7 +527,7 @@ fn test_update() {
false,
SupportedAlgorithms::new()),
add_record.iter().collect::<Vec<&Record>>());
assert_eq!(serial + 1, authority.get_serial());
assert_eq!(serial + 1, authority.serial());
let add_www_record = &[Record::new()
.set_name(www_name.clone())
@ -537,7 +537,7 @@ fn test_update() {
.set_rdata(RData::A(Ipv4Addr::new(10, 0, 0, 1)))
.clone()];
assert!(authority.update_records(add_www_record, true).expect("update failed"));
assert_eq!(serial + 2, authority.get_serial());
assert_eq!(serial + 2, authority.serial());
{
let mut www_rrset = authority.lookup(&www_name,
@ -562,7 +562,7 @@ fn test_update() {
.set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 24)))
.clone()];
assert!(authority.update_records(del_record, true).expect("update failed"));
assert_eq!(serial + 3, authority.get_serial());
assert_eq!(serial + 3, authority.serial());
{
println!("after delete of specific record: {:?}",
authority.lookup(&new_name,
@ -585,7 +585,7 @@ fn test_update() {
.set_rdata(RData::A(Ipv4Addr::new(10, 0, 0, 1)))
.clone()];
assert!(authority.update_records(del_record, true).expect("update failed"));
assert_eq!(serial + 4, authority.get_serial());
assert_eq!(serial + 4, authority.serial());
{
let mut www_rrset = authority.lookup(&www_name,
RecordType::ANY,
@ -606,7 +606,7 @@ fn test_update() {
.set_rdata(RData::NULL(NULL::new()))
.clone()];
assert!(authority.update_records(del_record, true).expect("update failed"));
assert_eq!(serial + 5, authority.get_serial());
assert_eq!(serial + 5, authority.serial());
let mut removed_a_vec: Vec<_> = vec![Record::new()
.set_name(www_name.clone())
.set_ttl(86400)
@ -657,14 +657,14 @@ fn test_update() {
false,
SupportedAlgorithms::new())
.is_empty());
assert_eq!(serial + 6, authority.get_serial());
assert_eq!(serial + 6, authority.serial());
}
#[test]
fn test_zone_signing() {
let authority: Authority = create_secure_example();
let results = authority.lookup(&authority.get_origin(),
let results = authority.lookup(&authority.origin(),
RecordType::AXFR,
true,
SupportedAlgorithms::all());
@ -714,7 +714,7 @@ fn test_journal() {
journal.schema_up().unwrap();
let mut authority = create_example();
authority.journal(journal);
authority.set_journal(journal);
authority.persist_to_journal().unwrap();
let new_name = Name::new().label("new").label("example").label("com");
@ -740,12 +740,12 @@ fn test_journal() {
assert!(delete_rrset.is_empty());
// that record should have been recorded... let's reload the journal and see if we get it.
let mut recovered_authority = Authority::new(authority.get_origin().clone(),
let mut recovered_authority = Authority::new(authority.origin().clone(),
BTreeMap::new(),
ZoneType::Master,
false,
false);
recovered_authority.recover_with_journal(authority.get_journal().expect("journal not Some"))
recovered_authority.recover_with_journal(authority.journal().expect("journal not Some"))
.expect("recovery");
// assert that the correct set of records is there.
@ -768,11 +768,11 @@ fn test_recovery() {
journal.schema_up().unwrap();
let mut authority = create_example();
authority.journal(journal);
authority.set_journal(journal);
authority.persist_to_journal().unwrap();
let journal = authority.get_journal().unwrap();
let mut recovered_authority = Authority::new(authority.get_origin().clone(),
let journal = authority.journal().unwrap();
let mut recovered_authority = Authority::new(authority.origin().clone(),
BTreeMap::new(),
ZoneType::Master,
false,
@ -780,20 +780,20 @@ fn test_recovery() {
recovered_authority.recover_with_journal(journal).expect("recovery");
assert_eq!(recovered_authority.get_records().len(),
authority.get_records().len());
assert_eq!(recovered_authority.get_soa(), authority.get_soa());
assert!(recovered_authority.get_records().iter().all(|(rr_key, rr_set)| {
assert_eq!(recovered_authority.records().len(),
authority.records().len());
assert_eq!(recovered_authority.soa(), authority.soa());
assert!(recovered_authority.records().iter().all(|(rr_key, rr_set)| {
let other_rr_set =
authority.get_records().get(rr_key).expect(&format!("key doesn't exist: {:?}", rr_key));
authority.records().get(rr_key).expect(&format!("key doesn't exist: {:?}", rr_key));
rr_set.iter().zip(other_rr_set.iter()).all(|(record, other_record)| {
record.ttl() == other_record.ttl() &&
record.rdata() == other_record.rdata()
})
}));
assert!(authority.get_records().iter().all(|(rr_key, rr_set)| {
let other_rr_set = recovered_authority.get_records()
assert!(authority.records().iter().all(|(rr_key, rr_set)| {
let other_rr_set = recovered_authority.records()
.get(rr_key)
.expect(&format!("key doesn't exist: {:?}", rr_key));
rr_set.iter().zip(other_rr_set.iter()).all(|(record, other_record)| {

View File

@ -114,8 +114,8 @@ pub fn create_test() -> Authority {
fn test_catalog_lookup() {
let example = create_example();
let test = create_test();
let origin = example.get_origin().clone();
let test_origin = test.get_origin().clone();
let origin = example.origin().clone();
let test_origin = test.origin().clone();
let mut catalog: Catalog = Catalog::new();
catalog.upsert(origin.clone(), example);
@ -173,7 +173,7 @@ fn test_catalog_lookup() {
#[test]
fn test_catalog_nx_soa() {
let example = create_example();
let origin = example.get_origin().clone();
let origin = example.origin().clone();
let mut catalog: Catalog = Catalog::new();
catalog.upsert(origin.clone(), example);
@ -207,7 +207,7 @@ fn test_catalog_nx_soa() {
#[test]
fn test_axfr() {
let test = create_test();
let origin = test.get_origin().clone();
let origin = test.origin().clone();
let soa = Record::new()
.set_name(origin.clone())
.set_ttl(3600)

View File

@ -39,7 +39,7 @@ use common::authority::create_example;
fn test_query_nonet() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
catalog.upsert(authority.origin().clone(), authority);
let mut io_loop = Core::new().unwrap();
let (stream, sender) = TestClientStream::new(catalog);
@ -149,7 +149,7 @@ fn test_query(client: &mut BasicClientHandle) -> Box<Future<Item = (), Error = (
fn test_notify() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
catalog.upsert(authority.origin().clone(), authority);
let mut io_loop = Core::new().unwrap();
let (stream, sender) = TestClientStream::new(catalog);
@ -175,7 +175,7 @@ fn test_notify() {
fn create_sig0_ready_client(io_loop: &Core) -> (BasicClientHandle, domain::Name) {
let mut authority = create_example();
authority.set_allow_update(true);
let origin = authority.get_origin().clone();
let origin = authority.origin().clone();
let rsa = Rsa::generate(512).unwrap();
let key = KeyPair::from_rsa(rsa).unwrap();
@ -206,7 +206,7 @@ fn create_sig0_ready_client(io_loop: &Core) -> (BasicClientHandle, domain::Name)
// setup the catalog
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
catalog.upsert(authority.origin().clone(), authority);
let (stream, sender) = TestClientStream::new(catalog);
let client = ClientFuture::new(stream, sender, io_loop.handle(), Some(signer));
@ -791,7 +791,7 @@ impl fmt::Debug for NeverReturnsClientStream {
fn test_timeout_query_nonet() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
catalog.upsert(authority.origin().clone(), authority);
let mut io_loop = Core::new().unwrap();
let (stream, sender) = NeverReturnsClientStream::new();

View File

@ -53,7 +53,7 @@ impl ClientConnection for TestClientConnection {
fn test_query_nonet() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
catalog.upsert(authority.origin().clone(), authority);
let client = SyncClient::new(TestClientConnection::new(catalog));
@ -120,7 +120,7 @@ fn test_secure_query_example_nonet() {
let authority = create_secure_example();
let trust_anchor = {
let signers = authority.get_secure_keys();
let signers = authority.secure_keys();
let public_key = signers.first().expect("expected a key in the authority").key();
let mut trust_anchor = TrustAnchor::new();
@ -130,7 +130,7 @@ fn test_secure_query_example_nonet() {
};
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
catalog.upsert(authority.origin().clone(), authority);
let client = SecureSyncClient::new(TestClientConnection::new(catalog))
.trust_anchor(trust_anchor)
@ -232,7 +232,7 @@ fn test_nsec_query_example_nonet() {
let authority = create_secure_example();
let trust_anchor = {
let signers = authority.get_secure_keys();
let signers = authority.secure_keys();
let public_key = signers.first().expect("expected a key in the authority").key();
let mut trust_anchor = TrustAnchor::new();
@ -242,7 +242,7 @@ fn test_nsec_query_example_nonet() {
};
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
catalog.upsert(authority.origin().clone(), authority);
let client = SecureSyncClient::new(TestClientConnection::new(catalog))
.trust_anchor(trust_anchor)
@ -344,7 +344,7 @@ fn test_nsec_query_type() {
fn create_sig0_ready_client(mut catalog: Catalog) -> (SyncClient, domain::Name) {
let mut authority = create_example();
authority.set_allow_update(true);
let origin = authority.get_origin().clone();
let origin = authority.origin().clone();
let rsa = Rsa::generate(512).unwrap();
let key = KeyPair::from_rsa(rsa).unwrap();
@ -373,7 +373,7 @@ fn create_sig0_ready_client(mut catalog: Catalog) -> (SyncClient, domain::Name)
.expect("to_vec failed"))));
authority.upsert(auth_key, 0);
catalog.upsert(authority.get_origin().clone(), authority);
catalog.upsert(authority.origin().clone(), authority);
let client = SyncClient::with_signer(TestClientConnection::new(catalog), signer);
(client, origin)

View File

@ -170,7 +170,7 @@ pub fn create_secure_example() -> Authority {
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
key,
authority.get_origin().clone(),
authority.origin().clone(),
Duration::weeks(1),
true,
true);

View File

@ -65,7 +65,7 @@ fn test_read_config() {
vec![]),
ZoneConfig::new("0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.\
ip6.arpa"
.into(),
.into(),
ZoneType::Master,
"default/ipv6_1.zone".into(),
None,
@ -100,7 +100,9 @@ fn test_parse_toml() {
assert_eq!(config.get_listen_addrs_ipv4(),
vec![Ipv4Addr::new(0, 0, 0, 0)]);
let config: Config = "listen_addrs_ipv4 = [\"0.0.0.0\", \"127.0.0.1\"]".parse().unwrap();
let config: Config = "listen_addrs_ipv4 = [\"0.0.0.0\", \"127.0.0.1\"]"
.parse()
.unwrap();
assert_eq!(config.get_listen_addrs_ipv4(),
vec![Ipv4Addr::new(0, 0, 0, 0), Ipv4Addr::new(127, 0, 0, 1)]);
@ -110,7 +112,8 @@ fn test_parse_toml() {
let config: Config = "listen_addrs_ipv6 = [\"::0\", \"::1\"]".parse().unwrap();
assert_eq!(config.get_listen_addrs_ipv6(),
vec![Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)]);
vec![Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0),
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)]);
let config: Config = "tcp_request_timeout = 25".parse().unwrap();
assert_eq!(config.get_tcp_request_timeout(), Duration::from_secs(25));
@ -124,8 +127,7 @@ fn test_parse_toml() {
#[test]
fn test_parse_zone_keys() {
let config: Config =
"
let config: Config = "
[[zones]]
zone = \"example.com\"
zone_type = \"Master\"
@ -151,11 +153,16 @@ signer_name = \"ns.example.com.\"
"
.parse()
.unwrap();
assert_eq!(config.get_zones()[0].get_keys()[0].get_key_path(),
assert_eq!(config.get_zones()[0].get_keys()[0].key_path(),
Path::new("/path/to/my_ed25519.pem"));
assert_eq!(config.get_zones()[0].get_keys()[0].get_algorithm().unwrap(),
assert_eq!(config.get_zones()[0].get_keys()[0]
.algorithm()
.unwrap(),
Algorithm::ED25519);
assert_eq!(config.get_zones()[0].get_keys()[0].get_signer_name().unwrap().unwrap(),
assert_eq!(config.get_zones()[0].get_keys()[0]
.signer_name()
.unwrap()
.unwrap(),
Name::parse("ns.example.com.", None).unwrap());
assert_eq!(config.get_zones()[0].get_keys()[0].is_zone_signing_key(),
false);
@ -163,11 +170,16 @@ signer_name = \"ns.example.com.\"
true);
assert_eq!(config.get_zones()[0].get_keys()[0].create_if_absent(), true);
assert_eq!(config.get_zones()[0].get_keys()[1].get_key_path(),
assert_eq!(config.get_zones()[0].get_keys()[1].key_path(),
Path::new("/path/to/my_rsa.pem"));
assert_eq!(config.get_zones()[0].get_keys()[1].get_algorithm().unwrap(),
assert_eq!(config.get_zones()[0].get_keys()[1]
.algorithm()
.unwrap(),
Algorithm::RSASHA256);
assert_eq!(config.get_zones()[0].get_keys()[1].get_signer_name().unwrap().unwrap(),
assert_eq!(config.get_zones()[0].get_keys()[1]
.signer_name()
.unwrap()
.unwrap(),
Name::parse("ns.example.com.", None).unwrap());
assert_eq!(config.get_zones()[0].get_keys()[1].is_zone_signing_key(),
false);
@ -190,8 +202,8 @@ tls_cert = { path = \"path/to/some.pkcs12\", create_if_absent = true, \
subject_name = \"ns.example.com\" }
tls_listen_port = 8853
"
.parse()
.unwrap();
.parse()
.unwrap();
assert_eq!(config.get_tls_listen_port(), 8853);
assert_eq!(config.get_tls_cert().unwrap().get_path(),

View File

@ -14,7 +14,7 @@ use trust_dns_server::authority::persistence::CURRENT_VERSION;
#[test]
fn test_new_journal() {
let conn = Connection::open_in_memory().expect("could not create in memory DB");
assert_eq!(Journal::new(conn).expect("new Journal").get_schema_version(),
assert_eq!(Journal::new(conn).expect("new Journal").schema_version(),
-1);
}
@ -24,7 +24,7 @@ fn test_init_journal() {
let mut journal = Journal::new(conn).unwrap();
let version = journal.schema_up().unwrap();
assert_eq!(version, CURRENT_VERSION);
assert_eq!(Journal::select_schema_version(journal.get_conn()).unwrap(),
assert_eq!(Journal::select_schema_version(journal.conn()).unwrap(),
CURRENT_VERSION);
}

View File

@ -202,7 +202,7 @@ fn with_nonet<F>(test: F)
let authority = create_secure_example();
let trust_anchor = {
let signers = authority.get_secure_keys();
let signers = authority.secure_keys();
let public_key = signers
.first()
.expect("expected a key in the authority")
@ -215,7 +215,7 @@ fn with_nonet<F>(test: F)
};
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
catalog.upsert(authority.origin().clone(), authority);
let io_loop = Core::new().unwrap();
let (stream, sender) = TestClientStream::new(catalog);

View File

@ -241,7 +241,7 @@ fn client_thread_www<C: ClientConnection>(conn: C)
fn new_catalog() -> Catalog {
let example = create_example();
let origin = example.get_origin().clone();
let origin = example.origin().clone();
let mut catalog: Catalog = Catalog::new();
catalog.upsert(origin.clone(), example);

View File

@ -63,7 +63,7 @@ venera A 10.1.0.52
// not validating everything, just one of each...
// SOA
let soa_record = authority.get_soa().unwrap();
let soa_record = authority.soa().unwrap();
assert_eq!(RecordType::SOA, soa_record.rr_type());
assert_eq!(&Name::new().label("isi").label("edu"),
soa_record.name()); // i.e. the origin or domain