mycrl_stun/
lib.rs

1//! ## Session Traversal Utilities for NAT (STUN)
2//!
3//! [RFC8445]: https://tools.ietf.org/html/rfc8445
4//! [RFC5626]: https://tools.ietf.org/html/rfc5626
5//! [Section 13]: https://tools.ietf.org/html/rfc8489#section-13
6//!
7//! ### STUN Message Structure
8//!
9//! ```text
10//! 0                   1                   2                   3
11//! 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
12//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13//! |0 0|     STUN Message Type     |         Message Length        |
14//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15//! |                         Magic Cookie                          |
16//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17//! |                                                               |
18//! |                     Transaction ID (96 bits)                  |
19//! |                                                               |
20//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21//! ```
22//!
23//! ### STUN Attributes
24//!
25//! ```text
26//! 0                   1                   2                   3
27//! 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
28//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29//! |         Type                  |            Length             |
30//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31//! |                         Value (variable)                ....
32//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33//! ```
34//!
35//! STUN is intended to be used in the context of one or more NAT
36//! traversal solutions.  These solutions are known as "STUN Usages".
37//! Each usage describes how STUN is utilized to achieve the NAT
38//! traversal solution.  Typically, a usage indicates when STUN messages
39//! get sent, which optional attributes to include, what server is used,
40//! and what authentication mechanism is to be used.  Interactive
41//! Connectivity Establishment (ICE) [RFC8445] is one usage of STUN.
42//! SIP Outbound [RFC5626] is another usage of STUN.  In some cases,
43//! a usage will require extensions to STUN. A STUN extension can be
44//! in the form of new methods, attributes, or error response codes.
45//! More information on STUN Usages can be found in [Section 13].
46
47pub mod attribute;
48pub mod channel;
49pub mod message;
50pub mod util;
51
52pub use self::{
53    attribute::{AttrKind, Transport},
54    channel::ChannelData,
55    message::*,
56};
57
58use std::ops::Range;
59
60use thiserror::Error;
61
62#[derive(Debug, Error)]
63pub enum StunError {
64    #[error("InvalidInput")]
65    InvalidInput,
66    #[error("SummaryFailed")]
67    SummaryFailed,
68    #[error("NotIntegrity")]
69    NotIntegrity,
70    #[error("IntegrityFailed")]
71    IntegrityFailed,
72    #[error("NotCookie")]
73    NotCookie,
74    #[error("UnknownMethod")]
75    UnknownMethod,
76    #[error("FatalError")]
77    FatalError,
78    #[error("Utf8Error: {0}")]
79    Utf8Error(#[from] std::str::Utf8Error),
80    #[error("TryFromSliceError: {0}")]
81    TryFromSliceError(#[from] std::array::TryFromSliceError),
82}
83
84/// STUN Methods Registry
85///
86/// [RFC5389]: https://datatracker.ietf.org/doc/html/rfc5389
87/// [RFC8489]: https://datatracker.ietf.org/doc/html/rfc8489
88/// [RFC8126]: https://datatracker.ietf.org/doc/html/rfc8126
89/// [Section 5]: https://datatracker.ietf.org/doc/html/rfc8489#section-5
90///
91/// A STUN method is a hex number in the range 0x000-0x0FF.  The encoding
92/// of a STUN method into a STUN message is described in [Section 5].
93///
94/// STUN methods in the range 0x000-0x07F are assigned by IETF Review
95/// [RFC8126].  STUN methods in the range 0x080-0x0FF are assigned by
96/// Expert Review [RFC8126].  The responsibility of the expert is to
97/// verify that the selected codepoint(s) is not in use and that the
98/// request is not for an abnormally large number of codepoints.
99/// Technical review of the extension itself is outside the scope of the
100/// designated expert responsibility.
101///
102/// IANA has updated the name for method 0x002 as described below as well
103/// as updated the reference from [RFC5389] to [RFC8489] for the following
104/// STUN methods:
105///
106/// 0x000: Reserved
107/// 0x001: Binding
108/// 0x002: Reserved; was SharedSecret prior to [RFC5389]
109/// 0x003: Allocate
110/// 0x004: Refresh
111/// 0x006: Send
112/// 0x007: Data
113/// 0x008: CreatePermission
114/// 0x009: ChannelBind
115#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
116pub enum Kind {
117    Request,
118    Response,
119    Error,
120}
121
122#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
123pub enum Method {
124    Binding(Kind),
125    Allocate(Kind),
126    CreatePermission(Kind),
127    ChannelBind(Kind),
128    Refresh(Kind),
129    SendIndication,
130    DataIndication,
131}
132
133impl Method {
134    pub fn is_error(&self) -> bool {
135        match self {
136            Method::Binding(Kind::Error)
137            | Method::Refresh(Kind::Error)
138            | Method::Allocate(Kind::Error)
139            | Method::CreatePermission(Kind::Error)
140            | Method::ChannelBind(Kind::Error) => true,
141            _ => false,
142        }
143    }
144}
145
146impl TryFrom<u16> for Method {
147    type Error = StunError;
148
149    /// # Test
150    ///
151    /// ```
152    /// use std::convert::TryFrom;
153    /// use stun::*;
154    ///
155    /// assert_eq!(
156    ///     Method::try_from(0x0001).unwrap(),
157    ///     Method::Binding(Kind::Request)
158    /// );
159    /// assert_eq!(
160    ///     Method::try_from(0x0101).unwrap(),
161    ///     Method::Binding(Kind::Response)
162    /// );
163    /// assert_eq!(
164    ///     Method::try_from(0x0111).unwrap(),
165    ///     Method::Binding(Kind::Error)
166    /// );
167    /// assert_eq!(
168    ///     Method::try_from(0x0003).unwrap(),
169    ///     Method::Allocate(Kind::Request)
170    /// );
171    /// assert_eq!(
172    ///     Method::try_from(0x0103).unwrap(),
173    ///     Method::Allocate(Kind::Response)
174    /// );
175    /// assert_eq!(
176    ///     Method::try_from(0x0113).unwrap(),
177    ///     Method::Allocate(Kind::Error)
178    /// );
179    /// assert_eq!(
180    ///     Method::try_from(0x0008).unwrap(),
181    ///     Method::CreatePermission(Kind::Request)
182    /// );
183    /// assert_eq!(
184    ///     Method::try_from(0x0108).unwrap(),
185    ///     Method::CreatePermission(Kind::Response)
186    /// );
187    /// assert_eq!(
188    ///     Method::try_from(0x0118).unwrap(),
189    ///     Method::CreatePermission(Kind::Error)
190    /// );
191    /// assert_eq!(
192    ///     Method::try_from(0x0009).unwrap(),
193    ///     Method::ChannelBind(Kind::Request)
194    /// );
195    /// assert_eq!(
196    ///     Method::try_from(0x0109).unwrap(),
197    ///     Method::ChannelBind(Kind::Response)
198    /// );
199    /// assert_eq!(
200    ///     Method::try_from(0x0119).unwrap(),
201    ///     Method::ChannelBind(Kind::Error)
202    /// );
203    /// assert_eq!(
204    ///     Method::try_from(0x0004).unwrap(),
205    ///     Method::Refresh(Kind::Request)
206    /// );
207    /// assert_eq!(
208    ///     Method::try_from(0x0104).unwrap(),
209    ///     Method::Refresh(Kind::Response)
210    /// );
211    /// assert_eq!(
212    ///     Method::try_from(0x0114).unwrap(),
213    ///     Method::Refresh(Kind::Error)
214    /// );
215    /// assert_eq!(Method::try_from(0x0016).unwrap(), Method::SendIndication);
216    /// assert_eq!(Method::try_from(0x0017).unwrap(), Method::DataIndication);
217    /// ```
218    fn try_from(value: u16) -> Result<Self, Self::Error> {
219        Ok(match value {
220            0x0001 => Self::Binding(Kind::Request),
221            0x0101 => Self::Binding(Kind::Response),
222            0x0111 => Self::Binding(Kind::Error),
223            0x0003 => Self::Allocate(Kind::Request),
224            0x0103 => Self::Allocate(Kind::Response),
225            0x0113 => Self::Allocate(Kind::Error),
226            0x0008 => Self::CreatePermission(Kind::Request),
227            0x0108 => Self::CreatePermission(Kind::Response),
228            0x0118 => Self::CreatePermission(Kind::Error),
229            0x0009 => Self::ChannelBind(Kind::Request),
230            0x0109 => Self::ChannelBind(Kind::Response),
231            0x0119 => Self::ChannelBind(Kind::Error),
232            0x0004 => Self::Refresh(Kind::Request),
233            0x0104 => Self::Refresh(Kind::Response),
234            0x0114 => Self::Refresh(Kind::Error),
235            0x0016 => Self::SendIndication,
236            0x0017 => Self::DataIndication,
237            _ => return Err(StunError::UnknownMethod),
238        })
239    }
240}
241
242impl From<Method> for u16 {
243    /// # Test
244    ///
245    /// ```
246    /// use std::convert::Into;
247    /// use stun::*;
248    ///
249    /// assert_eq!(0x0001u16, Method::Binding(Kind::Request).into());
250    /// assert_eq!(0x0101u16, Method::Binding(Kind::Response).into());
251    /// assert_eq!(0x0111u16, Method::Binding(Kind::Error).into());
252    /// assert_eq!(0x0003u16, Method::Allocate(Kind::Request).into());
253    /// assert_eq!(0x0103u16, Method::Allocate(Kind::Response).into());
254    /// assert_eq!(0x0113u16, Method::Allocate(Kind::Error).into());
255    /// assert_eq!(0x0008u16, Method::CreatePermission(Kind::Request).into());
256    /// assert_eq!(0x0108u16, Method::CreatePermission(Kind::Response).into());
257    /// assert_eq!(0x0118u16, Method::CreatePermission(Kind::Error).into());
258    /// assert_eq!(0x0009u16, Method::ChannelBind(Kind::Request).into());
259    /// assert_eq!(0x0109u16, Method::ChannelBind(Kind::Response).into());
260    /// assert_eq!(0x0119u16, Method::ChannelBind(Kind::Error).into());
261    /// assert_eq!(0x0004u16, Method::Refresh(Kind::Request).into());
262    /// assert_eq!(0x0104u16, Method::Refresh(Kind::Response).into());
263    /// assert_eq!(0x0114u16, Method::Refresh(Kind::Error).into());
264    /// assert_eq!(0x0016u16, Method::SendIndication.into());
265    /// assert_eq!(0x0017u16, Method::DataIndication.into());
266    /// ```
267    fn from(val: Method) -> Self {
268        match val {
269            Method::Binding(Kind::Request) => 0x0001,
270            Method::Binding(Kind::Response) => 0x0101,
271            Method::Binding(Kind::Error) => 0x0111,
272            Method::Allocate(Kind::Request) => 0x0003,
273            Method::Allocate(Kind::Response) => 0x0103,
274            Method::Allocate(Kind::Error) => 0x0113,
275            Method::CreatePermission(Kind::Request) => 0x0008,
276            Method::CreatePermission(Kind::Response) => 0x0108,
277            Method::CreatePermission(Kind::Error) => 0x0118,
278            Method::ChannelBind(Kind::Request) => 0x0009,
279            Method::ChannelBind(Kind::Response) => 0x0109,
280            Method::ChannelBind(Kind::Error) => 0x0119,
281            Method::Refresh(Kind::Request) => 0x0004,
282            Method::Refresh(Kind::Response) => 0x0104,
283            Method::Refresh(Kind::Error) => 0x0114,
284            Method::SendIndication => 0x0016,
285            Method::DataIndication => 0x0017,
286        }
287    }
288}
289
290#[derive(Debug)]
291pub enum Payload<'a> {
292    Message(MessageReader<'a>),
293    ChannelData(ChannelData<'a>),
294}
295
296/// A cache of the list of attributes, this is for internal use only.
297#[derive(Debug)]
298pub struct Attributes(Vec<(AttrKind, Range<usize>)>);
299
300impl Default for Attributes {
301    fn default() -> Self {
302        Self(Vec::with_capacity(20))
303    }
304}
305
306impl Attributes {
307    /// Adds an attribute to the list.
308    pub fn append(&mut self, kind: AttrKind, range: Range<usize>) {
309        self.0.push((kind, range));
310    }
311
312    /// Gets an attribute from the list.
313    ///
314    /// Note: This function will only look for the first matching property in
315    /// the list and return it.
316    pub fn get(&self, kind: &AttrKind) -> Option<Range<usize>> {
317        self.0
318            .iter()
319            .find(|(k, _)| k == kind)
320            .map(|(_, v)| v.clone())
321    }
322
323    /// Gets all the values of an attribute from a list.
324    ///
325    /// Normally a stun message can have multiple attributes with the same name,
326    /// and this function will all the values of the current attribute.
327    pub fn get_all<'a>(&'a self, kind: &'a AttrKind) -> impl Iterator<Item = &'a Range<usize>> {
328        self.0
329            .iter()
330            .filter(move |(k, _)| k == kind)
331            .map(|(_, v)| v)
332            .into_iter()
333    }
334
335    pub fn clear(&mut self) {
336        if !self.0.is_empty() {
337            self.0.clear();
338        }
339    }
340}
341
342#[derive(Default)]
343pub struct Decoder(Attributes);
344
345impl Decoder {
346    /// # Test
347    ///
348    /// ```
349    /// use stun::attribute::*;
350    /// use stun::*;
351    ///
352    /// let buffer = [
353    ///     0x00, 0x01, 0x00, 0x4c, 0x21, 0x12, 0xa4, 0x42, 0x71, 0x66, 0x46, 0x31,
354    ///     0x2b, 0x59, 0x79, 0x65, 0x56, 0x69, 0x32, 0x72, 0x00, 0x06, 0x00, 0x09,
355    ///     0x55, 0x43, 0x74, 0x39, 0x3a, 0x56, 0x2f, 0x2b, 0x2f, 0x00, 0x00, 0x00,
356    ///     0xc0, 0x57, 0x00, 0x04, 0x00, 0x00, 0x03, 0xe7, 0x80, 0x29, 0x00, 0x08,
357    ///     0x22, 0x49, 0xda, 0x28, 0x2c, 0x6f, 0x2e, 0xdb, 0x00, 0x24, 0x00, 0x04,
358    ///     0x6e, 0x00, 0x28, 0xff, 0x00, 0x08, 0x00, 0x14, 0x19, 0x58, 0xda, 0x38,
359    ///     0xed, 0x1e, 0xdd, 0xc8, 0x6b, 0x8e, 0x22, 0x63, 0x3a, 0x22, 0x63, 0x97,
360    ///     0xcf, 0xf5, 0xde, 0x82, 0x80, 0x28, 0x00, 0x04, 0x56, 0xf7, 0xa3, 0xed,
361    /// ];
362    ///
363    /// let mut decoder = Decoder::default();
364    /// let payload = decoder.decode(&buffer).unwrap();
365    /// if let Payload::Message(reader) = payload {
366    ///     assert!(reader.get::<UserName>().is_some())
367    /// }
368    /// ```
369    pub fn decode<'a>(&'a mut self, bytes: &'a [u8]) -> Result<Payload<'a>, StunError> {
370        assert!(bytes.len() >= 4);
371
372        let flag = bytes[0] >> 6;
373        if flag > 3 {
374            return Err(StunError::InvalidInput);
375        }
376
377        Ok(if flag == 0 {
378            self.0.clear();
379
380            Payload::Message(MessageReader::decode(bytes, &mut self.0)?)
381        } else {
382            Payload::ChannelData(ChannelData::try_from(bytes)?)
383        })
384    }
385
386    /// # Test
387    ///
388    /// ```
389    /// use stun::attribute::*;
390    /// use stun::*;
391    ///
392    /// let buffer = [
393    ///     0x00, 0x01, 0x00, 0x4c, 0x21, 0x12, 0xa4, 0x42, 0x71, 0x66, 0x46, 0x31,
394    ///     0x2b, 0x59, 0x79, 0x65, 0x56, 0x69, 0x32, 0x72, 0x00, 0x06, 0x00, 0x09,
395    ///     0x55, 0x43, 0x74, 0x39, 0x3a, 0x56, 0x2f, 0x2b, 0x2f, 0x00, 0x00, 0x00,
396    ///     0xc0, 0x57, 0x00, 0x04, 0x00, 0x00, 0x03, 0xe7, 0x80, 0x29, 0x00, 0x08,
397    ///     0x22, 0x49, 0xda, 0x28, 0x2c, 0x6f, 0x2e, 0xdb, 0x00, 0x24, 0x00, 0x04,
398    ///     0x6e, 0x00, 0x28, 0xff, 0x00, 0x08, 0x00, 0x14, 0x19, 0x58, 0xda, 0x38,
399    ///     0xed, 0x1e, 0xdd, 0xc8, 0x6b, 0x8e, 0x22, 0x63, 0x3a, 0x22, 0x63, 0x97,
400    ///     0xcf, 0xf5, 0xde, 0x82, 0x80, 0x28, 0x00, 0x04, 0x56, 0xf7, 0xa3, 0xed,
401    /// ];
402    ///
403    /// let size = Decoder::message_size(&buffer, false).unwrap();
404    /// assert_eq!(size, 96);
405    /// ```
406    pub fn message_size(bytes: &[u8], is_tcp: bool) -> Result<usize, StunError> {
407        let flag = bytes[0] >> 6;
408        if flag > 3 {
409            return Err(StunError::InvalidInput);
410        }
411
412        Ok(if flag == 0 {
413            MessageReader::message_size(bytes)?
414        } else {
415            ChannelData::message_size(bytes, is_tcp)?
416        })
417    }
418}