#[cfg(test)]
mod addr_test;
use crate::attributes::*;
use crate::message::*;
use shared::error::*;
use std::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
pub(crate) const FAMILY_IPV4: u16 = 0x01;
pub(crate) const FAMILY_IPV6: u16 = 0x02;
pub(crate) const IPV4LEN: usize = 4;
pub(crate) const IPV6LEN: usize = 16;
pub struct MappedAddress {
pub ip: IpAddr,
pub port: u16,
}
impl fmt::Display for MappedAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.ip {
IpAddr::V4(ipv4) => write!(f, "{}:{}", ipv4, self.port),
IpAddr::V6(ipv6) => write!(f, "[{}]:{}", ipv6, self.port),
}
}
}
impl Default for MappedAddress {
fn default() -> Self {
MappedAddress {
ip: IpAddr::V4(Ipv4Addr::from(0)),
port: 0,
}
}
}
impl Setter for MappedAddress {
fn add_to(&self, m: &mut Message) -> Result<()> {
self.add_to_as(m, ATTR_MAPPED_ADDRESS)
}
}
impl Getter for MappedAddress {
fn get_from(&mut self, m: &Message) -> Result<()> {
self.get_from_as(m, ATTR_MAPPED_ADDRESS)
}
}
impl MappedAddress {
pub fn get_from_as(&mut self, m: &Message, t: AttrType) -> Result<()> {
let v = m.get(t)?;
if v.len() <= 4 {
return Err(Error::ErrUnexpectedEof);
}
let family = u16::from_be_bytes([v[0], v[1]]);
if family != FAMILY_IPV6 && family != FAMILY_IPV4 {
return Err(Error::Other(format!("bad value {family}")));
}
self.port = u16::from_be_bytes([v[2], v[3]]);
if family == FAMILY_IPV6 {
let mut ip = [0; IPV6LEN];
let l = std::cmp::min(ip.len(), v[4..].len());
ip[..l].copy_from_slice(&v[4..4 + l]);
self.ip = IpAddr::V6(Ipv6Addr::from(ip));
} else {
let mut ip = [0; IPV4LEN];
let l = std::cmp::min(ip.len(), v[4..].len());
ip[..l].copy_from_slice(&v[4..4 + l]);
self.ip = IpAddr::V4(Ipv4Addr::from(ip));
};
Ok(())
}
pub fn add_to_as(&self, m: &mut Message, t: AttrType) -> Result<()> {
let family = match self.ip {
IpAddr::V4(_) => FAMILY_IPV4,
IpAddr::V6(_) => FAMILY_IPV6,
};
let mut value = vec![0u8; 4];
value[0..2].copy_from_slice(&family.to_be_bytes());
value[2..4].copy_from_slice(&self.port.to_be_bytes());
match self.ip {
IpAddr::V4(ipv4) => value.extend_from_slice(&ipv4.octets()),
IpAddr::V6(ipv6) => value.extend_from_slice(&ipv6.octets()),
};
m.add(t, &value);
Ok(())
}
}
pub type AlternateServer = MappedAddress;
pub type ResponseOrigin = MappedAddress;
pub type OtherAddress = MappedAddress;