faster_stun/attribute/
address.rs

1use bytes::{BufMut, BytesMut};
2
3use std::convert::TryInto;
4use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
5
6use crate::StunError;
7
8pub const FAMILY_IPV4: u8 = 0x01;
9pub const FAMILY_IPV6: u8 = 0x02;
10
11/// [RFC3489]: https://datatracker.ietf.org/doc/html/rfc3489
12///
13/// The Address attribute indicates a reflexive transport address
14/// of the client.  It consists of an 8-bit address family and a 16-bit
15/// port, followed by a fixed-length value representing the IP address.
16/// If the address family is IPv4, the address MUST be 32 bits.  If the
17/// address family is IPv6, the address MUST be 128 bits.  All fields
18/// must be in network byte order.
19///
20/// The format of the MAPPED-ADDRESS attribute is:
21///
22/// ```text
23/// 0                   1                   2                   3
24/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
25/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26/// |0 0 0 0 0 0 0 0|    Family     |           Port                |
27/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28/// |                                                               |
29/// |                 Address (32 bits or 128 bits)                 |
30/// |                                                               |
31/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32/// ```
33///
34/// Figure 5: Format of MAPPED-ADDRESS Attribute
35///
36/// The address family can take on the following values:
37///
38/// * 0x01:IPv4
39/// * 0x02:IPv6
40///
41/// The first 8 bits of the MAPPED-ADDRESS MUST be set to 0 and MUST be
42/// ignored by receivers.  These bits are present for aligning parameters
43/// on natural 32-bit boundaries.
44///
45/// This attribute is used only by servers for achieving backwards
46/// compatibility with [RFC3489] clients.
47///
48/// The XOR-MAPPED-ADDRESS attribute is identical to the MAPPED-ADDRESS
49/// attribute, except that the reflexive transport address is obfuscated
50/// through the XOR function.
51///
52/// The format of the XOR-MAPPED-ADDRESS is:
53///
54/// ```text
55/// 0                   1                   2                   3
56/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
57/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58/// |0 0 0 0 0 0 0 0|    Family     |         X-Port                |
59/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60/// |                X-Address (Variable)
61/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62///
63///          Figure 6: Format of XOR-MAPPED-ADDRESS Attribute
64/// ```
65///
66/// The Family field represents the IP address family and is encoded
67/// identically to the Family field in MAPPED-ADDRESS.
68///
69/// X-Port is computed by XOR'ing the mapped port with the most
70/// significant 16 bits of the magic cookie.  If the IP address family is
71/// IPv4, X-Address is computed by XOR'ing the mapped IP address with the
72/// magic cookie.  If the IP address family is IPv6, X-Address is
73/// computed by XOR'ing the mapped IP address with the concatenation of
74/// the magic cookie and the 96-bit transaction ID.  In all cases, the
75/// XOR operation works on its inputs in network byte order (that is, the
76/// order they will be encoded in the message).
77///
78/// The rules for encoding and processing the first 8 bits of the
79/// attribute's value, the rules for handling multiple occurrences of the
80/// attribute, and the rules for processing address families are the same
81/// as for MAPPED-ADDRESS.
82///
83/// Note: XOR-MAPPED-ADDRESS and MAPPED-ADDRESS differ only in their
84/// encoding of the transport address.  The former encodes the transport
85/// address by XOR'ing it with the magic cookie.  The latter encodes it
86/// directly in binary.  [RFC3489] originally specified only MAPPED-
87/// ADDRESS.  However, deployment experience found that some NATs rewrite
88/// the 32-bit binary payloads containing the NAT's public IP address,
89/// such as STUN's MAPPED-ADDRESS attribute, in the well-meaning but
90/// misguided attempt to provide a generic Application Layer Gateway
91/// (ALG) function.  Such behavior interferes with the operation of STUN
92/// and also causes failure of STUN's message-integrity checking.
93pub struct Addr;
94
95impl Addr {
96    /// encoder SocketAddr as Bytes.
97    ///
98    /// # Unit Test
99    ///
100    /// ```
101    /// use bytes::BytesMut;
102    /// use faster_stun::attribute::*;
103    ///
104    /// let xor_addr_buf: [u8; 8] =
105    ///     [0x00, 0x01, 0xfc, 0xbe, 0xe1, 0xba, 0xa4, 0x29];
106    ///
107    /// let addr_buf: [u8; 8] = [0x00, 0x01, 0xdd, 0xac, 0xc0, 0xa8, 0x00, 0x6b];
108    ///
109    /// let token: [u8; 12] = [
110    ///     0x6c, 0x46, 0x62, 0x54, 0x75, 0x4b, 0x44, 0x51, 0x46, 0x48, 0x4c, 0x71,
111    /// ];
112    ///
113    /// let source = "192.168.0.107:56748".parse().unwrap();
114    ///
115    /// let mut buffer = BytesMut::with_capacity(1280);
116    /// Addr::into(&source, &token, &mut buffer, true);
117    /// assert_eq!(&xor_addr_buf, &buffer[..]);
118    ///
119    /// let mut buffer = BytesMut::with_capacity(1280);
120    /// Addr::into(&source, &token, &mut buffer, false);
121    /// assert_eq!(&addr_buf, &buffer[..]);
122    /// ```
123    pub fn into(a: &SocketAddr, token: &[u8], buf: &mut BytesMut, is_xor: bool) {
124        buf.put_u8(0);
125        let xor_addr = if is_xor { xor(a, token) } else { *a };
126
127        buf.put_u8(if xor_addr.is_ipv4() {
128            FAMILY_IPV4
129        } else {
130            FAMILY_IPV6
131        });
132
133        buf.put_u16(xor_addr.port());
134        if let IpAddr::V4(ip) = xor_addr.ip() {
135            buf.put(&ip.octets()[..]);
136        }
137
138        if let IpAddr::V6(ip) = xor_addr.ip() {
139            buf.put(&ip.octets()[..]);
140        }
141    }
142
143    /// decoder Bytes as SocketAddr.
144    ///
145    /// # Unit Test
146    ///
147    /// ```
148    /// use faster_stun::attribute::*;
149    ///
150    /// let xor_addr_buf: [u8; 8] =
151    ///     [0x00, 0x01, 0xfc, 0xbe, 0xe1, 0xba, 0xa4, 0x29];
152    ///
153    /// let addr_buf: [u8; 8] = [0x00, 0x01, 0xdd, 0xac, 0xc0, 0xa8, 0x00, 0x6b];
154    ///
155    /// let token: [u8; 12] = [
156    ///     0x6c, 0x46, 0x62, 0x54, 0x75, 0x4b, 0x44, 0x51, 0x46, 0x48, 0x4c, 0x71,
157    /// ];
158    ///
159    /// let source = "192.168.0.107:56748".parse().unwrap();
160    ///
161    /// let addr = Addr::try_from(&xor_addr_buf, &token, true).unwrap();
162    /// assert_eq!(addr, source);
163    ///
164    /// let addr = Addr::try_from(&addr_buf, &token, false).unwrap();
165    /// assert_eq!(addr, source);
166    /// ```
167    pub fn try_from(packet: &[u8], token: &[u8], is_xor: bool) -> Result<SocketAddr, StunError> {
168        if !(packet.len() >= 4) {
169            return Err(StunError::InvalidInput);
170        }
171
172        let port = u16::from_be_bytes([packet[2], packet[3]]);
173        let ip_addr = match packet[1] {
174            FAMILY_IPV4 => from_bytes_v4(packet)?,
175            FAMILY_IPV6 => from_bytes_v6(packet)?,
176            _ => return Err(StunError::UnsupportedIpFamily),
177        };
178
179        let dyn_addr = SocketAddr::new(ip_addr, port);
180        Ok(if is_xor {
181            xor(&dyn_addr, token)
182        } else {
183            dyn_addr
184        })
185    }
186}
187
188/// # Unit Test
189///
190/// ```
191/// use faster_stun::attribute::address::*;
192/// use std::net::IpAddr;
193///
194/// let buf: [u8; 8] = [0x00, 0x01, 0xdd, 0xac, 0xc0, 0xa8, 0x00, 0x6b];
195///
196/// let source: IpAddr = "192.168.0.107".parse().unwrap();
197///
198/// let addr = from_bytes_v4(&buf).unwrap();
199/// assert_eq!(addr, source);
200/// ```
201pub fn from_bytes_v4(packet: &[u8]) -> Result<IpAddr, StunError> {
202    if !(packet.len() == 8) {
203        return Err(StunError::InvalidInput);
204    }
205
206    let buf: [u8; 4] = packet[4..8].try_into().map_err(|_| StunError::FatalError)?;
207    Ok(IpAddr::V4(buf.into()))
208}
209
210/// # Unit Test
211///
212/// ```
213/// use faster_stun::attribute::address::*;
214/// use std::net::IpAddr;
215///
216/// let buf: [u8; 20] = [
217///     0x00, 0x01, 0xdd, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218///     0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x0A, 0x2F, 0x0F,
219/// ];
220///
221/// let source: IpAddr = "::ffff:192.10.47.15".parse().unwrap();
222///
223/// let addr = from_bytes_v6(&buf).unwrap();
224/// assert_eq!(addr, source);
225/// ```
226pub fn from_bytes_v6(packet: &[u8]) -> Result<IpAddr, StunError> {
227    if !(packet.len() == 20) {
228        return Err(StunError::InvalidInput);
229    }
230
231    let buf: [u8; 16] = packet[4..20]
232        .try_into()
233        .map_err(|_| StunError::FatalError)?;
234    Ok(IpAddr::V6(buf.into()))
235}
236
237/// # Unit Test
238///
239/// ```
240/// use faster_stun::attribute::address::*;
241/// use std::net::SocketAddr;
242///
243/// let source: SocketAddr = "192.168.0.107:1".parse().unwrap();
244///
245/// let res: SocketAddr = "225.186.164.41:8467".parse().unwrap();
246///
247/// let token: [u8; 12] = [
248///     0x6c, 0x46, 0x62, 0x54, 0x75, 0x4b, 0x44, 0x51, 0x46, 0x48, 0x4c, 0x71,
249/// ];
250///
251/// let addr = xor(&source, &token);
252/// assert_eq!(addr, res);
253/// ```
254pub fn xor(addr: &SocketAddr, token: &[u8]) -> SocketAddr {
255    let port = addr.port() ^ (0x2112A442 >> 16) as u16;
256    let ip_addr = match addr.ip() {
257        IpAddr::V4(x) => xor_v4(x),
258        IpAddr::V6(x) => xor_v6(x, token),
259    };
260
261    SocketAddr::new(ip_addr, port)
262}
263
264/// # Unit Test
265///
266/// ```
267/// use faster_stun::attribute::address::*;
268/// use std::net::{IpAddr, Ipv4Addr};
269///
270/// let source: Ipv4Addr = "192.168.0.107".parse().unwrap();
271///
272/// let xor: IpAddr = "225.186.164.41".parse().unwrap();
273///
274/// let addr = xor_v4(source);
275/// assert_eq!(addr, xor);
276/// ```
277pub fn xor_v4(addr: Ipv4Addr) -> IpAddr {
278    let mut octets = addr.octets();
279    for (i, b) in octets.iter_mut().enumerate() {
280        *b ^= (0x2112A442 >> (24 - i * 8)) as u8;
281    }
282
283    IpAddr::V4(From::from(octets))
284}
285
286/// # Unit Test
287///
288/// ```
289/// use faster_stun::attribute::address::*;
290/// use std::net::{IpAddr, Ipv6Addr};
291///
292/// let source: Ipv6Addr = "::ffff:192.10.47.15".parse().unwrap();
293///
294/// let xor: IpAddr =
295///     "2112:a442:6c46:6254:754b:bbae:8642:637e".parse().unwrap();
296///
297/// let token: [u8; 12] = [
298///     0x6c, 0x46, 0x62, 0x54, 0x75, 0x4b, 0x44, 0x51, 0x46, 0x48, 0x4c, 0x71,
299/// ];
300///
301/// let addr = xor_v6(source, &token);
302/// assert_eq!(addr, xor);
303/// ```
304pub fn xor_v6(addr: Ipv6Addr, token: &[u8]) -> IpAddr {
305    let mut octets = addr.octets();
306    for (i, b) in octets.iter_mut().enumerate().take(4) {
307        *b ^= (0x2112A442 >> (24 - i * 8)) as u8;
308    }
309
310    for (i, b) in octets.iter_mut().enumerate().take(16).skip(4) {
311        *b ^= token[i - 4];
312    }
313
314    IpAddr::V6(From::from(octets))
315}