1use alloc::borrow::ToOwned;
10use alloc::string::String;
11use alloc::vec;
12use alloc::vec::Vec;
13use core::convert::TryFrom;
14
15use byteorder::{BigEndian, ByteOrder};
16
17use crate::message::{StunParseError, StunWriteError};
18
19use super::{
20 Attribute, AttributeExt, AttributeFromRaw, AttributeStaticType, AttributeType, AttributeWrite,
21 AttributeWriteExt, RawAttribute,
22};
23
24#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct ErrorCode {
27 code: u16,
28 reason: String,
29}
30impl AttributeStaticType for ErrorCode {
31 const TYPE: AttributeType = AttributeType(0x0009);
32}
33impl Attribute for ErrorCode {
34 fn get_type(&self) -> AttributeType {
35 Self::TYPE
36 }
37
38 fn length(&self) -> u16 {
39 self.reason.len() as u16 + 4
40 }
41}
42
43impl AttributeWrite for ErrorCode {
44 fn to_raw(&self) -> RawAttribute<'_> {
45 let mut data = Vec::with_capacity(self.length() as usize);
46 data.push(0u8);
47 data.push(0u8);
48 data.push((self.code / 100) as u8);
49 data.push((self.code % 100) as u8);
50 data.extend(self.reason.as_bytes());
51 RawAttribute::new_owned(ErrorCode::TYPE, data.into_boxed_slice())
52 }
53
54 fn write_into_unchecked(&self, dest: &mut [u8]) {
55 let len = self.padded_len();
56 let mut offset = self.write_header_unchecked(dest);
57 offset += self.write_into_data(&mut dest[offset..]);
58 if len - offset > 0 {
59 dest[offset..len].fill(0);
60 }
61 }
62}
63
64impl AttributeFromRaw<'_> for ErrorCode {
65 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
66 where
67 Self: Sized,
68 {
69 Self::try_from(raw)
70 }
71}
72
73impl TryFrom<&RawAttribute<'_>> for ErrorCode {
74 type Error = StunParseError;
75
76 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
77 raw.check_type_and_len(Self::TYPE, 4..=763 + 4)?;
78 let code_h = (raw.value[2] & 0x7) as u16;
79 let code_tens = raw.value[3] as u16;
80 if !(3..7).contains(&code_h) || code_tens > 99 {
81 return Err(StunParseError::InvalidAttributeData);
82 }
83 let code = code_h * 100 + code_tens;
84 Ok(Self {
85 code,
86 reason: core::str::from_utf8(&raw.value[4..])
87 .map_err(|_| StunParseError::InvalidAttributeData)?
88 .to_owned(),
89 })
90 }
91}
92
93#[derive(Debug)]
95pub struct ErrorCodeBuilder<'reason> {
96 code: u16,
97 reason: Option<&'reason str>,
98}
99
100impl<'reason> ErrorCodeBuilder<'reason> {
101 fn new(code: u16) -> Self {
102 Self { code, reason: None }
103 }
104
105 pub fn reason(mut self, reason: &'reason str) -> Self {
107 self.reason = Some(reason);
108 self
109 }
110
111 pub fn build(self) -> Result<ErrorCode, StunWriteError> {
117 if !(300..700).contains(&self.code) {
118 return Err(StunWriteError::OutOfRange {
119 value: self.code as usize,
120 min: 300,
121 max: 699,
122 });
123 }
124 let reason = self
125 .reason
126 .unwrap_or_else(|| ErrorCode::default_reason_for_code(self.code))
127 .to_owned();
128 Ok(ErrorCode {
129 code: self.code,
130 reason,
131 })
132 }
133}
134
135impl ErrorCode {
136 pub const TRY_ALTERNATE: u16 = 300;
141 pub const BAD_REQUEST: u16 = 400;
143 pub const UNAUTHORIZED: u16 = 401;
145 pub const FORBIDDEN: u16 = 403;
147 pub const UNKNOWN_ATTRIBUTE: u16 = 420;
150 pub const ALLOCATION_MISMATCH: u16 = 437;
152 pub const STALE_NONCE: u16 = 438;
154 pub const ADDRESS_FAMILY_NOT_SUPPORTED: u16 = 440;
156 pub const WRONG_CREDENTIALS: u16 = 441;
158 pub const UNSUPPORTED_TRANSPORT_PROTOCOL: u16 = 442;
160 pub const PEER_ADDRESS_FAMILY_MISMATCH: u16 = 443;
162 pub const CONNECTION_ALREADY_EXISTS: u16 = 446;
164 pub const CONNECTION_TIMEOUT_OR_FAILURE: u16 = 447;
166 pub const ALLOCATION_QUOTA_REACHED: u16 = 486;
168 pub const ROLE_CONFLICT: u16 = 487;
170 pub const SERVER_ERROR: u16 = 500;
172 pub const INSUFFICIENT_CAPACITY: u16 = 508;
174
175 pub fn builder<'reason>(code: u16) -> ErrorCodeBuilder<'reason> {
186 ErrorCodeBuilder::new(code)
187 }
188
189 pub fn new(code: u16, reason: &str) -> Result<Self, StunWriteError> {
204 if !(300..700).contains(&code) {
205 return Err(StunWriteError::OutOfRange {
206 value: code as usize,
207 min: 300,
208 max: 699,
209 });
210 }
211 Ok(Self {
212 code,
213 reason: reason.to_owned(),
214 })
215 }
216
217 pub fn code(&self) -> u16 {
227 self.code
228 }
229
230 pub fn reason(&self) -> &str {
240 &self.reason
241 }
242
243 pub fn default_reason_for_code(code: u16) -> &'static str {
268 match code {
269 Self::TRY_ALTERNATE => "Try Alternate",
270 Self::BAD_REQUEST => "Bad Request",
271 Self::UNAUTHORIZED => "Unauthorized",
272 Self::FORBIDDEN => "Forbidden",
273 Self::UNKNOWN_ATTRIBUTE => "Unknown Attribute",
274 Self::ALLOCATION_MISMATCH => "Allocation Mismatch",
275 Self::STALE_NONCE => "Stale Nonce",
276 Self::ADDRESS_FAMILY_NOT_SUPPORTED => "Address Family Not Supported",
277 Self::WRONG_CREDENTIALS => "Wrong Credentials",
278 Self::UNSUPPORTED_TRANSPORT_PROTOCOL => "Unsupported Transport Protocol",
279 Self::PEER_ADDRESS_FAMILY_MISMATCH => "Peer Address Family Mismatch",
280 Self::CONNECTION_ALREADY_EXISTS => "Connection Already Exists",
281 Self::CONNECTION_TIMEOUT_OR_FAILURE => "Connection Timeout or Failure",
282 Self::ALLOCATION_QUOTA_REACHED => "Allocation Quota Reached",
283 Self::ROLE_CONFLICT => "Role Conflict",
284 Self::SERVER_ERROR => "Server Error",
285 Self::INSUFFICIENT_CAPACITY => "Insufficient Capacity",
286 _ => "Unknown",
287 }
288 }
289
290 fn write_into_data(&self, dest: &mut [u8]) -> usize {
291 dest[0] = 0u8;
292 dest[1] = 0u8;
293 dest[2] = (self.code / 100) as u8;
294 dest[3] = (self.code % 100) as u8;
295 let bytes = self.reason.as_bytes();
296 dest[4..4 + bytes.len()].copy_from_slice(bytes);
297 4 + bytes.len()
298 }
299}
300
301impl core::fmt::Display for ErrorCode {
302 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
303 write!(f, "{}: {} '{}'", Self::TYPE, self.code, self.reason)
304 }
305}
306
307#[derive(Debug, Clone, PartialEq, Eq)]
309pub struct UnknownAttributes {
310 attributes: Vec<AttributeType>,
311}
312impl AttributeStaticType for UnknownAttributes {
313 const TYPE: AttributeType = AttributeType(0x000A);
314}
315impl Attribute for UnknownAttributes {
316 fn get_type(&self) -> AttributeType {
317 Self::TYPE
318 }
319 fn length(&self) -> u16 {
320 (self.attributes.len() as u16) * 2
321 }
322}
323impl AttributeWrite for UnknownAttributes {
324 fn to_raw(&self) -> RawAttribute<'_> {
325 let mut data = vec![0; self.length() as usize];
326 self.write_into_data(&mut data);
327 RawAttribute::new_owned(UnknownAttributes::TYPE, data.into_boxed_slice())
328 }
329
330 fn write_into_unchecked(&self, dest: &mut [u8]) {
331 let len = self.padded_len();
332 let mut offset = self.write_header_unchecked(dest);
333 offset += self.write_into_data(&mut dest[offset..]);
334 if len - offset > 0 {
335 dest[offset..len].fill(0);
336 }
337 }
338}
339
340impl AttributeFromRaw<'_> for UnknownAttributes {
341 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
342 where
343 Self: Sized,
344 {
345 Self::try_from(raw)
346 }
347}
348
349impl TryFrom<&RawAttribute<'_>> for UnknownAttributes {
350 type Error = StunParseError;
351
352 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
353 if raw.header.atype != Self::TYPE {
354 return Err(StunParseError::WrongAttributeImplementation);
355 }
356 if raw.value.len() % 2 != 0 {
357 return Err(StunParseError::Truncated {
359 expected: raw.value.len() + 1,
360 actual: raw.value.len(),
361 });
362 }
363 let mut attrs = vec![];
364 for attr in raw.value.chunks_exact(2) {
365 attrs.push(BigEndian::read_u16(attr).into());
366 }
367 Ok(Self { attributes: attrs })
368 }
369}
370impl UnknownAttributes {
371 pub fn new(attrs: &[AttributeType]) -> Self {
381 Self {
382 attributes: attrs.to_vec(),
383 }
384 }
385
386 pub fn add_attribute(&mut self, attr: AttributeType) {
397 if !self.has_attribute(attr) {
398 self.attributes.push(attr);
399 }
400 }
401
402 pub fn has_attribute(&self, attr: AttributeType) -> bool {
413 self.attributes.contains(&attr)
414 }
415
416 fn write_into_data(&self, dest: &mut [u8]) -> usize {
417 let mut offset = 0;
418 for attr in &self.attributes {
419 BigEndian::write_u16(&mut dest[offset..offset + 2], (*attr).into());
420 offset += 2;
421 }
422 offset
423 }
424}
425
426impl core::fmt::Display for UnknownAttributes {
427 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
428 write!(f, "{}: {:?}", Self::TYPE, self.attributes)
429 }
430}
431
432#[cfg(test)]
433mod tests {
434 use super::*;
435 use crate::attribute::{AlternateServer, Nonce, Realm};
436 use tracing::trace;
437
438 #[test]
439 fn error_code() {
440 let _log = crate::tests::test_init_log();
441 let codes = [
442 300, 301, 400, 401, 403, 420, 437, 438, 440, 441, 442, 443, 486, 487, 500, 508, 699,
443 ];
444 for code in codes.iter().copied() {
445 let reason = ErrorCode::default_reason_for_code(code);
446 let err = ErrorCode::new(code, reason).unwrap();
447 trace!("{err}");
448 assert_eq!(err.code(), code);
449 assert_eq!(err.reason(), reason);
450 let raw = RawAttribute::from(&err);
451 trace!("{raw}");
452 assert_eq!(raw.get_type(), ErrorCode::TYPE);
453 let err2 = ErrorCode::try_from(&raw).unwrap();
454 assert_eq!(err2.code(), code);
455 assert_eq!(err2.reason(), reason);
456
457 let mut dest = vec![0; raw.padded_len()];
458 err.write_into(&mut dest).unwrap();
459 let raw = RawAttribute::from_bytes(&dest).unwrap();
460 let err2 = ErrorCode::try_from(&raw).unwrap();
461 assert_eq!(err2.code(), code);
462 assert_eq!(err2.reason(), reason);
463 }
464 }
465
466 fn error_code_new(code: u16) -> ErrorCode {
467 let reason = ErrorCode::default_reason_for_code(code);
468 ErrorCode::new(code, reason).unwrap()
469 }
470
471 #[test]
472 fn error_code_parse_short() {
473 let _log = crate::tests::test_init_log();
474 let err = error_code_new(420);
475 let raw = RawAttribute::from(&err);
476 let mut data: Vec<_> = raw.into();
478 let len = 0;
479 BigEndian::write_u16(&mut data[2..4], len as u16);
480 assert!(matches!(
481 ErrorCode::try_from(&RawAttribute::from_bytes(data[..len + 4].as_ref()).unwrap()),
482 Err(StunParseError::Truncated {
483 expected: 4,
484 actual: 0
485 })
486 ));
487 }
488
489 #[test]
490 fn error_code_parse_wrong_implementation() {
491 let _log = crate::tests::test_init_log();
492 let err = error_code_new(420);
493 let raw = RawAttribute::from(&err);
494 let mut data: Vec<_> = raw.into();
496 BigEndian::write_u16(&mut data[0..2], 0);
497 assert!(matches!(
498 ErrorCode::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
499 Err(StunParseError::WrongAttributeImplementation)
500 ));
501 }
502
503 #[test]
504 fn error_code_parse_out_of_range_code() {
505 let _log = crate::tests::test_init_log();
506 let err = error_code_new(420);
507 let raw = RawAttribute::from(&err);
508 let mut data: Vec<_> = raw.into();
509
510 data[6] = 7;
512 assert!(matches!(
513 ErrorCode::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
514 Err(StunParseError::InvalidAttributeData)
515 ));
516 }
517
518 #[test]
519 fn error_code_parse_invalid_reason() {
520 let _log = crate::tests::test_init_log();
521 let err = error_code_new(420);
522 let raw = RawAttribute::from(&err);
523 let mut data: Vec<_> = raw.into();
524
525 data[10] = 0x88;
527 assert!(matches!(
528 ErrorCode::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
529 Err(StunParseError::InvalidAttributeData)
530 ));
531 }
532
533 #[test]
534 fn error_code_build_default_reason() {
535 let _log = crate::tests::test_init_log();
536 let err = ErrorCode::builder(420).build().unwrap();
537 assert_eq!(err.code(), 420);
538 assert!(err.reason().len() > 0);
539 }
540
541 #[test]
542 fn error_code_build_out_of_range() {
543 let _log = crate::tests::test_init_log();
544 assert!(matches!(
545 ErrorCode::builder(700).build(),
546 Err(StunWriteError::OutOfRange {
547 value: 700,
548 min: _,
549 max: _
550 })
551 ));
552 }
553
554 #[test]
555 fn error_code_new_out_of_range() {
556 let _log = crate::tests::test_init_log();
557 assert!(matches!(
558 ErrorCode::new(700, "some-reason"),
559 Err(StunWriteError::OutOfRange {
560 value: 700,
561 min: _,
562 max: _
563 })
564 ));
565 }
566
567 #[test]
568 fn unknown_attributes() {
569 let _log = crate::tests::test_init_log();
570 let mut unknown = UnknownAttributes::new(&[Realm::TYPE]);
571 unknown.add_attribute(AlternateServer::TYPE);
572 unknown.add_attribute(AlternateServer::TYPE);
574 trace!("{unknown}");
575 assert!(unknown.has_attribute(Realm::TYPE));
576 assert!(unknown.has_attribute(AlternateServer::TYPE));
577 assert!(!unknown.has_attribute(Nonce::TYPE));
578 let raw = RawAttribute::from(&unknown);
579 assert_eq!(raw.get_type(), UnknownAttributes::TYPE);
580 let unknown2 = UnknownAttributes::try_from(&raw).unwrap();
581 assert!(unknown2.has_attribute(Realm::TYPE));
582 assert!(unknown2.has_attribute(AlternateServer::TYPE));
583 assert!(!unknown2.has_attribute(Nonce::TYPE));
584 let mut data: Vec<_> = raw.clone().into();
586 let len = data.len();
587 BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
588 assert!(matches!(
589 UnknownAttributes::try_from(
590 &RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()
591 ),
592 Err(StunParseError::Truncated {
593 expected: 4,
594 actual: 3
595 })
596 ));
597 let mut data: Vec<_> = raw.clone().into();
599 BigEndian::write_u16(&mut data[0..2], 0);
600 assert!(matches!(
601 UnknownAttributes::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
602 Err(StunParseError::WrongAttributeImplementation)
603 ));
604
605 let mut dest = vec![0; raw.padded_len()];
606 unknown.write_into(&mut dest).unwrap();
607 tracing::error!("{dest:?}");
608 let raw = RawAttribute::from_bytes(&dest).unwrap();
609 let unknown2 = UnknownAttributes::try_from(&raw).unwrap();
610 assert!(unknown2.has_attribute(Realm::TYPE));
611 assert!(unknown2.has_attribute(AlternateServer::TYPE));
612 }
613}