step
This commit is contained in:
parent
e8df03648a
commit
5a15519480
@ -1,8 +1,8 @@
|
||||
use bytes::Bytes;
|
||||
use bytes::{Bytes, BufMut};
|
||||
use data_encoding::{self, HEXLOWER_PERMISSIVE};
|
||||
use errors::*;
|
||||
use failure::{Fail, ResultExt};
|
||||
use ser::packet::{DnsPacketData, remaining_bytes, short_blob};
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes, short_blob, write_short_blob};
|
||||
use ser::text::*;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
@ -37,6 +37,10 @@ impl DnsPacketData for HexShortBlob {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
Ok(HexShortBlob(short_blob(data)?))
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
write_short_blob(&self.0, packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for HexShortBlob {
|
||||
@ -73,6 +77,12 @@ impl DnsPacketData for Base64RemainingBlob {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
Ok(Base64RemainingBlob(remaining_bytes(data)))
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
packet.reserve(self.0.len());
|
||||
packet.put_slice(&self.0);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for Base64RemainingBlob {
|
||||
@ -98,6 +108,12 @@ impl DnsPacketData for HexRemainingBlob {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
Ok(HexRemainingBlob(remaining_bytes(data)))
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
packet.reserve(self.0.len());
|
||||
packet.put_slice(&self.0);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for HexRemainingBlob {
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use bytes::Bytes;
|
||||
use errors::*;
|
||||
use ser::DnsPacketData;
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field};
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
@ -201,6 +201,10 @@ impl DnsPacketData for Class {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
Ok(Class(DnsPacketData::deserialize(data)?))
|
||||
}
|
||||
|
||||
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
self.0.serialize(context, packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for Class {
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
use bytes::Bytes;
|
||||
use errors::*;
|
||||
use ser::DnsPacketData;
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext};
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
@ -29,7 +29,7 @@ enum LabelOffset {
|
||||
#[derive(Clone,PartialEq,Eq,PartialOrd,Ord,Hash,Debug)]
|
||||
enum LabelOffsets {
|
||||
Uncompressed(SmallVec<[u8;16]>),
|
||||
Compressed(usize, SmallVec<[LabelOffset;8]>),
|
||||
Compressed(usize, SmallVec<[LabelOffset;4]>),
|
||||
}
|
||||
|
||||
impl LabelOffsets {
|
||||
@ -65,7 +65,7 @@ impl LabelOffsets {
|
||||
///
|
||||
/// Uses the "original" raw representation for storage (i.e. can share
|
||||
/// memory with a parsed packet)
|
||||
#[derive(Clone,Hash)]
|
||||
#[derive(Clone)]
|
||||
pub struct DnsName {
|
||||
// in uncompressed form always includes terminating null octect;
|
||||
// but even in uncompressed form can include unused bytes at the
|
||||
@ -198,6 +198,10 @@ impl DnsPacketData for DnsName {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
DnsName::parse_name(data, false)
|
||||
}
|
||||
|
||||
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
context.write_uncompressed_name(packet, self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Similar to `DnsName`, but allows using compressed labels in the
|
||||
@ -264,6 +268,10 @@ impl DnsPacketData for DnsCompressedName {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
Ok(DnsCompressedName(DnsName::parse_name(data, true)?))
|
||||
}
|
||||
|
||||
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
context.write_compressed_name(packet, self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator type for [`DnsName::labels`]
|
||||
|
@ -1,9 +1,9 @@
|
||||
use bytes::{Bytes, Buf};
|
||||
use bytes::{Bytes, Buf, BufMut};
|
||||
use common_types::Type;
|
||||
use data_encoding;
|
||||
use errors::*;
|
||||
use failure::{Fail, ResultExt};
|
||||
use ser::packet::{DnsPacketData, remaining_bytes, short_blob};
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes, short_blob, write_short_blob};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, skip_whitespace, next_field};
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt;
|
||||
@ -100,6 +100,12 @@ impl DnsPacketData for NsecTypeBitmap {
|
||||
set: set,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
packet.reserve(self.raw.len());
|
||||
packet.put_slice(&self.raw);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for NsecTypeBitmap {
|
||||
@ -134,6 +140,11 @@ impl DnsPacketData for NextHashedOwnerName {
|
||||
ensure!(text.len() > 0, "NextHashedOwnerName must not be empty");
|
||||
Ok(NextHashedOwnerName(text))
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
ensure!(self.0.len() > 0, "NextHashedOwnerName must not be empty");
|
||||
write_short_blob(&self.0, packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for NextHashedOwnerName {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use bytes::{Bytes, Buf};
|
||||
use bytes::{Bytes, Buf, BufMut};
|
||||
use common_types::Type;
|
||||
use errors::*;
|
||||
use ser::packet::{DnsPacketData, remaining_bytes};
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, skip_whitespace};
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt;
|
||||
@ -72,6 +72,12 @@ impl DnsPacketData for NxtTypeBitmap {
|
||||
set: set,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
packet.reserve(self.raw.len());
|
||||
packet.put_slice(&self.raw);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for NxtTypeBitmap {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use bytes::{Bytes, Buf};
|
||||
use bytes::{Bytes, Buf, BufMut};
|
||||
use errors::*;
|
||||
use ser::packet::{DnsPacketData, short_blob, remaining_bytes};
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext, short_blob, write_short_blob, remaining_bytes};
|
||||
use ser::text::*;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
@ -13,6 +13,10 @@ impl DnsPacketData for ShortText {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
Ok(ShortText(short_blob(data)?))
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
write_short_blob(&self.0, packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for ShortText {
|
||||
@ -43,6 +47,14 @@ impl DnsPacketData for LongText {
|
||||
}
|
||||
Ok(LongText(texts))
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
ensure!(self.0.len() > 0, "empty LongText not allowed");
|
||||
for t in &self.0 {
|
||||
write_short_blob(t, packet)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for LongText {
|
||||
@ -77,6 +89,10 @@ impl DnsPacketData for UnquotedShortText {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
Ok(UnquotedShortText(short_blob(data)?))
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
write_short_blob(&self.0, packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for UnquotedShortText {
|
||||
@ -102,6 +118,12 @@ impl DnsPacketData for RemainingText {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
Ok(RemainingText(remaining_bytes(data)))
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
packet.reserve(self.0.len());
|
||||
packet.put_slice(&self.0);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for RemainingText {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use bytes::Bytes;
|
||||
use errors::*;
|
||||
use ser::packet::DnsPacketData;
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field};
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
@ -15,6 +15,10 @@ impl DnsPacketData for Time {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
Ok(Time(DnsPacketData::deserialize(data)?))
|
||||
}
|
||||
|
||||
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
self.0.serialize(context, packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for Time {
|
||||
|
@ -3,7 +3,7 @@
|
||||
use bytes::Bytes;
|
||||
use errors::*;
|
||||
use records::registry::{lookup_type_to_name, lookup_type_name};
|
||||
use ser::DnsPacketData;
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
@ -573,6 +573,10 @@ impl DnsPacketData for Type {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
Ok(Type(DnsPacketData::deserialize(data)?))
|
||||
}
|
||||
|
||||
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
self.0.serialize(context, packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for Type {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use bytes::Bytes;
|
||||
use bytes::{Bytes, BufMut};
|
||||
use errors::*;
|
||||
use ser::packet::{DnsPacketData, remaining_bytes};
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes};
|
||||
use ser::text::*;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
@ -21,6 +21,13 @@ impl DnsPacketData for UriText {
|
||||
ensure!(!raw.is_empty(), "URI must not be empty");
|
||||
Ok(UriText(raw))
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
ensure!(self.0.is_empty(), "URI must not be empty");
|
||||
packet.reserve(self.0.len());
|
||||
packet.put_slice(&self.0);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for UriText {
|
||||
|
@ -1,9 +1,9 @@
|
||||
use bytes::Bytes;
|
||||
use bytes::{Bytes, BufMut};
|
||||
use common_types::*;
|
||||
use common_types::binary::HEXLOWER_PERMISSIVE_ALLOW_WS;
|
||||
use errors::*;
|
||||
use failure::{ResultExt, Fail};
|
||||
use ser::packet::remaining_bytes;
|
||||
use ser::packet::{DnsPacketWriteContext, remaining_bytes};
|
||||
use ser::{RRData, RRDataPacket, RRDataText};
|
||||
use ser::text::{DnsTextFormatter, DnsTextContext, next_field};
|
||||
use std::borrow::Cow;
|
||||
@ -54,6 +54,12 @@ impl RRDataPacket for UnknownRecord {
|
||||
fn rr_type(&self) -> Type {
|
||||
self.rr_type
|
||||
}
|
||||
|
||||
fn serialize_rr_data(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
packet.reserve(self.raw.len());
|
||||
packet.put_slice(&self.raw);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl RRDataText for UnknownRecord {
|
||||
@ -69,7 +75,7 @@ impl RRDataText for UnknownRecord {
|
||||
UnknownRecord::dns_parse(t, data)
|
||||
}
|
||||
|
||||
// format might fail if there is no (known) text representation.
|
||||
/// this must never fail unless the underlying buffer fails.
|
||||
fn dns_format_rr_data(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
||||
write!(f, "\\# {} {}", self.raw.len(), HEXLOWER_PERMISSIVE_ALLOW_WS.encode(&self.raw))
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
use bytes::{Bytes, Buf};
|
||||
use bytes::{Bytes, Buf, BufMut};
|
||||
use errors::*;
|
||||
use common_types::*;
|
||||
use failure::ResultExt;
|
||||
use ser::DnsPacketData;
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext};
|
||||
use std::fmt;
|
||||
use std::io::Read;
|
||||
@ -22,7 +23,7 @@ pub enum LOC {
|
||||
}
|
||||
|
||||
impl DnsPacketData for LOC {
|
||||
fn deserialize(data: &mut ::std::io::Cursor<Bytes>) -> ::errors::Result<Self> {
|
||||
fn deserialize(data: &mut ::std::io::Cursor<Bytes>) -> Result<Self> {
|
||||
let version: u8 = DnsPacketData::deserialize(data)?;
|
||||
if 0 == version {
|
||||
Ok(LOC::Version0(DnsPacketData::deserialize(data)?))
|
||||
@ -33,10 +34,26 @@ impl DnsPacketData for LOC {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
match *self {
|
||||
LOC::Version0(ref l0) => {
|
||||
packet.reserve(1);
|
||||
packet.put_u8(0);
|
||||
l0.serialize(context, packet)
|
||||
},
|
||||
LOC::UnknownVersion{version, ref data} => {
|
||||
packet.reserve(data.len() + 1);
|
||||
packet.put_u8(version);
|
||||
packet.put_slice(data);
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for LOC {
|
||||
fn dns_parse(_context: &DnsTextContext, _data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(_context: &DnsTextContext, _data: &mut &str) -> Result<Self> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@ -67,7 +84,7 @@ pub struct A6 {
|
||||
}
|
||||
|
||||
impl DnsPacketData for A6 {
|
||||
fn deserialize(data: &mut ::std::io::Cursor<Bytes>) -> ::errors::Result<Self> {
|
||||
fn deserialize(data: &mut ::std::io::Cursor<Bytes>) -> Result<Self> {
|
||||
let prefix: u8 = DnsPacketData::deserialize(data)
|
||||
.context("failed parsing field A6::prefix")?;
|
||||
ensure!(prefix <= 128, "invalid A6::prefix {}", prefix);
|
||||
@ -98,10 +115,24 @@ impl DnsPacketData for A6 {
|
||||
prefix_name,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
let suffix_offset = (self.prefix / 8) as usize;
|
||||
debug_assert!(suffix_offset <= 16);
|
||||
let suffix = self.dirty_suffix.octets();
|
||||
let suffix_data = &suffix[suffix_offset..];
|
||||
packet.reserve(1 /* prefix */ + suffix_data.len());
|
||||
packet.put_u8(self.prefix);
|
||||
packet.put_slice(suffix_data);
|
||||
if let Some(ref n) = self.prefix_name {
|
||||
n.serialize(context, packet)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsTextData for A6 {
|
||||
fn dns_parse(context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
|
||||
fn dns_parse(context: &DnsTextContext, data: &mut &str) -> Result<Self> {
|
||||
let prefix: u8 = DnsTextData::dns_parse(context, data)
|
||||
.context("failed parsing field A6::prefix")?;
|
||||
ensure!(prefix <= 128, "invalid A6::prefix {}", prefix);
|
||||
|
@ -2,6 +2,4 @@ pub mod packet;
|
||||
pub mod text;
|
||||
mod rrdata;
|
||||
|
||||
pub use self::packet::DnsPacketData;
|
||||
pub use self::text::DnsTextData;
|
||||
pub use self::rrdata::{RRDataPacket, RRDataText, RRData, StaticRRData};
|
||||
|
@ -1,11 +1,15 @@
|
||||
use bytes::{Bytes, Buf};
|
||||
use bytes::{Bytes, Buf, BufMut};
|
||||
use errors::*;
|
||||
use std::io::Cursor;
|
||||
|
||||
mod std_impls;
|
||||
mod write;
|
||||
|
||||
pub use self::write::*;
|
||||
|
||||
pub trait DnsPacketData: Sized {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self>;
|
||||
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()>;
|
||||
}
|
||||
|
||||
pub fn deserialize_with<F, O>(data: Bytes, parser: F) -> Result<O>
|
||||
@ -37,3 +41,11 @@ pub fn short_blob(data: &mut Cursor<Bytes>) -> Result<Bytes> {
|
||||
data.advance(blob_len);
|
||||
Ok(blob)
|
||||
}
|
||||
|
||||
pub fn write_short_blob(data: &[u8], packet: &mut Vec<u8>) -> Result<()> {
|
||||
ensure!(data.len() < 256, "short blob must be at most 255 bytes long");
|
||||
packet.reserve(data.len() + 1);
|
||||
packet.put_u8(data.len() as u8);
|
||||
packet.put_slice(data);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use bytes::{Bytes,Buf,BigEndian};
|
||||
use bytes::{Bytes, Buf, BufMut, BigEndian};
|
||||
use errors::*;
|
||||
use ser::packet::DnsPacketData;
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext};
|
||||
use std::io::{Cursor, Read};
|
||||
use std::mem::size_of;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
@ -10,6 +10,12 @@ impl DnsPacketData for u8 {
|
||||
check_enough_data!(data, size_of::<Self>(), "u8");
|
||||
Ok(data.get_u8())
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
packet.reserve(size_of::<Self>());
|
||||
packet.put_u8(*self);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsPacketData for u16 {
|
||||
@ -17,6 +23,12 @@ impl DnsPacketData for u16 {
|
||||
check_enough_data!(data, size_of::<Self>(), "u16");
|
||||
Ok(data.get_u16::<BigEndian>())
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
packet.reserve(size_of::<Self>());
|
||||
packet.put_u16::<BigEndian>(*self);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsPacketData for u32 {
|
||||
@ -24,6 +36,12 @@ impl DnsPacketData for u32 {
|
||||
check_enough_data!(data, size_of::<Self>(), "u32");
|
||||
Ok(data.get_u32::<BigEndian>())
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
packet.reserve(size_of::<Self>());
|
||||
packet.put_u32::<BigEndian>(*self);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsPacketData for Ipv4Addr {
|
||||
@ -31,6 +49,14 @@ impl DnsPacketData for Ipv4Addr {
|
||||
check_enough_data!(data, size_of::<u32>(), "Ipv4Addr");
|
||||
Ok(data.get_u32::<BigEndian>().into())
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
let data = self.octets();
|
||||
debug_assert!(data.len() == 4);
|
||||
packet.reserve(data.len());
|
||||
packet.put_slice(&data);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsPacketData for Ipv6Addr {
|
||||
@ -40,6 +66,14 @@ impl DnsPacketData for Ipv6Addr {
|
||||
data.read_exact(&mut buf)?;
|
||||
Ok(buf.into())
|
||||
}
|
||||
|
||||
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
let data = self.octets();
|
||||
debug_assert!(data.len() == 16);
|
||||
packet.reserve(data.len());
|
||||
packet.put_slice(&data);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
184
lib/dnsbox-base/src/ser/packet/write.rs
Normal file
184
lib/dnsbox-base/src/ser/packet/write.rs
Normal file
@ -0,0 +1,184 @@
|
||||
use bytes::{BufMut, BigEndian};
|
||||
use errors::*;
|
||||
use common_types::name::{DnsName, DnsCompressedName, DnsLabelRef};
|
||||
|
||||
// only points to uncompressed labels; if a label of a name is stored,
|
||||
// all following labels must be stored too, even if their pos >= 0x4000.
|
||||
//
|
||||
// the entries are ordered by pos.
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
struct LabelEntry {
|
||||
pos: usize, // serialized at position in packet
|
||||
next_entry: usize, // offset in labels vector; points to itself for TLD
|
||||
}
|
||||
|
||||
impl LabelEntry {
|
||||
fn label_ref<'a>(&self, packet: &'a Vec<u8>) -> DnsLabelRef<'a> {
|
||||
let p = self.pos as usize;
|
||||
let len = packet[p] as usize;
|
||||
DnsLabelRef::new(&packet[p+1..][..len]).unwrap()
|
||||
}
|
||||
|
||||
fn next(&self, labels: &Vec<LabelEntry>) -> Option<Self> {
|
||||
let next = labels[self.next_entry as usize];
|
||||
if next.pos == self.pos {
|
||||
None
|
||||
} else {
|
||||
Some(next)
|
||||
}
|
||||
}
|
||||
|
||||
fn matches(&self, packet: &Vec<u8>, labels: &Vec<LabelEntry>, name: &DnsName, min: u8) -> Option<u8> {
|
||||
'outer: for i in 0..min {
|
||||
if name.label_ref(i) != self.label_ref(packet) {
|
||||
continue;
|
||||
}
|
||||
let mut l = *self;
|
||||
for j in i+1..name.label_count() {
|
||||
l = match l.next(labels) {
|
||||
None => continue 'outer,
|
||||
Some(l) => l,
|
||||
};
|
||||
if name.label_ref(j) != l.label_ref(packet) {
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
match l.next(labels) {
|
||||
None => return Some(i),
|
||||
Some(_) => (),
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn write_label(packet: &mut Vec<u8>, label: DnsLabelRef) {
|
||||
let l = label.len();
|
||||
debug_assert!(l < 64);
|
||||
packet.reserve(l as usize + 1);
|
||||
packet.put_u8(l);
|
||||
packet.put_slice(label.as_raw());
|
||||
}
|
||||
|
||||
fn write_name(packet: &mut Vec<u8>, name: &DnsName) {
|
||||
for label in name {
|
||||
write_label(packet, label);
|
||||
}
|
||||
packet.reserve(1);
|
||||
packet.put_u8(0);
|
||||
}
|
||||
|
||||
fn write_label_remember(packet: &mut Vec<u8>, labels: &mut Vec<LabelEntry>, label: DnsLabelRef, next_entry: usize) {
|
||||
labels.push(LabelEntry {
|
||||
pos: packet.len(),
|
||||
next_entry: next_entry,
|
||||
});
|
||||
write_label(packet, label);
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct DnsPacketWriteContext {
|
||||
labels: Option<Vec<LabelEntry>>,
|
||||
}
|
||||
|
||||
impl DnsPacketWriteContext {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn enable_compression(&mut self) {
|
||||
self.labels = Some(Vec::new());
|
||||
}
|
||||
|
||||
pub fn write_uncompressed_name(&mut self, packet: &mut Vec<u8>, name: &DnsName) -> Result<()> {
|
||||
// for now we don't remember labels of these names.
|
||||
//
|
||||
// if we did: would we want to check whether a suffix is already
|
||||
// known before we store a new variant? the list could grow big
|
||||
// with duplicates...
|
||||
write_name(packet, name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_compressed_name(&mut self, packet: &mut Vec<u8>, name: &DnsCompressedName) -> Result<()> {
|
||||
if name.is_root() {
|
||||
write_name(packet, name);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let labels = match self.labels {
|
||||
Some(ref mut labels) => labels,
|
||||
None => {
|
||||
// compression disabled
|
||||
write_name(packet, name);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let mut best_match = None;
|
||||
let mut best_match_len = name.label_count();
|
||||
|
||||
for (e_ndx, e) in (labels as &Vec<LabelEntry>).into_iter().enumerate() {
|
||||
if e.pos >= 0x4000 { break; } // this and following labels can't be used for compression
|
||||
if let Some(l) = e.matches(packet, labels, name, best_match_len) {
|
||||
debug_assert!(l < best_match_len);
|
||||
best_match_len = l;
|
||||
best_match = Some(e_ndx);
|
||||
if best_match_len == 0 {
|
||||
// can't improve
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match best_match {
|
||||
Some(e_ndx) => {
|
||||
// found compressable suffix
|
||||
if best_match_len > 0 {
|
||||
// but not for complete name, need to write some labels
|
||||
if packet.len() < 0x4000 {
|
||||
// remember labels
|
||||
for i in 0..best_match_len - 1 {
|
||||
let n = labels.len() + 1; // next label follows directly
|
||||
write_label_remember(packet, labels, name.label_ref(i), n);
|
||||
}
|
||||
// the next label following is at e_ndx
|
||||
write_label_remember(packet, labels, name.label_ref(best_match_len-1), e_ndx);
|
||||
} else {
|
||||
// no need to remember, can't be used for compression
|
||||
for i in 0..best_match_len {
|
||||
write_label(packet, name.label_ref(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
let p = labels[e_ndx].pos;
|
||||
debug_assert!(p < 0x4000);
|
||||
packet.reserve(2);
|
||||
packet.put_u16::<BigEndian>(0xc000 | p as u16);
|
||||
},
|
||||
None => {
|
||||
// no suffix written already
|
||||
debug_assert!(best_match_len > 0);
|
||||
debug_assert!(best_match_len == name.label_count());
|
||||
if packet.len() < 0x4000 {
|
||||
// remember all labels for the name
|
||||
for i in 0..best_match_len - 1 {
|
||||
let n = labels.len() + 1; // next label follows directly
|
||||
write_label_remember(packet, labels, name.label_ref(i), n);
|
||||
}
|
||||
// the next label is the TLD
|
||||
let n = labels.len(); // point to itself
|
||||
write_label_remember(packet, labels, name.label_ref(best_match_len-1), n);
|
||||
// terminate name
|
||||
packet.reserve(1);
|
||||
packet.put_u8(0);
|
||||
} else {
|
||||
// no need to remember, can't be used for compression
|
||||
write_name(packet, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
use bytes::Bytes;
|
||||
use common_types::{Class, Type, classes};
|
||||
use errors::*;
|
||||
use ser::DnsPacketData;
|
||||
use ser::packet::{DnsPacketData, DnsPacketWriteContext};
|
||||
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
use records::UnknownRecord;
|
||||
|
||||
pub trait RRDataPacket {
|
||||
fn deserialize_rr_data(ttl: u32, rr_class: Class, rr_type: Type, data: &mut Cursor<Bytes>) -> Result<Self>
|
||||
@ -14,6 +15,8 @@ pub trait RRDataPacket {
|
||||
;
|
||||
|
||||
fn rr_type(&self) -> Type;
|
||||
|
||||
fn serialize_rr_data(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()>;
|
||||
}
|
||||
|
||||
impl<T: DnsPacketData + StaticRRData> RRDataPacket for T {
|
||||
@ -28,6 +31,10 @@ impl<T: DnsPacketData + StaticRRData> RRDataPacket for T {
|
||||
fn rr_type(&self) -> Type {
|
||||
T::TYPE
|
||||
}
|
||||
|
||||
fn serialize_rr_data(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
||||
self.serialize(context, packet)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RRDataText {
|
||||
@ -42,7 +49,10 @@ pub trait RRDataText {
|
||||
fn rr_type_txt(&self) -> Cow<'static, str>;
|
||||
|
||||
// (type, rrdata)
|
||||
fn text(&self) -> Result<(String, String)> {
|
||||
fn text(&self) -> Result<(String, String)>
|
||||
where
|
||||
Self: RRDataPacket,
|
||||
{
|
||||
let mut buf = String::new();
|
||||
match self.dns_format_rr_data(&mut DnsTextFormatter::new(&mut buf)) {
|
||||
Ok(()) => {
|
||||
@ -50,8 +60,13 @@ pub trait RRDataText {
|
||||
},
|
||||
Err(_) => (),
|
||||
}
|
||||
let mut raw = Vec::new();
|
||||
self.serialize_rr_data(&mut DnsPacketWriteContext::new(), &mut raw)?;
|
||||
let ur = UnknownRecord::new(self.rr_type(), raw.into());
|
||||
// formatting UnknownRecord should not fail
|
||||
buf.clear();
|
||||
unimplemented!()
|
||||
self.dns_format_rr_data(&mut DnsTextFormatter::new(&mut buf)).unwrap();
|
||||
Ok((ur.rr_type_txt().into(), buf))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,23 +23,37 @@ pub fn build(ast: &syn::DeriveInput) -> quote::Tokens {
|
||||
let name = &ast.ident;
|
||||
|
||||
let mut parse_fields = quote!{};
|
||||
let mut serialize_fields = quote!{};
|
||||
for field in fields {
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
let ctx_msg = format!("failed parsing field {}::{}", name, field_name);
|
||||
let parse_ctx_msg = format!("failed parsing field {}::{}", name, field_name);
|
||||
let serialize_ctx_msg = format!("failed serializing field {}::{}", name, field_name);
|
||||
|
||||
parse_fields = quote!{#parse_fields
|
||||
#field_name: DnsPacketData::deserialize(_data).context(#ctx_msg)?,
|
||||
#field_name: DnsPacketData::deserialize(_data).context(#parse_ctx_msg)?,
|
||||
};
|
||||
|
||||
serialize_fields = quote!{#serialize_fields
|
||||
self.#field_name.serialize(_context, _packet).context(#serialize_ctx_msg)?;
|
||||
};
|
||||
}
|
||||
|
||||
quote!{
|
||||
impl ::dnsbox_base::ser::DnsPacketData for #name {
|
||||
impl ::dnsbox_base::ser::packet::DnsPacketData for #name {
|
||||
#[allow(unused_imports)]
|
||||
fn deserialize(_data: &mut ::std::io::Cursor<::dnsbox_base::bytes::Bytes>) -> ::dnsbox_base::errors::Result<Self> {
|
||||
use ::dnsbox_base::failure::ResultExt;
|
||||
use ::dnsbox_base::ser::DnsPacketData;
|
||||
use ::dnsbox_base::ser::packet::DnsPacketData;
|
||||
Ok(#name{ #parse_fields })
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
fn serialize(&self, _context: &mut ::dnsbox_base::ser::packet::DnsPacketWriteContext, _packet: &mut Vec<u8>) -> ::dnsbox_base::errors::Result<()> {
|
||||
use ::dnsbox_base::failure::ResultExt;
|
||||
use ::dnsbox_base::ser::packet::DnsPacketData;
|
||||
#serialize_fields
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,15 +38,15 @@ pub fn build(ast: &syn::DeriveInput) -> quote::Tokens {
|
||||
|
||||
quote!{
|
||||
#[allow(unused_imports)]
|
||||
impl ::dnsbox_base::ser::DnsTextData for #name {
|
||||
impl ::dnsbox_base::ser::text::DnsTextData for #name {
|
||||
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;
|
||||
use dnsbox_base::ser::text::DnsTextData;
|
||||
Ok(#name{ #parse_fields })
|
||||
}
|
||||
|
||||
fn dns_format(&self, f: &mut ::dnsbox_base::ser::text::DnsTextFormatter) -> ::std::fmt::Result {
|
||||
use dnsbox_base::ser::DnsTextData;
|
||||
use dnsbox_base::ser::text::DnsTextData;
|
||||
use std::fmt::{self, Write};
|
||||
#format_fields
|
||||
Ok(())
|
||||
|
Loading…
Reference in New Issue
Block a user