stun_types/attribute/
address.rs

1// Copyright (C) 2020 Matthew Waters <matthew@centricular.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
10
11use byteorder::{BigEndian, ByteOrder};
12
13use crate::message::{StunParseError, TransactionId, MAGIC_COOKIE};
14
15use super::{check_len, AttributeType, RawAttribute};
16
17/// The address family of the socket
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum AddressFamily {
20    /// IP version 4 address.
21    IPV4,
22    /// IP version 6 address.
23    IPV6,
24}
25
26impl AddressFamily {
27    pub(crate) fn to_byte(self) -> u8 {
28        match self {
29            AddressFamily::IPV4 => 0x1,
30            AddressFamily::IPV6 => 0x2,
31        }
32    }
33
34    pub(crate) fn from_byte(byte: u8) -> Result<AddressFamily, StunParseError> {
35        match byte {
36            0x1 => Ok(AddressFamily::IPV4),
37            0x2 => Ok(AddressFamily::IPV6),
38            _ => Err(StunParseError::InvalidAttributeData),
39        }
40    }
41}
42
43impl std::fmt::Display for AddressFamily {
44    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45        match self {
46            AddressFamily::IPV4 => write!(f, "IPV4"),
47            AddressFamily::IPV6 => write!(f, "IPV6"),
48        }
49    }
50}
51
52/// Helper struct for `SocketAddr`s that are stored as an attribute.
53#[derive(Debug, Clone, PartialEq, Eq)]
54pub struct MappedSocketAddr {
55    addr: SocketAddr,
56}
57
58impl MappedSocketAddr {
59    /// Create a new [`MappedSocketAddr`].
60    pub fn new(addr: SocketAddr) -> Self {
61        Self { addr }
62    }
63
64    /// The number of bytes of this [`MappedSocketAddr`].
65    pub fn length(&self) -> u16 {
66        match self.addr {
67            SocketAddr::V4(_) => 8,
68            SocketAddr::V6(_) => 20,
69        }
70    }
71
72    /// Convert this [`MappedSocketAddr`] into a [`RawAttribute`]
73    pub fn to_raw<'a>(&self, atype: AttributeType) -> RawAttribute<'a> {
74        match self.addr {
75            SocketAddr::V4(_addr) => {
76                let mut buf = [0; 8];
77                self.write_into_unchecked(&mut buf);
78                RawAttribute::new(atype, &buf).into_owned()
79            }
80            SocketAddr::V6(_addr) => {
81                let mut buf = [0; 20];
82                self.write_into_unchecked(&mut buf);
83                RawAttribute::new(atype, &buf).into_owned()
84            }
85        }
86    }
87
88    /// Try to convert a [`RawAttribute`] into a [`MappedSocketAddr`]
89    pub fn from_raw(raw: &RawAttribute) -> Result<Self, StunParseError> {
90        if raw.value.len() < 4 {
91            return Err(StunParseError::Truncated {
92                expected: 4,
93                actual: raw.value.len(),
94            });
95        }
96        let port = BigEndian::read_u16(&raw.value[2..4]);
97        let family = AddressFamily::from_byte(raw.value[1])?;
98        let addr = match family {
99            AddressFamily::IPV4 => {
100                // ipv4
101                check_len(raw.value.len(), 8..=8)?;
102                IpAddr::V4(Ipv4Addr::from(BigEndian::read_u32(&raw.value[4..8])))
103            }
104            AddressFamily::IPV6 => {
105                // ipv6
106                check_len(raw.value.len(), 20..=20)?;
107                let mut octets = [0; 16];
108                octets.clone_from_slice(&raw.value[4..]);
109                IpAddr::V6(Ipv6Addr::from(octets))
110            }
111        };
112        Ok(Self {
113            addr: SocketAddr::new(addr, port),
114        })
115    }
116
117    /// The `SocketAddr` in this [`MappedSocketAddr`]
118    pub fn addr(&self) -> SocketAddr {
119        self.addr
120    }
121
122    /// Write the [`MappedSocketAddr`] to the provided destination buffer.
123    pub fn write_into_unchecked(&self, dest: &mut [u8]) {
124        match self.addr {
125            SocketAddr::V4(addr) => {
126                dest[0] = 0x0;
127                dest[1] = AddressFamily::IPV4.to_byte();
128                BigEndian::write_u16(&mut dest[2..4], addr.port());
129                let octets = u32::from(*addr.ip());
130                BigEndian::write_u32(&mut dest[4..8], octets);
131            }
132            SocketAddr::V6(addr) => {
133                dest[0] = 0x0;
134                dest[1] = AddressFamily::IPV6.to_byte();
135                BigEndian::write_u16(&mut dest[2..4], addr.port());
136                let octets = u128::from(*addr.ip());
137                BigEndian::write_u128(&mut dest[4..20], octets);
138            }
139        }
140    }
141}
142
143impl std::fmt::Display for MappedSocketAddr {
144    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145        match self.addr {
146            SocketAddr::V4(addr) => write!(f, "{:?}", addr),
147            SocketAddr::V6(addr) => write!(f, "{:?}", addr),
148        }
149    }
150}
151
152/// Helper struct for [`SocketAddr`] that are stored as an
153/// [`Attribute`](crate::attribute::Attribute) after an XOR operation with the [`TransactionId`]
154/// of a [`Message`](crate::message::Message).
155#[derive(Debug, Clone, PartialEq, Eq)]
156#[repr(transparent)]
157pub struct XorSocketAddr {
158    /// The parent [`MappedSocketAddr`]
159    pub addr: MappedSocketAddr,
160}
161
162impl XorSocketAddr {
163    /// Create a new [`XorSocketAddr`].
164    pub fn new(addr: SocketAddr, transaction: TransactionId) -> Self {
165        Self {
166            addr: MappedSocketAddr::new(XorSocketAddr::xor_addr(addr, transaction)),
167        }
168    }
169
170    /// The number of bytes of this [`XorSocketAddr`].
171    pub fn length(&self) -> u16 {
172        self.addr.length()
173    }
174
175    /// Convert this [`XorSocketAddr`] into a [`RawAttribute`]
176    pub fn to_raw<'a>(&self, atype: AttributeType) -> RawAttribute<'a> {
177        self.addr.to_raw(atype)
178    }
179
180    /// Try to convert a [`RawAttribute`] into a [`XorSocketAddr`]
181    pub fn from_raw(raw: &RawAttribute) -> Result<Self, StunParseError> {
182        let addr = MappedSocketAddr::from_raw(raw)?;
183        Ok(Self { addr })
184    }
185
186    /// Returns the XOR of the `addr` with the `transaction` and the hardcoded XOR constant.
187    pub fn xor_addr(addr: SocketAddr, transaction: TransactionId) -> SocketAddr {
188        match addr {
189            SocketAddr::V4(addr) => {
190                let port = addr.port() ^ (MAGIC_COOKIE >> 16) as u16;
191                let const_octets = MAGIC_COOKIE.to_be_bytes();
192                let addr_octets = addr.ip().octets();
193                let octets = bytewise_xor!(4, const_octets, addr_octets, 0);
194                SocketAddr::new(IpAddr::V4(Ipv4Addr::from(octets)), port)
195            }
196            SocketAddr::V6(addr) => {
197                let port = addr.port() ^ (MAGIC_COOKIE >> 16) as u16;
198                let transaction: u128 = transaction.into();
199                let const_octets = ((MAGIC_COOKIE as u128) << 96
200                    | (transaction & 0x0000_0000_ffff_ffff_ffff_ffff_ffff_ffff))
201                    .to_be_bytes();
202                let addr_octets = addr.ip().octets();
203                let octets = bytewise_xor!(16, const_octets, addr_octets, 0);
204                SocketAddr::new(IpAddr::V6(Ipv6Addr::from(octets)), port)
205            }
206        }
207    }
208
209    /// Retrieve the `SocketAddr` from this [`XorSocketAddr`]
210    pub fn addr(&self, transaction: TransactionId) -> SocketAddr {
211        XorSocketAddr::xor_addr(self.addr.addr(), transaction)
212    }
213
214    /// Write the [`XorSocketAddr`] to the provided destination buffer.
215    pub fn write_into_unchecked(&self, dest: &mut [u8]) {
216        self.addr.write_into_unchecked(dest)
217    }
218}
219
220impl std::fmt::Display for XorSocketAddr {
221    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222        match self.addr.addr() {
223            SocketAddr::V4(_) => write!(f, "{:?}", self.addr(0x0.into())),
224            SocketAddr::V6(addr) => write!(f, "XOR({:?})", addr),
225        }
226    }
227}
228
229#[cfg(test)]
230pub(crate) mod tests {
231    use super::*;
232    use tracing::trace;
233
234    #[test]
235    fn mapped_address_ipv4() {
236        let addr = "192.168.0.1:3178".parse().unwrap();
237        let _log = crate::tests::test_init_log();
238        let data = [
239            0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x0C, 0x6A, 0xC0, 0xA8, 0x00, 0x01,
240        ];
241        let mapped = MappedSocketAddr::from_raw(&RawAttribute::from_bytes(&data).unwrap()).unwrap();
242        trace!("mapped: {mapped}");
243        assert_eq!(mapped.addr(), addr);
244    }
245
246    #[test]
247    fn mapped_address_short() {
248        let _log = crate::tests::test_init_log();
249        let data = [0x00, 0x01, 0x00, 0x02, 0x00, 0x00];
250        assert!(matches!(
251            MappedSocketAddr::from_raw(&RawAttribute::from_bytes(&data).unwrap()),
252            Err(StunParseError::Truncated {
253                expected: 4,
254                actual: 2
255            })
256        ));
257    }
258
259    #[test]
260    fn mapped_address_unknown_family() {
261        let _log = crate::tests::test_init_log();
262        let data = [0x00, 0x01, 0x00, 0x04, 0x00, 0x99, 0x00, 0x00];
263        assert!(matches!(
264            MappedSocketAddr::from_raw(&RawAttribute::from_bytes(&data).unwrap()),
265            Err(StunParseError::InvalidAttributeData)
266        ));
267    }
268}