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}