Skip to main content

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