#[cfg(test)]
mod xoraddr_test;
use crate::addr::*;
use crate::attributes::*;
use crate::checks::*;
use crate::message::*;
use shared::error::*;
use std::fmt;
use std::mem;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
const WORD_SIZE: usize = mem::size_of::<usize>();
fn safe_xor_bytes(dst: &mut [u8], a: &[u8], b: &[u8]) -> usize {
let mut n = a.len();
if b.len() < n {
n = b.len();
}
if dst.len() < n {
n = dst.len();
}
for i in 0..n {
dst[i] = a[i] ^ b[i];
}
n
}
pub fn xor_bytes(dst: &mut [u8], a: &[u8], b: &[u8]) -> usize {
safe_xor_bytes(dst, a, b)
}
pub struct XorMappedAddress {
pub ip: IpAddr,
pub port: u16,
}
impl Default for XorMappedAddress {
fn default() -> Self {
XorMappedAddress {
ip: IpAddr::V4(Ipv4Addr::from(0)),
port: 0,
}
}
}
impl fmt::Display for XorMappedAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.ip {
IpAddr::V4(_) => write!(f, "{}:{}", self.ip, self.port),
IpAddr::V6(_) => write!(f, "[{}]:{}", self.ip, self.port),
}
}
}
impl Setter for XorMappedAddress {
fn add_to(&self, m: &mut Message) -> Result<()> {
self.add_to_as(m, ATTR_XORMAPPED_ADDRESS)
}
}
impl Getter for XorMappedAddress {
fn get_from(&mut self, m: &Message) -> Result<()> {
self.get_from_as(m, ATTR_XORMAPPED_ADDRESS)
}
}
impl XorMappedAddress {
pub fn add_to_as(&self, m: &mut Message, t: AttrType) -> Result<()> {
let (family, ip_len, ip) = match self.ip {
IpAddr::V4(ipv4) => (FAMILY_IPV4, IPV4LEN, ipv4.octets().to_vec()),
IpAddr::V6(ipv6) => (FAMILY_IPV6, IPV6LEN, ipv6.octets().to_vec()),
};
let mut value = [0; 32 + 128];
let mut xor_value = vec![0; IPV6LEN];
xor_value[4..].copy_from_slice(&m.transaction_id.0);
xor_value[0..4].copy_from_slice(&MAGIC_COOKIE.to_be_bytes());
value[0..2].copy_from_slice(&family.to_be_bytes());
value[2..4].copy_from_slice(&(self.port ^ (MAGIC_COOKIE >> 16) as u16).to_be_bytes());
xor_bytes(&mut value[4..4 + ip_len], &ip, &xor_value);
m.add(t, &value[..4 + ip_len]);
Ok(())
}
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}")));
}
check_overflow(
t,
v[4..].len(),
if family == FAMILY_IPV4 {
IPV4LEN
} else {
IPV6LEN
},
)?;
self.port = u16::from_be_bytes([v[2], v[3]]) ^ (MAGIC_COOKIE >> 16) as u16;
let mut xor_value = vec![0; 4 + TRANSACTION_ID_SIZE];
xor_value[0..4].copy_from_slice(&MAGIC_COOKIE.to_be_bytes());
xor_value[4..].copy_from_slice(&m.transaction_id.0);
if family == FAMILY_IPV6 {
let mut ip = [0; IPV6LEN];
xor_bytes(&mut ip, &v[4..], &xor_value);
self.ip = IpAddr::V6(Ipv6Addr::from(ip));
} else {
let mut ip = [0; IPV4LEN];
xor_bytes(&mut ip, &v[4..], &xor_value);
self.ip = IpAddr::V4(Ipv4Addr::from(ip));
};
Ok(())
}
}