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}