rtc_stun/
xoraddr.rs

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
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
43fn 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.
59pub 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
69pub 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        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
97impl Setter for XorMappedAddress {
98    /// add_to adds XOR-MAPPED-ADDRESS to m. Can return ErrBadIPLength
99    /// if len(a.IP) is invalid.
100    fn add_to(&self, m: &mut Message) -> Result<()> {
101        self.add_to_as(m, ATTR_XORMAPPED_ADDRESS)
102    }
103}
104
105impl 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.
110    fn get_from(&mut self, m: &Message) -> Result<()> {
111        self.get_from_as(m, ATTR_XORMAPPED_ADDRESS)
112    }
113}
114
115impl XorMappedAddress {
116    /// add_to_as adds XOR-MAPPED-ADDRESS value to m as t attribute.
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 = [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.
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}