bgpkit_parser/parser/bgp/attributes/
mod.rs

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_32_large_communities;
13mod attr_35_otc;
14
15use bytes::{Buf, BufMut, Bytes, BytesMut};
16use log::{debug, warn};
17use std::net::IpAddr;
18
19use crate::models::*;
20
21use crate::error::ParserError;
22use crate::parser::bgp::attributes::attr_01_origin::{encode_origin, parse_origin};
23use crate::parser::bgp::attributes::attr_02_17_as_path::{encode_as_path, parse_as_path};
24use crate::parser::bgp::attributes::attr_03_next_hop::{encode_next_hop, parse_next_hop};
25use crate::parser::bgp::attributes::attr_04_med::{encode_med, parse_med};
26use crate::parser::bgp::attributes::attr_05_local_pref::{encode_local_pref, parse_local_pref};
27use crate::parser::bgp::attributes::attr_07_18_aggregator::{encode_aggregator, parse_aggregator};
28use crate::parser::bgp::attributes::attr_08_communities::{
29    encode_regular_communities, parse_regular_communities,
30};
31use crate::parser::bgp::attributes::attr_09_originator::{
32    encode_originator_id, parse_originator_id,
33};
34use crate::parser::bgp::attributes::attr_10_13_cluster::{encode_clusters, parse_clusters};
35use crate::parser::bgp::attributes::attr_14_15_nlri::{encode_nlri, parse_nlri};
36use crate::parser::bgp::attributes::attr_16_25_extended_communities::{
37    encode_extended_communities, encode_ipv6_extended_communities, parse_extended_community,
38    parse_ipv6_extended_community,
39};
40use crate::parser::bgp::attributes::attr_32_large_communities::{
41    encode_large_communities, parse_large_communities,
42};
43use crate::parser::bgp::attributes::attr_35_otc::{
44    encode_only_to_customer, parse_only_to_customer,
45};
46use crate::parser::ReadUtils;
47
48/// Parse BGP attributes given a slice of u8 and some options.
49///
50/// The `data: &[u8]` contains the entirety of the attributes bytes, therefore the size of
51/// the slice is the total byte length of the attributes section of the message.
52pub fn parse_attributes(
53    mut data: Bytes,
54    asn_len: &AsnLength,
55    add_path: bool,
56    afi: Option<Afi>,
57    safi: Option<Safi>,
58    prefixes: Option<&[NetworkPrefix]>,
59) -> Result<Attributes, ParserError> {
60    let mut attributes: Vec<Attribute> = Vec::with_capacity(20);
61
62    while data.remaining() >= 3 {
63        // each attribute is at least 3 bytes: flag(1) + type(1) + length(1)
64        // thus the while loop condition is set to be at least 3 bytes to read.
65
66        // has content to read
67        let flag = AttrFlags::from_bits_retain(data.get_u8());
68        let attr_type = data.get_u8();
69        let attr_length = match flag.contains(AttrFlags::EXTENDED) {
70            false => data.get_u8() as usize,
71            true => data.get_u16() as usize,
72        };
73
74        let mut partial = false;
75        if flag.contains(AttrFlags::PARTIAL) {
76            /*
77                https://datatracker.ietf.org/doc/html/rfc4271#section-4.3
78
79            > The third high-order bit (bit 2) of the Attribute Flags octet
80            > is the Partial bit.  It defines whether the information
81            > contained in the optional transitive attribute is partial (if
82            > set to 1) or complete (if set to 0).  For well-known attributes
83            > and for optional non-transitive attributes, the Partial bit
84            > MUST be set to 0.
85            */
86            partial = true;
87        }
88
89        debug!(
90            "reading attribute: type -- {:?}, length -- {}",
91            &attr_type, attr_length
92        );
93        let attr_type = match AttrType::from(attr_type) {
94            attr_type @ AttrType::Unknown(unknown_type) => {
95                // skip pass the remaining bytes of this attribute
96                let bytes = data.read_n_bytes(attr_length)?;
97                let attr_value = match get_deprecated_attr_type(unknown_type) {
98                    Some(t) => {
99                        debug!("deprecated attribute type: {} - {}", unknown_type, t);
100                        AttributeValue::Deprecated(AttrRaw { attr_type, bytes })
101                    }
102                    None => {
103                        debug!("unknown attribute type: {}", unknown_type);
104                        AttributeValue::Unknown(AttrRaw { attr_type, bytes })
105                    }
106                };
107
108                assert_eq!(attr_type, attr_value.attr_type());
109                attributes.push(Attribute {
110                    value: attr_value,
111                    flag,
112                });
113                continue;
114            }
115            t => t,
116        };
117
118        let bytes_left = data.remaining();
119
120        if data.remaining() < attr_length {
121            warn!(
122                "not enough bytes: input bytes left - {}, want to read - {}; skipping",
123                bytes_left, attr_length
124            );
125            // break and return already parsed attributes
126            break;
127        }
128
129        // we know data has enough bytes to read, so we can split the bytes into a new Bytes object
130        data.has_n_remaining(attr_length)?;
131        let mut attr_data = data.split_to(attr_length);
132
133        let attr = match attr_type {
134            AttrType::ORIGIN => parse_origin(attr_data),
135            AttrType::AS_PATH => {
136                parse_as_path(attr_data, asn_len).map(|path| AttributeValue::AsPath {
137                    path,
138                    is_as4: false,
139                })
140            }
141            AttrType::NEXT_HOP => parse_next_hop(attr_data, &afi),
142            AttrType::MULTI_EXIT_DISCRIMINATOR => parse_med(attr_data),
143            AttrType::LOCAL_PREFERENCE => parse_local_pref(attr_data),
144            AttrType::ATOMIC_AGGREGATE => Ok(AttributeValue::AtomicAggregate),
145            AttrType::AGGREGATOR => {
146                parse_aggregator(attr_data, asn_len).map(|(asn, id)| AttributeValue::Aggregator {
147                    asn,
148                    id,
149                    is_as4: false,
150                })
151            }
152            AttrType::ORIGINATOR_ID => parse_originator_id(attr_data),
153            AttrType::CLUSTER_LIST => parse_clusters(attr_data),
154            AttrType::MP_REACHABLE_NLRI => {
155                parse_nlri(attr_data, &afi, &safi, &prefixes, true, add_path)
156            }
157            AttrType::MP_UNREACHABLE_NLRI => {
158                parse_nlri(attr_data, &afi, &safi, &prefixes, false, add_path)
159            }
160            AttrType::AS4_PATH => parse_as_path(attr_data, &AsnLength::Bits32)
161                .map(|path| AttributeValue::AsPath { path, is_as4: true }),
162            AttrType::AS4_AGGREGATOR => {
163                parse_aggregator(attr_data, &AsnLength::Bits32).map(|(asn, id)| {
164                    AttributeValue::Aggregator {
165                        asn,
166                        id,
167                        is_as4: true,
168                    }
169                })
170            }
171
172            // communities
173            AttrType::COMMUNITIES => parse_regular_communities(attr_data),
174            AttrType::LARGE_COMMUNITIES => parse_large_communities(attr_data),
175            AttrType::EXTENDED_COMMUNITIES => parse_extended_community(attr_data),
176            AttrType::IPV6_ADDRESS_SPECIFIC_EXTENDED_COMMUNITIES => {
177                parse_ipv6_extended_community(attr_data)
178            }
179            AttrType::DEVELOPMENT => {
180                let mut value = vec![];
181                for _i in 0..attr_length {
182                    value.push(attr_data.get_u8());
183                }
184                Ok(AttributeValue::Development(value))
185            }
186            AttrType::ONLY_TO_CUSTOMER => parse_only_to_customer(attr_data),
187            _ => Err(ParserError::Unsupported(format!(
188                "unsupported attribute type: {:?}",
189                attr_type
190            ))),
191        };
192
193        match attr {
194            Ok(value) => {
195                assert_eq!(attr_type, value.attr_type());
196                attributes.push(Attribute { value, flag });
197            }
198            Err(e) => {
199                if partial {
200                    // it's ok to have errors when reading partial bytes
201                    debug!("PARTIAL: {}", e);
202                } else {
203                    debug!("{}", e);
204                }
205                continue;
206            }
207        };
208    }
209
210    Ok(Attributes::from(attributes))
211}
212
213impl Attribute {
214    pub fn encode(&self, add_path: bool, asn_len: AsnLength) -> Bytes {
215        let mut bytes = BytesMut::new();
216
217        let flag = self.flag.bits();
218        let type_code = self.value.attr_type().into();
219
220        bytes.put_u8(flag);
221        bytes.put_u8(type_code);
222
223        let value_bytes = match &self.value {
224            AttributeValue::Origin(v) => encode_origin(v),
225            AttributeValue::AsPath { path, is_as4 } => {
226                let four_byte = match is_as4 {
227                    true => AsnLength::Bits32,
228                    false => match asn_len.is_four_byte() {
229                        true => AsnLength::Bits32,
230                        false => AsnLength::Bits16,
231                    },
232                };
233                encode_as_path(path, four_byte)
234            }
235            AttributeValue::NextHop(v) => encode_next_hop(v),
236            AttributeValue::MultiExitDiscriminator(v) => encode_med(*v),
237            AttributeValue::LocalPreference(v) => encode_local_pref(*v),
238            AttributeValue::OnlyToCustomer(v) => encode_only_to_customer(v.into()),
239            AttributeValue::AtomicAggregate => Bytes::default(),
240            AttributeValue::Aggregator { asn, id, is_as4: _ } => {
241                encode_aggregator(asn, &IpAddr::from(*id))
242            }
243            AttributeValue::Communities(v) => encode_regular_communities(v),
244            AttributeValue::ExtendedCommunities(v) => encode_extended_communities(v),
245            AttributeValue::LargeCommunities(v) => encode_large_communities(v),
246            AttributeValue::Ipv6AddressSpecificExtendedCommunities(v) => {
247                encode_ipv6_extended_communities(v)
248            }
249            AttributeValue::OriginatorId(v) => encode_originator_id(&IpAddr::from(*v)),
250            AttributeValue::Clusters(v) => encode_clusters(v),
251            AttributeValue::MpReachNlri(v) => encode_nlri(v, true, add_path),
252            AttributeValue::MpUnreachNlri(v) => encode_nlri(v, false, add_path),
253            AttributeValue::Development(v) => Bytes::from(v.to_owned()),
254            AttributeValue::Deprecated(v) => Bytes::from(v.bytes.to_owned()),
255            AttributeValue::Unknown(v) => Bytes::from(v.bytes.to_owned()),
256        };
257
258        match self.is_extended() {
259            false => {
260                bytes.put_u8(value_bytes.len() as u8);
261            }
262            true => {
263                bytes.put_u16(value_bytes.len() as u16);
264            }
265        }
266        bytes.extend(value_bytes);
267        bytes.freeze()
268    }
269}
270
271impl Attributes {
272    pub fn encode(&self, add_path: bool, asn_len: AsnLength) -> Bytes {
273        let mut bytes = BytesMut::new();
274        for attr in &self.inner {
275            bytes.extend(attr.encode(add_path, asn_len));
276        }
277        bytes.freeze()
278    }
279}
280
281#[cfg(test)]
282mod tests {
283    use super::*;
284
285    #[test]
286    fn test_unknwon_attribute_type() {
287        let data = Bytes::from(vec![0x40, 0xFE, 0x00]);
288        let asn_len = AsnLength::Bits16;
289        let add_path = false;
290        let afi = None;
291        let safi = None;
292        let prefixes = None;
293        let attributes = parse_attributes(data, &asn_len, add_path, afi, safi, prefixes);
294        assert!(attributes.is_ok());
295        let attributes = attributes.unwrap();
296        assert_eq!(attributes.inner.len(), 1);
297        assert_eq!(
298            attributes.inner[0].value.attr_type(),
299            AttrType::Unknown(254)
300        );
301    }
302}