stun_types/attribute/mod.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//! STUN Attributes
10//!
11//! Provides implementations for generating, parsing and manipulating STUN attributes as specified
12//! in one of [RFC8489], [RFC5389], or [RFC3489].
13//!
14//! There are two levels of attribute implementations:
15//! 1. A generic [`RawAttribute`] which contains the [`AttributeHeader`] (type and length) and the
16//! byte sequence of data (either borrowed or owned). Parsing a
17//! [`Message`](crate::message::Message) will only perform zerocopy parsing to this level. Any
18//! attribute-specific restrictions on the actual contents of the data should be performed by
19//! concrete attribute implementations.
20//! 2. Concrete implementations based on implementing [`Attribute`], and [`AttributeStaticType`].
21//! These concrete attribute implementations have much more ergonomic API specific to their
22//! particular needs. A concrete attribute implementation may have restrictions on what data is
23//! allowed to be parsed from a [`RawAttribute`] that should return errors when calling
24//! [`AttributeFromRaw::from_raw_ref`].
25//!
26//! [RFC8489]: https://tools.ietf.org/html/rfc8489
27//! [RFC5389]: https://tools.ietf.org/html/rfc5389
28//! [RFC3489]: https://tools.ietf.org/html/rfc3489
29//!
30//! # Examples
31//!
32//! ### Parse and write an already defined [`Attribute`]
33//!
34//! ```
35//! # use stun_types::prelude::*;
36//! use stun_types::attribute::{RawAttribute, Software};
37//! let software_name = "stun-types";
38//! let software = Software::new(software_name).unwrap();
39//! assert_eq!(software.software(), software_name);
40//!
41//! let attribute_data = [
42//! 0x80, 0x22, 0x00, 0x0a, // Attribute type (0x8022: Software) and length (0x000a)
43//! 0x73, 0x74, 0x75, 0x6E, // s t u n
44//! 0x2D, 0x74, 0x79, 0x70, // - t y p
45//! 0x65, 0x73, 0x00, 0x00 // e s
46//! ];
47//!
48//! let raw = RawAttribute::from(&software);
49//! assert_eq!(raw.to_bytes(), attribute_data);
50//!
51//! // Can also parse data into a typed attribute as needed
52//! let software = Software::from_raw(raw).unwrap();
53//! assert_eq!(software.software(), software_name);
54//! ```
55//!
56//! ### Defining your own [`Attribute`]
57//!
58//! ```
59//! # use stun_types::prelude::*;
60//! use byteorder::{BigEndian, ByteOrder};
61//! use stun_types::attribute::{AttributeType, RawAttribute};
62//! use stun_types::message::StunParseError;
63//! #[derive(Debug)]
64//! struct MyAttribute {
65//! value: u32,
66//! }
67//! impl AttributeStaticType for MyAttribute {
68//! const TYPE: AttributeType = AttributeType::new(0x8851);
69//! }
70//! impl Attribute for MyAttribute {
71//! fn get_type(&self) -> AttributeType {
72//! Self::TYPE
73//! }
74//!
75//! fn length(&self) -> u16 {
76//! 4
77//! }
78//! }
79//! impl AttributeWrite for MyAttribute {
80//! fn to_raw(&self) -> RawAttribute<'_> {
81//! let mut ret = [0; 4];
82//! BigEndian::write_u32(&mut ret, self.value);
83//! RawAttribute::new(MyAttribute::TYPE, &ret).into_owned()
84//! }
85//! fn write_into_unchecked(&self, dest: &mut [u8]) {
86//! self.write_header_unchecked(dest);
87//! BigEndian::write_u32(&mut dest[4..], self.value);
88//! }
89//! }
90//! impl AttributeFromRaw<'_> for MyAttribute {
91//! fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
92//! where
93//! Self: Sized,
94//! {
95//! raw.check_type_and_len(Self::TYPE, 4..=4)?;
96//! let value = BigEndian::read_u32(&raw.value);
97//! Ok(Self {
98//! value,
99//! })
100//! }
101//! }
102//!
103//! // Optional: if you want this attribute to be displayed nicely when the corresponding
104//! // `RawAttribute` (based on `AttributeType`) is formatted using `RawAttribute`'s `Display`
105//! // implementation.
106//! impl core::fmt::Display for MyAttribute {
107//! fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
108//! write!(f, "MyAttribute: {}", self.value)
109//! }
110//! }
111//! # #[cfg(feature = "std")]
112//! stun_types::attribute_display!(MyAttribute);
113//! # #[cfg(feature = "std")]
114//! MyAttribute::TYPE.add_name("MY-ATTRIBUTE");
115//!
116//! let my_attr = MyAttribute { value: 0x4729 };
117//! let raw = RawAttribute::from(&my_attr);
118//!
119//! let attribute_data = [
120//! 0x88, 0x51, 0x00, 0x04,
121//! 0x00, 0x00, 0x47, 0x29,
122//! ];
123//! assert_eq!(raw.to_bytes(), attribute_data);
124//!
125//! let my_attr = MyAttribute::from_raw(raw).unwrap();
126//! assert_eq!(my_attr.value, 0x4729);
127//! ```
128
129macro_rules! bytewise_xor {
130 ($size:literal, $a:expr, $b:expr, $default:literal) => {{
131 let mut arr = [$default; $size];
132 for (i, item) in arr.iter_mut().enumerate() {
133 *item = $a[i] ^ $b[i];
134 }
135 arr
136 }};
137}
138
139mod address;
140pub use address::{MappedSocketAddr, XorSocketAddr};
141mod alternate;
142pub use alternate::{AlternateDomain, AlternateServer};
143mod error;
144pub use error::{ErrorCode, UnknownAttributes};
145mod integrity;
146pub use integrity::{MessageIntegrity, MessageIntegritySha256};
147mod fingerprint;
148pub use fingerprint::Fingerprint;
149mod nonce;
150pub use nonce::Nonce;
151mod password_algorithm;
152pub use password_algorithm::{PasswordAlgorithm, PasswordAlgorithmValue, PasswordAlgorithms};
153mod realm;
154pub use realm::Realm;
155mod user;
156pub use user::{Userhash, Username};
157mod software;
158pub use software::Software;
159mod xor_addr;
160pub use xor_addr::XorMappedAddress;
161
162use crate::data::Data;
163use crate::message::{StunParseError, StunWriteError};
164use alloc::boxed::Box;
165use alloc::vec::Vec;
166
167use byteorder::{BigEndian, ByteOrder};
168
169#[cfg(feature = "std")]
170use alloc::collections::BTreeMap;
171#[cfg(feature = "std")]
172use std::sync::{Mutex, OnceLock};
173
174/// A closure definition for an externally provided `Display` implementation for a [`RawAttribute`].
175///
176/// Typically, a concrete [`Attribute`] implements `Display` and
177/// [`attribute_display`](crate::attribute_display) can be used
178/// to generate and install this closure.
179///
180/// See the module level documentation for an example.
181pub type AttributeDisplay =
182 fn(&RawAttribute<'_>, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result;
183#[cfg(feature = "std")]
184static ATTRIBUTE_EXTERNAL_DISPLAY_IMPL: OnceLock<Mutex<BTreeMap<AttributeType, AttributeDisplay>>> =
185 OnceLock::new();
186
187/// Adds an externally provided Display implementation for a particular [`AttributeType`]. Any
188/// previous implementation is overidden.
189#[cfg(feature = "std")]
190pub fn add_display_impl(atype: AttributeType, imp: AttributeDisplay) {
191 let mut display_impls = ATTRIBUTE_EXTERNAL_DISPLAY_IMPL
192 .get_or_init(Default::default)
193 .lock()
194 .unwrap();
195 display_impls.insert(atype, imp);
196}
197
198/// Implement an [`AttributeDisplay`] closure for an [`Attribute`] from a [`RawAttribute`] and calls
199/// [`add_display_impl`] with the generated closure.
200///
201/// # Examples
202/// ```
203/// use stun_types::attribute::{AttributeType, Attribute, AttributeStaticType, AttributeFromRaw};
204/// use stun_types::attribute::RawAttribute;
205/// use stun_types::message::StunParseError;
206/// #[derive(Debug)]
207/// struct MyAttribute {}
208/// impl AttributeStaticType for MyAttribute {
209/// const TYPE: AttributeType = AttributeType::new(0x8852);
210/// }
211/// impl Attribute for MyAttribute {
212/// fn get_type(&self) -> AttributeType {
213/// Self::TYPE
214/// }
215/// fn length(&self) -> u16 {
216/// 0
217/// }
218/// }
219/// impl AttributeFromRaw<'_> for MyAttribute {
220/// fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
221/// where
222/// Self: Sized,
223/// {
224/// raw.check_type_and_len(Self::TYPE, 0..=0)?;
225/// Ok(Self {})
226/// }
227/// }
228/// // An Attribute would also implement AttributeWrite but that has been omitted for brevity.
229/// impl core::fmt::Display for MyAttribute {
230/// fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
231/// write!(f, "MyAttribute")
232/// }
233/// }
234/// # #[cfg(feature = "std")]
235/// # {
236/// stun_types::attribute_display!(MyAttribute);
237/// let attr = RawAttribute::new(MyAttribute::TYPE, &[]);
238/// let display_str = format!("{attr}");
239/// assert_eq!(display_str, "MyAttribute");
240/// # }
241/// ```
242#[macro_export]
243macro_rules! attribute_display {
244 ($typ:ty) => {{
245 let imp = |attr: &$crate::attribute::RawAttribute<'_>,
246 f: &mut core::fmt::Formatter<'_>|
247 -> core::fmt::Result {
248 if let Ok(attr) = <$typ>::from_raw_ref(attr) {
249 write!(f, "{}", attr)
250 } else {
251 write!(
252 f,
253 "{}(Malformed): len: {}, data: {:?})",
254 attr.get_type(),
255 attr.header.length(),
256 attr.value
257 )
258 }
259 };
260
261 $crate::attribute::add_display_impl(<$typ>::TYPE, imp);
262 }};
263}
264
265#[cfg(feature = "std")]
266static ATTRIBUTE_TYPE_NAME_MAP: OnceLock<Mutex<BTreeMap<AttributeType, &'static str>>> =
267 OnceLock::new();
268
269/// The type of an [`Attribute`] in a STUN [`Message`](crate::message::Message)
270#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
271pub struct AttributeType(u16);
272
273impl core::fmt::Display for AttributeType {
274 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
275 write!(f, "{}({:#x}: {})", self.0, self.0, self.name())
276 }
277}
278
279impl AttributeType {
280 /// Add the name for a particular [`AttributeType`] for formatting purposes.
281 #[cfg(feature = "std")]
282 pub fn add_name(self, name: &'static str) {
283 let mut anames = ATTRIBUTE_TYPE_NAME_MAP
284 .get_or_init(Default::default)
285 .lock()
286 .unwrap();
287 anames.insert(self, name);
288 }
289
290 /// Create a new AttributeType from an existing value
291 ///
292 /// Note: the value passed in is not encoded as in a stun message
293 ///
294 /// # Examples
295 /// ```
296 /// # use stun_types::attribute::AttributeType;
297 /// assert_eq!(AttributeType::new(0x123).value(), 0x123);
298 /// ```
299 pub const fn new(val: u16) -> Self {
300 Self(val)
301 }
302
303 /// Return the integer value of this AttributeType
304 ///
305 /// Note: the value returned is not encoded as in a stun message
306 ///
307 /// # Examples
308 /// ```
309 /// # use stun_types::attribute::AttributeType;
310 /// assert_eq!(AttributeType::new(0x123).value(), 0x123);
311 /// ```
312 pub fn value(&self) -> u16 {
313 self.0
314 }
315
316 /// Returns a human readable name of this `AttributeType` or "unknown"
317 ///
318 /// # Examples
319 /// ```
320 /// # use stun_types::attribute::*;
321 /// assert_eq!(XorMappedAddress::TYPE.name(), "XOR-MAPPED-ADDRESS");
322 /// ```
323 pub fn name(self) -> &'static str {
324 match self {
325 AttributeType(0x0001) => "MAPPED-ADDRESS",
326 Username::TYPE => "USERNAME",
327 MessageIntegrity::TYPE => "MESSAGE-INTEGRITY",
328 ErrorCode::TYPE => "ERROR-CODE",
329 UnknownAttributes::TYPE => "UNKNOWN-ATTRIBUTES",
330 Realm::TYPE => "REALM",
331 Nonce::TYPE => "NONCE",
332 MessageIntegritySha256::TYPE => "MESSAGE-INTEGRITY-SHA256",
333 PasswordAlgorithm::TYPE => "PASSWORD-ALGORITHM",
334 Userhash::TYPE => "USERHASH",
335 XorMappedAddress::TYPE => "XOR-MAPPED-ADDRESS",
336 PasswordAlgorithms::TYPE => "PASSWORD_ALGORITHMS",
337 AlternateDomain::TYPE => "ALTERNATE-DOMAIN",
338 Software::TYPE => "SOFTWARE",
339 AlternateServer::TYPE => "ALTERNATE-SERVER",
340 Fingerprint::TYPE => "FINGERPRINT",
341 _ => {
342 #[cfg(feature = "std")]
343 {
344 let anames = ATTRIBUTE_TYPE_NAME_MAP
345 .get_or_init(Default::default)
346 .lock()
347 .unwrap();
348 if let Some(name) = anames.get(&self) {
349 return name;
350 }
351 }
352 "unknown"
353 }
354 }
355 }
356
357 /// Check if comprehension is required for an `AttributeType`. All attribute
358 /// values < 0x8000 require comprehension.
359 ///
360 /// # Examples
361 ///
362 /// ```
363 /// # use stun_types::attribute::AttributeType;
364 /// assert_eq!(AttributeType::new(0x0).comprehension_required(), true);
365 /// assert_eq!(AttributeType::new(0x8000).comprehension_required(), false);
366 /// ```
367 pub fn comprehension_required(self) -> bool {
368 self.0 < 0x8000
369 }
370}
371impl From<u16> for AttributeType {
372 fn from(f: u16) -> Self {
373 Self::new(f)
374 }
375}
376impl From<AttributeType> for u16 {
377 fn from(f: AttributeType) -> Self {
378 f.0
379 }
380}
381
382/// Structure for holding the header of a STUN attribute. Contains the type and the length
383#[derive(Debug, Copy, Clone, PartialEq, Eq)]
384pub struct AttributeHeader {
385 atype: AttributeType,
386 length: u16,
387}
388
389impl AttributeHeader {
390 fn parse(data: &[u8]) -> Result<Self, StunParseError> {
391 if data.len() < 4 {
392 return Err(StunParseError::Truncated {
393 expected: 4,
394 actual: data.len(),
395 });
396 }
397 let ret = Self {
398 atype: BigEndian::read_u16(&data[0..2]).into(),
399 length: BigEndian::read_u16(&data[2..4]),
400 };
401 Ok(ret)
402 }
403
404 fn to_bytes(self) -> [u8; 4] {
405 let mut ret = [0; 4];
406 self.write_into(&mut ret);
407 ret
408 }
409
410 fn write_into(&self, ret: &mut [u8]) {
411 BigEndian::write_u16(&mut ret[0..2], self.atype.into());
412 BigEndian::write_u16(&mut ret[2..4], self.length);
413 }
414
415 /// Returns the type of the attribute
416 pub fn get_type(&self) -> AttributeType {
417 self.atype
418 }
419
420 /// Returns the length of the attribute
421 pub fn length(&self) -> u16 {
422 self.length
423 }
424}
425impl From<AttributeHeader> for [u8; 4] {
426 fn from(f: AttributeHeader) -> Self {
427 f.to_bytes()
428 }
429}
430impl TryFrom<&[u8]> for AttributeHeader {
431 type Error = StunParseError;
432
433 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
434 AttributeHeader::parse(value)
435 }
436}
437
438/// A static type for an [`Attribute`]
439pub trait AttributeStaticType {
440 /// The [`AttributeType`]
441 const TYPE: AttributeType;
442}
443
444/// A STUN attribute for use in [`Message`](crate::message::Message)s
445pub trait Attribute: core::fmt::Debug + core::marker::Sync + core::marker::Send {
446 /// Retrieve the type of an `Attribute`.
447 fn get_type(&self) -> AttributeType;
448
449 /// Retrieve the length of an `Attribute`. This is not the padded length as stored in a
450 /// `Message` and does not include the size of the attribute header.
451 fn length(&self) -> u16;
452}
453
454/// A trait for converting from a [`RawAttribute`] to a concrete [`Attribute`].
455pub trait AttributeFromRaw<'a>: Attribute {
456 /// Produce an `Attribute` from a `RawAttribute`
457 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
458 where
459 Self: Sized;
460
461 /// Produce an `Attribute` from a `RawAttribute`
462 fn from_raw(raw: RawAttribute<'a>) -> Result<Self, StunParseError>
463 where
464 Self: Sized,
465 {
466 Self::from_raw_ref(&raw)
467 }
468}
469
470fn padded_attr_len(len: usize) -> usize {
471 if len % 4 == 0 {
472 len
473 } else {
474 len + 4 - len % 4
475 }
476}
477
478/// Automatically implemented trait providing some helper functions for [`Attribute`]s.
479pub trait AttributeExt {
480 /// The length in bytes of an [`Attribute`] as stored in a [`Message`](crate::message::Message)
481 /// including any padding and the attribute header.
482 fn padded_len(&self) -> usize;
483}
484
485impl<A: Attribute + ?Sized> AttributeExt for A {
486 fn padded_len(&self) -> usize {
487 4 + padded_attr_len(self.length() as usize)
488 }
489}
490
491/// Trait required when implementing writing an [`Attribute`] to a sequence of bytes
492pub trait AttributeWrite: Attribute {
493 /// Write attribute to the provided destination buffer.
494 ///
495 /// Panics if the destination buffer is not large enough
496 fn write_into_unchecked(&self, dest: &mut [u8]);
497 /// Produce a [`RawAttribute`] from this [`Attribute`]
498 fn to_raw(&self) -> RawAttribute<'_>;
499}
500
501/// Automatically implemented trait providing helper functionality for writing an [`Attribute`] to
502/// a sequence of bytes.
503pub trait AttributeWriteExt: AttributeWrite {
504 /// Write the 4 byte attribute header into the provided destination buffer returning the
505 /// number of bytes written.
506 ///
507 /// Panics if the destination cannot hold at least 4 bytes of data.
508 fn write_header_unchecked(&self, dest: &mut [u8]) -> usize;
509 /// Write the 4 byte attribute header into the provided destination buffer returning the
510 /// number of bytes written, or an error.
511 fn write_header(&self, dest: &mut [u8]) -> Result<usize, StunWriteError>;
512 /// Write this attribute into the provided destination buffer returning the number of bytes
513 /// written, or an error.
514 fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError>;
515}
516
517impl<A: AttributeWrite + ?Sized> AttributeWriteExt for A {
518 fn write_header(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
519 if dest.len() < 4 {
520 return Err(StunWriteError::TooSmall {
521 expected: 4,
522 actual: dest.len(),
523 });
524 }
525 self.write_header_unchecked(dest);
526 Ok(4)
527 }
528 fn write_header_unchecked(&self, dest: &mut [u8]) -> usize {
529 AttributeHeader {
530 atype: self.get_type(),
531 length: self.length(),
532 }
533 .write_into(dest);
534 4
535 }
536
537 fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
538 let len = self.padded_len();
539 if len > dest.len() {
540 return Err(StunWriteError::TooSmall {
541 expected: len,
542 actual: dest.len(),
543 });
544 }
545 self.write_into_unchecked(dest);
546 Ok(len)
547 }
548}
549
550/// The header and raw bytes of an unparsed [`Attribute`]
551#[derive(Debug, Clone, PartialEq, Eq)]
552pub struct RawAttribute<'a> {
553 /// The [`AttributeHeader`] of this [`RawAttribute`]
554 pub header: AttributeHeader,
555 /// The raw bytes of this [`RawAttribute`]
556 pub value: Data<'a>,
557}
558
559macro_rules! display_attr {
560 ($this:ident, $f:ident, $CamelType:ty) => {{
561 if let Ok(attr) = <$CamelType>::from_raw_ref($this) {
562 write!($f, "{}", attr)
563 } else {
564 write!(
565 $f,
566 "{}(Malformed): len: {}, data: {:?})",
567 $this.get_type(),
568 $this.header.length(),
569 $this.value
570 )
571 }
572 }};
573}
574
575impl core::fmt::Display for RawAttribute<'_> {
576 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
577 // try to get a more specialised display
578 match self.get_type() {
579 Username::TYPE => display_attr!(self, f, Username),
580 MessageIntegrity::TYPE => display_attr!(self, f, MessageIntegrity),
581 ErrorCode::TYPE => display_attr!(self, f, ErrorCode),
582 UnknownAttributes::TYPE => display_attr!(self, f, UnknownAttributes),
583 Realm::TYPE => display_attr!(self, f, Realm),
584 Nonce::TYPE => display_attr!(self, f, Nonce),
585 MessageIntegritySha256::TYPE => {
586 display_attr!(self, f, MessageIntegritySha256)
587 }
588 PasswordAlgorithm::TYPE => display_attr!(self, f, PasswordAlgorithm),
589 //UserHash::TYPE => display_attr!(self, UserHash),
590 XorMappedAddress::TYPE => display_attr!(self, f, XorMappedAddress),
591 PasswordAlgorithms::TYPE => display_attr!(self, f, PasswordAlgorithms),
592 AlternateDomain::TYPE => display_attr!(self, f, AlternateDomain),
593 Software::TYPE => display_attr!(self, f, Software),
594 AlternateServer::TYPE => display_attr!(self, f, AlternateServer),
595 Fingerprint::TYPE => display_attr!(self, f, Fingerprint),
596 _ => {
597 #[cfg(feature = "std")]
598 {
599 let mut display_impls = ATTRIBUTE_EXTERNAL_DISPLAY_IMPL
600 .get_or_init(|| Default::default())
601 .lock()
602 .unwrap();
603 if let Some(imp) = display_impls.get_mut(&self.get_type()) {
604 return imp(self, f);
605 }
606 }
607 write!(
608 f,
609 "RawAttribute (type: {:?}, len: {}, data: {:?})",
610 self.header.get_type(),
611 self.header.length(),
612 &self.value
613 )
614 }
615 }
616 }
617}
618
619impl<'a> RawAttribute<'a> {
620 /// Create a new [`RawAttribute`]
621 pub fn new(atype: AttributeType, data: &'a [u8]) -> Self {
622 Self {
623 header: AttributeHeader {
624 atype,
625 length: data.len() as u16,
626 },
627 value: data.into(),
628 }
629 }
630
631 /// Create a new owned [`RawAttribute`]
632 pub fn new_owned(atype: AttributeType, data: Box<[u8]>) -> Self {
633 Self {
634 header: AttributeHeader {
635 atype,
636 length: data.len() as u16,
637 },
638 value: data.into(),
639 }
640 }
641
642 /// Deserialize a `RawAttribute` from bytes.
643 ///
644 /// # Examples
645 ///
646 /// ```
647 /// # use stun_types::attribute::{RawAttribute, Attribute, AttributeType};
648 /// let data = &[0, 1, 0, 2, 5, 6, 0, 0];
649 /// let attr = RawAttribute::from_bytes(data).unwrap();
650 /// assert_eq!(attr.get_type(), AttributeType::new(1));
651 /// assert_eq!(attr.length(), 2);
652 /// ```
653 pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
654 let header = AttributeHeader::parse(data)?;
655 // the advertised length is larger than actual data -> error
656 if header.length() > (data.len() - 4) as u16 {
657 return Err(StunParseError::Truncated {
658 expected: header.length() as usize,
659 actual: data.len() - 4,
660 });
661 }
662 Ok(Self {
663 header,
664 value: Data::Borrowed(data[4..header.length() as usize + 4].into()),
665 })
666 }
667
668 /// Serialize a `RawAttribute` to bytes.
669 ///
670 /// # Examples
671 ///
672 /// ```
673 /// # use stun_types::attribute::{RawAttribute, Attribute, AttributeType};
674 /// let attr = RawAttribute::new(AttributeType::new(1), &[5, 6]);
675 /// assert_eq!(attr.to_bytes(), &[0, 1, 0, 2, 5, 6, 0, 0]);
676 /// ```
677 pub fn to_bytes(&self) -> Vec<u8> {
678 let mut vec = Vec::with_capacity(self.padded_len());
679 let mut header_bytes = [0; 4];
680 self.header.write_into(&mut header_bytes);
681 vec.extend(&header_bytes);
682 vec.extend(&*self.value);
683 let len = vec.len();
684 if len % 4 != 0 {
685 // pad to 4 bytes
686 vec.resize(len + 4 - (len % 4), 0);
687 }
688 vec
689 }
690
691 /// Helper for checking that a raw attribute is of a particular type and has a data length
692 /// within a certain range.
693 pub fn check_type_and_len(
694 &self,
695 atype: AttributeType,
696 allowed_range: impl core::ops::RangeBounds<usize>,
697 ) -> Result<(), StunParseError> {
698 if self.header.get_type() != atype {
699 return Err(StunParseError::WrongAttributeImplementation);
700 }
701 check_len(self.value.len(), allowed_range)
702 }
703
704 /// Consume this [`RawAttribute`] and return a new owned [`RawAttribute`]
705 pub fn into_owned<'b>(self) -> RawAttribute<'b> {
706 RawAttribute {
707 header: self.header,
708 value: self.value.into_owned(),
709 }
710 }
711}
712
713impl Attribute for RawAttribute<'_> {
714 /// Returns the [`AttributeType`] of this [`RawAttribute`]
715 fn get_type(&self) -> AttributeType {
716 self.header.get_type()
717 }
718
719 /// Returns the length of this [`RawAttribute`]
720 fn length(&self) -> u16 {
721 self.value.len() as u16
722 }
723}
724
725impl AttributeWrite for RawAttribute<'_> {
726 /// Write this [`RawAttribute`] into a byte slice. Returns the number of bytes written.
727 fn write_into_unchecked(&self, dest: &mut [u8]) {
728 let len = self.padded_len();
729 self.header.write_into(dest);
730 let mut offset = 4;
731 dest[offset..offset + self.value.len()].copy_from_slice(&self.value);
732 offset += self.value.len();
733 if len - offset > 0 {
734 dest[offset..len].fill(0);
735 }
736 }
737
738 fn to_raw(&self) -> RawAttribute<'_> {
739 self.clone()
740 }
741}
742
743impl<'a, A: AttributeWrite> From<&'a A> for RawAttribute<'a> {
744 fn from(value: &'a A) -> Self {
745 value.to_raw()
746 }
747}
748
749fn check_len(
750 len: usize,
751 allowed_range: impl core::ops::RangeBounds<usize>,
752) -> Result<(), StunParseError> {
753 match allowed_range.start_bound() {
754 core::ops::Bound::Unbounded => (),
755 core::ops::Bound::Included(start) => {
756 if len < *start {
757 return Err(StunParseError::Truncated {
758 expected: *start,
759 actual: len,
760 });
761 }
762 }
763 core::ops::Bound::Excluded(start) => {
764 if len <= *start {
765 return Err(StunParseError::Truncated {
766 expected: start + 1,
767 actual: len,
768 });
769 }
770 }
771 }
772 match allowed_range.end_bound() {
773 core::ops::Bound::Unbounded => (),
774 core::ops::Bound::Included(end) => {
775 if len > *end {
776 return Err(StunParseError::TooLarge {
777 expected: *end,
778 actual: len,
779 });
780 }
781 }
782 core::ops::Bound::Excluded(end) => {
783 if len >= *end {
784 return Err(StunParseError::TooLarge {
785 expected: *end - 1,
786 actual: len,
787 });
788 }
789 }
790 }
791 Ok(())
792}
793
794impl From<RawAttribute<'_>> for Vec<u8> {
795 fn from(f: RawAttribute) -> Self {
796 f.to_bytes()
797 }
798}
799
800#[cfg(test)]
801mod tests {
802 use super::*;
803
804 #[test]
805 fn attribute_type() {
806 let _log = crate::tests::test_init_log();
807 let atype = ErrorCode::TYPE;
808 let anum: u16 = atype.into();
809 assert_eq!(atype, anum.into());
810 }
811
812 #[test]
813 fn short_attribute_header() {
814 let _log = crate::tests::test_init_log();
815 let data = [0; 1];
816 // not enough data to parse the header
817 let res: Result<AttributeHeader, _> = data.as_ref().try_into();
818 assert!(res.is_err());
819 }
820
821 #[test]
822 fn raw_attribute_construct() {
823 let _log = crate::tests::test_init_log();
824 let a = RawAttribute::new(1.into(), &[80, 160]);
825 assert_eq!(a.get_type(), 1.into());
826 let bytes: Vec<_> = a.into();
827 assert_eq!(bytes, &[0, 1, 0, 2, 80, 160, 0, 0]);
828 let b = RawAttribute::from_bytes(bytes.as_ref()).unwrap();
829 assert_eq!(b.get_type(), 1.into());
830 }
831
832 #[test]
833 fn raw_attribute_encoding() {
834 let _log = crate::tests::test_init_log();
835 let orig = RawAttribute::new(1.into(), &[80, 160]);
836 assert_eq!(orig.get_type(), 1.into());
837 let mut data: Vec<_> = orig.into();
838 let len = data.len();
839 // one byte too big vs data size
840 BigEndian::write_u16(&mut data[2..4], len as u16 - 4 + 1);
841 assert!(matches!(
842 RawAttribute::from_bytes(data.as_ref()),
843 Err(StunParseError::Truncated {
844 expected: 5,
845 actual: 4
846 })
847 ));
848 }
849
850 #[test]
851 fn test_check_len() {
852 let _log = crate::tests::test_init_log();
853 assert!(check_len(4, ..).is_ok());
854 assert!(check_len(4, 0..).is_ok());
855 assert!(check_len(4, 0..8).is_ok());
856 assert!(check_len(4, 0..=8).is_ok());
857 assert!(check_len(4, ..=8).is_ok());
858 assert!(matches!(
859 check_len(4, ..4),
860 Err(StunParseError::TooLarge {
861 expected: 3,
862 actual: 4
863 })
864 ));
865 assert!(matches!(
866 check_len(4, 5..),
867 Err(StunParseError::Truncated {
868 expected: 5,
869 actual: 4
870 })
871 ));
872 assert!(matches!(
873 check_len(4, ..=3),
874 Err(StunParseError::TooLarge {
875 expected: 3,
876 actual: 4
877 })
878 ));
879 assert!(matches!(
880 check_len(
881 4,
882 (core::ops::Bound::Excluded(4), core::ops::Bound::Unbounded)
883 ),
884 Err(StunParseError::Truncated {
885 expected: 5,
886 actual: 4
887 })
888 ));
889 }
890
891 #[test]
892 #[cfg(feature = "std")]
893 fn test_external_display_impl() {
894 let _log = crate::tests::test_init_log();
895 let atype = AttributeType::new(0xFFFF);
896 let imp = |attr: &RawAttribute<'_>,
897 f: &mut core::fmt::Formatter<'_>|
898 -> core::fmt::Result { write!(f, "Custom {}", attr.value[0]) };
899 add_display_impl(atype, imp);
900 let data = [4, 0];
901 let attr = RawAttribute::new(atype, &data);
902 let display_str = alloc::format!("{}", attr);
903 assert_eq!(display_str, "Custom 4");
904
905 atype.add_name("SOME-NAME");
906 assert_eq!(atype.name(), "SOME-NAME");
907
908 attribute_display!(Fingerprint);
909 }
910}