turn_server/codec/message/attributes/
address.rs

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