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