step
This commit is contained in:
parent
c4c84bd887
commit
302300c184
@ -40,7 +40,7 @@ impl DnsPacketData for HexShortBlob {
|
||||
}
|
||||
|
||||
impl DnsTextData for HexShortBlob {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
let s = next_field(data)?;
|
||||
if s == "-" {
|
||||
Ok(HexShortBlob(Bytes::new()))
|
||||
@ -76,7 +76,7 @@ impl DnsPacketData for Base64RemainingBlob {
|
||||
}
|
||||
|
||||
impl DnsTextData for Base64RemainingBlob {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
skip_whitespace(data);
|
||||
let result = BASE64_ALLOW_WS.decode(data.as_bytes())
|
||||
.with_context(|e| e.context(format!("invalid base64: {:?}", data)))?;
|
||||
@ -101,7 +101,7 @@ impl DnsPacketData for HexRemainingBlob {
|
||||
}
|
||||
|
||||
impl DnsTextData for HexRemainingBlob {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
skip_whitespace(data);
|
||||
let result = HEXLOWER_PERMISSIVE_ALLOW_WS.decode(data.as_bytes())
|
||||
.with_context(|e| e.context(format!("invalid hex: {:?}", data)))?;
|
||||
|
@ -3,7 +3,7 @@
|
||||
use bytes::Bytes;
|
||||
use errors::*;
|
||||
use ser::DnsPacketData;
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, next_field};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field};
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
use std::borrow::Cow;
|
||||
@ -153,7 +153,7 @@ impl Class {
|
||||
/// parses generic names of the form "CLASS..."
|
||||
pub fn from_generic_name(name: &str) -> Option<Self> {
|
||||
use std::ascii::AsciiExt;
|
||||
if name.as_bytes()[0..5].eq_ignore_ascii_case(b"CLASS") {
|
||||
if name.len() > 5 && name.as_bytes()[0..5].eq_ignore_ascii_case(b"CLASS") {
|
||||
name[5..].parse::<u16>().ok().map(Class)
|
||||
} else {
|
||||
None
|
||||
@ -204,7 +204,7 @@ impl DnsPacketData for Class {
|
||||
}
|
||||
|
||||
impl DnsTextData for Class {
|
||||
fn dns_parse(data: &mut &str) -> Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> Result<Self> {
|
||||
let field = next_field(data)?;
|
||||
Class::from_name(field).ok_or_else(|| format_err!("unknown CLASS {:?}", field))
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
use super::*;
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, next_field, quoted};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field, quoted};
|
||||
|
||||
impl DnsName {
|
||||
/// Parse text representation of a domain name
|
||||
pub fn parse<'a, O>(value: &str, origin: O) -> ::errors::Result<Self>
|
||||
where
|
||||
O: IntoIterator<Item = DnsLabelRef<'a>>
|
||||
pub fn parse(context: &DnsTextContext, value: &str) -> Result<Self>
|
||||
{
|
||||
let raw = value.as_bytes();
|
||||
let mut name = DnsName::new_root();
|
||||
if raw == b"." {
|
||||
return Ok(name);
|
||||
} else if raw == b"@" {
|
||||
for l in origin.into_iter() { name.push_back(l)?; }
|
||||
return Ok(name);
|
||||
match context.origin() {
|
||||
Some(o) => return Ok(o.clone()),
|
||||
None => bail!("@ invalid without $ORIGIN"),
|
||||
}
|
||||
}
|
||||
ensure!(!raw.is_empty(), "invalid empty name");
|
||||
let mut label = Vec::new();
|
||||
@ -48,8 +48,16 @@ impl DnsName {
|
||||
|
||||
if !label.is_empty() {
|
||||
// no trailing dot, relative name
|
||||
|
||||
// push last label
|
||||
name.push_back(DnsLabelRef::new(&label)?)?;
|
||||
for l in origin.into_iter() { name.push_back(l)?; }
|
||||
|
||||
match context.origin() {
|
||||
Some(o) => {
|
||||
for l in o { name.push_back(l)?; }
|
||||
},
|
||||
None => bail!("missing trailing dot without $ORIGIN"),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(name)
|
||||
@ -57,9 +65,9 @@ impl DnsName {
|
||||
}
|
||||
|
||||
impl DnsTextData for DnsName {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(context: &DnsTextContext, data: &mut &str) -> Result<Self> {
|
||||
let field = next_field(data)?;
|
||||
DnsName::parse(field, &DnsName::new_root())
|
||||
DnsName::parse(context, field)
|
||||
}
|
||||
|
||||
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
||||
@ -69,18 +77,16 @@ impl DnsTextData for DnsName {
|
||||
|
||||
impl DnsCompressedName {
|
||||
/// Parse text representation of a domain name
|
||||
pub fn parse<'a, O>(value: &str, origin: O) -> ::errors::Result<Self>
|
||||
where
|
||||
O: IntoIterator<Item = DnsLabelRef<'a>>
|
||||
pub fn parse(context: &DnsTextContext, value: &str) -> Result<Self>
|
||||
{
|
||||
Ok(DnsCompressedName(DnsName::parse(value, origin)?))
|
||||
Ok(DnsCompressedName(DnsName::parse(context, value)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for DnsCompressedName {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(context: &DnsTextContext, data: &mut &str) -> Result<Self> {
|
||||
let field = next_field(data)?;
|
||||
DnsCompressedName::parse(field, &DnsName::new_root())
|
||||
DnsCompressedName::parse(context, field)
|
||||
}
|
||||
|
||||
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
||||
|
@ -4,7 +4,7 @@ use data_encoding;
|
||||
use errors::*;
|
||||
use failure::{Fail, ResultExt};
|
||||
use ser::packet::{DnsPacketData, remaining_bytes, short_blob};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, skip_whitespace, next_field};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, skip_whitespace, next_field};
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
@ -103,11 +103,11 @@ impl DnsPacketData for NsecTypeBitmap {
|
||||
}
|
||||
|
||||
impl DnsTextData for NsecTypeBitmap {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
let mut set = BTreeSet::new();
|
||||
skip_whitespace(data);
|
||||
while !data.is_empty() {
|
||||
let t = Type::dns_parse(data)?;
|
||||
let t = Type::dns_parse(context, data)?;
|
||||
set.insert(t);
|
||||
}
|
||||
Ok(NsecTypeBitmap::from_set(set))
|
||||
@ -137,7 +137,7 @@ impl DnsPacketData for NextHashedOwnerName {
|
||||
}
|
||||
|
||||
impl DnsTextData for NextHashedOwnerName {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
let field = next_field(data)?;
|
||||
let raw = BASE32HEX_NOPAD_ALLOW_WS.decode(field.as_bytes())
|
||||
.with_context(|e| e.context(format!("invalid base32hex (no padding): {:?}", field)))?;
|
||||
|
@ -2,7 +2,7 @@ use bytes::{Bytes, Buf};
|
||||
use common_types::Type;
|
||||
use errors::*;
|
||||
use ser::packet::{DnsPacketData, remaining_bytes};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, skip_whitespace};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, skip_whitespace};
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
@ -75,11 +75,11 @@ impl DnsPacketData for NxtTypeBitmap {
|
||||
}
|
||||
|
||||
impl DnsTextData for NxtTypeBitmap {
|
||||
fn dns_parse(data: &mut &str) -> Result<Self> {
|
||||
fn dns_parse(context: &DnsTextContext, data: &mut &str) -> Result<Self> {
|
||||
let mut set = BTreeSet::new();
|
||||
skip_whitespace(data);
|
||||
while !data.is_empty() {
|
||||
let t = Type::dns_parse(data)?;
|
||||
let t = Type::dns_parse(context, data)?;
|
||||
set.insert(t);
|
||||
}
|
||||
NxtTypeBitmap::from_set(set)
|
||||
|
@ -16,7 +16,7 @@ impl DnsPacketData for ShortText {
|
||||
}
|
||||
|
||||
impl DnsTextData for ShortText {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
let raw = next_quoted_field(data)?;
|
||||
ensure!(raw.len() < 256, "short text must be at most 255 bytes long");
|
||||
Ok(ShortText(raw.into()))
|
||||
@ -46,7 +46,7 @@ impl DnsPacketData for LongText {
|
||||
}
|
||||
|
||||
impl DnsTextData for LongText {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
let mut result = Vec::new();
|
||||
// `next_quoted_field` should skip trailing whitespace, we only
|
||||
// need to skip the beginning whitespace for the first
|
||||
@ -80,7 +80,7 @@ impl DnsPacketData for UnquotedShortText {
|
||||
}
|
||||
|
||||
impl DnsTextData for UnquotedShortText {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
let raw = next_quoted_field(data)?;
|
||||
ensure!(raw.len() < 256, "short text must be at most 255 bytes long");
|
||||
Ok(UnquotedShortText(raw.into()))
|
||||
@ -105,7 +105,7 @@ impl DnsPacketData for RemainingText {
|
||||
}
|
||||
|
||||
impl DnsTextData for RemainingText {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
Ok(RemainingText(next_quoted_field(data)?.into()))
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use bytes::Bytes;
|
||||
use errors::*;
|
||||
use ser::packet::DnsPacketData;
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, next_field};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field};
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
|
||||
@ -18,7 +18,7 @@ impl DnsPacketData for Time {
|
||||
}
|
||||
|
||||
impl DnsTextData for Time {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
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() {
|
||||
|
@ -4,7 +4,7 @@ use bytes::Bytes;
|
||||
use errors::*;
|
||||
use records::registry::{lookup_type_to_name, lookup_type_name};
|
||||
use ser::DnsPacketData;
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, next_field};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
@ -475,7 +475,7 @@ impl Type {
|
||||
/// parses generic names of the form "TYPE..."
|
||||
pub fn from_generic_name(name: &str) -> Option<Self> {
|
||||
use std::ascii::AsciiExt;
|
||||
if name.as_bytes()[0..4].eq_ignore_ascii_case(b"TYPE") {
|
||||
if name.len() > 4 && name.as_bytes()[0..4].eq_ignore_ascii_case(b"TYPE") {
|
||||
name[4..].parse::<u16>().ok().map(Type)
|
||||
} else {
|
||||
None
|
||||
@ -576,7 +576,7 @@ impl DnsPacketData for Type {
|
||||
}
|
||||
|
||||
impl DnsTextData for Type {
|
||||
fn dns_parse(data: &mut &str) -> Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> Result<Self> {
|
||||
let field = next_field(data)?;
|
||||
Type::from_name(field).ok_or_else(|| format_err!("unknown TYPE {:?}", field))
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ impl DnsPacketData for UriText {
|
||||
}
|
||||
|
||||
impl DnsTextData for UriText {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
let raw = next_quoted_field(data)?;
|
||||
ensure!(!raw.is_empty(), "URI must not be empty");
|
||||
Ok(UriText(raw.into()))
|
||||
|
@ -20,11 +20,13 @@ fn rrdata_parse<T>(data: &str) -> ::errors::Result<T>
|
||||
where
|
||||
T: StaticRRData
|
||||
{
|
||||
let mut data = data;
|
||||
let result = T::dns_parse_rr_data(3600, classes::IN, T::TYPE, &mut data)?;
|
||||
let data = data.trim();
|
||||
ensure!(data.is_empty(), "didn't parse complete rrdata text, remaining: {:?}", data);
|
||||
Ok(result)
|
||||
let mut ctx = text::DnsTextContext::new();
|
||||
ctx.set_zone_class(classes::IN);
|
||||
ctx.set_record_type(T::TYPE);
|
||||
ctx.set_last_ttl(3600);
|
||||
text::parse_with(data, |data| {
|
||||
T::dns_parse_rr_data(&ctx, data)
|
||||
})
|
||||
}
|
||||
|
||||
fn check<T>(txt: &str, data: &'static [u8]) -> ::errors::Result<()>
|
||||
@ -109,8 +111,8 @@ fn test_nsec3() {
|
||||
check::<structs::NSEC3>("1 2 300 ab vs A NS", b"\x01\x02\x01\x2c\x01\xab\x01\xff\x00\x01\x60").unwrap();
|
||||
|
||||
// invalid base32 texts
|
||||
text::parse::<structs::NSEC3>("1 2 300 - v").unwrap_err();
|
||||
text::parse::<structs::NSEC3>("1 2 300 - vv").unwrap_err();
|
||||
rrdata_parse::<structs::NSEC3>("1 2 300 - v").unwrap_err();
|
||||
rrdata_parse::<structs::NSEC3>("1 2 300 - vv").unwrap_err();
|
||||
|
||||
// invalid (empty) next-hashed values
|
||||
packet::deserialize::<structs::NSEC3>(Bytes::from_static(b"\x01\x02\x01\x2c\x00\x00")).unwrap_err();
|
||||
@ -121,7 +123,7 @@ 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
|
||||
text::parse::<structs::NSEC3PARAM>("1 2 300 a b").unwrap_err();
|
||||
rrdata_parse::<structs::NSEC3PARAM>("1 2 300 a b").unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2,7 +2,7 @@ use bytes::{Bytes, Buf};
|
||||
use common_types::*;
|
||||
use failure::ResultExt;
|
||||
use ser::DnsPacketData;
|
||||
use ser::text::{DnsTextData, DnsTextFormatter};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext};
|
||||
use std::fmt;
|
||||
use std::io::Read;
|
||||
use std::net::Ipv6Addr;
|
||||
@ -36,7 +36,7 @@ impl DnsPacketData for LOC {
|
||||
}
|
||||
|
||||
impl DnsTextData for LOC {
|
||||
fn dns_parse(_data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, _data: &mut &str) -> ::errors::Result<Self> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@ -101,15 +101,15 @@ impl DnsPacketData for A6 {
|
||||
}
|
||||
|
||||
impl DnsTextData for A6 {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
let prefix: u8 = DnsTextData::dns_parse(data)
|
||||
fn dns_parse(context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
let prefix: u8 = DnsTextData::dns_parse(context, data)
|
||||
.context("failed parsing field A6::prefix")?;
|
||||
ensure!(prefix <= 128, "invalid A6::prefix {}", prefix);
|
||||
|
||||
let suffix_offset = (prefix / 8) as usize;
|
||||
debug_assert!(suffix_offset <= 16);
|
||||
|
||||
let suffix: Ipv6Addr = DnsTextData::dns_parse(data)
|
||||
let suffix: Ipv6Addr = DnsTextData::dns_parse(context, data)
|
||||
.context("failed parsing field A6::suffix")?;
|
||||
|
||||
// clear prefix bits
|
||||
@ -124,7 +124,7 @@ impl DnsTextData for A6 {
|
||||
let suffix = Ipv6Addr::from(suffix);
|
||||
|
||||
let prefix_name = if !data.is_empty() {
|
||||
Some(DnsTextData::dns_parse(data)
|
||||
Some(DnsTextData::dns_parse(context, data)
|
||||
.context("failed parsing field A6::prefix_name")?)
|
||||
} else {
|
||||
None
|
||||
|
@ -2,7 +2,7 @@ use bytes::Bytes;
|
||||
use common_types::{Class, Type, classes};
|
||||
use errors::*;
|
||||
use ser::DnsPacketData;
|
||||
use ser::text::{DnsTextData, DnsTextFormatter};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
@ -31,7 +31,7 @@ impl<T: DnsPacketData + StaticRRData> RRDataPacket for T {
|
||||
}
|
||||
|
||||
pub trait RRDataText {
|
||||
fn dns_parse_rr_data(ttl: u32, rr_class: Class, rr_type: Type, data: &mut &str) -> Result<Self>
|
||||
fn dns_parse_rr_data(context: &DnsTextContext, data: &mut &str) -> Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
;
|
||||
@ -59,15 +59,17 @@ pub trait RRDataText {
|
||||
}
|
||||
|
||||
impl<T: DnsTextData + StaticRRData> RRDataText for T {
|
||||
fn dns_parse_rr_data(_ttl: u32, rr_class: Class, rr_type: Type, data: &mut &str) -> Result<Self>
|
||||
fn dns_parse_rr_data(context: &DnsTextContext, data: &mut &str) -> Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
ensure!(rr_type == T::TYPE, "type mismatch");
|
||||
ensure!(context.record_type() == Some(T::TYPE), "type mismatch");
|
||||
let rr_class = context.zone_class().expect("require zone CLASS to parse record");
|
||||
if T::CLASS != classes::ANY {
|
||||
ensure!(rr_class == T::CLASS, "class mismatch: got {}, need {}", rr_class, T::CLASS);
|
||||
}
|
||||
T::dns_parse(data)
|
||||
ensure!(context.last_ttl().is_some(), "require TTL to parse record");
|
||||
T::dns_parse(context, data)
|
||||
}
|
||||
|
||||
fn dns_format_rr_data(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
||||
|
@ -1,3 +1,4 @@
|
||||
use common_types;
|
||||
use std::fmt;
|
||||
|
||||
mod std_impls;
|
||||
@ -94,8 +95,74 @@ impl<'a, 'b> DnsTextFormatter<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct DnsTextContext {
|
||||
zone_class: Option<common_types::Class>,
|
||||
origin: Option<common_types::DnsName>,
|
||||
record_type: Option<common_types::Type>,
|
||||
last_ttl: Option<u32>,
|
||||
}
|
||||
|
||||
impl DnsTextContext {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn zone_class(&self) -> Option<common_types::Class> {
|
||||
self.zone_class
|
||||
}
|
||||
|
||||
pub fn set_zone_class(&mut self, zone_class: common_types::Class) -> &mut Self {
|
||||
self.zone_class = Some(zone_class);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn unset_zone_class(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn origin(&self) -> Option<&common_types::DnsName> {
|
||||
self.origin.as_ref()
|
||||
}
|
||||
|
||||
pub fn set_origin(&mut self, origin: common_types::DnsName) -> &mut Self {
|
||||
self.origin = Some(origin);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn unset_origin(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn record_type(&self) -> Option<common_types::Type> {
|
||||
self.record_type
|
||||
}
|
||||
|
||||
pub fn set_record_type(&mut self, record_type: common_types::Type) -> &mut Self {
|
||||
self.record_type = Some(record_type);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn unset_record_type(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn last_ttl(&self) -> Option<u32> {
|
||||
self.last_ttl
|
||||
}
|
||||
|
||||
pub fn set_last_ttl(&mut self, last_ttl: u32) -> &mut Self {
|
||||
self.last_ttl = Some(last_ttl);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn unset_last_ttl(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DnsTextData {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self>
|
||||
fn dns_parse(context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
;
|
||||
@ -103,12 +170,12 @@ pub trait DnsTextData {
|
||||
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result;
|
||||
}
|
||||
|
||||
pub fn parse<T>(data: &str) -> ::errors::Result<T>
|
||||
pub fn parse_with<'a, F, O>(data: &'a str, parser: F) -> ::errors::Result<O>
|
||||
where
|
||||
T: DnsTextData
|
||||
for<'b> F: FnOnce(&'b mut &'a str) -> ::errors::Result<O>,
|
||||
{
|
||||
let mut data = data;
|
||||
let result = T::dns_parse(&mut data)?;
|
||||
let result = parser(&mut data)?;
|
||||
let data = data.trim();
|
||||
ensure!(data.is_empty(), "didn't parse complete text, remaining: {:?}", data);
|
||||
Ok(result)
|
||||
|
@ -1,10 +1,10 @@
|
||||
use std::fmt;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, next_field};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field};
|
||||
|
||||
/* only decimal representations are used for numbers */
|
||||
impl DnsTextData for u8 {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
Ok(next_field(data)?.parse()?)
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ impl DnsTextData for u8 {
|
||||
}
|
||||
|
||||
impl DnsTextData for u16 {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
Ok(next_field(data)?.parse()?)
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ impl DnsTextData for u16 {
|
||||
}
|
||||
|
||||
impl DnsTextData for u32 {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
Ok(next_field(data)?.parse()?)
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ impl DnsTextData for u32 {
|
||||
|
||||
/* only decimal representations are needed for octets */
|
||||
impl DnsTextData for Ipv4Addr {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
Ok(next_field(data)?.parse()?)
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ impl DnsTextData for Ipv4Addr {
|
||||
|
||||
/* representation as in RFC 3513: https://tools.ietf.org/html/rfc3513#section-2.2 */
|
||||
impl DnsTextData for Ipv6Addr {
|
||||
fn dns_parse(data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
Ok(next_field(data)?.parse()?)
|
||||
}
|
||||
|
||||
@ -60,8 +60,9 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
fn deserialize<T: DnsTextData>(data: &str) -> ::errors::Result<T> {
|
||||
let context = DnsTextContext::new();
|
||||
let mut data = data;
|
||||
let res = T::dns_parse(&mut data)?;
|
||||
let res = T::dns_parse(&context, &mut data)?;
|
||||
let data = data.trim();
|
||||
ensure!(data.is_empty(), "didn't read data completely");
|
||||
Ok(res)
|
||||
|
@ -28,7 +28,7 @@ pub fn build(ast: &syn::DeriveInput) -> quote::Tokens {
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
|
||||
parse_fields = quote!{#parse_fields
|
||||
#field_name: DnsTextData::dns_parse(_data).with_context(|_| format!("failed parsing field {}::{}", stringify!(#name), stringify!(#field_name)))?,
|
||||
#field_name: DnsTextData::dns_parse(_context, _data).with_context(|_| format!("failed parsing field {}::{}", stringify!(#name), stringify!(#field_name)))?,
|
||||
};
|
||||
|
||||
format_fields = quote!{#format_fields
|
||||
@ -39,7 +39,7 @@ pub fn build(ast: &syn::DeriveInput) -> quote::Tokens {
|
||||
quote!{
|
||||
#[allow(unused_imports)]
|
||||
impl ::dnsbox_base::ser::DnsTextData for #name {
|
||||
fn dns_parse(_data: &mut &str) -> ::dnsbox_base::errors::Result<Self> {
|
||||
fn dns_parse(_context: &::dnsbox_base::ser::text::DnsTextContext, _data: &mut &str) -> ::dnsbox_base::errors::Result<Self> {
|
||||
use dnsbox_base::failure::ResultExt;
|
||||
use dnsbox_base::ser::DnsTextData;
|
||||
Ok(#name{ #parse_fields })
|
||||
|
Loading…
Reference in New Issue
Block a user