1macro_rules! bytewise_xor {
130 ($size:literal, $a:expr, $b:expr, $default:literal) => {{
131 let mut arr = [$default; $size];
132 for (i, item) in arr.iter_mut().enumerate() {
133 *item = $a[i] ^ $b[i];
134 }
135 arr
136 }};
137}
138
139mod address;
140pub use address::{MappedSocketAddr, XorSocketAddr};
141mod alternate;
142pub use alternate::{AlternateDomain, AlternateServer};
143mod error;
144pub use error::{ErrorCode, UnknownAttributes};
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};
164use alloc::boxed::Box;
165use alloc::vec::Vec;
166
167use byteorder::{BigEndian, ByteOrder};
168
169#[cfg(feature = "std")]
170use alloc::collections::BTreeMap;
171#[cfg(feature = "std")]
172use std::sync::{Mutex, OnceLock};
173
174pub type AttributeDisplay =
182 fn(&RawAttribute<'_>, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result;
183#[cfg(feature = "std")]
184static ATTRIBUTE_EXTERNAL_DISPLAY_IMPL: OnceLock<Mutex<BTreeMap<AttributeType, AttributeDisplay>>> =
185 OnceLock::new();
186
187#[cfg(feature = "std")]
190pub fn add_display_impl(atype: AttributeType, imp: AttributeDisplay) {
191 let mut display_impls = ATTRIBUTE_EXTERNAL_DISPLAY_IMPL
192 .get_or_init(Default::default)
193 .lock()
194 .unwrap();
195 display_impls.insert(atype, imp);
196}
197
198#[macro_export]
243macro_rules! attribute_display {
244 ($typ:ty) => {{
245 let imp = |attr: &$crate::attribute::RawAttribute<'_>,
246 f: &mut core::fmt::Formatter<'_>|
247 -> core::fmt::Result {
248 if let Ok(attr) = <$typ>::from_raw_ref(attr) {
249 write!(f, "{}", attr)
250 } else {
251 write!(
252 f,
253 "{}(Malformed): len: {}, data: {:?})",
254 attr.get_type(),
255 attr.header.length(),
256 attr.value
257 )
258 }
259 };
260
261 $crate::attribute::add_display_impl(<$typ>::TYPE, imp);
262 }};
263}
264
265#[cfg(feature = "std")]
266static ATTRIBUTE_TYPE_NAME_MAP: OnceLock<Mutex<BTreeMap<AttributeType, &'static str>>> =
267 OnceLock::new();
268
269#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
271pub struct AttributeType(u16);
272
273impl core::fmt::Display for AttributeType {
274 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
275 write!(f, "{}({:#x}: {})", self.0, self.0, self.name())
276 }
277}
278
279impl AttributeType {
280 #[cfg(feature = "std")]
282 pub fn add_name(self, name: &'static str) {
283 let mut anames = ATTRIBUTE_TYPE_NAME_MAP
284 .get_or_init(Default::default)
285 .lock()
286 .unwrap();
287 anames.insert(self, name);
288 }
289
290 pub const fn new(val: u16) -> Self {
300 Self(val)
301 }
302
303 pub fn value(&self) -> u16 {
313 self.0
314 }
315
316 pub fn name(self) -> &'static str {
324 match self {
325 AttributeType(0x0001) => "MAPPED-ADDRESS",
326 Username::TYPE => "USERNAME",
327 MessageIntegrity::TYPE => "MESSAGE-INTEGRITY",
328 ErrorCode::TYPE => "ERROR-CODE",
329 UnknownAttributes::TYPE => "UNKNOWN-ATTRIBUTES",
330 Realm::TYPE => "REALM",
331 Nonce::TYPE => "NONCE",
332 MessageIntegritySha256::TYPE => "MESSAGE-INTEGRITY-SHA256",
333 PasswordAlgorithm::TYPE => "PASSWORD-ALGORITHM",
334 Userhash::TYPE => "USERHASH",
335 XorMappedAddress::TYPE => "XOR-MAPPED-ADDRESS",
336 PasswordAlgorithms::TYPE => "PASSWORD_ALGORITHMS",
337 AlternateDomain::TYPE => "ALTERNATE-DOMAIN",
338 Software::TYPE => "SOFTWARE",
339 AlternateServer::TYPE => "ALTERNATE-SERVER",
340 Fingerprint::TYPE => "FINGERPRINT",
341 _ => {
342 #[cfg(feature = "std")]
343 {
344 let anames = ATTRIBUTE_TYPE_NAME_MAP
345 .get_or_init(Default::default)
346 .lock()
347 .unwrap();
348 if let Some(name) = anames.get(&self) {
349 return name;
350 }
351 }
352 "unknown"
353 }
354 }
355 }
356
357 pub fn comprehension_required(self) -> bool {
368 self.0 < 0x8000
369 }
370}
371impl From<u16> for AttributeType {
372 fn from(f: u16) -> Self {
373 Self::new(f)
374 }
375}
376impl From<AttributeType> for u16 {
377 fn from(f: AttributeType) -> Self {
378 f.0
379 }
380}
381
382#[derive(Debug, Copy, Clone, PartialEq, Eq)]
384pub struct AttributeHeader {
385 atype: AttributeType,
386 length: u16,
387}
388
389impl AttributeHeader {
390 fn parse(data: &[u8]) -> Result<Self, StunParseError> {
391 if data.len() < 4 {
392 return Err(StunParseError::Truncated {
393 expected: 4,
394 actual: data.len(),
395 });
396 }
397 let ret = Self {
398 atype: BigEndian::read_u16(&data[0..2]).into(),
399 length: BigEndian::read_u16(&data[2..4]),
400 };
401 Ok(ret)
402 }
403
404 fn to_bytes(self) -> [u8; 4] {
405 let mut ret = [0; 4];
406 self.write_into(&mut ret);
407 ret
408 }
409
410 fn write_into(&self, ret: &mut [u8]) {
411 BigEndian::write_u16(&mut ret[0..2], self.atype.into());
412 BigEndian::write_u16(&mut ret[2..4], self.length);
413 }
414
415 pub fn get_type(&self) -> AttributeType {
417 self.atype
418 }
419
420 pub fn length(&self) -> u16 {
422 self.length
423 }
424}
425impl From<AttributeHeader> for [u8; 4] {
426 fn from(f: AttributeHeader) -> Self {
427 f.to_bytes()
428 }
429}
430impl TryFrom<&[u8]> for AttributeHeader {
431 type Error = StunParseError;
432
433 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
434 AttributeHeader::parse(value)
435 }
436}
437
438pub trait AttributeStaticType {
440 const TYPE: AttributeType;
442}
443
444pub trait Attribute: core::fmt::Debug + core::marker::Sync + core::marker::Send {
446 fn get_type(&self) -> AttributeType;
448
449 fn length(&self) -> u16;
452}
453
454pub trait AttributeFromRaw<'a>: Attribute {
456 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
458 where
459 Self: Sized;
460
461 fn from_raw(raw: RawAttribute<'a>) -> Result<Self, StunParseError>
463 where
464 Self: Sized,
465 {
466 Self::from_raw_ref(&raw)
467 }
468}
469
470fn padded_attr_len(len: usize) -> usize {
471 if len % 4 == 0 {
472 len
473 } else {
474 len + 4 - len % 4
475 }
476}
477
478pub trait AttributeExt {
480 fn padded_len(&self) -> usize;
483}
484
485impl<A: Attribute + ?Sized> AttributeExt for A {
486 fn padded_len(&self) -> usize {
487 4 + padded_attr_len(self.length() as usize)
488 }
489}
490
491pub trait AttributeWrite: Attribute {
493 fn write_into_unchecked(&self, dest: &mut [u8]);
497 fn to_raw(&self) -> RawAttribute<'_>;
499}
500
501pub trait AttributeWriteExt: AttributeWrite {
504 fn write_header_unchecked(&self, dest: &mut [u8]) -> usize;
509 fn write_header(&self, dest: &mut [u8]) -> Result<usize, StunWriteError>;
512 fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError>;
515}
516
517impl<A: AttributeWrite + ?Sized> AttributeWriteExt for A {
518 fn write_header(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
519 if dest.len() < 4 {
520 return Err(StunWriteError::TooSmall {
521 expected: 4,
522 actual: dest.len(),
523 });
524 }
525 self.write_header_unchecked(dest);
526 Ok(4)
527 }
528 fn write_header_unchecked(&self, dest: &mut [u8]) -> usize {
529 AttributeHeader {
530 atype: self.get_type(),
531 length: self.length(),
532 }
533 .write_into(dest);
534 4
535 }
536
537 fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
538 let len = self.padded_len();
539 if len > dest.len() {
540 return Err(StunWriteError::TooSmall {
541 expected: len,
542 actual: dest.len(),
543 });
544 }
545 self.write_into_unchecked(dest);
546 Ok(len)
547 }
548}
549
550#[derive(Debug, Clone, PartialEq, Eq)]
552pub struct RawAttribute<'a> {
553 pub header: AttributeHeader,
555 pub value: Data<'a>,
557}
558
559macro_rules! display_attr {
560 ($this:ident, $f:ident, $CamelType:ty) => {{
561 if let Ok(attr) = <$CamelType>::from_raw_ref($this) {
562 write!($f, "{}", attr)
563 } else {
564 write!(
565 $f,
566 "{}(Malformed): len: {}, data: {:?})",
567 $this.get_type(),
568 $this.header.length(),
569 $this.value
570 )
571 }
572 }};
573}
574
575impl core::fmt::Display for RawAttribute<'_> {
576 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
577 match self.get_type() {
579 Username::TYPE => display_attr!(self, f, Username),
580 MessageIntegrity::TYPE => display_attr!(self, f, MessageIntegrity),
581 ErrorCode::TYPE => display_attr!(self, f, ErrorCode),
582 UnknownAttributes::TYPE => display_attr!(self, f, UnknownAttributes),
583 Realm::TYPE => display_attr!(self, f, Realm),
584 Nonce::TYPE => display_attr!(self, f, Nonce),
585 MessageIntegritySha256::TYPE => {
586 display_attr!(self, f, MessageIntegritySha256)
587 }
588 PasswordAlgorithm::TYPE => display_attr!(self, f, PasswordAlgorithm),
589 XorMappedAddress::TYPE => display_attr!(self, f, XorMappedAddress),
591 PasswordAlgorithms::TYPE => display_attr!(self, f, PasswordAlgorithms),
592 AlternateDomain::TYPE => display_attr!(self, f, AlternateDomain),
593 Software::TYPE => display_attr!(self, f, Software),
594 AlternateServer::TYPE => display_attr!(self, f, AlternateServer),
595 Fingerprint::TYPE => display_attr!(self, f, Fingerprint),
596 _ => {
597 #[cfg(feature = "std")]
598 {
599 let mut display_impls = ATTRIBUTE_EXTERNAL_DISPLAY_IMPL
600 .get_or_init(|| Default::default())
601 .lock()
602 .unwrap();
603 if let Some(imp) = display_impls.get_mut(&self.get_type()) {
604 return imp(self, f);
605 }
606 }
607 write!(
608 f,
609 "RawAttribute (type: {:?}, len: {}, data: {:?})",
610 self.header.get_type(),
611 self.header.length(),
612 &self.value
613 )
614 }
615 }
616 }
617}
618
619impl<'a> RawAttribute<'a> {
620 pub fn new(atype: AttributeType, data: &'a [u8]) -> Self {
622 Self {
623 header: AttributeHeader {
624 atype,
625 length: data.len() as u16,
626 },
627 value: data.into(),
628 }
629 }
630
631 pub fn new_owned(atype: AttributeType, data: Box<[u8]>) -> Self {
633 Self {
634 header: AttributeHeader {
635 atype,
636 length: data.len() as u16,
637 },
638 value: data.into(),
639 }
640 }
641
642 pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
654 let header = AttributeHeader::parse(data)?;
655 if header.length() > (data.len() - 4) as u16 {
657 return Err(StunParseError::Truncated {
658 expected: header.length() as usize,
659 actual: data.len() - 4,
660 });
661 }
662 Ok(Self {
663 header,
664 value: Data::Borrowed(data[4..header.length() as usize + 4].into()),
665 })
666 }
667
668 pub fn to_bytes(&self) -> Vec<u8> {
678 let mut vec = Vec::with_capacity(self.padded_len());
679 let mut header_bytes = [0; 4];
680 self.header.write_into(&mut header_bytes);
681 vec.extend(&header_bytes);
682 vec.extend(&*self.value);
683 let len = vec.len();
684 if len % 4 != 0 {
685 vec.resize(len + 4 - (len % 4), 0);
687 }
688 vec
689 }
690
691 pub fn check_type_and_len(
694 &self,
695 atype: AttributeType,
696 allowed_range: impl core::ops::RangeBounds<usize>,
697 ) -> Result<(), StunParseError> {
698 if self.header.get_type() != atype {
699 return Err(StunParseError::WrongAttributeImplementation);
700 }
701 check_len(self.value.len(), allowed_range)
702 }
703
704 pub fn into_owned<'b>(self) -> RawAttribute<'b> {
706 RawAttribute {
707 header: self.header,
708 value: self.value.into_owned(),
709 }
710 }
711}
712
713impl Attribute for RawAttribute<'_> {
714 fn get_type(&self) -> AttributeType {
716 self.header.get_type()
717 }
718
719 fn length(&self) -> u16 {
721 self.value.len() as u16
722 }
723}
724
725impl AttributeWrite for RawAttribute<'_> {
726 fn write_into_unchecked(&self, dest: &mut [u8]) {
728 let len = self.padded_len();
729 self.header.write_into(dest);
730 let mut offset = 4;
731 dest[offset..offset + self.value.len()].copy_from_slice(&self.value);
732 offset += self.value.len();
733 if len - offset > 0 {
734 dest[offset..len].fill(0);
735 }
736 }
737
738 fn to_raw(&self) -> RawAttribute<'_> {
739 self.clone()
740 }
741}
742
743impl<'a, A: AttributeWrite> From<&'a A> for RawAttribute<'a> {
744 fn from(value: &'a A) -> Self {
745 value.to_raw()
746 }
747}
748
749fn check_len(
750 len: usize,
751 allowed_range: impl core::ops::RangeBounds<usize>,
752) -> Result<(), StunParseError> {
753 match allowed_range.start_bound() {
754 core::ops::Bound::Unbounded => (),
755 core::ops::Bound::Included(start) => {
756 if len < *start {
757 return Err(StunParseError::Truncated {
758 expected: *start,
759 actual: len,
760 });
761 }
762 }
763 core::ops::Bound::Excluded(start) => {
764 if len <= *start {
765 return Err(StunParseError::Truncated {
766 expected: start + 1,
767 actual: len,
768 });
769 }
770 }
771 }
772 match allowed_range.end_bound() {
773 core::ops::Bound::Unbounded => (),
774 core::ops::Bound::Included(end) => {
775 if len > *end {
776 return Err(StunParseError::TooLarge {
777 expected: *end,
778 actual: len,
779 });
780 }
781 }
782 core::ops::Bound::Excluded(end) => {
783 if len >= *end {
784 return Err(StunParseError::TooLarge {
785 expected: *end - 1,
786 actual: len,
787 });
788 }
789 }
790 }
791 Ok(())
792}
793
794impl From<RawAttribute<'_>> for Vec<u8> {
795 fn from(f: RawAttribute) -> Self {
796 f.to_bytes()
797 }
798}
799
800#[cfg(test)]
801mod tests {
802 use super::*;
803
804 #[test]
805 fn attribute_type() {
806 let _log = crate::tests::test_init_log();
807 let atype = ErrorCode::TYPE;
808 let anum: u16 = atype.into();
809 assert_eq!(atype, anum.into());
810 }
811
812 #[test]
813 fn short_attribute_header() {
814 let _log = crate::tests::test_init_log();
815 let data = [0; 1];
816 let res: Result<AttributeHeader, _> = data.as_ref().try_into();
818 assert!(res.is_err());
819 }
820
821 #[test]
822 fn raw_attribute_construct() {
823 let _log = crate::tests::test_init_log();
824 let a = RawAttribute::new(1.into(), &[80, 160]);
825 assert_eq!(a.get_type(), 1.into());
826 let bytes: Vec<_> = a.into();
827 assert_eq!(bytes, &[0, 1, 0, 2, 80, 160, 0, 0]);
828 let b = RawAttribute::from_bytes(bytes.as_ref()).unwrap();
829 assert_eq!(b.get_type(), 1.into());
830 }
831
832 #[test]
833 fn raw_attribute_encoding() {
834 let mut out = [0; 8];
835 let mut out2 = [0; 8];
836 let _log = crate::tests::test_init_log();
837 let orig = RawAttribute::new(1.into(), &[80, 160]);
838 assert_eq!(orig.get_type(), 1.into());
839 orig.write_into(&mut out).unwrap();
840 orig.write_into_unchecked(&mut out2);
841 assert_eq!(out, out2);
842 let mut data: Vec<_> = orig.into();
843 let len = data.len();
844 BigEndian::write_u16(&mut data[2..4], len as u16 - 4 + 1);
846 assert!(matches!(
847 RawAttribute::from_bytes(data.as_ref()),
848 Err(StunParseError::Truncated {
849 expected: 5,
850 actual: 4
851 })
852 ));
853 }
854
855 #[test]
856 fn raw_attribute_header() {
857 let mut out = [0; 4];
858 let mut out2 = [0; 4];
859 let _log = crate::tests::test_init_log();
860 let orig = RawAttribute::new(1.into(), &[80, 160]);
861 assert!(matches!(orig.write_header(&mut out), Ok(4)));
862 assert_eq!(orig.write_header_unchecked(&mut out2), 4);
863 assert_eq!(out, out2);
864 assert_eq!(orig.header.to_bytes(), out);
865 assert_eq!(&orig.to_bytes()[..4], out);
866 let bytes: [_; 4] = orig.header.into();
867 assert_eq!(bytes, out);
868 }
869
870 #[test]
871 fn test_check_len() {
872 let _log = crate::tests::test_init_log();
873 assert!(check_len(4, ..).is_ok());
874 assert!(check_len(4, 0..).is_ok());
875 assert!(check_len(4, 0..8).is_ok());
876 assert!(check_len(4, 0..=8).is_ok());
877 assert!(check_len(4, ..=8).is_ok());
878 assert!(matches!(
879 check_len(4, ..4),
880 Err(StunParseError::TooLarge {
881 expected: 3,
882 actual: 4
883 })
884 ));
885 assert!(matches!(
886 check_len(4, 5..),
887 Err(StunParseError::Truncated {
888 expected: 5,
889 actual: 4
890 })
891 ));
892 assert!(matches!(
893 check_len(4, ..=3),
894 Err(StunParseError::TooLarge {
895 expected: 3,
896 actual: 4
897 })
898 ));
899 assert!(matches!(
900 check_len(
901 4,
902 (core::ops::Bound::Excluded(4), core::ops::Bound::Unbounded)
903 ),
904 Err(StunParseError::Truncated {
905 expected: 5,
906 actual: 4
907 })
908 ));
909 }
910
911 #[test]
912 #[cfg(feature = "std")]
913 fn test_external_display_impl() {
914 let _log = crate::tests::test_init_log();
915 let atype = AttributeType::new(0xFFFF);
916 let imp = |attr: &RawAttribute<'_>,
917 f: &mut core::fmt::Formatter<'_>|
918 -> core::fmt::Result { write!(f, "Custom {}", attr.value[0]) };
919 add_display_impl(atype, imp);
920 let data = [4, 0];
921 let attr = RawAttribute::new(atype, &data);
922 let display_str = alloc::format!("{}", attr);
923 assert_eq!(display_str, "Custom 4");
924
925 atype.add_name("SOME-NAME");
926 assert_eq!(atype.name(), "SOME-NAME");
927
928 attribute_display!(Fingerprint);
929 }
930}