step
This commit is contained in:
parent
af95fbdf67
commit
d362520632
@ -2,7 +2,7 @@ use bytes::{Bytes, BufMut};
|
||||
use data_encoding::{self, HEXLOWER_PERMISSIVE};
|
||||
use errors::*;
|
||||
use failure::{Fail, ResultExt};
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes, short_blob, write_short_blob};
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes, short_blob, write_short_blob, get_blob};
|
||||
use ser::text::*;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
@ -65,6 +65,57 @@ impl DnsTextData for HexShortBlob {
|
||||
}
|
||||
}
|
||||
|
||||
// 16-bit length, uses decimal length + base64 encoding (if length > 0)
|
||||
// for text representation.
|
||||
//
|
||||
// In base64 encoding no whitespace allowed and padding required.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Base64LongBlob(Bytes);
|
||||
|
||||
impl DnsPacketData for Base64LongBlob {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
let len = u16::deserialize(data)? as usize;
|
||||
check_enough_data!(data, len, "data for long blob");
|
||||
|
||||
Ok(Base64LongBlob(get_blob(data, len)?))
|
||||
}
|
||||
|
||||
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
let len = self.0.len();
|
||||
ensure!(len < 0x1_0000, "blob too long");
|
||||
(len as u16).serialize(context, packet)?;
|
||||
packet.reserve(len);
|
||||
packet.put_slice(&self.0);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for Base64LongBlob {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
let length_field = next_field(data)?;
|
||||
let length = length_field.parse::<u16>()
|
||||
.with_context(|_| format!("invalid length for blob: {:?}", length_field))?;
|
||||
|
||||
if length > 0 {
|
||||
let blob_field = next_field(data)?;
|
||||
let result = BASE64_ALLOW_WS.decode(blob_field.as_bytes())
|
||||
.with_context(|e| e.context(format!("invalid base64: {:?}", blob_field)))?;
|
||||
Ok(Base64LongBlob(result.into()))
|
||||
} else {
|
||||
Ok(Base64LongBlob(Bytes::new()))
|
||||
}
|
||||
}
|
||||
|
||||
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
||||
if self.0.len() >= 0x1_0000 { return Err(fmt::Error); }
|
||||
if self.0.is_empty() {
|
||||
write!(f, "0")
|
||||
} else {
|
||||
write!(f, "{} {}", self.0.len(), BASE64_ALLOW_WS.encode(&self.0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No length byte (or restriction), just all data to end of record. uses
|
||||
// base64 encoding for text representation, whitespace allowed, padding
|
||||
// required.
|
||||
@ -95,7 +146,11 @@ impl DnsTextData for Base64RemainingBlob {
|
||||
}
|
||||
|
||||
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
||||
write!(f, "{}", BASE64_ALLOW_WS.encode(&self.0))
|
||||
if !self.0.is_empty() {
|
||||
write!(f, "{}", BASE64_ALLOW_WS.encode(&self.0))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
143
lib/dnsbox-base/src/common_types/eui.rs
Normal file
143
lib/dnsbox-base/src/common_types/eui.rs
Normal file
@ -0,0 +1,143 @@
|
||||
use bytes::Bytes;
|
||||
use errors::*;
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field};
|
||||
use std::fmt;
|
||||
use std::io::{Cursor, Read};
|
||||
|
||||
fn fmt_eui_hyphens(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:02x}", data[0])?;
|
||||
for v in &data[1..] {
|
||||
write!(f, "-{:02x}", v)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_eui_hyphens(dest: &mut [u8], source: &str) -> Result<()> {
|
||||
let mut pos = 0;
|
||||
for octet in source.split('-') {
|
||||
ensure!(pos < dest.len(), "too many octets for EUI{}", dest.len() * 8);
|
||||
ensure!(octet.len() == 2, "invalid octet {:?}", octet);
|
||||
match u8::from_str_radix(octet, 16) {
|
||||
Ok(o) => {
|
||||
dest[pos] = o;
|
||||
pos += 1;
|
||||
},
|
||||
Err(_) => {
|
||||
bail!("invalid octet {:?}", octet);
|
||||
},
|
||||
}
|
||||
}
|
||||
ensure!(pos == dest.len(), "not enough octets for EUI{}", dest.len() * 8);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct EUI48Addr(pub [u8; 6]);
|
||||
|
||||
impl fmt::Display for EUI48Addr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt_eui_hyphens(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for EUI48Addr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt_eui_hyphens(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsPacketData for EUI48Addr {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
let mut buf = [0u8; 6];
|
||||
check_enough_data!(data, 6, "not enough bytes for EUI48Addr");
|
||||
data.read_exact(&mut buf)?;
|
||||
Ok(EUI48Addr(buf))
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
packet.extend_from_slice(&self.0);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for EUI48Addr {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> Result<Self> {
|
||||
let field = next_field(data)?;
|
||||
let mut buf = [0u8; 6];
|
||||
parse_eui_hyphens(&mut buf, field)?;
|
||||
Ok(EUI48Addr(buf))
|
||||
}
|
||||
|
||||
// format might fail if there is no (known) text representation.
|
||||
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 6]> for EUI48Addr {
|
||||
fn from(v: [u8; 6]) -> Self {
|
||||
EUI48Addr(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<[u8; 6]> for EUI48Addr {
|
||||
fn into(self) -> [u8; 6] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct EUI64Addr(pub [u8; 8]);
|
||||
|
||||
impl fmt::Display for EUI64Addr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt_eui_hyphens(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for EUI64Addr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt_eui_hyphens(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsPacketData for EUI64Addr {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
let mut buf = [0u8; 8];
|
||||
check_enough_data!(data, 8, "not enough bytes for EUI64Addr");
|
||||
data.read_exact(&mut buf)?;
|
||||
Ok(EUI64Addr(buf))
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
packet.extend_from_slice(&self.0);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for EUI64Addr {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> Result<Self> {
|
||||
let field = next_field(data)?;
|
||||
let mut buf = [0u8; 8];
|
||||
parse_eui_hyphens(&mut buf, field)?;
|
||||
Ok(EUI64Addr(buf))
|
||||
}
|
||||
|
||||
// format might fail if there is no (known) text representation.
|
||||
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 8]> for EUI64Addr {
|
||||
fn from(v: [u8; 8]) -> Self {
|
||||
EUI64Addr(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<[u8; 8]> for EUI64Addr {
|
||||
fn into(self) -> [u8; 8] {
|
||||
self.0
|
||||
}
|
||||
}
|
@ -1,19 +1,21 @@
|
||||
pub mod name;
|
||||
pub mod text;
|
||||
pub mod binary;
|
||||
pub mod classes;
|
||||
pub mod name;
|
||||
pub mod text;
|
||||
pub mod types;
|
||||
mod eui;
|
||||
mod nsec;
|
||||
mod nxt;
|
||||
mod time;
|
||||
mod uri;
|
||||
|
||||
pub use self::binary::{HexShortBlob, Base64RemainingBlob, HexRemainingBlob};
|
||||
pub use self::binary::{HexShortBlob, Base64LongBlob, Base64RemainingBlob, HexRemainingBlob};
|
||||
pub use self::classes::Class;
|
||||
pub use self::eui::{EUI48Addr, EUI64Addr};
|
||||
pub use self::name::{DnsName, DnsCanonicalName, DnsCompressedName};
|
||||
pub use self::nsec::{NsecTypeBitmap, NextHashedOwnerName};
|
||||
pub use self::types::Type;
|
||||
pub use self::classes::Class;
|
||||
pub use self::text::{ShortText, LongText, UnquotedShortText, RemainingText};
|
||||
pub use self::uri::UriText;
|
||||
pub use self::time::Time;
|
||||
pub use self::nxt::NxtTypeBitmap;
|
||||
pub use self::text::{ShortText, LongText, UnquotedShortText, RemainingText};
|
||||
pub use self::time::{Time, Time48};
|
||||
pub use self::types::Type;
|
||||
pub use self::uri::UriText;
|
||||
|
@ -9,7 +9,7 @@ use std::io::Cursor;
|
||||
///
|
||||
/// Is expected to wrap around.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Time(u32);
|
||||
pub struct Time(pub u32);
|
||||
|
||||
impl DnsPacketData for Time {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
@ -21,12 +21,80 @@ impl DnsPacketData for Time {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct Tm {
|
||||
year: u16, // 1970...9999
|
||||
month: u8, // 01...12
|
||||
day: u8, // 01..31
|
||||
hour: u8, // 00..23
|
||||
minute: u8, // 00..59
|
||||
second: u8, // 00..59
|
||||
}
|
||||
|
||||
impl Tm {
|
||||
// 0..365
|
||||
fn dayofyear(&self) -> u16 {
|
||||
let is_leap_year = (0 == self.year % 4) && ((0 != self.year % 100) || (0 == self.year % 400));
|
||||
static MONTH_START: [u16; 12] = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
|
||||
let leap_add = if self.month > 2 && is_leap_year { 1 } else { 0 };
|
||||
MONTH_START[self.month as usize - 1] + leap_add + (self.day as u16 - 1)
|
||||
}
|
||||
|
||||
fn epoch(&self) -> u64 {
|
||||
let yday = self.dayofyear();
|
||||
self.second as u64
|
||||
+ 60 * self.minute as u64
|
||||
+ 3600 * self.hour as u64
|
||||
+ 86400 * yday as u64
|
||||
+ 31536000 * (self.year as u64 - 1970)
|
||||
+ 86400 * ((self.year as u64 - 1969) / 4)
|
||||
- 86400 * ((self.year as u64 - 1901) / 100)
|
||||
+ 86400 * ((self.year as u64 - 1900 + 299) / 400)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::str::FromStr for Tm {
|
||||
type Err = ::failure::Error;
|
||||
fn from_str(s: &str) -> ::errors::Result<Self> {
|
||||
ensure!(s.len() == 14, "Tm string must be exactly 14 digits long");
|
||||
ensure!(s.as_bytes().iter().all(|&b| b >= b'0' && b <= b'9'), "Tm string must be exactly 14 digits long");
|
||||
let year = s[0..4].parse::<u16>()?;
|
||||
ensure!(year >= 1970, "year must be >= 1970");
|
||||
ensure!(year <= 9999, "year must be <= 9999");
|
||||
|
||||
fn p(s: &str, min: u8, max: u8, name: &'static str) -> ::errors::Result<u8> {
|
||||
let v = s.parse::<u8>()?;
|
||||
ensure!(v >= min && v <= max, "{} {} out of range {}-{}", name, v, min, max);
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
let month = p(&s[4..6], 1, 12, "month")?;
|
||||
let day = p(&s[6..8], 1, 31, "day")?;
|
||||
let hour = p(&s[8..10], 0, 23, "hour")?;
|
||||
let minute = p(&s[10..12], 0, 59, "minute")?;
|
||||
let second = p(&s[12..14], 0, 59, "second")?;
|
||||
|
||||
if 2 == month {
|
||||
let is_leap_year = (0 == year % 4) && ((0 != year % 100) || (0 == year % 400));
|
||||
ensure!(day < 30, "day {} out of range in february", day);
|
||||
ensure!(is_leap_year || day < 29, "day {} out of range in february (not a leap year)", day);
|
||||
} else {
|
||||
static DAYS_IN_MONTHS: [u8; 12] = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
let max_days = DAYS_IN_MONTHS[month as usize - 1];
|
||||
ensure!(day <= max_days, "day {} out of range for month {}", day, month);
|
||||
}
|
||||
|
||||
Ok(Tm{ year, month, day, hour, minute, second })
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for Time {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
let field = next_field(data)?;
|
||||
let epoch = field.parse::<u32>();
|
||||
if field.len() == 14 && epoch.is_err() {
|
||||
unimplemented!()
|
||||
let tm = field.parse::<Tm>()?;
|
||||
Ok(Time(tm.epoch() as u32))
|
||||
} else {
|
||||
Ok(Time(epoch?))
|
||||
}
|
||||
@ -36,3 +104,39 @@ impl DnsTextData for Time {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub const TIME48_MAX: u64 = 0xffff_ffff_ffff;
|
||||
|
||||
/// 48-bit timestamp in seconds since epoch (ignoring leap seconds)
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Time48(pub u64);
|
||||
|
||||
impl DnsPacketData for Time48 {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
let high16 = u16::deserialize(data)? as u64;
|
||||
let low32 = u32::deserialize(data)? as u64;
|
||||
Ok(Time48(high16 | low32))
|
||||
}
|
||||
|
||||
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
ensure!(self.0 <= TIME48_MAX, "time48 overflow");
|
||||
let high16 = (self.0 >> 32) as u16;
|
||||
let low32 = self.0 as u32;
|
||||
high16.serialize(context, packet)?;
|
||||
low32.serialize(context, packet)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for Time48 {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
let field = next_field(data)?;
|
||||
let epoch = field.parse::<u64>()?;
|
||||
ensure!(epoch <= TIME48_MAX, "time48 overflow");
|
||||
Ok(Time48(epoch))
|
||||
}
|
||||
|
||||
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +277,8 @@ fn test_TXT() {
|
||||
None,
|
||||
b"\xfflong record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\x0a2222222222",
|
||||
);
|
||||
/* autosplitting not supported
|
||||
// autosplitting not supported
|
||||
/*
|
||||
check(types::TXT,
|
||||
"\"long record test 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222\"",
|
||||
Some("\"long record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\" \"2222222222\""),
|
||||
@ -514,7 +515,8 @@ fn test_IPSECKEY() {
|
||||
fn test_RRSIG() {
|
||||
check(types::RRSIG,
|
||||
"SOA 8 3 300 20130523000000 20130509000000 54216 rec.test. ecWKD/OsdAiXpbM/sgPT82KVD/WiQnnqcxoJgiH3ixHa+LOAcYU7FG7V4BRRJxLriY1e0rB2gAs3kCel9D4bzfK6wAqG4Di/eHUgHptRlaR2ycELJ4t1pjzrnuGiIzA1wM2izRmeE+Xoy1367Qu0pOz5DLzTfQITWFsB2iUzN4Y=",
|
||||
None,
|
||||
// None, // we use the epoch as canoninc format
|
||||
Some("SOA 8 3 300 1369267200 1368057600 54216 rec.test. ecWKD/OsdAiXpbM/sgPT82KVD/WiQnnqcxoJgiH3ixHa+LOAcYU7FG7V4BRRJxLriY1e0rB2gAs3kCel9D4bzfK6wAqG4Di/eHUgHptRlaR2ycELJ4t1pjzrnuGiIzA1wM2izRmeE+Xoy1367Qu0pOz5DLzTfQITWFsB2iUzN4Y="),
|
||||
b"\x00\x06\x08\x03\x00\x00\x01\x2c\x51\x9d\x5c\x00\x51\x8a\xe7\x00\xd3\xc8\x03\x72\x65\x63\x04\x74\x65\x73\x74\x00\x79\xc5\x8a\x0f\xf3\xac\x74\x08\x97\xa5\xb3\x3f\xb2\x03\xd3\xf3\x62\x95\x0f\xf5\xa2\x42\x79\xea\x73\x1a\x09\x82\x21\xf7\x8b\x11\xda\xf8\xb3\x80\x71\x85\x3b\x14\x6e\xd5\xe0\x14\x51\x27\x12\xeb\x89\x8d\x5e\xd2\xb0\x76\x80\x0b\x37\x90\x27\xa5\xf4\x3e\x1b\xcd\xf2\xba\xc0\x0a\x86\xe0\x38\xbf\x78\x75\x20\x1e\x9b\x51\x95\xa4\x76\xc9\xc1\x0b\x27\x8b\x75\xa6\x3c\xeb\x9e\xe1\xa2\x23\x30\x35\xc0\xcd\xa2\xcd\x19\x9e\x13\xe5\xe8\xcb\x5d\xfa\xed\x0b\xb4\xa4\xec\xf9\x0c\xbc\xd3\x7d\x02\x13\x58\x5b\x01\xda\x25\x33\x37\x86",
|
||||
);
|
||||
}
|
||||
|
@ -158,22 +158,22 @@ impl Registry {
|
||||
r.register_unknown("APL" , types::APL);
|
||||
r.register_known::<structs::DS>();
|
||||
r.register_known::<structs::SSHFP>();
|
||||
r.register_unknown("IPSECKEY" , types::IPSECKEY);
|
||||
r.register_known::<structs::IPSECKEY>();
|
||||
r.register_known::<structs::RRSIG>();
|
||||
r.register_known::<structs::NSEC>();
|
||||
r.register_known::<structs::DNSKEY>();
|
||||
r.register_unknown("DHCID" , types::DHCID);
|
||||
r.register_known::<structs::DHCID>();
|
||||
r.register_known::<structs::NSEC3>();
|
||||
r.register_known::<structs::NSEC3PARAM>();
|
||||
r.register_unknown("TLSA" , types::TLSA);
|
||||
r.register_unknown("SMIMEA" , types::SMIMEA);
|
||||
r.register_known::<structs::TLSA>();
|
||||
r.register_known::<structs::SMIMEA>();
|
||||
r.register_unknown("HIP" , types::HIP);
|
||||
r.register_unknown("NINFO" , types::NINFO);
|
||||
r.register_unknown("RKEY" , types::RKEY);
|
||||
r.register_unknown("TALINK" , types::TALINK);
|
||||
r.register_unknown("CDS" , types::CDS);
|
||||
r.register_unknown("CDNSKEY" , types::CDNSKEY);
|
||||
r.register_unknown("OPENPGPKEY", types::OPENPGPKEY);
|
||||
r.register_known::<structs::OPENPGPKEY>();
|
||||
r.register_unknown("CSYNC" , types::CSYNC);
|
||||
r.register_known::<structs::SPF>();
|
||||
r.register_unknown("UINFO" , types::UINFO);
|
||||
@ -184,10 +184,10 @@ impl Registry {
|
||||
r.register_unknown("L32" , types::L32);
|
||||
r.register_unknown("L64" , types::L64);
|
||||
r.register_unknown("LP" , types::LP);
|
||||
r.register_unknown("EUI48" , types::EUI48);
|
||||
r.register_unknown("EUI64" , types::EUI64);
|
||||
r.register_unknown("TKEY" , types::TKEY);
|
||||
r.register_unknown("TSIG" , types::TSIG);
|
||||
r.register_known::<structs::EUI48>();
|
||||
r.register_known::<structs::EUI64>();
|
||||
r.register_known::<structs::TKEY>();
|
||||
r.register_known::<structs::TSIG>();
|
||||
r.register_unknown("IXFR" , types::IXFR);
|
||||
r.register_unknown("AXFR" , types::AXFR);
|
||||
r.register_unknown("MAILB" , types::MAILB);
|
||||
@ -198,7 +198,7 @@ impl Registry {
|
||||
r.register_unknown("AVC" , types::AVC);
|
||||
r.register_unknown("DOA" , types::DOA);
|
||||
r.register_unknown("TA" , types::TA);
|
||||
r.register_unknown("DLV" , types::DLV);
|
||||
r.register_known::<structs::DLV>();
|
||||
r.register_known::<structs::ALIAS>();
|
||||
|
||||
// "ALL" could be an alias for the ANY type?
|
||||
|
@ -317,9 +317,7 @@ pub struct SSHFP {
|
||||
fingerprint: HexRemainingBlob,
|
||||
}
|
||||
|
||||
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
// #[RRClass(?)]
|
||||
// pub struct IPSECKEY;
|
||||
pub use super::weird_structs::IPSECKEY;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
#[RRClass(ANY)]
|
||||
@ -351,9 +349,11 @@ pub struct DNSKEY {
|
||||
public_key: Base64RemainingBlob,
|
||||
}
|
||||
|
||||
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
// #[RRClass(?)]
|
||||
// pub struct DHCID;
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
#[RRClass(IN)]
|
||||
pub struct DHCID {
|
||||
content: Base64RemainingBlob,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
#[RRClass(ANY)]
|
||||
@ -375,13 +375,25 @@ pub struct NSEC3PARAM {
|
||||
salt: HexShortBlob,
|
||||
}
|
||||
|
||||
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
// #[RRClass(?)]
|
||||
// pub struct TLSA;
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
#[RRClass(ANY)]
|
||||
pub struct TLSA {
|
||||
// TODO: support acronyms from https://tools.ietf.org/html/rfc7218
|
||||
cert_usage: u8,
|
||||
selector: u8,
|
||||
matching_type: u8,
|
||||
data: HexRemainingBlob,
|
||||
}
|
||||
|
||||
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
// #[RRClass(?)]
|
||||
// pub struct SMIMEA;
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
#[RRClass(ANY)]
|
||||
pub struct SMIMEA {
|
||||
// TODO: support acronyms from https://tools.ietf.org/html/rfc7218
|
||||
cert_usage: u8,
|
||||
selector: u8,
|
||||
matching_type: u8,
|
||||
data: HexRemainingBlob,
|
||||
}
|
||||
|
||||
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
// #[RRClass(?)]
|
||||
@ -407,9 +419,11 @@ pub struct NSEC3PARAM {
|
||||
// #[RRClass(?)]
|
||||
// pub struct CDNSKEY;
|
||||
|
||||
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
// #[RRClass(?)]
|
||||
// pub struct OPENPGPKEY;
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
#[RRClass(ANY)]
|
||||
pub struct OPENPGPKEY {
|
||||
public_key: Base64RemainingBlob,
|
||||
}
|
||||
|
||||
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
// #[RRClass(?)]
|
||||
@ -453,21 +467,41 @@ pub struct SPF {
|
||||
// #[RRClass(?)]
|
||||
// pub struct LP;
|
||||
|
||||
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
// #[RRClass(?)]
|
||||
// pub struct EUI48;
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
#[RRClass(ANY)]
|
||||
pub struct EUI48 {
|
||||
addr: EUI48Addr,
|
||||
}
|
||||
|
||||
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
// #[RRClass(?)]
|
||||
// pub struct EUI64;
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
#[RRClass(ANY)]
|
||||
pub struct EUI64 {
|
||||
addr: EUI64Addr
|
||||
}
|
||||
|
||||
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
// #[RRClass(?)]
|
||||
// pub struct TKEY;
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
#[RRClass(ANY)]
|
||||
pub struct TKEY {
|
||||
algorithm: DnsName,
|
||||
inception: Time,
|
||||
expiration: Time,
|
||||
mode: u16,
|
||||
error: u16,
|
||||
key: Base64LongBlob,
|
||||
other: Base64LongBlob,
|
||||
}
|
||||
|
||||
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
// #[RRClass(?)]
|
||||
// pub struct TSIG;
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
#[RRClass(ANY)]
|
||||
pub struct TSIG {
|
||||
algorithm: DnsName,
|
||||
signed: Time48,
|
||||
fudge: u16,
|
||||
mac: Base64LongBlob,
|
||||
original_id: u16,
|
||||
error: u16,
|
||||
other: Base64LongBlob,
|
||||
}
|
||||
|
||||
// QTYPEs: IXFR, AXFR, MAILB, MAILA, ANY
|
||||
|
||||
@ -490,8 +524,14 @@ pub struct CAA {
|
||||
// pub struct AVC;
|
||||
// pub struct DOA;
|
||||
|
||||
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
// pub struct DLV;
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
#[RRClass(ANY)]
|
||||
pub struct DLV {
|
||||
key_tag: u16,
|
||||
algorithm: u8,
|
||||
digest_type: u8,
|
||||
digest: HexRemainingBlob,
|
||||
}
|
||||
|
||||
// powerdns
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||
|
@ -2,11 +2,11 @@ use bytes::{Bytes, Buf, BufMut};
|
||||
use errors::*;
|
||||
use common_types::*;
|
||||
use failure::ResultExt;
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext};
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext};
|
||||
use std::fmt;
|
||||
use std::io::Read;
|
||||
use std::net::Ipv6Addr;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
// deriving RRData will add a unit test to make sure the type is
|
||||
// registered; there must be a records::types::$name `Type` constant
|
||||
@ -30,7 +30,7 @@ impl DnsPacketData for LOC {
|
||||
} else {
|
||||
Ok(LOC::UnknownVersion{
|
||||
version: version,
|
||||
data: ::ser::packet::remaining_bytes(data),
|
||||
data: remaining_bytes(data),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -182,3 +182,131 @@ impl DnsTextData for A6 {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum IpsecKeyGateway {
|
||||
None,
|
||||
Ipv4(Ipv4Addr),
|
||||
Ipv6(Ipv6Addr),
|
||||
Name(DnsName),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, RRData)]
|
||||
#[RRClass(ANY)]
|
||||
pub enum IPSECKEY {
|
||||
Known{
|
||||
precedence: u8,
|
||||
algorithm: u8,
|
||||
gateway: IpsecKeyGateway,
|
||||
public_key: Base64RemainingBlob,
|
||||
},
|
||||
UnknownGateway{
|
||||
precedence: u8,
|
||||
gateway_type: u8,
|
||||
algorithm: u8,
|
||||
// length of gateway is unknown, can't split gateway and public key
|
||||
remaining: Bytes,
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsPacketData for IPSECKEY {
|
||||
fn deserialize(data: &mut ::std::io::Cursor<Bytes>) -> Result<Self> {
|
||||
let precedence = u8::deserialize(data)?;
|
||||
let gateway_type = u8::deserialize(data)?;
|
||||
let algorithm = u8::deserialize(data)?;
|
||||
let gateway = match gateway_type {
|
||||
0 => IpsecKeyGateway::None,
|
||||
1 => IpsecKeyGateway::Ipv4(Ipv4Addr::deserialize(data)?),
|
||||
2 => IpsecKeyGateway::Ipv6(Ipv6Addr::deserialize(data)?),
|
||||
3 => IpsecKeyGateway::Name(DnsName::deserialize(data)?),
|
||||
_ => return Ok(IPSECKEY::UnknownGateway{
|
||||
precedence,
|
||||
gateway_type,
|
||||
algorithm,
|
||||
remaining: remaining_bytes(data),
|
||||
}),
|
||||
};
|
||||
Ok(IPSECKEY::Known{
|
||||
precedence,
|
||||
algorithm,
|
||||
gateway,
|
||||
public_key: Base64RemainingBlob::deserialize(data)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
match *self {
|
||||
IPSECKEY::Known{precedence, algorithm, ref gateway, ref public_key} => {
|
||||
packet.reserve(3);
|
||||
packet.put_u8(precedence);
|
||||
let gateway_type: u8 = match *gateway {
|
||||
IpsecKeyGateway::None => 0,
|
||||
IpsecKeyGateway::Ipv4(_) => 1,
|
||||
IpsecKeyGateway::Ipv6(_) => 2,
|
||||
IpsecKeyGateway::Name(_) => 3,
|
||||
};
|
||||
packet.put_u8(gateway_type);
|
||||
packet.put_u8(algorithm);
|
||||
match *gateway {
|
||||
IpsecKeyGateway::None => (),
|
||||
IpsecKeyGateway::Ipv4(ref a) => a.serialize(context, packet)?,
|
||||
IpsecKeyGateway::Ipv6(ref a) => a.serialize(context, packet)?,
|
||||
IpsecKeyGateway::Name(ref n) => n.serialize(context, packet)?,
|
||||
};
|
||||
public_key.serialize(context, packet)?;
|
||||
},
|
||||
IPSECKEY::UnknownGateway{precedence, gateway_type, algorithm, ref remaining} => {
|
||||
packet.reserve(3 + remaining.len());
|
||||
packet.put_u8(precedence);
|
||||
packet.put_u8(gateway_type);
|
||||
packet.put_u8(algorithm);
|
||||
packet.put_slice(remaining);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for IPSECKEY {
|
||||
fn dns_parse(context: &DnsTextContext, data: &mut &str) -> Result<Self> {
|
||||
let precedence = u8::dns_parse(context, data)?;
|
||||
let gateway_type = u8::dns_parse(context, data)?;
|
||||
let algorithm = u8::dns_parse(context, data)?;
|
||||
let gateway = match gateway_type {
|
||||
0 => IpsecKeyGateway::None,
|
||||
1 => IpsecKeyGateway::Ipv4(Ipv4Addr::dns_parse(context, data)?),
|
||||
2 => IpsecKeyGateway::Ipv6(Ipv6Addr::dns_parse(context, data)?),
|
||||
3 => IpsecKeyGateway::Name(DnsName::dns_parse(context, data)?),
|
||||
_ => bail!("unknown gateway type {} for IPSECKEY", gateway_type),
|
||||
};
|
||||
Ok(IPSECKEY::Known{
|
||||
precedence,
|
||||
algorithm,
|
||||
gateway,
|
||||
public_key: Base64RemainingBlob::dns_parse(context, data)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
||||
match *self {
|
||||
IPSECKEY::Known{precedence, algorithm, ref gateway, ref public_key} => {
|
||||
let gateway_type: u8 = match *gateway {
|
||||
IpsecKeyGateway::None => 0,
|
||||
IpsecKeyGateway::Ipv4(_) => 1,
|
||||
IpsecKeyGateway::Ipv6(_) => 2,
|
||||
IpsecKeyGateway::Name(_) => 3,
|
||||
};
|
||||
write!(f, "{} {} {}", precedence, gateway_type, algorithm)?;
|
||||
match *gateway {
|
||||
IpsecKeyGateway::None => (),
|
||||
IpsecKeyGateway::Ipv4(ref a) => a.dns_format(f)?,
|
||||
IpsecKeyGateway::Ipv6(ref a) => a.dns_format(f)?,
|
||||
IpsecKeyGateway::Name(ref n) => n.dns_format(f)?,
|
||||
};
|
||||
public_key.dns_format(f)?;
|
||||
Ok(())
|
||||
},
|
||||
IPSECKEY::UnknownGateway{..} => Err(fmt::Error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,14 +30,18 @@ pub fn remaining_bytes(data: &mut Cursor<Bytes>) -> Bytes {
|
||||
result
|
||||
}
|
||||
|
||||
pub fn get_blob(data: &mut Cursor<Bytes>, len: usize) -> Result<Bytes> {
|
||||
check_enough_data!(data, len, "blob content");
|
||||
let pos = data.position() as usize;
|
||||
let blob = data.get_ref().slice(pos, pos + len);
|
||||
data.advance(len);
|
||||
Ok(blob)
|
||||
}
|
||||
|
||||
pub fn short_blob(data: &mut Cursor<Bytes>) -> Result<Bytes> {
|
||||
check_enough_data!(data, 1, "short blob length");
|
||||
let blob_len = data.get_u8() as usize;
|
||||
check_enough_data!(data, blob_len, "short blob content");
|
||||
let pos = data.position() as usize;
|
||||
let blob = data.get_ref().slice(pos, pos + blob_len);
|
||||
data.advance(blob_len);
|
||||
Ok(blob)
|
||||
get_blob(data, blob_len)
|
||||
}
|
||||
|
||||
pub fn write_short_blob(data: &[u8], packet: &mut Vec<u8>) -> Result<()> {
|
||||
|
Loading…
Reference in New Issue
Block a user