use crate::afi::*;
#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::net::Ipv6Addr;
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg(feature = "serialization")]
#[derive(Serialize, Deserialize)]
pub struct BgpAddrV6 {
pub addr: Ipv6Addr,
pub prefixlen: u8,
}
impl Default for BgpAddrV6 {
fn default() -> Self {
BgpAddrV6 {
addr: Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1),
prefixlen: 128,
}
}
}
impl BgpAddrV6 {
pub fn new(address: Ipv6Addr, prefix_len: u8) -> BgpAddrV6 {
BgpAddrV6 {
addr: address,
prefixlen: prefix_len,
}
}
pub fn contains(&self, a: &BgpAddrV6) -> bool {
if self.prefixlen < 1 {
true
} else if self.prefixlen > a.prefixlen {
false
} else if self.prefixlen == a.prefixlen {
self.addr == a.addr
} else {
(getn_u128(&self.addr.octets()) & (!((1 << (128 - self.prefixlen)) - 1)))
== (getn_u128(&a.addr.octets()) & (!((1 << (128 - self.prefixlen)) - 1)))
}
}
fn norm_subnet_u128(&self) -> u128 {
getn_u128(&self.addr.octets())
& (((1 << (128 - self.prefixlen)) - 1) ^ 0xffffffffffffffffffffffffffffffff)
}
pub fn in_subnet(&self, a: &std::net::Ipv6Addr) -> bool {
if self.prefixlen > 127 {
getn_u128(&self.addr.octets()) == getn_u128(&a.octets())
} else {
let lv = self.norm_subnet_u128();
let lh = lv + ((1 << (128 - self.prefixlen)) - 1);
let va = getn_u128(&a.octets());
(va >= lv) && (va < lh)
}
}
pub fn range_first(&self) -> std::net::Ipv6Addr {
let lv = self.norm_subnet_u128();
std::net::Ipv6Addr::new(
(lv >> 112) as u16,
(lv >> 96) as u16,
(lv >> 80) as u16,
(lv >> 64) as u16,
(lv >> 48) as u16,
(lv >> 32) as u16,
(lv >> 16) as u16,
(lv & 0xffff) as u16,
)
}
pub fn range_last(&self) -> std::net::Ipv6Addr {
if self.prefixlen < 1 {
std::net::Ipv6Addr::new(
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
)
} else if self.prefixlen > 127 {
self.range_first()
} else {
let lv = self.norm_subnet_u128() + ((1 << (128 - self.prefixlen)) - 1);
std::net::Ipv6Addr::new(
(lv >> 112) as u16,
(lv >> 96) as u16,
(lv >> 80) as u16,
(lv >> 64) as u16,
(lv >> 48) as u16,
(lv >> 32) as u16,
(lv >> 16) as u16,
(lv & 0xffff) as u16,
)
}
}
pub fn is_multicast(&self) -> bool {
self.addr.octets()[0] == 255
}
pub fn from_bits(bits: u8, buf: &[u8]) -> Result<(BgpAddrV6, usize), BgpError> {
let bytes = ((bits + 7) / 8) as usize;
if bits > 128 || buf.len() < bytes {
return Err(BgpError::from_string(format!(
"Invalid ipv6 FEC length: {:?}",
bits
)));
}
let mut bf = [0_u8; 16];
if bits == 0 {
return Ok((
BgpAddrV6 {
addr: decode_addrv6_from(&bf)?,
prefixlen: 0,
},
0,
));
}
bf[0..bytes].clone_from_slice(&buf[0..bytes]);
Ok((
BgpAddrV6 {
addr: decode_addrv6_from(&bf)?,
prefixlen: bits,
},
bytes,
))
}
pub fn to_bits(&self, buf: &mut [u8]) -> Result<(u8, usize), BgpError> {
if self.prefixlen == 0 {
return Ok((0, 0));
}
let mut bf = [0_u8; 16];
bf.clone_from_slice(&self.addr.octets());
let bytes = ((self.prefixlen + 7) / 8) as usize;
buf[0..bytes].clone_from_slice(&bf[0..bytes]);
Ok((self.prefixlen, bytes))
}
}
impl std::str::FromStr for BgpAddrV6 {
type Err = std::net::AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split('/').collect();
if parts.len() < 2 {
Ok(BgpAddrV6 {
addr: parts[0].parse::<std::net::Ipv6Addr>()?,
prefixlen: 128,
})
} else {
Ok(BgpAddrV6 {
addr: parts[0].parse::<std::net::Ipv6Addr>()?,
prefixlen: parts[1].parse::<u8>().unwrap_or(128),
})
}
}
}
impl BgpItem<BgpAddrV6> for BgpAddrV6 {
fn extract_bits_from(bits: u8, buf: &[u8]) -> Result<(BgpAddrV6, usize), BgpError> {
BgpAddrV6::from_bits(bits, buf)
}
fn set_bits_to(&self, buf: &mut [u8]) -> Result<(u8, usize), BgpError> {
self.to_bits(buf)
}
fn prefixlen(&self) -> usize {
self.prefixlen as usize
}
}
impl std::fmt::Display for BgpAddrV6 {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}/{:?}", self.addr, self.prefixlen)
}
}
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[cfg(feature = "serialization")]
#[derive(Serialize, Deserialize)]
pub struct BgpIPv6RD {
pub rd: BgpRD,
pub addr: std::net::Ipv6Addr,
}
impl std::fmt::Display for BgpIPv6RD {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if self.rd.is_zero() {
self.addr.fmt(f)
} else {
write!(f, "<{}>{}", self.rd, self.addr)
}
}
}
impl BgpAddrItem<BgpIPv6RD> for BgpIPv6RD {
fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(BgpIPv6RD, usize), BgpError> {
if buf.len() >= 24 {
let rdp = BgpRD::decode_from(mode, &buf[0..8])?;
Ok((
BgpIPv6RD {
rd: rdp.0,
addr: match decode_addr_from(&buf[(rdp.1)..(rdp.1 + 16)])? {
std::net::IpAddr::V6(n) => n,
_ => return Err(BgpError::static_str("Invalid address kind")),
},
},
rdp.1 + 16,
))
} else {
Err(BgpError::static_str("Invalid BgpIPv6RD buffer len"))
}
}
fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result<usize, BgpError> {
let pos = self.rd.encode_to(mode, buf)?;
let p2 = encode_addrv6_to(&self.addr, &mut buf[pos..])?;
Ok(pos + p2)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ipv6_parse() {
assert_eq!(
"2a02::/32".parse::<BgpAddrV6>(),
Ok(BgpAddrV6::new(
Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0),
32
))
);
assert_eq!(
"2a02::1".parse::<BgpAddrV6>(),
Ok(BgpAddrV6::new(
Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 1),
128
))
);
}
#[test]
fn test_ipv6_in_subnet() {
assert!(
BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 32)
.in_subnet(&Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 1))
);
assert!(
!BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 32)
.in_subnet(&Ipv6Addr::new(0x2a01, 0, 0, 0, 0, 0, 0, 1))
);
assert!(
BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 32).contains(
&BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 33)
)
);
}
#[test]
fn test_ipv6_ranges() {
assert_eq!(
BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 120).range_first(),
Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0)
);
assert_eq!(
BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 120).range_last(),
Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0xff)
);
}
}