2019-07-01 15:43:34 +00:00
|
|
|
use crate::common_types::classes;
|
|
|
|
use crate::records::structs;
|
|
|
|
use crate::ser::packet::DnsPacketData;
|
2020-03-07 15:57:47 +00:00
|
|
|
use crate::ser::{packet, text, StaticRRData};
|
|
|
|
use bytes::{Buf, Bytes};
|
|
|
|
use failure::ResultExt;
|
2017-12-21 12:32:14 +00:00
|
|
|
use std::fmt;
|
|
|
|
use std::io::Cursor;
|
2017-12-16 20:58:18 +00:00
|
|
|
|
2019-07-01 15:43:34 +00:00
|
|
|
fn rrdata_de<T>(data: &'static [u8]) -> crate::errors::Result<T>
|
2017-12-16 20:58:18 +00:00
|
|
|
where
|
2020-03-07 15:57:47 +00:00
|
|
|
T: StaticRRData,
|
2017-12-16 20:58:18 +00:00
|
|
|
{
|
2017-12-21 12:32:14 +00:00
|
|
|
let mut data = Cursor::new(Bytes::from_static(data));
|
2017-12-26 16:30:08 +00:00
|
|
|
let result = T::deserialize_rr_data(3600, classes::IN, T::TYPE, &mut data)?;
|
2019-07-01 15:43:34 +00:00
|
|
|
failure::ensure!(!data.has_remaining(), "rrdata not read completely");
|
2017-12-21 12:32:14 +00:00
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
|
2019-07-01 15:43:34 +00:00
|
|
|
fn rrdata_parse<T>(data: &str) -> crate::errors::Result<T>
|
2017-12-26 21:23:47 +00:00
|
|
|
where
|
2020-03-07 15:57:47 +00:00
|
|
|
T: StaticRRData,
|
2017-12-26 21:23:47 +00:00
|
|
|
{
|
2017-12-26 21:23:51 +00:00
|
|
|
let mut ctx = text::DnsTextContext::new();
|
|
|
|
ctx.set_zone_class(classes::IN);
|
|
|
|
ctx.set_record_type(T::TYPE);
|
|
|
|
ctx.set_last_ttl(3600);
|
2020-03-07 15:57:47 +00:00
|
|
|
text::parse_with(data, |data| T::dns_parse_rr_data(&ctx, data))
|
2017-12-26 21:23:47 +00:00
|
|
|
}
|
|
|
|
|
2019-07-01 15:43:34 +00:00
|
|
|
fn check<T>(txt: &str, data: &'static [u8]) -> crate::errors::Result<()>
|
2017-12-21 12:32:14 +00:00
|
|
|
where
|
2020-03-07 15:57:47 +00:00
|
|
|
T: StaticRRData + fmt::Debug + PartialEq,
|
2017-12-21 12:32:14 +00:00
|
|
|
{
|
|
|
|
let d1: T = rrdata_de(data).context("couldn't parse binary record")?;
|
2017-12-26 21:23:47 +00:00
|
|
|
let d2: T = rrdata_parse(txt).context("couldn't parse text record")?;
|
2019-07-01 15:43:34 +00:00
|
|
|
failure::ensure!(d1 == d2, "decoded data not equal: {:?} != {:?}", d1, d2);
|
2017-12-21 12:32:14 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-07-01 15:43:34 +00:00
|
|
|
fn check2<T>(txt: &str, data: &'static [u8], canon: &str) -> crate::errors::Result<()>
|
2017-12-21 12:32:14 +00:00
|
|
|
where
|
2020-03-07 15:57:47 +00:00
|
|
|
T: StaticRRData + fmt::Debug + PartialEq,
|
2017-12-21 12:32:14 +00:00
|
|
|
{
|
|
|
|
let d1: T = rrdata_de(data).context("couldn't parse binary record")?;
|
2017-12-26 21:23:47 +00:00
|
|
|
let d2: T = rrdata_parse(txt).context("couldn't parse text record")?;
|
2019-07-01 15:43:34 +00:00
|
|
|
failure::ensure!(d1 == d2, "decoded data not equal: {:?} != {:?}", d1, d2);
|
2017-12-26 21:23:47 +00:00
|
|
|
|
2017-12-29 21:25:43 +00:00
|
|
|
let d1_text = d1.text().unwrap();
|
|
|
|
let d2_text = d2.text().unwrap();
|
|
|
|
let canon_text = (T::NAME.to_owned(), canon.into());
|
|
|
|
|
2020-03-07 15:57:47 +00:00
|
|
|
failure::ensure!(
|
|
|
|
d1_text == canon_text,
|
|
|
|
"re-formatted binary record not equal to canonical representation: {:?} != {:?}",
|
|
|
|
d1_text,
|
|
|
|
canon_text
|
|
|
|
);
|
|
|
|
failure::ensure!(
|
|
|
|
d2_text == canon_text,
|
|
|
|
"re-formatted text record not equal to canonical representation: {:?} != {:?}",
|
|
|
|
d2_text,
|
|
|
|
canon_text
|
|
|
|
);
|
2017-12-29 21:25:43 +00:00
|
|
|
|
2017-12-21 12:32:14 +00:00
|
|
|
Ok(())
|
2017-12-16 20:58:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_a() {
|
2017-12-21 12:32:14 +00:00
|
|
|
check::<structs::A>("127.0.0.1", b"\x7f\x00\x00\x01").unwrap();
|
|
|
|
}
|
|
|
|
|
2017-12-27 11:41:54 +00:00
|
|
|
#[test]
|
|
|
|
fn test_mx() {
|
|
|
|
check::<structs::MX>("10 mx.rec.test.", b"\x00\x0a\x02mx\x03rec\x04test\x00").unwrap();
|
|
|
|
}
|
|
|
|
|
2017-12-21 12:32:14 +00:00
|
|
|
fn test_txt_for<T>()
|
|
|
|
where
|
2020-03-07 15:57:47 +00:00
|
|
|
T: StaticRRData + fmt::Debug + PartialEq,
|
2017-12-21 12:32:14 +00:00
|
|
|
{
|
|
|
|
// at least one "segment" (which could be empty)
|
2017-12-29 21:25:43 +00:00
|
|
|
check2::<T>(r#" "" "#, b"", r#""""#).unwrap_err();
|
|
|
|
check2::<T>(r#""#, b"\x00", r#""""#).unwrap_err();
|
2017-12-21 12:32:14 +00:00
|
|
|
// one empty segment
|
2017-12-29 21:25:43 +00:00
|
|
|
check2::<T>(r#" "" "#, b"\x00", r#""""#).unwrap();
|
2017-12-21 12:32:14 +00:00
|
|
|
// one segment
|
|
|
|
check::<T>(r#" "foo" "#, b"\x03foo").unwrap();
|
|
|
|
// two segments
|
|
|
|
check::<T>(r#" "foo" "bar!" "#, b"\x03foo\x04bar!").unwrap();
|
|
|
|
// segment with too many bytes in text form
|
|
|
|
{
|
|
|
|
let mut s = String::new();
|
|
|
|
s.push('"');
|
2020-03-07 15:57:47 +00:00
|
|
|
for _ in 0..256 {
|
|
|
|
s.push('a');
|
|
|
|
}
|
2017-12-21 12:32:14 +00:00
|
|
|
s.push('"');
|
2017-12-26 21:23:47 +00:00
|
|
|
rrdata_parse::<T>(&s).unwrap_err();
|
2017-12-21 12:32:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_txt() {
|
|
|
|
test_txt_for::<structs::TXT>();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ds() {
|
|
|
|
check::<structs::DS>(" 1 2 3 ", b"\x00\x01\x02\x03").unwrap();
|
|
|
|
check::<structs::DS>(" 1 2 3 abcd", b"\x00\x01\x02\x03\xab\xcd").unwrap();
|
|
|
|
check::<structs::DS>(" 1 2 3 a b c d", b"\x00\x01\x02\x03\xab\xcd").unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_nsec() {
|
|
|
|
check::<structs::NSEC>("foo.bar. ", b"\x03foo\x03bar\x00").unwrap();
|
|
|
|
check::<structs::NSEC>("foo.bar. A NS ", b"\x03foo\x03bar\x00\x00\x01\x60").unwrap();
|
2020-03-07 15:57:47 +00:00
|
|
|
check::<structs::NSEC>(
|
|
|
|
"foo.bar. A NS SOA MX AAAA RRSIG NSEC DNSKEY ",
|
|
|
|
b"\x03foo\x03bar\x00\x00\x07\x62\x01\x00\x08\x00\x03\x80",
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
check::<structs::NSEC>(
|
|
|
|
"foo.bar. A NS TYPE256 TYPE65280 ",
|
|
|
|
b"\x03foo\x03bar\x00\x00\x01\x60\x01\x01\x80\xff\x01\x80",
|
|
|
|
)
|
|
|
|
.unwrap();
|
2017-12-21 12:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_dnskey() {
|
|
|
|
check::<structs::DNSKEY>("256 2 3", b"\x01\x00\x02\x03").unwrap();
|
|
|
|
check::<structs::DNSKEY>("256 2 3 /w==", b"\x01\x00\x02\x03\xff").unwrap();
|
|
|
|
check::<structs::DNSKEY>("256 2 3 /w ==", b"\x01\x00\x02\x03\xff").unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_nsec3() {
|
|
|
|
check::<structs::NSEC3>("1 2 300 - vs", b"\x01\x02\x01\x2c\x00\x01\xff").unwrap();
|
2020-03-07 15:57:47 +00:00
|
|
|
check::<structs::NSEC3>(
|
|
|
|
"1 2 300 - vs A NS",
|
|
|
|
b"\x01\x02\x01\x2c\x00\x01\xff\x00\x01\x60",
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
check::<structs::NSEC3>(
|
|
|
|
"1 2 300 ab vs A NS",
|
|
|
|
b"\x01\x02\x01\x2c\x01\xab\x01\xff\x00\x01\x60",
|
|
|
|
)
|
|
|
|
.unwrap();
|
2017-12-21 12:32:14 +00:00
|
|
|
|
|
|
|
// invalid base32 texts
|
2017-12-26 21:23:51 +00:00
|
|
|
rrdata_parse::<structs::NSEC3>("1 2 300 - v").unwrap_err();
|
|
|
|
rrdata_parse::<structs::NSEC3>("1 2 300 - vv").unwrap_err();
|
2017-12-21 12:32:14 +00:00
|
|
|
|
|
|
|
// invalid (empty) next-hashed values
|
2020-03-07 15:57:47 +00:00
|
|
|
packet::deserialize_with(
|
|
|
|
Bytes::from_static(b"\x01\x02\x01\x2c\x00\x00"),
|
|
|
|
structs::NSEC3::deserialize,
|
|
|
|
)
|
|
|
|
.unwrap_err();
|
2017-12-21 12:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_nsec3param() {
|
|
|
|
check::<structs::NSEC3PARAM>("1 2 300 -", b"\x01\x02\x01\x2c\x00").unwrap();
|
|
|
|
check::<structs::NSEC3PARAM>("1 2 300 ab", b"\x01\x02\x01\x2c\x01\xab").unwrap();
|
|
|
|
// `salt` hex string must not contain spaces
|
2017-12-26 21:23:51 +00:00
|
|
|
rrdata_parse::<structs::NSEC3PARAM>("1 2 300 a b").unwrap_err();
|
2017-12-21 12:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_spf() {
|
|
|
|
test_txt_for::<structs::SPF>();
|
2017-12-16 20:58:18 +00:00
|
|
|
}
|
2020-03-07 15:11:28 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_apl() {
|
|
|
|
check::<structs::APL>("1:0.0.0.0/0", b"\x00\x01\x00\x00").unwrap();
|
|
|
|
check::<structs::APL>("!1:0.0.0.0/0", b"\x00\x01\x00\x80").unwrap();
|
|
|
|
check::<structs::APL>("2:::/0", b"\x00\x02\x00\x00").unwrap();
|
|
|
|
check::<structs::APL>("!2:::/0", b"\x00\x02\x00\x80").unwrap();
|
2020-03-07 15:57:47 +00:00
|
|
|
check::<structs::APL>(
|
|
|
|
"1:192.0.2.0/24 !2:2001:db8::/32",
|
|
|
|
b"\x00\x01\x18\x03\xc0\x00\x02\x00\x02\x20\x84\x20\x01\x0d\xb8",
|
|
|
|
)
|
|
|
|
.unwrap();
|
2020-03-07 15:11:28 +00:00
|
|
|
}
|