bgpkit_parser/parser/mrt/messages/
bgp4mp.rs1use crate::error::{EncodingError, 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;
7use std::net::{IpAddr, Ipv4Addr};
8
9pub(crate) fn is_short_zebra_open(data: &Bytes, asn_len: &AsnLength) -> bool {
10 if !matches!(asn_len, AsnLength::Bits16) {
11 return false;
12 }
13
14 let asn_bytes = asn_len.bytes() * 2;
15 data.len() >= asn_bytes + 19
16 && data[asn_bytes..asn_bytes + 16] == [0xff; 16]
17 && data[asn_bytes + 18] == BgpMessageType::OPEN as u8
18}
19
20pub(crate) fn uses_zebra_compat(sub_type: u16, data: &Bytes) -> bool {
21 match Bgp4MpType::try_from(sub_type) {
22 Ok(Bgp4MpType::StateChange) => data.len() == 8,
23 Ok(
24 Bgp4MpType::Message
25 | Bgp4MpType::MessageLocal
26 | Bgp4MpType::MessageAddpath
27 | Bgp4MpType::MessageLocalAddpath,
28 ) => is_short_zebra_open(data, &AsnLength::Bits16),
29 _ => false,
30 }
31}
32
33pub fn parse_bgp4mp(sub_type: u16, input: Bytes) -> Result<Bgp4MpEnum, ParserError> {
38 let bgp4mp_type: Bgp4MpType = Bgp4MpType::try_from(sub_type)?;
39 let msg: Bgp4MpEnum = match bgp4mp_type {
40 Bgp4MpType::StateChange => Bgp4MpEnum::StateChange(parse_bgp4mp_state_change(
41 input,
42 AsnLength::Bits16,
43 &bgp4mp_type,
44 )?),
45 Bgp4MpType::StateChangeAs4 => Bgp4MpEnum::StateChange(parse_bgp4mp_state_change(
46 input,
47 AsnLength::Bits32,
48 &bgp4mp_type,
49 )?),
50 Bgp4MpType::Message | Bgp4MpType::MessageLocal => Bgp4MpEnum::Message(
51 parse_bgp4mp_message(input, false, AsnLength::Bits16, &bgp4mp_type)?,
52 ),
53 Bgp4MpType::MessageAs4 | Bgp4MpType::MessageAs4Local => Bgp4MpEnum::Message(
54 parse_bgp4mp_message(input, false, AsnLength::Bits32, &bgp4mp_type)?,
55 ),
56 Bgp4MpType::MessageAddpath | Bgp4MpType::MessageLocalAddpath => Bgp4MpEnum::Message(
57 parse_bgp4mp_message(input, true, AsnLength::Bits16, &bgp4mp_type)?,
58 ),
59 Bgp4MpType::MessageAs4Addpath | Bgp4MpType::MessageLocalAs4Addpath => Bgp4MpEnum::Message(
60 parse_bgp4mp_message(input, true, AsnLength::Bits32, &bgp4mp_type)?,
61 ),
62 };
63
64 Ok(msg)
65}
66
67pub(crate) fn validate_bgp4mp_afi(afi: &Afi) -> Result<(), ParserError> {
115 match afi {
116 Afi::Ipv4 | Afi::Ipv6 => Ok(()),
117 Afi::LinkState => Err(ParserError::ParseError(
118 "Link-State AFI is invalid in a BGP4MP envelope".to_string(),
119 )),
120 }
121}
122
123pub(crate) fn bgp4mp_message_payload_len(
124 afi: &Afi,
125 asn_len: &AsnLength,
126 total_size: usize,
127) -> Result<usize, ParserError> {
128 validate_bgp4mp_afi(afi)?;
129 let ip_size = if matches!(afi, Afi::Ipv4) {
130 4 * 2
131 } else {
132 16 * 2
133 };
134 let asn_size = match asn_len {
135 AsnLength::Bits16 => 2 * 2,
136 AsnLength::Bits32 => 2 * 4,
137 };
138 Ok(total_size
142 .saturating_sub(asn_size)
143 .saturating_sub(2)
144 .saturating_sub(2)
145 .saturating_sub(ip_size))
146}
147pub fn parse_bgp4mp_message(
163 mut data: Bytes,
164 add_path: bool,
165 asn_len: AsnLength,
166 msg_type: &Bgp4MpType,
167) -> Result<Bgp4MpMessage, ParserError> {
168 let total_size = data.len();
169 let is_short_zebra_open = is_short_zebra_open(&data, &asn_len);
170
171 let peer_asn: Asn = data.read_asn(asn_len)?;
172 let local_asn: Asn = data.read_asn(asn_len)?;
173
174 if is_short_zebra_open {
179 let bgp_message = parse_bgp_message(&mut data, add_path, &asn_len)?;
180 return Ok(Bgp4MpMessage {
181 msg_type: *msg_type,
182 peer_asn,
183 local_asn,
184 interface_index: 0,
185 peer_ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
186 local_ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
187 bgp_message,
188 });
189 }
190
191 let interface_index: u16 = data.read_u16()?;
192 let afi: Afi = data.read_afi()?;
193 let should_read = bgp4mp_message_payload_len(&afi, &asn_len, total_size)?;
194 let peer_ip = data.read_address(&afi)?;
195 let local_ip = data.read_address(&afi)?;
196
197 if should_read != data.remaining() {
198 return Err(ParserError::TruncatedMsg(format!(
199 "truncated bgp4mp message: should read {} bytes, have {} bytes available",
200 should_read,
201 data.remaining()
202 )));
203 }
204 let bgp_message: BgpMessage = parse_bgp_message(&mut data, add_path, &asn_len)?;
205
206 Ok(Bgp4MpMessage {
207 msg_type: *msg_type,
208 peer_asn,
209 local_asn,
210 interface_index,
211 peer_ip,
212 local_ip,
213 bgp_message,
214 })
215}
216
217impl Bgp4MpMessage {
218 pub fn encode(&self, asn_len: AsnLength) -> Result<Bytes, EncodingError> {
219 let mut bytes = BytesMut::new();
220 bytes.extend(encode_asn(&self.peer_asn, &asn_len));
221 bytes.extend(encode_asn(&self.local_asn, &asn_len));
222 bytes.put_u16(self.interface_index);
223 bytes.put_u16(address_family(&self.peer_ip));
224 bytes.extend(encode_ipaddr(&self.peer_ip));
225 bytes.extend(encode_ipaddr(&self.local_ip));
226 bytes.put_slice(&self.bgp_message.encode(asn_len)?);
227 Ok(bytes.freeze())
228 }
229}
230
231pub fn parse_bgp4mp_state_change(
263 mut input: Bytes,
264 asn_len: AsnLength,
265 msg_type: &Bgp4MpType,
266) -> Result<Bgp4MpStateChange, ParserError> {
267 let is_short_zebra_state_change = matches!(asn_len, AsnLength::Bits16) && input.len() == 8;
268 let peer_asn: Asn = input.read_asn(asn_len)?;
269 let local_asn: Asn = input.read_asn(asn_len)?;
270
271 if is_short_zebra_state_change {
274 let old_state = BgpState::try_from(input.read_u16()?)?;
275 let new_state = BgpState::try_from(input.read_u16()?)?;
276 return Ok(Bgp4MpStateChange {
277 msg_type: *msg_type,
278 peer_asn,
279 local_asn,
280 interface_index: 0,
281 peer_ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
282 local_addr: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
283 old_state,
284 new_state,
285 });
286 }
287
288 let interface_index: u16 = input.read_u16()?;
289 let address_family: Afi = input.read_afi()?;
290 validate_bgp4mp_afi(&address_family)?;
291 let peer_ip = input.read_address(&address_family)?;
292 let local_addr = input.read_address(&address_family)?;
293 let old_state = BgpState::try_from(input.read_u16()?)?;
294 let new_state = BgpState::try_from(input.read_u16()?)?;
295 Ok(Bgp4MpStateChange {
296 msg_type: *msg_type,
297 peer_asn,
298 local_asn,
299 interface_index,
300 peer_ip,
301 local_addr,
302 old_state,
303 new_state,
304 })
305}
306
307impl Bgp4MpStateChange {
308 pub fn encode(&self, asn_len: AsnLength) -> Bytes {
309 let mut bytes = BytesMut::new();
310 bytes.extend(encode_asn(&self.peer_asn, &asn_len));
311 bytes.extend(encode_asn(&self.local_asn, &asn_len));
312 bytes.put_u16(self.interface_index);
313 bytes.put_u16(address_family(&self.peer_ip));
314 bytes.extend(encode_ipaddr(&self.peer_ip));
315 bytes.extend(encode_ipaddr(&self.local_addr));
316 bytes.put_u16(self.old_state as u16);
317 bytes.put_u16(self.new_state as u16);
318 bytes.freeze()
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325 use std::net::IpAddr;
326 use std::str::FromStr;
327
328 #[test]
329 fn test_bgp4mp_message_encode_uses_subtype_asn_width() {
330 let message = Bgp4MpMessage {
331 msg_type: Bgp4MpType::Message,
332 peer_asn: Asn::new_32bit(65000),
333 local_asn: Asn::new_32bit(65001),
334 interface_index: 1,
335 peer_ip: IpAddr::from_str("10.0.0.1").unwrap(),
336 local_ip: IpAddr::from_str("10.0.0.2").unwrap(),
337 bgp_message: BgpMessage::KeepAlive,
338 };
339
340 let encoded = message.encode(AsnLength::Bits16).unwrap();
341 let parsed = parse_bgp4mp(Bgp4MpType::Message as u16, encoded).unwrap();
342
343 match parsed {
344 Bgp4MpEnum::Message(parsed) => {
345 assert_eq!(parsed.peer_asn, Asn::new_16bit(65000));
346 assert_eq!(parsed.local_asn, Asn::new_16bit(65001));
347 assert_eq!(parsed.interface_index, 1);
348 assert_eq!(parsed.peer_ip, message.peer_ip);
349 assert_eq!(parsed.local_ip, message.local_ip);
350 assert_eq!(parsed.bgp_message, BgpMessage::KeepAlive);
351 }
352 other => panic!("unexpected BGP4MP message: {other:?}"),
353 }
354 }
355
356 #[test]
357 fn test_bgp4mp_message_rejects_link_state_envelope_afi() {
358 let mut data = BytesMut::new();
359 data.put_u16(65000);
360 data.put_u16(65001);
361 data.put_u16(0);
362 data.put_u16(Afi::LinkState as u16);
363 data.put_slice(&BgpMessage::KeepAlive.encode(AsnLength::Bits16).unwrap());
364
365 let error = match parse_bgp4mp(Bgp4MpType::Message as u16, data.freeze()) {
366 Err(error) => error,
367 Ok(message) => panic!("unexpectedly parsed BGP4MP message: {message:?}"),
368 };
369 assert!(matches!(
370 error,
371 ParserError::ParseError(message)
372 if message == "Link-State AFI is invalid in a BGP4MP envelope"
373 ));
374 }
375
376 #[test]
377 fn test_bgp4mp_state_change_rejects_link_state_envelope_afi() {
378 let mut data = BytesMut::new();
379 data.put_u16(65000);
380 data.put_u16(65001);
381 data.put_u16(0);
382 data.put_u16(Afi::LinkState as u16);
383 data.put_u16(BgpState::Idle as u16);
384 data.put_u16(BgpState::Connect as u16);
385
386 let error = match parse_bgp4mp(Bgp4MpType::StateChange as u16, data.freeze()) {
387 Err(error) => error,
388 Ok(message) => panic!("unexpectedly parsed BGP4MP state change: {message:?}"),
389 };
390 assert!(matches!(
391 error,
392 ParserError::ParseError(message)
393 if message == "Link-State AFI is invalid in a BGP4MP envelope"
394 ));
395 }
396}