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::Ipv6Addr;

use crate::Header;

/// The BGPPLUS enum represents all possible subtypes of the BGPPLUS record type.
#[derive(Debug)]
#[allow(missing_docs)]
#[allow(non_camel_case_types)]
pub enum BGP4PLUS {
    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 BGP4PLUS {
    pub(crate) fn parse(header: &Header, stream: &mut Read) -> Result<BGP4PLUS, Error> {
        match header.sub_type {
            0 => Ok(BGP4PLUS::NULL),
            1 => Ok(BGP4PLUS::UPDATE(MESSAGE::parse(header, stream)?)),
            2 => Ok(BGP4PLUS::PREF_UPDATE),
            3 => Ok(BGP4PLUS::STATE_CHANGE(STATE_CHANGE::parse(stream)?)),
            4 => Ok(BGP4PLUS::SYNC(SYNC::parse(stream)?)),
            5 => Ok(BGP4PLUS::OPEN(MESSAGE::parse(header, stream)?)),
            6 => Ok(BGP4PLUS::NOTIFY(MESSAGE::parse(header, stream)?)),
            7 => Ok(BGP4PLUS::KEEPALIVE(MESSAGE::parse(header, stream)?)),
            _ => Err(Error::new(
                ErrorKind::Other,
                "Unknown MRT record subtype found in MRTHeader",
            )),
        }
    }
}

/// Represents the BGP_UPDATE, BGP_OPEN, BGP_NOTIFY and BGP_KEEPALIVE subtypes of IPv6 peers.
#[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 IPv6 address from which the BGP message has been received.
    pub peer_ip: Ipv6Addr,

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

    /// The IPv6 of the AS that received this BGP message.
    pub local_ip: Ipv6Addr,

    /// 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 = Ipv6Addr::from(stream.read_u128::<BigEndian>()?);
        let local_as = stream.read_u16::<BigEndian>()?;
        let local_ip = Ipv6Addr::from(stream.read_u128::<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 IPv6 address from which the BGP message has been received.
    pub peer_ip: Ipv6Addr,

    /// 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: Ipv6Addr::from(stream.read_u128::<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 view number of this Routing Information Base.
    pub view_number: u16,

    /// The filename of the BGP RIB entries. NULL-terminated.
    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,
        })
    }
}