1macro_rules! bytewise_xor {
128 ($size:literal, $a:expr, $b:expr, $default:literal) => {{
129 let mut arr = [$default; $size];
130 for (i, item) in arr.iter_mut().enumerate() {
131 *item = $a[i] ^ $b[i];
132 }
133 arr
134 }};
135}
136
137mod address;
138pub use address::{AddressFamily, MappedSocketAddr, XorSocketAddr};
139mod alternate;
140pub use alternate::{AlternateDomain, AlternateServer};
141mod error;
142pub use error::{ErrorCode, UnknownAttributes};
143mod ice;
144pub use ice::{IceControlled, IceControlling, Priority, UseCandidate};
145mod integrity;
146pub use integrity::{MessageIntegrity, MessageIntegritySha256};
147mod fingerprint;
148pub use fingerprint::Fingerprint;
149mod nonce;
150pub use nonce::Nonce;
151mod password_algorithm;
152pub use password_algorithm::{PasswordAlgorithm, PasswordAlgorithmValue, PasswordAlgorithms};
153mod realm;
154pub use realm::Realm;
155mod user;
156pub use user::{Userhash, Username};
157mod software;
158pub use software::Software;
159mod xor_addr;
160pub use xor_addr::XorMappedAddress;
161
162use crate::data::Data;
163use crate::message::{StunParseError, StunWriteError};
164
165use byteorder::{BigEndian, ByteOrder};
166
167use std::collections::HashMap;
168use std::sync::{Mutex, OnceLock};
169
170pub type AttributeDisplay =
178 fn(&RawAttribute<'_>, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
179static ATTRIBUTE_EXTERNAL_DISPLAY_IMPL: OnceLock<Mutex<HashMap<AttributeType, AttributeDisplay>>> =
180 OnceLock::new();
181
182pub fn add_display_impl(atype: AttributeType, imp: AttributeDisplay) {
185 let mut display_impls = ATTRIBUTE_EXTERNAL_DISPLAY_IMPL
186 .get_or_init(Default::default)
187 .lock()
188 .unwrap();
189 display_impls.insert(atype, imp);
190}
191
192#[macro_export]
234macro_rules! attribute_display {
235 ($typ:ty) => {{
236 let imp = |attr: &$crate::attribute::RawAttribute<'_>,
237 f: &mut std::fmt::Formatter<'_>|
238 -> std::fmt::Result {
239 if let Ok(attr) = <$typ>::from_raw_ref(attr) {
240 write!(f, "{}", attr)
241 } else {
242 write!(
243 f,
244 "{}(Malformed): len: {}, data: {:?})",
245 attr.get_type(),
246 attr.header.length(),
247 attr.value
248 )
249 }
250 };
251
252 $crate::attribute::add_display_impl(<$typ>::TYPE, imp);
253 }};
254}
255
256static ATTRIBUTE_TYPE_NAME_MAP: OnceLock<Mutex<HashMap<AttributeType, &'static str>>> =
257 OnceLock::new();
258
259#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
261pub struct AttributeType(u16);
262
263impl std::fmt::Display for AttributeType {
264 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265 write!(f, "{}({:#x}: {})", self.0, self.0, self.name())
266 }
267}
268
269impl AttributeType {
270 pub fn add_name(self, name: &'static str) {
272 let mut anames = ATTRIBUTE_TYPE_NAME_MAP
273 .get_or_init(Default::default)
274 .lock()
275 .unwrap();
276 anames.insert(self, name);
277 }
278
279 pub const fn new(val: u16) -> Self {
289 Self(val)
290 }
291
292 pub fn value(&self) -> u16 {
302 self.0
303 }
304
305 pub fn name(self) -> &'static str {
313 match self {
314 AttributeType(0x0001) => "MAPPED-ADDRESS",
315 Username::TYPE => "USERNAME",
316 MessageIntegrity::TYPE => "MESSAGE-INTEGRITY",
317 ErrorCode::TYPE => "ERROR-CODE",
318 UnknownAttributes::TYPE => "UNKNOWN-ATTRIBUTES",
319 Realm::TYPE => "REALM",
320 Nonce::TYPE => "NONCE",
321 MessageIntegritySha256::TYPE => "MESSAGE-INTEGRITY-SHA256",
322 PasswordAlgorithm::TYPE => "PASSWORD-ALGORITHM",
323 Userhash::TYPE => "USERHASH",
324 XorMappedAddress::TYPE => "XOR-MAPPED-ADDRESS",
325 PasswordAlgorithms::TYPE => "PASSWORD_ALGORITHMS",
326 AlternateDomain::TYPE => "ALTERNATE-DOMAIN",
327 Software::TYPE => "SOFTWARE",
328 AlternateServer::TYPE => "ALTERNATE-SERVER",
329 Fingerprint::TYPE => "FINGERPRINT",
330 Priority::TYPE => "PRIORITY",
331 UseCandidate::TYPE => "USE-CANDIDATE",
332 IceControlled::TYPE => "ICE-CONTROLLED",
333 IceControlling::TYPE => "ICE-CONTROLLING",
334 _ => {
335 let anames = ATTRIBUTE_TYPE_NAME_MAP
336 .get_or_init(Default::default)
337 .lock()
338 .unwrap();
339 if let Some(name) = anames.get(&self) {
340 name
341 } else {
342 "unknown"
343 }
344 }
345 }
346 }
347
348 pub fn comprehension_required(self) -> bool {
359 self.0 < 0x8000
360 }
361}
362impl From<u16> for AttributeType {
363 fn from(f: u16) -> Self {
364 Self::new(f)
365 }
366}
367impl From<AttributeType> for u16 {
368 fn from(f: AttributeType) -> Self {
369 f.0
370 }
371}
372
373#[derive(Debug, Copy, Clone, PartialEq, Eq)]
375pub struct AttributeHeader {
376 atype: AttributeType,
377 length: u16,
378}
379
380impl AttributeHeader {
381 fn parse(data: &[u8]) -> Result<Self, StunParseError> {
382 if data.len() < 4 {
383 return Err(StunParseError::Truncated {
384 expected: 4,
385 actual: data.len(),
386 });
387 }
388 let ret = Self {
389 atype: BigEndian::read_u16(&data[0..2]).into(),
390 length: BigEndian::read_u16(&data[2..4]),
391 };
392 Ok(ret)
393 }
394
395 fn to_bytes(self) -> [u8; 4] {
396 let mut ret = [0; 4];
397 self.write_into(&mut ret);
398 ret
399 }
400
401 fn write_into(&self, ret: &mut [u8]) {
402 BigEndian::write_u16(&mut ret[0..2], self.atype.into());
403 BigEndian::write_u16(&mut ret[2..4], self.length);
404 }
405
406 pub fn get_type(&self) -> AttributeType {
408 self.atype
409 }
410
411 pub fn length(&self) -> u16 {
413 self.length
414 }
415}
416impl From<AttributeHeader> for [u8; 4] {
417 fn from(f: AttributeHeader) -> Self {
418 f.to_bytes()
419 }
420}
421impl TryFrom<&[u8]> for AttributeHeader {
422 type Error = StunParseError;
423
424 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
425 AttributeHeader::parse(value)
426 }
427}
428
429pub trait AttributeStaticType {
431 const TYPE: AttributeType;
433}
434
435pub trait Attribute: std::fmt::Debug + std::marker::Sync + std::marker::Send {
437 fn get_type(&self) -> AttributeType;
439
440 fn length(&self) -> u16;
443}
444
445pub trait AttributeFromRaw<'a>: Attribute {
447 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
449 where
450 Self: Sized;
451
452 fn from_raw(raw: RawAttribute<'a>) -> Result<Self, StunParseError>
454 where
455 Self: Sized,
456 {
457 Self::from_raw_ref(&raw)
458 }
459}
460
461fn padded_attr_len(len: usize) -> usize {
462 if len % 4 == 0 {
463 len
464 } else {
465 len + 4 - len % 4
466 }
467}
468
469pub trait AttributeExt {
471 fn padded_len(&self) -> usize;
474}
475
476impl<A: Attribute + ?Sized> AttributeExt for A {
477 fn padded_len(&self) -> usize {
478 4 + padded_attr_len(self.length() as usize)
479 }
480}
481
482pub trait AttributeWrite: Attribute {
484 fn write_into_unchecked(&self, dest: &mut [u8]);
488 fn to_raw(&self) -> RawAttribute<'_>;
490}
491
492pub trait AttributeWriteExt: AttributeWrite {
495 fn write_header_unchecked(&self, dest: &mut [u8]) -> usize;
500 fn write_header(&self, dest: &mut [u8]) -> Result<usize, StunWriteError>;
503 fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError>;
506}
507
508impl<A: AttributeWrite + ?Sized> AttributeWriteExt for A {
509 fn write_header(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
510 if dest.len() < 4 {
511 return Err(StunWriteError::TooSmall {
512 expected: 4,
513 actual: dest.len(),
514 });
515 }
516 self.write_header_unchecked(dest);
517 Ok(4)
518 }
519 fn write_header_unchecked(&self, dest: &mut [u8]) -> usize {
520 AttributeHeader {
521 atype: self.get_type(),
522 length: self.length(),
523 }
524 .write_into(dest);
525 4
526 }
527
528 fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
529 let len = self.padded_len();
530 if len > dest.len() {
531 return Err(StunWriteError::TooSmall {
532 expected: len,
533 actual: dest.len(),
534 });
535 }
536 self.write_into_unchecked(dest);
537 Ok(len)
538 }
539}
540
541#[derive(Debug, Clone, PartialEq, Eq)]
543pub struct RawAttribute<'a> {
544 pub header: AttributeHeader,
546 pub value: Data<'a>,
548}
549
550macro_rules! display_attr {
551 ($this:ident, $f:ident, $CamelType:ty) => {{
552 if let Ok(attr) = <$CamelType>::from_raw_ref($this) {
553 write!($f, "{}", attr)
554 } else {
555 write!(
556 $f,
557 "{}(Malformed): len: {}, data: {:?})",
558 $this.get_type(),
559 $this.header.length(),
560 $this.value
561 )
562 }
563 }};
564}
565
566impl std::fmt::Display for RawAttribute<'_> {
567 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
568 match self.get_type() {
570 Username::TYPE => display_attr!(self, f, Username),
571 MessageIntegrity::TYPE => display_attr!(self, f, MessageIntegrity),
572 ErrorCode::TYPE => display_attr!(self, f, ErrorCode),
573 UnknownAttributes::TYPE => display_attr!(self, f, UnknownAttributes),
574 Realm::TYPE => display_attr!(self, f, Realm),
575 Nonce::TYPE => display_attr!(self, f, Nonce),
576 MessageIntegritySha256::TYPE => {
577 display_attr!(self, f, MessageIntegritySha256)
578 }
579 PasswordAlgorithm::TYPE => display_attr!(self, f, PasswordAlgorithm),
580 XorMappedAddress::TYPE => display_attr!(self, f, XorMappedAddress),
582 PasswordAlgorithms::TYPE => display_attr!(self, f, PasswordAlgorithms),
583 AlternateDomain::TYPE => display_attr!(self, f, AlternateDomain),
584 Software::TYPE => display_attr!(self, f, Software),
585 AlternateServer::TYPE => display_attr!(self, f, AlternateServer),
586 Fingerprint::TYPE => display_attr!(self, f, Fingerprint),
587 Priority::TYPE => display_attr!(self, f, Priority),
588 UseCandidate::TYPE => display_attr!(self, f, UseCandidate),
589 IceControlled::TYPE => display_attr!(self, f, IceControlled),
590 IceControlling::TYPE => display_attr!(self, f, IceControlling),
591 _ => {
592 let mut display_impls = ATTRIBUTE_EXTERNAL_DISPLAY_IMPL
593 .get_or_init(|| Default::default())
594 .lock()
595 .unwrap();
596 if let Some(imp) = display_impls.get_mut(&self.get_type()) {
597 imp(self, f)
598 } else {
599 write!(
600 f,
601 "RawAttribute (type: {:?}, len: {}, data: {:?})",
602 self.header.get_type(),
603 self.header.length(),
604 &self.value
605 )
606 }
607 }
608 }
609 }
610}
611
612impl<'a> RawAttribute<'a> {
613 pub fn new(atype: AttributeType, data: &'a [u8]) -> Self {
615 Self {
616 header: AttributeHeader {
617 atype,
618 length: data.len() as u16,
619 },
620 value: data.into(),
621 }
622 }
623
624 pub fn new_owned(atype: AttributeType, data: Box<[u8]>) -> Self {
626 Self {
627 header: AttributeHeader {
628 atype,
629 length: data.len() as u16,
630 },
631 value: data.into(),
632 }
633 }
634
635 pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
647 let header = AttributeHeader::parse(data)?;
648 if header.length() > (data.len() - 4) as u16 {
650 return Err(StunParseError::Truncated {
651 expected: header.length() as usize,
652 actual: data.len() - 4,
653 });
654 }
655 Ok(Self {
656 header,
657 value: Data::Borrowed(data[4..header.length() as usize + 4].into()),
658 })
659 }
660
661 pub fn to_bytes(&self) -> Vec<u8> {
671 let mut vec = Vec::with_capacity(self.padded_len());
672 let mut header_bytes = [0; 4];
673 self.header.write_into(&mut header_bytes);
674 vec.extend(&header_bytes);
675 vec.extend(&*self.value);
676 let len = vec.len();
677 if len % 4 != 0 {
678 vec.resize(len + 4 - (len % 4), 0);
680 }
681 vec
682 }
683
684 pub fn check_type_and_len(
687 &self,
688 atype: AttributeType,
689 allowed_range: impl std::ops::RangeBounds<usize>,
690 ) -> Result<(), StunParseError> {
691 if self.header.get_type() != atype {
692 return Err(StunParseError::WrongAttributeImplementation);
693 }
694 check_len(self.value.len(), allowed_range)
695 }
696
697 pub fn into_owned<'b>(self) -> RawAttribute<'b> {
699 RawAttribute {
700 header: self.header,
701 value: self.value.into_owned(),
702 }
703 }
704}
705
706impl Attribute for RawAttribute<'_> {
707 fn get_type(&self) -> AttributeType {
709 self.header.get_type()
710 }
711
712 fn length(&self) -> u16 {
714 self.value.len() as u16
715 }
716}
717
718impl AttributeWrite for RawAttribute<'_> {
719 fn write_into_unchecked(&self, dest: &mut [u8]) {
721 let len = self.padded_len();
722 self.header.write_into(dest);
723 let mut offset = 4;
724 dest[offset..offset + self.value.len()].copy_from_slice(&self.value);
725 offset += self.value.len();
726 if len - offset > 0 {
727 dest[offset..len].fill(0);
728 }
729 }
730
731 fn to_raw(&self) -> RawAttribute<'_> {
732 self.clone()
733 }
734}
735
736impl<'a, A: AttributeWrite> From<&'a A> for RawAttribute<'a> {
737 fn from(value: &'a A) -> Self {
738 value.to_raw()
739 }
740}
741
742fn check_len(
743 len: usize,
744 allowed_range: impl std::ops::RangeBounds<usize>,
745) -> Result<(), StunParseError> {
746 match allowed_range.start_bound() {
747 std::ops::Bound::Unbounded => (),
748 std::ops::Bound::Included(start) => {
749 if len < *start {
750 return Err(StunParseError::Truncated {
751 expected: *start,
752 actual: len,
753 });
754 }
755 }
756 std::ops::Bound::Excluded(start) => {
757 if len <= *start {
758 return Err(StunParseError::Truncated {
759 expected: start + 1,
760 actual: len,
761 });
762 }
763 }
764 }
765 match allowed_range.end_bound() {
766 std::ops::Bound::Unbounded => (),
767 std::ops::Bound::Included(end) => {
768 if len > *end {
769 return Err(StunParseError::TooLarge {
770 expected: *end,
771 actual: len,
772 });
773 }
774 }
775 std::ops::Bound::Excluded(end) => {
776 if len >= *end {
777 return Err(StunParseError::TooLarge {
778 expected: *end - 1,
779 actual: len,
780 });
781 }
782 }
783 }
784 Ok(())
785}
786
787impl From<RawAttribute<'_>> for Vec<u8> {
788 fn from(f: RawAttribute) -> Self {
789 f.to_bytes()
790 }
791}
792
793#[cfg(test)]
794mod tests {
795 use super::*;
796
797 #[test]
798 fn attribute_type() {
799 let _log = crate::tests::test_init_log();
800 let atype = ErrorCode::TYPE;
801 let anum: u16 = atype.into();
802 assert_eq!(atype, anum.into());
803 }
804
805 #[test]
806 fn short_attribute_header() {
807 let _log = crate::tests::test_init_log();
808 let data = [0; 1];
809 let res: Result<AttributeHeader, _> = data.as_ref().try_into();
811 assert!(res.is_err());
812 }
813
814 #[test]
815 fn raw_attribute_construct() {
816 let _log = crate::tests::test_init_log();
817 let a = RawAttribute::new(1.into(), &[80, 160]);
818 assert_eq!(a.get_type(), 1.into());
819 let bytes: Vec<_> = a.into();
820 assert_eq!(bytes, &[0, 1, 0, 2, 80, 160, 0, 0]);
821 let b = RawAttribute::from_bytes(bytes.as_ref()).unwrap();
822 assert_eq!(b.get_type(), 1.into());
823 }
824
825 #[test]
826 fn raw_attribute_encoding() {
827 let _log = crate::tests::test_init_log();
828 let orig = RawAttribute::new(1.into(), &[80, 160]);
829 assert_eq!(orig.get_type(), 1.into());
830 let mut data: Vec<_> = orig.into();
831 let len = data.len();
832 BigEndian::write_u16(&mut data[2..4], len as u16 - 4 + 1);
834 assert!(matches!(
835 RawAttribute::from_bytes(data.as_ref()),
836 Err(StunParseError::Truncated {
837 expected: 5,
838 actual: 4
839 })
840 ));
841 }
842
843 #[test]
844 fn test_check_len() {
845 let _log = crate::tests::test_init_log();
846 assert!(check_len(4, ..).is_ok());
847 assert!(check_len(4, 0..).is_ok());
848 assert!(check_len(4, 0..8).is_ok());
849 assert!(check_len(4, 0..=8).is_ok());
850 assert!(check_len(4, ..=8).is_ok());
851 assert!(matches!(
852 check_len(4, ..4),
853 Err(StunParseError::TooLarge {
854 expected: 3,
855 actual: 4
856 })
857 ));
858 assert!(matches!(
859 check_len(4, 5..),
860 Err(StunParseError::Truncated {
861 expected: 5,
862 actual: 4
863 })
864 ));
865 assert!(matches!(
866 check_len(4, ..=3),
867 Err(StunParseError::TooLarge {
868 expected: 3,
869 actual: 4
870 })
871 ));
872 assert!(matches!(
873 check_len(
874 4,
875 (std::ops::Bound::Excluded(4), std::ops::Bound::Unbounded)
876 ),
877 Err(StunParseError::Truncated {
878 expected: 5,
879 actual: 4
880 })
881 ));
882 }
883
884 #[test]
885 fn test_external_display_impl() {
886 let _log = crate::tests::test_init_log();
887 let atype = AttributeType::new(0xFFFF);
888 let imp = |attr: &RawAttribute<'_>, f: &mut std::fmt::Formatter<'_>| -> std::fmt::Result {
889 write!(f, "Custom {}", attr.value[0])
890 };
891 add_display_impl(atype, imp);
892 let data = [4, 0];
893 let attr = RawAttribute::new(atype, &data);
894 let display_str = format!("{}", attr);
895 assert_eq!(display_str, "Custom 4");
896
897 atype.add_name("SOME-NAME");
898 assert_eq!(atype.name(), "SOME-NAME");
899
900 attribute_display!(Fingerprint);
901 }
902}