xref: /webrtc/stun/src/xoraddr.rs (revision 5d8fe953)
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