stun_types/attribute/
alternate.rs1use std::convert::TryFrom;
10use std::net::SocketAddr;
11
12use crate::message::StunParseError;
13
14use super::{
15 Attribute, AttributeExt, AttributeFromRaw, AttributeStaticType, AttributeType, AttributeWrite,
16 AttributeWriteExt, MappedSocketAddr, RawAttribute,
17};
18
19#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct AlternateServer {
22 addr: MappedSocketAddr,
23}
24
25impl AttributeStaticType for AlternateServer {
26 const TYPE: AttributeType = AttributeType(0x8023);
27}
28impl Attribute for AlternateServer {
29 fn get_type(&self) -> AttributeType {
30 Self::TYPE
31 }
32
33 fn length(&self) -> u16 {
34 self.addr.length()
35 }
36}
37
38impl AttributeWrite for AlternateServer {
39 fn to_raw(&self) -> RawAttribute {
40 self.addr.to_raw(AlternateServer::TYPE)
41 }
42 fn write_into_unchecked(&self, dest: &mut [u8]) {
43 self.write_header_unchecked(dest);
44 self.addr.write_into_unchecked(&mut dest[4..]);
45 }
46}
47
48impl AttributeFromRaw<'_> for AlternateServer {
49 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError> {
50 Self::try_from(raw)
51 }
52}
53
54impl TryFrom<&RawAttribute<'_>> for AlternateServer {
55 type Error = StunParseError;
56
57 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
58 raw.check_type_and_len(Self::TYPE, ..)?;
59 let addr = MappedSocketAddr::from_raw(raw)?;
60 Ok(Self { addr })
61 }
62}
63
64impl AlternateServer {
65 pub fn new(addr: SocketAddr) -> Self {
76 Self {
77 addr: MappedSocketAddr::new(addr),
78 }
79 }
80
81 pub fn server(&self) -> SocketAddr {
92 self.addr.addr()
93 }
94}
95
96impl std::fmt::Display for AlternateServer {
97 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98 write!(f, "{}: {}", AlternateServer::TYPE, self.addr)
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct AlternateDomain {
105 domain: String,
106}
107
108impl AttributeStaticType for AlternateDomain {
109 const TYPE: AttributeType = AttributeType(0x8003);
110}
111
112impl Attribute for AlternateDomain {
113 fn get_type(&self) -> AttributeType {
114 Self::TYPE
115 }
116 fn length(&self) -> u16 {
117 self.domain.len() as u16
118 }
119}
120impl AttributeFromRaw<'_> for AlternateDomain {
121 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
122 where
123 Self: Sized,
124 {
125 Self::try_from(raw)
126 }
127}
128impl TryFrom<&RawAttribute<'_>> for AlternateDomain {
129 type Error = StunParseError;
130
131 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
132 raw.check_type_and_len(Self::TYPE, ..)?;
133 Ok(Self {
135 domain: std::str::from_utf8(&raw.value)
136 .map_err(|_| StunParseError::InvalidAttributeData)?
137 .to_owned(),
138 })
139 }
140}
141impl AttributeWrite for AlternateDomain {
142 fn to_raw(&self) -> RawAttribute {
143 RawAttribute::new(AlternateDomain::TYPE, self.domain.as_bytes())
144 }
145 fn write_into_unchecked(&self, dest: &mut [u8]) {
146 let len = self.padded_len();
147 self.write_header_unchecked(dest);
148 dest[4..4 + self.domain.len()].copy_from_slice(self.domain.as_bytes());
149 let offset = 4 + self.domain.len();
150 if len > offset {
151 dest[offset..len].fill(0);
152 }
153 }
154}
155
156impl AlternateDomain {
157 pub fn new(domain: &str) -> Self {
168 Self {
169 domain: domain.to_string(),
170 }
171 }
172
173 pub fn domain(&self) -> &str {
184 &self.domain
185 }
186}
187
188impl std::fmt::Display for AlternateDomain {
189 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190 write!(f, "{}: {}", AlternateDomain::TYPE, self.domain)
191 }
192}
193
194#[cfg(test)]
195mod tests {
196 use super::*;
197 use byteorder::{BigEndian, ByteOrder};
198 use tracing::trace;
199
200 #[test]
201 fn alternate_server() {
202 let _log = crate::tests::test_init_log();
203 let addrs = &[
204 "192.168.0.1:40000".parse().unwrap(),
205 "[fd12:3456:789a:1::1]:41000".parse().unwrap(),
206 ];
207 for addr in addrs {
208 let mapped = AlternateServer::new(*addr);
209 trace!("{mapped}");
210 assert_eq!(mapped.server(), *addr);
211 match addr {
212 SocketAddr::V4(_) => assert_eq!(mapped.length(), 8),
213 SocketAddr::V6(_) => assert_eq!(mapped.length(), 20),
214 }
215 let raw = RawAttribute::from(&mapped);
216 trace!("{raw}");
217 assert_eq!(raw.get_type(), AlternateServer::TYPE);
218 let mapped2 = AlternateServer::try_from(&raw).unwrap();
219 assert_eq!(mapped2.server(), *addr);
220 let mut data: Vec<_> = raw.clone().into();
222 let len = data.len();
223 BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
224 assert!(matches!(
225 AlternateServer::try_from(
226 &RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()
227 ),
228 Err(StunParseError::Truncated {
229 expected: _,
230 actual: _
231 })
232 ));
233 let mut data: Vec<_> = raw.clone().into();
235 BigEndian::write_u16(&mut data[0..2], 0);
236 assert!(matches!(
237 AlternateServer::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
238 Err(StunParseError::WrongAttributeImplementation)
239 ));
240
241 let mut dest = vec![0; raw.padded_len()];
242 mapped.write_into(&mut dest).unwrap();
243 let raw = RawAttribute::from_bytes(&dest).unwrap();
244 let mapped2 = AlternateServer::try_from(&raw).unwrap();
245 assert_eq!(mapped2.server(), *addr);
246 }
247 }
248
249 #[test]
250 fn alternative_domain() {
251 let _log = crate::tests::test_init_log();
252 let dns = "example.com";
253 let attr = AlternateDomain::new(dns);
254 trace!("{attr}");
255 assert_eq!(attr.domain(), dns);
256 assert_eq!(attr.length() as usize, dns.len());
257 let raw = RawAttribute::from(&attr);
258 trace!("{raw}");
259 assert_eq!(raw.get_type(), AlternateDomain::TYPE);
260 let mapped2 = AlternateDomain::try_from(&raw).unwrap();
261 assert_eq!(mapped2.domain(), dns);
262 let mut data: Vec<_> = raw.clone().into();
264 BigEndian::write_u16(&mut data[0..2], 0);
265 assert!(matches!(
266 AlternateDomain::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
267 Err(StunParseError::WrongAttributeImplementation)
268 ));
269 let mut data: Vec<_> = raw.clone().into();
270 data[8] = 0x88;
272 assert!(matches!(
273 AlternateDomain::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
274 Err(StunParseError::InvalidAttributeData)
275 ));
276
277 let mut dest = vec![0; raw.padded_len()];
278 attr.write_into(&mut dest).unwrap();
279 let raw = RawAttribute::from_bytes(&dest).unwrap();
280 let mapped2 = AlternateDomain::try_from(&raw).unwrap();
281 assert_eq!(mapped2.domain(), dns);
282 }
283}