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.

124 lines
2.8 KiB

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<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)?;
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<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 => 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<dyn RRData> {
Box::new(self.clone()) as _
}
fn as_any(&self) -> &dyn ::std::any::Any {
self as _
}
fn as_box_any(self: Box<Self>) -> Box<dyn ::std::any::Any> {
self as _
}
}