bgpkit_parser/parser/mrt/messages/
bgp4mp.rs1use 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
8pub 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
42pub(crate) fn validate_bgp4mp_afi(afi: &Afi) -> Result<(), ParserError> {
90 match afi {
91 Afi::Ipv4 | Afi::Ipv6 => Ok(()),
92 Afi::LinkState => Err(ParserError::ParseError(
93 "Link-State AFI is invalid in a BGP4MP envelope".to_string(),
94 )),
95 }
96}
97
98pub(crate) fn bgp4mp_message_payload_len(
99 afi: &Afi,
100 asn_len: &AsnLength,
101 total_size: usize,
102) -> Result<usize, ParserError> {
103 validate_bgp4mp_afi(afi)?;
104 let ip_size = if matches!(afi, Afi::Ipv4) {
105 4 * 2
106 } else {
107 16 * 2
108 };
109 let asn_size = match asn_len {
110 AsnLength::Bits16 => 2 * 2,
111 AsnLength::Bits32 => 2 * 4,
112 };
113 Ok(total_size
117 .saturating_sub(asn_size)
118 .saturating_sub(2)
119 .saturating_sub(2)
120 .saturating_sub(ip_size))
121}
122pub fn parse_bgp4mp_message(
138 mut data: Bytes,
139 add_path: bool,
140 asn_len: AsnLength,
141 msg_type: &Bgp4MpType,
142) -> Result<Bgp4MpMessage, ParserError> {
143 let total_size = data.len();
144
145 let peer_asn: Asn = data.read_asn(asn_len)?;
146 let local_asn: Asn = data.read_asn(asn_len)?;
147 let interface_index: u16 = data.read_u16()?;
148 let afi: Afi = data.read_afi()?;
149 let should_read = bgp4mp_message_payload_len(&afi, &asn_len, total_size)?;
150 let peer_ip = data.read_address(&afi)?;
151 let local_ip = data.read_address(&afi)?;
152
153 if should_read != data.remaining() {
154 return Err(ParserError::TruncatedMsg(format!(
155 "truncated bgp4mp message: should read {} bytes, have {} bytes available",
156 should_read,
157 data.remaining()
158 )));
159 }
160 let bgp_message: BgpMessage = parse_bgp_message(&mut data, add_path, &asn_len)?;
161
162 Ok(Bgp4MpMessage {
163 msg_type: *msg_type,
164 peer_asn,
165 local_asn,
166 interface_index,
167 peer_ip,
168 local_ip,
169 bgp_message,
170 })
171}
172
173impl Bgp4MpMessage {
174 pub fn encode(&self, asn_len: AsnLength) -> Bytes {
175 let mut bytes = BytesMut::new();
176 bytes.extend(encode_asn(&self.peer_asn, &asn_len));
177 bytes.extend(encode_asn(&self.local_asn, &asn_len));
178 bytes.put_u16(self.interface_index);
179 bytes.put_u16(address_family(&self.peer_ip));
180 bytes.extend(encode_ipaddr(&self.peer_ip));
181 bytes.extend(encode_ipaddr(&self.local_ip));
182 bytes.extend(&self.bgp_message.encode(asn_len));
183 bytes.freeze()
184 }
185}
186
187pub fn parse_bgp4mp_state_change(
219 mut input: Bytes,
220 asn_len: AsnLength,
221 msg_type: &Bgp4MpType,
222) -> Result<Bgp4MpStateChange, ParserError> {
223 let peer_asn: Asn = input.read_asn(asn_len)?;
224 let local_asn: Asn = input.read_asn(asn_len)?;
225 let interface_index: u16 = input.read_u16()?;
226 let address_family: Afi = input.read_afi()?;
227 validate_bgp4mp_afi(&address_family)?;
228 let peer_ip = input.read_address(&address_family)?;
229 let local_addr = input.read_address(&address_family)?;
230 let old_state = BgpState::try_from(input.read_u16()?)?;
231 let new_state = BgpState::try_from(input.read_u16()?)?;
232 Ok(Bgp4MpStateChange {
233 msg_type: *msg_type,
234 peer_asn,
235 local_asn,
236 interface_index,
237 peer_ip,
238 local_addr,
239 old_state,
240 new_state,
241 })
242}
243
244impl Bgp4MpStateChange {
245 pub fn encode(&self, asn_len: AsnLength) -> Bytes {
246 let mut bytes = BytesMut::new();
247 bytes.extend(encode_asn(&self.peer_asn, &asn_len));
248 bytes.extend(encode_asn(&self.local_asn, &asn_len));
249 bytes.put_u16(self.interface_index);
250 bytes.put_u16(address_family(&self.peer_ip));
251 bytes.extend(encode_ipaddr(&self.peer_ip));
252 bytes.extend(encode_ipaddr(&self.local_addr));
253 bytes.put_u16(self.old_state as u16);
254 bytes.put_u16(self.new_state as u16);
255 bytes.freeze()
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262 use std::net::IpAddr;
263 use std::str::FromStr;
264
265 #[test]
266 fn test_bgp4mp_message_encode_uses_subtype_asn_width() {
267 let message = Bgp4MpMessage {
268 msg_type: Bgp4MpType::Message,
269 peer_asn: Asn::new_32bit(65000),
270 local_asn: Asn::new_32bit(65001),
271 interface_index: 1,
272 peer_ip: IpAddr::from_str("10.0.0.1").unwrap(),
273 local_ip: IpAddr::from_str("10.0.0.2").unwrap(),
274 bgp_message: BgpMessage::KeepAlive,
275 };
276
277 let encoded = message.encode(AsnLength::Bits16);
278 let parsed = parse_bgp4mp(Bgp4MpType::Message as u16, encoded).unwrap();
279
280 match parsed {
281 Bgp4MpEnum::Message(parsed) => {
282 assert_eq!(parsed.peer_asn, Asn::new_16bit(65000));
283 assert_eq!(parsed.local_asn, Asn::new_16bit(65001));
284 assert_eq!(parsed.interface_index, 1);
285 assert_eq!(parsed.peer_ip, message.peer_ip);
286 assert_eq!(parsed.local_ip, message.local_ip);
287 assert_eq!(parsed.bgp_message, BgpMessage::KeepAlive);
288 }
289 other => panic!("unexpected BGP4MP message: {other:?}"),
290 }
291 }
292
293 #[test]
294 fn test_bgp4mp_message_rejects_link_state_envelope_afi() {
295 let mut data = BytesMut::new();
296 data.put_u16(65000);
297 data.put_u16(65001);
298 data.put_u16(0);
299 data.put_u16(Afi::LinkState as u16);
300 data.extend(&BgpMessage::KeepAlive.encode(AsnLength::Bits16));
301
302 let error = match parse_bgp4mp(Bgp4MpType::Message as u16, data.freeze()) {
303 Err(error) => error,
304 Ok(message) => panic!("unexpectedly parsed BGP4MP message: {message:?}"),
305 };
306 assert!(matches!(
307 error,
308 ParserError::ParseError(message)
309 if message == "Link-State AFI is invalid in a BGP4MP envelope"
310 ));
311 }
312
313 #[test]
314 fn test_bgp4mp_state_change_rejects_link_state_envelope_afi() {
315 let mut data = BytesMut::new();
316 data.put_u16(65000);
317 data.put_u16(65001);
318 data.put_u16(0);
319 data.put_u16(Afi::LinkState as u16);
320 data.put_u16(BgpState::Idle as u16);
321 data.put_u16(BgpState::Connect as u16);
322
323 let error = match parse_bgp4mp(Bgp4MpType::StateChange as u16, data.freeze()) {
324 Err(error) => error,
325 Ok(message) => panic!("unexpectedly parsed BGP4MP state change: {message:?}"),
326 };
327 assert!(matches!(
328 error,
329 ParserError::ParseError(message)
330 if message == "Link-State AFI is invalid in a BGP4MP envelope"
331 ));
332 }
333}