use bytes::{Bytes, Buf, BufMut}; use errors::*; use common_types::*; use failure::ResultExt; use ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes}; use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext}; use std::fmt; use std::io::Read; use std::net::{Ipv4Addr, 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) -> Result { let version: u8 = DnsPacketData::deserialize(data)?; if 0 == version { Ok(LOC::Version0(DnsPacketData::deserialize(data)?)) } else { Ok(LOC::UnknownVersion{ version: version, data: remaining_bytes(data), }) } } fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec) -> 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 { 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, } impl DnsPacketData for A6 { fn deserialize(data: &mut ::std::io::Cursor) -> Result { 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) -> 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 { 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(()) } } #[derive(Clone, PartialEq, Eq, Debug)] pub enum IpsecKeyGateway { None, Ipv4(Ipv4Addr), Ipv6(Ipv6Addr), Name(DnsName), } #[derive(Clone, PartialEq, Eq, Debug, RRData)] #[RRClass(ANY)] pub enum IPSECKEY { Known{ precedence: u8, algorithm: u8, gateway: IpsecKeyGateway, public_key: Base64RemainingBlob, }, UnknownGateway{ precedence: u8, gateway_type: u8, algorithm: u8, // length of gateway is unknown, can't split gateway and public key remaining: Bytes, } } impl DnsPacketData for IPSECKEY { fn deserialize(data: &mut ::std::io::Cursor) -> Result { let precedence = u8::deserialize(data)?; let gateway_type = u8::deserialize(data)?; let algorithm = u8::deserialize(data)?; let gateway = match gateway_type { 0 => IpsecKeyGateway::None, 1 => IpsecKeyGateway::Ipv4(Ipv4Addr::deserialize(data)?), 2 => IpsecKeyGateway::Ipv6(Ipv6Addr::deserialize(data)?), 3 => IpsecKeyGateway::Name(DnsName::deserialize(data)?), _ => return Ok(IPSECKEY::UnknownGateway{ precedence, gateway_type, algorithm, remaining: remaining_bytes(data), }), }; Ok(IPSECKEY::Known{ precedence, algorithm, gateway, public_key: Base64RemainingBlob::deserialize(data)?, }) } fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { match *self { IPSECKEY::Known{precedence, algorithm, ref gateway, ref public_key} => { packet.reserve(3); packet.put_u8(precedence); let gateway_type: u8 = match *gateway { IpsecKeyGateway::None => 0, IpsecKeyGateway::Ipv4(_) => 1, IpsecKeyGateway::Ipv6(_) => 2, IpsecKeyGateway::Name(_) => 3, }; packet.put_u8(gateway_type); packet.put_u8(algorithm); match *gateway { IpsecKeyGateway::None => (), IpsecKeyGateway::Ipv4(ref a) => a.serialize(context, packet)?, IpsecKeyGateway::Ipv6(ref a) => a.serialize(context, packet)?, IpsecKeyGateway::Name(ref n) => n.serialize(context, packet)?, }; public_key.serialize(context, packet)?; }, IPSECKEY::UnknownGateway{precedence, gateway_type, algorithm, ref remaining} => { packet.reserve(3 + remaining.len()); packet.put_u8(precedence); packet.put_u8(gateway_type); packet.put_u8(algorithm); packet.put_slice(remaining); } } Ok(()) } } impl DnsTextData for IPSECKEY { fn dns_parse(context: &DnsTextContext, data: &mut &str) -> Result { let precedence = u8::dns_parse(context, data)?; let gateway_type = u8::dns_parse(context, data)?; let algorithm = u8::dns_parse(context, data)?; let gateway = match gateway_type { 0 => IpsecKeyGateway::None, 1 => IpsecKeyGateway::Ipv4(Ipv4Addr::dns_parse(context, data)?), 2 => IpsecKeyGateway::Ipv6(Ipv6Addr::dns_parse(context, data)?), 3 => IpsecKeyGateway::Name(DnsName::dns_parse(context, data)?), _ => bail!("unknown gateway type {} for IPSECKEY", gateway_type), }; Ok(IPSECKEY::Known{ precedence, algorithm, gateway, public_key: Base64RemainingBlob::dns_parse(context, data)?, }) } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { match *self { IPSECKEY::Known{precedence, algorithm, ref gateway, ref public_key} => { let gateway_type: u8 = match *gateway { IpsecKeyGateway::None => 0, IpsecKeyGateway::Ipv4(_) => 1, IpsecKeyGateway::Ipv6(_) => 2, IpsecKeyGateway::Name(_) => 3, }; write!(f, "{} {} {}", precedence, gateway_type, algorithm)?; match *gateway { IpsecKeyGateway::None => (), IpsecKeyGateway::Ipv4(ref a) => a.dns_format(f)?, IpsecKeyGateway::Ipv6(ref a) => a.dns_format(f)?, IpsecKeyGateway::Name(ref n) => n.dns_format(f)?, }; public_key.dns_format(f)?; Ok(()) }, IPSECKEY::UnknownGateway{..} => Err(fmt::Error), } } }