|
|
|
@ -3,7 +3,7 @@ use crate::errors::*;
|
|
|
|
|
use crate::common_types::*; |
|
|
|
|
use failure::ResultExt; |
|
|
|
|
use crate::ser::RRData; |
|
|
|
|
use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes}; |
|
|
|
|
use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes, get_blob}; |
|
|
|
|
use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field}; |
|
|
|
|
use std::fmt; |
|
|
|
|
use std::io::Read; |
|
|
|
@ -360,6 +360,129 @@ impl DnsTextData for A6 {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)] |
|
|
|
|
pub struct AplItem { |
|
|
|
|
pub prefix: cidr::IpCidr, |
|
|
|
|
pub negation: bool, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, RRData)] |
|
|
|
|
#[RRClass(IN)] |
|
|
|
|
pub struct APL { |
|
|
|
|
items: Vec<AplItem>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl DnsPacketData for APL { |
|
|
|
|
fn deserialize(data: &mut ::std::io::Cursor<Bytes>) -> Result<Self> { |
|
|
|
|
let mut items = Vec::new(); |
|
|
|
|
while data.has_remaining() { |
|
|
|
|
let family: u16 = DnsPacketData::deserialize(data) |
|
|
|
|
.context("failed parsing APL::ADDRESSFAMILY")?; |
|
|
|
|
failure::ensure!(family == 1 || family == 2, "unknown APL::ADDRESSFAMILY {}", family); |
|
|
|
|
let prefix: u8 = DnsPacketData::deserialize(data) |
|
|
|
|
.context("failed parsing field APL::PREFIX")?; |
|
|
|
|
let afd_length: u8 = DnsPacketData::deserialize(data) |
|
|
|
|
.context("failed parsing field APL::AFDLENGTH")?; |
|
|
|
|
let negation = 0 != (afd_length & 0x80); |
|
|
|
|
let afd_length = afd_length & 0x7f; |
|
|
|
|
let data = get_blob(data, afd_length as usize)?; |
|
|
|
|
|
|
|
|
|
failure::ensure!(!data.ends_with(b"\0"), "APL::AFDPART ends with trailing zero"); |
|
|
|
|
|
|
|
|
|
let address = if family == 1 { |
|
|
|
|
failure::ensure!(prefix <= 32, "invalid APL::prefix {} for IPv4", prefix); |
|
|
|
|
failure::ensure!((afd_length as u32) * 8 < (prefix as u32) + 7, "APL::AFDPART too long {} for prefix {}", afd_length, prefix); |
|
|
|
|
assert!(afd_length <= 4); |
|
|
|
|
let mut buf = [0u8; 4]; |
|
|
|
|
buf[..data.len()].copy_from_slice(&data); |
|
|
|
|
std::net::IpAddr::from(std::net::Ipv4Addr::from(buf)) |
|
|
|
|
} else { |
|
|
|
|
assert!(family == 2); |
|
|
|
|
failure::ensure!(prefix <= 128, "invalid APL::prefix {} for IPv6", prefix); |
|
|
|
|
failure::ensure!((afd_length as u32) * 8 < (prefix as u32) + 7, "AFD::AFDPART too long {} for prefix {}", afd_length, prefix); |
|
|
|
|
assert!(afd_length <= 16); |
|
|
|
|
let mut buf = [0u8; 16]; |
|
|
|
|
buf[..data.len()].copy_from_slice(&data); |
|
|
|
|
std::net::IpAddr::from(std::net::Ipv6Addr::from(buf)) |
|
|
|
|
}; |
|
|
|
|
use cidr::Cidr; |
|
|
|
|
let prefix = cidr::IpCidr::new(address, prefix)?; |
|
|
|
|
|
|
|
|
|
items.push(AplItem { |
|
|
|
|
prefix, |
|
|
|
|
negation, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
Ok(APL { items }) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> { |
|
|
|
|
use cidr::Cidr; |
|
|
|
|
for item in &self.items { |
|
|
|
|
packet.reserve(4); |
|
|
|
|
packet.put_u16_be(if item.prefix.is_ipv4() { 1 } else { 2 }); |
|
|
|
|
packet.put_u8(item.prefix.network_length()); |
|
|
|
|
let negation_flag = if item.negation { 0x80 } else { 0x00 }; |
|
|
|
|
let mut l = (item.prefix.network_length() + 7) / 4; |
|
|
|
|
match &item.prefix { |
|
|
|
|
cidr::IpCidr::V4(p) => { |
|
|
|
|
let addr = p.first_address().octets(); |
|
|
|
|
while l > 0 && addr[l as usize -1] == 0 { l -= 1; } |
|
|
|
|
packet.put_u8(l | negation_flag); |
|
|
|
|
packet.extend_from_slice(&addr[..l as usize]); |
|
|
|
|
}, |
|
|
|
|
cidr::IpCidr::V6(p) => { |
|
|
|
|
let addr = p.first_address().octets(); |
|
|
|
|
while l > 0 && addr[l as usize -1] == 0 { l -= 1; } |
|
|
|
|
packet.put_u8(l | negation_flag); |
|
|
|
|
packet.extend_from_slice(&addr[..l as usize]); |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl DnsTextData for APL { |
|
|
|
|
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> Result<Self> { |
|
|
|
|
let mut items = Vec::new(); |
|
|
|
|
for item in data.split_ascii_whitespace() { |
|
|
|
|
let (negation, content) = if item.starts_with('!') { |
|
|
|
|
(true, &item[1..]) |
|
|
|
|
} else { |
|
|
|
|
(false, item) |
|
|
|
|
}; |
|
|
|
|
let (afi, prefix) = match content.find(':') { |
|
|
|
|
Some(colon) => (&content[..colon], &content[colon+1..]), |
|
|
|
|
None => failure::bail!("no colon in APL item: {:?}", item), |
|
|
|
|
}; |
|
|
|
|
let afi = afi.parse::<u16>()?; |
|
|
|
|
let prefix = match afi { |
|
|
|
|
1 => prefix.parse::<cidr::Ipv4Cidr>()?.into(), |
|
|
|
|
2 => prefix.parse::<cidr::Ipv6Cidr>()?.into(), |
|
|
|
|
_ => failure::bail!("Unknown address family {} in item: {:?}", afi, item), |
|
|
|
|
}; |
|
|
|
|
items.push(AplItem { |
|
|
|
|
prefix, |
|
|
|
|
negation, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
*data = ""; |
|
|
|
|
Ok(APL { items }) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { |
|
|
|
|
for item in &self.items { |
|
|
|
|
f.next_field()?; |
|
|
|
|
let family = if item.prefix.is_ipv4() { 1 } else { 2 }; |
|
|
|
|
let negation = if item.negation { "!" } else { "" }; |
|
|
|
|
write!(f, "{}{}:{}", negation, family, item.prefix)?; |
|
|
|
|
} |
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)] |
|
|
|
|
pub enum IpsecKeyGateway { |
|
|
|
|
None, |
|
|
|
|