1#[cfg(test)]
2mod xoraddr_test;
3
4use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
5use std::{fmt, mem};
6
7use crate::addr::*;
8use crate::attributes::*;
9use crate::checks::*;
10use crate::error::*;
11use crate::message::*;
12
13const WORD_SIZE: usize = mem::size_of::<usize>();
14
15fn safe_xor_bytes(dst: &mut [u8], a: &[u8], b: &[u8]) -> usize {
43 let mut n = a.len();
44 if b.len() < n {
45 n = b.len();
46 }
47 if dst.len() < n {
48 n = dst.len();
49 }
50 for i in 0..n {
51 dst[i] = a[i] ^ b[i];
52 }
53 n
54}
55
56pub fn xor_bytes(dst: &mut [u8], a: &[u8], b: &[u8]) -> usize {
59 safe_xor_bytes(dst, a, b)
63}
64
65pub struct XorMappedAddress {
69 pub ip: IpAddr,
70 pub port: u16,
71}
72
73impl Default for XorMappedAddress {
74 fn default() -> Self {
75 XorMappedAddress {
76 ip: IpAddr::V4(Ipv4Addr::from(0)),
77 port: 0,
78 }
79 }
80}
81
82impl fmt::Display for XorMappedAddress {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 match self.ip {
85 IpAddr::V4(_) => write!(f, "{}:{}", self.ip, self.port),
86 IpAddr::V6(_) => write!(f, "[{}]:{}", self.ip, self.port),
87 }
88 }
89}
90
91impl Setter for XorMappedAddress {
92 fn add_to(&self, m: &mut Message) -> Result<()> {
95 self.add_to_as(m, ATTR_XORMAPPED_ADDRESS)
96 }
97}
98
99impl Getter for XorMappedAddress {
100 fn get_from(&mut self, m: &Message) -> Result<()> {
105 self.get_from_as(m, ATTR_XORMAPPED_ADDRESS)
106 }
107}
108
109impl XorMappedAddress {
110 pub fn add_to_as(&self, m: &mut Message, t: AttrType) -> Result<()> {
112 let (family, ip_len, ip) = match self.ip {
113 IpAddr::V4(ipv4) => (FAMILY_IPV4, IPV4LEN, ipv4.octets().to_vec()),
114 IpAddr::V6(ipv6) => (FAMILY_IPV6, IPV6LEN, ipv6.octets().to_vec()),
115 };
116
117 let mut value = [0; 32 + 128];
118 let mut xor_value = vec![0; IPV6LEN];
120 xor_value[4..].copy_from_slice(&m.transaction_id.0);
121 xor_value[0..4].copy_from_slice(&MAGIC_COOKIE.to_be_bytes());
122 value[0..2].copy_from_slice(&family.to_be_bytes());
123 value[2..4].copy_from_slice(&(self.port ^ (MAGIC_COOKIE >> 16) as u16).to_be_bytes());
124 xor_bytes(&mut value[4..4 + ip_len], &ip, &xor_value);
125 m.add(t, &value[..4 + ip_len]);
126 Ok(())
127 }
128
129 pub fn get_from_as(&mut self, m: &Message, t: AttrType) -> Result<()> {
132 let v = m.get(t)?;
133 if v.len() <= 4 {
134 return Err(Error::ErrUnexpectedEof);
135 }
136
137 let family = u16::from_be_bytes([v[0], v[1]]);
138 if family != FAMILY_IPV6 && family != FAMILY_IPV4 {
139 return Err(Error::Other(format!("bad value {family}")));
140 }
141
142 check_overflow(
143 t,
144 v[4..].len(),
145 if family == FAMILY_IPV4 {
146 IPV4LEN
147 } else {
148 IPV6LEN
149 },
150 )?;
151 self.port = u16::from_be_bytes([v[2], v[3]]) ^ (MAGIC_COOKIE >> 16) as u16;
152 let mut xor_value = vec![0; 4 + TRANSACTION_ID_SIZE];
153 xor_value[0..4].copy_from_slice(&MAGIC_COOKIE.to_be_bytes());
154 xor_value[4..].copy_from_slice(&m.transaction_id.0);
155
156 if family == FAMILY_IPV6 {
157 let mut ip = [0; IPV6LEN];
158 xor_bytes(&mut ip, &v[4..], &xor_value);
159 self.ip = IpAddr::V6(Ipv6Addr::from(ip));
160 } else {
161 let mut ip = [0; IPV4LEN];
162 xor_bytes(&mut ip, &v[4..], &xor_value);
163 self.ip = IpAddr::V4(Ipv4Addr::from(ip));
164 };
165
166 Ok(())
167 }
168}