use crate::common_types::binary::HEXLOWER_PERMISSIVE_ALLOW_WS; use crate::common_types::*; use crate::errors::*; use crate::ser::packet::{remaining_bytes, DnsPacketWriteContext}; use crate::ser::text::{next_field, DnsTextContext, DnsTextFormatter}; use crate::ser::{RRData, RRDataPacket, RRDataText}; use bytes::{BufMut, Bytes}; use failure::{Fail, ResultExt}; use std::borrow::Cow; use std::fmt; use std::io::Cursor; #[derive(Clone, PartialEq, Eq, Debug)] pub struct UnknownRecord { rr_type: Type, raw: Bytes, } impl UnknownRecord { pub fn new(rr_type: Type, raw: Bytes) -> Self { UnknownRecord { rr_type: rr_type, raw: raw, } } pub fn raw(&self) -> &Bytes { &self.raw } pub fn deserialize(rr_type: Type, data: &mut ::std::io::Cursor) -> Result { Ok(UnknownRecord::new(rr_type, remaining_bytes(data))) } pub fn dns_parse(rr_type: Type, data: &mut &str) -> Result { let field = next_field(data)?; failure::ensure!(field == r"\#", "expect \\# token to mark generic encoding"); let field = next_field(data).context("generic record data length")?; let len: usize = field.parse()?; let result = HEXLOWER_PERMISSIVE_ALLOW_WS .decode(data.as_bytes()) .with_context(|e| e.context(format!("invalid hex: {:?}", data)))?; failure::ensure!( len == result.len(), "length {} doesn't match length of encoded data {}", len, result.len() ); *data = ""; // read all data Ok(UnknownRecord { rr_type, raw: result.into(), }) } } impl RRDataPacket for UnknownRecord { fn deserialize_rr_data( _ttl: u32, _rr_class: Class, rr_type: Type, data: &mut Cursor, ) -> Result { UnknownRecord::deserialize(rr_type, data) } fn rr_type(&self) -> Type { self.rr_type } fn serialize_rr_data( &self, _context: &mut DnsPacketWriteContext, packet: &mut Vec, ) -> Result<()> { packet.reserve(self.raw.len()); packet.put_slice(&self.raw); Ok(()) } } impl RRDataText for UnknownRecord { fn dns_parse_rr_data(context: &DnsTextContext, data: &mut &str) -> Result where Self: Sized, { let t = match context.record_type() { Some(t) => t, None => failure::bail!("must parse DNS record with record type context"), }; UnknownRecord::dns_parse(t, data) } /// 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) ) } fn rr_type_txt(&self) -> Cow<'static, str> { Cow::Owned(self.rr_type.generic_name()) } } impl RRData for UnknownRecord { fn clone_box(&self) -> Box { Box::new(self.clone()) as _ } fn as_any(&self) -> &dyn ::std::any::Any { self as _ } fn as_box_any(self: Box) -> Box { self as _ } }