1use crate::models::rpki::rtr::*;
30use crate::models::Asn;
31use std::fmt;
32use std::io::{self, Read};
33use std::net::{Ipv4Addr, Ipv6Addr};
34
35#[derive(Debug)]
41pub enum RtrError {
42 IoError(io::Error),
44 IncompletePdu {
46 available: usize,
48 needed: usize,
50 },
51 InvalidPduType(u8),
53 InvalidProtocolVersion(u8),
55 InvalidErrorCode(u16),
57 InvalidLength {
59 expected: u32,
61 actual: u32,
63 pdu_type: u8,
65 },
66 InvalidPrefixLength {
68 prefix_len: u8,
70 max_len: u8,
72 max_allowed: u8,
74 },
75 InvalidUtf8,
77 RouterKeyInV0,
79}
80
81impl fmt::Display for RtrError {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 match self {
84 RtrError::IoError(e) => write!(f, "I/O error: {}", e),
85 RtrError::IncompletePdu { available, needed } => {
86 write!(
87 f,
88 "Incomplete PDU: have {} bytes, need {} bytes",
89 available, needed
90 )
91 }
92 RtrError::InvalidPduType(t) => write!(f, "Invalid PDU type: {}", t),
93 RtrError::InvalidProtocolVersion(v) => write!(f, "Invalid protocol version: {}", v),
94 RtrError::InvalidErrorCode(c) => write!(f, "Invalid error code: {}", c),
95 RtrError::InvalidLength {
96 expected,
97 actual,
98 pdu_type,
99 } => {
100 write!(
101 f,
102 "Invalid length for PDU type {}: expected {}, got {}",
103 pdu_type, expected, actual
104 )
105 }
106 RtrError::InvalidPrefixLength {
107 prefix_len,
108 max_len,
109 max_allowed,
110 } => {
111 write!(
112 f,
113 "Invalid prefix length: prefix_len={}, max_len={}, max_allowed={}",
114 prefix_len, max_len, max_allowed
115 )
116 }
117 RtrError::InvalidUtf8 => write!(f, "Invalid UTF-8 in error text"),
118 RtrError::RouterKeyInV0 => write!(f, "Router Key PDU is not valid in RTR v0"),
119 }
120 }
121}
122
123impl std::error::Error for RtrError {
124 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
125 match self {
126 RtrError::IoError(e) => Some(e),
127 _ => None,
128 }
129 }
130}
131
132impl From<io::Error> for RtrError {
133 fn from(e: io::Error) -> Self {
134 RtrError::IoError(e)
135 }
136}
137
138pub const RTR_HEADER_LEN: usize = 8;
144
145pub const RTR_SERIAL_NOTIFY_LEN: u32 = 12;
147
148pub const RTR_SERIAL_QUERY_LEN: u32 = 12;
150
151pub const RTR_RESET_QUERY_LEN: u32 = 8;
153
154pub const RTR_CACHE_RESPONSE_LEN: u32 = 8;
156
157pub const RTR_IPV4_PREFIX_LEN: u32 = 20;
159
160pub const RTR_IPV6_PREFIX_LEN: u32 = 32;
162
163pub const RTR_END_OF_DATA_V0_LEN: u32 = 12;
165
166pub const RTR_END_OF_DATA_V1_LEN: u32 = 24;
168
169pub const RTR_CACHE_RESET_LEN: u32 = 8;
171
172pub const RTR_ROUTER_KEY_MIN_LEN: u32 = 34;
174
175pub const RTR_MAX_PDU_LEN: usize = 65_535;
185
186pub const RTR_MAX_ERROR_REPORT_LEN: usize = 8 + 4 + RTR_MAX_PDU_LEN + 4 + RTR_MAX_PDU_LEN;
198
199pub fn parse_rtr_pdu(input: &[u8]) -> Result<(RtrPdu, usize), RtrError> {
225 if input.len() < RTR_HEADER_LEN {
227 return Err(RtrError::IncompletePdu {
228 available: input.len(),
229 needed: RTR_HEADER_LEN,
230 });
231 }
232
233 let version_byte = input[0];
235 let pdu_type_byte = input[1];
236 let session_or_error = u16::from_be_bytes([input[2], input[3]]);
237 let length = u32::from_be_bytes([input[4], input[5], input[6], input[7]]);
238
239 let length_usize = length as usize;
241 if input.len() < length_usize {
242 return Err(RtrError::IncompletePdu {
243 available: input.len(),
244 needed: length_usize,
245 });
246 }
247
248 let version = RtrProtocolVersion::from_u8(version_byte)
250 .ok_or(RtrError::InvalidProtocolVersion(version_byte))?;
251
252 let pdu_type =
254 RtrPduType::from_u8(pdu_type_byte).ok_or(RtrError::InvalidPduType(pdu_type_byte))?;
255
256 let pdu = match pdu_type {
258 RtrPduType::SerialNotify => {
259 validate_length(length, RTR_SERIAL_NOTIFY_LEN, pdu_type_byte)?;
260 let serial_number = u32::from_be_bytes([input[8], input[9], input[10], input[11]]);
261 RtrPdu::SerialNotify(RtrSerialNotify {
262 version,
263 session_id: session_or_error,
264 serial_number,
265 })
266 }
267
268 RtrPduType::SerialQuery => {
269 validate_length(length, RTR_SERIAL_QUERY_LEN, pdu_type_byte)?;
270 let serial_number = u32::from_be_bytes([input[8], input[9], input[10], input[11]]);
271 RtrPdu::SerialQuery(RtrSerialQuery {
272 version,
273 session_id: session_or_error,
274 serial_number,
275 })
276 }
277
278 RtrPduType::ResetQuery => {
279 validate_length(length, RTR_RESET_QUERY_LEN, pdu_type_byte)?;
280 RtrPdu::ResetQuery(RtrResetQuery { version })
281 }
282
283 RtrPduType::CacheResponse => {
284 validate_length(length, RTR_CACHE_RESPONSE_LEN, pdu_type_byte)?;
285 RtrPdu::CacheResponse(RtrCacheResponse {
286 version,
287 session_id: session_or_error,
288 })
289 }
290
291 RtrPduType::IPv4Prefix => {
292 validate_length(length, RTR_IPV4_PREFIX_LEN, pdu_type_byte)?;
293 let flags = input[8];
294 let prefix_length = input[9];
295 let max_length = input[10];
296 validate_prefix_length(prefix_length, max_length, 32)?;
299
300 let prefix = Ipv4Addr::new(input[12], input[13], input[14], input[15]);
301 let asn = u32::from_be_bytes([input[16], input[17], input[18], input[19]]);
302
303 RtrPdu::IPv4Prefix(RtrIPv4Prefix {
304 version,
305 flags,
306 prefix_length,
307 max_length,
308 prefix,
309 asn: Asn::from(asn),
310 })
311 }
312
313 RtrPduType::IPv6Prefix => {
314 validate_length(length, RTR_IPV6_PREFIX_LEN, pdu_type_byte)?;
315 let flags = input[8];
316 let prefix_length = input[9];
317 let max_length = input[10];
318 validate_prefix_length(prefix_length, max_length, 128)?;
321
322 let prefix = Ipv6Addr::from([
323 input[12], input[13], input[14], input[15], input[16], input[17], input[18],
324 input[19], input[20], input[21], input[22], input[23], input[24], input[25],
325 input[26], input[27],
326 ]);
327 let asn = u32::from_be_bytes([input[28], input[29], input[30], input[31]]);
328
329 RtrPdu::IPv6Prefix(RtrIPv6Prefix {
330 version,
331 flags,
332 prefix_length,
333 max_length,
334 prefix,
335 asn: Asn::from(asn),
336 })
337 }
338
339 RtrPduType::EndOfData => {
340 let expected_len = match version {
341 RtrProtocolVersion::V0 => RTR_END_OF_DATA_V0_LEN,
342 RtrProtocolVersion::V1 => RTR_END_OF_DATA_V1_LEN,
343 };
344 validate_length(length, expected_len, pdu_type_byte)?;
345
346 let serial_number = u32::from_be_bytes([input[8], input[9], input[10], input[11]]);
347
348 let (refresh_interval, retry_interval, expire_interval) = match version {
349 RtrProtocolVersion::V0 => (None, None, None),
350 RtrProtocolVersion::V1 => {
351 let refresh = u32::from_be_bytes([input[12], input[13], input[14], input[15]]);
352 let retry = u32::from_be_bytes([input[16], input[17], input[18], input[19]]);
353 let expire = u32::from_be_bytes([input[20], input[21], input[22], input[23]]);
354 (Some(refresh), Some(retry), Some(expire))
355 }
356 };
357
358 RtrPdu::EndOfData(RtrEndOfData {
359 version,
360 session_id: session_or_error,
361 serial_number,
362 refresh_interval,
363 retry_interval,
364 expire_interval,
365 })
366 }
367
368 RtrPduType::CacheReset => {
369 validate_length(length, RTR_CACHE_RESET_LEN, pdu_type_byte)?;
370 RtrPdu::CacheReset(RtrCacheReset { version })
371 }
372
373 RtrPduType::RouterKey => {
374 if version == RtrProtocolVersion::V0 {
376 return Err(RtrError::RouterKeyInV0);
377 }
378
379 if length < RTR_ROUTER_KEY_MIN_LEN {
380 return Err(RtrError::InvalidLength {
381 expected: RTR_ROUTER_KEY_MIN_LEN,
382 actual: length,
383 pdu_type: pdu_type_byte,
384 });
385 }
386
387 let flags = input[8];
388 let mut ski = [0u8; 20];
390 ski.copy_from_slice(&input[10..30]);
391 let asn = u32::from_be_bytes([input[30], input[31], input[32], input[33]]);
392
393 let spki_len = (length as usize) - 34;
395 let spki = if spki_len > 0 {
396 input[34..34 + spki_len].to_vec()
397 } else {
398 Vec::new()
399 };
400
401 RtrPdu::RouterKey(RtrRouterKey {
402 version,
403 flags,
404 subject_key_identifier: ski,
405 asn: Asn::from(asn),
406 subject_public_key_info: spki,
407 })
408 }
409
410 RtrPduType::ErrorReport => {
411 if length < 16 {
414 return Err(RtrError::InvalidLength {
415 expected: 16,
416 actual: length,
417 pdu_type: pdu_type_byte,
418 });
419 }
420
421 let error_code = RtrErrorCode::from_u16(session_or_error)
422 .ok_or(RtrError::InvalidErrorCode(session_or_error))?;
423
424 let encap_pdu_len =
425 u32::from_be_bytes([input[8], input[9], input[10], input[11]]) as usize;
426
427 if encap_pdu_len > length_usize - 16 {
432 return Err(RtrError::InvalidLength {
433 expected: u32::try_from(encap_pdu_len.saturating_add(16)).unwrap_or(u32::MAX),
434 actual: length,
435 pdu_type: pdu_type_byte,
436 });
437 }
438
439 let erroneous_pdu = if encap_pdu_len > 0 {
440 input[12..12 + encap_pdu_len].to_vec()
441 } else {
442 Vec::new()
443 };
444
445 let error_text_len_offset = 12 + encap_pdu_len;
446 let error_text_len = u32::from_be_bytes([
447 input[error_text_len_offset],
448 input[error_text_len_offset + 1],
449 input[error_text_len_offset + 2],
450 input[error_text_len_offset + 3],
451 ]) as usize;
452
453 let error_text_offset = error_text_len_offset + 4;
454
455 if error_text_len > length_usize - error_text_offset {
463 return Err(RtrError::InvalidLength {
464 expected: u32::try_from(error_text_offset.saturating_add(error_text_len))
465 .unwrap_or(u32::MAX),
466 actual: length,
467 pdu_type: pdu_type_byte,
468 });
469 }
470
471 let error_text = if error_text_len > 0 {
472 std::str::from_utf8(&input[error_text_offset..error_text_offset + error_text_len])
473 .map_err(|_| RtrError::InvalidUtf8)?
474 .to_string()
475 } else {
476 String::new()
477 };
478
479 RtrPdu::ErrorReport(RtrErrorReport {
480 version,
481 error_code,
482 erroneous_pdu,
483 error_text,
484 })
485 }
486 };
487
488 Ok((pdu, length_usize))
489}
490
491pub fn read_rtr_pdu<R: Read>(reader: &mut R) -> Result<RtrPdu, RtrError> {
509 let mut header = [0u8; RTR_HEADER_LEN];
511 reader.read_exact(&mut header)?;
512
513 let length = u32::from_be_bytes([header[4], header[5], header[6], header[7]]) as usize;
515
516 if length < RTR_HEADER_LEN {
517 return Err(RtrError::InvalidLength {
518 expected: RTR_HEADER_LEN as u32,
519 actual: length as u32,
520 pdu_type: header[1],
521 });
522 }
523
524 if length > RTR_MAX_ERROR_REPORT_LEN {
527 return Err(RtrError::InvalidLength {
528 expected: RTR_MAX_ERROR_REPORT_LEN as u32,
529 actual: length as u32,
530 pdu_type: header[1],
531 });
532 }
533
534 let mut buffer = vec![0u8; length];
536 buffer[..RTR_HEADER_LEN].copy_from_slice(&header);
537
538 if length > RTR_HEADER_LEN {
540 reader.read_exact(&mut buffer[RTR_HEADER_LEN..])?;
541 }
542
543 let (pdu, _) = parse_rtr_pdu(&buffer)?;
545 Ok(pdu)
546}
547
548fn validate_length(actual: u32, expected: u32, pdu_type: u8) -> Result<(), RtrError> {
549 if actual != expected {
550 Err(RtrError::InvalidLength {
551 expected,
552 actual,
553 pdu_type,
554 })
555 } else {
556 Ok(())
557 }
558}
559
560fn validate_prefix_length(prefix_len: u8, max_len: u8, max_allowed: u8) -> Result<(), RtrError> {
561 if prefix_len > max_len || max_len > max_allowed {
562 Err(RtrError::InvalidPrefixLength {
563 prefix_len,
564 max_len,
565 max_allowed,
566 })
567 } else {
568 Ok(())
569 }
570}
571
572pub trait RtrEncode {
578 fn encode(&self) -> Vec<u8>;
580}
581
582impl RtrEncode for RtrSerialNotify {
583 fn encode(&self) -> Vec<u8> {
584 let mut buf = Vec::with_capacity(RTR_SERIAL_NOTIFY_LEN as usize);
585 buf.push(self.version.to_u8());
586 buf.push(RtrPduType::SerialNotify.to_u8());
587 buf.extend_from_slice(&self.session_id.to_be_bytes());
588 buf.extend_from_slice(&RTR_SERIAL_NOTIFY_LEN.to_be_bytes());
589 buf.extend_from_slice(&self.serial_number.to_be_bytes());
590 buf
591 }
592}
593
594impl RtrEncode for RtrSerialQuery {
595 fn encode(&self) -> Vec<u8> {
596 let mut buf = Vec::with_capacity(RTR_SERIAL_QUERY_LEN as usize);
597 buf.push(self.version.to_u8());
598 buf.push(RtrPduType::SerialQuery.to_u8());
599 buf.extend_from_slice(&self.session_id.to_be_bytes());
600 buf.extend_from_slice(&RTR_SERIAL_QUERY_LEN.to_be_bytes());
601 buf.extend_from_slice(&self.serial_number.to_be_bytes());
602 buf
603 }
604}
605
606impl RtrEncode for RtrResetQuery {
607 fn encode(&self) -> Vec<u8> {
608 let mut buf = Vec::with_capacity(RTR_RESET_QUERY_LEN as usize);
609 buf.push(self.version.to_u8());
610 buf.push(RtrPduType::ResetQuery.to_u8());
611 buf.extend_from_slice(&[0, 0]); buf.extend_from_slice(&RTR_RESET_QUERY_LEN.to_be_bytes());
613 buf
614 }
615}
616
617impl RtrEncode for RtrCacheResponse {
618 fn encode(&self) -> Vec<u8> {
619 let mut buf = Vec::with_capacity(RTR_CACHE_RESPONSE_LEN as usize);
620 buf.push(self.version.to_u8());
621 buf.push(RtrPduType::CacheResponse.to_u8());
622 buf.extend_from_slice(&self.session_id.to_be_bytes());
623 buf.extend_from_slice(&RTR_CACHE_RESPONSE_LEN.to_be_bytes());
624 buf
625 }
626}
627
628impl RtrEncode for RtrIPv4Prefix {
629 fn encode(&self) -> Vec<u8> {
630 let mut buf = Vec::with_capacity(RTR_IPV4_PREFIX_LEN as usize);
631 buf.push(self.version.to_u8());
632 buf.push(RtrPduType::IPv4Prefix.to_u8());
633 buf.extend_from_slice(&[0, 0]); buf.extend_from_slice(&RTR_IPV4_PREFIX_LEN.to_be_bytes());
635 buf.push(self.flags);
636 buf.push(self.prefix_length);
637 buf.push(self.max_length);
638 buf.push(0); buf.extend_from_slice(&self.prefix.octets());
640 buf.extend_from_slice(&self.asn.to_u32().to_be_bytes());
641 buf
642 }
643}
644
645impl RtrEncode for RtrIPv6Prefix {
646 fn encode(&self) -> Vec<u8> {
647 let mut buf = Vec::with_capacity(RTR_IPV6_PREFIX_LEN as usize);
648 buf.push(self.version.to_u8());
649 buf.push(RtrPduType::IPv6Prefix.to_u8());
650 buf.extend_from_slice(&[0, 0]); buf.extend_from_slice(&RTR_IPV6_PREFIX_LEN.to_be_bytes());
652 buf.push(self.flags);
653 buf.push(self.prefix_length);
654 buf.push(self.max_length);
655 buf.push(0); buf.extend_from_slice(&self.prefix.octets());
657 buf.extend_from_slice(&self.asn.to_u32().to_be_bytes());
658 buf
659 }
660}
661
662impl RtrEncode for RtrEndOfData {
663 fn encode(&self) -> Vec<u8> {
664 let length = match self.version {
665 RtrProtocolVersion::V0 => RTR_END_OF_DATA_V0_LEN,
666 RtrProtocolVersion::V1 => RTR_END_OF_DATA_V1_LEN,
667 };
668 let mut buf = Vec::with_capacity(length as usize);
669 buf.push(self.version.to_u8());
670 buf.push(RtrPduType::EndOfData.to_u8());
671 buf.extend_from_slice(&self.session_id.to_be_bytes());
672 buf.extend_from_slice(&length.to_be_bytes());
673 buf.extend_from_slice(&self.serial_number.to_be_bytes());
674
675 if self.version == RtrProtocolVersion::V1 {
676 buf.extend_from_slice(
677 &self
678 .refresh_interval
679 .unwrap_or(RtrEndOfData::DEFAULT_REFRESH)
680 .to_be_bytes(),
681 );
682 buf.extend_from_slice(
683 &self
684 .retry_interval
685 .unwrap_or(RtrEndOfData::DEFAULT_RETRY)
686 .to_be_bytes(),
687 );
688 buf.extend_from_slice(
689 &self
690 .expire_interval
691 .unwrap_or(RtrEndOfData::DEFAULT_EXPIRE)
692 .to_be_bytes(),
693 );
694 }
695 buf
696 }
697}
698
699impl RtrEncode for RtrCacheReset {
700 fn encode(&self) -> Vec<u8> {
701 let mut buf = Vec::with_capacity(RTR_CACHE_RESET_LEN as usize);
702 buf.push(self.version.to_u8());
703 buf.push(RtrPduType::CacheReset.to_u8());
704 buf.extend_from_slice(&[0, 0]); buf.extend_from_slice(&RTR_CACHE_RESET_LEN.to_be_bytes());
706 buf
707 }
708}
709
710impl RtrEncode for RtrRouterKey {
711 fn encode(&self) -> Vec<u8> {
712 let length = RTR_ROUTER_KEY_MIN_LEN + self.subject_public_key_info.len() as u32;
713 let mut buf = Vec::with_capacity(length as usize);
714 buf.push(self.version.to_u8());
715 buf.push(RtrPduType::RouterKey.to_u8());
716 buf.extend_from_slice(&[0, 0]); buf.extend_from_slice(&length.to_be_bytes());
718 buf.push(self.flags);
719 buf.push(0); buf.extend_from_slice(&self.subject_key_identifier);
721 buf.extend_from_slice(&self.asn.to_u32().to_be_bytes());
722 buf.extend_from_slice(&self.subject_public_key_info);
723 buf
724 }
725}
726
727impl RtrEncode for RtrErrorReport {
728 fn encode(&self) -> Vec<u8> {
729 let error_text_bytes = self.error_text.as_bytes();
730 let length = 16 + self.erroneous_pdu.len() + error_text_bytes.len();
731 let mut buf = Vec::with_capacity(length);
732 buf.push(self.version.to_u8());
733 buf.push(RtrPduType::ErrorReport.to_u8());
734 buf.extend_from_slice(&self.error_code.to_u16().to_be_bytes());
735 buf.extend_from_slice(&(length as u32).to_be_bytes());
736 buf.extend_from_slice(&(self.erroneous_pdu.len() as u32).to_be_bytes());
737 buf.extend_from_slice(&self.erroneous_pdu);
738 buf.extend_from_slice(&(error_text_bytes.len() as u32).to_be_bytes());
739 buf.extend_from_slice(error_text_bytes);
740 buf
741 }
742}
743
744impl RtrEncode for RtrPdu {
745 fn encode(&self) -> Vec<u8> {
746 match self {
747 RtrPdu::SerialNotify(p) => p.encode(),
748 RtrPdu::SerialQuery(p) => p.encode(),
749 RtrPdu::ResetQuery(p) => p.encode(),
750 RtrPdu::CacheResponse(p) => p.encode(),
751 RtrPdu::IPv4Prefix(p) => p.encode(),
752 RtrPdu::IPv6Prefix(p) => p.encode(),
753 RtrPdu::EndOfData(p) => p.encode(),
754 RtrPdu::CacheReset(p) => p.encode(),
755 RtrPdu::RouterKey(p) => p.encode(),
756 RtrPdu::ErrorReport(p) => p.encode(),
757 }
758 }
759}
760
761#[cfg(test)]
766mod tests {
767 use super::*;
768
769 #[test]
770 fn test_reset_query_roundtrip() {
771 let query = RtrResetQuery::new_v1();
772 let bytes = query.encode();
773 assert_eq!(bytes.len(), 8);
774
775 let (pdu, consumed) = parse_rtr_pdu(&bytes).unwrap();
776 assert_eq!(consumed, 8);
777 assert!(matches!(pdu, RtrPdu::ResetQuery(q) if q.version == RtrProtocolVersion::V1));
778 }
779
780 #[test]
781 fn test_reset_query_v0_roundtrip() {
782 let query = RtrResetQuery::new_v0();
783 let bytes = query.encode();
784
785 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
786 assert!(matches!(pdu, RtrPdu::ResetQuery(q) if q.version == RtrProtocolVersion::V0));
787 }
788
789 #[test]
790 fn test_serial_query_roundtrip() {
791 let query = RtrSerialQuery::new(RtrProtocolVersion::V1, 12345, 67890);
792 let bytes = query.encode();
793 assert_eq!(bytes.len(), 12);
794
795 let (pdu, consumed) = parse_rtr_pdu(&bytes).unwrap();
796 assert_eq!(consumed, 12);
797 match pdu {
798 RtrPdu::SerialQuery(q) => {
799 assert_eq!(q.session_id, 12345);
800 assert_eq!(q.serial_number, 67890);
801 }
802 _ => panic!("Expected SerialQuery"),
803 }
804 }
805
806 #[test]
807 fn test_serial_notify_roundtrip() {
808 let notify = RtrSerialNotify {
809 version: RtrProtocolVersion::V1,
810 session_id: 100,
811 serial_number: 200,
812 };
813 let bytes = notify.encode();
814
815 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
816 match pdu {
817 RtrPdu::SerialNotify(n) => {
818 assert_eq!(n.session_id, 100);
819 assert_eq!(n.serial_number, 200);
820 }
821 _ => panic!("Expected SerialNotify"),
822 }
823 }
824
825 #[test]
826 fn test_cache_response_roundtrip() {
827 let response = RtrCacheResponse {
828 version: RtrProtocolVersion::V1,
829 session_id: 42,
830 };
831 let bytes = response.encode();
832
833 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
834 match pdu {
835 RtrPdu::CacheResponse(r) => {
836 assert_eq!(r.session_id, 42);
837 }
838 _ => panic!("Expected CacheResponse"),
839 }
840 }
841
842 #[test]
843 fn test_ipv4_prefix_roundtrip() {
844 let prefix = RtrIPv4Prefix {
845 version: RtrProtocolVersion::V1,
846 flags: 1,
847 prefix_length: 24,
848 max_length: 24,
849 prefix: Ipv4Addr::new(192, 0, 2, 0),
850 asn: Asn::from(65001u32),
851 };
852 let bytes = prefix.encode();
853 assert_eq!(bytes.len(), 20);
854
855 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
856 match pdu {
857 RtrPdu::IPv4Prefix(p) => {
858 assert!(p.is_announcement());
859 assert_eq!(p.prefix_length, 24);
860 assert_eq!(p.max_length, 24);
861 assert_eq!(p.prefix, Ipv4Addr::new(192, 0, 2, 0));
862 assert_eq!(p.asn.to_u32(), 65001);
863 }
864 _ => panic!("Expected IPv4Prefix"),
865 }
866 }
867
868 #[test]
869 fn test_ipv4_prefix_withdrawal() {
870 let prefix = RtrIPv4Prefix {
871 version: RtrProtocolVersion::V1,
872 flags: 0, prefix_length: 24,
874 max_length: 24,
875 prefix: Ipv4Addr::new(192, 0, 2, 0),
876 asn: Asn::from(65001u32),
877 };
878 let bytes = prefix.encode();
879
880 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
881 match pdu {
882 RtrPdu::IPv4Prefix(p) => {
883 assert!(p.is_withdrawal());
884 assert!(!p.is_announcement());
885 }
886 _ => panic!("Expected IPv4Prefix"),
887 }
888 }
889
890 #[test]
891 fn test_ipv6_prefix_roundtrip() {
892 let prefix = RtrIPv6Prefix {
893 version: RtrProtocolVersion::V1,
894 flags: 1,
895 prefix_length: 48,
896 max_length: 64,
897 prefix: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
898 asn: Asn::from(65002u32),
899 };
900 let bytes = prefix.encode();
901 assert_eq!(bytes.len(), 32);
902
903 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
904 match pdu {
905 RtrPdu::IPv6Prefix(p) => {
906 assert!(p.is_announcement());
907 assert_eq!(p.prefix_length, 48);
908 assert_eq!(p.max_length, 64);
909 assert_eq!(p.prefix, Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0));
910 assert_eq!(p.asn.to_u32(), 65002);
911 }
912 _ => panic!("Expected IPv6Prefix"),
913 }
914 }
915
916 #[test]
917 fn test_end_of_data_v0_roundtrip() {
918 let eod = RtrEndOfData {
919 version: RtrProtocolVersion::V0,
920 session_id: 100,
921 serial_number: 200,
922 refresh_interval: None,
923 retry_interval: None,
924 expire_interval: None,
925 };
926 let bytes = eod.encode();
927 assert_eq!(bytes.len(), 12);
928
929 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
930 match pdu {
931 RtrPdu::EndOfData(e) => {
932 assert_eq!(e.version, RtrProtocolVersion::V0);
933 assert_eq!(e.session_id, 100);
934 assert_eq!(e.serial_number, 200);
935 assert_eq!(e.refresh_interval, None);
936 assert_eq!(e.retry_interval, None);
937 assert_eq!(e.expire_interval, None);
938 }
939 _ => panic!("Expected EndOfData"),
940 }
941 }
942
943 #[test]
944 fn test_end_of_data_v1_roundtrip() {
945 let eod = RtrEndOfData {
946 version: RtrProtocolVersion::V1,
947 session_id: 100,
948 serial_number: 200,
949 refresh_interval: Some(1800),
950 retry_interval: Some(300),
951 expire_interval: Some(3600),
952 };
953 let bytes = eod.encode();
954 assert_eq!(bytes.len(), 24);
955
956 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
957 match pdu {
958 RtrPdu::EndOfData(e) => {
959 assert_eq!(e.version, RtrProtocolVersion::V1);
960 assert_eq!(e.refresh_interval, Some(1800));
961 assert_eq!(e.retry_interval, Some(300));
962 assert_eq!(e.expire_interval, Some(3600));
963 }
964 _ => panic!("Expected EndOfData"),
965 }
966 }
967
968 #[test]
969 fn test_end_of_data_v1_with_defaults() {
970 let eod = RtrEndOfData {
971 version: RtrProtocolVersion::V1,
972 session_id: 100,
973 serial_number: 200,
974 refresh_interval: None, retry_interval: None,
976 expire_interval: None,
977 };
978 let bytes = eod.encode();
979 assert_eq!(bytes.len(), 24);
980
981 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
982 match pdu {
983 RtrPdu::EndOfData(e) => {
984 assert_eq!(e.refresh_interval, Some(3600));
986 assert_eq!(e.retry_interval, Some(600));
987 assert_eq!(e.expire_interval, Some(7200));
988 }
989 _ => panic!("Expected EndOfData"),
990 }
991 }
992
993 #[test]
994 fn test_cache_reset_roundtrip() {
995 let reset = RtrCacheReset {
996 version: RtrProtocolVersion::V1,
997 };
998 let bytes = reset.encode();
999 assert_eq!(bytes.len(), 8);
1000
1001 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
1002 assert!(matches!(pdu, RtrPdu::CacheReset(_)));
1003 }
1004
1005 #[test]
1006 fn test_router_key_roundtrip() {
1007 let key = RtrRouterKey {
1008 version: RtrProtocolVersion::V1,
1009 flags: 1,
1010 subject_key_identifier: [
1011 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
1012 ],
1013 asn: Asn::from(65003u32),
1014 subject_public_key_info: vec![0xAB, 0xCD, 0xEF],
1015 };
1016 let bytes = key.encode();
1017 assert_eq!(bytes.len(), 37); let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
1020 match pdu {
1021 RtrPdu::RouterKey(k) => {
1022 assert!(k.is_announcement());
1023 assert_eq!(k.subject_key_identifier[0], 1);
1024 assert_eq!(k.subject_key_identifier[19], 20);
1025 assert_eq!(k.asn.to_u32(), 65003);
1026 assert_eq!(k.subject_public_key_info, vec![0xAB, 0xCD, 0xEF]);
1027 }
1028 _ => panic!("Expected RouterKey"),
1029 }
1030 }
1031
1032 #[test]
1033 fn test_router_key_in_v0_error() {
1034 let mut bytes = vec![
1036 0, 9, 0, 0, 0, 0, 0, 34, 1, 0, ];
1043 bytes.extend_from_slice(&[0u8; 20]); bytes.extend_from_slice(&[0, 0, 0, 1]); let result = parse_rtr_pdu(&bytes);
1047 assert!(matches!(result, Err(RtrError::RouterKeyInV0)));
1048 }
1049
1050 #[test]
1051 fn test_error_report_roundtrip() {
1052 let error = RtrErrorReport {
1053 version: RtrProtocolVersion::V1,
1054 error_code: RtrErrorCode::UnsupportedProtocolVersion,
1055 erroneous_pdu: vec![99, 2, 0, 0, 0, 0, 0, 8], error_text: "Test error".to_string(),
1057 };
1058 let bytes = error.encode();
1059
1060 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
1061 match pdu {
1062 RtrPdu::ErrorReport(e) => {
1063 assert_eq!(e.error_code, RtrErrorCode::UnsupportedProtocolVersion);
1064 assert_eq!(e.erroneous_pdu, vec![99, 2, 0, 0, 0, 0, 0, 8]);
1065 assert_eq!(e.error_text, "Test error");
1066 }
1067 _ => panic!("Expected ErrorReport"),
1068 }
1069 }
1070
1071 #[test]
1072 fn test_error_report_empty() {
1073 let error = RtrErrorReport {
1074 version: RtrProtocolVersion::V1,
1075 error_code: RtrErrorCode::InternalError,
1076 erroneous_pdu: vec![],
1077 error_text: String::new(),
1078 };
1079 let bytes = error.encode();
1080 assert_eq!(bytes.len(), 16);
1081
1082 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
1083 match pdu {
1084 RtrPdu::ErrorReport(e) => {
1085 assert_eq!(e.error_code, RtrErrorCode::InternalError);
1086 assert!(e.erroneous_pdu.is_empty());
1087 assert!(e.error_text.is_empty());
1088 }
1089 _ => panic!("Expected ErrorReport"),
1090 }
1091 }
1092
1093 #[test]
1094 fn test_incomplete_pdu_error() {
1095 let bytes = [1, 2, 0]; let result = parse_rtr_pdu(&bytes);
1097 assert!(matches!(result, Err(RtrError::IncompletePdu { .. })));
1098 }
1099
1100 #[test]
1101 fn test_invalid_pdu_type_error() {
1102 let bytes = [1, 5, 0, 0, 0, 0, 0, 8]; let result = parse_rtr_pdu(&bytes);
1104 assert!(matches!(result, Err(RtrError::InvalidPduType(5))));
1105 }
1106
1107 #[test]
1108 fn test_invalid_protocol_version_error() {
1109 let bytes = [99, 2, 0, 0, 0, 0, 0, 8]; let result = parse_rtr_pdu(&bytes);
1111 assert!(matches!(result, Err(RtrError::InvalidProtocolVersion(99))));
1112 }
1113
1114 #[test]
1115 fn test_invalid_length_error() {
1116 let bytes = [1, 2, 0, 0, 0, 0, 0, 10, 0, 0]; let result = parse_rtr_pdu(&bytes);
1119 assert!(matches!(result, Err(RtrError::InvalidLength { .. })));
1120 }
1121
1122 #[test]
1123 fn test_invalid_prefix_length_error() {
1124 let mut bytes = vec![
1126 1, 4, 0, 0, 0, 0, 0, 20, 1, 25, 24, 0, ];
1135 bytes.extend_from_slice(&[192, 0, 2, 0]); bytes.extend_from_slice(&[0, 0, 0, 1]); let result = parse_rtr_pdu(&bytes);
1139 assert!(matches!(result, Err(RtrError::InvalidPrefixLength { .. })));
1140 }
1141
1142 #[test]
1143 fn test_invalid_max_length_error() {
1144 let mut bytes = vec![
1146 1, 4, 0, 0, 0, 0, 0, 20, 1, 24, 33, 0, ];
1155 bytes.extend_from_slice(&[192, 0, 2, 0]); bytes.extend_from_slice(&[0, 0, 0, 1]); let result = parse_rtr_pdu(&bytes);
1159 assert!(matches!(result, Err(RtrError::InvalidPrefixLength { .. })));
1160 }
1161
1162 #[test]
1163 fn test_read_rtr_pdu_from_cursor() {
1164 use std::io::Cursor;
1165
1166 let query = RtrResetQuery::new_v1();
1167 let bytes = query.encode();
1168 let mut cursor = Cursor::new(bytes);
1169
1170 let pdu = read_rtr_pdu(&mut cursor).unwrap();
1171 assert!(matches!(pdu, RtrPdu::ResetQuery(_)));
1172 }
1173
1174 #[test]
1175 fn test_pdu_enum_encode() {
1176 let pdu = RtrPdu::ResetQuery(RtrResetQuery::new_v1());
1177 let bytes = pdu.encode();
1178 assert_eq!(bytes.len(), 8);
1179
1180 let (parsed, _) = parse_rtr_pdu(&bytes).unwrap();
1181 assert!(matches!(parsed, RtrPdu::ResetQuery(_)));
1182 }
1183
1184 #[test]
1185 fn test_all_pdu_types_roundtrip() {
1186 let pdus: Vec<RtrPdu> = vec![
1188 RtrPdu::SerialNotify(RtrSerialNotify {
1189 version: RtrProtocolVersion::V1,
1190 session_id: 1,
1191 serial_number: 100,
1192 }),
1193 RtrPdu::SerialQuery(RtrSerialQuery::new(RtrProtocolVersion::V1, 1, 100)),
1194 RtrPdu::ResetQuery(RtrResetQuery::new_v1()),
1195 RtrPdu::CacheResponse(RtrCacheResponse {
1196 version: RtrProtocolVersion::V1,
1197 session_id: 1,
1198 }),
1199 RtrPdu::IPv4Prefix(RtrIPv4Prefix {
1200 version: RtrProtocolVersion::V1,
1201 flags: 1,
1202 prefix_length: 24,
1203 max_length: 24,
1204 prefix: Ipv4Addr::new(10, 0, 0, 0),
1205 asn: Asn::from(65000u32),
1206 }),
1207 RtrPdu::IPv6Prefix(RtrIPv6Prefix {
1208 version: RtrProtocolVersion::V1,
1209 flags: 1,
1210 prefix_length: 48,
1211 max_length: 48,
1212 prefix: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
1213 asn: Asn::from(65000u32),
1214 }),
1215 RtrPdu::EndOfData(RtrEndOfData {
1216 version: RtrProtocolVersion::V1,
1217 session_id: 1,
1218 serial_number: 100,
1219 refresh_interval: Some(3600),
1220 retry_interval: Some(600),
1221 expire_interval: Some(7200),
1222 }),
1223 RtrPdu::CacheReset(RtrCacheReset {
1224 version: RtrProtocolVersion::V1,
1225 }),
1226 RtrPdu::RouterKey(RtrRouterKey {
1227 version: RtrProtocolVersion::V1,
1228 flags: 1,
1229 subject_key_identifier: [0; 20],
1230 asn: Asn::from(65000u32),
1231 subject_public_key_info: vec![1, 2, 3, 4],
1232 }),
1233 RtrPdu::ErrorReport(RtrErrorReport {
1234 version: RtrProtocolVersion::V1,
1235 error_code: RtrErrorCode::NoDataAvailable,
1236 erroneous_pdu: vec![],
1237 error_text: "No data".to_string(),
1238 }),
1239 ];
1240
1241 for original in pdus {
1242 let bytes = original.encode();
1243 let (parsed, consumed) = parse_rtr_pdu(&bytes).unwrap();
1244 assert_eq!(consumed, bytes.len());
1245 assert_eq!(parsed.pdu_type(), original.pdu_type());
1246 }
1247 }
1248
1249 #[test]
1250 fn test_error_display() {
1251 let err = RtrError::InvalidPduType(42);
1252 assert!(err.to_string().contains("42"));
1253
1254 let err = RtrError::IncompletePdu {
1255 available: 4,
1256 needed: 8,
1257 };
1258 assert!(err.to_string().contains("4"));
1259 assert!(err.to_string().contains("8"));
1260 }
1261
1262 #[test]
1263 fn test_error_display_all_variants() {
1264 let io_err = RtrError::IoError(std::io::Error::new(
1266 std::io::ErrorKind::ConnectionReset,
1267 "connection reset",
1268 ));
1269 assert!(io_err.to_string().contains("I/O error"));
1270
1271 let incomplete = RtrError::IncompletePdu {
1272 available: 5,
1273 needed: 10,
1274 };
1275 assert!(incomplete.to_string().contains("Incomplete PDU"));
1276 assert!(incomplete.to_string().contains("5"));
1277 assert!(incomplete.to_string().contains("10"));
1278
1279 let invalid_type = RtrError::InvalidPduType(99);
1280 assert!(invalid_type.to_string().contains("Invalid PDU type"));
1281 assert!(invalid_type.to_string().contains("99"));
1282
1283 let invalid_version = RtrError::InvalidProtocolVersion(5);
1284 assert!(invalid_version
1285 .to_string()
1286 .contains("Invalid protocol version"));
1287 assert!(invalid_version.to_string().contains("5"));
1288
1289 let invalid_error_code = RtrError::InvalidErrorCode(100);
1290 assert!(invalid_error_code
1291 .to_string()
1292 .contains("Invalid error code"));
1293 assert!(invalid_error_code.to_string().contains("100"));
1294
1295 let invalid_length = RtrError::InvalidLength {
1296 expected: 20,
1297 actual: 15,
1298 pdu_type: 4,
1299 };
1300 assert!(invalid_length.to_string().contains("Invalid length"));
1301 assert!(invalid_length.to_string().contains("20"));
1302 assert!(invalid_length.to_string().contains("15"));
1303 assert!(invalid_length.to_string().contains("4"));
1304
1305 let invalid_prefix = RtrError::InvalidPrefixLength {
1306 prefix_len: 25,
1307 max_len: 24,
1308 max_allowed: 32,
1309 };
1310 assert!(invalid_prefix.to_string().contains("Invalid prefix length"));
1311 assert!(invalid_prefix.to_string().contains("25"));
1312 assert!(invalid_prefix.to_string().contains("24"));
1313 assert!(invalid_prefix.to_string().contains("32"));
1314
1315 let invalid_utf8 = RtrError::InvalidUtf8;
1316 assert!(invalid_utf8.to_string().contains("Invalid UTF-8"));
1317
1318 let router_key_v0 = RtrError::RouterKeyInV0;
1319 assert!(router_key_v0.to_string().contains("Router Key PDU"));
1320 assert!(router_key_v0.to_string().contains("v0"));
1321 }
1322
1323 #[test]
1324 fn test_error_source() {
1325 use std::error::Error;
1326
1327 let io_err = RtrError::IoError(std::io::Error::new(
1329 std::io::ErrorKind::NotFound,
1330 "file not found",
1331 ));
1332 assert!(io_err.source().is_some());
1333
1334 let incomplete = RtrError::IncompletePdu {
1336 available: 1,
1337 needed: 2,
1338 };
1339 assert!(incomplete.source().is_none());
1340
1341 let invalid_type = RtrError::InvalidPduType(5);
1342 assert!(invalid_type.source().is_none());
1343
1344 let invalid_utf8 = RtrError::InvalidUtf8;
1345 assert!(invalid_utf8.source().is_none());
1346 }
1347
1348 #[test]
1349 fn test_error_from_io_error() {
1350 let io_err = std::io::Error::new(std::io::ErrorKind::TimedOut, "timeout");
1351 let rtr_err: RtrError = io_err.into();
1352 assert!(matches!(rtr_err, RtrError::IoError(_)));
1353 }
1354
1355 #[test]
1356 fn test_read_rtr_pdu_short_length() {
1357 use std::io::Cursor;
1358
1359 let bytes = vec![
1361 1, 2, 0, 0, 0, 0, 0, 4, ];
1366 let mut cursor = Cursor::new(bytes);
1367 let result = read_rtr_pdu(&mut cursor);
1368 assert!(matches!(result, Err(RtrError::InvalidLength { .. })));
1369 }
1370
1371 #[test]
1372 fn test_parse_invalid_error_code() {
1373 let bytes = vec![
1375 1, 10, 0, 100, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, ];
1382 let result = parse_rtr_pdu(&bytes);
1383 assert!(matches!(result, Err(RtrError::InvalidErrorCode(100))));
1384 }
1385
1386 #[test]
1387 fn test_parse_error_report_invalid_utf8() {
1388 let bytes = vec![
1390 1, 10, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 4, 0xFF, 0xFE, 0xFF, 0xFE, ];
1398 let result = parse_rtr_pdu(&bytes);
1399 assert!(matches!(result, Err(RtrError::InvalidUtf8)));
1400 }
1401
1402 #[test]
1403 fn test_parse_error_report_truncated() {
1404 let bytes = vec![
1406 1, 10, 0, 0, 0, 0, 0, 16, 0, 0, 0, 100, 0, 0, 0, 0, ];
1413 let result = parse_rtr_pdu(&bytes);
1414 assert!(matches!(result, Err(RtrError::InvalidLength { .. })));
1415 }
1416
1417 #[test]
1418 fn test_parse_router_key_empty_spki() {
1419 let mut bytes = vec![
1421 1, 9, 0, 0, 0, 0, 0, 34, 1, 0, ];
1428 bytes.extend_from_slice(&[0u8; 20]); bytes.extend_from_slice(&[0, 0, 0, 1]); let (pdu, consumed) = parse_rtr_pdu(&bytes).unwrap();
1432 assert_eq!(consumed, 34);
1433 match pdu {
1434 RtrPdu::RouterKey(k) => {
1435 assert!(k.subject_public_key_info.is_empty());
1436 }
1437 _ => panic!("Expected RouterKey"),
1438 }
1439 }
1440
1441 #[test]
1442 fn test_parse_ipv6_invalid_max_length() {
1443 let mut bytes = vec![
1445 1, 6, 0, 0, 0, 0, 0, 32, 1, 64, 129, 0, ];
1454 bytes.extend_from_slice(&[0u8; 16]); bytes.extend_from_slice(&[0, 0, 0, 1]); let result = parse_rtr_pdu(&bytes);
1458 assert!(matches!(result, Err(RtrError::InvalidPrefixLength { .. })));
1459 }
1460
1461 #[test]
1462 fn test_encode_all_pdu_types_v0() {
1463 let notify = RtrSerialNotify {
1465 version: RtrProtocolVersion::V0,
1466 session_id: 100,
1467 serial_number: 200,
1468 };
1469 let bytes = notify.encode();
1470 assert_eq!(bytes[0], 0); let response = RtrCacheResponse {
1473 version: RtrProtocolVersion::V0,
1474 session_id: 300,
1475 };
1476 let bytes = response.encode();
1477 assert_eq!(bytes[0], 0); let reset = RtrCacheReset {
1480 version: RtrProtocolVersion::V0,
1481 };
1482 let bytes = reset.encode();
1483 assert_eq!(bytes[0], 0); let prefix4 = RtrIPv4Prefix {
1486 version: RtrProtocolVersion::V0,
1487 flags: 0,
1488 prefix_length: 16,
1489 max_length: 24,
1490 prefix: Ipv4Addr::new(172, 16, 0, 0),
1491 asn: Asn::from(64512u32),
1492 };
1493 let bytes = prefix4.encode();
1494 assert_eq!(bytes[0], 0); assert_eq!(bytes.len(), 20);
1496
1497 let prefix6 = RtrIPv6Prefix {
1498 version: RtrProtocolVersion::V0,
1499 flags: 1,
1500 prefix_length: 32,
1501 max_length: 48,
1502 prefix: Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 0),
1503 asn: Asn::from(64513u32),
1504 };
1505 let bytes = prefix6.encode();
1506 assert_eq!(bytes[0], 0); assert_eq!(bytes.len(), 32);
1508 }
1509
1510 #[test]
1511 fn test_read_multiple_pdus() {
1512 use std::io::Cursor;
1513
1514 let query1 = RtrResetQuery::new_v1();
1516 let query2 = RtrSerialQuery::new(RtrProtocolVersion::V1, 100, 200);
1517
1518 let mut buffer = query1.encode();
1519 buffer.extend(query2.encode());
1520
1521 let mut cursor = Cursor::new(buffer);
1522
1523 let pdu1 = read_rtr_pdu(&mut cursor).unwrap();
1525 assert!(matches!(pdu1, RtrPdu::ResetQuery(_)));
1526
1527 let pdu2 = read_rtr_pdu(&mut cursor).unwrap();
1529 assert!(matches!(pdu2, RtrPdu::SerialQuery(_)));
1530 }
1531
1532 #[test]
1533 fn test_parse_with_extra_bytes() {
1534 let query = RtrResetQuery::new_v1();
1536 let mut bytes = query.encode();
1537 bytes.extend_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]); let (pdu, consumed) = parse_rtr_pdu(&bytes).unwrap();
1540 assert!(matches!(pdu, RtrPdu::ResetQuery(_)));
1541 assert_eq!(consumed, 8); }
1543
1544 #[test]
1545 fn test_error_report_with_pdu_and_text() {
1546 let error = RtrErrorReport {
1548 version: RtrProtocolVersion::V1,
1549 error_code: RtrErrorCode::CorruptData,
1550 erroneous_pdu: vec![1, 2, 3, 4, 5, 6, 7, 8], error_text: "Something went wrong!".to_string(), };
1553 let bytes = error.encode();
1554
1555 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
1556 match pdu {
1557 RtrPdu::ErrorReport(e) => {
1558 assert_eq!(e.error_code, RtrErrorCode::CorruptData);
1559 assert_eq!(e.erroneous_pdu, vec![1, 2, 3, 4, 5, 6, 7, 8]);
1560 assert_eq!(e.error_text, "Something went wrong!");
1561 }
1562 _ => panic!("Expected ErrorReport"),
1563 }
1564 }
1565
1566 #[test]
1569 fn test_error_report_oversized_text_len_no_panic() {
1570 let bytes: Vec<u8> = vec![
1571 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, ];
1576 assert!(matches!(
1577 parse_rtr_pdu(&bytes),
1578 Err(RtrError::InvalidLength { .. })
1579 ));
1580 }
1581
1582 #[test]
1586 fn test_read_rtr_pdu_rejects_oversized_length() {
1587 let header: Vec<u8> = vec![
1589 0x01, 0x03, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, ];
1592 let mut reader = std::io::Cursor::new(header);
1593 assert!(matches!(
1594 read_rtr_pdu(&mut reader),
1595 Err(RtrError::InvalidLength { .. })
1596 ));
1597 }
1598
1599 #[test]
1603 fn test_read_rtr_pdu_accepts_large_error_report() {
1604 let encap_len = RTR_MAX_PDU_LEN; let text = "diagnostic text".repeat(10);
1606 let length = 8 + 4 + encap_len + 4 + text.len();
1607 assert!(length > RTR_MAX_PDU_LEN);
1608 assert!(length <= RTR_MAX_ERROR_REPORT_LEN);
1609
1610 let mut bytes: Vec<u8> = vec![0x01, 0x0A, 0x00, 0x00]; bytes.extend((length as u32).to_be_bytes());
1612 bytes.extend((encap_len as u32).to_be_bytes());
1613 bytes.extend(std::iter::repeat_n(0xAAu8, encap_len));
1614 bytes.extend((text.len() as u32).to_be_bytes());
1615 bytes.extend(text.as_bytes());
1616
1617 let mut reader = std::io::Cursor::new(bytes);
1618 match read_rtr_pdu(&mut reader).unwrap() {
1619 RtrPdu::ErrorReport(report) => {
1620 assert_eq!(report.erroneous_pdu.len(), encap_len);
1621 assert_eq!(report.error_text, text);
1622 }
1623 _ => panic!("Expected ErrorReport"),
1624 }
1625 }
1626}