You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
2.5 KiB
92 lines
2.5 KiB
use bytes::{Bytes, BufMut}; |
|
use common_types::*; |
|
use common_types::binary::HEXLOWER_PERMISSIVE_ALLOW_WS; |
|
use errors::*; |
|
use failure::{ResultExt, Fail}; |
|
use ser::packet::{DnsPacketWriteContext, remaining_bytes}; |
|
use ser::{RRData, RRDataPacket, RRDataText}; |
|
use ser::text::{DnsTextFormatter, DnsTextContext, next_field}; |
|
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 deserialize(rr_type: Type, data: &mut ::std::io::Cursor<Bytes>) -> Result<Self> { |
|
Ok(UnknownRecord::new(rr_type, remaining_bytes(data))) |
|
} |
|
|
|
pub fn dns_parse(rr_type: Type, data: &mut &str) -> Result<Self> { |
|
let field = next_field(data)?; |
|
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)))?; |
|
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<Bytes>) -> Result<Self> { |
|
UnknownRecord::deserialize(rr_type, data) |
|
} |
|
|
|
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 { |
|
fn dns_parse_rr_data(context: &DnsTextContext, data: &mut &str) -> Result<Self> |
|
where |
|
Self: Sized, |
|
{ |
|
let t = match context.record_type() { |
|
Some(t) => t, |
|
None => 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<RRData> { |
|
Box::new(self.clone()) as _ |
|
} |
|
}
|
|
|