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#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
24pub enum MessageClass {
25 Request,
26 Indication,
27 Success,
28 Error,
29}
30
31impl MessageClass {
32 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 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#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
56pub enum Method {
57 Binding,
58 Other(u16),
59}
60
61impl Method {
62 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 fn into_message_type(self) -> u16 {
72 match self {
73 Self::Binding => 0x0001,
74 Self::Other(m) => m & !0xc110,
75 }
76 }
77}
78
79type TransactionID = [u8; 12];
81
82struct InvalidMessageHeader;
84
85struct MessageHeader {
87 message_type: u16,
88 message_length: u16,
89 magic_cookie: u32,
90 transaction_id: TransactionID,
91}
92
93impl MessageHeader {
94 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 fn message_class(&self) -> MessageClass {
118 MessageClass::from_message_type(self.message_type)
119 }
120
121 fn method(&self) -> Method {
123 Method::from_message_type(self.message_type)
124 }
125}
126
127#[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#[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#[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 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 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 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 #[inline]
265 pub fn is_rfc5389_message(&self) -> bool {
266 self.magic_cookie == RFC_5389_MAGIC_COOKIE
267 }
268
269 #[inline]
271 pub fn is_request(&self) -> bool {
272 matches!(self.class, MessageClass::Request)
273 }
274
275 #[inline]
277 pub fn is_response(&self) -> bool {
278 matches!(self.class, MessageClass::Success | MessageClass::Error)
279 }
280
281 #[inline]
283 pub fn class(&self) -> MessageClass {
284 self.class
285 }
286
287 #[inline]
289 pub fn method(&self) -> Method {
290 self.method
291 }
292
293 #[inline]
295 pub fn magic_cookie(&self) -> u32 {
296 self.magic_cookie
297 }
298
299 #[inline]
301 pub fn transaction_id(&self) -> [u8; 12] {
302 self.transaction_id
303 }
304
305 #[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 #[inline]
318 pub fn attributes(&self) -> &Attributes {
319 &self.attributes
320 }
321
322 #[inline]
328 pub fn unknown_attributes(&self) -> &[u16] {
329 &self.unknown_attributes
330 }
331
332 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 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
378pub 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 #[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 #[inline]
448 pub fn binding_request(transaction_id: [u8; 12]) -> Self {
449 Self::new(MessageClass::Request, Method::Binding, transaction_id)
450 }
451
452 #[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 #[inline]
463 pub fn success_response(request: &Message) -> Self {
464 Self::response(MessageClass::Success, request)
465 }
466
467 #[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 #[inline]
478 pub fn class(&mut self, class: MessageClass) -> &mut Self {
479 self.class = class;
480 self
481 }
482
483 #[inline]
485 pub fn method(&mut self, method: Method) -> &mut Self {
486 self.method = method;
487 self
488 }
489
490 #[inline]
492 pub fn magic_cookie(&mut self, cookie: u32) -> &mut Self {
493 self.magic_cookie = cookie;
494 self
495 }
496
497 #[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 #[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 #[inline]
521 pub fn mapped_address(&mut self, addr: SocketAddr) -> &mut Self {
522 self.mapped_address = Some(addr);
523 self
524 }
525
526 #[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 #[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 #[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 #[inline]
555 pub fn fingerprint(&mut self, enable: bool) -> &mut Self {
556 self.fingerprint = enable;
557 self
558 }
559
560 #[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 #[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 #[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 #[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 #[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 #[inline]
609 pub fn alternate_server(&mut self, server: SocketAddr) -> &mut Self {
610 self.alternate_server = Some(server);
611 self
612 }
613
614 #[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 #[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 #[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 #[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 pub fn build(&self) -> Bytes {
648 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#[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 #[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 #[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 #[inline]
761 pub fn code(&self) -> u16 {
762 self.code
763 }
764
765 #[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
781fn 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
791fn 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
799fn 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
819fn 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}