1use crate::models::Asn;
34use std::net::{Ipv4Addr, Ipv6Addr};
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
46#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
47#[repr(u8)]
48pub enum RtrProtocolVersion {
49 V0 = 0,
51 #[default]
53 V1 = 1,
54}
55
56impl RtrProtocolVersion {
57 pub fn from_u8(value: u8) -> Option<Self> {
59 match value {
60 0 => Some(RtrProtocolVersion::V0),
61 1 => Some(RtrProtocolVersion::V1),
62 _ => None,
63 }
64 }
65
66 pub fn to_u8(self) -> u8 {
68 self as u8
69 }
70}
71
72impl From<RtrProtocolVersion> for u8 {
73 fn from(v: RtrProtocolVersion) -> Self {
74 v as u8
75 }
76}
77
78impl TryFrom<u8> for RtrProtocolVersion {
79 type Error = u8;
80
81 fn try_from(value: u8) -> Result<Self, Self::Error> {
82 RtrProtocolVersion::from_u8(value).ok_or(value)
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
90#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
91#[repr(u8)]
92pub enum RtrPduType {
93 SerialNotify = 0,
95 SerialQuery = 1,
97 ResetQuery = 2,
99 CacheResponse = 3,
101 IPv4Prefix = 4,
103 IPv6Prefix = 6,
105 EndOfData = 7,
107 CacheReset = 8,
109 RouterKey = 9,
111 ErrorReport = 10,
113}
114
115impl RtrPduType {
116 pub fn from_u8(value: u8) -> Option<Self> {
118 match value {
119 0 => Some(RtrPduType::SerialNotify),
120 1 => Some(RtrPduType::SerialQuery),
121 2 => Some(RtrPduType::ResetQuery),
122 3 => Some(RtrPduType::CacheResponse),
123 4 => Some(RtrPduType::IPv4Prefix),
124 6 => Some(RtrPduType::IPv6Prefix),
125 7 => Some(RtrPduType::EndOfData),
126 8 => Some(RtrPduType::CacheReset),
127 9 => Some(RtrPduType::RouterKey),
128 10 => Some(RtrPduType::ErrorReport),
129 _ => None,
130 }
131 }
132
133 pub fn to_u8(self) -> u8 {
135 self as u8
136 }
137}
138
139impl From<RtrPduType> for u8 {
140 fn from(v: RtrPduType) -> Self {
141 v as u8
142 }
143}
144
145impl TryFrom<u8> for RtrPduType {
146 type Error = u8;
147
148 fn try_from(value: u8) -> Result<Self, Self::Error> {
149 RtrPduType::from_u8(value).ok_or(value)
150 }
151}
152
153#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
157#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
158#[repr(u16)]
159pub enum RtrErrorCode {
160 CorruptData = 0,
162 InternalError = 1,
164 NoDataAvailable = 2,
166 InvalidRequest = 3,
168 UnsupportedProtocolVersion = 4,
170 UnsupportedPduType = 5,
172 WithdrawalOfUnknownRecord = 6,
174 DuplicateAnnouncementReceived = 7,
176 UnexpectedProtocolVersion = 8,
178}
179
180impl RtrErrorCode {
181 pub fn from_u16(value: u16) -> Option<Self> {
183 match value {
184 0 => Some(RtrErrorCode::CorruptData),
185 1 => Some(RtrErrorCode::InternalError),
186 2 => Some(RtrErrorCode::NoDataAvailable),
187 3 => Some(RtrErrorCode::InvalidRequest),
188 4 => Some(RtrErrorCode::UnsupportedProtocolVersion),
189 5 => Some(RtrErrorCode::UnsupportedPduType),
190 6 => Some(RtrErrorCode::WithdrawalOfUnknownRecord),
191 7 => Some(RtrErrorCode::DuplicateAnnouncementReceived),
192 8 => Some(RtrErrorCode::UnexpectedProtocolVersion),
193 _ => None,
194 }
195 }
196
197 pub fn to_u16(self) -> u16 {
199 self as u16
200 }
201}
202
203impl From<RtrErrorCode> for u16 {
204 fn from(v: RtrErrorCode) -> Self {
205 v as u16
206 }
207}
208
209impl TryFrom<u16> for RtrErrorCode {
210 type Error = u16;
211
212 fn try_from(value: u16) -> Result<Self, Self::Error> {
213 RtrErrorCode::from_u16(value).ok_or(value)
214 }
215}
216
217#[derive(Debug, Clone, PartialEq, Eq, Hash)]
228#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
229pub struct RtrSerialNotify {
230 pub version: RtrProtocolVersion,
232 pub session_id: u16,
234 pub serial_number: u32,
236}
237
238#[derive(Debug, Clone, PartialEq, Eq, Hash)]
244#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
245pub struct RtrSerialQuery {
246 pub version: RtrProtocolVersion,
248 pub session_id: u16,
250 pub serial_number: u32,
252}
253
254impl RtrSerialQuery {
255 pub fn new(version: RtrProtocolVersion, session_id: u16, serial_number: u32) -> Self {
257 Self {
258 version,
259 session_id,
260 serial_number,
261 }
262 }
263}
264
265#[derive(Debug, Clone, PartialEq, Eq, Hash)]
271#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
272pub struct RtrResetQuery {
273 pub version: RtrProtocolVersion,
275}
276
277impl RtrResetQuery {
278 pub fn new(version: RtrProtocolVersion) -> Self {
280 Self { version }
281 }
282
283 pub fn new_v1() -> Self {
285 Self::new(RtrProtocolVersion::V1)
286 }
287
288 pub fn new_v0() -> Self {
290 Self::new(RtrProtocolVersion::V0)
291 }
292}
293
294impl Default for RtrResetQuery {
295 fn default() -> Self {
296 Self::new_v1()
297 }
298}
299
300#[derive(Debug, Clone, PartialEq, Eq, Hash)]
308#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
309pub struct RtrCacheResponse {
310 pub version: RtrProtocolVersion,
312 pub session_id: u16,
314}
315
316#[derive(Debug, Clone, PartialEq, Eq, Hash)]
322#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
323pub struct RtrIPv4Prefix {
324 pub version: RtrProtocolVersion,
326 pub flags: u8,
328 pub prefix_length: u8,
330 pub max_length: u8,
332 pub prefix: Ipv4Addr,
334 pub asn: Asn,
336}
337
338impl RtrIPv4Prefix {
339 #[inline]
341 pub fn is_announcement(&self) -> bool {
342 self.flags & 0x01 != 0
343 }
344
345 #[inline]
347 pub fn is_withdrawal(&self) -> bool {
348 !self.is_announcement()
349 }
350}
351
352#[derive(Debug, Clone, PartialEq, Eq, Hash)]
358#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
359pub struct RtrIPv6Prefix {
360 pub version: RtrProtocolVersion,
362 pub flags: u8,
364 pub prefix_length: u8,
366 pub max_length: u8,
368 pub prefix: Ipv6Addr,
370 pub asn: Asn,
372}
373
374impl RtrIPv6Prefix {
375 #[inline]
377 pub fn is_announcement(&self) -> bool {
378 self.flags & 0x01 != 0
379 }
380
381 #[inline]
383 pub fn is_withdrawal(&self) -> bool {
384 !self.is_announcement()
385 }
386}
387
388#[derive(Debug, Clone, PartialEq, Eq, Hash)]
396#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
397pub struct RtrEndOfData {
398 pub version: RtrProtocolVersion,
400 pub session_id: u16,
402 pub serial_number: u32,
404 pub refresh_interval: Option<u32>,
406 pub retry_interval: Option<u32>,
408 pub expire_interval: Option<u32>,
410}
411
412impl RtrEndOfData {
413 pub const DEFAULT_REFRESH: u32 = 3600;
415 pub const DEFAULT_RETRY: u32 = 600;
417 pub const DEFAULT_EXPIRE: u32 = 7200;
419
420 pub fn refresh_interval_or_default(&self) -> u32 {
422 self.refresh_interval.unwrap_or(Self::DEFAULT_REFRESH)
423 }
424
425 pub fn retry_interval_or_default(&self) -> u32 {
427 self.retry_interval.unwrap_or(Self::DEFAULT_RETRY)
428 }
429
430 pub fn expire_interval_or_default(&self) -> u32 {
432 self.expire_interval.unwrap_or(Self::DEFAULT_EXPIRE)
433 }
434}
435
436#[derive(Debug, Clone, PartialEq, Eq, Hash)]
444#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
445pub struct RtrCacheReset {
446 pub version: RtrProtocolVersion,
448}
449
450#[derive(Debug, Clone, PartialEq, Eq, Hash)]
456#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
457pub struct RtrRouterKey {
458 pub version: RtrProtocolVersion,
460 pub flags: u8,
462 pub subject_key_identifier: [u8; 20],
464 pub asn: Asn,
466 pub subject_public_key_info: Vec<u8>,
468}
469
470impl RtrRouterKey {
471 #[inline]
473 pub fn is_announcement(&self) -> bool {
474 self.flags & 0x01 != 0
475 }
476
477 #[inline]
479 pub fn is_withdrawal(&self) -> bool {
480 !self.is_announcement()
481 }
482}
483
484#[derive(Debug, Clone, PartialEq, Eq, Hash)]
490#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
491pub struct RtrErrorReport {
492 pub version: RtrProtocolVersion,
494 pub error_code: RtrErrorCode,
496 pub erroneous_pdu: Vec<u8>,
498 pub error_text: String,
500}
501
502impl RtrErrorReport {
503 pub fn new(
505 version: RtrProtocolVersion,
506 error_code: RtrErrorCode,
507 erroneous_pdu: Vec<u8>,
508 error_text: String,
509 ) -> Self {
510 Self {
511 version,
512 error_code,
513 erroneous_pdu,
514 error_text,
515 }
516 }
517
518 pub fn unsupported_version(version: RtrProtocolVersion, erroneous_pdu: Vec<u8>) -> Self {
520 Self::new(
521 version,
522 RtrErrorCode::UnsupportedProtocolVersion,
523 erroneous_pdu,
524 "Unsupported protocol version".to_string(),
525 )
526 }
527
528 pub fn unsupported_pdu_type(version: RtrProtocolVersion, erroneous_pdu: Vec<u8>) -> Self {
530 Self::new(
531 version,
532 RtrErrorCode::UnsupportedPduType,
533 erroneous_pdu,
534 "Unsupported PDU type".to_string(),
535 )
536 }
537
538 pub fn corrupt_data(
540 version: RtrProtocolVersion,
541 erroneous_pdu: Vec<u8>,
542 message: &str,
543 ) -> Self {
544 Self::new(
545 version,
546 RtrErrorCode::CorruptData,
547 erroneous_pdu,
548 message.to_string(),
549 )
550 }
551}
552
553#[derive(Debug, Clone, PartialEq, Eq)]
562#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
563pub enum RtrPdu {
564 SerialNotify(RtrSerialNotify),
566 SerialQuery(RtrSerialQuery),
568 ResetQuery(RtrResetQuery),
570 CacheResponse(RtrCacheResponse),
572 IPv4Prefix(RtrIPv4Prefix),
574 IPv6Prefix(RtrIPv6Prefix),
576 EndOfData(RtrEndOfData),
578 CacheReset(RtrCacheReset),
580 RouterKey(RtrRouterKey),
582 ErrorReport(RtrErrorReport),
584}
585
586impl RtrPdu {
587 pub fn pdu_type(&self) -> RtrPduType {
589 match self {
590 RtrPdu::SerialNotify(_) => RtrPduType::SerialNotify,
591 RtrPdu::SerialQuery(_) => RtrPduType::SerialQuery,
592 RtrPdu::ResetQuery(_) => RtrPduType::ResetQuery,
593 RtrPdu::CacheResponse(_) => RtrPduType::CacheResponse,
594 RtrPdu::IPv4Prefix(_) => RtrPduType::IPv4Prefix,
595 RtrPdu::IPv6Prefix(_) => RtrPduType::IPv6Prefix,
596 RtrPdu::EndOfData(_) => RtrPduType::EndOfData,
597 RtrPdu::CacheReset(_) => RtrPduType::CacheReset,
598 RtrPdu::RouterKey(_) => RtrPduType::RouterKey,
599 RtrPdu::ErrorReport(_) => RtrPduType::ErrorReport,
600 }
601 }
602
603 pub fn version(&self) -> RtrProtocolVersion {
605 match self {
606 RtrPdu::SerialNotify(p) => p.version,
607 RtrPdu::SerialQuery(p) => p.version,
608 RtrPdu::ResetQuery(p) => p.version,
609 RtrPdu::CacheResponse(p) => p.version,
610 RtrPdu::IPv4Prefix(p) => p.version,
611 RtrPdu::IPv6Prefix(p) => p.version,
612 RtrPdu::EndOfData(p) => p.version,
613 RtrPdu::CacheReset(p) => p.version,
614 RtrPdu::RouterKey(p) => p.version,
615 RtrPdu::ErrorReport(p) => p.version,
616 }
617 }
618}
619
620impl From<RtrSerialNotify> for RtrPdu {
621 fn from(pdu: RtrSerialNotify) -> Self {
622 RtrPdu::SerialNotify(pdu)
623 }
624}
625
626impl From<RtrSerialQuery> for RtrPdu {
627 fn from(pdu: RtrSerialQuery) -> Self {
628 RtrPdu::SerialQuery(pdu)
629 }
630}
631
632impl From<RtrResetQuery> for RtrPdu {
633 fn from(pdu: RtrResetQuery) -> Self {
634 RtrPdu::ResetQuery(pdu)
635 }
636}
637
638impl From<RtrCacheResponse> for RtrPdu {
639 fn from(pdu: RtrCacheResponse) -> Self {
640 RtrPdu::CacheResponse(pdu)
641 }
642}
643
644impl From<RtrIPv4Prefix> for RtrPdu {
645 fn from(pdu: RtrIPv4Prefix) -> Self {
646 RtrPdu::IPv4Prefix(pdu)
647 }
648}
649
650impl From<RtrIPv6Prefix> for RtrPdu {
651 fn from(pdu: RtrIPv6Prefix) -> Self {
652 RtrPdu::IPv6Prefix(pdu)
653 }
654}
655
656impl From<RtrEndOfData> for RtrPdu {
657 fn from(pdu: RtrEndOfData) -> Self {
658 RtrPdu::EndOfData(pdu)
659 }
660}
661
662impl From<RtrCacheReset> for RtrPdu {
663 fn from(pdu: RtrCacheReset) -> Self {
664 RtrPdu::CacheReset(pdu)
665 }
666}
667
668impl From<RtrRouterKey> for RtrPdu {
669 fn from(pdu: RtrRouterKey) -> Self {
670 RtrPdu::RouterKey(pdu)
671 }
672}
673
674impl From<RtrErrorReport> for RtrPdu {
675 fn from(pdu: RtrErrorReport) -> Self {
676 RtrPdu::ErrorReport(pdu)
677 }
678}
679
680#[cfg(test)]
685mod tests {
686 use super::*;
687
688 #[test]
689 fn test_protocol_version_conversion() {
690 assert_eq!(RtrProtocolVersion::from_u8(0), Some(RtrProtocolVersion::V0));
691 assert_eq!(RtrProtocolVersion::from_u8(1), Some(RtrProtocolVersion::V1));
692 assert_eq!(RtrProtocolVersion::from_u8(2), None);
693
694 assert_eq!(RtrProtocolVersion::V0.to_u8(), 0);
695 assert_eq!(RtrProtocolVersion::V1.to_u8(), 1);
696 }
697
698 #[test]
699 fn test_pdu_type_conversion() {
700 assert_eq!(RtrPduType::from_u8(0), Some(RtrPduType::SerialNotify));
701 assert_eq!(RtrPduType::from_u8(1), Some(RtrPduType::SerialQuery));
702 assert_eq!(RtrPduType::from_u8(4), Some(RtrPduType::IPv4Prefix));
703 assert_eq!(RtrPduType::from_u8(5), None); assert_eq!(RtrPduType::from_u8(6), Some(RtrPduType::IPv6Prefix));
705 assert_eq!(RtrPduType::from_u8(9), Some(RtrPduType::RouterKey));
706
707 assert_eq!(RtrPduType::SerialNotify.to_u8(), 0);
708 assert_eq!(RtrPduType::IPv6Prefix.to_u8(), 6);
709 }
710
711 #[test]
712 fn test_error_code_conversion() {
713 assert_eq!(RtrErrorCode::from_u16(0), Some(RtrErrorCode::CorruptData));
714 assert_eq!(
715 RtrErrorCode::from_u16(4),
716 Some(RtrErrorCode::UnsupportedProtocolVersion)
717 );
718 assert_eq!(
719 RtrErrorCode::from_u16(8),
720 Some(RtrErrorCode::UnexpectedProtocolVersion)
721 );
722 assert_eq!(RtrErrorCode::from_u16(9), None);
723
724 assert_eq!(RtrErrorCode::CorruptData.to_u16(), 0);
725 assert_eq!(RtrErrorCode::UnsupportedProtocolVersion.to_u16(), 4);
726 }
727
728 #[test]
729 fn test_ipv4_prefix_flags() {
730 let announcement = RtrIPv4Prefix {
731 version: RtrProtocolVersion::V1,
732 flags: 1,
733 prefix_length: 24,
734 max_length: 24,
735 prefix: Ipv4Addr::new(192, 0, 2, 0),
736 asn: 65001.into(),
737 };
738 assert!(announcement.is_announcement());
739 assert!(!announcement.is_withdrawal());
740
741 let withdrawal = RtrIPv4Prefix {
742 version: RtrProtocolVersion::V1,
743 flags: 0,
744 prefix_length: 24,
745 max_length: 24,
746 prefix: Ipv4Addr::new(192, 0, 2, 0),
747 asn: 65001.into(),
748 };
749 assert!(!withdrawal.is_announcement());
750 assert!(withdrawal.is_withdrawal());
751 }
752
753 #[test]
754 fn test_ipv6_prefix_flags() {
755 let announcement = RtrIPv6Prefix {
756 version: RtrProtocolVersion::V1,
757 flags: 1,
758 prefix_length: 48,
759 max_length: 48,
760 prefix: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
761 asn: 65001.into(),
762 };
763 assert!(announcement.is_announcement());
764 assert!(!announcement.is_withdrawal());
765 }
766
767 #[test]
768 fn test_router_key_flags() {
769 let announcement = RtrRouterKey {
770 version: RtrProtocolVersion::V1,
771 flags: 1,
772 subject_key_identifier: [0; 20],
773 asn: 65001.into(),
774 subject_public_key_info: vec![1, 2, 3],
775 };
776 assert!(announcement.is_announcement());
777 assert!(!announcement.is_withdrawal());
778 }
779
780 #[test]
781 fn test_end_of_data_defaults() {
782 assert_eq!(RtrEndOfData::DEFAULT_REFRESH, 3600);
783 assert_eq!(RtrEndOfData::DEFAULT_RETRY, 600);
784 assert_eq!(RtrEndOfData::DEFAULT_EXPIRE, 7200);
785
786 let eod = RtrEndOfData {
787 version: RtrProtocolVersion::V0,
788 session_id: 1,
789 serial_number: 100,
790 refresh_interval: None,
791 retry_interval: None,
792 expire_interval: None,
793 };
794 assert_eq!(eod.refresh_interval_or_default(), 3600);
795 assert_eq!(eod.retry_interval_or_default(), 600);
796 assert_eq!(eod.expire_interval_or_default(), 7200);
797
798 let eod_v1 = RtrEndOfData {
799 version: RtrProtocolVersion::V1,
800 session_id: 1,
801 serial_number: 100,
802 refresh_interval: Some(1800),
803 retry_interval: Some(300),
804 expire_interval: Some(3600),
805 };
806 assert_eq!(eod_v1.refresh_interval_or_default(), 1800);
807 assert_eq!(eod_v1.retry_interval_or_default(), 300);
808 assert_eq!(eod_v1.expire_interval_or_default(), 3600);
809 }
810
811 #[test]
812 fn test_reset_query_constructors() {
813 let v1 = RtrResetQuery::new_v1();
814 assert_eq!(v1.version, RtrProtocolVersion::V1);
815
816 let v0 = RtrResetQuery::new_v0();
817 assert_eq!(v0.version, RtrProtocolVersion::V0);
818
819 let default = RtrResetQuery::default();
820 assert_eq!(default.version, RtrProtocolVersion::V1);
821 }
822
823 #[test]
824 fn test_pdu_enum_type() {
825 let pdu = RtrPdu::SerialNotify(RtrSerialNotify {
826 version: RtrProtocolVersion::V1,
827 session_id: 1,
828 serial_number: 100,
829 });
830 assert_eq!(pdu.pdu_type(), RtrPduType::SerialNotify);
831 assert_eq!(pdu.version(), RtrProtocolVersion::V1);
832 }
833
834 #[test]
835 fn test_pdu_enum_all_types_and_versions() {
836 let pdus = vec![
838 (
839 RtrPdu::SerialNotify(RtrSerialNotify {
840 version: RtrProtocolVersion::V0,
841 session_id: 1,
842 serial_number: 100,
843 }),
844 RtrPduType::SerialNotify,
845 RtrProtocolVersion::V0,
846 ),
847 (
848 RtrPdu::SerialQuery(RtrSerialQuery {
849 version: RtrProtocolVersion::V1,
850 session_id: 2,
851 serial_number: 200,
852 }),
853 RtrPduType::SerialQuery,
854 RtrProtocolVersion::V1,
855 ),
856 (
857 RtrPdu::ResetQuery(RtrResetQuery {
858 version: RtrProtocolVersion::V0,
859 }),
860 RtrPduType::ResetQuery,
861 RtrProtocolVersion::V0,
862 ),
863 (
864 RtrPdu::CacheResponse(RtrCacheResponse {
865 version: RtrProtocolVersion::V1,
866 session_id: 3,
867 }),
868 RtrPduType::CacheResponse,
869 RtrProtocolVersion::V1,
870 ),
871 (
872 RtrPdu::IPv4Prefix(RtrIPv4Prefix {
873 version: RtrProtocolVersion::V0,
874 flags: 1,
875 prefix_length: 24,
876 max_length: 24,
877 prefix: Ipv4Addr::new(10, 0, 0, 0),
878 asn: 65000.into(),
879 }),
880 RtrPduType::IPv4Prefix,
881 RtrProtocolVersion::V0,
882 ),
883 (
884 RtrPdu::IPv6Prefix(RtrIPv6Prefix {
885 version: RtrProtocolVersion::V1,
886 flags: 0,
887 prefix_length: 48,
888 max_length: 64,
889 prefix: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
890 asn: 65001.into(),
891 }),
892 RtrPduType::IPv6Prefix,
893 RtrProtocolVersion::V1,
894 ),
895 (
896 RtrPdu::EndOfData(RtrEndOfData {
897 version: RtrProtocolVersion::V0,
898 session_id: 4,
899 serial_number: 300,
900 refresh_interval: None,
901 retry_interval: None,
902 expire_interval: None,
903 }),
904 RtrPduType::EndOfData,
905 RtrProtocolVersion::V0,
906 ),
907 (
908 RtrPdu::CacheReset(RtrCacheReset {
909 version: RtrProtocolVersion::V1,
910 }),
911 RtrPduType::CacheReset,
912 RtrProtocolVersion::V1,
913 ),
914 (
915 RtrPdu::RouterKey(RtrRouterKey {
916 version: RtrProtocolVersion::V1,
917 flags: 1,
918 subject_key_identifier: [0; 20],
919 asn: 65002.into(),
920 subject_public_key_info: vec![],
921 }),
922 RtrPduType::RouterKey,
923 RtrProtocolVersion::V1,
924 ),
925 (
926 RtrPdu::ErrorReport(RtrErrorReport {
927 version: RtrProtocolVersion::V0,
928 error_code: RtrErrorCode::InternalError,
929 erroneous_pdu: vec![],
930 error_text: String::new(),
931 }),
932 RtrPduType::ErrorReport,
933 RtrProtocolVersion::V0,
934 ),
935 ];
936
937 for (pdu, expected_type, expected_version) in pdus {
938 assert_eq!(pdu.pdu_type(), expected_type);
939 assert_eq!(pdu.version(), expected_version);
940 }
941 }
942
943 #[test]
944 fn test_pdu_from_impls() {
945 let query = RtrResetQuery::new_v1();
946 let pdu: RtrPdu = query.into();
947 assert_eq!(pdu.pdu_type(), RtrPduType::ResetQuery);
948 }
949
950 #[test]
951 fn test_all_pdu_from_impls() {
952 let notify = RtrSerialNotify {
954 version: RtrProtocolVersion::V1,
955 session_id: 1,
956 serial_number: 100,
957 };
958 let pdu: RtrPdu = notify.into();
959 assert!(matches!(pdu, RtrPdu::SerialNotify(_)));
960
961 let query = RtrSerialQuery::new(RtrProtocolVersion::V1, 1, 100);
962 let pdu: RtrPdu = query.into();
963 assert!(matches!(pdu, RtrPdu::SerialQuery(_)));
964
965 let response = RtrCacheResponse {
966 version: RtrProtocolVersion::V1,
967 session_id: 1,
968 };
969 let pdu: RtrPdu = response.into();
970 assert!(matches!(pdu, RtrPdu::CacheResponse(_)));
971
972 let prefix4 = RtrIPv4Prefix {
973 version: RtrProtocolVersion::V1,
974 flags: 1,
975 prefix_length: 24,
976 max_length: 24,
977 prefix: Ipv4Addr::new(10, 0, 0, 0),
978 asn: 65000.into(),
979 };
980 let pdu: RtrPdu = prefix4.into();
981 assert!(matches!(pdu, RtrPdu::IPv4Prefix(_)));
982
983 let prefix6 = RtrIPv6Prefix {
984 version: RtrProtocolVersion::V1,
985 flags: 1,
986 prefix_length: 48,
987 max_length: 48,
988 prefix: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
989 asn: 65000.into(),
990 };
991 let pdu: RtrPdu = prefix6.into();
992 assert!(matches!(pdu, RtrPdu::IPv6Prefix(_)));
993
994 let eod = RtrEndOfData {
995 version: RtrProtocolVersion::V1,
996 session_id: 1,
997 serial_number: 100,
998 refresh_interval: Some(3600),
999 retry_interval: Some(600),
1000 expire_interval: Some(7200),
1001 };
1002 let pdu: RtrPdu = eod.into();
1003 assert!(matches!(pdu, RtrPdu::EndOfData(_)));
1004
1005 let reset = RtrCacheReset {
1006 version: RtrProtocolVersion::V1,
1007 };
1008 let pdu: RtrPdu = reset.into();
1009 assert!(matches!(pdu, RtrPdu::CacheReset(_)));
1010
1011 let key = RtrRouterKey {
1012 version: RtrProtocolVersion::V1,
1013 flags: 1,
1014 subject_key_identifier: [0; 20],
1015 asn: 65000.into(),
1016 subject_public_key_info: vec![],
1017 };
1018 let pdu: RtrPdu = key.into();
1019 assert!(matches!(pdu, RtrPdu::RouterKey(_)));
1020
1021 let error = RtrErrorReport::new(
1022 RtrProtocolVersion::V1,
1023 RtrErrorCode::InternalError,
1024 vec![],
1025 String::new(),
1026 );
1027 let pdu: RtrPdu = error.into();
1028 assert!(matches!(pdu, RtrPdu::ErrorReport(_)));
1029 }
1030
1031 #[test]
1032 fn test_error_report_constructors() {
1033 let err = RtrErrorReport::unsupported_version(RtrProtocolVersion::V0, vec![1, 2, 3]);
1034 assert_eq!(err.error_code, RtrErrorCode::UnsupportedProtocolVersion);
1035 assert_eq!(err.error_text, "Unsupported protocol version");
1036
1037 let err = RtrErrorReport::unsupported_pdu_type(RtrProtocolVersion::V1, vec![4, 5, 6]);
1038 assert_eq!(err.error_code, RtrErrorCode::UnsupportedPduType);
1039 assert_eq!(err.error_text, "Unsupported PDU type");
1040
1041 let err = RtrErrorReport::corrupt_data(RtrProtocolVersion::V1, vec![], "test error");
1042 assert_eq!(err.error_code, RtrErrorCode::CorruptData);
1043 assert_eq!(err.error_text, "test error");
1044
1045 let err = RtrErrorReport::new(
1046 RtrProtocolVersion::V0,
1047 RtrErrorCode::NoDataAvailable,
1048 vec![7, 8, 9],
1049 "Custom error".to_string(),
1050 );
1051 assert_eq!(err.version, RtrProtocolVersion::V0);
1052 assert_eq!(err.error_code, RtrErrorCode::NoDataAvailable);
1053 assert_eq!(err.erroneous_pdu, vec![7, 8, 9]);
1054 assert_eq!(err.error_text, "Custom error");
1055 }
1056
1057 #[test]
1058 #[cfg(feature = "serde")]
1059 fn test_serde_roundtrip() {
1060 let prefix = RtrIPv4Prefix {
1061 version: RtrProtocolVersion::V1,
1062 flags: 1,
1063 prefix_length: 24,
1064 max_length: 24,
1065 prefix: Ipv4Addr::new(192, 0, 2, 0),
1066 asn: 65001.into(),
1067 };
1068
1069 let json = serde_json::to_string(&prefix).unwrap();
1070 let decoded: RtrIPv4Prefix = serde_json::from_str(&json).unwrap();
1071 assert_eq!(prefix, decoded);
1072 }
1073
1074 #[test]
1075 fn test_try_from_protocol_version() {
1076 let v0: Result<RtrProtocolVersion, u8> = 0u8.try_into();
1078 assert_eq!(v0, Ok(RtrProtocolVersion::V0));
1079
1080 let v1: Result<RtrProtocolVersion, u8> = 1u8.try_into();
1081 assert_eq!(v1, Ok(RtrProtocolVersion::V1));
1082
1083 let invalid: Result<RtrProtocolVersion, u8> = 99u8.try_into();
1084 assert_eq!(invalid, Err(99u8));
1085
1086 let byte: u8 = RtrProtocolVersion::V0.into();
1088 assert_eq!(byte, 0);
1089 let byte: u8 = RtrProtocolVersion::V1.into();
1090 assert_eq!(byte, 1);
1091 }
1092
1093 #[test]
1094 fn test_try_from_pdu_type() {
1095 let serial_notify: Result<RtrPduType, u8> = 0u8.try_into();
1097 assert_eq!(serial_notify, Ok(RtrPduType::SerialNotify));
1098
1099 let error_report: Result<RtrPduType, u8> = 10u8.try_into();
1100 assert_eq!(error_report, Ok(RtrPduType::ErrorReport));
1101
1102 let invalid: Result<RtrPduType, u8> = 5u8.try_into(); assert_eq!(invalid, Err(5u8));
1104
1105 let invalid: Result<RtrPduType, u8> = 255u8.try_into();
1106 assert_eq!(invalid, Err(255u8));
1107
1108 let byte: u8 = RtrPduType::SerialNotify.into();
1110 assert_eq!(byte, 0);
1111 let byte: u8 = RtrPduType::IPv6Prefix.into();
1112 assert_eq!(byte, 6);
1113 let byte: u8 = RtrPduType::ErrorReport.into();
1114 assert_eq!(byte, 10);
1115 }
1116
1117 #[test]
1118 fn test_try_from_error_code() {
1119 let corrupt: Result<RtrErrorCode, u16> = 0u16.try_into();
1121 assert_eq!(corrupt, Ok(RtrErrorCode::CorruptData));
1122
1123 let unexpected: Result<RtrErrorCode, u16> = 8u16.try_into();
1124 assert_eq!(unexpected, Ok(RtrErrorCode::UnexpectedProtocolVersion));
1125
1126 let invalid: Result<RtrErrorCode, u16> = 9u16.try_into();
1127 assert_eq!(invalid, Err(9u16));
1128
1129 let invalid: Result<RtrErrorCode, u16> = 1000u16.try_into();
1130 assert_eq!(invalid, Err(1000u16));
1131
1132 let code: u16 = RtrErrorCode::CorruptData.into();
1134 assert_eq!(code, 0);
1135 let code: u16 = RtrErrorCode::UnexpectedProtocolVersion.into();
1136 assert_eq!(code, 8);
1137 }
1138
1139 #[test]
1140 fn test_ipv6_prefix_withdrawal() {
1141 let withdrawal = RtrIPv6Prefix {
1142 version: RtrProtocolVersion::V1,
1143 flags: 0, prefix_length: 48,
1145 max_length: 64,
1146 prefix: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
1147 asn: 65001.into(),
1148 };
1149 assert!(!withdrawal.is_announcement());
1150 assert!(withdrawal.is_withdrawal());
1151 }
1152
1153 #[test]
1154 fn test_router_key_withdrawal() {
1155 let withdrawal = RtrRouterKey {
1156 version: RtrProtocolVersion::V1,
1157 flags: 0, subject_key_identifier: [1; 20],
1159 asn: 65001.into(),
1160 subject_public_key_info: vec![0xAB, 0xCD],
1161 };
1162 assert!(!withdrawal.is_announcement());
1163 assert!(withdrawal.is_withdrawal());
1164 }
1165
1166 #[test]
1167 fn test_serial_query_new() {
1168 let query = RtrSerialQuery::new(RtrProtocolVersion::V0, 12345, 67890);
1169 assert_eq!(query.version, RtrProtocolVersion::V0);
1170 assert_eq!(query.session_id, 12345);
1171 assert_eq!(query.serial_number, 67890);
1172 }
1173
1174 #[test]
1175 fn test_reset_query_new() {
1176 let v0 = RtrResetQuery::new(RtrProtocolVersion::V0);
1177 assert_eq!(v0.version, RtrProtocolVersion::V0);
1178
1179 let v1 = RtrResetQuery::new(RtrProtocolVersion::V1);
1180 assert_eq!(v1.version, RtrProtocolVersion::V1);
1181 }
1182
1183 #[test]
1184 fn test_protocol_version_default() {
1185 let default = RtrProtocolVersion::default();
1186 assert_eq!(default, RtrProtocolVersion::V1);
1187 }
1188
1189 #[test]
1190 fn test_all_error_codes() {
1191 let codes = [
1193 (0u16, RtrErrorCode::CorruptData),
1194 (1u16, RtrErrorCode::InternalError),
1195 (2u16, RtrErrorCode::NoDataAvailable),
1196 (3u16, RtrErrorCode::InvalidRequest),
1197 (4u16, RtrErrorCode::UnsupportedProtocolVersion),
1198 (5u16, RtrErrorCode::UnsupportedPduType),
1199 (6u16, RtrErrorCode::WithdrawalOfUnknownRecord),
1200 (7u16, RtrErrorCode::DuplicateAnnouncementReceived),
1201 (8u16, RtrErrorCode::UnexpectedProtocolVersion),
1202 ];
1203
1204 for (value, expected) in codes {
1205 assert_eq!(RtrErrorCode::from_u16(value), Some(expected));
1206 assert_eq!(expected.to_u16(), value);
1207 }
1208 }
1209
1210 #[test]
1211 fn test_all_pdu_types() {
1212 let types = [
1214 (0u8, RtrPduType::SerialNotify),
1215 (1u8, RtrPduType::SerialQuery),
1216 (2u8, RtrPduType::ResetQuery),
1217 (3u8, RtrPduType::CacheResponse),
1218 (4u8, RtrPduType::IPv4Prefix),
1219 (6u8, RtrPduType::IPv6Prefix),
1220 (7u8, RtrPduType::EndOfData),
1221 (8u8, RtrPduType::CacheReset),
1222 (9u8, RtrPduType::RouterKey),
1223 (10u8, RtrPduType::ErrorReport),
1224 ];
1225
1226 for (value, expected) in types {
1227 assert_eq!(RtrPduType::from_u8(value), Some(expected));
1228 assert_eq!(expected.to_u8(), value);
1229 }
1230
1231 assert_eq!(RtrPduType::from_u8(5), None);
1233 }
1234}