bgp_rs/
lib.rs

1#![deny(missing_docs)]
2
3//! The `bgp-rs` crate provides functionality to parse BGP-formatted streams.
4//!
5//! # Examples
6//!
7//! ## Reading a MRT file containing BPG4MP messages
8//! ```
9//! use std::fs::File;
10//! use std::io::Cursor;
11//! use std::io::Read;
12//! use std::io::BufReader;
13//! use libflate::gzip::Decoder;
14//! use bgp_rs::{Identifier, PathAttribute};
15//! use mrt_rs::Record;
16//! use mrt_rs::bgp4mp::BGP4MP;
17//!
18//! // Download an update message.
19//! let file = File::open("res/mrt/updates.20190101.0000.gz").unwrap();
20//!
21//! // Decode the GZIP stream.
22//! let mut decoder = Decoder::new(BufReader::new(file)).unwrap();
23//!
24//! // Keep reading MRT (Header, Record) tuples till the end of the file has been reached.
25//! while let Ok(Some((_, record))) = mrt_rs::read(&mut decoder) {
26//!
27//!     // Extract BGP4MP::MESSAGE_AS4 entries.
28//!     if let Record::BGP4MP(BGP4MP::MESSAGE_AS4(x)) = record {
29//!
30//!         // Read each BGP (Header, Message)
31//!         let cursor = Cursor::new(x.message);
32//!         let mut reader = bgp_rs::Reader::new(cursor);
33//!         let (_, message) = reader.read().unwrap();
34//!
35//!         // If this is an UPDATE message that contains announcements, extract its origin.
36//!         if let bgp_rs::Message::Update(x) = message {
37//!             if x.is_announcement() {
38//!                 if let PathAttribute::AS_PATH(path) = x.get(Identifier::AS_PATH).unwrap()
39//!                 {
40//!                     // Test the path.origin() method.
41//!                     let origin = path.origin();
42//!
43//!                     // Do other stuff ...
44//!                 }
45//!             }
46//!         }
47//!     }
48//! }
49//! ```
50//!
51//! ## Reading a MRT file containing TABLE_DUMP_V2 messages
52//! ```
53//! use std::fs::File;
54//! use std::io::Cursor;
55//! use std::io::Read;
56//! use std::io::BufReader;
57//! use libflate::gzip::Decoder;
58//! use bgp_rs::{Identifier, PathAttribute, Capabilities};
59//! use mrt_rs::records::tabledump::TABLE_DUMP_V2;
60//! use mrt_rs::Record;
61//! use mrt_rs::bgp4mp::BGP4MP;
62//!
63//! // Download an update message.
64//! let file = File::open("res/mrt/bview.20100101.0759.gz").unwrap();
65//!
66//! // Decode the GZIP stream.
67//! let mut decoder = Decoder::new(BufReader::new(file)).unwrap();
68//!
69//! // Keep reading MRT (Header, Record) tuples till the end of the file has been reached.
70//! while let Ok(Some((_, record))) = mrt_rs::read(&mut decoder) {
71//!
72//!     // Extract TABLE_DUMP_V2::RIB_IPV4_UNICAST entries.
73//!     if let Record::TABLE_DUMP_V2(TABLE_DUMP_V2::RIB_IPV4_UNICAST(x)) = record {
74//!
75//!         // Loop over each route for this particular prefix.
76//!         for mut entry in x.entries {
77//!             let length = entry.attributes.len() as u64;
78//!             let mut cursor = Cursor::new(entry.attributes);
79//!
80//!             // Parse each PathAttribute in each route.
81//!             while cursor.position() < length {
82//!                 PathAttribute::parse(&mut cursor, &Default::default()).unwrap();
83//!             }
84//!         }
85//!     }
86//! }
87//! ```
88/// Contains the OPEN Message implementation
89pub mod open;
90pub use crate::open::*;
91/// Contains the NOTIFICATION Message implementation
92pub mod notification;
93pub use crate::notification::*;
94/// Contains the UPDATE Message implementation
95pub mod update;
96pub use crate::update::*;
97
98mod util;
99
100use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
101
102use std::convert::TryFrom;
103use std::fmt::{Debug, Display, Formatter};
104use std::io::{Error, ErrorKind, Read, Write};
105
106// RFC 4271: 4.1
107const BGP_MIN_MESSAGE_SIZE: usize = 19;
108const BGP_MAX_MESSAGE_SIZE: usize = 4096;
109
110/// Represents an Address Family Identifier. Currently only IPv4 and IPv6 are supported.
111/// Currently only IPv4, IPv6, and L2VPN are supported.
112#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
113#[repr(u16)]
114pub enum AFI {
115    /// Internet Protocol version 4 (32 bits)
116    IPV4 = 0x01,
117    /// Internet Protocol version 6 (128 bits)
118    IPV6 = 0x02,
119    /// L2VPN
120    L2VPN = 0x19,
121    /// BGPLS
122    BGPLS = 0x4004,
123}
124
125impl AFI {
126    fn empty_buffer(&self) -> Vec<u8> {
127        match self {
128            AFI::IPV4 => vec![0u8; 4],
129            AFI::IPV6 => vec![0u8; 16],
130            _ => unimplemented!(),
131        }
132    }
133}
134
135/// Convert u16 to AFI
136/// ```
137/// use std::convert::TryFrom;
138/// use bgp_rs::AFI;
139/// let val = 2u16;
140/// let afi = AFI::try_from(val).unwrap();
141/// assert_eq!(afi, AFI::IPV6);
142/// ```
143impl TryFrom<u16> for AFI {
144    type Error = Error;
145    fn try_from(v: u16) -> Result<Self, Self::Error> {
146        match v {
147            0x01 => Ok(AFI::IPV4),
148            0x02 => Ok(AFI::IPV6),
149            0x19 => Ok(AFI::L2VPN),
150            0x4004 => Ok(AFI::BGPLS),
151            _ => Err(Error::new(
152                ErrorKind::Other,
153                format!("Not a supported AFI: '{}'", v),
154            )),
155        }
156    }
157}
158
159/// Display AFI in a human-friendly format
160/// ```
161/// use bgp_rs::AFI;
162/// let afi = AFI::IPV6;
163/// assert_eq!(&afi.to_string(), "IPv6");
164/// ```
165impl Display for AFI {
166    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
167        use AFI::*;
168        let s = match self {
169            IPV4 => "IPv4",
170            IPV6 => "IPv6",
171            L2VPN => "L2VPN",
172            BGPLS => "BGPLS",
173        };
174        write!(f, "{}", s)
175    }
176}
177
178/// Represents an Subsequent Address Family Identifier. Currently only Unicast and Multicast are
179/// supported.
180#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
181#[repr(u8)]
182pub enum SAFI {
183    /// Unicast Forwarding [RFC4760]
184    Unicast = 1,
185    /// Multicast Forwarding [RFC4760]
186    Multicast = 2,
187    /// MPLS Labels [RFC3107]
188    Mpls = 4,
189    /// Multicast VPN
190    MulticastVpn = 5,
191    /// VPLS [draft-ietf-l2vpn-evpn]
192    Vpls = 65,
193    /// EVPN [draft-ietf-l2vpn-evpn]
194    Evpn = 70,
195    /// BGP LS [RFC7752]
196    BgpLs = 71,
197    /// BGP LS VPN [RFC7752]
198    BgpLsVpn = 72,
199    /// RTC [RFC4684]
200    Rtc = 132,
201    /// MPLS VPN [RFC4364]
202    MplsVpn = 128,
203    /// Flowspec Unicast
204    Flowspec = 133,
205    /// Flowspec Unicast
206    FlowspecVPN = 134,
207}
208
209/// Convert u8 to SAFI
210/// ```
211/// use std::convert::TryFrom;
212/// use bgp_rs::SAFI;
213/// let val = 1u8;
214/// let safi = SAFI::try_from(val).unwrap();
215/// assert_eq!(safi, SAFI::Unicast);
216/// ```
217impl TryFrom<u8> for SAFI {
218    type Error = Error;
219
220    fn try_from(v: u8) -> Result<Self, Self::Error> {
221        match v {
222            1 => Ok(SAFI::Unicast),
223            2 => Ok(SAFI::Multicast),
224            4 => Ok(SAFI::Mpls),
225            5 => Ok(SAFI::MulticastVpn),
226            65 => Ok(SAFI::Vpls),
227            70 => Ok(SAFI::Evpn),
228            71 => Ok(SAFI::BgpLs),
229            72 => Ok(SAFI::BgpLsVpn),
230            128 => Ok(SAFI::MplsVpn),
231            132 => Ok(SAFI::Rtc),
232            133 => Ok(SAFI::Flowspec),
233            134 => Ok(SAFI::FlowspecVPN),
234            _ => Err(std::io::Error::new(
235                std::io::ErrorKind::Other,
236                format!("Not a supported SAFI: '{}'", v),
237            )),
238        }
239    }
240}
241
242/// Display SAFI in a human-friendly format
243/// ```
244/// use bgp_rs::SAFI;
245/// let safi = SAFI::Flowspec;
246/// assert_eq!(&safi.to_string(), "Flowspec");
247/// ```
248impl Display for SAFI {
249    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
250        use SAFI::*;
251        let s = match self {
252            Unicast => "Unicast",
253            Multicast => "Multicast",
254            Mpls => "MPLS",
255            MulticastVpn => "Multicast VPN",
256            Vpls => "VPLS",
257            Evpn => "EVPN",
258            BgpLs => "BGPLS",
259            BgpLsVpn => "BGPLSVPN",
260            Rtc => "RTC",
261            MplsVpn => "MPLS VPN",
262            Flowspec => "Flowspec",
263            FlowspecVPN => "Flowspec VPN",
264        };
265        write!(f, "{}", s)
266    }
267}
268
269/// Represents the BGP header accompanying every BGP message.
270#[derive(Clone, Debug)]
271pub struct Header {
272    /// Predefined marker, must be set to all ones.
273    pub marker: [u8; 16],
274
275    /// Indicates the total length of the message, including the header in bytes.
276    pub length: u16,
277
278    /// Indicates the type of message that follows the header.
279    pub record_type: u8,
280}
281
282impl Header {
283    /// parse
284    pub fn parse(stream: &mut impl Read) -> Result<Header, Error> {
285        let mut marker = [0u8; 16];
286        stream.read_exact(&mut marker)?;
287
288        let length = stream.read_u16::<BigEndian>()?;
289        let record_type = stream.read_u8()?;
290
291        Ok(Header {
292            marker,
293            length,
294            record_type,
295        })
296    }
297
298    /// Writes self into the stream, including the length and record type.
299    pub fn encode(&self, buf: &mut impl Write) -> Result<(), Error> {
300        buf.write_all(&self.marker)?;
301        buf.write_u16::<BigEndian>(self.length)?;
302        buf.write_u8(self.record_type)
303    }
304}
305
306/// Represents a single BGP message.
307#[derive(Clone, Debug)]
308pub enum Message {
309    /// Represent a BGP OPEN message.
310    Open(Open),
311
312    /// Represent a BGP UPDATE message.
313    Update(Update),
314
315    /// Represent a BGP NOTIFICATION message.
316    Notification(Notification),
317
318    /// Represent a BGP KEEPALIVE message.
319    KeepAlive,
320
321    /// Represent a BGP ROUTE_REFRESH message.
322    RouteRefresh(RouteRefresh),
323}
324
325impl Message {
326    fn encode_noheader(&self, buf: &mut impl Write) -> Result<(), Error> {
327        match self {
328            Message::Open(open) => open.encode(buf),
329            Message::Update(update) => update.encode(buf),
330            Message::Notification(notification) => notification.encode(buf),
331            Message::KeepAlive => Ok(()),
332            Message::RouteRefresh(refresh) => refresh.encode(buf),
333        }
334    }
335
336    /// Writes message into the stream, including the appropriate header.
337    pub fn encode(&self, buf: &mut impl Write) -> Result<(), Error> {
338        let mut message_buf: Vec<u8> = Vec::with_capacity(BGP_MIN_MESSAGE_SIZE); // Start with minimum size
339        self.encode_noheader(&mut message_buf)?;
340        let message_length = message_buf.len();
341        if (message_length + BGP_MIN_MESSAGE_SIZE) > BGP_MAX_MESSAGE_SIZE {
342            return Err(Error::new(
343                ErrorKind::Other,
344                format!("Cannot encode message of length {}", message_length),
345            ));
346        }
347        let header = Header {
348            marker: [0xff; 16],
349            length: (message_length + BGP_MIN_MESSAGE_SIZE) as u16,
350            record_type: match self {
351                Message::Open(_) => 1,
352                Message::Update(_) => 2,
353                Message::Notification(_) => 3,
354                Message::KeepAlive => 4,
355                Message::RouteRefresh(_) => 5,
356            },
357        };
358        header.encode(buf)?;
359        buf.write_all(&message_buf)
360    }
361}
362
363/// Represents a BGP Route Refresh message.
364#[derive(Clone, Debug)]
365pub struct RouteRefresh {
366    /// Address Family being requested
367    pub afi: AFI,
368    /// Subsequent Address Family being requested
369    pub safi: SAFI,
370    /// This can be a subtype or RESERVED=0 for older senders
371    pub subtype: u8,
372}
373
374impl RouteRefresh {
375    fn parse(stream: &mut impl Read) -> Result<RouteRefresh, Error> {
376        let afi = AFI::try_from(stream.read_u16::<BigEndian>()?)?;
377        let subtype = stream.read_u8()?;
378        let safi = SAFI::try_from(stream.read_u8()?)?;
379
380        Ok(RouteRefresh { afi, safi, subtype })
381    }
382
383    /// Encode RouteRefresh to bytes
384    pub fn encode(&self, buf: &mut impl Write) -> Result<(), Error> {
385        buf.write_u16::<BigEndian>(self.afi as u16)?;
386        buf.write_u8(self.subtype)?;
387        buf.write_u8(self.safi as u8)
388    }
389}
390
391/// An abstract way of getting a reference to a Capabilities struct.
392/// This is used in Reader to allow use of either an owned Capabilites or a reference to one.
393pub trait CapabilitiesRef {
394    /// Gets a reference to the Capabilities
395    fn get_ref(&self) -> &Capabilities;
396}
397impl CapabilitiesRef for Capabilities {
398    fn get_ref(&self) -> &Capabilities {
399        self
400    }
401}
402impl<'a> CapabilitiesRef for &'a Capabilities {
403    fn get_ref(&self) -> &Capabilities {
404        self
405    }
406}
407
408/// The BGPReader can read BGP messages from a BGP-formatted stream.
409pub struct Reader<T, C>
410where
411    T: Read,
412    C: CapabilitiesRef,
413{
414    /// The stream from which BGP messages will be read.
415    pub stream: T,
416
417    /// Capability parameters that distinguish how BGP messages should be parsed.
418    pub capabilities: C,
419}
420
421impl<T, C> Reader<T, C>
422where
423    T: Read,
424    C: CapabilitiesRef,
425{
426    ///
427    /// Reads the next BGP message in the stream.
428    ///
429    /// # Panics
430    /// This function does not panic.
431    ///
432    /// # Errors
433    /// Any IO error will be returned while reading from the stream.
434    /// If an ill-formatted stream provided behavior will be undefined.
435    ///
436    /// # Safety
437    /// This function does not make use of unsafe code.
438    ///
439    pub fn read(&mut self) -> Result<(Header, Message), Error> {
440        // Parse the header.
441        let mut marker: [u8; 16] = [0; 16];
442        self.stream.read_exact(&mut marker)?;
443
444        let header = Header {
445            marker,
446            length: self.stream.read_u16::<BigEndian>()?,
447            record_type: self.stream.read_u8()?,
448        };
449
450        match header.record_type {
451            1 => Ok((header, Message::Open(Open::parse(&mut self.stream)?))),
452            2 => {
453                let attribute = Message::Update(Update::parse(
454                    &header,
455                    &mut self.stream,
456                    self.capabilities.get_ref(),
457                )?);
458                Ok((header, attribute))
459            }
460            3 => {
461                let attribute =
462                    Message::Notification(Notification::parse(&header, &mut self.stream)?);
463                Ok((header, attribute))
464            }
465            4 => Ok((header, Message::KeepAlive)),
466            5 => Ok((
467                header,
468                Message::RouteRefresh(RouteRefresh::parse(&mut self.stream)?),
469            )),
470            _ => Err(Error::new(
471                ErrorKind::Other,
472                "Unknown BGP message type found in BGPHeader",
473            )),
474        }
475    }
476}
477
478impl<T> Reader<T, Capabilities>
479where
480    T: Read,
481{
482    ///
483    /// Constructs a BGPReader with default parameters.
484    ///
485    /// # Panics
486    /// This function does not panic.
487    ///
488    /// # Errors
489    /// Any IO error will be returned while reading from the stream.
490    /// If an ill-formatted stream provided behavior will be undefined.
491    ///
492    /// # Safety
493    /// This function does not make use of unsafe code.
494    ///
495    ///
496    pub fn new(stream: T) -> Self
497    where
498        T: Read,
499    {
500        Reader::<T, Capabilities> {
501            stream,
502            capabilities: Default::default(),
503        }
504    }
505}