bgpkit_parser/parser/bgp/attributes/
attr_07_18_aggregator.rs

1use crate::models::*;
2use crate::parser::ReadUtils;
3use crate::ParserError;
4use bytes::{Buf, BufMut, Bytes, BytesMut};
5use log::warn;
6use std::net::IpAddr;
7
8/// Parse aggregator attribute.
9///
10/// https://www.rfc-editor.org/rfc/rfc4271.html#section-5.1.7
11///
12/// ```text
13///    AGGREGATOR is an optional transitive attribute, which MAY be included
14///    in updates that are formed by aggregation (see Section 9.2.2.2).  A
15///    BGP speaker that performs route aggregation MAY add the AGGREGATOR
16///    attribute, which SHALL contain its own AS number and IP address.  The
17///    IP address SHOULD be the same as the BGP Identifier of the speaker.`
18/// ```
19pub fn parse_aggregator(
20    mut input: Bytes,
21    asn_len: &AsnLength,
22) -> Result<(Asn, BgpIdentifier), ParserError> {
23    let asn_len_found = match input.remaining() {
24        8 => AsnLength::Bits32,
25        6 => AsnLength::Bits16,
26        _ => {
27            return Err(ParserError::ParseError(format!(
28                "Aggregator attribute length is invalid: found {}, should 6 or 8",
29                input.remaining()
30            )))
31        }
32    };
33    if asn_len_found != *asn_len {
34        warn!(
35            "Aggregator attribute with ASN length set to {:?} but found {:?}",
36            asn_len, asn_len_found
37        );
38    }
39    let asn = input.read_asn(asn_len_found)?;
40
41    // the BGP identifier is always 4 bytes or IPv4 address
42    let identifier = input.read_ipv4_address()?;
43    Ok((asn, identifier))
44}
45
46pub fn encode_aggregator(asn: &Asn, addr: &IpAddr) -> Bytes {
47    let mut bytes = BytesMut::new();
48
49    bytes.extend(asn.encode());
50    match addr {
51        IpAddr::V4(ip) => bytes.put_u32((*ip).into()),
52        IpAddr::V6(ip) => {
53            bytes.put_u128((*ip).into());
54        }
55    }
56    bytes.freeze()
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use std::net::{Ipv4Addr, Ipv6Addr};
63    use std::str::FromStr;
64
65    #[test]
66    fn test_parse_aggregator() {
67        let identifier = Ipv4Addr::from_str("10.0.0.1").unwrap();
68        let mut data = vec![];
69        data.extend([1u8, 2]);
70        data.extend(identifier.octets());
71        let bytes = Bytes::from(data);
72
73        if let Ok((asn, n)) = parse_aggregator(bytes, &AsnLength::Bits16) {
74            assert_eq!(n, identifier);
75            assert_eq!(asn, Asn::new_16bit(258))
76        }
77
78        let mut data = vec![];
79        data.extend([0u8, 0, 1, 2]);
80        data.extend(identifier.octets());
81        let bytes = Bytes::from(data);
82
83        if let Ok((asn, n)) = parse_aggregator(bytes, &AsnLength::Bits32) {
84            assert_eq!(n, identifier);
85            assert_eq!(asn, Asn::new_32bit(258))
86        }
87
88        // invalid number of bytes
89        let mut data = vec![];
90        data.extend([0u8, 0, 1, 2, 3]);
91        data.extend(identifier.octets());
92        let bytes = Bytes::from(data);
93        assert!(parse_aggregator(bytes, &AsnLength::Bits32).is_err());
94
95        // bytes length not matching
96        let mut data = vec![];
97        data.extend([0u8, 0, 1, 2, 3, 4]); // 6 bytes --> 2 bytes ASN
98        data.extend(identifier.octets());
99        let bytes = Bytes::from(data);
100        assert!(parse_aggregator(bytes, &AsnLength::Bits32).is_err());
101    }
102
103    #[test]
104    fn test_encode_aggregator() {
105        let ipv4 = Ipv4Addr::from_str("10.0.0.1").unwrap();
106        let asn = Asn::new_16bit(258);
107        let bytes = encode_aggregator(&asn, &ipv4.into());
108        assert_eq!(bytes, Bytes::from_static(&[1u8, 2, 10, 0, 0, 1]));
109
110        let ipv6 = Ipv6Addr::from_str("fc00::1").unwrap();
111        let asn = Asn::new_32bit(258);
112        let bytes = encode_aggregator(&asn, &ipv6.into());
113        assert_eq!(
114            bytes,
115            Bytes::from_static(&[
116                0u8, 0, 1, 2, 0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01
117            ])
118        );
119    }
120}