Convert domain-tsig to new core.

This commit is contained in:
Martin Hoffmann
2019-12-11 12:31:22 +01:00
parent 0004f0625b
commit f90cdc49de
13 changed files with 585 additions and 366 deletions
-2
View File
@@ -1,5 +1,3 @@
[workspace]
members = ["domain", "domain-core", "domain-resolv", "domain-sign", "domain-tsig", "domain-validate", "interop"]
[patch.crates-io]
ring = { git = "https://github.com/andrewtj/ring.git", rev = "eedb0514fb73e1034eefbec10140af8a51effff3"}
+19 -13
View File
@@ -83,9 +83,9 @@ impl<Octets> Message<Octets> {
/// # Header Section
///
impl<Octets: AsRef<[u8]>> Message<Octets> {
/// Returns a reference to the message header.
pub fn header(&self) -> &Header {
Header::for_message_slice(self.as_slice())
/// Returns a the message header.
pub fn header(&self) -> Header {
*Header::for_message_slice(self.as_slice())
}
/// Returns a mutable reference to the message header.
@@ -94,18 +94,14 @@ impl<Octets: AsRef<[u8]>> Message<Octets> {
Header::for_message_slice_mut(self.as_slice_mut())
}
/// Returns a reference the header counts of the message.
pub fn header_counts(&self) -> &HeaderCounts {
HeaderCounts::for_message_slice(self.as_slice())
/// Returns the header counts of the message.
pub fn header_counts(&self) -> HeaderCounts {
*HeaderCounts::for_message_slice(self.as_slice())
}
/// Returns a mutable reference to the header counts.
///
/// Since you can quite effectively break the message with this, it is
/// private.
pub fn header_counts_mut(&mut self) -> &mut HeaderCounts
where Octets: AsMut<[u8]> {
HeaderCounts::for_message_slice_mut(self.as_slice_mut())
/// Returns the entire header section.
pub fn header_section(&self) -> HeaderSection {
*HeaderSection::for_message_slice(&self.as_slice())
}
/// Returns whether the rcode is NoError.
@@ -424,6 +420,11 @@ impl<Ref: OctetsRef> QuestionSection<Ref> {
}
}
/// Returns the current position relative to the beginning of the message.
pub fn pos(&self) -> usize {
self.parser.pos()
}
/// Proceeds to the answer section.
///
/// Skips over any remaining questions and then converts itself into the
@@ -556,6 +557,11 @@ impl<Ref: OctetsRef> RecordSection<Ref> {
}
}
/// Returns the current position relative to the beginning of the message.
pub fn pos(&self) -> usize {
self.parser.pos()
}
/// Trades `self` in for an iterator limited to a concrete record type.
///
/// The record type is given through its record data type. Since the data
+53 -8
View File
@@ -8,10 +8,12 @@ use core::ops::{Deref, DerefMut};
#[cfg(feature = "bytes")] use bytes::BytesMut;
use unwrap::unwrap;
use crate::header::{Header, HeaderCounts, HeaderSection};
use crate::iana::{OptionCode, OptRcode};
use crate::iana::{OptionCode, OptRcode, Rcode, Rtype};
use crate::message::Message;
use crate::name::{ToDname, Label};
use crate::octets::{Compose, IntoOctets, Octets64, OctetsBuilder, ShortBuf};
use crate::octets::{
Compose, IntoOctets, Octets64, OctetsBuilder, OctetsRef, ShortBuf
};
use crate::opt::{OptHeader, OptData};
use crate::question::Question;
use crate::rdata::RecordData;
@@ -68,6 +70,45 @@ impl MessageBuilder<StreamTarget<BytesMut>> {
}
impl<Target: OctetsBuilder> MessageBuilder<Target> {
/// Starts creating an answer for the given message.
///
/// Specifically, this sets the ID, QR, OPCODE, RD, and RCODE fields
/// in the header and attempts to push the message’s questions to the
/// builder. If iterating of the questions fails, it adds what it can.
pub fn start_answer<Octets>(
mut self,
msg: &Message<Octets>,
rcode: Rcode,
) -> Result<AnswerBuilder<Target>, ShortBuf>
where Octets: AsRef<[u8]>, for<'a> &'a Octets: OctetsRef {
{
let header = self.header_mut();
header.set_id(msg.header().id());
header.set_qr(true);
header.set_opcode(msg.header().opcode());
header.set_rd(msg.header().rd());
header.set_rcode(rcode);
}
let mut builder = self.question();
for item in msg.question() {
if let Ok(item) = item {
builder.push(item)?;
}
}
Ok(builder.answer())
}
/// Creates an AXFR request for the given domain.
pub fn request_axfr<N: ToDname>(
mut self,
apex: N
) -> Result<AnswerBuilder<Target>, ShortBuf> {
self.header_mut().set_random_id();
let mut builder = self.question();
builder.push((apex, Rtype::Axfr))?;
Ok(builder.answer())
}
pub fn question(self) -> QuestionBuilder<Target> {
QuestionBuilder::new(self)
}
@@ -96,6 +137,10 @@ impl<Target: OctetsBuilder> MessageBuilder<Target> {
&mut self.target
}
pub fn as_slice(&self) -> &[u8] {
self.as_target().as_ref()
}
pub fn as_message(&self) -> Message<&[u8]>
where Target: AsRef<[u8]> {
unsafe { Message::from_octets_unchecked(self.target.as_ref()) }
@@ -106,16 +151,16 @@ impl<Target: OctetsBuilder> MessageBuilder<Target> {
unsafe { Message::from_octets_unchecked(self.target.into_octets()) }
}
pub fn header(&self) -> &Header {
Header::for_message_slice(self.target.as_ref())
pub fn header(&self) -> Header {
*Header::for_message_slice(self.target.as_ref())
}
pub fn header_mut(&mut self) -> &mut Header {
Header::for_message_slice_mut(self.target.as_mut())
}
pub fn counts(&self) -> &HeaderCounts {
HeaderCounts::for_message_slice(self.target.as_ref())
pub fn counts(&self) -> HeaderCounts {
*HeaderCounts::for_message_slice(self.target.as_ref())
}
fn counts_mut(&mut self) -> &mut HeaderCounts {
@@ -508,7 +553,7 @@ where Target: OctetsBuilder {
fn push<N, D, R>(&mut self, record: R) -> Result<(), ShortBuf>
where N: ToDname, D: RecordData, R: Into<Record<N, D>> {
record.into().compose(self.as_target_mut())?;
self.counts_mut().inc_ancount();
self.counts_mut().inc_arcount();
Ok(())
}
}
@@ -592,7 +637,7 @@ impl<Target: OctetsBuilder> OptBuilder<Target> {
}
pub fn rcode(&self) -> OptRcode {
self.opt_header().rcode(*self.header())
self.opt_header().rcode(self.header())
}
pub fn set_rcode(&mut self, rcode: OptRcode) {
+3
View File
@@ -676,6 +676,9 @@ octets_array!(pub Octets2048 => 2048);
octets_array!(pub Octets4096 => 4096);
#[cfg(feature = "smallvec")]
pub type OctetsVec = SmallVec<[u8; 24]>;
//------------ ShortBuf ------------------------------------------------------
/// An attempt was made to go beyond the end of a buffer.
-1
View File
@@ -157,7 +157,6 @@ impl<O, N> Tsig<O, N> {
///
/// [`fudge`]: #method.fudge
/// [`time_signed`]: #method.time_signed
#[cfg(feature = "chrono")]
pub fn is_valid_now(&self) -> bool {
Time48::now().eq_fudged(self.time_signed, self.fudge.into())
}
+2 -4
View File
@@ -6,7 +6,7 @@
//! [`Serial`]: struct.Serial.html
use core::{cmp, fmt, str};
#[cfg(feature = "bytes")] use chrono::{Utc, TimeZone};
use chrono::{DateTime, Utc, TimeZone};
use crate::cmp::CanonicalOrd;
#[cfg(feature = "bytes")] use crate::master::scan::{
CharSource, Scan, ScanError, Scanner, SyntaxError
@@ -42,7 +42,6 @@ pub struct Serial(pub u32);
impl Serial {
/// Returns a serial number for the current Unix time.
#[cfg(feature = "chrono")]
pub fn now() -> Self {
Utc::now().into()
}
@@ -88,7 +87,7 @@ impl Serial {
/// In RRSIG records, the expiration and inception time is given as
/// serial values. Their master file format can either be the signature
/// value or a specific date in `YYYYMMDDHHmmSS` format.
#[cfg(all(feature="bytes"))]
#[cfg(feature="bytes")]
pub fn scan_rrsig<C: CharSource>(
scanner: &mut Scanner<C>
) -> Result<Self, ScanError> {
@@ -182,7 +181,6 @@ impl From<Serial> for u32 {
}
}
#[cfg(feature = "chrono")]
impl<T: TimeZone> From<DateTime<T>> for Serial {
fn from(value: DateTime<T>) -> Self {
let mut value = value.timestamp();
+3 -3
View File
@@ -19,13 +19,13 @@ path = "src/lib.rs"
bytes = "0.4"
derive_more = "^0.15"
openssl = { version = "^0.10", optional = true }
ring = { version = "0.15.0-alpha", optional = true }
ring = { version = "0.16", optional = true }
unwrap = "^1.2"
[dependencies.domain-core]
path = "../domain-core"
version = "0.4.1"
version = "0.5.0-pre"
[features]
ringsigner = ["ring"]
default = ["ringsigner"]
default = ["ringsigner"]
+6 -3
View File
@@ -17,10 +17,13 @@ path = "src/lib.rs"
[dependencies]
bytes = "^0.4"
derive_more = "^0.14"
ring = "0.15.0-alpha"
derive_more = "^0.99"
ring = "0.16"
smallvec = "1.0"
unwrap = "1.2"
[dependencies.domain-core]
path = "../domain-core"
version = "0.4.1"
version = "0.5.0-pre"
features = ["std", "smallvec"]
+390 -256
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -18,8 +18,8 @@ path = "src/lib.rs"
[dependencies]
bytes = "0.4"
derive_more = "^0.15"
ring = "=0.15.0-alpha3"
ring = "0.16"
[dependencies.domain-core]
path = "../domain-core"
version = "0.4.1"
version = "0.5.0-pre"
+3 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "domain"
version = "0.4.1"
version = "0.5.0-pre"
edition = "2018"
authors = ["Martin Hoffmann <martin@nlnetlabs.nl>"]
description = "A DNS library for Rust – Meta Crate."
@@ -19,11 +19,11 @@ validate = ["domain-validate"]
[dependencies.domain-core]
path = "../domain-core"
version = "0.4.1"
version = "0.5.0-pre"
[dependencies.domain-resolv]
path = "../domain-resolv"
version = "0.4.1"
version = "0.5.0-pre"
optional = true
[dependencies.domain-sign]
+2 -1
View File
@@ -11,5 +11,6 @@ domain-core = { path = "../domain-core" }
domain-resolv = { path = "../domain-resolv" }
domain-tsig = { path = "../domain-tsig" }
bytes = "0.4"
ring = "0.15.0-alpha"
ring = "0.16"
unwrap = "1.2"
+102 -70
View File
@@ -1,6 +1,4 @@
//! Tests the TSIG implementation.
extern crate interop;
extern crate ring;
use std::{env, fs, io, thread};
use std::io::{Read, Write};
@@ -9,16 +7,24 @@ use std::process::Command;
use std::str::FromStr;
use std::time::Duration;
use ring::rand::SystemRandom;
use unwrap::unwrap;
use interop::nsd;
use interop::domain::core::{Dname, Message, MessageBuilder, Record};
use interop::domain::core::message::Message;
use interop::domain::core::message_builder::{
AdditionalBuilder, RecordSectionBuilder, SectionBuilder
AdditionalBuilder, AnswerBuilder, MessageBuilder, RecordSectionBuilder,
StreamTarget,
};
use interop::domain::core::name::Dname;
use interop::domain::core::iana::{Rcode, Rtype};
use interop::domain::core::rdata::{A, Soa};
use interop::domain::core::utils::base64;
use interop::domain::tsig;
type TestMessage = Message<Vec<u8>>;
type TestBuilder = MessageBuilder<StreamTarget<Vec<u8>>>;
type TestAnswer = AnswerBuilder<StreamTarget<Vec<u8>>>;
type TestAdditional = AdditionalBuilder<StreamTarget<Vec<u8>>>;
//------------ Tests --------------------------------------------------------
@@ -66,21 +72,27 @@ fn tsig_client_nsd() {
let res = thread::spawn(move || {
// Create an AXFR request and send it to NSD.
let request = MessageBuilder::request_axfr(
Dname::from_str("example.com.").unwrap()
).additional();
let (msg, tran) = tsig::ClientTransaction::request(&key, request)
.unwrap();
let request = TestBuilder::new_stream_vec();
let mut request = unwrap!(request.request_axfr(
unwrap!(Dname::<Vec<u8>>::from_str("example.com."))
)).additional();
let tran = unwrap!(
tsig::ClientTransaction::request(&key, &mut request)
);
let sock = UdpSocket::bind("127.0.0.1:54320").unwrap();
sock.send_to(msg.as_ref(), "127.0.0.1:54321").unwrap();
unwrap!(sock.send_to(
request.as_target().as_dgram_slice(),
"127.0.0.1:54321"
));
let mut answer = loop {
let mut buf = vec![0; 512];
let (len, addr) = sock.recv_from(buf.as_mut()).unwrap();
if addr != SocketAddr::from_str("127.0.0.1:54321").unwrap() {
continue;
}
let answer = Message::from_bytes(buf[..len].into()).unwrap();
if answer.header().id() == msg.header().id() {
buf.truncate(len);
let answer = Message::from_octets(buf).unwrap();
if answer.header().id() == request.header().id() {
break answer;
}
};
@@ -91,7 +103,7 @@ fn tsig_client_nsd() {
// Shut down NSD just to be sure.
let _ = nsd.kill();
res.unwrap(); // Panic if the thread paniced.
unwrap!(res); // Panic if the thread paniced.
}
/// Tests the TSIG server implementation against drill as a client.
@@ -113,25 +125,34 @@ fn tsig_server_drill() {
loop {
let mut buf = vec![0; 512];
let (len, addr) = sock.recv_from(buf.as_mut()).unwrap();
let mut request = match Message::from_bytes(buf[..len].into()) {
buf.truncate(len);
let mut request = match Message::from_octets(buf) {
Ok(request) => request,
Err(_) => continue,
};
let mut answer = MessageBuilder::new_udp();
answer.start_answer(&request, Rcode::NoError);
let tran = match tsig::ServerTransaction::request(&&key,
&mut request) {
let answer = TestBuilder::new_stream_vec();
let answer = unwrap!(
answer.start_answer(&request, Rcode::NoError)
);
let tran = match tsig::ServerTransaction::request(
&&key, &mut request
) {
Ok(Some(tran)) => tran,
Ok(None) => {
sock.send_to(answer.freeze().as_slice(), addr).unwrap();
sock.send_to(answer.as_slice(), addr).unwrap();
continue;
}
Err(error) => {
sock.send_to(error.as_slice(), addr).unwrap();
let answer = unwrap!(error.build_message(
&request,
TestBuilder::new_stream_vec()
));
sock.send_to(answer.as_slice(), addr).unwrap();
continue;
}
};
let answer = tran.answer(answer.additional()).unwrap();
let mut answer = answer.additional();
unwrap!(tran.answer(&mut answer));
sock.send_to(answer.as_slice(), addr).unwrap();
}
});
@@ -187,14 +208,15 @@ fn tsig_client_sequence_nsd() {
}
let res = thread::spawn(move || {
let mut sock = TcpStream::connect("127.0.0.1:54323").unwrap();
let request = MessageBuilder::request_axfr(
Dname::from_str("example.com.").unwrap()
).additional();
let (msg, mut tran) = tsig::ClientSequence::request(&key, request)
.unwrap();
sock.write_all(&(msg.len() as u16).to_be_bytes()).unwrap();
sock.write_all(msg.as_slice()).unwrap();
let mut sock = unwrap!(TcpStream::connect("127.0.0.1:54323"));
let request = TestBuilder::new_stream_vec();
let mut request = unwrap!(request.request_axfr(
unwrap!(Dname::<Vec<u8>>::from_str("example.com."))
)).additional();
let mut tran = unwrap!(
tsig::ClientSequence::request(&key, &mut request)
);
unwrap!(sock.write_all(request.as_target().as_stream_slice()));
loop {
let mut len = [0u8; 2];
sock.read_exact(&mut len).unwrap();
@@ -202,8 +224,8 @@ fn tsig_client_sequence_nsd() {
assert!(len != 0);
let mut buf = vec![0; len];
sock.read_exact(&mut buf).unwrap();
let mut answer = Message::from_bytes(buf.into()).unwrap();
tran.answer(&mut answer).unwrap();
let mut answer = unwrap!(Message::from_octets(buf));
unwrap!(tran.answer(&mut answer));
// Last message has SOA as last record in answer section.
// We don’t care about details.
if answer.answer().unwrap().last().unwrap().unwrap().rtype()
@@ -211,7 +233,7 @@ fn tsig_client_sequence_nsd() {
break
}
}
tran.done().unwrap()
unwrap!(tran.done())
}).join();
// Shut down NSD just to be sure.
@@ -243,25 +265,30 @@ fn tsig_server_sequence_drill() {
let len = u16::from_be_bytes(buf) as usize;
let mut buf = vec![0; len];
sock.read_exact(&mut buf).unwrap();
let mut request = Message::from_bytes(buf.into()).unwrap();
let mut request = Message::from_octets(buf).unwrap();
let mut tran = tsig::ServerSequence::request(&&key, &mut request)
.unwrap().unwrap();
let mut answer = make_first_axfr(&request);
unwrap!(tran.answer(&mut answer));
send_tcp(
&mut sock,
tran.answer(make_first_axfr(&request)).unwrap().as_ref()
answer.as_target().as_stream_slice()
).unwrap();
for two in 0..10u8 {
for one in 0..10u8 {
let mut answer = make_middle_axfr(&request, one, two);
unwrap!(tran.answer(&mut answer));
send_tcp(
&mut sock,
tran.answer(make_middle_axfr(&request, one, two))
.unwrap().as_ref()
answer.as_target().as_stream_slice()
).unwrap();
}
}
let mut answer = make_last_axfr(&request);
unwrap!(tran.answer(&mut answer));
send_tcp(
&mut sock,
tran.answer(make_last_axfr(&request)).unwrap().as_ref()
answer.as_target().as_stream_slice()
).unwrap();
}
});
@@ -286,50 +313,55 @@ fn send_tcp(sock: &mut TcpStream, msg: &[u8]) -> Result<(), io::Error> {
sock.write_all(msg)
}
fn make_first_axfr(request: &Message) -> AdditionalBuilder {
let mut msg = MessageBuilder::new_tcp(1024);
msg.start_answer(request, Rcode::NoError);
let mut msg = msg.answer();
msg.push(make_soa()).unwrap();
msg.push(make_a(0, 0, 0)).unwrap();
fn make_first_axfr(request: &TestMessage) -> TestAdditional {
let msg = TestBuilder::new_stream_vec();
let mut msg = unwrap!(msg.start_answer(request, Rcode::NoError));
push_soa(&mut msg);
push_a(&mut msg, 0, 0, 0);
msg.additional()
}
fn make_middle_axfr(request: &Message, one: u8, two: u8) -> AdditionalBuilder {
let mut msg = MessageBuilder::new_tcp(1024);
msg.start_answer(request, Rcode::NoError);
let mut msg = msg.answer();
msg.push(make_a(1, one, two)).unwrap();
fn make_middle_axfr(
request: &TestMessage,
one: u8,
two: u8
) -> TestAdditional {
let msg = TestBuilder::new_stream_vec();
let mut msg = unwrap!(msg.start_answer(request, Rcode::NoError));
push_a(&mut msg, 1, one, two);
msg.additional()
}
fn make_last_axfr(request: &Message) -> AdditionalBuilder {
let mut msg = MessageBuilder::new_tcp(1024);
msg.start_answer(request, Rcode::NoError);
let mut msg = msg.answer();
msg.push(make_a(2, 0, 0)).unwrap();
msg.push(make_soa()).unwrap();
fn make_last_axfr(request: &TestMessage) -> TestAdditional {
let msg = TestBuilder::new_stream_vec();
let mut msg = unwrap!(msg.start_answer(request, Rcode::NoError));
push_a(&mut msg, 2, 0, 0);
push_soa(&mut msg);
msg.additional()
}
fn make_soa() -> Record<Dname, Soa<Dname>> {
(
Dname::from_str("example.com.").unwrap(),
3600,
Soa::new(
Dname::from_str("mname.example.com.").unwrap(),
Dname::from_str("rname.example.com.").unwrap(),
12.into(),
3600, 3600, 3600, 3600
fn push_soa(builder: &mut TestAnswer) {
unwrap!(builder.push(
(
Dname::<Vec<u8>>::from_str("example.com.").unwrap(),
3600,
Soa::new(
Dname::<Vec<u8>>::from_str("mname.example.com.").unwrap(),
Dname::<Vec<u8>>::from_str("rname.example.com.").unwrap(),
12.into(),
3600, 3600, 3600, 3600
)
)
).into()
))
}
fn make_a(zero: u8, one: u8, two: u8) -> Record<Dname, A> {
(
Dname::from_str("example.com.").unwrap(),
3600,
A::from_octets(10, zero, one, two)
).into()
fn push_a(builder: &mut TestAnswer, zero: u8, one: u8, two: u8) {
unwrap!(builder.push(
(
Dname::<Vec<u8>>::from_str("example.com.").unwrap(),
3600,
A::from_octets(10, zero, one, two)
)
))
}