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