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 mut out = [0; 8];
835        let mut out2 = [0; 8];
836        let _log = crate::tests::test_init_log();
837        let orig = RawAttribute::new(1.into(), &[80, 160]);
838        assert_eq!(orig.get_type(), 1.into());
839        orig.write_into(&mut out).unwrap();
840        orig.write_into_unchecked(&mut out2);
841        assert_eq!(out, out2);
842        let mut data: Vec<_> = orig.into();
843        let len = data.len();
844        // one byte too big vs data size
845        BigEndian::write_u16(&mut data[2..4], len as u16 - 4 + 1);
846        assert!(matches!(
847            RawAttribute::from_bytes(data.as_ref()),
848            Err(StunParseError::Truncated {
849                expected: 5,
850                actual: 4
851            })
852        ));
853    }
854
855    #[test]
856    fn raw_attribute_header() {
857        let mut out = [0; 4];
858        let mut out2 = [0; 4];
859        let _log = crate::tests::test_init_log();
860        let orig = RawAttribute::new(1.into(), &[80, 160]);
861        assert!(matches!(orig.write_header(&mut out), Ok(4)));
862        assert_eq!(orig.write_header_unchecked(&mut out2), 4);
863        assert_eq!(out, out2);
864        assert_eq!(orig.header.to_bytes(), out);
865        assert_eq!(&orig.to_bytes()[..4], out);
866        let bytes: [_; 4] = orig.header.into();
867        assert_eq!(bytes, out);
868    }
869
870    #[test]
871    fn test_check_len() {
872        let _log = crate::tests::test_init_log();
873        assert!(check_len(4, ..).is_ok());
874        assert!(check_len(4, 0..).is_ok());
875        assert!(check_len(4, 0..8).is_ok());
876        assert!(check_len(4, 0..=8).is_ok());
877        assert!(check_len(4, ..=8).is_ok());
878        assert!(matches!(
879            check_len(4, ..4),
880            Err(StunParseError::TooLarge {
881                expected: 3,
882                actual: 4
883            })
884        ));
885        assert!(matches!(
886            check_len(4, 5..),
887            Err(StunParseError::Truncated {
888                expected: 5,
889                actual: 4
890            })
891        ));
892        assert!(matches!(
893            check_len(4, ..=3),
894            Err(StunParseError::TooLarge {
895                expected: 3,
896                actual: 4
897            })
898        ));
899        assert!(matches!(
900            check_len(
901                4,
902                (core::ops::Bound::Excluded(4), core::ops::Bound::Unbounded)
903            ),
904            Err(StunParseError::Truncated {
905                expected: 5,
906                actual: 4
907            })
908        ));
909    }
910
911    #[test]
912    #[cfg(feature = "std")]
913    fn test_external_display_impl() {
914        let _log = crate::tests::test_init_log();
915        let atype = AttributeType::new(0xFFFF);
916        let imp = |attr: &RawAttribute<'_>,
917                   f: &mut core::fmt::Formatter<'_>|
918         -> core::fmt::Result { write!(f, "Custom {}", attr.value[0]) };
919        add_display_impl(atype, imp);
920        let data = [4, 0];
921        let attr = RawAttribute::new(atype, &data);
922        let display_str = alloc::format!("{}", attr);
923        assert_eq!(display_str, "Custom 4");
924
925        atype.add_name("SOME-NAME");
926        assert_eq!(atype.name(), "SOME-NAME");
927
928        attribute_display!(Fingerprint);
929    }
930}