1use 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum AddressFamily {
20 IPV4,
22 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#[derive(Debug, Clone, PartialEq, Eq)]
54pub struct MappedSocketAddr {
55 addr: SocketAddr,
56}
57
58impl MappedSocketAddr {
59 pub fn new(addr: SocketAddr) -> Self {
61 Self { addr }
62 }
63
64 pub fn length(&self) -> u16 {
66 match self.addr {
67 SocketAddr::V4(_) => 8,
68 SocketAddr::V6(_) => 20,
69 }
70 }
71
72 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 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 check_len(raw.value.len(), 8..=8)?;
102 IpAddr::V4(Ipv4Addr::from(BigEndian::read_u32(&raw.value[4..8])))
103 }
104 AddressFamily::IPV6 => {
105 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 pub fn addr(&self) -> SocketAddr {
119 self.addr
120 }
121
122 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#[derive(Debug, Clone, PartialEq, Eq)]
156#[repr(transparent)]
157pub struct XorSocketAddr {
158 pub addr: MappedSocketAddr,
160}
161
162impl XorSocketAddr {
163 pub fn new(addr: SocketAddr, transaction: TransactionId) -> Self {
165 Self {
166 addr: MappedSocketAddr::new(XorSocketAddr::xor_addr(addr, transaction)),
167 }
168 }
169
170 pub fn length(&self) -> u16 {
172 self.addr.length()
173 }
174
175 pub fn to_raw<'a>(&self, atype: AttributeType) -> RawAttribute<'a> {
177 self.addr.to_raw(atype)
178 }
179
180 pub fn from_raw(raw: &RawAttribute) -> Result<Self, StunParseError> {
182 let addr = MappedSocketAddr::from_raw(raw)?;
183 Ok(Self { addr })
184 }
185
186 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 pub fn addr(&self, transaction: TransactionId) -> SocketAddr {
211 XorSocketAddr::xor_addr(self.addr.addr(), transaction)
212 }
213
214 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}