msf_stun/
lib.rs

1mod attribute;
2mod writer;
3
4use std::{
5    borrow::Cow,
6    error::Error,
7    fmt::{self, Display, Formatter},
8    net::SocketAddr,
9};
10
11use bytes::{Buf, Bytes};
12use crc::{Crc, CRC_32_ISO_HDLC};
13use hmac::{Hmac, Mac};
14use sha1::Sha1;
15
16use self::{attribute::AttributeError, writer::MessageWriter};
17
18pub use self::attribute::{Attribute, Attributes};
19
20const RFC_5389_MAGIC_COOKIE: u32 = 0x2112a442;
21
22/// Message class.
23#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
24pub enum MessageClass {
25    Request,
26    Indication,
27    Success,
28    Error,
29}
30
31impl MessageClass {
32    /// Get message class from a given message type.
33    fn from_message_type(msg_type: u16) -> Self {
34        match msg_type & 0x0110 {
35            0x0000 => Self::Request,
36            0x0010 => Self::Indication,
37            0x0100 => Self::Success,
38            0x0110 => Self::Error,
39            _ => unreachable!(),
40        }
41    }
42
43    /// Get the message type bits that correspond to this message class.
44    fn into_message_type(self) -> u16 {
45        match self {
46            Self::Request => 0x0000,
47            Self::Indication => 0x0010,
48            Self::Success => 0x0100,
49            Self::Error => 0x0110,
50        }
51    }
52}
53
54/// Method.
55#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
56pub enum Method {
57    Binding,
58    Other(u16),
59}
60
61impl Method {
62    /// Get method from a given message type.
63    fn from_message_type(msg_type: u16) -> Self {
64        match msg_type & !0xc110 {
65            0x0001 => Self::Binding,
66            m => Self::Other(m),
67        }
68    }
69
70    /// Get the message type bits that correspond to this method.
71    fn into_message_type(self) -> u16 {
72        match self {
73            Self::Binding => 0x0001,
74            Self::Other(m) => m & !0xc110,
75        }
76    }
77}
78
79/// Transaction ID.
80type TransactionID = [u8; 12];
81
82/// Invalid message header error.
83struct InvalidMessageHeader;
84
85/// Message header.
86struct MessageHeader {
87    message_type: u16,
88    message_length: u16,
89    magic_cookie: u32,
90    transaction_id: TransactionID,
91}
92
93impl MessageHeader {
94    /// Consume message header from a given buffer and parse it.
95    fn from_bytes(data: &mut Bytes) -> Result<Self, InvalidMessageHeader> {
96        if data.len() < 20 {
97            return Err(InvalidMessageHeader);
98        }
99
100        let mut res = Self {
101            message_type: data.get_u16(),
102            message_length: data.get_u16(),
103            magic_cookie: data.get_u32(),
104            transaction_id: TransactionID::default(),
105        };
106
107        data.copy_to_slice(&mut res.transaction_id);
108
109        if (res.message_type & 0xc000) == 0 {
110            Ok(res)
111        } else {
112            Err(InvalidMessageHeader)
113        }
114    }
115
116    /// Get the message class.
117    fn message_class(&self) -> MessageClass {
118        MessageClass::from_message_type(self.message_type)
119    }
120
121    /// Get the method.
122    fn method(&self) -> Method {
123        Method::from_message_type(self.message_type)
124    }
125}
126
127/// Invalid message.
128#[derive(Debug, Copy, Clone)]
129pub enum InvalidMessage {
130    InvalidHeader,
131    InvalidAttribute,
132}
133
134impl Display for InvalidMessage {
135    #[inline]
136    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
137        let msg = match self {
138            Self::InvalidHeader => "invalid header",
139            Self::InvalidAttribute => "invalid attribute",
140        };
141
142        f.write_str(msg)
143    }
144}
145
146impl Error for InvalidMessage {}
147
148impl From<InvalidMessageHeader> for InvalidMessage {
149    #[inline]
150    fn from(_: InvalidMessageHeader) -> Self {
151        Self::InvalidHeader
152    }
153}
154
155/// Message integrity error.
156#[derive(Debug, Copy, Clone)]
157pub enum IntegrityError {
158    Missing,
159    Invalid,
160}
161
162impl Display for IntegrityError {
163    #[inline]
164    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
165        let msg = match self {
166            IntegrityError::Missing => "missing message integrity",
167            IntegrityError::Invalid => "invalid message integrity",
168        };
169
170        f.write_str(msg)
171    }
172}
173
174impl Error for IntegrityError {}
175
176/// STUN message.
177#[derive(Clone)]
178pub struct Message {
179    original: Bytes,
180    class: MessageClass,
181    method: Method,
182    magic_cookie: u32,
183    transaction_id: TransactionID,
184    attributes: Attributes,
185    unknown_attributes: Vec<u16>,
186    message_integrity_offset: Option<usize>,
187    fingerprint_offset: Option<usize>,
188}
189
190impl Message {
191    /// Parse a STUN message from a given frame.
192    pub fn from_frame(mut frame: Bytes) -> Result<Self, InvalidMessage> {
193        let mut original = frame.clone();
194
195        let header = MessageHeader::from_bytes(&mut frame)?;
196
197        let len = header.message_length as usize;
198
199        if (len & 3) != 0 || frame.len() < len {
200            return Err(InvalidMessage::InvalidHeader);
201        }
202
203        let mut res = Self {
204            original: original.split_to(20 + len),
205            class: header.message_class(),
206            method: header.method(),
207            magic_cookie: header.magic_cookie,
208            transaction_id: header.transaction_id,
209            attributes: Attributes::empty(),
210            unknown_attributes: Vec::new(),
211            message_integrity_offset: None,
212            fingerprint_offset: None,
213        };
214
215        res.read_attributes()?;
216
217        Ok(res)
218    }
219
220    /// Parse message attributes.
221    fn read_attributes(&mut self) -> Result<(), InvalidMessage> {
222        let mut attributes = Vec::new();
223
224        let len = self.original.len();
225
226        let mut body = self.original.slice(20..);
227
228        while !body.is_empty() {
229            match Attribute::from_bytes(&mut body, self.long_transaction_id()) {
230                Ok(Attribute::Fingerprint(crc)) => {
231                    attributes.push(Attribute::Fingerprint(crc));
232
233                    self.fingerprint_offset = Some(len - body.len() - 8);
234                }
235                Ok(Attribute::MessageIntegrity(hash)) => {
236                    attributes.push(Attribute::MessageIntegrity(hash));
237
238                    self.message_integrity_offset = Some(len - body.len() - 24);
239                }
240                Ok(attr) => {
241                    // attributes received after message integrity must be
242                    // ignored (only fingerprint is allowed)
243                    if self.message_integrity_offset.is_none() {
244                        attributes.push(attr);
245                    }
246                }
247                Err(AttributeError::InvalidAttribute) => {
248                    return Err(InvalidMessage::InvalidAttribute);
249                }
250                Err(AttributeError::UnknownAttribute(attr_type)) => {
251                    if (attr_type & 0x8000) == 0 {
252                        self.unknown_attributes.push(attr_type);
253                    }
254                }
255            }
256        }
257
258        self.attributes = Attributes::new(attributes);
259
260        Ok(())
261    }
262
263    /// Check if this is a STUN message as defined in RFC 5389.
264    #[inline]
265    pub fn is_rfc5389_message(&self) -> bool {
266        self.magic_cookie == RFC_5389_MAGIC_COOKIE
267    }
268
269    /// Check if this is a STUN request.
270    #[inline]
271    pub fn is_request(&self) -> bool {
272        matches!(self.class, MessageClass::Request)
273    }
274
275    /// Check if this is a STUN response.
276    #[inline]
277    pub fn is_response(&self) -> bool {
278        matches!(self.class, MessageClass::Success | MessageClass::Error)
279    }
280
281    /// Get the message class.
282    #[inline]
283    pub fn class(&self) -> MessageClass {
284        self.class
285    }
286
287    /// Get the STUN method.
288    #[inline]
289    pub fn method(&self) -> Method {
290        self.method
291    }
292
293    /// Get value of the magic cookie as defined in RFC 5389.
294    #[inline]
295    pub fn magic_cookie(&self) -> u32 {
296        self.magic_cookie
297    }
298
299    /// Get the transaction ID as defined in RFC 5389.
300    #[inline]
301    pub fn transaction_id(&self) -> [u8; 12] {
302        self.transaction_id
303    }
304
305    /// Get the transaction ID as defined in RFC 3489.
306    #[inline]
307    pub fn long_transaction_id(&self) -> [u8; 16] {
308        let mut res = [0u8; 16];
309
310        res[..4].copy_from_slice(&self.magic_cookie.to_be_bytes());
311        res[4..].copy_from_slice(&self.transaction_id);
312
313        res
314    }
315
316    /// Get message attributes.
317    #[inline]
318    pub fn attributes(&self) -> &Attributes {
319        &self.attributes
320    }
321
322    /// Get types of unknown attributes.
323    ///
324    /// # Note
325    /// This is not a value of the unknown attributes attribute. These are the
326    /// attributes that we actually weren't able to parse.
327    #[inline]
328    pub fn unknown_attributes(&self) -> &[u16] {
329        &self.unknown_attributes
330    }
331
332    /// Check the message fingerprint.
333    ///
334    /// The method return `true` only if the fingerprint attribute exists and
335    /// the value of the fingerprint is correct.
336    pub fn check_fingerprint(&self) -> bool {
337        if let Some(offset) = self.fingerprint_offset {
338            let fingerprint = self
339                .attributes
340                .iter()
341                .find_map(|attr| match attr {
342                    Attribute::Fingerprint(crc) => Some(crc),
343                    _ => None,
344                })
345                .copied()
346                .unwrap();
347
348            fingerprint == calculate_fingerprint(&self.original[..offset])
349        } else {
350            false
351        }
352    }
353
354    /// Check short-term credentials.
355    pub fn check_st_credentials(&self, key: &[u8]) -> Result<(), IntegrityError> {
356        if let Some(offset) = self.message_integrity_offset {
357            let hash = self
358                .attributes
359                .iter()
360                .find_map(|attr| match attr {
361                    Attribute::MessageIntegrity(hash) => Some(hash),
362                    _ => None,
363                })
364                .copied()
365                .unwrap();
366
367            if hash == calculate_message_integrity(key, &self.original[..offset]) {
368                Ok(())
369            } else {
370                Err(IntegrityError::Invalid)
371            }
372        } else {
373            Err(IntegrityError::Missing)
374        }
375    }
376}
377
378/// STUN message builder.
379pub struct MessageBuilder {
380    class: MessageClass,
381    method: Method,
382    magic_cookie: u32,
383    transaction_id: TransactionID,
384
385    mapped_address: Option<SocketAddr>,
386    xor_mapped_address: Option<SocketAddr>,
387    username: Option<String>,
388    message_integrity: Option<Vec<u8>>,
389    fingerprint: bool,
390    error_code: Option<ErrorCode>,
391    realm: Option<String>,
392    nonce: Option<String>,
393    unknown_attributes: Option<Vec<u16>>,
394    software: Option<String>,
395    alternate_server: Option<SocketAddr>,
396
397    #[cfg(feature = "ice")]
398    priority: Option<u32>,
399
400    #[cfg(feature = "ice")]
401    use_candidate: bool,
402
403    #[cfg(feature = "ice")]
404    ice_controlled: Option<u64>,
405
406    #[cfg(feature = "ice")]
407    ice_controlling: Option<u64>,
408}
409
410impl MessageBuilder {
411    /// Create a new message builder.
412    #[inline]
413    pub const fn new(class: MessageClass, method: Method, transaction_id: [u8; 12]) -> Self {
414        Self {
415            class,
416            method,
417            magic_cookie: RFC_5389_MAGIC_COOKIE,
418            transaction_id,
419
420            mapped_address: None,
421            xor_mapped_address: None,
422            username: None,
423            message_integrity: None,
424            fingerprint: false,
425            error_code: None,
426            realm: None,
427            nonce: None,
428            unknown_attributes: None,
429            software: None,
430            alternate_server: None,
431
432            #[cfg(feature = "ice")]
433            priority: None,
434
435            #[cfg(feature = "ice")]
436            use_candidate: false,
437
438            #[cfg(feature = "ice")]
439            ice_controlled: None,
440
441            #[cfg(feature = "ice")]
442            ice_controlling: None,
443        }
444    }
445
446    /// Create a new message builder for a STUN binding request.
447    #[inline]
448    pub fn binding_request(transaction_id: [u8; 12]) -> Self {
449        Self::new(MessageClass::Request, Method::Binding, transaction_id)
450    }
451
452    /// Create a new message builder for a STUN response.
453    #[inline]
454    pub fn response(class: MessageClass, request: &Message) -> Self {
455        let mut res = Self::new(class, request.method, request.transaction_id);
456
457        res.magic_cookie(request.magic_cookie);
458        res
459    }
460
461    /// Create a new message builder for a success STUN response.
462    #[inline]
463    pub fn success_response(request: &Message) -> Self {
464        Self::response(MessageClass::Success, request)
465    }
466
467    /// Create a new message builder for an error STUN response.
468    #[inline]
469    pub fn error_response(request: &Message, error_code: ErrorCode) -> Self {
470        let mut res = Self::response(MessageClass::Error, request);
471
472        res.error_code(error_code);
473        res
474    }
475
476    /// Set message class.
477    #[inline]
478    pub fn class(&mut self, class: MessageClass) -> &mut Self {
479        self.class = class;
480        self
481    }
482
483    /// Set STUN method.
484    #[inline]
485    pub fn method(&mut self, method: Method) -> &mut Self {
486        self.method = method;
487        self
488    }
489
490    /// Set magic cookie as defined in RFC 5389.
491    #[inline]
492    pub fn magic_cookie(&mut self, cookie: u32) -> &mut Self {
493        self.magic_cookie = cookie;
494        self
495    }
496
497    /// Set transaction ID as defined in RFC 5389.
498    #[inline]
499    pub fn transaction_id(&mut self, transaction_id: [u8; 12]) -> &mut Self {
500        self.transaction_id = transaction_id;
501        self
502    }
503
504    /// Set transaction ID as defined in RFC 3489.
505    #[inline]
506    pub fn long_transaction_id(&mut self, transaction_id: [u8; 16]) -> &mut Self {
507        let mut magic_cookie = [0u8; 4];
508        let mut short_id = [0u8; 12];
509
510        magic_cookie.copy_from_slice(&transaction_id[..4]);
511        short_id.copy_from_slice(&transaction_id[4..]);
512
513        self.magic_cookie = u32::from_be_bytes(magic_cookie);
514        self.transaction_id = short_id;
515
516        self
517    }
518
519    /// Set mapped address.
520    #[inline]
521    pub fn mapped_address(&mut self, addr: SocketAddr) -> &mut Self {
522        self.mapped_address = Some(addr);
523        self
524    }
525
526    /// Set XOR mapped address.
527    #[inline]
528    pub fn xor_mapped_address(&mut self, addr: SocketAddr) -> &mut Self {
529        self.xor_mapped_address = Some(addr);
530        self
531    }
532
533    /// Set username.
534    #[inline]
535    pub fn username<T>(&mut self, username: T) -> &mut Self
536    where
537        T: ToString,
538    {
539        self.username = Some(username.to_string());
540        self
541    }
542
543    /// Enable message integrity and use a given key.
544    #[inline]
545    pub fn message_integrity<T>(&mut self, key: T) -> &mut Self
546    where
547        T: Into<Vec<u8>>,
548    {
549        self.message_integrity = Some(key.into());
550        self
551    }
552
553    /// Enable or disable message fingerprint.
554    #[inline]
555    pub fn fingerprint(&mut self, enable: bool) -> &mut Self {
556        self.fingerprint = enable;
557        self
558    }
559
560    /// Set error code.
561    #[inline]
562    pub fn error_code(&mut self, error_code: ErrorCode) -> &mut Self {
563        self.error_code = Some(error_code);
564        self
565    }
566
567    /// Set realm.
568    #[inline]
569    pub fn realm<T>(&mut self, realm: T) -> &mut Self
570    where
571        T: ToString,
572    {
573        self.realm = Some(realm.to_string());
574        self
575    }
576
577    /// Set nonce.
578    #[inline]
579    pub fn nonce<T>(&mut self, nonce: T) -> &mut Self
580    where
581        T: ToString,
582    {
583        self.nonce = Some(nonce.to_string());
584        self
585    }
586
587    /// Set unknown attributes.
588    #[inline]
589    pub fn unknown_attributes<T>(&mut self, unknown_attributes: T) -> &mut Self
590    where
591        T: Into<Vec<u16>>,
592    {
593        self.unknown_attributes = Some(unknown_attributes.into());
594        self
595    }
596
597    /// Set software.
598    #[inline]
599    pub fn software<T>(&mut self, software: T) -> &mut Self
600    where
601        T: ToString,
602    {
603        self.software = Some(software.to_string());
604        self
605    }
606
607    /// Set alternate server.
608    #[inline]
609    pub fn alternate_server(&mut self, server: SocketAddr) -> &mut Self {
610        self.alternate_server = Some(server);
611        self
612    }
613
614    /// Set ICE candidate priority.
615    #[cfg(feature = "ice")]
616    #[inline]
617    pub fn priority(&mut self, priority: u32) -> &mut Self {
618        self.priority = Some(priority);
619        self
620    }
621
622    /// Set the use candidate ICE flag.
623    #[cfg(feature = "ice")]
624    #[inline]
625    pub fn use_candidate(&mut self, enable: bool) -> &mut Self {
626        self.use_candidate = enable;
627        self
628    }
629
630    /// Set the ICE controlled attribute.
631    #[cfg(feature = "ice")]
632    #[inline]
633    pub fn ice_controlled(&mut self, n: u64) -> &mut Self {
634        self.ice_controlled = Some(n);
635        self
636    }
637
638    /// Set the ICE controlling attribute.
639    #[cfg(feature = "ice")]
640    #[inline]
641    pub fn ice_controlling(&mut self, n: u64) -> &mut Self {
642        self.ice_controlling = Some(n);
643        self
644    }
645
646    /// Finalize the message.
647    pub fn build(&self) -> Bytes {
648        // create a buffer with an empty header
649        let mut writer = MessageWriter::new(
650            self.class,
651            self.method,
652            self.magic_cookie,
653            self.transaction_id,
654        );
655
656        if let Some(status) = self.error_code.as_ref() {
657            writer.put_error_code(status);
658        }
659
660        if let Some(attributes) = self.unknown_attributes.as_ref() {
661            writer.put_unknown_attributes(attributes);
662        }
663
664        if let Some(alternate_server) = self.alternate_server {
665            writer.put_alternate_server(alternate_server);
666        }
667
668        if let Some(addr) = self.mapped_address {
669            writer.put_mapped_address(addr);
670        }
671
672        if let Some(addr) = self.xor_mapped_address {
673            writer.put_xor_mapped_address(addr);
674        }
675
676        if let Some(username) = self.username.as_deref() {
677            writer.put_username(username);
678        }
679
680        if let Some(realm) = self.realm.as_deref() {
681            writer.put_realm(realm);
682        }
683
684        if let Some(nonce) = self.nonce.as_deref() {
685            writer.put_nonce(nonce);
686        }
687
688        if let Some(software) = self.software.as_deref() {
689            writer.put_software(software);
690        }
691
692        #[cfg(feature = "ice")]
693        {
694            if let Some(priority) = self.priority {
695                writer.put_priority(priority);
696            }
697
698            if self.use_candidate {
699                writer.put_use_candidate();
700            }
701
702            if let Some(n) = self.ice_controlled {
703                writer.put_ice_controlled(n);
704            }
705
706            if let Some(n) = self.ice_controlling {
707                writer.put_ice_controlling(n);
708            }
709        }
710
711        if let Some(key) = self.message_integrity.as_ref() {
712            writer.put_message_integrity(key);
713        }
714
715        if self.fingerprint {
716            writer.put_fingerprint();
717        }
718
719        writer.finalize()
720    }
721}
722
723/// Error code and error message.
724#[derive(Clone)]
725pub struct ErrorCode {
726    code: u16,
727    msg: Cow<'static, str>,
728}
729
730impl ErrorCode {
731    pub const BAD_REQUEST: Self = Self::new_static(400, "Bad Request");
732    pub const UNAUTHORIZED: Self = Self::new_static(401, "Unauthorized");
733    pub const UNKNOWN_ATTRIBUTES: Self = Self::new_static(420, "Unknown Attributes");
734
735    #[cfg(feature = "ice")]
736    pub const ROLE_CONFLICT: Self = Self::new_static(487, "Role Conflict");
737
738    /// Create a new error code with a given code and a message.
739    #[inline]
740    pub const fn new_static(code: u16, msg: &'static str) -> Self {
741        Self {
742            code,
743            msg: Cow::Borrowed(msg),
744        }
745    }
746
747    /// Create a new error code with a given code and a message.
748    #[inline]
749    pub fn new<T>(code: u16, msg: T) -> Self
750    where
751        T: ToString,
752    {
753        Self {
754            code,
755            msg: Cow::Owned(msg.to_string()),
756        }
757    }
758
759    /// Get the error code.
760    #[inline]
761    pub fn code(&self) -> u16 {
762        self.code
763    }
764
765    /// Get the error message.
766    #[inline]
767    pub fn message(&self) -> &str {
768        &self.msg
769    }
770}
771
772impl PartialEq for ErrorCode {
773    #[inline]
774    fn eq(&self, other: &Self) -> bool {
775        self.code == other.code
776    }
777}
778
779impl Eq for ErrorCode {}
780
781/// Take the message header bytes from a given STUN message.
782fn take_message_header(msg: &[u8]) -> [u8; 20] {
783    assert!(msg.len() >= 20);
784
785    let mut header = [0u8; 20];
786
787    header.copy_from_slice(&msg[..20]);
788    header
789}
790
791/// Set message length to a given STUN message.
792fn set_message_length(msg: &mut [u8], len: u16) {
793    assert!(msg.len() >= 20);
794
795    msg[2] = (len >> 8) as u8;
796    msg[3] = (len & 0xff) as u8;
797}
798
799/// Calculate message integrity of a given STUN message.
800fn calculate_message_integrity(key: &[u8], msg: &[u8]) -> [u8; 20] {
801    let mut header = take_message_header(msg);
802
803    let len = msg.len() - 20 + 24;
804
805    set_message_length(&mut header, len as u16);
806
807    let mut hmac = Hmac::<Sha1>::new_from_slice(key).expect("unable to initialize HMAC-SHA1");
808
809    hmac.update(&header);
810    hmac.update(&msg[20..]);
811
812    let hash = hmac.finalize().into_bytes();
813
814    assert_eq!(hash.len(), 20);
815
816    hash.into()
817}
818
819/// Calculate fingerprint of a given stun message.
820fn calculate_fingerprint(msg: &[u8]) -> u32 {
821    let mut header = take_message_header(msg);
822
823    let len = msg.len() - 20 + 8;
824
825    set_message_length(&mut header, len as u16);
826
827    let crc = Crc::<u32>::new(&CRC_32_ISO_HDLC);
828
829    let mut digest = crc.digest();
830
831    digest.update(&header);
832    digest.update(&msg[20..]);
833
834    digest.finalize() ^ 0x5354554e
835}