bgpkit_parser/parser/rpki/
rtr.rs

1//! RPKI-to-Router (RTR) Protocol Parser
2//!
3//! This module provides parsing and encoding functions for RTR protocol PDUs
4//! as defined in RFC 6810 (v0) and RFC 8210 (v1).
5//!
6//! # Parsing
7//!
8//! ```rust
9//! use bgpkit_parser::parser::rpki::rtr::{parse_rtr_pdu, read_rtr_pdu};
10//! use bgpkit_parser::models::rpki::rtr::*;
11//!
12//! // Parse from a byte slice
13//! let bytes = [1, 2, 0, 0, 0, 0, 0, 8]; // Reset Query v1
14//! let (pdu, consumed) = parse_rtr_pdu(&bytes).unwrap();
15//! assert_eq!(consumed, 8);
16//! ```
17//!
18//! # Encoding
19//!
20//! ```rust
21//! use bgpkit_parser::parser::rpki::rtr::RtrEncode;
22//! use bgpkit_parser::models::rpki::rtr::*;
23//!
24//! let query = RtrResetQuery::new_v1();
25//! let bytes = query.encode();
26//! assert_eq!(bytes.len(), 8);
27//! ```
28
29use crate::models::rpki::rtr::*;
30use crate::models::Asn;
31use std::fmt;
32use std::io::{self, Read};
33use std::net::{Ipv4Addr, Ipv6Addr};
34
35// =============================================================================
36// Error Types
37// =============================================================================
38
39/// Errors that can occur during RTR PDU parsing or encoding
40#[derive(Debug)]
41pub enum RtrError {
42    /// I/O error during reading
43    IoError(io::Error),
44    /// PDU is incomplete (need more data)
45    IncompletePdu {
46        /// Number of bytes available
47        available: usize,
48        /// Number of bytes needed
49        needed: usize,
50    },
51    /// Invalid PDU type
52    InvalidPduType(u8),
53    /// Invalid protocol version
54    InvalidProtocolVersion(u8),
55    /// Invalid error code
56    InvalidErrorCode(u16),
57    /// Invalid PDU length
58    InvalidLength {
59        /// Expected length
60        expected: u32,
61        /// Actual length in header
62        actual: u32,
63        /// PDU type
64        pdu_type: u8,
65    },
66    /// Invalid prefix length
67    InvalidPrefixLength {
68        /// Prefix length
69        prefix_len: u8,
70        /// Maximum length
71        max_len: u8,
72        /// Maximum allowed for address family (32 for IPv4, 128 for IPv6)
73        max_allowed: u8,
74    },
75    /// Invalid UTF-8 in error text
76    InvalidUtf8,
77    /// Router Key PDU in v0 (not supported)
78    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
138// =============================================================================
139// PDU Length Constants
140// =============================================================================
141
142/// RTR PDU header length (common to all PDUs)
143pub const RTR_HEADER_LEN: usize = 8;
144
145/// Serial Notify PDU length
146pub const RTR_SERIAL_NOTIFY_LEN: u32 = 12;
147
148/// Serial Query PDU length
149pub const RTR_SERIAL_QUERY_LEN: u32 = 12;
150
151/// Reset Query PDU length
152pub const RTR_RESET_QUERY_LEN: u32 = 8;
153
154/// Cache Response PDU length
155pub const RTR_CACHE_RESPONSE_LEN: u32 = 8;
156
157/// IPv4 Prefix PDU length
158pub const RTR_IPV4_PREFIX_LEN: u32 = 20;
159
160/// IPv6 Prefix PDU length
161pub const RTR_IPV6_PREFIX_LEN: u32 = 32;
162
163/// End of Data PDU length (v0)
164pub const RTR_END_OF_DATA_V0_LEN: u32 = 12;
165
166/// End of Data PDU length (v1)
167pub const RTR_END_OF_DATA_V1_LEN: u32 = 24;
168
169/// Cache Reset PDU length
170pub const RTR_CACHE_RESET_LEN: u32 = 8;
171
172/// Router Key PDU minimum length (header(8) + flags(1) + zero(1) + SKI(20) + ASN(4) = 34)
173pub const RTR_ROUTER_KEY_MIN_LEN: u32 = 34;
174
175// =============================================================================
176// Parsing Functions
177// =============================================================================
178
179/// Parse a single RTR PDU from a byte slice.
180///
181/// Returns the parsed PDU and the number of bytes consumed.
182///
183/// # Errors
184///
185/// Returns an error if the input is too short, contains invalid data,
186/// or references an unknown PDU type.
187///
188/// # Example
189///
190/// ```rust
191/// use bgpkit_parser::parser::rpki::rtr::parse_rtr_pdu;
192/// use bgpkit_parser::models::rpki::rtr::*;
193///
194/// // Reset Query PDU (v1)
195/// let bytes = [1, 2, 0, 0, 0, 0, 0, 8];
196/// let (pdu, consumed) = parse_rtr_pdu(&bytes).unwrap();
197/// assert!(matches!(pdu, RtrPdu::ResetQuery(_)));
198/// assert_eq!(consumed, 8);
199/// ```
200pub fn parse_rtr_pdu(input: &[u8]) -> Result<(RtrPdu, usize), RtrError> {
201    // Need at least the header
202    if input.len() < RTR_HEADER_LEN {
203        return Err(RtrError::IncompletePdu {
204            available: input.len(),
205            needed: RTR_HEADER_LEN,
206        });
207    }
208
209    // Parse header
210    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    // Validate we have enough data
216    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    // Parse version
225    let version = RtrProtocolVersion::from_u8(version_byte)
226        .ok_or(RtrError::InvalidProtocolVersion(version_byte))?;
227
228    // Parse PDU type
229    let pdu_type =
230        RtrPduType::from_u8(pdu_type_byte).ok_or(RtrError::InvalidPduType(pdu_type_byte))?;
231
232    // Parse based on PDU type
233    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            // input[11] is reserved/zero
273
274            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            // input[11] is reserved/zero
295
296            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            // Router Key is v1 only
351            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            // input[9] is zero
365            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            // SPKI is the rest of the PDU (34 bytes of header + fixed fields already parsed)
370            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            // Error Report has variable length
388            // Minimum: header (8) + length of encapsulated PDU (4) + length of error text (4) = 16
389            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            // Validate encapsulated PDU fits
404            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
447/// Read a single RTR PDU from a reader.
448///
449/// This function reads exactly one complete PDU from the reader.
450///
451/// # Errors
452///
453/// Returns an error if reading fails or the PDU is invalid.
454///
455/// # Example
456///
457/// ```rust,no_run
458/// use std::net::TcpStream;
459/// use bgpkit_parser::parser::rpki::rtr::read_rtr_pdu;
460///
461/// let mut stream = TcpStream::connect("rtr.example.com:8282").unwrap();
462/// let pdu = read_rtr_pdu(&mut stream).unwrap();
463/// ```
464pub fn read_rtr_pdu<R: Read>(reader: &mut R) -> Result<RtrPdu, RtrError> {
465    // Read header first
466    let mut header = [0u8; RTR_HEADER_LEN];
467    reader.read_exact(&mut header)?;
468
469    // Get length from header
470    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    // Allocate buffer for full PDU
481    let mut buffer = vec![0u8; length];
482    buffer[..RTR_HEADER_LEN].copy_from_slice(&header);
483
484    // Read remaining bytes
485    if length > RTR_HEADER_LEN {
486        reader.read_exact(&mut buffer[RTR_HEADER_LEN..])?;
487    }
488
489    // Parse the complete PDU
490    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
518// =============================================================================
519// Encoding Trait and Implementations
520// =============================================================================
521
522/// Trait for encoding RTR PDUs to bytes
523pub trait RtrEncode {
524    /// Encode this PDU to a byte vector
525    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]); // zero
558        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]); // zero
580        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); // zero
585        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]); // zero
597        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); // zero
602        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]); // zero
651        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]); // zero (session_id field is zero for Router Key)
663        buf.extend_from_slice(&length.to_be_bytes());
664        buf.push(self.flags);
665        buf.push(0); // zero
666        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// =============================================================================
708// Tests
709// =============================================================================
710
711#[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, // withdrawal
819            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, // Will use default when encoding
921            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                // Since v1 encoding always includes timing, they'll be the defaults
931                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); // 34 min + 3 SPKI
964
965        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        // Manually construct a Router Key PDU with v0 version
981        let mut bytes = vec![
982            0, // version 0
983            9, // type 9 (Router Key)
984            0, 0, // zero
985            0, 0, 0, 34, // length = 34 (minimum)
986            1,  // flags
987            0,  // zero
988        ];
989        bytes.extend_from_slice(&[0u8; 20]); // SKI
990        bytes.extend_from_slice(&[0, 0, 0, 1]); // ASN
991
992        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], // Some invalid PDU
1002            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]; // Too short
1042        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]; // Type 5 doesn't exist
1049        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]; // Version 99 doesn't exist
1056        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        // Reset Query with wrong length - need full buffer to match declared length
1063        let bytes = [1, 2, 0, 0, 0, 0, 0, 10, 0, 0]; // Length says 10, should be 8
1064        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        // IPv4 prefix with prefix_len > max_len
1071        let mut bytes = vec![
1072            1, // version
1073            4, // type (IPv4 Prefix)
1074            0, 0, // zero
1075            0, 0, 0, 20, // length
1076            1,  // flags
1077            25, // prefix_length (25)
1078            24, // max_length (24) - INVALID: prefix_len > max_len
1079            0,  // zero
1080        ];
1081        bytes.extend_from_slice(&[192, 0, 2, 0]); // prefix
1082        bytes.extend_from_slice(&[0, 0, 0, 1]); // ASN
1083
1084        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        // IPv4 prefix with max_len > 32
1091        let mut bytes = vec![
1092            1, // version
1093            4, // type (IPv4 Prefix)
1094            0, 0, // zero
1095            0, 0, 0, 20, // length
1096            1,  // flags
1097            24, // prefix_length
1098            33, // max_length (33) - INVALID: > 32 for IPv4
1099            0,  // zero
1100        ];
1101        bytes.extend_from_slice(&[192, 0, 2, 0]); // prefix
1102        bytes.extend_from_slice(&[0, 0, 0, 1]); // ASN
1103
1104        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        // Test that all PDU types can be encoded and decoded
1133        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        // Test Display for all RtrError variants
1211        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        // IoError should have a source
1274        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        // Other errors should not have a source
1281        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        // PDU with length less than header size
1306        let bytes = vec![
1307            1, // version
1308            2, // type (Reset Query)
1309            0, 0, // zero
1310            0, 0, 0, 4, // length = 4 (less than header)
1311        ];
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        // Error Report with invalid error code
1320        let bytes = vec![
1321            1,  // version
1322            10, // type (Error Report)
1323            0, 100, // error code = 100 (invalid)
1324            0, 0, 0, 16, // length = 16 (minimum)
1325            0, 0, 0, 0, // encapsulated PDU length = 0
1326            0, 0, 0, 0, // error text length = 0
1327        ];
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        // Error Report with invalid UTF-8 in error text
1335        let bytes = vec![
1336            1,  // version
1337            10, // type (Error Report)
1338            0, 0, // error code = 0
1339            0, 0, 0, 20, // length = 20
1340            0, 0, 0, 0, // encapsulated PDU length = 0
1341            0, 0, 0, 4, // error text length = 4
1342            0xFF, 0xFE, 0xFF, 0xFE, // invalid UTF-8
1343        ];
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        // Error Report with encapsulated PDU length exceeding bounds
1351        let bytes = vec![
1352            1,  // version
1353            10, // type (Error Report)
1354            0, 0, // error code = 0
1355            0, 0, 0, 16, // length = 16
1356            0, 0, 0, 100, // encapsulated PDU length = 100 (too large)
1357            0, 0, 0, 0, // error text length = 0
1358        ];
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        // Router Key with no SPKI (minimum length)
1366        let mut bytes = vec![
1367            1, // version
1368            9, // type (Router Key)
1369            0, 0, // zero
1370            0, 0, 0, 34, // length = 34 (minimum)
1371            1,  // flags
1372            0,  // zero
1373        ];
1374        bytes.extend_from_slice(&[0u8; 20]); // SKI
1375        bytes.extend_from_slice(&[0, 0, 0, 1]); // ASN = 1
1376
1377        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        // IPv6 prefix with max_len > 128
1390        let mut bytes = vec![
1391            1, // version
1392            6, // type (IPv6 Prefix)
1393            0, 0, // zero
1394            0, 0, 0, 32,  // length
1395            1,   // flags
1396            64,  // prefix_length
1397            129, // max_length (129) - INVALID: > 128 for IPv6
1398            0,   // zero
1399        ];
1400        bytes.extend_from_slice(&[0u8; 16]); // prefix
1401        bytes.extend_from_slice(&[0, 0, 0, 1]); // ASN
1402
1403        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        // Test encoding v0 PDUs
1410        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); // version 0
1417
1418        let response = RtrCacheResponse {
1419            version: RtrProtocolVersion::V0,
1420            session_id: 300,
1421        };
1422        let bytes = response.encode();
1423        assert_eq!(bytes[0], 0); // version 0
1424
1425        let reset = RtrCacheReset {
1426            version: RtrProtocolVersion::V0,
1427        };
1428        let bytes = reset.encode();
1429        assert_eq!(bytes[0], 0); // version 0
1430
1431        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); // version 0
1441        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); // version 0
1453        assert_eq!(bytes.len(), 32);
1454    }
1455
1456    #[test]
1457    fn test_read_multiple_pdus() {
1458        use std::io::Cursor;
1459
1460        // Create buffer with two PDUs
1461        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        // Read first PDU
1470        let pdu1 = read_rtr_pdu(&mut cursor).unwrap();
1471        assert!(matches!(pdu1, RtrPdu::ResetQuery(_)));
1472
1473        // Read second PDU
1474        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        // PDU followed by extra bytes - should only consume PDU length
1481        let query = RtrResetQuery::new_v1();
1482        let mut bytes = query.encode();
1483        bytes.extend_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]); // extra bytes
1484
1485        let (pdu, consumed) = parse_rtr_pdu(&bytes).unwrap();
1486        assert!(matches!(pdu, RtrPdu::ResetQuery(_)));
1487        assert_eq!(consumed, 8); // Only consumed the PDU, not extra bytes
1488    }
1489
1490    #[test]
1491    fn test_error_report_with_pdu_and_text() {
1492        // Full error report with both encapsulated PDU and error text
1493        let error = RtrErrorReport {
1494            version: RtrProtocolVersion::V1,
1495            error_code: RtrErrorCode::CorruptData,
1496            erroneous_pdu: vec![1, 2, 3, 4, 5, 6, 7, 8], // 8 bytes
1497            error_text: "Something went wrong!".to_string(), // 21 bytes
1498        };
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}