1use crate::Capabilities;
2
3use byteorder::{BigEndian, ReadBytesExt};
4
5use std::fmt::{Display, Formatter};
6use std::io::{Cursor, Error, ErrorKind, Read};
7use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
8
9use crate::*;
10
11#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
12#[allow(non_camel_case_types)]
13#[allow(missing_docs)]
14pub enum Identifier {
15 ORIGIN = 1,
16 AS_PATH = 2,
17 NEXT_HOP = 3,
18 MULTI_EXIT_DISC = 4,
19 LOCAL_PREF = 5,
20 ATOMIC_AGGREGATOR = 6,
21 AGGREGATOR = 7,
22 COMMUNITY = 8,
23 ORIGINATOR_ID = 9,
24 CLUSTER_LIST = 10,
25 DPA = 11,
26 ADVERTISER = 12,
27 CLUSTER_ID = 13,
28 MP_REACH_NLRI = 14,
29 MP_UNREACH_NLRI = 15,
30 EXTENDED_COMMUNITIES = 16,
31 AS4_PATH = 17,
32 AS4_AGGREGATOR = 18,
33 SSA = 19,
34 CONNECTOR = 20,
35 AS_PATHLIMIT = 21,
36 PMSI_TUNNEL = 22,
37 TUNNEL_ENCAPSULATION = 23,
38 TRAFFIC_ENGINEERING = 24,
39 IPV6_SPECIFIC_EXTENDED_COMMUNITY = 25,
40 AIGP = 26,
41 PE_DISTINGUISHER_LABELS = 27,
42 ENTROPY_LABEL_CAPABILITY = 28,
43 BGP_LS = 29,
44 LARGE_COMMUNITY = 32,
45 BGPSEC_PATH = 33,
46 BGP_PREFIX_SID = 34,
47 ATTR_SET = 128,
48}
49
50#[derive(Debug, Clone)]
52#[allow(non_camel_case_types)]
53pub enum PathAttribute {
54 ORIGIN(Origin),
56
57 AS_PATH(ASPath),
59
60 NEXT_HOP(IpAddr),
62
63 MULTI_EXIT_DISC(u32),
65
66 LOCAL_PREF(u32),
68
69 ATOMIC_AGGREGATOR,
71
72 AGGREGATOR((u32, Ipv4Addr)),
74
75 COMMUNITY(Vec<u32>),
77
78 ORIGINATOR_ID(u32),
80
81 CLUSTER_LIST(Vec<u32>),
84
85 DPA((u16, u32)),
88
89 ADVERTISER,
91
92 CLUSTER_ID,
94
95 MP_REACH_NLRI(MPReachNLRI),
97
98 MP_UNREACH_NLRI(MPUnreachNLRI),
100
101 EXTENDED_COMMUNITIES(Vec<u64>),
103
104 AS4_PATH(ASPath),
106
107 AS4_AGGREGATOR((u32, Ipv4Addr)),
109
110 SSA,
112
113 CONNECTOR(Ipv4Addr),
115
116 AS_PATHLIMIT((u8, u32)),
118
119 PMSI_TUNNEL((u8, u32, Vec<u8>)),
122
123 TUNNEL_ENCAPSULATION((u16, Vec<u8>)),
126
127 TRAFFIC_ENGINEERING,
129
130 IPV6_SPECIFIC_EXTENDED_COMMUNITY((u8, u8, Ipv6Addr, u16)),
133
134 AIGP((u8, Vec<u8>)),
137
138 PE_DISTINGUISHER_LABELS,
140
141 ENTROPY_LABEL_CAPABILITY,
143
144 BGP_LS,
146
147 LARGE_COMMUNITY(Vec<(u32, u32, u32)>),
149
150 BGPSEC_PATH,
152
153 BGP_PREFIX_SID,
155
156 ATTR_SET((u32, Vec<PathAttribute>)),
158}
159
160struct ReadCountingStream<'a, R: Read> {
161 stream: &'a mut R,
162 remaining: usize,
163}
164
165impl<'a, R: Read> Read for ReadCountingStream<'a, R> {
166 fn read(&mut self, buff: &mut [u8]) -> Result<usize, Error> {
167 if buff.len() > self.remaining {
168 return Err(Error::new(
169 ErrorKind::Other,
170 "Attribute decode tried to read more than its length",
171 ));
172 }
173 let res = self.stream.read(buff)?;
174 self.remaining -= res;
175 Ok(res)
176 }
177}
178
179impl PathAttribute {
180 pub fn parse(
194 stream: &mut impl Read,
195 capabilities: &Capabilities,
196 ) -> Result<PathAttribute, Error> {
197 let flags = stream.read_u8()?;
198 let code = stream.read_u8()?;
199
200 let length: u16 = if flags & (1 << 4) == 0 {
202 u16::from(stream.read_u8()?)
203 } else {
204 stream.read_u16::<BigEndian>()?
205 };
206
207 let mut count_stream = ReadCountingStream {
208 stream,
209 remaining: length as usize,
210 };
211
212 let res =
213 PathAttribute::parse_limited(&mut count_stream, capabilities, flags, code, length);
214
215 if count_stream.remaining != 0 {
218 let mut dummy_buff = vec![0; count_stream.remaining];
219 stream.read_exact(&mut dummy_buff)?;
220 }
221 res
222 }
223
224 fn parse_limited(
225 stream: &mut impl Read,
226 capabilities: &Capabilities,
227 _flags: u8,
228 code: u8,
229 length: u16,
230 ) -> Result<PathAttribute, Error> {
231 match code {
232 1 => Ok(PathAttribute::ORIGIN(Origin::parse(stream)?)),
233 2 => Ok(PathAttribute::AS_PATH(ASPath::parse(
234 stream,
235 length,
236 capabilities,
237 )?)),
238 3 => {
239 let ip: IpAddr = if length == 4 {
240 IpAddr::V4(Ipv4Addr::from(stream.read_u32::<BigEndian>()?))
241 } else {
242 IpAddr::V6(Ipv6Addr::from(stream.read_u128::<BigEndian>()?))
243 };
244
245 Ok(PathAttribute::NEXT_HOP(ip))
246 }
247 4 => Ok(PathAttribute::MULTI_EXIT_DISC(
248 stream.read_u32::<BigEndian>()?,
249 )),
250 5 => Ok(PathAttribute::LOCAL_PREF(stream.read_u32::<BigEndian>()?)),
251 6 => Ok(PathAttribute::ATOMIC_AGGREGATOR),
252 7 => {
253 let asn = if length == 6 {
254 u32::from(stream.read_u16::<BigEndian>()?)
255 } else {
256 stream.read_u32::<BigEndian>()?
257 };
258
259 let ip = Ipv4Addr::from(stream.read_u32::<BigEndian>()?);
260 Ok(PathAttribute::AGGREGATOR((asn, ip)))
261 }
262 8 => {
263 let mut communities = Vec::with_capacity(usize::from(length / 4));
264 for _ in 0..(length / 4) {
265 communities.push(stream.read_u32::<BigEndian>()?)
266 }
267
268 Ok(PathAttribute::COMMUNITY(communities))
269 }
270 9 => Ok(PathAttribute::ORIGINATOR_ID(
271 stream.read_u32::<BigEndian>()?,
272 )),
273 10 => {
274 let mut ids = Vec::with_capacity(usize::from(length / 4));
275 for _ in 0..(length / 4) {
276 ids.push(stream.read_u32::<BigEndian>()?)
277 }
278
279 Ok(PathAttribute::CLUSTER_LIST(ids))
280 }
281 11 => Ok(PathAttribute::DPA((
282 stream.read_u16::<BigEndian>()?,
283 stream.read_u32::<BigEndian>()?,
284 ))),
285 14 => Ok(PathAttribute::MP_REACH_NLRI(MPReachNLRI::parse(
286 stream,
287 length,
288 capabilities,
289 )?)),
290 15 => Ok(PathAttribute::MP_UNREACH_NLRI(MPUnreachNLRI::parse(
291 stream,
292 length,
293 capabilities,
294 )?)),
295 16 => {
296 let mut communities = Vec::with_capacity(usize::from(length / 8));
297 for _ in 0..(length / 8) {
298 communities.push(stream.read_u64::<BigEndian>()?)
299 }
300
301 Ok(PathAttribute::EXTENDED_COMMUNITIES(communities))
302 }
303 17 => Ok(PathAttribute::AS4_PATH(ASPath::parse(
304 stream,
305 length,
306 capabilities,
307 )?)),
308 18 => {
309 let asn = stream.read_u32::<BigEndian>()?;
310 let ip = Ipv4Addr::from(stream.read_u32::<BigEndian>()?);
311 Ok(PathAttribute::AS4_AGGREGATOR((asn, ip)))
312 }
313 20 => {
314 let mut buf = vec![0u8; length as usize];
315 stream.read_exact(&mut buf)?;
316
317 let mut cur = Cursor::new(buf);
318 let _ = cur.read_u16::<BigEndian>()?;
319 let _ = cur.read_u64::<BigEndian>()?;
322 let ip = Ipv4Addr::from(cur.read_u32::<BigEndian>()?);
323
324 Ok(PathAttribute::CONNECTOR(ip))
325 }
326 21 => {
327 let limit = stream.read_u8()?;
328 let asn = stream.read_u32::<BigEndian>()?;
329
330 Ok(PathAttribute::AS_PATHLIMIT((limit, asn)))
331 }
332 22 => {
333 let flags = stream.read_u8()?;
334 let label = stream.read_u32::<BigEndian>()?;
335 let mut identifier = vec![0; usize::from(length - 4)];
336 stream.read_exact(&mut identifier)?;
337
338 Ok(PathAttribute::PMSI_TUNNEL((flags, label, identifier)))
339 }
340 23 => {
341 let tunnel_type = stream.read_u16::<BigEndian>()?;
342 let length = stream.read_u16::<BigEndian>()?;
343 let mut value = vec![0; usize::from(length)];
344 stream.read_exact(&mut value)?;
345
346 Ok(PathAttribute::TUNNEL_ENCAPSULATION((tunnel_type, value)))
347 }
348 25 => {
349 let transitive = stream.read_u8()?;
350 let subtype = stream.read_u8()?;
351 let global_admin = Ipv6Addr::from(stream.read_u128::<BigEndian>()?);
352 let local_admin = stream.read_u16::<BigEndian>()?;
353
354 Ok(PathAttribute::IPV6_SPECIFIC_EXTENDED_COMMUNITY((
355 transitive,
356 subtype,
357 global_admin,
358 local_admin,
359 )))
360 }
361 26 => {
362 let aigp_type = stream.read_u8()?;
363 let length = stream.read_u16::<BigEndian>()?;
364 if length < 3 {
365 Err(Error::new(
366 ErrorKind::Other,
367 format!("Bogus AIGP length: {} < 3", length),
368 ))
369 } else {
370 let mut value = vec![0; usize::from(length - 3)];
371 stream.read_exact(&mut value)?;
372
373 Ok(PathAttribute::AIGP((aigp_type, value)))
374 }
375 }
376 28 => {
377 stream.read_exact(&mut vec![0u8; length as usize])?;
378
379 Ok(PathAttribute::ENTROPY_LABEL_CAPABILITY)
380 }
381 32 => {
382 let mut communities: Vec<(u32, u32, u32)> =
383 Vec::with_capacity(usize::from(length / 12));
384 for _ in 0..(length / 12) {
385 let admin = stream.read_u32::<BigEndian>()?;
386 let part1 = stream.read_u32::<BigEndian>()?;
387 let part2 = stream.read_u32::<BigEndian>()?;
388 communities.push((admin, part1, part2))
389 }
390
391 Ok(PathAttribute::LARGE_COMMUNITY(communities))
392 }
393 128 => {
394 let asn = stream.read_u32::<BigEndian>()?;
395
396 let mut buffer = vec![0; length as usize - 4];
397 stream.read_exact(&mut buffer)?;
398
399 let mut cursor = Cursor::new(buffer);
400
401 let mut attributes = Vec::with_capacity(5);
402 while cursor.position() < (length - 4).into() {
403 let result = PathAttribute::parse(&mut cursor, capabilities);
404 match result {
405 Err(x) => println!("Error: {}", x),
406 Ok(x) => attributes.push(x),
407 }
408 }
409
410 Ok(PathAttribute::ATTR_SET((asn, attributes)))
411 }
412 x => {
413 let mut buffer = vec![0; usize::from(length)];
414 stream.read_exact(&mut buffer)?;
415
416 Err(Error::new(
417 ErrorKind::Other,
418 format!("Unknown path attribute type found: {}", x),
419 ))
420 }
421 }
422 }
423
424 pub fn id(&self) -> Identifier {
426 match self {
427 PathAttribute::ORIGIN(_) => Identifier::ORIGIN,
428 PathAttribute::AS_PATH(_) => Identifier::AS_PATH,
429 PathAttribute::NEXT_HOP(_) => Identifier::NEXT_HOP,
430 PathAttribute::MULTI_EXIT_DISC(_) => Identifier::MULTI_EXIT_DISC,
431 PathAttribute::LOCAL_PREF(_) => Identifier::LOCAL_PREF,
432 PathAttribute::ATOMIC_AGGREGATOR => Identifier::ATOMIC_AGGREGATOR,
433 PathAttribute::AGGREGATOR(_) => Identifier::AGGREGATOR,
434 PathAttribute::COMMUNITY(_) => Identifier::COMMUNITY,
435 PathAttribute::ORIGINATOR_ID(_) => Identifier::ORIGINATOR_ID,
436 PathAttribute::CLUSTER_LIST(_) => Identifier::CLUSTER_LIST,
437 PathAttribute::DPA(_) => Identifier::DPA,
438 PathAttribute::ADVERTISER => Identifier::ADVERTISER,
439 PathAttribute::CLUSTER_ID => Identifier::CLUSTER_ID,
440 PathAttribute::MP_REACH_NLRI(_) => Identifier::MP_REACH_NLRI,
441 PathAttribute::MP_UNREACH_NLRI(_) => Identifier::MP_UNREACH_NLRI,
442 PathAttribute::EXTENDED_COMMUNITIES(_) => Identifier::EXTENDED_COMMUNITIES,
443 PathAttribute::AS4_PATH(_) => Identifier::AS4_PATH,
444 PathAttribute::AS4_AGGREGATOR(_) => Identifier::AS4_AGGREGATOR,
445 PathAttribute::SSA => Identifier::SSA,
446 PathAttribute::CONNECTOR(_) => Identifier::CONNECTOR,
447 PathAttribute::AS_PATHLIMIT(_) => Identifier::AS_PATHLIMIT,
448 PathAttribute::PMSI_TUNNEL(_) => Identifier::PMSI_TUNNEL,
449 PathAttribute::TUNNEL_ENCAPSULATION(_) => Identifier::TUNNEL_ENCAPSULATION,
450 PathAttribute::TRAFFIC_ENGINEERING => Identifier::TRAFFIC_ENGINEERING,
451 PathAttribute::IPV6_SPECIFIC_EXTENDED_COMMUNITY(_) => {
452 Identifier::IPV6_SPECIFIC_EXTENDED_COMMUNITY
453 }
454 PathAttribute::AIGP(_) => Identifier::AIGP,
455 PathAttribute::PE_DISTINGUISHER_LABELS => Identifier::PE_DISTINGUISHER_LABELS,
456 PathAttribute::ENTROPY_LABEL_CAPABILITY => Identifier::ENTROPY_LABEL_CAPABILITY,
457 PathAttribute::BGP_LS => Identifier::BGP_LS,
458 PathAttribute::LARGE_COMMUNITY(_) => Identifier::LARGE_COMMUNITY,
459 PathAttribute::BGPSEC_PATH => Identifier::BGPSEC_PATH,
460 PathAttribute::BGP_PREFIX_SID => Identifier::BGP_PREFIX_SID,
461 PathAttribute::ATTR_SET(_) => Identifier::ATTR_SET,
462 }
463 }
464
465 pub fn encode(&self, buf: &mut impl Write) -> Result<(), Error> {
467 use PathAttribute::*;
468 let mut bytes = Vec::with_capacity(8);
469 let (mut flags, identifier) = match self {
470 ORIGIN(origin) => {
471 let value: u8 = match origin {
472 Origin::IGP => 0,
473 Origin::EGP => 1,
474 Origin::INCOMPLETE => 2,
475 };
476 bytes.write_u8(value)?;
477 (0x40, Identifier::ORIGIN)
478 }
479 AS_PATH(as_path) => {
480 as_path.encode(&mut bytes)?;
481 (0x40, Identifier::AS_PATH)
482 }
483 COMMUNITY(communities) => {
484 for comm in communities {
485 bytes.write_u32::<BigEndian>(*comm)?;
486 }
487 (0xc0, Identifier::COMMUNITY)
488 }
489 NEXT_HOP(next_hop) => {
490 match next_hop {
491 IpAddr::V4(addr) => bytes.write_all(&addr.octets())?,
492 IpAddr::V6(addr) => bytes.write_all(&addr.octets())?,
493 }
494 (0x40, Identifier::NEXT_HOP)
495 }
496 MULTI_EXIT_DISC(med) => {
497 bytes.write_u32::<BigEndian>(*med)?;
498 (0x80, Identifier::MULTI_EXIT_DISC)
499 }
500 LOCAL_PREF(pref) => {
501 bytes.write_u32::<BigEndian>(*pref)?;
502 (0x40, Identifier::LOCAL_PREF)
503 }
504 MP_REACH_NLRI(mp_reach) => {
505 mp_reach.encode(&mut bytes)?;
506 (0x80, Identifier::MP_REACH_NLRI)
507 }
508 MP_UNREACH_NLRI(mp_unreach) => {
509 mp_unreach.encode(&mut bytes)?;
510 (0x80, Identifier::MP_UNREACH_NLRI)
511 }
512 EXTENDED_COMMUNITIES(ext_communities) => {
513 for comm in ext_communities {
514 bytes.write_u64::<BigEndian>(*comm)?;
515 }
516 (0xc0, Identifier::EXTENDED_COMMUNITIES)
517 }
518 CLUSTER_LIST(clusters) => {
519 for cluster in clusters {
520 bytes.write_u32::<BigEndian>(*cluster)?;
521 }
522 (0x80, Identifier::CLUSTER_LIST)
523 }
524 ORIGINATOR_ID(origin_id) => {
525 bytes.write_u32::<BigEndian>(*origin_id)?;
526 (0x80, Identifier::ORIGINATOR_ID)
527 }
528 AS4_PATH(as_path) => {
529 as_path.encode(&mut bytes)?;
530 (0xc0, Identifier::AS4_PATH)
531 }
532 AGGREGATOR((asn, ip)) => {
533 bytes.write_u16::<BigEndian>(*asn as u16)?;
534 bytes.write_u32::<BigEndian>((*ip).into())?;
535 (0xc0, Identifier::AGGREGATOR)
536 }
537 _ => {
538 unimplemented!("{:?}", self);
539 }
540 };
541 let is_extended_length = bytes.len() > std::u8::MAX as usize || (flags & 0x10) == 0x10;
544 if is_extended_length {
545 flags |= 0x10; }
547 buf.write_u8(flags)?;
548 buf.write_u8(identifier as u8)?;
549 if is_extended_length {
550 buf.write_u16::<BigEndian>(bytes.len() as u16)?;
551 } else {
552 buf.write_u8(bytes.len() as u8)?;
553 }
554 buf.write_all(&bytes)
555 }
556}
557
558#[derive(Debug, Clone)]
560pub enum Origin {
561 IGP,
563
564 EGP,
566
567 INCOMPLETE,
569}
570
571impl Origin {
572 fn parse(stream: &mut impl Read) -> Result<Origin, Error> {
573 match stream.read_u8()? {
574 0 => Ok(Origin::IGP),
575 1 => Ok(Origin::EGP),
576 2 => Ok(Origin::INCOMPLETE),
577 _ => Err(Error::new(ErrorKind::Other, "Unknown origin type found.")),
578 }
579 }
580}
581
582impl Display for Origin {
583 fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
584 match self {
585 Origin::IGP => write!(f, "IGP"),
586 Origin::EGP => write!(f, "EGP"),
587 Origin::INCOMPLETE => write!(f, "Incomplete"),
588 }
589 }
590}
591
592#[derive(Debug, Clone)]
594pub struct ASPath {
595 pub segments: Vec<Segment>,
597}
598
599impl ASPath {
600 fn parse(stream: &mut impl Read, length: u16, _: &Capabilities) -> Result<ASPath, Error> {
601 let segments = Segment::parse_unknown_segments(stream, length)?;
602 Ok(ASPath { segments })
603 }
604
605 pub fn origin(&self) -> Option<u32> {
608 let segment = self.segments.last()?;
609 if let Segment::AS_SEQUENCE(x) = segment {
610 return Some(*x.last()?);
611 }
612 None
613 }
614
615 pub fn has_4_byte_asns(&self) -> bool {
617 self.segments.iter().any(|s| s.has_4_byte_asns())
618 }
619
620 pub fn sequence(&self) -> Option<Vec<u32>> {
623 let mut sequence = Vec::with_capacity(8);
624 for segment in &self.segments {
625 match segment {
626 Segment::AS_SEQUENCE(x) => sequence.extend(x),
627 Segment::AS_SET(_) => return None,
628 }
629 }
630
631 Some(sequence)
632 }
633
634 pub fn encode(&self, buf: &mut impl Write) -> Result<(), Error> {
636 for segment in &self.segments {
637 let (path_type, seq) = match segment {
638 Segment::AS_SET(set) => (1u8, set),
639 Segment::AS_SEQUENCE(seq) => (2u8, seq),
640 };
641 buf.write_u8(path_type)?;
642 buf.write_u8(seq.len() as u8)?;
643 let is_4_byte_aspath = self.has_4_byte_asns();
644 for asn in seq.iter() {
645 if is_4_byte_aspath {
646 buf.write_u32::<BigEndian>(*asn)?;
647 } else {
648 buf.write_u16::<BigEndian>(*asn as u16)?;
649 }
650 }
651 }
652 Ok(())
653 }
654}
655
656#[derive(Debug, Clone)]
658#[allow(non_camel_case_types)]
659pub enum Segment {
660 AS_SEQUENCE(Vec<u32>),
662
663 AS_SET(Vec<u32>),
665}
666
667impl Segment {
668 pub fn has_4_byte_asns(&self) -> bool {
670 let asns = match &self {
671 Segment::AS_SEQUENCE(asns) => asns,
672 Segment::AS_SET(asns) => asns,
673 };
674 asns.iter().any(|a| a > &(std::u16::MAX as u32))
675 }
676
677 fn parse_unknown_segments(stream: &mut impl Read, length: u16) -> Result<Vec<Segment>, Error> {
678 let mut buf = vec![0u8; length as usize];
681 stream.read_exact(&mut buf)?;
682 let size = buf.len();
683 let mut cur = Cursor::new(buf);
684
685 'as_len: for i in 1..=2u64 {
686 cur.set_position(0);
687
688 let assumed_as_len = i * 2;
690 let mut total_segments = 0u64;
691
692 while cur.position() < size as u64 {
693 let segment_type = cur.read_u8()?;
694 let segment_len = cur.read_u8()?;
695
696 if (assumed_as_len == 2 && total_segments >= 1)
698 && (segment_type < 1 || segment_type > 2)
699 {
700 continue 'as_len;
701 }
702
703 cur.set_position(cur.position() + (u64::from(segment_len) * assumed_as_len));
704 total_segments += 1;
705 }
706
707 if cur.position() == u64::from(length) {
708 cur.set_position(0);
709
710 match i {
711 1 => {
712 return Segment::parse_u16_segments(&mut cur, length);
713 }
714 2 => {
715 return Segment::parse_u32_segments(&mut cur, length);
716 }
717 _ => {}
718 };
719 }
720 }
721
722 Err(Error::new(
723 ErrorKind::Other,
724 "Invalid AS_PATH length detected",
725 ))
726 }
727
728 fn parse_u16_segments(stream: &mut impl Read, length: u16) -> Result<Vec<Segment>, Error> {
729 let mut segments: Vec<Segment> = Vec::with_capacity(1);
730
731 let mut size = length;
733 while size != 0 {
734 let segment_type = stream.read_u8()?;
736
737 let segment_length = stream.read_u8()?;
739
740 let mut elements: Vec<u32> = Vec::with_capacity(usize::from(segment_length));
742
743 for _ in 0..segment_length {
745 elements.push(u32::from(stream.read_u16::<BigEndian>()?));
746 }
747
748 match segment_type {
749 1 => segments.push(Segment::AS_SET(elements)),
750 2 => segments.push(Segment::AS_SEQUENCE(elements)),
751 x => {
752 return Err(Error::new(
753 ErrorKind::Other,
754 format!("Unknown AS_PATH (2 byte) segment type found: {}", x),
755 ));
756 }
757 }
758
759 size -= 2 + (u16::from(segment_length) * 2);
760 }
761
762 Ok(segments)
763 }
764
765 fn parse_u32_segments(stream: &mut impl Read, length: u16) -> Result<Vec<Segment>, Error> {
766 let mut segments: Vec<Segment> = Vec::with_capacity(1);
767
768 let mut size: i32 = i32::from(length);
770
771 while size != 0 {
772 let segment_type = stream.read_u8()?;
774
775 let segment_length = stream.read_u8()?;
777
778 let mut elements: Vec<u32> = Vec::with_capacity(usize::from(segment_length));
780
781 for _ in 0..segment_length {
783 elements.push(stream.read_u32::<BigEndian>()?);
784 }
785
786 match segment_type {
787 1 => segments.push(Segment::AS_SET(elements)),
788 2 => segments.push(Segment::AS_SEQUENCE(elements)),
789 x => {
790 return Err(Error::new(
791 ErrorKind::Other,
792 format!("Unknown AS_PATH (4 byte) segment type found: {}", x),
793 ));
794 }
795 }
796
797 size -= 2 + i32::from(u16::from(segment_length) * 4);
798 }
799
800 Ok(segments)
801 }
802}