1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Error, ErrorKind, Read};
use std::net::Ipv4Addr;

use crate::Header;

/// The BGP enum represents all possible subtypes of the BGP record type.
#[derive(Debug)]
#[allow(missing_docs)]
#[allow(non_camel_case_types)]
pub enum BGP {
    NULL,
    UPDATE(MESSAGE),
    PREF_UPDATE,
    STATE_CHANGE(STATE_CHANGE),
    SYNC(SYNC),
    OPEN(MESSAGE),
    NOTIFY(MESSAGE),
    KEEPALIVE(MESSAGE),
}

/// Used for the deprecated BGP message type.
impl BGP {
    pub(crate) fn parse(header: &Header, stream: &mut Read) -> Result<BGP, Error> {
        match header.sub_type {
            0 => Ok(BGP::NULL),
            1 => Ok(BGP::UPDATE(MESSAGE::parse(header, stream)?)),
            2 => Ok(BGP::PREF_UPDATE),
            3 => Ok(BGP::STATE_CHANGE(STATE_CHANGE::parse(stream)?)),
            4 => Ok(BGP::SYNC(SYNC::parse(stream)?)),
            5 => Ok(BGP::OPEN(MESSAGE::parse(header, stream)?)),
            6 => Ok(BGP::NOTIFY(MESSAGE::parse(header, stream)?)),
            7 => Ok(BGP::KEEPALIVE(MESSAGE::parse(header, stream)?)),
            _ => Err(Error::new(
                ErrorKind::Other,
                "Unknown record subtype found in MRT header",
            )),
        }
    }
}

/// Represents the UPDATE, OPEN, NOTIFY and KEEPALIVE messages.
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct MESSAGE {
    /// The peer ASN from which the BGP message has been received.
    pub peer_as: u16,

    /// The peer IPv4 address from which the BGP message has been received.
    pub peer_ip: Ipv4Addr,

    /// The ASN of the AS that received this BGP message.
    pub local_as: u16,

    /// The IPv4 of the AS that received this BGP message.
    pub local_ip: Ipv4Addr,

    /// The message that has been received.
    pub message: Vec<u8>,
}

impl MESSAGE {
    fn parse(header: &Header, stream: &mut Read) -> Result<MESSAGE, Error> {
        let peer_as = stream.read_u16::<BigEndian>()?;
        let peer_ip = Ipv4Addr::from(stream.read_u32::<BigEndian>()?);
        let local_as = stream.read_u16::<BigEndian>()?;
        let local_ip = Ipv4Addr::from(stream.read_u32::<BigEndian>()?);

        let length = header.length - 12;
        let mut message = vec![0; length as usize];
        stream.read_exact(&mut message)?;

        Ok(MESSAGE {
            peer_as,
            peer_ip,
            local_as,
            local_ip,
            message,
        })
    }
}

///
/// Represents a state change in the BGP Finite State Machine (FSM).
/// More information can found in [RFC4271](https://tools.ietf.org/html/rfc4271#section-8).
///
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct STATE_CHANGE {
    /// The peer ASN from which the BGP message has been received.
    pub peer_as: u16,

    /// The peer IPv4 address from which the BGP message has been received.
    pub peer_ip: Ipv4Addr,

    /// The old state of the BGP collector.
    pub old_state: u16,

    /// The new state of the BGP collector.
    pub new_state: u16,
}

impl STATE_CHANGE {
    fn parse(stream: &mut Read) -> Result<STATE_CHANGE, Error> {
        Ok(STATE_CHANGE {
            peer_as: stream.read_u16::<BigEndian>()?,
            peer_ip: Ipv4Addr::from(stream.read_u32::<BigEndian>()?),
            old_state: stream.read_u16::<BigEndian>()?,
            new_state: stream.read_u16::<BigEndian>()?,
        })
    }
}

/// Deprecated: Used to record RIB entries in a file.
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct SYNC {
    /// The associated view number.
    pub view_number: u16,

    /// The NULL-terminated filename of the file where RIB entries are recorded.
    pub filename: Vec<u8>,
}

impl SYNC {
    fn parse(stream: &mut Read) -> Result<SYNC, Error> {
        let view_number = stream.read_u16::<BigEndian>()?;
        let mut filename = Vec::new();

        let mut buffer = stream.read_u8()?;
        while buffer != b'\0' {
            filename.push(buffer);
            buffer = stream.read_u8()?;
        }

        Ok(SYNC {
            view_number,
            filename,
        })
    }
}