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 {
397 self.attributes.iter().any(|&a| a == attr)
398 }
399
400 fn write_into_data(&self, dest: &mut [u8]) -> usize {
401 let mut offset = 0;
402 for attr in &self.attributes {
403 BigEndian::write_u16(&mut dest[offset..offset + 2], (*attr).into());
404 offset += 2;
405 }
406 offset
407 }
408}
409
410impl std::fmt::Display for UnknownAttributes {
411 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
412 write!(f, "{}: {:?}", Self::TYPE, self.attributes)
413 }
414}
415
416#[cfg(test)]
417mod tests {
418 use super::*;
419 use crate::attribute::{AlternateServer, Nonce, Realm};
420 use tracing::trace;
421
422 #[test]
423 fn error_code() {
424 let _log = crate::tests::test_init_log();
425 let codes = [
426 300, 301, 400, 401, 403, 420, 437, 438, 440, 441, 442, 443, 486, 487, 500, 508, 699,
427 ];
428 for code in codes.iter().copied() {
429 let reason = ErrorCode::default_reason_for_code(code);
430 let err = ErrorCode::new(code, reason).unwrap();
431 trace!("{err}");
432 assert_eq!(err.code(), code);
433 assert_eq!(err.reason(), reason);
434 let raw = RawAttribute::from(&err);
435 trace!("{raw}");
436 assert_eq!(raw.get_type(), ErrorCode::TYPE);
437 let err2 = ErrorCode::try_from(&raw).unwrap();
438 assert_eq!(err2.code(), code);
439 assert_eq!(err2.reason(), reason);
440
441 let mut dest = vec![0; raw.padded_len()];
442 err.write_into(&mut dest).unwrap();
443 let raw = RawAttribute::from_bytes(&dest).unwrap();
444 let err2 = ErrorCode::try_from(&raw).unwrap();
445 assert_eq!(err2.code(), code);
446 assert_eq!(err2.reason(), reason);
447 }
448 }
449
450 fn error_code_new(code: u16) -> ErrorCode {
451 let reason = ErrorCode::default_reason_for_code(code);
452 ErrorCode::new(code, reason).unwrap()
453 }
454
455 #[test]
456 fn error_code_parse_short() {
457 let _log = crate::tests::test_init_log();
458 let err = error_code_new(420);
459 let raw = RawAttribute::from(&err);
460 let mut data: Vec<_> = raw.into();
462 let len = 0;
463 BigEndian::write_u16(&mut data[2..4], len as u16);
464 assert!(matches!(
465 ErrorCode::try_from(&RawAttribute::from_bytes(data[..len + 4].as_ref()).unwrap()),
466 Err(StunParseError::Truncated {
467 expected: 4,
468 actual: 0
469 })
470 ));
471 }
472
473 #[test]
474 fn error_code_parse_wrong_implementation() {
475 let _log = crate::tests::test_init_log();
476 let err = error_code_new(420);
477 let raw = RawAttribute::from(&err);
478 let mut data: Vec<_> = raw.into();
480 BigEndian::write_u16(&mut data[0..2], 0);
481 assert!(matches!(
482 ErrorCode::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
483 Err(StunParseError::WrongAttributeImplementation)
484 ));
485 }
486
487 #[test]
488 fn error_code_parse_out_of_range_code() {
489 let _log = crate::tests::test_init_log();
490 let err = error_code_new(420);
491 let raw = RawAttribute::from(&err);
492 let mut data: Vec<_> = raw.into();
493
494 data[6] = 7;
496 assert!(matches!(
497 ErrorCode::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
498 Err(StunParseError::InvalidAttributeData)
499 ));
500 }
501
502 #[test]
503 fn error_code_parse_invalid_reason() {
504 let _log = crate::tests::test_init_log();
505 let err = error_code_new(420);
506 let raw = RawAttribute::from(&err);
507 let mut data: Vec<_> = raw.into();
508
509 data[10] = 0x88;
511 assert!(matches!(
512 ErrorCode::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
513 Err(StunParseError::InvalidAttributeData)
514 ));
515 }
516
517 #[test]
518 fn error_code_build_default_reason() {
519 let _log = crate::tests::test_init_log();
520 let err = ErrorCode::builder(420).build().unwrap();
521 assert_eq!(err.code(), 420);
522 assert!(err.reason().len() > 0);
523 }
524
525 #[test]
526 fn error_code_build_out_of_range() {
527 let _log = crate::tests::test_init_log();
528 assert!(matches!(
529 ErrorCode::builder(700).build(),
530 Err(StunWriteError::OutOfRange {
531 value: 700,
532 min: _,
533 max: _
534 })
535 ));
536 }
537
538 #[test]
539 fn error_code_new_out_of_range() {
540 let _log = crate::tests::test_init_log();
541 assert!(matches!(
542 ErrorCode::new(700, "some-reason"),
543 Err(StunWriteError::OutOfRange {
544 value: 700,
545 min: _,
546 max: _
547 })
548 ));
549 }
550
551 #[test]
552 fn unknown_attributes() {
553 let _log = crate::tests::test_init_log();
554 let mut unknown = UnknownAttributes::new(&[Realm::TYPE]);
555 unknown.add_attribute(AlternateServer::TYPE);
556 unknown.add_attribute(AlternateServer::TYPE);
558 trace!("{unknown}");
559 assert!(unknown.has_attribute(Realm::TYPE));
560 assert!(unknown.has_attribute(AlternateServer::TYPE));
561 assert!(!unknown.has_attribute(Nonce::TYPE));
562 let raw = RawAttribute::from(&unknown);
563 assert_eq!(raw.get_type(), UnknownAttributes::TYPE);
564 let unknown2 = UnknownAttributes::try_from(&raw).unwrap();
565 assert!(unknown2.has_attribute(Realm::TYPE));
566 assert!(unknown2.has_attribute(AlternateServer::TYPE));
567 assert!(!unknown2.has_attribute(Nonce::TYPE));
568 let mut data: Vec<_> = raw.clone().into();
570 let len = data.len();
571 BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
572 assert!(matches!(
573 UnknownAttributes::try_from(
574 &RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()
575 ),
576 Err(StunParseError::Truncated {
577 expected: 4,
578 actual: 3
579 })
580 ));
581 let mut data: Vec<_> = raw.clone().into();
583 BigEndian::write_u16(&mut data[0..2], 0);
584 assert!(matches!(
585 UnknownAttributes::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
586 Err(StunParseError::WrongAttributeImplementation)
587 ));
588
589 let mut dest = vec![0; raw.padded_len()];
590 unknown.write_into(&mut dest).unwrap();
591 tracing::error!("{dest:?}");
592 let raw = RawAttribute::from_bytes(&dest).unwrap();
593 let unknown2 = UnknownAttributes::try_from(&raw).unwrap();
594 assert!(unknown2.has_attribute(Realm::TYPE));
595 assert!(unknown2.has_attribute(AlternateServer::TYPE));
596 }
597}