bgpkit_parser/parser/bmp/openbmp.rs
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 142 143 144 145 146 147 148 149 150
use crate::parser::bmp::error::ParserBmpError;
use crate::parser::ReadUtils;
use bytes::{Buf, Bytes};
use std::net::IpAddr;
///
/// ```text
/// 0 1 2 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Magic Number (0x4F424D50) |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Major Ver. | Minor Ver. | Header Length |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Message Length |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Flags | Obj. Type |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Coll. Timestamp (seconds) |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Coll. Timestamp (microseconds) |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Collector Hash (16 bytes) |
/// ~ ~
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Coll. Admin ID Length |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Coll. Admin ID (variable) |
/// ~ ~
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Router Hash (16 bytes) |
/// ~ ~
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Router IP (16 bytes) |
/// ~ ~
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Router Group Length |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Router Group (variable) |
/// ~ ~
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Row Count |
/// +---------------------------------------------------------------+
/// ```
#[derive(Debug)]
pub struct OpenBmpHeader {
pub major_version: u8,
pub minor_version: u8,
/// Total number of bytes in the header (including version and header length fields)
pub header_len: u16,
/// Number of "data" bytes following the header
pub msg_len: u32,
pub object_type: u8,
pub timestamp: f64,
pub admin_id: String,
pub router_ip: IpAddr,
pub router_group: Option<String>,
}
pub fn parse_openbmp_header(data: &mut Bytes) -> Result<OpenBmpHeader, ParserBmpError> {
// read magic number
let magic_number = data.read_n_bytes_to_string(4)?;
if magic_number != "OBMP" {
return Err(ParserBmpError::InvalidOpenBmpHeader);
}
// read version numbers
let version_major = data.read_u8()?;
let version_minor = data.read_u8()?;
if (version_major, version_minor) != (1, 7) {
return Err(ParserBmpError::InvalidOpenBmpHeader);
}
// read msg lengths
let header_len = data.read_u16()?;
let msg_len = data.read_u32()?;
// read flags
let flags = data.read_u8()?;
let (is_router_msg, is_router_ipv6) = (flags & 0x80 != 0, flags & 0x40 != 0);
if !is_router_msg {
return Err(ParserBmpError::UnsupportedOpenBmpMessage);
}
// read object type
let object_type = data.read_u8()?;
if object_type != 12 {
return Err(ParserBmpError::UnsupportedOpenBmpMessage);
}
// read_timestamp
let t_sec = data.read_u32()?;
let t_usec = data.read_u32()?;
let timestamp = t_sec as f64 + (t_usec as f64) / 1_000_000.0;
// read admin-id
data.advance(16);
let mut name_len = data.read_u16()?;
if name_len > 255 {
name_len = 255;
}
let admin_id = data.read_n_bytes_to_string(name_len as usize)?;
// read router IP
data.advance(16);
let ip: IpAddr = if is_router_ipv6 {
data.read_ipv6_address()?.into()
} else {
let ip = data.read_ipv4_address()?;
data.advance(12);
ip.into()
};
// read router group
let group = match data.read_u16()? {
0 => "".to_string(),
n => data.read_n_bytes_to_string(n as usize)?,
};
// read msg count
let row_count = data.read_u32()?;
if row_count != 1 {
return Err(ParserBmpError::InvalidOpenBmpHeader);
}
Ok(OpenBmpHeader {
major_version: version_major,
minor_version: version_minor,
header_len,
msg_len,
object_type,
timestamp,
admin_id,
router_ip: ip,
router_group: Some(group),
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_open_bmp_header() {
let input = "4f424d500107006400000033800c6184b9c2000c602cbf4f072f3ae149d23486024bc3dadfc4000a69732d63632d626d7031c677060bdd020a9e92be000200de2e3180df3369000000000000000000000000000c726f7574652d76696577733500000001030000003302000000000000000000000000000000000000000000003fda060e00000da30000000061523c36000c0e1c0200000a";
let decoded = hex::decode(input).unwrap();
let mut data = Bytes::from(decoded);
let _header = parse_openbmp_header(&mut data).unwrap();
}
}