1use std::convert::TryFrom;
10
11use byteorder::{BigEndian, ByteOrder};
12
13use crate::message::{StunParseError, StunWriteError};
14
15use super::{
16 Attribute, AttributeExt, AttributeFromRaw, AttributeStaticType, AttributeType, AttributeWrite,
17 AttributeWriteExt, RawAttribute,
18};
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct ErrorCode {
23 code: u16,
24 reason: String,
25}
26impl AttributeStaticType for ErrorCode {
27 const TYPE: AttributeType = AttributeType(0x0009);
28}
29impl Attribute for ErrorCode {
30 fn get_type(&self) -> AttributeType {
31 Self::TYPE
32 }
33
34 fn length(&self) -> u16 {
35 self.reason.len() as u16 + 4
36 }
37}
38
39impl AttributeWrite for ErrorCode {
40 fn to_raw(&self) -> RawAttribute<'_> {
41 let mut data = Vec::with_capacity(self.length() as usize);
42 data.push(0u8);
43 data.push(0u8);
44 data.push((self.code / 100) as u8);
45 data.push((self.code % 100) as u8);
46 data.extend(self.reason.as_bytes());
47 RawAttribute::new_owned(ErrorCode::TYPE, data.into_boxed_slice())
48 }
49
50 fn write_into_unchecked(&self, dest: &mut [u8]) {
51 let len = self.padded_len();
52 let mut offset = self.write_header_unchecked(dest);
53 offset += self.write_into_data(&mut dest[offset..]);
54 if len - offset > 0 {
55 dest[offset..len].fill(0);
56 }
57 }
58}
59
60impl AttributeFromRaw<'_> for ErrorCode {
61 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
62 where
63 Self: Sized,
64 {
65 Self::try_from(raw)
66 }
67}
68
69impl TryFrom<&RawAttribute<'_>> for ErrorCode {
70 type Error = StunParseError;
71
72 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
73 raw.check_type_and_len(Self::TYPE, 4..=763 + 4)?;
74 let code_h = (raw.value[2] & 0x7) as u16;
75 let code_tens = raw.value[3] as u16;
76 if !(3..7).contains(&code_h) || code_tens > 99 {
77 return Err(StunParseError::InvalidAttributeData);
78 }
79 let code = code_h * 100 + code_tens;
80 Ok(Self {
81 code,
82 reason: std::str::from_utf8(&raw.value[4..])
83 .map_err(|_| StunParseError::InvalidAttributeData)?
84 .to_owned(),
85 })
86 }
87}
88
89#[derive(Debug)]
91pub struct ErrorCodeBuilder<'reason> {
92 code: u16,
93 reason: Option<&'reason str>,
94}
95
96impl<'reason> ErrorCodeBuilder<'reason> {
97 fn new(code: u16) -> Self {
98 Self { code, reason: None }
99 }
100
101 pub fn reason(mut self, reason: &'reason str) -> Self {
103 self.reason = Some(reason);
104 self
105 }
106
107 pub fn build(self) -> Result<ErrorCode, StunWriteError> {
113 if !(300..700).contains(&self.code) {
114 return Err(StunWriteError::OutOfRange {
115 value: self.code as usize,
116 min: 300,
117 max: 699,
118 });
119 }
120 let reason = self
121 .reason
122 .unwrap_or_else(|| ErrorCode::default_reason_for_code(self.code))
123 .to_owned();
124 Ok(ErrorCode {
125 code: self.code,
126 reason,
127 })
128 }
129}
130
131impl ErrorCode {
132 pub const TRY_ALTERNATE: u16 = 301;
137 pub const BAD_REQUEST: u16 = 400;
139 pub const UNAUTHORIZED: u16 = 401;
141 pub const FORBIDDEN: u16 = 403;
143 pub const UNKNOWN_ATTRIBUTE: u16 = 420;
146 pub const ALLOCATION_MISMATCH: u16 = 437;
148 pub const STALE_NONCE: u16 = 438;
150 pub const ADDRESS_FAMILY_NOT_SUPPORTED: u16 = 440;
152 pub const WRONG_CREDENTIALS: u16 = 441;
154 pub const UNSUPPORTED_TRANSPORT_PROTOCOL: u16 = 442;
156 pub const PEER_ADDRESS_FAMILY_MISMATCH: u16 = 443;
158 pub const ALLOCATION_QUOTA_REACHED: u16 = 486;
160 pub const ROLE_CONFLICT: u16 = 487;
162 pub const SERVER_ERROR: u16 = 500;
164 pub const INSUFFICIENT_CAPACITY: u16 = 508;
166
167 pub fn builder<'reason>(code: u16) -> ErrorCodeBuilder<'reason> {
178 ErrorCodeBuilder::new(code)
179 }
180
181 pub fn new(code: u16, reason: &str) -> Result<Self, StunWriteError> {
196 if !(300..700).contains(&code) {
197 return Err(StunWriteError::OutOfRange {
198 value: code as usize,
199 min: 300,
200 max: 699,
201 });
202 }
203 Ok(Self {
204 code,
205 reason: reason.to_owned(),
206 })
207 }
208
209 pub fn code(&self) -> u16 {
219 self.code
220 }
221
222 pub fn reason(&self) -> &str {
232 &self.reason
233 }
234
235 pub fn default_reason_for_code(code: u16) -> &'static str {
255 match code {
256 Self::TRY_ALTERNATE => "Try Alternate",
257 Self::BAD_REQUEST => "Bad Request",
258 Self::UNAUTHORIZED => "Unauthorized",
259 Self::FORBIDDEN => "Forbidden",
260 Self::UNKNOWN_ATTRIBUTE => "Unknown Attribute",
261 Self::ALLOCATION_MISMATCH => "Allocation Mismatch",
262 Self::STALE_NONCE => "Stale Nonce",
263 Self::ADDRESS_FAMILY_NOT_SUPPORTED => "Address Family Not Supported",
264 Self::WRONG_CREDENTIALS => "Wrong Credentials",
265 Self::UNSUPPORTED_TRANSPORT_PROTOCOL => "Unsupported Transport Protocol",
266 Self::PEER_ADDRESS_FAMILY_MISMATCH => "Peer Address Family Mismatch",
267 Self::ALLOCATION_QUOTA_REACHED => "Allocation Quota Reached",
268 Self::ROLE_CONFLICT => "Role Conflict",
269 Self::SERVER_ERROR => "Server Error",
270 Self::INSUFFICIENT_CAPACITY => "Insufficient Capacity",
271 _ => "Unknown",
272 }
273 }
274
275 fn write_into_data(&self, dest: &mut [u8]) -> usize {
276 dest[0] = 0u8;
277 dest[1] = 0u8;
278 dest[2] = (self.code / 100) as u8;
279 dest[3] = (self.code % 100) as u8;
280 let bytes = self.reason.as_bytes();
281 dest[4..4 + bytes.len()].copy_from_slice(bytes);
282 4 + bytes.len()
283 }
284}
285
286impl std::fmt::Display for ErrorCode {
287 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
288 write!(f, "{}: {} '{}'", Self::TYPE, self.code, self.reason)
289 }
290}
291
292#[derive(Debug, Clone, PartialEq, Eq)]
294pub struct UnknownAttributes {
295 attributes: Vec<AttributeType>,
296}
297impl AttributeStaticType for UnknownAttributes {
298 const TYPE: AttributeType = AttributeType(0x000A);
299}
300impl Attribute for UnknownAttributes {
301 fn get_type(&self) -> AttributeType {
302 Self::TYPE
303 }
304 fn length(&self) -> u16 {
305 (self.attributes.len() as u16) * 2
306 }
307}
308impl AttributeWrite for UnknownAttributes {
309 fn to_raw(&self) -> RawAttribute<'_> {
310 let mut data = vec![0; self.length() as usize];
311 self.write_into_data(&mut data);
312 RawAttribute::new_owned(UnknownAttributes::TYPE, data.into_boxed_slice())
313 }
314
315 fn write_into_unchecked(&self, dest: &mut [u8]) {
316 let len = self.padded_len();
317 let mut offset = self.write_header_unchecked(dest);
318 offset += self.write_into_data(&mut dest[offset..]);
319 if len - offset > 0 {
320 dest[offset..len].fill(0);
321 }
322 }
323}
324
325impl AttributeFromRaw<'_> for UnknownAttributes {
326 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
327 where
328 Self: Sized,
329 {
330 Self::try_from(raw)
331 }
332}
333
334impl TryFrom<&RawAttribute<'_>> for UnknownAttributes {
335 type Error = StunParseError;
336
337 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
338 if raw.header.atype != Self::TYPE {
339 return Err(StunParseError::WrongAttributeImplementation);
340 }
341 if raw.value.len() % 2 != 0 {
342 return Err(StunParseError::Truncated {
344 expected: raw.value.len() + 1,
345 actual: raw.value.len(),
346 });
347 }
348 let mut attrs = vec![];
349 for attr in raw.value.chunks_exact(2) {
350 attrs.push(BigEndian::read_u16(attr).into());
351 }
352 Ok(Self { attributes: attrs })
353 }
354}
355impl UnknownAttributes {
356 pub fn new(attrs: &[AttributeType]) -> Self {
366 Self {
367 attributes: attrs.to_vec(),
368 }
369 }
370
371 pub fn add_attribute(&mut self, attr: AttributeType) {
382 if !self.has_attribute(attr) {
383 self.attributes.push(attr);
384 }
385 }
386
387 pub fn has_attribute(&self, attr: AttributeType) -> bool {
398 self.attributes.contains(&attr)
399 }
400
401 fn write_into_data(&self, dest: &mut [u8]) -> usize {
402 let mut offset = 0;
403 for attr in &self.attributes {
404 BigEndian::write_u16(&mut dest[offset..offset + 2], (*attr).into());
405 offset += 2;
406 }
407 offset
408 }
409}
410
411impl std::fmt::Display for UnknownAttributes {
412 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
413 write!(f, "{}: {:?}", Self::TYPE, self.attributes)
414 }
415}
416
417#[cfg(test)]
418mod tests {
419 use super::*;
420 use crate::attribute::{AlternateServer, Nonce, Realm};
421 use tracing::trace;
422
423 #[test]
424 fn error_code() {
425 let _log = crate::tests::test_init_log();
426 let codes = [
427 300, 301, 400, 401, 403, 420, 437, 438, 440, 441, 442, 443, 486, 487, 500, 508, 699,
428 ];
429 for code in codes.iter().copied() {
430 let reason = ErrorCode::default_reason_for_code(code);
431 let err = ErrorCode::new(code, reason).unwrap();
432 trace!("{err}");
433 assert_eq!(err.code(), code);
434 assert_eq!(err.reason(), reason);
435 let raw = RawAttribute::from(&err);
436 trace!("{raw}");
437 assert_eq!(raw.get_type(), ErrorCode::TYPE);
438 let err2 = ErrorCode::try_from(&raw).unwrap();
439 assert_eq!(err2.code(), code);
440 assert_eq!(err2.reason(), reason);
441
442 let mut dest = vec![0; raw.padded_len()];
443 err.write_into(&mut dest).unwrap();
444 let raw = RawAttribute::from_bytes(&dest).unwrap();
445 let err2 = ErrorCode::try_from(&raw).unwrap();
446 assert_eq!(err2.code(), code);
447 assert_eq!(err2.reason(), reason);
448 }
449 }
450
451 fn error_code_new(code: u16) -> ErrorCode {
452 let reason = ErrorCode::default_reason_for_code(code);
453 ErrorCode::new(code, reason).unwrap()
454 }
455
456 #[test]
457 fn error_code_parse_short() {
458 let _log = crate::tests::test_init_log();
459 let err = error_code_new(420);
460 let raw = RawAttribute::from(&err);
461 let mut data: Vec<_> = raw.into();
463 let len = 0;
464 BigEndian::write_u16(&mut data[2..4], len as u16);
465 assert!(matches!(
466 ErrorCode::try_from(&RawAttribute::from_bytes(data[..len + 4].as_ref()).unwrap()),
467 Err(StunParseError::Truncated {
468 expected: 4,
469 actual: 0
470 })
471 ));
472 }
473
474 #[test]
475 fn error_code_parse_wrong_implementation() {
476 let _log = crate::tests::test_init_log();
477 let err = error_code_new(420);
478 let raw = RawAttribute::from(&err);
479 let mut data: Vec<_> = raw.into();
481 BigEndian::write_u16(&mut data[0..2], 0);
482 assert!(matches!(
483 ErrorCode::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
484 Err(StunParseError::WrongAttributeImplementation)
485 ));
486 }
487
488 #[test]
489 fn error_code_parse_out_of_range_code() {
490 let _log = crate::tests::test_init_log();
491 let err = error_code_new(420);
492 let raw = RawAttribute::from(&err);
493 let mut data: Vec<_> = raw.into();
494
495 data[6] = 7;
497 assert!(matches!(
498 ErrorCode::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
499 Err(StunParseError::InvalidAttributeData)
500 ));
501 }
502
503 #[test]
504 fn error_code_parse_invalid_reason() {
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[10] = 0x88;
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_build_default_reason() {
520 let _log = crate::tests::test_init_log();
521 let err = ErrorCode::builder(420).build().unwrap();
522 assert_eq!(err.code(), 420);
523 assert!(err.reason().len() > 0);
524 }
525
526 #[test]
527 fn error_code_build_out_of_range() {
528 let _log = crate::tests::test_init_log();
529 assert!(matches!(
530 ErrorCode::builder(700).build(),
531 Err(StunWriteError::OutOfRange {
532 value: 700,
533 min: _,
534 max: _
535 })
536 ));
537 }
538
539 #[test]
540 fn error_code_new_out_of_range() {
541 let _log = crate::tests::test_init_log();
542 assert!(matches!(
543 ErrorCode::new(700, "some-reason"),
544 Err(StunWriteError::OutOfRange {
545 value: 700,
546 min: _,
547 max: _
548 })
549 ));
550 }
551
552 #[test]
553 fn unknown_attributes() {
554 let _log = crate::tests::test_init_log();
555 let mut unknown = UnknownAttributes::new(&[Realm::TYPE]);
556 unknown.add_attribute(AlternateServer::TYPE);
557 unknown.add_attribute(AlternateServer::TYPE);
559 trace!("{unknown}");
560 assert!(unknown.has_attribute(Realm::TYPE));
561 assert!(unknown.has_attribute(AlternateServer::TYPE));
562 assert!(!unknown.has_attribute(Nonce::TYPE));
563 let raw = RawAttribute::from(&unknown);
564 assert_eq!(raw.get_type(), UnknownAttributes::TYPE);
565 let unknown2 = UnknownAttributes::try_from(&raw).unwrap();
566 assert!(unknown2.has_attribute(Realm::TYPE));
567 assert!(unknown2.has_attribute(AlternateServer::TYPE));
568 assert!(!unknown2.has_attribute(Nonce::TYPE));
569 let mut data: Vec<_> = raw.clone().into();
571 let len = data.len();
572 BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
573 assert!(matches!(
574 UnknownAttributes::try_from(
575 &RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()
576 ),
577 Err(StunParseError::Truncated {
578 expected: 4,
579 actual: 3
580 })
581 ));
582 let mut data: Vec<_> = raw.clone().into();
584 BigEndian::write_u16(&mut data[0..2], 0);
585 assert!(matches!(
586 UnknownAttributes::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
587 Err(StunParseError::WrongAttributeImplementation)
588 ));
589
590 let mut dest = vec![0; raw.padded_len()];
591 unknown.write_into(&mut dest).unwrap();
592 tracing::error!("{dest:?}");
593 let raw = RawAttribute::from_bytes(&dest).unwrap();
594 let unknown2 = UnknownAttributes::try_from(&raw).unwrap();
595 assert!(unknown2.has_attribute(Realm::TYPE));
596 assert!(unknown2.has_attribute(AlternateServer::TYPE));
597 }
598}