Skip to main content

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