webrtc_stun/
xoraddr.rs

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