1 #[cfg(test)]
2 mod xoraddr_test;
3
4 use crate::addr::*;
5 use crate::attributes::*;
6 use crate::checks::*;
7 use crate::error::*;
8 use crate::message::*;
9
10 use std::fmt;
11 use std::mem;
12 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
13
14 const WORD_SIZE: usize = mem::size_of::<usize>();
15
16 //var supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" // nolint:gochecknoglobals
17
18 // fast_xor_bytes xors in bulk. It only works on architectures that
19 // support unaligned read/writes.
20 /*TODO: fn fast_xor_bytes(dst:&[u8], a:&[u8], b:&[u8]) ->usize {
21 let mut n = a.len();
22 if b.len() < n {
23 n = b.len();
24 }
25
26 let w = n / WORD_SIZE;
27 if w > 0 {
28 let dw = *(*[]uintptr)(unsafe.Pointer(&dst))
29 let aw = *(*[]uintptr)(unsafe.Pointer(&a))
30 let bw = *(*[]uintptr)(unsafe.Pointer(&b))
31 for i := 0; i < w; i++ {
32 dw[i] = aw[i] ^ bw[i]
33 }
34 }
35
36 for i := n - n%WORD_SIZE; i < n; i++ {
37 dst[i] = a[i] ^ b[i]
38 }
39
40 return n
41 }*/
42
safe_xor_bytes(dst: &mut [u8], a: &[u8], b: &[u8]) -> usize43 fn 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
57 /// xor_bytes xors the bytes in a and b. The destination is assumed to have enough
58 /// space. Returns the number of bytes xor'd.
xor_bytes(dst: &mut [u8], a: &[u8], b: &[u8]) -> usize59 pub fn xor_bytes(dst: &mut [u8], a: &[u8], b: &[u8]) -> usize {
60 //TODO: if supportsUnaligned {
61 // return fastXORBytes(dst, a, b)
62 //}
63 safe_xor_bytes(dst, a, b)
64 }
65
66 /// XORMappedAddress implements XOR-MAPPED-ADDRESS attribute.
67 ///
68 /// RFC 5389 Section 15.2
69 pub struct XorMappedAddress {
70 pub ip: IpAddr,
71 pub port: u16,
72 }
73
74 impl Default for XorMappedAddress {
default() -> Self75 fn default() -> Self {
76 XorMappedAddress {
77 ip: IpAddr::V4(Ipv4Addr::from(0)),
78 port: 0,
79 }
80 }
81 }
82
83 impl fmt::Display for XorMappedAddress {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 let family = match self.ip {
86 IpAddr::V4(_) => FAMILY_IPV4,
87 IpAddr::V6(_) => FAMILY_IPV6,
88 };
89 if family == FAMILY_IPV4 {
90 write!(f, "{}:{}", self.ip, self.port)
91 } else {
92 write!(f, "[{}]:{}", self.ip, self.port)
93 }
94 }
95 }
96
97 impl Setter for XorMappedAddress {
98 /// add_to adds XOR-MAPPED-ADDRESS to m. Can return ErrBadIPLength
99 /// if len(a.IP) is invalid.
add_to(&self, m: &mut Message) -> Result<()>100 fn add_to(&self, m: &mut Message) -> Result<()> {
101 self.add_to_as(m, ATTR_XORMAPPED_ADDRESS)
102 }
103 }
104
105 impl Getter for XorMappedAddress {
106 /// get_from decodes XOR-MAPPED-ADDRESS attribute in message and returns
107 /// error if any. While decoding, a.IP is reused if possible and can be
108 /// rendered to invalid state (e.g. if a.IP was set to IPv6 and then
109 /// IPv4 value were decoded into it), be careful.
get_from(&mut self, m: &Message) -> Result<()>110 fn get_from(&mut self, m: &Message) -> Result<()> {
111 self.get_from_as(m, ATTR_XORMAPPED_ADDRESS)
112 }
113 }
114
115 impl XorMappedAddress {
116 /// add_to_as adds XOR-MAPPED-ADDRESS value to m as t attribute.
add_to_as(&self, m: &mut Message, t: AttrType) -> Result<()>117 pub fn add_to_as(&self, m: &mut Message, t: AttrType) -> Result<()> {
118 let (family, ip_len, ip) = match self.ip {
119 IpAddr::V4(ipv4) => (FAMILY_IPV4, IPV4LEN, ipv4.octets().to_vec()),
120 IpAddr::V6(ipv6) => (FAMILY_IPV6, IPV6LEN, ipv6.octets().to_vec()),
121 };
122
123 let mut value = vec![0; 32 + 128];
124 //value[0] = 0 // first 8 bits are zeroes
125 let mut xor_value = vec![0; IPV6LEN];
126 xor_value[4..].copy_from_slice(&m.transaction_id.0);
127 xor_value[0..4].copy_from_slice(&MAGIC_COOKIE.to_be_bytes());
128 value[0..2].copy_from_slice(&family.to_be_bytes());
129 value[2..4].copy_from_slice(&(self.port ^ (MAGIC_COOKIE >> 16) as u16).to_be_bytes());
130 xor_bytes(&mut value[4..4 + ip_len], &ip, &xor_value);
131 m.add(t, &value[..4 + ip_len]);
132 Ok(())
133 }
134
135 /// get_from_as decodes XOR-MAPPED-ADDRESS attribute value in message
136 /// getting it as for t type.
get_from_as(&mut self, m: &Message, t: AttrType) -> Result<()>137 pub fn get_from_as(&mut self, m: &Message, t: AttrType) -> Result<()> {
138 let v = m.get(t)?;
139 if v.len() <= 4 {
140 return Err(Error::ErrUnexpectedEof);
141 }
142
143 let family = u16::from_be_bytes([v[0], v[1]]);
144 if family != FAMILY_IPV6 && family != FAMILY_IPV4 {
145 return Err(Error::Other(format!("bad value {family}")));
146 }
147
148 check_overflow(
149 t,
150 v[4..].len(),
151 if family == FAMILY_IPV4 {
152 IPV4LEN
153 } else {
154 IPV6LEN
155 },
156 )?;
157 self.port = u16::from_be_bytes([v[2], v[3]]) ^ (MAGIC_COOKIE >> 16) as u16;
158 let mut xor_value = vec![0; 4 + TRANSACTION_ID_SIZE];
159 xor_value[0..4].copy_from_slice(&MAGIC_COOKIE.to_be_bytes());
160 xor_value[4..].copy_from_slice(&m.transaction_id.0);
161
162 if family == FAMILY_IPV6 {
163 let mut ip = [0; IPV6LEN];
164 xor_bytes(&mut ip, &v[4..], &xor_value);
165 self.ip = IpAddr::V6(Ipv6Addr::from(ip));
166 } else {
167 let mut ip = [0; IPV4LEN];
168 xor_bytes(&mut ip, &v[4..], &xor_value);
169 self.ip = IpAddr::V4(Ipv4Addr::from(ip));
170 };
171
172 Ok(())
173 }
174 }
175