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