stun_codec/
message.rs

1use crate::attribute::{
2    Attribute, LosslessAttribute, LosslessAttributeDecoder, LosslessAttributeEncoder, RawAttribute,
3};
4use crate::constants::MAGIC_COOKIE;
5use crate::convert::TryAsRef;
6use crate::{Method, TransactionId};
7use bytecodec::bytes::{BytesEncoder, CopyableBytesDecoder};
8use bytecodec::combinator::{Collect, Length, Peekable, PreEncode, Repeat};
9use bytecodec::fixnum::{U16beDecoder, U16beEncoder, U32beDecoder, U32beEncoder};
10use bytecodec::{ByteCount, Decode, Encode, Eos, Error, ErrorKind, Result, SizedEncode};
11use std::{fmt, vec};
12use trackable::error::ErrorKindExt;
13
14/// Message decoded by [`MessageDecoder`].
15pub type DecodedMessage<A> = std::result::Result<Message<A>, BrokenMessage>;
16
17/// The class of a message.
18#[allow(missing_docs)]
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum MessageClass {
21    Request,
22    Indication,
23    SuccessResponse,
24    ErrorResponse,
25}
26impl MessageClass {
27    fn from_u8(value: u8) -> Option<Self> {
28        match value {
29            0b00 => Some(MessageClass::Request),
30            0b01 => Some(MessageClass::Indication),
31            0b10 => Some(MessageClass::SuccessResponse),
32            0b11 => Some(MessageClass::ErrorResponse),
33            _ => None,
34        }
35    }
36}
37
38impl fmt::Display for MessageClass {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        match self {
41            MessageClass::Request => write!(f, "request"),
42            MessageClass::Indication => write!(f, "indication"),
43            MessageClass::SuccessResponse => write!(f, "success response"),
44            MessageClass::ErrorResponse => write!(f, "error response"),
45        }
46    }
47}
48
49/// STUN message.
50///
51/// # NOTE: Binary Format of STUN Messages
52///
53/// > STUN messages are encoded in binary using network-oriented format
54/// > (most significant byte or octet first, also commonly known as big-
55/// > endian).  The transmission order is described in detail in Appendix B
56/// > of [RFC 791].  Unless otherwise noted, numeric constants are
57/// > in decimal (base 10).
58/// >
59/// > All STUN messages MUST start with a 20-byte header followed by zero
60/// > or more Attributes.  The STUN header contains a STUN message type,
61/// > magic cookie, transaction ID, and message length.
62/// >
63/// > ```text
64/// >  0                   1                   2                   3
65/// >  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
66/// > +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67/// > |0 0|     STUN Message Type     |         Message Length        |
68/// > +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69/// > |                         Magic Cookie                          |
70/// > +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71/// > |                                                               |
72/// > |                     Transaction ID (96 bits)                  |
73/// > |                                                               |
74/// > +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75/// >
76/// >             Figure 2: Format of STUN Message Header
77/// > ```
78/// >
79/// > The most significant 2 bits of every STUN message MUST be zeroes.
80/// > This can be used to differentiate STUN packets from other protocols
81/// > when STUN is multiplexed with other protocols on the same port.
82/// >
83/// > The message type defines the message class (request, success
84/// > response, failure response, or indication) and the message method
85/// > (the primary function) of the STUN message.  Although there are four
86/// > message classes, there are only two types of transactions in STUN:
87/// > request/response transactions (which consist of a request message and
88/// > a response message) and indication transactions (which consist of a
89/// > single indication message).  Response classes are split into error
90/// > and success responses to aid in quickly processing the STUN message.
91/// >
92/// > The message type field is decomposed further into the following structure:
93/// >
94/// > ```text
95/// >  0                 1
96/// >  2  3  4 5 6 7 8 9 0 1 2 3 4 5
97/// > +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
98/// > |M |M |M|M|M|C|M|M|M|C|M|M|M|M|
99/// > |11|10|9|8|7|1|6|5|4|0|3|2|1|0|
100/// > +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
101/// >
102/// > Figure 3: Format of STUN Message Type Field
103/// > ```
104/// >
105/// > Here the bits in the message type field are shown as most significant
106/// > (M11) through least significant (M0).  M11 through M0 represent a 12-
107/// > bit encoding of the method.  C1 and C0 represent a 2-bit encoding of
108/// > the class.  A class of 0b00 is a request, a class of 0b01 is an
109/// > indication, a class of 0b10 is a success response, and a class of
110/// > 0b11 is an error response.  This specification defines a single
111/// > method, Binding.  The method and class are orthogonal, so that for
112/// > each method, a request, success response, error response, and
113/// > indication are possible for that method.  Extensions defining new
114/// > methods MUST indicate which classes are permitted for that method.
115/// >
116/// > For example, a Binding request has class=0b00 (request) and
117/// > method=0b000000000001 (Binding) and is encoded into the first 16 bits
118/// > as 0x0001.  A Binding response has class=0b10 (success response) and
119/// > method=0b000000000001, and is encoded into the first 16 bits as 0x0101.
120/// >
121/// > > Note: This unfortunate encoding is due to assignment of values in
122/// > > [RFC 3489] that did not consider encoding Indications, Success, and
123/// > > Errors using bit fields.
124/// >
125/// > The magic cookie field MUST contain the fixed value 0x2112A442 in
126/// > network byte order.  In [RFC 3489], this field was part of
127/// > the transaction ID; placing the magic cookie in this location allows
128/// > a server to detect if the client will understand certain attributes
129/// > that were added in this revised specification.  In addition, it aids
130/// > in distinguishing STUN packets from packets of other protocols when
131/// > STUN is multiplexed with those other protocols on the same port.
132/// >
133/// > The transaction ID is a 96-bit identifier, used to uniquely identify
134/// > STUN transactions.  For request/response transactions, the
135/// > transaction ID is chosen by the STUN client for the request and
136/// > echoed by the server in the response.  For indications, it is chosen
137/// > by the agent sending the indication.  It primarily serves to
138/// > correlate requests with responses, though it also plays a small role
139/// > in helping to prevent certain types of attacks.  The server also uses
140/// > the transaction ID as a key to identify each transaction uniquely
141/// > across all clients.  As such, the transaction ID MUST be uniformly
142/// > and randomly chosen from the interval 0 .. 2**96-1, and SHOULD be
143/// > cryptographically random.  Resends of the same request reuse the same
144/// > transaction ID, but the client MUST choose a new transaction ID for
145/// > new transactions unless the new request is bit-wise identical to the
146/// > previous request and sent from the same transport address to the same
147/// > IP address.  Success and error responses MUST carry the same
148/// > transaction ID as their corresponding request.  When an agent is
149/// > acting as a STUN server and STUN client on the same port, the
150/// > transaction IDs in requests sent by the agent have no relationship to
151/// > the transaction IDs in requests received by the agent.
152/// >
153/// > The message length MUST contain the size, in bytes, of the message
154/// > not including the 20-byte STUN header.  Since all STUN attributes are
155/// > padded to a multiple of 4 bytes, the last 2 bits of this field are
156/// > always zero.  This provides another way to distinguish STUN packets
157/// > from packets of other protocols.
158/// >
159/// > Following the STUN fixed portion of the header are zero or more
160/// > attributes.  Each attribute is TLV (Type-Length-Value) encoded.  The
161/// > details of the encoding, and of the attributes themselves are given
162/// > in Section 15.
163/// >
164/// > [RFC 5389 -- 6. STUN Message Structure]
165///
166/// [RFC 5389 -- 6. STUN Message Structure]: https://tools.ietf.org/html/rfc5389#section-6
167/// [RFC 791]: https://tools.ietf.org/html/rfc791
168/// [RFC 3489]: https://tools.ietf.org/html/rfc3489
169#[derive(Debug, Clone)]
170pub struct Message<A> {
171    class: MessageClass,
172    method: Method,
173    transaction_id: TransactionId,
174    attributes: Vec<LosslessAttribute<A>>,
175}
176impl<A: Attribute> Message<A> {
177    /// Makes a new `Message` instance.
178    pub fn new(class: MessageClass, method: Method, transaction_id: TransactionId) -> Self {
179        Message {
180            class,
181            method,
182            transaction_id,
183            attributes: Vec::new(),
184        }
185    }
186
187    /// Returns the class of the message.
188    pub fn class(&self) -> MessageClass {
189        self.class
190    }
191
192    /// Returns the method of the message.
193    pub fn method(&self) -> Method {
194        self.method
195    }
196
197    /// Returns the transaction ID of the message.
198    pub fn transaction_id(&self) -> TransactionId {
199        self.transaction_id
200    }
201
202    /// Returns a reference to the first occurance of `T` attribute in the attributes of the message.
203    ///
204    /// If there is no such attribute, this method will return `None`.
205    pub fn get_attribute<T>(&self) -> Option<&T>
206    where
207        T: Attribute,
208        A: TryAsRef<T>,
209    {
210        self.attributes().filter_map(|a| a.try_as_ref()).next()
211    }
212
213    /// Returns an iterator that iterates over the known attributes in the message.
214    pub fn attributes(&self) -> impl Iterator<Item = &A> {
215        self.attributes.iter().filter_map(|a| a.as_known())
216    }
217
218    /// Returns an iterator that iterates over the unknown attributes in the message.
219    ///
220    /// Note that it is the responsibility of users to check
221    /// whether the unknown attributes contains comprehension-required ones.
222    pub fn unknown_attributes(&self) -> impl Iterator<Item = &RawAttribute> {
223        self.attributes.iter().filter_map(|a| a.as_unknown())
224    }
225
226    /// Adds the given attribute to the tail of the attributes in the message.
227    pub fn add_attribute(&mut self, attribute: impl Into<A>) {
228        self.attributes
229            .push(LosslessAttribute::new(attribute.into()));
230    }
231}
232
233/// STUN message of which [`MessageDecoder`] could not decode the attribute part.
234#[allow(missing_docs)]
235#[derive(Debug, Clone)]
236pub struct BrokenMessage {
237    method: Method,
238    class: MessageClass,
239    transaction_id: TransactionId,
240    error: Error,
241}
242impl BrokenMessage {
243    /// Returns the class of the message.
244    pub fn class(&self) -> MessageClass {
245        self.class
246    }
247
248    /// Returns the method of the message.
249    pub fn method(&self) -> Method {
250        self.method
251    }
252
253    /// Returns the transaction ID of the message.
254    pub fn transaction_id(&self) -> TransactionId {
255        self.transaction_id
256    }
257
258    /// Returns a reference to the error object storing the cause of failure to decode the message.
259    pub fn error(&self) -> &Error {
260        &self.error
261    }
262}
263impl From<BrokenMessage> for Error {
264    fn from(f: BrokenMessage) -> Self {
265        ErrorKind::InvalidInput.cause(format!("{f:?}")).into()
266    }
267}
268
269#[derive(Debug, Default)]
270struct MessageHeaderDecoder {
271    message_type: U16beDecoder,
272    message_len: U16beDecoder,
273    magic_cookie: U32beDecoder,
274    transaction_id: CopyableBytesDecoder<[u8; 12]>,
275}
276impl MessageHeaderDecoder {
277    fn check_magic_cookie(&self, magic_cookie: u32) -> Result<()> {
278        track_assert_eq!(
279            magic_cookie,
280            MAGIC_COOKIE,
281            ErrorKind::InvalidInput,
282            "Unexpected MAGIC_COOKIE: actual=0x{:08x}, expected=0x{:08x}",
283            magic_cookie,
284            MAGIC_COOKIE,
285        );
286        Ok(())
287    }
288}
289impl Decode for MessageHeaderDecoder {
290    type Item = (Type, u16, TransactionId);
291
292    fn decode(&mut self, buf: &[u8], eos: Eos) -> Result<usize> {
293        let mut offset = 0;
294        bytecodec_try_decode!(self.message_type, offset, buf, eos);
295        bytecodec_try_decode!(self.message_len, offset, buf, eos);
296        bytecodec_try_decode!(self.magic_cookie, offset, buf, eos);
297        bytecodec_try_decode!(self.transaction_id, offset, buf, eos);
298        Ok(offset)
299    }
300
301    fn finish_decoding(&mut self) -> Result<Self::Item> {
302        let message_type = track!(self.message_type.finish_decoding())?;
303        let message_type = track!(Type::from_u16(message_type))?;
304        let message_len = track!(self.message_len.finish_decoding())?;
305        let magic_cookie = track!(self.magic_cookie.finish_decoding())?;
306        let transaction_id = TransactionId::new(track!(self.transaction_id.finish_decoding())?);
307        track!(self.check_magic_cookie(magic_cookie); message_type, message_len, transaction_id)?;
308        Ok((message_type, message_len, transaction_id))
309    }
310
311    fn requiring_bytes(&self) -> ByteCount {
312        self.message_type
313            .requiring_bytes()
314            .add_for_decoding(self.message_len.requiring_bytes())
315            .add_for_decoding(self.magic_cookie.requiring_bytes())
316            .add_for_decoding(self.transaction_id.requiring_bytes())
317    }
318
319    fn is_idle(&self) -> bool {
320        self.transaction_id.is_idle()
321    }
322}
323
324#[derive(Debug)]
325struct AttributesDecoder<A: Attribute> {
326    inner: Collect<LosslessAttributeDecoder<A>, Vec<LosslessAttribute<A>>>,
327    last_error: Option<Error>,
328    is_eos: bool,
329}
330impl<A: Attribute> Default for AttributesDecoder<A> {
331    fn default() -> Self {
332        AttributesDecoder {
333            inner: Default::default(),
334            last_error: None,
335            is_eos: false,
336        }
337    }
338}
339impl<A: Attribute> Decode for AttributesDecoder<A> {
340    type Item = Vec<LosslessAttribute<A>>;
341
342    fn decode(&mut self, buf: &[u8], eos: Eos) -> Result<usize> {
343        if self.last_error.is_none() {
344            match track!(self.inner.decode(buf, eos)) {
345                Err(e) => {
346                    self.last_error = Some(e);
347                }
348                Ok(size) => return Ok(size),
349            }
350        }
351
352        // Skips remaining bytes if an error occurred
353        self.is_eos = eos.is_reached();
354        Ok(buf.len())
355    }
356
357    fn finish_decoding(&mut self) -> Result<Self::Item> {
358        self.is_eos = false;
359        if let Some(e) = self.last_error.take() {
360            return Err(track!(e));
361        }
362        track!(self.inner.finish_decoding())
363    }
364
365    fn requiring_bytes(&self) -> ByteCount {
366        if self.last_error.is_none() {
367            self.inner.requiring_bytes()
368        } else if self.is_eos {
369            ByteCount::Finite(0)
370        } else {
371            ByteCount::Unknown
372        }
373    }
374
375    fn is_idle(&self) -> bool {
376        if self.last_error.is_none() {
377            self.inner.is_idle()
378        } else {
379            self.is_eos
380        }
381    }
382}
383
384/// [`Message`] decoder.
385#[derive(Debug)]
386pub struct MessageDecoder<A: Attribute> {
387    header: Peekable<MessageHeaderDecoder>,
388    attributes: Length<AttributesDecoder<A>>,
389}
390impl<A: Attribute> MessageDecoder<A> {
391    /// Makes a new `MessageDecoder` instance.
392    pub fn new() -> Self {
393        Self::default()
394    }
395
396    fn finish_decoding_with_header(
397        &mut self,
398        method: Method,
399        class: MessageClass,
400        transaction_id: TransactionId,
401    ) -> Result<Message<A>> {
402        let attributes = track!(self.attributes.finish_decoding())?;
403        let mut message = Message {
404            class,
405            method,
406            transaction_id,
407            attributes,
408        };
409
410        let attributes_len = message.attributes.len();
411        for i in 0..attributes_len {
412            unsafe {
413                let message_mut = &mut *(&mut message as *mut Message<A>);
414                let attr = message_mut.attributes.get_unchecked_mut(i);
415                message.attributes.set_len(i);
416                let decode_result = track!(attr.after_decode(&message));
417                message.attributes.set_len(attributes_len);
418                decode_result?;
419            }
420        }
421        Ok(message)
422    }
423}
424impl<A: Attribute> Default for MessageDecoder<A> {
425    fn default() -> Self {
426        MessageDecoder {
427            header: Default::default(),
428            attributes: Default::default(),
429        }
430    }
431}
432impl<A: Attribute> Decode for MessageDecoder<A> {
433    type Item = DecodedMessage<A>;
434
435    fn decode(&mut self, buf: &[u8], eos: Eos) -> Result<usize> {
436        let mut offset = 0;
437        if !self.header.is_idle() {
438            bytecodec_try_decode!(self.header, offset, buf, eos);
439
440            let message_len = self.header.peek().expect("never fails").1;
441            track!(self.attributes.set_expected_bytes(u64::from(message_len)))?;
442        }
443        bytecodec_try_decode!(self.attributes, offset, buf, eos);
444        Ok(offset)
445    }
446
447    fn finish_decoding(&mut self) -> Result<Self::Item> {
448        let (Type { method, class }, _, transaction_id) = track!(self.header.finish_decoding())?;
449        match self.finish_decoding_with_header(method, class, transaction_id) {
450            Err(error) => Ok(Err(BrokenMessage {
451                method,
452                class,
453                transaction_id,
454                error,
455            })),
456            Ok(message) => Ok(Ok(message)),
457        }
458    }
459
460    fn requiring_bytes(&self) -> ByteCount {
461        self.header
462            .requiring_bytes()
463            .add_for_decoding(self.attributes.requiring_bytes())
464    }
465
466    fn is_idle(&self) -> bool {
467        self.header.is_idle() && self.attributes.is_idle()
468    }
469}
470
471/// [`Message`] encoder.
472#[derive(Debug)]
473pub struct MessageEncoder<A: Attribute> {
474    message_type: U16beEncoder,
475    message_len: U16beEncoder,
476    magic_cookie: U32beEncoder,
477    transaction_id: BytesEncoder<TransactionId>,
478    attributes: PreEncode<Repeat<LosslessAttributeEncoder<A>, vec::IntoIter<LosslessAttribute<A>>>>,
479}
480impl<A: Attribute> MessageEncoder<A> {
481    /// Makes a new `MessageEncoder` instance.
482    pub fn new() -> Self {
483        Self::default()
484    }
485}
486impl<A: Attribute> Default for MessageEncoder<A> {
487    fn default() -> Self {
488        MessageEncoder {
489            message_type: Default::default(),
490            message_len: Default::default(),
491            magic_cookie: Default::default(),
492            transaction_id: Default::default(),
493            attributes: Default::default(),
494        }
495    }
496}
497impl<A: Attribute> Encode for MessageEncoder<A> {
498    type Item = Message<A>;
499
500    fn encode(&mut self, buf: &mut [u8], eos: Eos) -> Result<usize> {
501        let mut offset = 0;
502        bytecodec_try_encode!(self.message_type, offset, buf, eos);
503        bytecodec_try_encode!(self.message_len, offset, buf, eos);
504        bytecodec_try_encode!(self.magic_cookie, offset, buf, eos);
505        bytecodec_try_encode!(self.transaction_id, offset, buf, eos);
506        bytecodec_try_encode!(self.attributes, offset, buf, eos);
507        Ok(offset)
508    }
509
510    fn start_encoding(&mut self, mut item: Self::Item) -> Result<()> {
511        let attributes_len = item.attributes.len();
512        for i in 0..attributes_len {
513            unsafe {
514                let item_mut = &mut *(&mut item as *mut Message<A>);
515                let attr = item_mut.attributes.get_unchecked_mut(i);
516                item.attributes.set_len(i);
517                let encode_result = track!(attr.before_encode(&item));
518                item.attributes.set_len(attributes_len);
519                encode_result?;
520            }
521        }
522
523        let message_type = Type {
524            class: item.class,
525            method: item.method,
526        };
527        track!(self.message_type.start_encoding(message_type.as_u16()))?;
528        track!(self.magic_cookie.start_encoding(MAGIC_COOKIE))?;
529        track!(self.transaction_id.start_encoding(item.transaction_id))?;
530        track!(self.attributes.start_encoding(item.attributes.into_iter()))?;
531
532        let message_len = self.attributes.exact_requiring_bytes();
533        track_assert!(
534            message_len < 0x10000,
535            ErrorKind::InvalidInput,
536            "Too large message length: actual={}, limit=0xFFFF",
537            message_len
538        );
539        track!(self.message_len.start_encoding(message_len as u16))?;
540        Ok(())
541    }
542
543    fn requiring_bytes(&self) -> ByteCount {
544        ByteCount::Finite(self.exact_requiring_bytes())
545    }
546
547    fn is_idle(&self) -> bool {
548        self.transaction_id.is_idle() && self.attributes.is_idle()
549    }
550}
551impl<A: Attribute> SizedEncode for MessageEncoder<A> {
552    fn exact_requiring_bytes(&self) -> u64 {
553        self.message_type.exact_requiring_bytes()
554            + self.message_len.exact_requiring_bytes()
555            + self.magic_cookie.exact_requiring_bytes()
556            + self.transaction_id.exact_requiring_bytes()
557            + self.attributes.exact_requiring_bytes()
558    }
559}
560
561#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
562struct Type {
563    class: MessageClass,
564    method: Method,
565}
566impl Type {
567    fn as_u16(self) -> u16 {
568        let class = self.class as u16;
569        let method = self.method.as_u16();
570        (method & 0b0000_0000_1111)
571            | ((class & 0b01) << 4)
572            | ((method & 0b0000_0111_0000) << 5)
573            | ((class & 0b10) << 7)
574            | ((method & 0b1111_1000_0000) << 9)
575    }
576
577    fn from_u16(value: u16) -> Result<Self> {
578        track_assert!(
579            value >> 14 == 0,
580            ErrorKind::InvalidInput,
581            "First two-bits of STUN message must be 0"
582        );
583        let class = ((value >> 4) & 0b01) | ((value >> 7) & 0b10);
584        let class = MessageClass::from_u8(class as u8).unwrap();
585        let method = (value & 0b0000_0000_1111)
586            | ((value >> 1) & 0b0000_0111_0000)
587            | ((value >> 2) & 0b1111_1000_0000);
588        let method = Method(method);
589        Ok(Type { class, method })
590    }
591}
592
593#[cfg(test)]
594mod tests {
595    use super::*;
596    use crate::rfc5389::attributes::MappedAddress;
597    use crate::rfc5389::methods::BINDING;
598    use crate::{MessageClass, TransactionId};
599    use bytecodec::DecodeExt;
600    use trackable::result::TestResult;
601
602    #[test]
603    fn message_class_from_u8_works() {
604        assert_eq!(MessageClass::from_u8(0), Some(MessageClass::Request));
605        assert_eq!(MessageClass::from_u8(9), None);
606    }
607
608    #[test]
609    fn decoder_fails_when_decoding_attributes() -> TestResult {
610        let bytes = [
611            0, 1, 0, 12, 33, 18, 164, 66, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 1, 0, 8, 0, 1, 0,
612            80, 127, 0, /* 0, */ 1,
613        ];
614
615        let mut decoder = MessageDecoder::<MappedAddress>::new();
616        let broken_message = decoder.decode_from_bytes(&bytes)?.err().unwrap();
617        assert_eq!(broken_message.method, BINDING);
618        assert_eq!(broken_message.class, MessageClass::Request);
619        assert_eq!(broken_message.transaction_id, TransactionId::new([3; 12]));
620
621        Ok(())
622    }
623}