stun/
xoraddr.rs

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