#![deny(missing_docs)]
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Error, ErrorKind, Read};
pub mod records {
pub mod bgp;
pub mod bgp4plus;
pub mod bgp4mp;
pub mod isis;
pub mod ospf;
pub mod rip;
pub mod tabledump;
}
pub use records::bgp;
pub use records::bgp4mp;
pub use records::bgp4plus;
pub use records::isis;
pub use records::ospf;
pub use records::rip;
pub use records::tabledump;
#[derive(Debug)]
#[repr(u16)]
pub enum AFI {
IPV4 = 1,
IPV6 = 2,
}
impl AFI {
fn from(value: u16) -> Result<AFI, Error> {
match value {
1 => Ok(AFI::IPV4),
2 => Ok(AFI::IPV6),
_ => {
let msg = format!(
"Number {} does not represent a valid address family.",
value
);
Err(std::io::Error::new(std::io::ErrorKind::Other, msg))
}
}
}
pub fn size(&self) -> u32 {
match self {
AFI::IPV4 => 4,
AFI::IPV6 => 16,
}
}
}
pub struct Reader<T>
where
T: Read,
{
pub stream: T,
}
#[derive(Debug)]
pub struct Header {
pub timestamp: u32,
pub extended: u32,
pub record_type: u16,
pub sub_type: u16,
pub length: u32,
}
#[derive(Debug)]
#[allow(missing_docs)]
#[allow(non_camel_case_types)]
pub enum Record {
NULL,
START,
DIE,
I_AM_DEAD,
PEER_DOWN,
BGP(records::bgp::BGP),
RIP(records::rip::RIP),
IDRP,
RIPNG(records::rip::RIPNG),
BGP4PLUS(records::bgp4plus::BGP4PLUS),
BGP4PLUS_01(records::bgp4plus::BGP4PLUS),
OSPFv2(records::ospf::OSPFv2),
TABLE_DUMP(records::tabledump::TABLE_DUMP),
TABLE_DUMP_V2(records::tabledump::TABLE_DUMP_V2),
BGP4MP(records::bgp4mp::BGP4MP),
BGP4MP_ET(records::bgp4mp::BGP4MP),
ISIS(Vec<u8>),
ISIS_ET(Vec<u8>),
OSPFv3(records::ospf::OSPFv3),
OSPFv3_ET(records::ospf::OSPFv3),
}
impl<T> Reader<T>
where
T: Read,
{
pub fn read(&mut self) -> Result<Option<(Header, Record)>, Error> {
let result = self.stream.read_u32::<BigEndian>();
let timestamp = match result {
Err(ref e) if e.kind() == ErrorKind::UnexpectedEof => return Ok(None),
Err(e) => return Err(e),
Ok(x) => x,
};
let mut header = Header {
timestamp,
extended: 0,
record_type: self.stream.read_u16::<BigEndian>()?,
sub_type: self.stream.read_u16::<BigEndian>()?,
length: self.stream.read_u32::<BigEndian>()?,
};
match header.record_type {
0 => Ok(Some((header, Record::NULL))),
1 => Ok(Some((header, Record::START))),
2 => Ok(Some((header, Record::DIE))),
3 => Ok(Some((header, Record::I_AM_DEAD))),
4 => Ok(Some((header, Record::PEER_DOWN))),
5 => {
let record = records::bgp::BGP::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::BGP(record))))
}
6 => {
let record = records::rip::RIP::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::RIP(record))))
}
7 => Ok(Some((header, Record::IDRP))),
8 => {
let record = records::rip::RIPNG::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::RIPNG(record))))
}
9 => {
let record = records::bgp4plus::BGP4PLUS::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::BGP4PLUS(record))))
}
10 => {
let record = records::bgp4plus::BGP4PLUS::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::BGP4PLUS_01(record))))
}
11 => {
let record = records::ospf::OSPFv2::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::OSPFv2(record))))
}
12 => {
let record = records::tabledump::TABLE_DUMP::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::TABLE_DUMP(record))))
}
13 => {
let record = records::tabledump::TABLE_DUMP_V2::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::TABLE_DUMP_V2(record))))
}
16 => {
let record = records::bgp4mp::BGP4MP::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::BGP4MP(record))))
}
17 => {
header.extended = self.stream.read_u32::<BigEndian>()?;
let record = records::bgp4mp::BGP4MP::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::BGP4MP_ET(record))))
}
32 => {
let record = records::isis::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::ISIS(record))))
}
33 => {
header.extended = self.stream.read_u32::<BigEndian>()?;
let record = records::isis::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::ISIS_ET(record))))
}
48 => {
let record = records::ospf::OSPFv3::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::OSPFv3(record))))
}
49 => {
header.extended = self.stream.read_u32::<BigEndian>()?;
let record = records::ospf::OSPFv3::parse(&header, &mut self.stream)?;
Ok(Some((header, Record::OSPFv3_ET(record))))
}
x => Err(Error::new(
ErrorKind::Other,
format!("Unknown record type found in MRT header: {}", x),
)),
}
}
}