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 fn parse_rtr_pdu(input: &[u8]) -> Result<(RtrPdu, usize), RtrError> {
201 if input.len() < RTR_HEADER_LEN {
203 return Err(RtrError::IncompletePdu {
204 available: input.len(),
205 needed: RTR_HEADER_LEN,
206 });
207 }
208
209 let version_byte = input[0];
211 let pdu_type_byte = input[1];
212 let session_or_error = u16::from_be_bytes([input[2], input[3]]);
213 let length = u32::from_be_bytes([input[4], input[5], input[6], input[7]]);
214
215 let length_usize = length as usize;
217 if input.len() < length_usize {
218 return Err(RtrError::IncompletePdu {
219 available: input.len(),
220 needed: length_usize,
221 });
222 }
223
224 let version = RtrProtocolVersion::from_u8(version_byte)
226 .ok_or(RtrError::InvalidProtocolVersion(version_byte))?;
227
228 let pdu_type =
230 RtrPduType::from_u8(pdu_type_byte).ok_or(RtrError::InvalidPduType(pdu_type_byte))?;
231
232 let pdu = match pdu_type {
234 RtrPduType::SerialNotify => {
235 validate_length(length, RTR_SERIAL_NOTIFY_LEN, pdu_type_byte)?;
236 let serial_number = u32::from_be_bytes([input[8], input[9], input[10], input[11]]);
237 RtrPdu::SerialNotify(RtrSerialNotify {
238 version,
239 session_id: session_or_error,
240 serial_number,
241 })
242 }
243
244 RtrPduType::SerialQuery => {
245 validate_length(length, RTR_SERIAL_QUERY_LEN, pdu_type_byte)?;
246 let serial_number = u32::from_be_bytes([input[8], input[9], input[10], input[11]]);
247 RtrPdu::SerialQuery(RtrSerialQuery {
248 version,
249 session_id: session_or_error,
250 serial_number,
251 })
252 }
253
254 RtrPduType::ResetQuery => {
255 validate_length(length, RTR_RESET_QUERY_LEN, pdu_type_byte)?;
256 RtrPdu::ResetQuery(RtrResetQuery { version })
257 }
258
259 RtrPduType::CacheResponse => {
260 validate_length(length, RTR_CACHE_RESPONSE_LEN, pdu_type_byte)?;
261 RtrPdu::CacheResponse(RtrCacheResponse {
262 version,
263 session_id: session_or_error,
264 })
265 }
266
267 RtrPduType::IPv4Prefix => {
268 validate_length(length, RTR_IPV4_PREFIX_LEN, pdu_type_byte)?;
269 let flags = input[8];
270 let prefix_length = input[9];
271 let max_length = input[10];
272 validate_prefix_length(prefix_length, max_length, 32)?;
275
276 let prefix = Ipv4Addr::new(input[12], input[13], input[14], input[15]);
277 let asn = u32::from_be_bytes([input[16], input[17], input[18], input[19]]);
278
279 RtrPdu::IPv4Prefix(RtrIPv4Prefix {
280 version,
281 flags,
282 prefix_length,
283 max_length,
284 prefix,
285 asn: Asn::from(asn),
286 })
287 }
288
289 RtrPduType::IPv6Prefix => {
290 validate_length(length, RTR_IPV6_PREFIX_LEN, pdu_type_byte)?;
291 let flags = input[8];
292 let prefix_length = input[9];
293 let max_length = input[10];
294 validate_prefix_length(prefix_length, max_length, 128)?;
297
298 let prefix = Ipv6Addr::from([
299 input[12], input[13], input[14], input[15], input[16], input[17], input[18],
300 input[19], input[20], input[21], input[22], input[23], input[24], input[25],
301 input[26], input[27],
302 ]);
303 let asn = u32::from_be_bytes([input[28], input[29], input[30], input[31]]);
304
305 RtrPdu::IPv6Prefix(RtrIPv6Prefix {
306 version,
307 flags,
308 prefix_length,
309 max_length,
310 prefix,
311 asn: Asn::from(asn),
312 })
313 }
314
315 RtrPduType::EndOfData => {
316 let expected_len = match version {
317 RtrProtocolVersion::V0 => RTR_END_OF_DATA_V0_LEN,
318 RtrProtocolVersion::V1 => RTR_END_OF_DATA_V1_LEN,
319 };
320 validate_length(length, expected_len, pdu_type_byte)?;
321
322 let serial_number = u32::from_be_bytes([input[8], input[9], input[10], input[11]]);
323
324 let (refresh_interval, retry_interval, expire_interval) = match version {
325 RtrProtocolVersion::V0 => (None, None, None),
326 RtrProtocolVersion::V1 => {
327 let refresh = u32::from_be_bytes([input[12], input[13], input[14], input[15]]);
328 let retry = u32::from_be_bytes([input[16], input[17], input[18], input[19]]);
329 let expire = u32::from_be_bytes([input[20], input[21], input[22], input[23]]);
330 (Some(refresh), Some(retry), Some(expire))
331 }
332 };
333
334 RtrPdu::EndOfData(RtrEndOfData {
335 version,
336 session_id: session_or_error,
337 serial_number,
338 refresh_interval,
339 retry_interval,
340 expire_interval,
341 })
342 }
343
344 RtrPduType::CacheReset => {
345 validate_length(length, RTR_CACHE_RESET_LEN, pdu_type_byte)?;
346 RtrPdu::CacheReset(RtrCacheReset { version })
347 }
348
349 RtrPduType::RouterKey => {
350 if version == RtrProtocolVersion::V0 {
352 return Err(RtrError::RouterKeyInV0);
353 }
354
355 if length < RTR_ROUTER_KEY_MIN_LEN {
356 return Err(RtrError::InvalidLength {
357 expected: RTR_ROUTER_KEY_MIN_LEN,
358 actual: length,
359 pdu_type: pdu_type_byte,
360 });
361 }
362
363 let flags = input[8];
364 let mut ski = [0u8; 20];
366 ski.copy_from_slice(&input[10..30]);
367 let asn = u32::from_be_bytes([input[30], input[31], input[32], input[33]]);
368
369 let spki_len = (length as usize) - 34;
371 let spki = if spki_len > 0 {
372 input[34..34 + spki_len].to_vec()
373 } else {
374 Vec::new()
375 };
376
377 RtrPdu::RouterKey(RtrRouterKey {
378 version,
379 flags,
380 subject_key_identifier: ski,
381 asn: Asn::from(asn),
382 subject_public_key_info: spki,
383 })
384 }
385
386 RtrPduType::ErrorReport => {
387 if length < 16 {
390 return Err(RtrError::InvalidLength {
391 expected: 16,
392 actual: length,
393 pdu_type: pdu_type_byte,
394 });
395 }
396
397 let error_code = RtrErrorCode::from_u16(session_or_error)
398 .ok_or(RtrError::InvalidErrorCode(session_or_error))?;
399
400 let encap_pdu_len =
401 u32::from_be_bytes([input[8], input[9], input[10], input[11]]) as usize;
402
403 if 12 + encap_pdu_len + 4 > length_usize {
405 return Err(RtrError::InvalidLength {
406 expected: (12 + encap_pdu_len + 4) as u32,
407 actual: length,
408 pdu_type: pdu_type_byte,
409 });
410 }
411
412 let erroneous_pdu = if encap_pdu_len > 0 {
413 input[12..12 + encap_pdu_len].to_vec()
414 } else {
415 Vec::new()
416 };
417
418 let error_text_len_offset = 12 + encap_pdu_len;
419 let error_text_len = u32::from_be_bytes([
420 input[error_text_len_offset],
421 input[error_text_len_offset + 1],
422 input[error_text_len_offset + 2],
423 input[error_text_len_offset + 3],
424 ]) as usize;
425
426 let error_text_offset = error_text_len_offset + 4;
427 let error_text = if error_text_len > 0 {
428 std::str::from_utf8(&input[error_text_offset..error_text_offset + error_text_len])
429 .map_err(|_| RtrError::InvalidUtf8)?
430 .to_string()
431 } else {
432 String::new()
433 };
434
435 RtrPdu::ErrorReport(RtrErrorReport {
436 version,
437 error_code,
438 erroneous_pdu,
439 error_text,
440 })
441 }
442 };
443
444 Ok((pdu, length_usize))
445}
446
447pub fn read_rtr_pdu<R: Read>(reader: &mut R) -> Result<RtrPdu, RtrError> {
465 let mut header = [0u8; RTR_HEADER_LEN];
467 reader.read_exact(&mut header)?;
468
469 let length = u32::from_be_bytes([header[4], header[5], header[6], header[7]]) as usize;
471
472 if length < RTR_HEADER_LEN {
473 return Err(RtrError::InvalidLength {
474 expected: RTR_HEADER_LEN as u32,
475 actual: length as u32,
476 pdu_type: header[1],
477 });
478 }
479
480 let mut buffer = vec![0u8; length];
482 buffer[..RTR_HEADER_LEN].copy_from_slice(&header);
483
484 if length > RTR_HEADER_LEN {
486 reader.read_exact(&mut buffer[RTR_HEADER_LEN..])?;
487 }
488
489 let (pdu, _) = parse_rtr_pdu(&buffer)?;
491 Ok(pdu)
492}
493
494fn validate_length(actual: u32, expected: u32, pdu_type: u8) -> Result<(), RtrError> {
495 if actual != expected {
496 Err(RtrError::InvalidLength {
497 expected,
498 actual,
499 pdu_type,
500 })
501 } else {
502 Ok(())
503 }
504}
505
506fn validate_prefix_length(prefix_len: u8, max_len: u8, max_allowed: u8) -> Result<(), RtrError> {
507 if prefix_len > max_len || max_len > max_allowed {
508 Err(RtrError::InvalidPrefixLength {
509 prefix_len,
510 max_len,
511 max_allowed,
512 })
513 } else {
514 Ok(())
515 }
516}
517
518pub trait RtrEncode {
524 fn encode(&self) -> Vec<u8>;
526}
527
528impl RtrEncode for RtrSerialNotify {
529 fn encode(&self) -> Vec<u8> {
530 let mut buf = Vec::with_capacity(RTR_SERIAL_NOTIFY_LEN as usize);
531 buf.push(self.version.to_u8());
532 buf.push(RtrPduType::SerialNotify.to_u8());
533 buf.extend_from_slice(&self.session_id.to_be_bytes());
534 buf.extend_from_slice(&RTR_SERIAL_NOTIFY_LEN.to_be_bytes());
535 buf.extend_from_slice(&self.serial_number.to_be_bytes());
536 buf
537 }
538}
539
540impl RtrEncode for RtrSerialQuery {
541 fn encode(&self) -> Vec<u8> {
542 let mut buf = Vec::with_capacity(RTR_SERIAL_QUERY_LEN as usize);
543 buf.push(self.version.to_u8());
544 buf.push(RtrPduType::SerialQuery.to_u8());
545 buf.extend_from_slice(&self.session_id.to_be_bytes());
546 buf.extend_from_slice(&RTR_SERIAL_QUERY_LEN.to_be_bytes());
547 buf.extend_from_slice(&self.serial_number.to_be_bytes());
548 buf
549 }
550}
551
552impl RtrEncode for RtrResetQuery {
553 fn encode(&self) -> Vec<u8> {
554 let mut buf = Vec::with_capacity(RTR_RESET_QUERY_LEN as usize);
555 buf.push(self.version.to_u8());
556 buf.push(RtrPduType::ResetQuery.to_u8());
557 buf.extend_from_slice(&[0, 0]); buf.extend_from_slice(&RTR_RESET_QUERY_LEN.to_be_bytes());
559 buf
560 }
561}
562
563impl RtrEncode for RtrCacheResponse {
564 fn encode(&self) -> Vec<u8> {
565 let mut buf = Vec::with_capacity(RTR_CACHE_RESPONSE_LEN as usize);
566 buf.push(self.version.to_u8());
567 buf.push(RtrPduType::CacheResponse.to_u8());
568 buf.extend_from_slice(&self.session_id.to_be_bytes());
569 buf.extend_from_slice(&RTR_CACHE_RESPONSE_LEN.to_be_bytes());
570 buf
571 }
572}
573
574impl RtrEncode for RtrIPv4Prefix {
575 fn encode(&self) -> Vec<u8> {
576 let mut buf = Vec::with_capacity(RTR_IPV4_PREFIX_LEN as usize);
577 buf.push(self.version.to_u8());
578 buf.push(RtrPduType::IPv4Prefix.to_u8());
579 buf.extend_from_slice(&[0, 0]); buf.extend_from_slice(&RTR_IPV4_PREFIX_LEN.to_be_bytes());
581 buf.push(self.flags);
582 buf.push(self.prefix_length);
583 buf.push(self.max_length);
584 buf.push(0); buf.extend_from_slice(&self.prefix.octets());
586 buf.extend_from_slice(&self.asn.to_u32().to_be_bytes());
587 buf
588 }
589}
590
591impl RtrEncode for RtrIPv6Prefix {
592 fn encode(&self) -> Vec<u8> {
593 let mut buf = Vec::with_capacity(RTR_IPV6_PREFIX_LEN as usize);
594 buf.push(self.version.to_u8());
595 buf.push(RtrPduType::IPv6Prefix.to_u8());
596 buf.extend_from_slice(&[0, 0]); buf.extend_from_slice(&RTR_IPV6_PREFIX_LEN.to_be_bytes());
598 buf.push(self.flags);
599 buf.push(self.prefix_length);
600 buf.push(self.max_length);
601 buf.push(0); buf.extend_from_slice(&self.prefix.octets());
603 buf.extend_from_slice(&self.asn.to_u32().to_be_bytes());
604 buf
605 }
606}
607
608impl RtrEncode for RtrEndOfData {
609 fn encode(&self) -> Vec<u8> {
610 let length = match self.version {
611 RtrProtocolVersion::V0 => RTR_END_OF_DATA_V0_LEN,
612 RtrProtocolVersion::V1 => RTR_END_OF_DATA_V1_LEN,
613 };
614 let mut buf = Vec::with_capacity(length as usize);
615 buf.push(self.version.to_u8());
616 buf.push(RtrPduType::EndOfData.to_u8());
617 buf.extend_from_slice(&self.session_id.to_be_bytes());
618 buf.extend_from_slice(&length.to_be_bytes());
619 buf.extend_from_slice(&self.serial_number.to_be_bytes());
620
621 if self.version == RtrProtocolVersion::V1 {
622 buf.extend_from_slice(
623 &self
624 .refresh_interval
625 .unwrap_or(RtrEndOfData::DEFAULT_REFRESH)
626 .to_be_bytes(),
627 );
628 buf.extend_from_slice(
629 &self
630 .retry_interval
631 .unwrap_or(RtrEndOfData::DEFAULT_RETRY)
632 .to_be_bytes(),
633 );
634 buf.extend_from_slice(
635 &self
636 .expire_interval
637 .unwrap_or(RtrEndOfData::DEFAULT_EXPIRE)
638 .to_be_bytes(),
639 );
640 }
641 buf
642 }
643}
644
645impl RtrEncode for RtrCacheReset {
646 fn encode(&self) -> Vec<u8> {
647 let mut buf = Vec::with_capacity(RTR_CACHE_RESET_LEN as usize);
648 buf.push(self.version.to_u8());
649 buf.push(RtrPduType::CacheReset.to_u8());
650 buf.extend_from_slice(&[0, 0]); buf.extend_from_slice(&RTR_CACHE_RESET_LEN.to_be_bytes());
652 buf
653 }
654}
655
656impl RtrEncode for RtrRouterKey {
657 fn encode(&self) -> Vec<u8> {
658 let length = RTR_ROUTER_KEY_MIN_LEN + self.subject_public_key_info.len() as u32;
659 let mut buf = Vec::with_capacity(length as usize);
660 buf.push(self.version.to_u8());
661 buf.push(RtrPduType::RouterKey.to_u8());
662 buf.extend_from_slice(&[0, 0]); buf.extend_from_slice(&length.to_be_bytes());
664 buf.push(self.flags);
665 buf.push(0); buf.extend_from_slice(&self.subject_key_identifier);
667 buf.extend_from_slice(&self.asn.to_u32().to_be_bytes());
668 buf.extend_from_slice(&self.subject_public_key_info);
669 buf
670 }
671}
672
673impl RtrEncode for RtrErrorReport {
674 fn encode(&self) -> Vec<u8> {
675 let error_text_bytes = self.error_text.as_bytes();
676 let length = 16 + self.erroneous_pdu.len() + error_text_bytes.len();
677 let mut buf = Vec::with_capacity(length);
678 buf.push(self.version.to_u8());
679 buf.push(RtrPduType::ErrorReport.to_u8());
680 buf.extend_from_slice(&self.error_code.to_u16().to_be_bytes());
681 buf.extend_from_slice(&(length as u32).to_be_bytes());
682 buf.extend_from_slice(&(self.erroneous_pdu.len() as u32).to_be_bytes());
683 buf.extend_from_slice(&self.erroneous_pdu);
684 buf.extend_from_slice(&(error_text_bytes.len() as u32).to_be_bytes());
685 buf.extend_from_slice(error_text_bytes);
686 buf
687 }
688}
689
690impl RtrEncode for RtrPdu {
691 fn encode(&self) -> Vec<u8> {
692 match self {
693 RtrPdu::SerialNotify(p) => p.encode(),
694 RtrPdu::SerialQuery(p) => p.encode(),
695 RtrPdu::ResetQuery(p) => p.encode(),
696 RtrPdu::CacheResponse(p) => p.encode(),
697 RtrPdu::IPv4Prefix(p) => p.encode(),
698 RtrPdu::IPv6Prefix(p) => p.encode(),
699 RtrPdu::EndOfData(p) => p.encode(),
700 RtrPdu::CacheReset(p) => p.encode(),
701 RtrPdu::RouterKey(p) => p.encode(),
702 RtrPdu::ErrorReport(p) => p.encode(),
703 }
704 }
705}
706
707#[cfg(test)]
712mod tests {
713 use super::*;
714
715 #[test]
716 fn test_reset_query_roundtrip() {
717 let query = RtrResetQuery::new_v1();
718 let bytes = query.encode();
719 assert_eq!(bytes.len(), 8);
720
721 let (pdu, consumed) = parse_rtr_pdu(&bytes).unwrap();
722 assert_eq!(consumed, 8);
723 assert!(matches!(pdu, RtrPdu::ResetQuery(q) if q.version == RtrProtocolVersion::V1));
724 }
725
726 #[test]
727 fn test_reset_query_v0_roundtrip() {
728 let query = RtrResetQuery::new_v0();
729 let bytes = query.encode();
730
731 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
732 assert!(matches!(pdu, RtrPdu::ResetQuery(q) if q.version == RtrProtocolVersion::V0));
733 }
734
735 #[test]
736 fn test_serial_query_roundtrip() {
737 let query = RtrSerialQuery::new(RtrProtocolVersion::V1, 12345, 67890);
738 let bytes = query.encode();
739 assert_eq!(bytes.len(), 12);
740
741 let (pdu, consumed) = parse_rtr_pdu(&bytes).unwrap();
742 assert_eq!(consumed, 12);
743 match pdu {
744 RtrPdu::SerialQuery(q) => {
745 assert_eq!(q.session_id, 12345);
746 assert_eq!(q.serial_number, 67890);
747 }
748 _ => panic!("Expected SerialQuery"),
749 }
750 }
751
752 #[test]
753 fn test_serial_notify_roundtrip() {
754 let notify = RtrSerialNotify {
755 version: RtrProtocolVersion::V1,
756 session_id: 100,
757 serial_number: 200,
758 };
759 let bytes = notify.encode();
760
761 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
762 match pdu {
763 RtrPdu::SerialNotify(n) => {
764 assert_eq!(n.session_id, 100);
765 assert_eq!(n.serial_number, 200);
766 }
767 _ => panic!("Expected SerialNotify"),
768 }
769 }
770
771 #[test]
772 fn test_cache_response_roundtrip() {
773 let response = RtrCacheResponse {
774 version: RtrProtocolVersion::V1,
775 session_id: 42,
776 };
777 let bytes = response.encode();
778
779 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
780 match pdu {
781 RtrPdu::CacheResponse(r) => {
782 assert_eq!(r.session_id, 42);
783 }
784 _ => panic!("Expected CacheResponse"),
785 }
786 }
787
788 #[test]
789 fn test_ipv4_prefix_roundtrip() {
790 let prefix = RtrIPv4Prefix {
791 version: RtrProtocolVersion::V1,
792 flags: 1,
793 prefix_length: 24,
794 max_length: 24,
795 prefix: Ipv4Addr::new(192, 0, 2, 0),
796 asn: Asn::from(65001u32),
797 };
798 let bytes = prefix.encode();
799 assert_eq!(bytes.len(), 20);
800
801 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
802 match pdu {
803 RtrPdu::IPv4Prefix(p) => {
804 assert!(p.is_announcement());
805 assert_eq!(p.prefix_length, 24);
806 assert_eq!(p.max_length, 24);
807 assert_eq!(p.prefix, Ipv4Addr::new(192, 0, 2, 0));
808 assert_eq!(p.asn.to_u32(), 65001);
809 }
810 _ => panic!("Expected IPv4Prefix"),
811 }
812 }
813
814 #[test]
815 fn test_ipv4_prefix_withdrawal() {
816 let prefix = RtrIPv4Prefix {
817 version: RtrProtocolVersion::V1,
818 flags: 0, prefix_length: 24,
820 max_length: 24,
821 prefix: Ipv4Addr::new(192, 0, 2, 0),
822 asn: Asn::from(65001u32),
823 };
824 let bytes = prefix.encode();
825
826 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
827 match pdu {
828 RtrPdu::IPv4Prefix(p) => {
829 assert!(p.is_withdrawal());
830 assert!(!p.is_announcement());
831 }
832 _ => panic!("Expected IPv4Prefix"),
833 }
834 }
835
836 #[test]
837 fn test_ipv6_prefix_roundtrip() {
838 let prefix = RtrIPv6Prefix {
839 version: RtrProtocolVersion::V1,
840 flags: 1,
841 prefix_length: 48,
842 max_length: 64,
843 prefix: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
844 asn: Asn::from(65002u32),
845 };
846 let bytes = prefix.encode();
847 assert_eq!(bytes.len(), 32);
848
849 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
850 match pdu {
851 RtrPdu::IPv6Prefix(p) => {
852 assert!(p.is_announcement());
853 assert_eq!(p.prefix_length, 48);
854 assert_eq!(p.max_length, 64);
855 assert_eq!(p.prefix, Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0));
856 assert_eq!(p.asn.to_u32(), 65002);
857 }
858 _ => panic!("Expected IPv6Prefix"),
859 }
860 }
861
862 #[test]
863 fn test_end_of_data_v0_roundtrip() {
864 let eod = RtrEndOfData {
865 version: RtrProtocolVersion::V0,
866 session_id: 100,
867 serial_number: 200,
868 refresh_interval: None,
869 retry_interval: None,
870 expire_interval: None,
871 };
872 let bytes = eod.encode();
873 assert_eq!(bytes.len(), 12);
874
875 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
876 match pdu {
877 RtrPdu::EndOfData(e) => {
878 assert_eq!(e.version, RtrProtocolVersion::V0);
879 assert_eq!(e.session_id, 100);
880 assert_eq!(e.serial_number, 200);
881 assert_eq!(e.refresh_interval, None);
882 assert_eq!(e.retry_interval, None);
883 assert_eq!(e.expire_interval, None);
884 }
885 _ => panic!("Expected EndOfData"),
886 }
887 }
888
889 #[test]
890 fn test_end_of_data_v1_roundtrip() {
891 let eod = RtrEndOfData {
892 version: RtrProtocolVersion::V1,
893 session_id: 100,
894 serial_number: 200,
895 refresh_interval: Some(1800),
896 retry_interval: Some(300),
897 expire_interval: Some(3600),
898 };
899 let bytes = eod.encode();
900 assert_eq!(bytes.len(), 24);
901
902 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
903 match pdu {
904 RtrPdu::EndOfData(e) => {
905 assert_eq!(e.version, RtrProtocolVersion::V1);
906 assert_eq!(e.refresh_interval, Some(1800));
907 assert_eq!(e.retry_interval, Some(300));
908 assert_eq!(e.expire_interval, Some(3600));
909 }
910 _ => panic!("Expected EndOfData"),
911 }
912 }
913
914 #[test]
915 fn test_end_of_data_v1_with_defaults() {
916 let eod = RtrEndOfData {
917 version: RtrProtocolVersion::V1,
918 session_id: 100,
919 serial_number: 200,
920 refresh_interval: None, retry_interval: None,
922 expire_interval: None,
923 };
924 let bytes = eod.encode();
925 assert_eq!(bytes.len(), 24);
926
927 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
928 match pdu {
929 RtrPdu::EndOfData(e) => {
930 assert_eq!(e.refresh_interval, Some(3600));
932 assert_eq!(e.retry_interval, Some(600));
933 assert_eq!(e.expire_interval, Some(7200));
934 }
935 _ => panic!("Expected EndOfData"),
936 }
937 }
938
939 #[test]
940 fn test_cache_reset_roundtrip() {
941 let reset = RtrCacheReset {
942 version: RtrProtocolVersion::V1,
943 };
944 let bytes = reset.encode();
945 assert_eq!(bytes.len(), 8);
946
947 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
948 assert!(matches!(pdu, RtrPdu::CacheReset(_)));
949 }
950
951 #[test]
952 fn test_router_key_roundtrip() {
953 let key = RtrRouterKey {
954 version: RtrProtocolVersion::V1,
955 flags: 1,
956 subject_key_identifier: [
957 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
958 ],
959 asn: Asn::from(65003u32),
960 subject_public_key_info: vec![0xAB, 0xCD, 0xEF],
961 };
962 let bytes = key.encode();
963 assert_eq!(bytes.len(), 37); let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
966 match pdu {
967 RtrPdu::RouterKey(k) => {
968 assert!(k.is_announcement());
969 assert_eq!(k.subject_key_identifier[0], 1);
970 assert_eq!(k.subject_key_identifier[19], 20);
971 assert_eq!(k.asn.to_u32(), 65003);
972 assert_eq!(k.subject_public_key_info, vec![0xAB, 0xCD, 0xEF]);
973 }
974 _ => panic!("Expected RouterKey"),
975 }
976 }
977
978 #[test]
979 fn test_router_key_in_v0_error() {
980 let mut bytes = vec![
982 0, 9, 0, 0, 0, 0, 0, 34, 1, 0, ];
989 bytes.extend_from_slice(&[0u8; 20]); bytes.extend_from_slice(&[0, 0, 0, 1]); let result = parse_rtr_pdu(&bytes);
993 assert!(matches!(result, Err(RtrError::RouterKeyInV0)));
994 }
995
996 #[test]
997 fn test_error_report_roundtrip() {
998 let error = RtrErrorReport {
999 version: RtrProtocolVersion::V1,
1000 error_code: RtrErrorCode::UnsupportedProtocolVersion,
1001 erroneous_pdu: vec![99, 2, 0, 0, 0, 0, 0, 8], error_text: "Test error".to_string(),
1003 };
1004 let bytes = error.encode();
1005
1006 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
1007 match pdu {
1008 RtrPdu::ErrorReport(e) => {
1009 assert_eq!(e.error_code, RtrErrorCode::UnsupportedProtocolVersion);
1010 assert_eq!(e.erroneous_pdu, vec![99, 2, 0, 0, 0, 0, 0, 8]);
1011 assert_eq!(e.error_text, "Test error");
1012 }
1013 _ => panic!("Expected ErrorReport"),
1014 }
1015 }
1016
1017 #[test]
1018 fn test_error_report_empty() {
1019 let error = RtrErrorReport {
1020 version: RtrProtocolVersion::V1,
1021 error_code: RtrErrorCode::InternalError,
1022 erroneous_pdu: vec![],
1023 error_text: String::new(),
1024 };
1025 let bytes = error.encode();
1026 assert_eq!(bytes.len(), 16);
1027
1028 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
1029 match pdu {
1030 RtrPdu::ErrorReport(e) => {
1031 assert_eq!(e.error_code, RtrErrorCode::InternalError);
1032 assert!(e.erroneous_pdu.is_empty());
1033 assert!(e.error_text.is_empty());
1034 }
1035 _ => panic!("Expected ErrorReport"),
1036 }
1037 }
1038
1039 #[test]
1040 fn test_incomplete_pdu_error() {
1041 let bytes = [1, 2, 0]; let result = parse_rtr_pdu(&bytes);
1043 assert!(matches!(result, Err(RtrError::IncompletePdu { .. })));
1044 }
1045
1046 #[test]
1047 fn test_invalid_pdu_type_error() {
1048 let bytes = [1, 5, 0, 0, 0, 0, 0, 8]; let result = parse_rtr_pdu(&bytes);
1050 assert!(matches!(result, Err(RtrError::InvalidPduType(5))));
1051 }
1052
1053 #[test]
1054 fn test_invalid_protocol_version_error() {
1055 let bytes = [99, 2, 0, 0, 0, 0, 0, 8]; let result = parse_rtr_pdu(&bytes);
1057 assert!(matches!(result, Err(RtrError::InvalidProtocolVersion(99))));
1058 }
1059
1060 #[test]
1061 fn test_invalid_length_error() {
1062 let bytes = [1, 2, 0, 0, 0, 0, 0, 10, 0, 0]; let result = parse_rtr_pdu(&bytes);
1065 assert!(matches!(result, Err(RtrError::InvalidLength { .. })));
1066 }
1067
1068 #[test]
1069 fn test_invalid_prefix_length_error() {
1070 let mut bytes = vec![
1072 1, 4, 0, 0, 0, 0, 0, 20, 1, 25, 24, 0, ];
1081 bytes.extend_from_slice(&[192, 0, 2, 0]); bytes.extend_from_slice(&[0, 0, 0, 1]); let result = parse_rtr_pdu(&bytes);
1085 assert!(matches!(result, Err(RtrError::InvalidPrefixLength { .. })));
1086 }
1087
1088 #[test]
1089 fn test_invalid_max_length_error() {
1090 let mut bytes = vec![
1092 1, 4, 0, 0, 0, 0, 0, 20, 1, 24, 33, 0, ];
1101 bytes.extend_from_slice(&[192, 0, 2, 0]); bytes.extend_from_slice(&[0, 0, 0, 1]); let result = parse_rtr_pdu(&bytes);
1105 assert!(matches!(result, Err(RtrError::InvalidPrefixLength { .. })));
1106 }
1107
1108 #[test]
1109 fn test_read_rtr_pdu_from_cursor() {
1110 use std::io::Cursor;
1111
1112 let query = RtrResetQuery::new_v1();
1113 let bytes = query.encode();
1114 let mut cursor = Cursor::new(bytes);
1115
1116 let pdu = read_rtr_pdu(&mut cursor).unwrap();
1117 assert!(matches!(pdu, RtrPdu::ResetQuery(_)));
1118 }
1119
1120 #[test]
1121 fn test_pdu_enum_encode() {
1122 let pdu = RtrPdu::ResetQuery(RtrResetQuery::new_v1());
1123 let bytes = pdu.encode();
1124 assert_eq!(bytes.len(), 8);
1125
1126 let (parsed, _) = parse_rtr_pdu(&bytes).unwrap();
1127 assert!(matches!(parsed, RtrPdu::ResetQuery(_)));
1128 }
1129
1130 #[test]
1131 fn test_all_pdu_types_roundtrip() {
1132 let pdus: Vec<RtrPdu> = vec![
1134 RtrPdu::SerialNotify(RtrSerialNotify {
1135 version: RtrProtocolVersion::V1,
1136 session_id: 1,
1137 serial_number: 100,
1138 }),
1139 RtrPdu::SerialQuery(RtrSerialQuery::new(RtrProtocolVersion::V1, 1, 100)),
1140 RtrPdu::ResetQuery(RtrResetQuery::new_v1()),
1141 RtrPdu::CacheResponse(RtrCacheResponse {
1142 version: RtrProtocolVersion::V1,
1143 session_id: 1,
1144 }),
1145 RtrPdu::IPv4Prefix(RtrIPv4Prefix {
1146 version: RtrProtocolVersion::V1,
1147 flags: 1,
1148 prefix_length: 24,
1149 max_length: 24,
1150 prefix: Ipv4Addr::new(10, 0, 0, 0),
1151 asn: Asn::from(65000u32),
1152 }),
1153 RtrPdu::IPv6Prefix(RtrIPv6Prefix {
1154 version: RtrProtocolVersion::V1,
1155 flags: 1,
1156 prefix_length: 48,
1157 max_length: 48,
1158 prefix: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
1159 asn: Asn::from(65000u32),
1160 }),
1161 RtrPdu::EndOfData(RtrEndOfData {
1162 version: RtrProtocolVersion::V1,
1163 session_id: 1,
1164 serial_number: 100,
1165 refresh_interval: Some(3600),
1166 retry_interval: Some(600),
1167 expire_interval: Some(7200),
1168 }),
1169 RtrPdu::CacheReset(RtrCacheReset {
1170 version: RtrProtocolVersion::V1,
1171 }),
1172 RtrPdu::RouterKey(RtrRouterKey {
1173 version: RtrProtocolVersion::V1,
1174 flags: 1,
1175 subject_key_identifier: [0; 20],
1176 asn: Asn::from(65000u32),
1177 subject_public_key_info: vec![1, 2, 3, 4],
1178 }),
1179 RtrPdu::ErrorReport(RtrErrorReport {
1180 version: RtrProtocolVersion::V1,
1181 error_code: RtrErrorCode::NoDataAvailable,
1182 erroneous_pdu: vec![],
1183 error_text: "No data".to_string(),
1184 }),
1185 ];
1186
1187 for original in pdus {
1188 let bytes = original.encode();
1189 let (parsed, consumed) = parse_rtr_pdu(&bytes).unwrap();
1190 assert_eq!(consumed, bytes.len());
1191 assert_eq!(parsed.pdu_type(), original.pdu_type());
1192 }
1193 }
1194
1195 #[test]
1196 fn test_error_display() {
1197 let err = RtrError::InvalidPduType(42);
1198 assert!(err.to_string().contains("42"));
1199
1200 let err = RtrError::IncompletePdu {
1201 available: 4,
1202 needed: 8,
1203 };
1204 assert!(err.to_string().contains("4"));
1205 assert!(err.to_string().contains("8"));
1206 }
1207
1208 #[test]
1209 fn test_error_display_all_variants() {
1210 let io_err = RtrError::IoError(std::io::Error::new(
1212 std::io::ErrorKind::ConnectionReset,
1213 "connection reset",
1214 ));
1215 assert!(io_err.to_string().contains("I/O error"));
1216
1217 let incomplete = RtrError::IncompletePdu {
1218 available: 5,
1219 needed: 10,
1220 };
1221 assert!(incomplete.to_string().contains("Incomplete PDU"));
1222 assert!(incomplete.to_string().contains("5"));
1223 assert!(incomplete.to_string().contains("10"));
1224
1225 let invalid_type = RtrError::InvalidPduType(99);
1226 assert!(invalid_type.to_string().contains("Invalid PDU type"));
1227 assert!(invalid_type.to_string().contains("99"));
1228
1229 let invalid_version = RtrError::InvalidProtocolVersion(5);
1230 assert!(invalid_version
1231 .to_string()
1232 .contains("Invalid protocol version"));
1233 assert!(invalid_version.to_string().contains("5"));
1234
1235 let invalid_error_code = RtrError::InvalidErrorCode(100);
1236 assert!(invalid_error_code
1237 .to_string()
1238 .contains("Invalid error code"));
1239 assert!(invalid_error_code.to_string().contains("100"));
1240
1241 let invalid_length = RtrError::InvalidLength {
1242 expected: 20,
1243 actual: 15,
1244 pdu_type: 4,
1245 };
1246 assert!(invalid_length.to_string().contains("Invalid length"));
1247 assert!(invalid_length.to_string().contains("20"));
1248 assert!(invalid_length.to_string().contains("15"));
1249 assert!(invalid_length.to_string().contains("4"));
1250
1251 let invalid_prefix = RtrError::InvalidPrefixLength {
1252 prefix_len: 25,
1253 max_len: 24,
1254 max_allowed: 32,
1255 };
1256 assert!(invalid_prefix.to_string().contains("Invalid prefix length"));
1257 assert!(invalid_prefix.to_string().contains("25"));
1258 assert!(invalid_prefix.to_string().contains("24"));
1259 assert!(invalid_prefix.to_string().contains("32"));
1260
1261 let invalid_utf8 = RtrError::InvalidUtf8;
1262 assert!(invalid_utf8.to_string().contains("Invalid UTF-8"));
1263
1264 let router_key_v0 = RtrError::RouterKeyInV0;
1265 assert!(router_key_v0.to_string().contains("Router Key PDU"));
1266 assert!(router_key_v0.to_string().contains("v0"));
1267 }
1268
1269 #[test]
1270 fn test_error_source() {
1271 use std::error::Error;
1272
1273 let io_err = RtrError::IoError(std::io::Error::new(
1275 std::io::ErrorKind::NotFound,
1276 "file not found",
1277 ));
1278 assert!(io_err.source().is_some());
1279
1280 let incomplete = RtrError::IncompletePdu {
1282 available: 1,
1283 needed: 2,
1284 };
1285 assert!(incomplete.source().is_none());
1286
1287 let invalid_type = RtrError::InvalidPduType(5);
1288 assert!(invalid_type.source().is_none());
1289
1290 let invalid_utf8 = RtrError::InvalidUtf8;
1291 assert!(invalid_utf8.source().is_none());
1292 }
1293
1294 #[test]
1295 fn test_error_from_io_error() {
1296 let io_err = std::io::Error::new(std::io::ErrorKind::TimedOut, "timeout");
1297 let rtr_err: RtrError = io_err.into();
1298 assert!(matches!(rtr_err, RtrError::IoError(_)));
1299 }
1300
1301 #[test]
1302 fn test_read_rtr_pdu_short_length() {
1303 use std::io::Cursor;
1304
1305 let bytes = vec![
1307 1, 2, 0, 0, 0, 0, 0, 4, ];
1312 let mut cursor = Cursor::new(bytes);
1313 let result = read_rtr_pdu(&mut cursor);
1314 assert!(matches!(result, Err(RtrError::InvalidLength { .. })));
1315 }
1316
1317 #[test]
1318 fn test_parse_invalid_error_code() {
1319 let bytes = vec![
1321 1, 10, 0, 100, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, ];
1328 let result = parse_rtr_pdu(&bytes);
1329 assert!(matches!(result, Err(RtrError::InvalidErrorCode(100))));
1330 }
1331
1332 #[test]
1333 fn test_parse_error_report_invalid_utf8() {
1334 let bytes = vec![
1336 1, 10, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 4, 0xFF, 0xFE, 0xFF, 0xFE, ];
1344 let result = parse_rtr_pdu(&bytes);
1345 assert!(matches!(result, Err(RtrError::InvalidUtf8)));
1346 }
1347
1348 #[test]
1349 fn test_parse_error_report_truncated() {
1350 let bytes = vec![
1352 1, 10, 0, 0, 0, 0, 0, 16, 0, 0, 0, 100, 0, 0, 0, 0, ];
1359 let result = parse_rtr_pdu(&bytes);
1360 assert!(matches!(result, Err(RtrError::InvalidLength { .. })));
1361 }
1362
1363 #[test]
1364 fn test_parse_router_key_empty_spki() {
1365 let mut bytes = vec![
1367 1, 9, 0, 0, 0, 0, 0, 34, 1, 0, ];
1374 bytes.extend_from_slice(&[0u8; 20]); bytes.extend_from_slice(&[0, 0, 0, 1]); let (pdu, consumed) = parse_rtr_pdu(&bytes).unwrap();
1378 assert_eq!(consumed, 34);
1379 match pdu {
1380 RtrPdu::RouterKey(k) => {
1381 assert!(k.subject_public_key_info.is_empty());
1382 }
1383 _ => panic!("Expected RouterKey"),
1384 }
1385 }
1386
1387 #[test]
1388 fn test_parse_ipv6_invalid_max_length() {
1389 let mut bytes = vec![
1391 1, 6, 0, 0, 0, 0, 0, 32, 1, 64, 129, 0, ];
1400 bytes.extend_from_slice(&[0u8; 16]); bytes.extend_from_slice(&[0, 0, 0, 1]); let result = parse_rtr_pdu(&bytes);
1404 assert!(matches!(result, Err(RtrError::InvalidPrefixLength { .. })));
1405 }
1406
1407 #[test]
1408 fn test_encode_all_pdu_types_v0() {
1409 let notify = RtrSerialNotify {
1411 version: RtrProtocolVersion::V0,
1412 session_id: 100,
1413 serial_number: 200,
1414 };
1415 let bytes = notify.encode();
1416 assert_eq!(bytes[0], 0); let response = RtrCacheResponse {
1419 version: RtrProtocolVersion::V0,
1420 session_id: 300,
1421 };
1422 let bytes = response.encode();
1423 assert_eq!(bytes[0], 0); let reset = RtrCacheReset {
1426 version: RtrProtocolVersion::V0,
1427 };
1428 let bytes = reset.encode();
1429 assert_eq!(bytes[0], 0); let prefix4 = RtrIPv4Prefix {
1432 version: RtrProtocolVersion::V0,
1433 flags: 0,
1434 prefix_length: 16,
1435 max_length: 24,
1436 prefix: Ipv4Addr::new(172, 16, 0, 0),
1437 asn: Asn::from(64512u32),
1438 };
1439 let bytes = prefix4.encode();
1440 assert_eq!(bytes[0], 0); assert_eq!(bytes.len(), 20);
1442
1443 let prefix6 = RtrIPv6Prefix {
1444 version: RtrProtocolVersion::V0,
1445 flags: 1,
1446 prefix_length: 32,
1447 max_length: 48,
1448 prefix: Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 0),
1449 asn: Asn::from(64513u32),
1450 };
1451 let bytes = prefix6.encode();
1452 assert_eq!(bytes[0], 0); assert_eq!(bytes.len(), 32);
1454 }
1455
1456 #[test]
1457 fn test_read_multiple_pdus() {
1458 use std::io::Cursor;
1459
1460 let query1 = RtrResetQuery::new_v1();
1462 let query2 = RtrSerialQuery::new(RtrProtocolVersion::V1, 100, 200);
1463
1464 let mut buffer = query1.encode();
1465 buffer.extend(query2.encode());
1466
1467 let mut cursor = Cursor::new(buffer);
1468
1469 let pdu1 = read_rtr_pdu(&mut cursor).unwrap();
1471 assert!(matches!(pdu1, RtrPdu::ResetQuery(_)));
1472
1473 let pdu2 = read_rtr_pdu(&mut cursor).unwrap();
1475 assert!(matches!(pdu2, RtrPdu::SerialQuery(_)));
1476 }
1477
1478 #[test]
1479 fn test_parse_with_extra_bytes() {
1480 let query = RtrResetQuery::new_v1();
1482 let mut bytes = query.encode();
1483 bytes.extend_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]); let (pdu, consumed) = parse_rtr_pdu(&bytes).unwrap();
1486 assert!(matches!(pdu, RtrPdu::ResetQuery(_)));
1487 assert_eq!(consumed, 8); }
1489
1490 #[test]
1491 fn test_error_report_with_pdu_and_text() {
1492 let error = RtrErrorReport {
1494 version: RtrProtocolVersion::V1,
1495 error_code: RtrErrorCode::CorruptData,
1496 erroneous_pdu: vec![1, 2, 3, 4, 5, 6, 7, 8], error_text: "Something went wrong!".to_string(), };
1499 let bytes = error.encode();
1500
1501 let (pdu, _) = parse_rtr_pdu(&bytes).unwrap();
1502 match pdu {
1503 RtrPdu::ErrorReport(e) => {
1504 assert_eq!(e.error_code, RtrErrorCode::CorruptData);
1505 assert_eq!(e.erroneous_pdu, vec![1, 2, 3, 4, 5, 6, 7, 8]);
1506 assert_eq!(e.error_text, "Something went wrong!");
1507 }
1508 _ => panic!("Expected ErrorReport"),
1509 }
1510 }
1511}