1mod attr_01_origin;
2mod attr_02_17_as_path;
3mod attr_03_next_hop;
4mod attr_04_med;
5mod attr_05_local_pref;
6mod attr_07_18_aggregator;
7mod attr_08_communities;
8mod attr_09_originator;
9mod attr_10_13_cluster;
10mod attr_14_15_nlri;
11mod attr_16_25_extended_communities;
12mod attr_23_tunnel_encap;
13mod attr_29_linkstate;
14mod attr_32_large_communities;
15mod attr_35_otc;
16
17use bytes::{Buf, BufMut, Bytes, BytesMut};
18use log::{debug, warn};
19use std::net::IpAddr;
20
21use crate::models::*;
22
23use crate::error::{BgpValidationWarning, ParserError};
24use crate::parser::bgp::attributes::attr_01_origin::{encode_origin, parse_origin};
25use crate::parser::bgp::attributes::attr_02_17_as_path::{encode_as_path, parse_as_path};
26use crate::parser::bgp::attributes::attr_03_next_hop::{encode_next_hop, parse_next_hop};
27use crate::parser::bgp::attributes::attr_04_med::{encode_med, parse_med};
28use crate::parser::bgp::attributes::attr_05_local_pref::{encode_local_pref, parse_local_pref};
29use crate::parser::bgp::attributes::attr_07_18_aggregator::{encode_aggregator, parse_aggregator};
30use crate::parser::bgp::attributes::attr_08_communities::{
31 encode_regular_communities, parse_regular_communities,
32};
33use crate::parser::bgp::attributes::attr_09_originator::{
34 encode_originator_id, parse_originator_id,
35};
36use crate::parser::bgp::attributes::attr_10_13_cluster::{encode_clusters, parse_clusters};
37use crate::parser::bgp::attributes::attr_14_15_nlri::{encode_nlri, parse_nlri};
38use crate::parser::bgp::attributes::attr_16_25_extended_communities::{
39 encode_extended_communities, encode_ipv6_extended_communities, parse_extended_community,
40 parse_ipv6_extended_community,
41};
42use crate::parser::bgp::attributes::attr_23_tunnel_encap::{
43 encode_tunnel_encapsulation_attribute, parse_tunnel_encapsulation_attribute,
44};
45use crate::parser::bgp::attributes::attr_29_linkstate::{
46 encode_link_state_attribute, parse_link_state_attribute,
47};
48use crate::parser::bgp::attributes::attr_32_large_communities::{
49 encode_large_communities, parse_large_communities,
50};
51use crate::parser::bgp::attributes::attr_35_otc::{
52 encode_only_to_customer, parse_only_to_customer,
53};
54use crate::parser::ReadUtils;
55
56fn validate_attribute_flags(
58 attr_type: AttrType,
59 flags: AttrFlags,
60 warnings: &mut Vec<BgpValidationWarning>,
61) {
62 let expected_flags = match attr_type {
63 AttrType::ORIGIN | AttrType::AS_PATH | AttrType::NEXT_HOP => AttrFlags::TRANSITIVE,
65 AttrType::ATOMIC_AGGREGATE => AttrFlags::TRANSITIVE,
67 AttrType::MULTI_EXIT_DISCRIMINATOR
69 | AttrType::ORIGINATOR_ID
70 | AttrType::CLUSTER_LIST
71 | AttrType::MP_REACHABLE_NLRI
72 | AttrType::MP_UNREACHABLE_NLRI => AttrFlags::OPTIONAL,
73 AttrType::AGGREGATOR
75 | AttrType::AS4_AGGREGATOR
76 | AttrType::AS4_PATH
77 | AttrType::COMMUNITIES
78 | AttrType::EXTENDED_COMMUNITIES
79 | AttrType::IPV6_ADDRESS_SPECIFIC_EXTENDED_COMMUNITIES
80 | AttrType::LARGE_COMMUNITIES
81 | AttrType::ONLY_TO_CUSTOMER => AttrFlags::OPTIONAL | AttrFlags::TRANSITIVE,
82 AttrType::LOCAL_PREFERENCE => AttrFlags::TRANSITIVE,
84 _ => return, };
87
88 let relevant_flags = flags & (AttrFlags::OPTIONAL | AttrFlags::TRANSITIVE);
90 if relevant_flags != expected_flags {
91 warnings.push(BgpValidationWarning::AttributeFlagsError {
92 attr_type,
93 expected_flags: expected_flags.bits(),
94 actual_flags: relevant_flags.bits(),
95 });
96 }
97
98 if flags.contains(AttrFlags::PARTIAL) {
100 match attr_type {
101 AttrType::ORIGIN
103 | AttrType::AS_PATH
104 | AttrType::NEXT_HOP
105 | AttrType::LOCAL_PREFERENCE
106 | AttrType::ATOMIC_AGGREGATE
107 | AttrType::MULTI_EXIT_DISCRIMINATOR
108 | AttrType::ORIGINATOR_ID
109 | AttrType::CLUSTER_LIST
110 | AttrType::MP_REACHABLE_NLRI
111 | AttrType::MP_UNREACHABLE_NLRI => {
112 warnings.push(BgpValidationWarning::AttributeFlagsError {
113 attr_type,
114 expected_flags: expected_flags.bits(),
115 actual_flags: flags.bits(),
116 });
117 }
118 _ => {} }
120 }
121}
122
123fn is_well_known_mandatory(attr_type: AttrType) -> bool {
125 matches!(
126 attr_type,
127 AttrType::ORIGIN | AttrType::AS_PATH | AttrType::NEXT_HOP | AttrType::LOCAL_PREFERENCE
128 )
129}
130
131fn validate_attribute_length(
133 attr_type: AttrType,
134 length: usize,
135 warnings: &mut Vec<BgpValidationWarning>,
136) {
137 let expected_length = match attr_type {
138 AttrType::ORIGIN => Some(1),
139 AttrType::NEXT_HOP => Some(4), AttrType::MULTI_EXIT_DISCRIMINATOR => Some(4),
141 AttrType::LOCAL_PREFERENCE => Some(4),
142 AttrType::ATOMIC_AGGREGATE => Some(0),
143 AttrType::ORIGINATOR_ID => Some(4),
144 AttrType::ONLY_TO_CUSTOMER => Some(4),
145 AttrType::AS_PATH
147 | AttrType::AS4_PATH
148 | AttrType::AGGREGATOR
149 | AttrType::AS4_AGGREGATOR
150 | AttrType::COMMUNITIES
151 | AttrType::EXTENDED_COMMUNITIES
152 | AttrType::IPV6_ADDRESS_SPECIFIC_EXTENDED_COMMUNITIES
153 | AttrType::LARGE_COMMUNITIES
154 | AttrType::CLUSTER_LIST
155 | AttrType::MP_REACHABLE_NLRI
156 | AttrType::MP_UNREACHABLE_NLRI => None,
157 _ => None, };
159
160 if let Some(expected) = expected_length {
161 if length != expected {
162 warnings.push(BgpValidationWarning::AttributeLengthError {
163 attr_type,
164 expected_length: Some(expected),
165 actual_length: length,
166 });
167 }
168 }
169}
170
171pub fn parse_attributes(
176 mut data: Bytes,
177 asn_len: &AsnLength,
178 add_path: bool,
179 afi: Option<Afi>,
180 safi: Option<Safi>,
181 prefixes: Option<&[NetworkPrefix]>,
182) -> Result<Attributes, ParserError> {
183 let estimated_attrs = (data.remaining() / 3).min(256);
186 let mut attributes: Vec<Attribute> = Vec::with_capacity(estimated_attrs.max(8));
187 let mut validation_warnings: Vec<BgpValidationWarning> = Vec::new();
188 let mut seen_attributes: [bool; 256] = [false; 256];
190
191 while data.remaining() >= 3 {
192 let flag = AttrFlags::from_bits_retain(data.read_u8()?);
197 let attr_type = data.read_u8()?;
198 let attr_length = match flag.contains(AttrFlags::EXTENDED) {
199 false => data.read_u8()? as usize,
200 true => data.read_u16()? as usize,
201 };
202
203 let mut partial = false;
204 if flag.contains(AttrFlags::PARTIAL) {
205 partial = true;
216 }
217
218 debug!(
219 "reading attribute: type -- {:?}, length -- {}",
220 &attr_type, attr_length
221 );
222
223 let parsed_attr_type = AttrType::from(attr_type);
224
225 if seen_attributes[attr_type as usize] {
227 validation_warnings.push(BgpValidationWarning::DuplicateAttribute {
228 attr_type: parsed_attr_type,
229 });
230 }
232 seen_attributes[attr_type as usize] = true;
233
234 validate_attribute_flags(parsed_attr_type, flag, &mut validation_warnings);
236 validate_attribute_length(parsed_attr_type, attr_length, &mut validation_warnings);
237
238 let attr_type = match parsed_attr_type {
239 attr_type @ AttrType::Unknown(unknown_type) => {
240 let bytes = data.read_n_bytes(attr_length)?;
242 let attr_value = match get_deprecated_attr_type(unknown_type) {
243 Some(t) => {
244 debug!("deprecated attribute type: {} - {}", unknown_type, t);
245 AttributeValue::Deprecated(AttrRaw { attr_type, bytes })
246 }
247 None => {
248 debug!("unknown attribute type: {}", unknown_type);
249 AttributeValue::Unknown(AttrRaw { attr_type, bytes })
250 }
251 };
252
253 assert_eq!(attr_type, attr_value.attr_type());
254 attributes.push(Attribute {
255 value: attr_value,
256 flag,
257 });
258 continue;
259 }
260 t => t,
261 };
262
263 let bytes_left = data.remaining();
264
265 if data.remaining() < attr_length {
266 warn!(
267 "{:?} attribute encodes a length ({}) that is longer than the remaining attribute data ({}). Skipping remaining attribute data for BGP message",
268 attr_type, attr_length, bytes_left
269 );
270 break;
272 }
273
274 data.has_n_remaining(attr_length)?;
276 let mut attr_data = data.split_to(attr_length);
277
278 let attr = match attr_type {
279 AttrType::ORIGIN => parse_origin(attr_data),
280 AttrType::AS_PATH => {
281 parse_as_path(attr_data, asn_len).map(|path| AttributeValue::AsPath {
282 path,
283 is_as4: false,
284 })
285 }
286 AttrType::NEXT_HOP => parse_next_hop(attr_data, &afi),
287 AttrType::MULTI_EXIT_DISCRIMINATOR => parse_med(attr_data),
288 AttrType::LOCAL_PREFERENCE => parse_local_pref(attr_data),
289 AttrType::ATOMIC_AGGREGATE => Ok(AttributeValue::AtomicAggregate),
290 AttrType::AGGREGATOR => {
291 parse_aggregator(attr_data, asn_len).map(|(asn, id)| AttributeValue::Aggregator {
292 asn,
293 id,
294 is_as4: false,
295 })
296 }
297 AttrType::ORIGINATOR_ID => parse_originator_id(attr_data),
298 AttrType::CLUSTER_LIST => parse_clusters(attr_data),
299 AttrType::MP_REACHABLE_NLRI => {
300 parse_nlri(attr_data, &afi, &safi, &prefixes, true, add_path)
301 }
302 AttrType::MP_UNREACHABLE_NLRI => {
303 parse_nlri(attr_data, &afi, &safi, &prefixes, false, add_path)
304 }
305 AttrType::AS4_PATH => parse_as_path(attr_data, &AsnLength::Bits32)
306 .map(|path| AttributeValue::AsPath { path, is_as4: true }),
307 AttrType::AS4_AGGREGATOR => {
308 parse_aggregator(attr_data, &AsnLength::Bits32).map(|(asn, id)| {
309 AttributeValue::Aggregator {
310 asn,
311 id,
312 is_as4: true,
313 }
314 })
315 }
316
317 AttrType::COMMUNITIES => parse_regular_communities(attr_data),
319 AttrType::LARGE_COMMUNITIES => parse_large_communities(attr_data),
320 AttrType::EXTENDED_COMMUNITIES => parse_extended_community(attr_data),
321 AttrType::IPV6_ADDRESS_SPECIFIC_EXTENDED_COMMUNITIES => {
322 parse_ipv6_extended_community(attr_data)
323 }
324 AttrType::DEVELOPMENT => {
325 let mut value = vec![];
326 for _i in 0..attr_length {
327 value.push(attr_data.read_u8()?);
328 }
329 Ok(AttributeValue::Development(value))
330 }
331 AttrType::ONLY_TO_CUSTOMER => parse_only_to_customer(attr_data),
332 AttrType::TUNNEL_ENCAPSULATION => parse_tunnel_encapsulation_attribute(attr_data),
333 AttrType::BGP_LS_ATTRIBUTE => parse_link_state_attribute(attr_data),
334 _ => Err(ParserError::Unsupported(format!(
335 "unsupported attribute type: {attr_type:?}"
336 ))),
337 };
338
339 match attr {
340 Ok(value) => {
341 assert_eq!(attr_type, value.attr_type());
342 attributes.push(Attribute { value, flag });
343 }
344 Err(e) => {
345 if partial {
347 validation_warnings.push(BgpValidationWarning::PartialAttributeError {
349 attr_type,
350 reason: e.to_string(),
351 });
352 debug!("PARTIAL attribute error: {}", e);
353 } else if is_well_known_mandatory(attr_type) {
354 validation_warnings.push(BgpValidationWarning::MalformedAttributeList {
357 reason: format!(
358 "Well-known mandatory attribute {} parsing failed: {}",
359 u8::from(attr_type),
360 e
361 ),
362 });
363 debug!(
364 "Well-known mandatory attribute parsing failed, treating as withdraw: {}",
365 e
366 );
367 } else {
368 validation_warnings.push(BgpValidationWarning::OptionalAttributeError {
370 attr_type,
371 reason: e.to_string(),
372 });
373 debug!("Optional attribute error, discarding: {}", e);
374 }
375 continue;
377 }
378 };
379 }
380
381 let mandatory_attributes = [
383 AttrType::ORIGIN,
384 AttrType::AS_PATH,
385 AttrType::NEXT_HOP,
386 ];
388
389 for &mandatory_attr in &mandatory_attributes {
390 if !seen_attributes[u8::from(mandatory_attr) as usize] {
391 validation_warnings.push(BgpValidationWarning::MissingWellKnownAttribute {
392 attr_type: mandatory_attr,
393 });
394 }
395 }
396
397 let mut result = Attributes::from(attributes);
398 result.validation_warnings = validation_warnings;
399 Ok(result)
400}
401
402impl Attribute {
403 pub fn encode(&self, asn_len: AsnLength) -> Bytes {
404 let mut bytes = BytesMut::new();
405
406 let flag = self.flag.bits();
407 let type_code = self.value.attr_type().into();
408
409 bytes.put_u8(flag);
410 bytes.put_u8(type_code);
411
412 let value_bytes = match &self.value {
413 AttributeValue::Origin(v) => encode_origin(v),
414 AttributeValue::AsPath { path, is_as4 } => {
415 let four_byte = match is_as4 {
416 true => AsnLength::Bits32,
417 false => match asn_len.is_four_byte() {
418 true => AsnLength::Bits32,
419 false => AsnLength::Bits16,
420 },
421 };
422 encode_as_path(path, four_byte)
423 }
424 AttributeValue::NextHop(v) => encode_next_hop(v),
425 AttributeValue::MultiExitDiscriminator(v) => encode_med(*v),
426 AttributeValue::LocalPreference(v) => encode_local_pref(*v),
427 AttributeValue::OnlyToCustomer(v) => encode_only_to_customer(v.into()),
428 AttributeValue::AtomicAggregate => Bytes::default(),
429 AttributeValue::Aggregator { asn, id, is_as4: _ } => {
430 encode_aggregator(asn, &IpAddr::from(*id))
431 }
432 AttributeValue::Communities(v) => encode_regular_communities(v),
433 AttributeValue::ExtendedCommunities(v) => encode_extended_communities(v),
434 AttributeValue::LargeCommunities(v) => encode_large_communities(v),
435 AttributeValue::Ipv6AddressSpecificExtendedCommunities(v) => {
436 encode_ipv6_extended_communities(v)
437 }
438 AttributeValue::OriginatorId(v) => encode_originator_id(&IpAddr::from(*v)),
439 AttributeValue::Clusters(v) => encode_clusters(v),
440 AttributeValue::MpReachNlri(v) => encode_nlri(v, true),
441 AttributeValue::MpUnreachNlri(v) => encode_nlri(v, false),
442 AttributeValue::LinkState(v) => encode_link_state_attribute(v),
443 AttributeValue::TunnelEncapsulation(v) => encode_tunnel_encapsulation_attribute(v),
444 AttributeValue::Development(v) => Bytes::from(v.to_owned()),
445 AttributeValue::Deprecated(v) => Bytes::from(v.bytes.to_owned()),
446 AttributeValue::Unknown(v) => Bytes::from(v.bytes.to_owned()),
447 AttributeValue::Aigp(_v) => {
448 Bytes::new()
450 }
451 AttributeValue::AttrSet(_v) => {
452 Bytes::new()
454 }
455 };
456
457 match self.is_extended() {
458 false => {
459 bytes.put_u8(value_bytes.len() as u8);
460 }
461 true => {
462 bytes.put_u16(value_bytes.len() as u16);
463 }
464 }
465 bytes.extend(value_bytes);
466 bytes.freeze()
467 }
468}
469
470impl Attributes {
471 pub fn encode(&self, asn_len: AsnLength) -> Bytes {
472 let mut bytes = BytesMut::new();
473 for attr in &self.inner {
474 bytes.extend(attr.encode(asn_len));
475 }
476 bytes.freeze()
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use super::*;
483
484 #[test]
485 fn test_unknwon_attribute_type() {
486 let data = Bytes::from(vec![0x40, 0xFE, 0x00]);
487 let asn_len = AsnLength::Bits16;
488 let add_path = false;
489 let afi = None;
490 let safi = None;
491 let prefixes = None;
492 let attributes = parse_attributes(data, &asn_len, add_path, afi, safi, prefixes);
493 assert!(attributes.is_ok());
494 let attributes = attributes.unwrap();
495 assert_eq!(attributes.inner.len(), 1);
496 assert_eq!(
497 attributes.inner[0].value.attr_type(),
498 AttrType::Unknown(254)
499 );
500 }
501
502 #[test]
503 fn test_rfc7606_attribute_flags_error() {
504 let data = Bytes::from(vec![0x80, 0x01, 0x01, 0x00]); let asn_len = AsnLength::Bits16;
507 let add_path = false;
508 let afi = None;
509 let safi = None;
510 let prefixes = None;
511
512 let attributes = parse_attributes(data, &asn_len, add_path, afi, safi, prefixes).unwrap();
513
514 assert!(attributes.has_validation_warnings());
516 let warnings = attributes.validation_warnings();
517 assert!(!warnings.is_empty());
519
520 match &warnings[0] {
521 BgpValidationWarning::AttributeFlagsError { attr_type, .. } => {
522 assert_eq!(*attr_type, AttrType::ORIGIN);
523 }
524 _ => panic!("Expected AttributeFlagsError warning"),
525 }
526 }
527
528 #[test]
529 fn test_rfc7606_missing_mandatory_attribute() {
530 let data = Bytes::from(vec![]);
532 let asn_len = AsnLength::Bits16;
533 let add_path = false;
534 let afi = None;
535 let safi = None;
536 let prefixes = None;
537
538 let attributes = parse_attributes(data, &asn_len, add_path, afi, safi, prefixes).unwrap();
539
540 assert!(attributes.has_validation_warnings());
542 let warnings = attributes.validation_warnings();
543 assert_eq!(warnings.len(), 3); for warning in warnings {
546 match warning {
547 BgpValidationWarning::MissingWellKnownAttribute { attr_type } => {
548 assert!(matches!(
549 attr_type,
550 AttrType::ORIGIN | AttrType::AS_PATH | AttrType::NEXT_HOP
551 ));
552 }
553 _ => panic!("Expected MissingWellKnownAttribute warning"),
554 }
555 }
556 }
557
558 #[test]
559 fn test_rfc7606_duplicate_attribute() {
560 let data = Bytes::from(vec![
562 0x40, 0x01, 0x01, 0x00, 0x40, 0x01, 0x01, 0x01, ]);
565 let asn_len = AsnLength::Bits16;
566 let add_path = false;
567 let afi = None;
568 let safi = None;
569 let prefixes = None;
570
571 let attributes = parse_attributes(data, &asn_len, add_path, afi, safi, prefixes).unwrap();
572
573 assert!(attributes.has_validation_warnings());
575 let warnings = attributes.validation_warnings();
576
577 let has_duplicate_warning = warnings
579 .iter()
580 .any(|w| matches!(w, BgpValidationWarning::DuplicateAttribute { .. }));
581 assert!(has_duplicate_warning);
582 }
583
584 #[test]
585 fn test_attribute_type_boundaries() {
586 let asn_len = AsnLength::Bits16;
587 let add_path = false;
588 let afi = None;
589 let safi = None;
590 let prefixes = None;
591
592 const REQUIRED_ATTRS: &[u8] = &[
594 0x40, 0x01, 0x01, 0x00, 0x40, 0x02, 0x00, 0x40, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, ];
598
599 let mut data = REQUIRED_ATTRS.to_vec();
601 data.extend_from_slice(&[0x40, 0xFF, 0x01, 0x00]); let data = Bytes::from(data);
603
604 let attributes = parse_attributes(data, &asn_len, add_path, afi, safi, prefixes).unwrap();
605
606 assert!(attributes.has_attr(AttrType::DEVELOPMENT));
607 assert!(!attributes.has_validation_warnings());
608
609 let mut data = REQUIRED_ATTRS.to_vec();
611 data.extend_from_slice(&[0x40, 0x00, 0x01, 0x01]); let data = Bytes::from(data);
613
614 let attributes = parse_attributes(data, &asn_len, add_path, afi, safi, prefixes).unwrap();
615
616 assert!(attributes.validation_warnings.iter().any(|vw| {
618 matches!(vw, BgpValidationWarning::OptionalAttributeError { attr_type, reason:_ } if *attr_type == AttrType::RESERVED)
619 }));
620 }
621
622 #[test]
623 fn test_rfc7606_attribute_length_error() {
624 let data = Bytes::from(vec![0x40, 0x01, 0x02, 0x00, 0x01]);
626 let asn_len = AsnLength::Bits16;
627 let add_path = false;
628 let afi = None;
629 let safi = None;
630 let prefixes = None;
631
632 let attributes = parse_attributes(data, &asn_len, add_path, afi, safi, prefixes).unwrap();
633
634 assert!(attributes.has_validation_warnings());
636 let warnings = attributes.validation_warnings();
637
638 let has_length_warning = warnings
639 .iter()
640 .any(|w| matches!(w, BgpValidationWarning::AttributeLengthError { .. }));
641 assert!(has_length_warning);
642 }
643
644 #[test]
645 fn test_rfc7606_no_session_reset() {
646 let data = Bytes::from(vec![
648 0x80, 0x01, 0x02, 0x00, 0x01, 0x40, 0x01, 0x01, 0x00, 0x40, 0xFF, 0x01, 0x00, ]);
652 let asn_len = AsnLength::Bits16;
653 let add_path = false;
654 let afi = None;
655 let safi = None;
656 let prefixes = None;
657
658 let result = parse_attributes(data, &asn_len, add_path, afi, safi, prefixes);
660 assert!(result.is_ok());
661
662 let attributes = result.unwrap();
663 assert!(attributes.has_validation_warnings());
664
665 let warnings = attributes.validation_warnings();
667 assert!(!warnings.is_empty());
668 }
669}