bgpkit_parser/parser/mrt/messages/
bgp4mp.rs

1use crate::error::ParserError;
2use crate::models::*;
3use crate::parser::bgp::messages::parse_bgp_message;
4use crate::parser::{encode_asn, encode_ipaddr, ReadUtils};
5use bytes::{Buf, BufMut, Bytes, BytesMut};
6use std::convert::TryFrom;
7
8/// Parse MRT BGP4MP type
9///
10/// RFC: <https://www.rfc-editor.org/rfc/rfc6396#section-4.4>
11///
12pub fn parse_bgp4mp(sub_type: u16, input: Bytes) -> Result<Bgp4MpEnum, ParserError> {
13    let bgp4mp_type: Bgp4MpType = Bgp4MpType::try_from(sub_type)?;
14    let msg: Bgp4MpEnum = match bgp4mp_type {
15        Bgp4MpType::StateChange => Bgp4MpEnum::StateChange(parse_bgp4mp_state_change(
16            input,
17            AsnLength::Bits16,
18            &bgp4mp_type,
19        )?),
20        Bgp4MpType::StateChangeAs4 => Bgp4MpEnum::StateChange(parse_bgp4mp_state_change(
21            input,
22            AsnLength::Bits32,
23            &bgp4mp_type,
24        )?),
25        Bgp4MpType::Message | Bgp4MpType::MessageLocal => Bgp4MpEnum::Message(
26            parse_bgp4mp_message(input, false, AsnLength::Bits16, &bgp4mp_type)?,
27        ),
28        Bgp4MpType::MessageAs4 | Bgp4MpType::MessageAs4Local => Bgp4MpEnum::Message(
29            parse_bgp4mp_message(input, false, AsnLength::Bits32, &bgp4mp_type)?,
30        ),
31        Bgp4MpType::MessageAddpath | Bgp4MpType::MessageLocalAddpath => Bgp4MpEnum::Message(
32            parse_bgp4mp_message(input, true, AsnLength::Bits16, &bgp4mp_type)?,
33        ),
34        Bgp4MpType::MessageAs4Addpath | Bgp4MpType::MessageLocalAs4Addpath => Bgp4MpEnum::Message(
35            parse_bgp4mp_message(input, true, AsnLength::Bits32, &bgp4mp_type)?,
36        ),
37    };
38
39    Ok(msg)
40}
41
42fn total_should_read(afi: &Afi, asn_len: &AsnLength, total_size: usize) -> usize {
43    let ip_size = match afi {
44        Afi::Ipv4 => 4 * 2,
45        Afi::Ipv6 => 16 * 2,
46    };
47    let asn_size = match asn_len {
48        AsnLength::Bits16 => 2 * 2,
49        AsnLength::Bits32 => 2 * 4,
50    };
51    total_size - asn_size - 2 - 2 - ip_size
52}
53/*
54   0                   1                   2                   3
55   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
56  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57  |         Peer AS Number        |        Local AS Number        |
58  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59  |        Interface Index        |        Address Family         |
60  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61  |                      Peer IP Address (variable)               |
62  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63  |                      Local IP Address (variable)              |
64  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65  |                    BGP Message... (variable)
66  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67*/
68pub fn parse_bgp4mp_message(
69    mut data: Bytes,
70    add_path: bool,
71    asn_len: AsnLength,
72    msg_type: &Bgp4MpType,
73) -> Result<Bgp4MpMessage, ParserError> {
74    let total_size = data.len();
75
76    let peer_asn: Asn = data.read_asn(asn_len)?;
77    let local_asn: Asn = data.read_asn(asn_len)?;
78    let interface_index: u16 = data.read_u16()?;
79    let afi: Afi = data.read_afi()?;
80    let peer_ip = data.read_address(&afi)?;
81    let local_ip = data.read_address(&afi)?;
82
83    let should_read = total_should_read(&afi, &asn_len, total_size);
84    if should_read != data.remaining() {
85        return Err(ParserError::TruncatedMsg(format!(
86            "truncated bgp4mp message: should read {} bytes, have {} bytes available",
87            should_read,
88            data.remaining()
89        )));
90    }
91    let bgp_message: BgpMessage = parse_bgp_message(&mut data, add_path, &asn_len)?;
92
93    Ok(Bgp4MpMessage {
94        msg_type: *msg_type,
95        peer_asn,
96        local_asn,
97        interface_index,
98        peer_ip,
99        local_ip,
100        bgp_message,
101    })
102}
103
104impl Bgp4MpMessage {
105    pub fn encode(&self, add_path: bool, asn_len: AsnLength) -> Bytes {
106        let mut bytes = BytesMut::new();
107        bytes.extend(self.peer_asn.encode());
108        bytes.extend(self.local_asn.encode());
109        bytes.put_u16(self.interface_index);
110        bytes.put_u16(address_family(&self.peer_ip));
111        bytes.extend(encode_ipaddr(&self.peer_ip));
112        bytes.extend(encode_ipaddr(&self.local_ip));
113        bytes.extend(&self.bgp_message.encode(add_path, asn_len));
114        bytes.freeze()
115    }
116}
117
118/*
119   0                   1                   2                   3
120   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
121  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
122  |         Peer AS Number        |        Local AS Number        |
123  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
124  |        Interface Index        |        Address Family         |
125  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
126  |                      Peer IP Address (variable)               |
127  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
128  |                      Local IP Address (variable)              |
129  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
130  |            Old State          |          New State            |
131  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
132
133   0                   1                   2                   3
134   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
135  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
136  |                         Peer AS Number                        |
137  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
138  |                         Local AS Number                       |
139  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
140  |        Interface Index        |        Address Family         |
141  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
142  |                      Peer IP Address (variable)               |
143  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
144  |                      Local IP Address (variable)              |
145  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
146  |            Old State          |          New State            |
147  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
148*/
149pub fn parse_bgp4mp_state_change(
150    mut input: Bytes,
151    asn_len: AsnLength,
152    msg_type: &Bgp4MpType,
153) -> Result<Bgp4MpStateChange, ParserError> {
154    let peer_asn: Asn = input.read_asn(asn_len)?;
155    let local_asn: Asn = input.read_asn(asn_len)?;
156    let interface_index: u16 = input.read_u16()?;
157    let address_family: Afi = input.read_afi()?;
158    let peer_addr = input.read_address(&address_family)?;
159    let local_addr = input.read_address(&address_family)?;
160    let old_state = BgpState::try_from(input.read_u16()?)?;
161    let new_state = BgpState::try_from(input.read_u16()?)?;
162    Ok(Bgp4MpStateChange {
163        msg_type: *msg_type,
164        peer_asn,
165        local_asn,
166        interface_index,
167        peer_addr,
168        local_addr,
169        old_state,
170        new_state,
171    })
172}
173
174impl Bgp4MpStateChange {
175    pub fn encode(&self, asn_len: AsnLength) -> Bytes {
176        let mut bytes = BytesMut::new();
177        bytes.extend(encode_asn(&self.peer_asn, &asn_len));
178        bytes.extend(encode_asn(&self.local_asn, &asn_len));
179        bytes.put_u16(self.interface_index);
180        bytes.put_u16(address_family(&self.peer_addr));
181        bytes.extend(encode_ipaddr(&self.peer_addr));
182        bytes.extend(encode_ipaddr(&self.local_addr));
183        bytes.put_u16(self.old_state as u16);
184        bytes.put_u16(self.new_state as u16);
185        bytes.freeze()
186    }
187}