185 lines
4.6 KiB
Rust
185 lines
4.6 KiB
Rust
use bytes::{Bytes, Buf, BufMut};
|
|
use errors::*;
|
|
use common_types::*;
|
|
use failure::ResultExt;
|
|
use ser::packet::{DnsPacketData, DnsPacketWriteContext};
|
|
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext};
|
|
use std::fmt;
|
|
use std::io::Read;
|
|
use std::net::Ipv6Addr;
|
|
|
|
// deriving RRData will add a unit test to make sure the type is
|
|
// registered; there must be a records::types::$name `Type` constant
|
|
// with the same name as the struct.
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, RRData)]
|
|
#[RRClass(ANY)]
|
|
pub enum LOC {
|
|
Version0(LOC0),
|
|
UnknownVersion{
|
|
version: u8,
|
|
data: Bytes,
|
|
},
|
|
}
|
|
|
|
impl DnsPacketData for LOC {
|
|
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)?))
|
|
} else {
|
|
Ok(LOC::UnknownVersion{
|
|
version: version,
|
|
data: ::ser::packet::remaining_bytes(data),
|
|
})
|
|
}
|
|
}
|
|
|
|
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) -> Result<Self> {
|
|
unimplemented!()
|
|
}
|
|
|
|
fn dns_format(&self, _f: &mut DnsTextFormatter) -> fmt::Result {
|
|
// always prefer binary representation
|
|
Err(fmt::Error)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData)]
|
|
pub struct LOC0 {
|
|
size: u8,
|
|
horizontal_precision: u8,
|
|
vertical_precision: u8,
|
|
latitude: u32,
|
|
longitude: u32,
|
|
altitude: u32,
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, RRData)]
|
|
#[RRClass(IN)]
|
|
pub struct A6 {
|
|
prefix: u8, // [0...128]
|
|
// might include non-zero padding
|
|
dirty_suffix: Ipv6Addr,
|
|
suffix: Ipv6Addr,
|
|
prefix_name: Option<DnsCanonicalName>,
|
|
}
|
|
|
|
impl DnsPacketData for A6 {
|
|
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);
|
|
let suffix_offset = (prefix / 8) as usize;
|
|
debug_assert!(suffix_offset <= 16);
|
|
let suffix_len = 16 - suffix_offset;
|
|
check_enough_data!(data, suffix_len, "A6::suffix");
|
|
let mut addr = [0u8; 16];
|
|
data.read_exact(&mut addr[suffix_offset..16])?;
|
|
|
|
let dirty_suffix = Ipv6Addr::from(addr);
|
|
if suffix_offset < 16 {
|
|
let mask = 0xff >> (prefix % 8);
|
|
addr[suffix_offset] &= mask;
|
|
}
|
|
let suffix = Ipv6Addr::from(addr);
|
|
|
|
let prefix_name = if data.has_remaining() {
|
|
Some(DnsPacketData::deserialize(data)?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
Ok(A6 {
|
|
prefix,
|
|
dirty_suffix,
|
|
suffix,
|
|
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) -> 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(context, data)
|
|
.context("failed parsing field A6::suffix")?;
|
|
|
|
// clear prefix bits
|
|
let mut suffix = suffix.octets();
|
|
for i in 0..suffix_offset {
|
|
suffix[i] = 0;
|
|
}
|
|
if suffix_offset < 16 {
|
|
let mask = 0xff >> (prefix % 8);
|
|
suffix[suffix_offset] &= mask;
|
|
}
|
|
let suffix = Ipv6Addr::from(suffix);
|
|
|
|
let prefix_name = if !data.is_empty() {
|
|
Some(DnsTextData::dns_parse(context, data)
|
|
.context("failed parsing field A6::prefix_name")?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
Ok(A6 {
|
|
prefix,
|
|
dirty_suffix: suffix.clone(),
|
|
suffix,
|
|
prefix_name,
|
|
})
|
|
}
|
|
|
|
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
|
if self.dirty_suffix != self.suffix {
|
|
// parsing text clears the padding, so we would loose data.
|
|
// use binary representation instead.
|
|
return Err(fmt::Error);
|
|
}
|
|
write!(f, "{} {}", self.prefix, self.suffix)?;
|
|
if let Some(ref prefix_name) = self.prefix_name {
|
|
write!(f, "{}", prefix_name)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|