turn_server/stun/
mod.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("NotFoundIntegrity")]
69    NotFoundIntegrity,
70    #[error("IntegrityFailed")]
71    IntegrityFailed,
72    #[error("NotFoundCookie")]
73    NotFoundCookie,
74    #[error("UnknownStunMethod")]
75    UnknownStunMethod,
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#[rustfmt::skip]
85pub mod method {
86    use super::StunError;
87
88    pub const BINDING_REQUEST: StunMethod = StunMethod::Binding(StunMethodKind::Request);
89    pub const BINDING_RESPONSE: StunMethod = StunMethod::Binding(StunMethodKind::Response);
90    pub const BINDING_ERROR: StunMethod = StunMethod::Binding(StunMethodKind::Error);
91    pub const ALLOCATE_REQUEST: StunMethod = StunMethod::Allocate(StunMethodKind::Request);
92    pub const ALLOCATE_RESPONSE: StunMethod = StunMethod::Allocate(StunMethodKind::Response);
93    pub const ALLOCATE_ERROR: StunMethod = StunMethod::Allocate(StunMethodKind::Error);
94    pub const CREATE_PERMISSION_REQUEST: StunMethod = StunMethod::CreatePermission(StunMethodKind::Request);
95    pub const CREATE_PERMISSION_RESPONSE: StunMethod = StunMethod::CreatePermission(StunMethodKind::Response);
96    pub const CREATE_PERMISSION_ERROR: StunMethod = StunMethod::CreatePermission(StunMethodKind::Error);
97    pub const CHANNEL_BIND_REQUEST: StunMethod = StunMethod::ChannelBind(StunMethodKind::Request);
98    pub const CHANNEL_BIND_RESPONSE: StunMethod = StunMethod::ChannelBind(StunMethodKind::Response);
99    pub const CHANNEL_BIND_ERROR: StunMethod = StunMethod::ChannelBind(StunMethodKind::Error);
100    pub const REFRESH_REQUEST: StunMethod = StunMethod::Refresh(StunMethodKind::Request);
101    pub const REFRESH_RESPONSE: StunMethod = StunMethod::Refresh(StunMethodKind::Response);
102    pub const REFRESH_ERROR: StunMethod = StunMethod::Refresh(StunMethodKind::Error);
103    pub const SEND_INDICATION: StunMethod = StunMethod::SendIndication;
104    pub const DATA_INDICATION: StunMethod = StunMethod::DataIndication;
105
106    /// STUN StunMethods Registry
107    ///
108    /// [RFC5389]: https://datatracker.ietf.org/doc/html/rfc5389
109    /// [RFC8489]: https://datatracker.ietf.org/doc/html/rfc8489
110    /// [RFC8126]: https://datatracker.ietf.org/doc/html/rfc8126
111    /// [Section 5]: https://datatracker.ietf.org/doc/html/rfc8489#section-5
112    ///
113    /// A STUN method is a hex number in the range 0x000-0x0FF.  The encoding
114    /// of a STUN method into a STUN message is described in [Section 5].
115    ///
116    /// STUN methods in the range 0x000-0x07F are assigned by IETF Review
117    /// [RFC8126].  STUN methods in the range 0x080-0x0FF are assigned by
118    /// Expert Review [RFC8126].  The responsibility of the expert is to
119    /// verify that the selected codepoint(s) is not in use and that the
120    /// request is not for an abnormally large number of codepoints.
121    /// Technical review of the extension itself is outside the scope of the
122    /// designated expert responsibility.
123    ///
124    /// IANA has updated the name for method 0x002 as described below as well
125    /// as updated the reference from [RFC5389] to [RFC8489] for the following
126    /// STUN methods:
127    ///
128    /// 0x000: Reserved
129    /// 0x001: Binding
130    /// 0x002: Reserved; was SharedSecret prior to [RFC5389]
131    /// 0x003: Allocate
132    /// 0x004: Refresh
133    /// 0x006: Send
134    /// 0x007: Data
135    /// 0x008: CreatePermission
136    /// 0x009: ChannelBind
137    #[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
138    pub enum StunMethodKind {
139        Request,
140        Response,
141        Error,
142    }
143
144    #[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
145    pub enum StunMethod {
146        Binding(StunMethodKind),
147        Allocate(StunMethodKind),
148        CreatePermission(StunMethodKind),
149        ChannelBind(StunMethodKind),
150        Refresh(StunMethodKind),
151        SendIndication,
152        DataIndication,
153    }
154
155    impl StunMethod {
156        pub fn is_error(&self) -> bool {
157            match self {
158                StunMethod::Binding(StunMethodKind::Error)
159                | StunMethod::Refresh(StunMethodKind::Error)
160                | StunMethod::Allocate(StunMethodKind::Error)
161                | StunMethod::CreatePermission(StunMethodKind::Error)
162                | StunMethod::ChannelBind(StunMethodKind::Error) => true,
163                _ => false,
164            }
165        }
166    }
167
168    impl TryFrom<u16> for StunMethod {
169        type Error = StunError;
170
171        /// # Test
172        ///
173        /// ```
174        /// use turn_server::stun::method::*;
175        /// use std::convert::TryFrom;
176        ///
177        /// assert_eq!(StunMethod::try_from(0x0001).unwrap(), BINDING_REQUEST);
178        /// assert_eq!(StunMethod::try_from(0x0101).unwrap(), BINDING_RESPONSE);
179        /// assert_eq!(StunMethod::try_from(0x0111).unwrap(), BINDING_ERROR);
180        /// assert_eq!(StunMethod::try_from(0x0003).unwrap(), ALLOCATE_REQUEST);
181        /// assert_eq!(StunMethod::try_from(0x0103).unwrap(), ALLOCATE_RESPONSE);
182        /// assert_eq!(StunMethod::try_from(0x0113).unwrap(), ALLOCATE_ERROR);
183        /// assert_eq!(StunMethod::try_from(0x0008).unwrap(), CREATE_PERMISSION_REQUEST);
184        /// assert_eq!(StunMethod::try_from(0x0108).unwrap(), CREATE_PERMISSION_RESPONSE);
185        /// assert_eq!(StunMethod::try_from(0x0118).unwrap(), CREATE_PERMISSION_ERROR);
186        /// assert_eq!(StunMethod::try_from(0x0009).unwrap(), CHANNEL_BIND_REQUEST);
187        /// assert_eq!(StunMethod::try_from(0x0109).unwrap(), CHANNEL_BIND_RESPONSE);
188        /// assert_eq!(StunMethod::try_from(0x0119).unwrap(), CHANNEL_BIND_ERROR);
189        /// assert_eq!(StunMethod::try_from(0x0004).unwrap(), REFRESH_REQUEST);
190        /// assert_eq!(StunMethod::try_from(0x0104).unwrap(), REFRESH_RESPONSE);
191        /// assert_eq!(StunMethod::try_from(0x0114).unwrap(), REFRESH_ERROR);
192        /// assert_eq!(StunMethod::try_from(0x0016).unwrap(), SEND_INDICATION);
193        /// assert_eq!(StunMethod::try_from(0x0017).unwrap(), DATA_INDICATION);
194        /// ```
195        fn try_from(value: u16) -> Result<Self, Self::Error> {
196            Ok(match value {
197                0x0001 => Self::Binding(StunMethodKind::Request),
198                0x0101 => Self::Binding(StunMethodKind::Response),
199                0x0111 => Self::Binding(StunMethodKind::Error),
200                0x0003 => Self::Allocate(StunMethodKind::Request),
201                0x0103 => Self::Allocate(StunMethodKind::Response),
202                0x0113 => Self::Allocate(StunMethodKind::Error),
203                0x0008 => Self::CreatePermission(StunMethodKind::Request),
204                0x0108 => Self::CreatePermission(StunMethodKind::Response),
205                0x0118 => Self::CreatePermission(StunMethodKind::Error),
206                0x0009 => Self::ChannelBind(StunMethodKind::Request),
207                0x0109 => Self::ChannelBind(StunMethodKind::Response),
208                0x0119 => Self::ChannelBind(StunMethodKind::Error),
209                0x0004 => Self::Refresh(StunMethodKind::Request),
210                0x0104 => Self::Refresh(StunMethodKind::Response),
211                0x0114 => Self::Refresh(StunMethodKind::Error),
212                0x0016 => Self::SendIndication,
213                0x0017 => Self::DataIndication,
214                _ => return Err(StunError::UnknownStunMethod),
215            })
216        }
217    }
218
219    impl Into<u16> for StunMethod {
220        /// # Test
221        ///
222        /// ```
223        /// use turn_server::stun::method::*;
224        /// use std::convert::Into;
225        ///
226        /// assert_eq!(0x0001u16, <StunMethod as Into<u16>>::into(BINDING_REQUEST));
227        /// assert_eq!(0x0101u16, <StunMethod as Into<u16>>::into(BINDING_RESPONSE));
228        /// assert_eq!(0x0111u16, <StunMethod as Into<u16>>::into(BINDING_ERROR));
229        /// assert_eq!(0x0003u16, <StunMethod as Into<u16>>::into(ALLOCATE_REQUEST));
230        /// assert_eq!(0x0103u16, <StunMethod as Into<u16>>::into(ALLOCATE_RESPONSE));
231        /// assert_eq!(0x0113u16, <StunMethod as Into<u16>>::into(ALLOCATE_ERROR));
232        /// assert_eq!(0x0008u16, <StunMethod as Into<u16>>::into(CREATE_PERMISSION_REQUEST));
233        /// assert_eq!(0x0108u16, <StunMethod as Into<u16>>::into(CREATE_PERMISSION_RESPONSE));
234        /// assert_eq!(0x0118u16, <StunMethod as Into<u16>>::into(CREATE_PERMISSION_ERROR));
235        /// assert_eq!(0x0009u16, <StunMethod as Into<u16>>::into(CHANNEL_BIND_REQUEST));
236        /// assert_eq!(0x0109u16, <StunMethod as Into<u16>>::into(CHANNEL_BIND_RESPONSE));
237        /// assert_eq!(0x0119u16, <StunMethod as Into<u16>>::into(CHANNEL_BIND_ERROR));
238        /// assert_eq!(0x0004u16, <StunMethod as Into<u16>>::into(REFRESH_REQUEST));
239        /// assert_eq!(0x0104u16, <StunMethod as Into<u16>>::into(REFRESH_RESPONSE));
240        /// assert_eq!(0x0114u16, <StunMethod as Into<u16>>::into(REFRESH_ERROR));
241        /// assert_eq!(0x0016u16, <StunMethod as Into<u16>>::into(SEND_INDICATION));
242        /// assert_eq!(0x0017u16, <StunMethod as Into<u16>>::into(DATA_INDICATION));
243        /// ```
244        fn into(self) -> u16 {
245            match self {
246                Self::Binding(StunMethodKind::Request) => 0x0001,
247                Self::Binding(StunMethodKind::Response) => 0x0101,
248                Self::Binding(StunMethodKind::Error) => 0x0111,
249                Self::Allocate(StunMethodKind::Request) => 0x0003,
250                Self::Allocate(StunMethodKind::Response) => 0x0103,
251                Self::Allocate(StunMethodKind::Error) => 0x0113,
252                Self::CreatePermission(StunMethodKind::Request) => 0x0008,
253                Self::CreatePermission(StunMethodKind::Response) => 0x0108,
254                Self::CreatePermission(StunMethodKind::Error) => 0x0118,
255                Self::ChannelBind(StunMethodKind::Request) => 0x0009,
256                Self::ChannelBind(StunMethodKind::Response) => 0x0109,
257                Self::ChannelBind(StunMethodKind::Error) => 0x0119,
258                Self::Refresh(StunMethodKind::Request) => 0x0004,
259                Self::Refresh(StunMethodKind::Response) => 0x0104,
260                Self::Refresh(StunMethodKind::Error) => 0x0114,
261                Self::SendIndication => 0x0016,
262                Self::DataIndication => 0x0017,
263            }
264        }
265    }
266}
267
268#[derive(Debug)]
269pub enum Payload<'a> {
270    Message(MessageRef<'a>),
271    ChannelData(ChannelData<'a>),
272}
273
274/// A cache of the list of attributes, this is for internal use only.
275#[derive(Debug, Clone)]
276pub struct Attributes(Vec<(AttrKind, Range<usize>)>);
277
278impl Default for Attributes {
279    fn default() -> Self {
280        Self(Vec::with_capacity(20))
281    }
282}
283
284impl Attributes {
285    /// Adds an attribute to the list.
286    pub fn append(&mut self, kind: AttrKind, range: Range<usize>) {
287        self.0.push((kind, range));
288    }
289
290    /// Gets an attribute from the list.
291    ///
292    /// Note: This function will only look for the first matching property in
293    /// the list and return it.
294    pub fn get(&self, kind: &AttrKind) -> Option<Range<usize>> {
295        self.0.iter().find(|(k, _)| k == kind).map(|(_, v)| v.clone())
296    }
297
298    /// Gets all the values of an attribute from a list.
299    ///
300    /// Normally a stun message can have multiple attributes with the same name,
301    /// and this function will all the values of the current attribute.
302    pub fn get_all<'a>(&'a self, kind: &'a AttrKind) -> impl Iterator<Item = &'a Range<usize>> {
303        self.0
304            .iter()
305            .filter(move |(k, _)| k == kind)
306            .map(|(_, v)| v)
307            .into_iter()
308    }
309
310    pub fn clear(&mut self) {
311        if !self.0.is_empty() {
312            self.0.clear();
313        }
314    }
315}
316
317#[derive(Default)]
318pub struct Decoder(Attributes);
319
320impl Decoder {
321    /// # Test
322    ///
323    /// ```
324    /// use turn_server::stun::attribute::*;
325    /// use turn_server::stun::*;
326    ///
327    /// let buffer = [
328    ///     0x00, 0x01, 0x00, 0x4c, 0x21, 0x12, 0xa4, 0x42, 0x71, 0x66, 0x46, 0x31,
329    ///     0x2b, 0x59, 0x79, 0x65, 0x56, 0x69, 0x32, 0x72, 0x00, 0x06, 0x00, 0x09,
330    ///     0x55, 0x43, 0x74, 0x39, 0x3a, 0x56, 0x2f, 0x2b, 0x2f, 0x00, 0x00, 0x00,
331    ///     0xc0, 0x57, 0x00, 0x04, 0x00, 0x00, 0x03, 0xe7, 0x80, 0x29, 0x00, 0x08,
332    ///     0x22, 0x49, 0xda, 0x28, 0x2c, 0x6f, 0x2e, 0xdb, 0x00, 0x24, 0x00, 0x04,
333    ///     0x6e, 0x00, 0x28, 0xff, 0x00, 0x08, 0x00, 0x14, 0x19, 0x58, 0xda, 0x38,
334    ///     0xed, 0x1e, 0xdd, 0xc8, 0x6b, 0x8e, 0x22, 0x63, 0x3a, 0x22, 0x63, 0x97,
335    ///     0xcf, 0xf5, 0xde, 0x82, 0x80, 0x28, 0x00, 0x04, 0x56, 0xf7, 0xa3, 0xed,
336    /// ];
337    ///
338    /// let mut decoder = Decoder::default();
339    /// let payload = decoder.decode(&buffer).unwrap();
340    /// if let Payload::Message(reader) = payload {
341    ///     assert!(reader.get::<UserName>().is_some())
342    /// }
343    /// ```
344    pub fn decode<'a>(&'a mut self, bytes: &'a [u8]) -> Result<Payload<'a>, StunError> {
345        assert!(bytes.len() >= 4);
346
347        let flag = bytes[0] >> 6;
348        if flag > 3 {
349            return Err(StunError::InvalidInput);
350        }
351
352        Ok(if flag == 0 {
353            self.0.clear();
354
355            Payload::Message(MessageDecoder::decode(bytes, &mut self.0)?)
356        } else {
357            Payload::ChannelData(ChannelData::try_from(bytes)?)
358        })
359    }
360
361    /// # Test
362    ///
363    /// ```
364    /// use turn_server::stun::attribute::*;
365    /// use turn_server::stun::*;
366    ///
367    /// let buffer = [
368    ///     0x00, 0x01, 0x00, 0x4c, 0x21, 0x12, 0xa4, 0x42, 0x71, 0x66, 0x46, 0x31,
369    ///     0x2b, 0x59, 0x79, 0x65, 0x56, 0x69, 0x32, 0x72, 0x00, 0x06, 0x00, 0x09,
370    ///     0x55, 0x43, 0x74, 0x39, 0x3a, 0x56, 0x2f, 0x2b, 0x2f, 0x00, 0x00, 0x00,
371    ///     0xc0, 0x57, 0x00, 0x04, 0x00, 0x00, 0x03, 0xe7, 0x80, 0x29, 0x00, 0x08,
372    ///     0x22, 0x49, 0xda, 0x28, 0x2c, 0x6f, 0x2e, 0xdb, 0x00, 0x24, 0x00, 0x04,
373    ///     0x6e, 0x00, 0x28, 0xff, 0x00, 0x08, 0x00, 0x14, 0x19, 0x58, 0xda, 0x38,
374    ///     0xed, 0x1e, 0xdd, 0xc8, 0x6b, 0x8e, 0x22, 0x63, 0x3a, 0x22, 0x63, 0x97,
375    ///     0xcf, 0xf5, 0xde, 0x82, 0x80, 0x28, 0x00, 0x04, 0x56, 0xf7, 0xa3, 0xed,
376    /// ];
377    ///
378    /// let size = Decoder::message_size(&buffer, false).unwrap();
379    /// assert_eq!(size, 96);
380    /// ```
381    pub fn message_size(bytes: &[u8], is_tcp: bool) -> Result<usize, StunError> {
382        let flag = bytes[0] >> 6;
383        if flag > 3 {
384            return Err(StunError::InvalidInput);
385        }
386
387        Ok(if flag == 0 {
388            MessageDecoder::message_size(bytes)?
389        } else {
390            ChannelData::message_size(bytes, is_tcp)?
391        })
392    }
393}