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