1macro_rules! bytewise_xor {
132 ($size:literal, $a:expr, $b:expr, $default:literal) => {{
133 let mut arr = [$default; $size];
134 for (i, item) in arr.iter_mut().enumerate() {
135 *item = $a[i] ^ $b[i];
136 }
137 arr
138 }};
139}
140
141mod address;
142pub use address::{MappedSocketAddr, XorSocketAddr};
143mod alternate;
144pub use alternate::{AlternateDomain, AlternateServer};
145mod error;
146pub use error::{ErrorCode, UnknownAttributes};
147mod integrity;
148pub use integrity::{MessageIntegrity, MessageIntegritySha256};
149mod fingerprint;
150pub use fingerprint::Fingerprint;
151mod nonce;
152pub use nonce::Nonce;
153mod password_algorithm;
154pub use password_algorithm::{PasswordAlgorithm, PasswordAlgorithmValue, PasswordAlgorithms};
155mod realm;
156pub use realm::Realm;
157mod user;
158pub use user::{Userhash, Username};
159mod software;
160pub use software::Software;
161mod xor_addr;
162pub use xor_addr::XorMappedAddress;
163
164use crate::data::Data;
165use crate::message::{StunParseError, StunWriteError};
166use alloc::boxed::Box;
167use alloc::vec::Vec;
168
169use byteorder::{BigEndian, ByteOrder};
170
171#[cfg(feature = "std")]
172use alloc::collections::BTreeMap;
173#[cfg(feature = "std")]
174use std::sync::{Mutex, OnceLock};
175
176pub type AttributeDisplay =
184 fn(&RawAttribute<'_>, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result;
185#[cfg(feature = "std")]
186static ATTRIBUTE_EXTERNAL_DISPLAY_IMPL: OnceLock<Mutex<BTreeMap<AttributeType, AttributeDisplay>>> =
187 OnceLock::new();
188
189#[cfg(feature = "std")]
193pub fn add_display_impl(atype: AttributeType, imp: AttributeDisplay) {
194 let mut display_impls = ATTRIBUTE_EXTERNAL_DISPLAY_IMPL
195 .get_or_init(Default::default)
196 .lock()
197 .unwrap();
198 display_impls.insert(atype, imp);
199}
200
201#[cfg(feature = "std")]
246#[macro_export]
247macro_rules! attribute_display {
248 ($typ:ty) => {{
249 let imp = |attr: &$crate::attribute::RawAttribute<'_>,
250 f: &mut core::fmt::Formatter<'_>|
251 -> core::fmt::Result {
252 if let Ok(attr) = <$typ>::from_raw_ref(attr) {
253 write!(f, "{}", attr)
254 } else {
255 write!(
256 f,
257 "{}(Malformed): len: {}, data: {:?})",
258 attr.get_type(),
259 attr.header.length(),
260 attr.value
261 )
262 }
263 };
264
265 $crate::attribute::add_display_impl(<$typ>::TYPE, imp);
266 }};
267}
268
269#[cfg(feature = "std")]
270static ATTRIBUTE_TYPE_NAME_MAP: OnceLock<Mutex<BTreeMap<AttributeType, &'static str>>> =
271 OnceLock::new();
272
273#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
275pub struct AttributeType(u16);
276
277impl core::fmt::Display for AttributeType {
278 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
279 write!(f, "{}({:#x}: {})", self.0, self.0, self.name())
280 }
281}
282
283impl AttributeType {
284 #[cfg(feature = "std")]
286 pub fn add_name(self, name: &'static str) {
287 let mut anames = ATTRIBUTE_TYPE_NAME_MAP
288 .get_or_init(Default::default)
289 .lock()
290 .unwrap();
291 anames.insert(self, name);
292 }
293
294 pub const fn new(val: u16) -> Self {
304 Self(val)
305 }
306
307 pub fn value(&self) -> u16 {
317 self.0
318 }
319
320 pub fn name(self) -> &'static str {
328 match self {
329 AttributeType(0x0001) => "MAPPED-ADDRESS",
330 Username::TYPE => "USERNAME",
331 MessageIntegrity::TYPE => "MESSAGE-INTEGRITY",
332 ErrorCode::TYPE => "ERROR-CODE",
333 UnknownAttributes::TYPE => "UNKNOWN-ATTRIBUTES",
334 Realm::TYPE => "REALM",
335 Nonce::TYPE => "NONCE",
336 MessageIntegritySha256::TYPE => "MESSAGE-INTEGRITY-SHA256",
337 PasswordAlgorithm::TYPE => "PASSWORD-ALGORITHM",
338 Userhash::TYPE => "USERHASH",
339 XorMappedAddress::TYPE => "XOR-MAPPED-ADDRESS",
340 PasswordAlgorithms::TYPE => "PASSWORD_ALGORITHMS",
341 AlternateDomain::TYPE => "ALTERNATE-DOMAIN",
342 Software::TYPE => "SOFTWARE",
343 AlternateServer::TYPE => "ALTERNATE-SERVER",
344 Fingerprint::TYPE => "FINGERPRINT",
345 _ => {
346 #[cfg(feature = "std")]
347 {
348 let anames = ATTRIBUTE_TYPE_NAME_MAP
349 .get_or_init(Default::default)
350 .lock()
351 .unwrap();
352 if let Some(name) = anames.get(&self) {
353 return name;
354 }
355 }
356 "unknown"
357 }
358 }
359 }
360
361 pub fn comprehension_required(self) -> bool {
373 self.0 < 0x8000
374 }
375}
376impl From<u16> for AttributeType {
377 fn from(f: u16) -> Self {
378 Self::new(f)
379 }
380}
381impl From<AttributeType> for u16 {
382 fn from(f: AttributeType) -> Self {
383 f.0
384 }
385}
386
387#[derive(Debug, Copy, Clone, PartialEq, Eq)]
391pub struct AttributeHeader {
392 atype: AttributeType,
393 length: u16,
394}
395
396impl AttributeHeader {
397 fn parse(data: &[u8]) -> Result<Self, StunParseError> {
398 if data.len() < 4 {
399 return Err(StunParseError::Truncated {
400 expected: 4,
401 actual: data.len(),
402 });
403 }
404 let ret = Self {
405 atype: BigEndian::read_u16(&data[0..2]).into(),
406 length: BigEndian::read_u16(&data[2..4]),
407 };
408 Ok(ret)
409 }
410
411 fn to_bytes(self) -> [u8; 4] {
412 let mut ret = [0; 4];
413 self.write_into(&mut ret);
414 ret
415 }
416
417 fn write_into(&self, ret: &mut [u8]) {
418 BigEndian::write_u16(&mut ret[0..2], self.atype.into());
419 BigEndian::write_u16(&mut ret[2..4], self.length);
420 }
421
422 pub fn get_type(&self) -> AttributeType {
424 self.atype
425 }
426
427 pub fn length(&self) -> u16 {
429 self.length
430 }
431}
432impl From<AttributeHeader> for [u8; 4] {
433 fn from(f: AttributeHeader) -> Self {
434 f.to_bytes()
435 }
436}
437impl TryFrom<&[u8]> for AttributeHeader {
438 type Error = StunParseError;
439
440 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
441 AttributeHeader::parse(value)
442 }
443}
444
445pub trait AttributeStaticType {
447 const TYPE: AttributeType;
449}
450
451pub trait Attribute: core::fmt::Debug + core::marker::Sync + core::marker::Send {
453 fn get_type(&self) -> AttributeType;
455
456 fn length(&self) -> u16;
459}
460
461pub trait AttributeFromRaw<'a>: Attribute {
463 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
465 where
466 Self: Sized;
467
468 fn from_raw(raw: RawAttribute<'a>) -> Result<Self, StunParseError>
470 where
471 Self: Sized,
472 {
473 Self::from_raw_ref(&raw)
474 }
475}
476
477pub fn pad_attribute_len(len: usize) -> usize {
479 if len % 4 == 0 {
480 len
481 } else {
482 len + 4 - len % 4
483 }
484}
485
486pub trait AttributeExt {
488 fn padded_len(&self) -> usize;
491}
492
493impl<A: Attribute + ?Sized> AttributeExt for A {
494 fn padded_len(&self) -> usize {
495 4 + pad_attribute_len(self.length() as usize)
496 }
497}
498
499pub trait AttributeWrite: Attribute {
501 fn write_into_unchecked(&self, dest: &mut [u8]);
505 fn to_raw(&self) -> RawAttribute<'_>;
507}
508
509pub trait AttributeWriteExt: AttributeWrite {
512 fn write_header_unchecked(&self, dest: &mut [u8]) -> usize;
517 fn write_header(&self, dest: &mut [u8]) -> Result<usize, StunWriteError>;
520 fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError>;
523}
524
525impl<A: AttributeWrite + ?Sized> AttributeWriteExt for A {
526 fn write_header(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
527 if dest.len() < 4 {
528 return Err(StunWriteError::TooSmall {
529 expected: 4,
530 actual: dest.len(),
531 });
532 }
533 self.write_header_unchecked(dest);
534 Ok(4)
535 }
536 fn write_header_unchecked(&self, dest: &mut [u8]) -> usize {
537 AttributeHeader {
538 atype: self.get_type(),
539 length: self.length(),
540 }
541 .write_into(dest);
542 4
543 }
544
545 fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
546 let len = self.padded_len();
547 if len > dest.len() {
548 return Err(StunWriteError::TooSmall {
549 expected: len,
550 actual: dest.len(),
551 });
552 }
553 self.write_into_unchecked(dest);
554 Ok(len)
555 }
556}
557
558#[derive(Debug, Clone, PartialEq, Eq)]
560pub struct RawAttribute<'a> {
561 pub header: AttributeHeader,
563 pub value: Data<'a>,
565}
566
567macro_rules! display_attr {
568 ($this:ident, $f:ident, $CamelType:ty) => {{
569 if let Ok(attr) = <$CamelType>::from_raw_ref($this) {
570 write!($f, "{}", attr)
571 } else {
572 write!(
573 $f,
574 "{}(Malformed): len: {}, data: {:?})",
575 $this.get_type(),
576 $this.header.length(),
577 $this.value
578 )
579 }
580 }};
581}
582
583impl core::fmt::Display for RawAttribute<'_> {
584 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
585 match self.get_type() {
587 Username::TYPE => display_attr!(self, f, Username),
588 MessageIntegrity::TYPE => display_attr!(self, f, MessageIntegrity),
589 ErrorCode::TYPE => display_attr!(self, f, ErrorCode),
590 UnknownAttributes::TYPE => display_attr!(self, f, UnknownAttributes),
591 Realm::TYPE => display_attr!(self, f, Realm),
592 Nonce::TYPE => display_attr!(self, f, Nonce),
593 MessageIntegritySha256::TYPE => {
594 display_attr!(self, f, MessageIntegritySha256)
595 }
596 PasswordAlgorithm::TYPE => display_attr!(self, f, PasswordAlgorithm),
597 Userhash::TYPE => display_attr!(self, f, Userhash),
598 XorMappedAddress::TYPE => display_attr!(self, f, XorMappedAddress),
599 PasswordAlgorithms::TYPE => display_attr!(self, f, PasswordAlgorithms),
600 AlternateDomain::TYPE => display_attr!(self, f, AlternateDomain),
601 Software::TYPE => display_attr!(self, f, Software),
602 AlternateServer::TYPE => display_attr!(self, f, AlternateServer),
603 Fingerprint::TYPE => display_attr!(self, f, Fingerprint),
604 _ => {
605 #[cfg(feature = "std")]
606 {
607 let mut display_impls = ATTRIBUTE_EXTERNAL_DISPLAY_IMPL
608 .get_or_init(|| Default::default())
609 .lock()
610 .unwrap();
611 if let Some(imp) = display_impls.get_mut(&self.get_type()) {
612 return imp(self, f);
613 }
614 }
615 write!(
616 f,
617 "RawAttribute (type: {:?}, len: {}, data: {:?})",
618 self.header.get_type(),
619 self.header.length(),
620 &self.value
621 )
622 }
623 }
624 }
625}
626
627impl<'a> RawAttribute<'a> {
628 pub fn new(atype: AttributeType, data: &'a [u8]) -> Self {
630 Self {
631 header: AttributeHeader {
632 atype,
633 length: data.len() as u16,
634 },
635 value: data.into(),
636 }
637 }
638
639 pub fn new_owned(atype: AttributeType, data: Box<[u8]>) -> Self {
641 Self {
642 header: AttributeHeader {
643 atype,
644 length: data.len() as u16,
645 },
646 value: data.into(),
647 }
648 }
649
650 pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
662 let header = AttributeHeader::parse(data)?;
663 if header.length() > (data.len() - 4) as u16 {
665 return Err(StunParseError::Truncated {
666 expected: header.length() as usize,
667 actual: data.len() - 4,
668 });
669 }
670 Ok(Self {
671 header,
672 value: Data::Borrowed(data[4..header.length() as usize + 4].into()),
673 })
674 }
675
676 pub fn to_bytes(&self) -> Vec<u8> {
686 let mut vec = Vec::with_capacity(self.padded_len());
687 let mut header_bytes = [0; 4];
688 self.header.write_into(&mut header_bytes);
689 vec.extend(&header_bytes);
690 vec.extend(&*self.value);
691 let len = vec.len();
692 if len % 4 != 0 {
693 vec.resize(len + 4 - (len % 4), 0);
695 }
696 vec
697 }
698
699 pub fn check_type_and_len(
702 &self,
703 atype: AttributeType,
704 allowed_range: impl core::ops::RangeBounds<usize>,
705 ) -> Result<(), StunParseError> {
706 if self.header.get_type() != atype {
707 return Err(StunParseError::WrongAttributeImplementation);
708 }
709 check_len(self.value.len(), allowed_range)
710 }
711
712 pub fn into_owned<'b>(self) -> RawAttribute<'b> {
714 RawAttribute {
715 header: self.header,
716 value: self.value.into_owned(),
717 }
718 }
719}
720
721impl Attribute for RawAttribute<'_> {
722 fn get_type(&self) -> AttributeType {
724 self.header.get_type()
725 }
726
727 fn length(&self) -> u16 {
729 self.value.len() as u16
730 }
731}
732
733impl AttributeWrite for RawAttribute<'_> {
734 fn write_into_unchecked(&self, dest: &mut [u8]) {
738 let len = self.padded_len();
739 self.header.write_into(dest);
740 let mut offset = 4;
741 dest[offset..offset + self.value.len()].copy_from_slice(&self.value);
742 offset += self.value.len();
743 if len - offset > 0 {
744 dest[offset..len].fill(0);
745 }
746 }
747
748 fn to_raw(&self) -> RawAttribute<'_> {
749 self.clone()
750 }
751}
752
753impl<'a, A: AttributeWrite> From<&'a A> for RawAttribute<'a> {
754 fn from(value: &'a A) -> Self {
755 value.to_raw()
756 }
757}
758
759fn check_len(
760 len: usize,
761 allowed_range: impl core::ops::RangeBounds<usize>,
762) -> Result<(), StunParseError> {
763 match allowed_range.start_bound() {
764 core::ops::Bound::Unbounded => (),
765 core::ops::Bound::Included(start) => {
766 if len < *start {
767 return Err(StunParseError::Truncated {
768 expected: *start,
769 actual: len,
770 });
771 }
772 }
773 core::ops::Bound::Excluded(start) => {
774 if len <= *start {
775 return Err(StunParseError::Truncated {
776 expected: start + 1,
777 actual: len,
778 });
779 }
780 }
781 }
782 match allowed_range.end_bound() {
783 core::ops::Bound::Unbounded => (),
784 core::ops::Bound::Included(end) => {
785 if len > *end {
786 return Err(StunParseError::TooLarge {
787 expected: *end,
788 actual: len,
789 });
790 }
791 }
792 core::ops::Bound::Excluded(end) => {
793 if len >= *end {
794 return Err(StunParseError::TooLarge {
795 expected: *end - 1,
796 actual: len,
797 });
798 }
799 }
800 }
801 Ok(())
802}
803
804impl From<RawAttribute<'_>> for Vec<u8> {
805 fn from(f: RawAttribute) -> Self {
806 f.to_bytes()
807 }
808}
809
810#[cfg(test)]
811mod tests {
812 use super::*;
813
814 #[test]
815 fn attribute_type() {
816 let _log = crate::tests::test_init_log();
817 let atype = ErrorCode::TYPE;
818 let anum: u16 = atype.into();
819 assert_eq!(atype, anum.into());
820 }
821
822 #[test]
823 fn short_attribute_header() {
824 let _log = crate::tests::test_init_log();
825 let data = [0; 1];
826 let res: Result<AttributeHeader, _> = data.as_ref().try_into();
828 assert!(res.is_err());
829 }
830
831 #[test]
832 fn raw_attribute_construct() {
833 let _log = crate::tests::test_init_log();
834 let a = RawAttribute::new(1.into(), &[80, 160]);
835 assert_eq!(a.get_type(), 1.into());
836 let bytes: Vec<_> = a.into();
837 assert_eq!(bytes, &[0, 1, 0, 2, 80, 160, 0, 0]);
838 let b = RawAttribute::from_bytes(bytes.as_ref()).unwrap();
839 assert_eq!(b.get_type(), 1.into());
840 }
841
842 #[test]
843 fn raw_attribute_encoding() {
844 let mut out = [0; 8];
845 let mut out2 = [0; 8];
846 let _log = crate::tests::test_init_log();
847 let orig = RawAttribute::new(1.into(), &[80, 160]);
848 assert_eq!(orig.get_type(), 1.into());
849 orig.write_into(&mut out).unwrap();
850 orig.write_into_unchecked(&mut out2);
851 assert_eq!(out, out2);
852 let mut data: Vec<_> = orig.into();
853 let len = data.len();
854 BigEndian::write_u16(&mut data[2..4], len as u16 - 4 + 1);
856 assert!(matches!(
857 RawAttribute::from_bytes(data.as_ref()),
858 Err(StunParseError::Truncated {
859 expected: 5,
860 actual: 4
861 })
862 ));
863 }
864
865 #[test]
866 fn raw_attribute_header() {
867 let mut out = [0; 4];
868 let mut out2 = [0; 4];
869 let _log = crate::tests::test_init_log();
870 let orig = RawAttribute::new(1.into(), &[80, 160]);
871 assert!(matches!(orig.write_header(&mut out), Ok(4)));
872 assert_eq!(orig.write_header_unchecked(&mut out2), 4);
873 assert_eq!(out, out2);
874 assert_eq!(orig.header.to_bytes(), out);
875 assert_eq!(&orig.to_bytes()[..4], out);
876 let bytes: [_; 4] = orig.header.into();
877 assert_eq!(bytes, out);
878 }
879
880 #[test]
881 fn raw_attribute_write_into_small() {
882 let mut out = [0; 8];
883 let _log = crate::tests::test_init_log();
884 let orig = RawAttribute::new(1.into(), &[80, 160]);
885 assert_eq!(orig.get_type(), 1.into());
886 assert!(matches!(
887 orig.write_header(&mut out[..3]),
888 Err(StunWriteError::TooSmall {
889 expected: 4,
890 actual: 3,
891 })
892 ));
893 assert!(matches!(
894 orig.write_into(&mut out[..7]),
895 Err(StunWriteError::TooSmall {
896 expected: 8,
897 actual: 7,
898 })
899 ));
900 }
901
902 #[test]
903 fn test_check_len() {
904 let _log = crate::tests::test_init_log();
905 assert!(check_len(4, ..).is_ok());
906 assert!(check_len(4, 0..).is_ok());
907 assert!(check_len(4, 0..8).is_ok());
908 assert!(check_len(4, 0..=8).is_ok());
909 assert!(check_len(4, ..=8).is_ok());
910 assert!(matches!(
911 check_len(4, ..4),
912 Err(StunParseError::TooLarge {
913 expected: 3,
914 actual: 4
915 })
916 ));
917 assert!(matches!(
918 check_len(4, 5..),
919 Err(StunParseError::Truncated {
920 expected: 5,
921 actual: 4
922 })
923 ));
924 assert!(matches!(
925 check_len(4, ..=3),
926 Err(StunParseError::TooLarge {
927 expected: 3,
928 actual: 4
929 })
930 ));
931 assert!(matches!(
932 check_len(
933 4,
934 (core::ops::Bound::Excluded(4), core::ops::Bound::Unbounded)
935 ),
936 Err(StunParseError::Truncated {
937 expected: 5,
938 actual: 4
939 })
940 ));
941 }
942
943 #[test]
944 #[cfg(feature = "std")]
945 fn test_external_display_impl() {
946 use crate::message::TransactionId;
947
948 let _log = crate::tests::test_init_log();
949 let atype = AttributeType::new(0xFFFF);
950 assert_eq!(atype.name(), "unknown");
951 let data = [4, 0];
952 let attr = RawAttribute::new(atype, &data);
953 assert_eq!(
954 alloc::format!("{attr}"),
955 "RawAttribute (type: AttributeType(65535), len: 2, data: Borrowed(DataSlice([4, 0])))"
956 );
957 let imp = |attr: &RawAttribute<'_>,
958 f: &mut core::fmt::Formatter<'_>|
959 -> core::fmt::Result { write!(f, "Custom {}", attr.value[0]) };
960 add_display_impl(atype, imp);
961 let display_str = alloc::format!("{}", attr);
962 assert_eq!(display_str, "Custom 4");
963
964 atype.add_name("SOME-NAME");
965 assert_eq!(atype.name(), "SOME-NAME");
966
967 attribute_display!(Fingerprint);
968
969 let id = TransactionId::generate();
970 let xor_addr = XorMappedAddress::new("127.0.0.1:10000".parse().unwrap(), id);
971 let raw = xor_addr.to_raw();
972 let raw = RawAttribute::new(raw.get_type(), &raw.value[..3]);
973 assert_eq!(alloc::format!("{raw}"), "32(0x20: XOR-MAPPED-ADDRESS)(Malformed): len: 3, data: Borrowed(DataSlice([0, 1, 6])))");
974 }
975}