use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Error, ErrorKind, Read};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use crate::Header;
use crate::AFI;
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub enum BGP4MP {
STATE_CHANGE(STATE_CHANGE),
MESSAGE(MESSAGE),
ENTRY(ENTRY),
SNAPSHOT(SNAPSHOT),
MESSAGE_AS4(MESSAGE_AS4),
STATE_CHANGE_AS4(STATE_CHANGE_AS4),
MESSAGE_LOCAL(MESSAGE),
MESSAGE_AS4_LOCAL(MESSAGE_AS4),
MESSAGE_ADDPATH(MESSAGE),
MESSAGE_AS4_ADDPATH(MESSAGE_AS4),
MESSAGE_LOCAL_ADDPATH(MESSAGE),
MESSAGE_AS4_LOCAL_ADDPATH(MESSAGE_AS4),
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct STATE_CHANGE {
pub peer_as: u16,
pub local_as: u16,
pub interface: u16,
pub peer_address: IpAddr,
pub local_address: IpAddr,
pub old_state: u16,
pub new_state: u16,
}
impl STATE_CHANGE {
fn parse(stream: &mut Read) -> Result<STATE_CHANGE, Error> {
let peer_as = stream.read_u16::<BigEndian>()?;
let local_as = stream.read_u16::<BigEndian>()?;
let interface = stream.read_u16::<BigEndian>()?;
let afi = stream.read_u16::<BigEndian>()?;
let peer_address = match AFI::from(afi)? {
AFI::IPV4 => IpAddr::V4(Ipv4Addr::from(stream.read_u32::<BigEndian>()?)),
AFI::IPV6 => IpAddr::V6(Ipv6Addr::from(stream.read_u128::<BigEndian>()?)),
};
let local_address = match AFI::from(afi)? {
AFI::IPV4 => IpAddr::V4(Ipv4Addr::from(stream.read_u32::<BigEndian>()?)),
AFI::IPV6 => IpAddr::V6(Ipv6Addr::from(stream.read_u128::<BigEndian>()?)),
};
let old_state = stream.read_u16::<BigEndian>()?;
let new_state = stream.read_u16::<BigEndian>()?;
Ok(STATE_CHANGE {
peer_as,
local_as,
interface,
peer_address,
local_address,
old_state,
new_state,
})
}
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct MESSAGE {
pub peer_as: u16,
pub local_as: u16,
pub interface: u16,
pub peer_address: IpAddr,
pub local_address: IpAddr,
pub message: Vec<u8>,
}
impl MESSAGE {
fn parse(header: &Header, stream: &mut Read) -> Result<MESSAGE, Error> {
let peer_as = stream.read_u16::<BigEndian>()?;
let local_as = stream.read_u16::<BigEndian>()?;
let interface = stream.read_u16::<BigEndian>()?;
let afi = stream.read_u16::<BigEndian>()?;
let peer_address = match AFI::from(afi)? {
AFI::IPV4 => IpAddr::V4(Ipv4Addr::from(stream.read_u32::<BigEndian>()?)),
AFI::IPV6 => IpAddr::V6(Ipv6Addr::from(stream.read_u128::<BigEndian>()?)),
};
let local_address = match AFI::from(afi)? {
AFI::IPV4 => IpAddr::V4(Ipv4Addr::from(stream.read_u32::<BigEndian>()?)),
AFI::IPV6 => IpAddr::V6(Ipv6Addr::from(stream.read_u128::<BigEndian>()?)),
};
let length = header.length - (8 + 2 * AFI::from(afi)?.size());
let mut message = vec![0; length as usize];
stream.read_exact(&mut message)?;
Ok(MESSAGE {
peer_as,
local_as,
interface,
peer_address,
local_address,
message,
})
}
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct MESSAGE_AS4 {
pub peer_as: u32,
pub local_as: u32,
pub interface: u16,
pub peer_address: IpAddr,
pub local_address: IpAddr,
pub message: Vec<u8>,
}
impl MESSAGE_AS4 {
fn parse(header: &Header, stream: &mut Read) -> Result<MESSAGE_AS4, Error> {
let peer_as = stream.read_u32::<BigEndian>()?;
let local_as = stream.read_u32::<BigEndian>()?;
let interface = stream.read_u16::<BigEndian>()?;
let afi = stream.read_u16::<BigEndian>()?;
let peer_address = match AFI::from(afi)? {
AFI::IPV4 => IpAddr::V4(Ipv4Addr::from(stream.read_u32::<BigEndian>()?)),
AFI::IPV6 => IpAddr::V6(Ipv6Addr::from(stream.read_u128::<BigEndian>()?)),
};
let local_address = match AFI::from(afi)? {
AFI::IPV4 => IpAddr::V4(Ipv4Addr::from(stream.read_u32::<BigEndian>()?)),
AFI::IPV6 => IpAddr::V6(Ipv6Addr::from(stream.read_u128::<BigEndian>()?)),
};
let length = header.length - (12 + 2 * AFI::from(afi)?.size());
let mut message = vec![0; length as usize];
stream.read_exact(&mut message)?;
Ok(MESSAGE_AS4 {
peer_as,
local_as,
interface,
peer_address,
local_address,
message,
})
}
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct STATE_CHANGE_AS4 {
pub peer_as: u32,
pub local_as: u32,
pub interface: u16,
pub peer_address: IpAddr,
pub local_address: IpAddr,
pub old_state: u16,
pub new_state: u16,
}
impl STATE_CHANGE_AS4 {
fn parse(stream: &mut Read) -> Result<STATE_CHANGE_AS4, Error> {
let peer_as = stream.read_u32::<BigEndian>()?;
let local_as = stream.read_u32::<BigEndian>()?;
let interface = stream.read_u16::<BigEndian>()?;
let afi = stream.read_u16::<BigEndian>()?;
let peer_address = match AFI::from(afi)? {
AFI::IPV4 => IpAddr::V4(Ipv4Addr::from(stream.read_u32::<BigEndian>()?)),
AFI::IPV6 => IpAddr::V6(Ipv6Addr::from(stream.read_u128::<BigEndian>()?)),
};
let local_address = match AFI::from(afi)? {
AFI::IPV4 => IpAddr::V4(Ipv4Addr::from(stream.read_u32::<BigEndian>()?)),
AFI::IPV6 => IpAddr::V6(Ipv6Addr::from(stream.read_u128::<BigEndian>()?)),
};
let old_state = stream.read_u16::<BigEndian>()?;
let new_state = stream.read_u16::<BigEndian>()?;
Ok(STATE_CHANGE_AS4 {
peer_as,
local_as,
interface,
peer_address,
local_address,
old_state,
new_state,
})
}
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct SNAPSHOT {
pub view_number: u16,
pub filename: Vec<u8>,
}
impl SNAPSHOT {
fn parse(stream: &mut Read) -> Result<SNAPSHOT, 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(SNAPSHOT {
view_number,
filename,
})
}
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct ENTRY {
pub peer_as: u16,
pub local_as: u16,
pub interface: u16,
pub peer_address: IpAddr,
pub local_address: IpAddr,
pub view_number: u16,
pub status: u16,
pub time_last_change: u32,
pub next_hop: IpAddr,
pub afi: u16,
pub safi: u8,
pub prefix_length: u8,
pub prefix: Vec<u8>,
pub attributes: Vec<u8>,
}
impl ENTRY {
fn parse(stream: &mut Read) -> Result<ENTRY, Error> {
let peer_as = stream.read_u16::<BigEndian>()?;
let local_as = stream.read_u16::<BigEndian>()?;
let interface = stream.read_u16::<BigEndian>()?;
let afi = stream.read_u16::<BigEndian>()?;
let peer_address = match AFI::from(afi)? {
AFI::IPV4 => IpAddr::V4(Ipv4Addr::from(stream.read_u32::<BigEndian>()?)),
AFI::IPV6 => IpAddr::V6(Ipv6Addr::from(stream.read_u128::<BigEndian>()?)),
};
let local_address = match AFI::from(afi)? {
AFI::IPV4 => IpAddr::V4(Ipv4Addr::from(stream.read_u32::<BigEndian>()?)),
AFI::IPV6 => IpAddr::V6(Ipv6Addr::from(stream.read_u128::<BigEndian>()?)),
};
let view_number = stream.read_u16::<BigEndian>()?;
let status = stream.read_u16::<BigEndian>()?;
let time_last_change = stream.read_u32::<BigEndian>()?;
let afi = stream.read_u16::<BigEndian>()?;
let safi = stream.read_u8()?;
let next_hop_length = stream.read_u8()?;
let next_hop = match next_hop_length {
4 => IpAddr::V4(Ipv4Addr::from(stream.read_u32::<BigEndian>()?)),
16 => IpAddr::V6(Ipv6Addr::from(stream.read_u128::<BigEndian>()?)),
x => {
return Err(Error::new(
ErrorKind::InvalidData,
format!("Unknown NEXT_HOP length in BGP4MP::ENTRY: {}", x),
));
}
};
let prefix_length: u8 = stream.read_u8()?;
let length: u8 = (prefix_length + 7) / 8;
let mut prefix: Vec<u8> = vec![0; length as usize];
stream.read_exact(&mut prefix)?;
let attribute_length = stream.read_u16::<BigEndian>()?;
let mut attributes = vec![0; attribute_length as usize];
stream.read_exact(&mut attributes)?;
Ok(ENTRY {
peer_as,
local_as,
interface,
peer_address,
local_address,
view_number,
status,
time_last_change,
next_hop,
afi,
safi,
prefix_length,
prefix,
attributes,
})
}
}
impl BGP4MP {
pub(crate) fn parse(header: &Header, stream: &mut Read) -> Result<BGP4MP, Error> {
debug_assert!(
header.record_type == 16 || header.record_type == 17,
"Invalid record type in MRTHeader, expected BGP4MP record type."
);
match header.sub_type {
0 => Ok(BGP4MP::STATE_CHANGE(STATE_CHANGE::parse(stream)?)),
1 => Ok(BGP4MP::MESSAGE(MESSAGE::parse(header, stream)?)),
2 => Ok(BGP4MP::ENTRY(ENTRY::parse(stream)?)),
3 => Ok(BGP4MP::SNAPSHOT(SNAPSHOT::parse(stream)?)),
4 => Ok(BGP4MP::MESSAGE_AS4(MESSAGE_AS4::parse(header, stream)?)),
5 => Ok(BGP4MP::STATE_CHANGE_AS4(STATE_CHANGE_AS4::parse(stream)?)),
6 => Ok(BGP4MP::MESSAGE_LOCAL(MESSAGE::parse(header, stream)?)),
7 => Ok(BGP4MP::MESSAGE_AS4_LOCAL(MESSAGE_AS4::parse(
header, stream,
)?)),
8 => Ok(BGP4MP::MESSAGE_ADDPATH(MESSAGE::parse(header, stream)?)),
9 => Ok(BGP4MP::MESSAGE_AS4_ADDPATH(MESSAGE_AS4::parse(
header, stream,
)?)),
10 => Ok(BGP4MP::MESSAGE_LOCAL_ADDPATH(MESSAGE::parse(
header, stream,
)?)),
11 => Ok(BGP4MP::MESSAGE_AS4_LOCAL_ADDPATH(MESSAGE_AS4::parse(
header, stream,
)?)),
_ => Err(Error::new(
ErrorKind::InvalidData,
"Unknown MRT record subtype found in MRTHeader",
)),
}
}
}