1#![deny(missing_docs)]
2
3use byteorder::{BigEndian, ReadBytesExt};
30use std::io::{Error, ErrorKind, Read};
31
32pub mod records {
34
35 pub mod bgp;
37
38 pub mod bgp4plus;
40
41 pub mod bgp4mp;
43
44 pub mod isis;
46
47 pub mod ospf;
49
50 pub mod rip;
52
53 pub mod tabledump;
55}
56
57pub use records::bgp;
59pub use records::bgp4mp;
60pub use records::bgp4plus;
61pub use records::isis;
62pub use records::ospf;
63pub use records::rip;
64pub use records::tabledump;
65
66#[derive(Debug)]
68#[repr(u16)]
69pub enum AFI {
70 IPV4 = 1,
72 IPV6 = 2,
74}
75
76impl AFI {
77 fn from(value: u16) -> Result<AFI, Error> {
78 match value {
79 1 => Ok(AFI::IPV4),
80 2 => Ok(AFI::IPV6),
81 _ => {
82 let msg = format!(
83 "Number {} does not represent a valid address family.",
84 value
85 );
86 Err(std::io::Error::new(std::io::ErrorKind::Other, msg))
87 }
88 }
89 }
90
91 pub fn size(&self) -> u32 {
93 match self {
94 AFI::IPV4 => 4,
95 AFI::IPV6 => 16,
96 }
97 }
98}
99
100#[derive(Debug)]
102pub struct Header {
103 pub timestamp: u32,
105
106 pub extended: u32,
108
109 pub record_type: u16,
111
112 pub sub_type: u16,
114
115 pub length: u32,
117}
118
119#[derive(Debug)]
121#[allow(missing_docs)]
122#[allow(non_camel_case_types)]
123pub enum Record {
124 NULL,
125 START,
126 DIE,
127 I_AM_DEAD,
128 PEER_DOWN,
129 BGP(records::bgp::BGP),
130 RIP(records::rip::RIP),
131 IDRP,
132 RIPNG(records::rip::RIPNG),
133 BGP4PLUS(records::bgp4plus::BGP4PLUS),
134 BGP4PLUS_01(records::bgp4plus::BGP4PLUS),
135 OSPFv2(records::ospf::OSPFv2),
136 TABLE_DUMP(records::tabledump::TABLE_DUMP),
137 TABLE_DUMP_V2(records::tabledump::TABLE_DUMP_V2),
138 BGP4MP(records::bgp4mp::BGP4MP),
139 BGP4MP_ET(records::bgp4mp::BGP4MP),
140 ISIS(Vec<u8>),
141 ISIS_ET(Vec<u8>),
142 OSPFv3(records::ospf::OSPFv3),
143 OSPFv3_ET(records::ospf::OSPFv3),
144}
145
146pub fn read(mut stream: &mut impl Read) -> Result<Option<(Header, Record)>, Error> {
160 let result = stream.read_u32::<BigEndian>();
161
162 let timestamp = match result {
165 Err(ref e) if e.kind() == ErrorKind::UnexpectedEof => return Ok(None),
166 Err(e) => return Err(e),
167 Ok(x) => x,
168 };
169
170 let mut header = Header {
172 timestamp,
173 extended: 0,
174 record_type: stream.read_u16::<BigEndian>()?,
175 sub_type: stream.read_u16::<BigEndian>()?,
176 length: stream.read_u32::<BigEndian>()?,
177 };
178
179 match header.record_type {
180 0 => Ok(Some((header, Record::NULL))),
181 1 => Ok(Some((header, Record::START))),
182 2 => Ok(Some((header, Record::DIE))),
183 3 => Ok(Some((header, Record::I_AM_DEAD))),
184 4 => Ok(Some((header, Record::PEER_DOWN))),
185 5 => {
186 let record = records::bgp::BGP::parse(&header, &mut stream)?;
187 Ok(Some((header, Record::BGP(record))))
188 }
189 6 => {
190 let record = records::rip::RIP::parse(&header, &mut stream)?;
191 Ok(Some((header, Record::RIP(record))))
192 }
193 7 => Ok(Some((header, Record::IDRP))),
194 8 => {
195 let record = records::rip::RIPNG::parse(&header, &mut stream)?;
196 Ok(Some((header, Record::RIPNG(record))))
197 }
198 9 => {
199 let record = records::bgp4plus::BGP4PLUS::parse(&header, &mut stream)?;
200 Ok(Some((header, Record::BGP4PLUS(record))))
201 }
202 10 => {
203 let record = records::bgp4plus::BGP4PLUS::parse(&header, &mut stream)?;
204 Ok(Some((header, Record::BGP4PLUS_01(record))))
205 }
206 11 => {
207 let record = records::ospf::OSPFv2::parse(&header, &mut stream)?;
208 Ok(Some((header, Record::OSPFv2(record))))
209 }
210 12 => {
211 let record = records::tabledump::TABLE_DUMP::parse(&header, &mut stream)?;
212 Ok(Some((header, Record::TABLE_DUMP(record))))
213 }
214 13 => {
215 let record = records::tabledump::TABLE_DUMP_V2::parse(&header, &mut stream)?;
216 Ok(Some((header, Record::TABLE_DUMP_V2(record))))
217 }
218 16 => {
219 let record = records::bgp4mp::BGP4MP::parse(&header, &mut stream)?;
220 Ok(Some((header, Record::BGP4MP(record))))
221 }
222 17 => {
223 header.extended = stream.read_u32::<BigEndian>()?;
224 let record = records::bgp4mp::BGP4MP::parse(&header, &mut stream)?;
225 Ok(Some((header, Record::BGP4MP_ET(record))))
226 }
227 32 => {
228 let record = records::isis::parse(&header, &mut stream)?;
229 Ok(Some((header, Record::ISIS(record))))
230 }
231 33 => {
232 header.extended = stream.read_u32::<BigEndian>()?;
233 let record = records::isis::parse(&header, &mut stream)?;
234 Ok(Some((header, Record::ISIS_ET(record))))
235 }
236 48 => {
237 let record = records::ospf::OSPFv3::parse(&header, &mut stream)?;
238 Ok(Some((header, Record::OSPFv3(record))))
239 }
240 49 => {
241 header.extended = stream.read_u32::<BigEndian>()?;
242 let record = records::ospf::OSPFv3::parse(&header, &mut stream)?;
243 Ok(Some((header, Record::OSPFv3_ET(record))))
244 }
245 x => Err(Error::new(
246 ErrorKind::Other,
247 format!("Unknown record type found in MRT header: {}", x),
248 )),
249 }
250}