use crate::parser::{parse_ospf_external_tos_routes, parse_ospf_tos_routes, parse_ospf_vec_u32};
use nom::number::streaming::be_u24;
use nom_derive::*;
use rusticata_macros::newtype_enum;
use std::net::Ipv4Addr;
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, NomBE)]
pub struct OspfPacketType(pub u8);
newtype_enum! {
impl display OspfPacketType {
Hello = 1,
DatabaseDescription = 2,
LinkStateRequest = 3,
LinkStateUpdate = 4,
LinkStateAcknowledgment = 5,
}
}
#[derive(Debug)]
pub enum Ospfv2Packet {
Hello(OspfHelloPacket),
DatabaseDescription(OspfDatabaseDescriptionPacket),
LinkStateRequest(OspfLinkStateRequestPacket),
LinkStateUpdate(OspfLinkStateUpdatePacket),
LinkStateAcknowledgment(OspfLinkStateAcknowledgmentPacket),
}
#[derive(Debug, NomBE)]
pub struct Ospfv2PacketHeader {
#[nom(Verify = "*version == 2")]
pub version: u8,
pub packet_type: OspfPacketType,
pub packet_length: u16,
pub router_id: u32,
pub area_id: u32,
pub checksum: u16,
pub au_type: u16,
pub authentication: u64,
}
impl Ospfv2PacketHeader {
pub fn source_router(&self) -> Ipv4Addr {
Ipv4Addr::from(self.router_id)
}
}
#[derive(Debug, NomBE)]
pub struct OspfHelloPacket {
#[nom(Verify = "header.packet_type == OspfPacketType::Hello")]
pub header: Ospfv2PacketHeader,
pub network_mask: u32,
pub hello_interval: u16,
pub options: u8,
pub router_priority: u8,
pub router_dead_interval: u32,
pub designated_router: u32,
pub backup_designated_router: u32,
#[nom(Parse = "parse_ospf_vec_u32(header.packet_length, 44)")]
pub neighbor_list: Vec<u32>,
}
impl OspfHelloPacket {
pub fn network_mask(&self) -> Ipv4Addr {
Ipv4Addr::from(self.network_mask)
}
pub fn designated_router(&self) -> Ipv4Addr {
Ipv4Addr::from(self.designated_router)
}
pub fn backup_designated_router(&self) -> Ipv4Addr {
Ipv4Addr::from(self.backup_designated_router)
}
}
#[derive(Debug, NomBE)]
pub struct OspfDatabaseDescriptionPacket {
#[nom(Verify = "header.packet_type == OspfPacketType::DatabaseDescription")]
pub header: Ospfv2PacketHeader,
pub if_mtu: u16,
pub options: u8,
pub flags: u8,
pub dd_sequence_number: u32,
pub lsa_headers: Vec<OspfLinkStateAdvertisementHeader>,
}
#[derive(Debug, NomBE)]
pub struct OspfLinkStateRequestPacket {
#[nom(Verify = "header.packet_type == OspfPacketType::LinkStateRequest")]
pub header: Ospfv2PacketHeader,
pub requests: Vec<OspfLinkStateRequest>,
}
#[derive(Debug, NomBE)]
pub struct OspfLinkStateRequest {
pub link_state_type: u32,
pub link_state_id: u32,
pub advertising_router: u32,
}
impl OspfLinkStateRequest {
pub fn link_state_id(&self) -> Ipv4Addr {
Ipv4Addr::from(self.link_state_id)
}
pub fn advertising_router(&self) -> Ipv4Addr {
Ipv4Addr::from(self.advertising_router)
}
}
#[derive(Debug, NomBE)]
pub struct OspfLinkStateUpdatePacket {
#[nom(Verify = "header.packet_type == OspfPacketType::LinkStateUpdate")]
pub header: Ospfv2PacketHeader,
pub num_advertisements: u32,
#[nom(Count = "num_advertisements")]
pub lsa: Vec<OspfLinkStateAdvertisement>,
}
#[derive(Debug, NomBE)]
pub struct OspfLinkStateAcknowledgmentPacket {
#[nom(Verify = "header.packet_type == OspfPacketType::LinkStateAcknowledgment")]
pub header: Ospfv2PacketHeader,
pub lsa_headers: Vec<OspfLinkStateAdvertisementHeader>,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, NomBE)]
pub struct OspfLinkStateType(pub u8);
newtype_enum! {
impl display OspfLinkStateType {
RouterLinks = 1,
NetworkLinks = 2,
SummaryLinkIpNetwork = 3,
SummaryLinkAsbr = 4,
ASExternalLink = 5,
NSSAASExternal = 7,
OpaqueLinkLocalScope = 9,
OpaqueAreaLocalScope = 10,
OpaqueASWideScope = 11,
}
}
#[derive(Debug, NomBE)]
pub struct OspfLinkStateAdvertisementHeader {
pub ls_age: u16,
pub options: u8,
pub link_state_type: OspfLinkStateType,
pub link_state_id: u32,
pub advertising_router: u32,
pub ls_seq_number: u32,
pub ls_checksum: u16,
pub length: u16,
}
impl OspfLinkStateAdvertisementHeader {
pub fn link_state_id(&self) -> Ipv4Addr {
Ipv4Addr::from(self.link_state_id)
}
pub fn advertising_router(&self) -> Ipv4Addr {
Ipv4Addr::from(self.advertising_router)
}
}
#[derive(Debug)]
pub enum OspfLinkStateAdvertisement {
RouterLinks(OspfRouterLinksAdvertisement),
NetworkLinks(OspfNetworkLinksAdvertisement),
SummaryLinkIpNetwork(OspfSummaryLinkAdvertisement),
SummaryLinkAsbr(OspfSummaryLinkAdvertisement),
ASExternalLink(OspfASExternalLinkAdvertisement),
NSSAASExternal(OspfNSSAExternalLinkAdvertisement),
OpaqueLinkLocalScope(OspfOpaqueLinkAdvertisement),
OpaqueAreaLocalScope(OspfOpaqueLinkAdvertisement),
OpaqueASWideScope(OspfOpaqueLinkAdvertisement),
}
#[derive(Debug, NomBE)]
pub struct OspfRouterLinksAdvertisement {
#[nom(Verify = "header.link_state_type == OspfLinkStateType::RouterLinks")]
pub header: OspfLinkStateAdvertisementHeader,
pub flags: u16,
pub num_links: u16,
#[nom(Count = "num_links")]
pub links: Vec<OspfRouterLink>,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, NomBE)]
pub struct OspfRouterLinkType(pub u8);
newtype_enum! {
impl display OspfRouterLinkType {
PointToPoint = 1,
Transit = 2,
Stub = 3,
Virtual = 4,
}
}
#[derive(Debug, NomBE)]
pub struct OspfRouterLink {
pub link_id: u32,
pub link_data: u32,
pub link_type: OspfRouterLinkType,
pub num_tos: u8,
pub tos_0_metric: u16,
#[nom(Count = "num_tos")]
pub tos_list: Vec<OspfRouterTOS>,
}
impl OspfRouterLink {
pub fn link_id(&self) -> Ipv4Addr {
Ipv4Addr::from(self.link_id)
}
pub fn link_data(&self) -> Ipv4Addr {
Ipv4Addr::from(self.link_data)
}
}
#[derive(Debug, NomBE)]
pub struct OspfRouterTOS {
pub tos: u8,
pub reserved: u8,
pub metric: u16,
}
#[derive(Debug, NomBE)]
pub struct OspfNetworkLinksAdvertisement {
#[nom(Verify = "header.link_state_type == OspfLinkStateType::NetworkLinks")]
pub header: OspfLinkStateAdvertisementHeader,
pub network_mask: u32,
#[nom(Parse = "parse_ospf_vec_u32(header.length, 24)")]
pub attached_routers: Vec<u32>,
}
impl OspfNetworkLinksAdvertisement {
pub fn network_mask(&self) -> Ipv4Addr {
Ipv4Addr::from(self.network_mask)
}
pub fn iter_attached_routers(&self) -> impl Iterator<Item = Ipv4Addr> + '_ {
self.attached_routers.iter().map(|&u| Ipv4Addr::from(u))
}
}
#[derive(Debug, NomBE)]
pub struct OspfSummaryLinkAdvertisement {
#[nom(
Verify = "header.link_state_type == OspfLinkStateType::SummaryLinkIpNetwork ||
header.link_state_type == OspfLinkStateType::SummaryLinkAsbr"
)]
pub header: OspfLinkStateAdvertisementHeader,
pub network_mask: u32,
pub tos: u8,
#[nom(Parse = "be_u24")]
pub metric: u32,
#[nom(Parse = "parse_ospf_tos_routes(header.length)")]
pub tos_routes: Vec<OspfTosRoute>,
}
impl OspfSummaryLinkAdvertisement {
pub fn network_mask(&self) -> Ipv4Addr {
Ipv4Addr::from(self.network_mask)
}
}
#[derive(Debug, NomBE)]
pub struct OspfTosRoute {
pub tos: u8,
#[nom(Parse = "be_u24")]
pub metric: u32,
}
#[derive(Debug, NomBE)]
pub struct OspfASExternalLinkAdvertisement {
#[nom(Verify = "header.link_state_type == OspfLinkStateType::ASExternalLink")]
pub header: OspfLinkStateAdvertisementHeader,
pub network_mask: u32,
pub external_and_reserved: u8,
#[nom(Parse = "be_u24")]
pub metric: u32,
pub forwarding_address: u32,
pub external_route_tag: u32,
#[nom(Parse = "parse_ospf_external_tos_routes(header.length)")]
pub tos_list: Vec<OspfExternalTosRoute>,
}
impl OspfASExternalLinkAdvertisement {
pub fn forwarding_address(&self) -> Ipv4Addr {
Ipv4Addr::from(self.forwarding_address)
}
pub fn network_mask(&self) -> Ipv4Addr {
Ipv4Addr::from(self.network_mask)
}
}
#[derive(Debug, NomBE)]
pub struct OspfExternalTosRoute {
pub tos: u8,
#[nom(Parse = "be_u24")]
pub metric: u32,
pub forwarding_address: u32,
pub external_route_tag: u32,
}
impl OspfExternalTosRoute {
pub fn forwarding_address(&self) -> Ipv4Addr {
Ipv4Addr::from(self.forwarding_address)
}
}
#[derive(Debug, NomBE)]
pub struct OspfNSSAExternalLinkAdvertisement {
#[nom(Verify = "header.link_state_type == OspfLinkStateType::NSSAASExternal")]
pub header: OspfLinkStateAdvertisementHeader,
pub network_mask: u32,
pub external_and_tos: u8,
#[nom(Parse = "be_u24")]
pub metric: u32,
pub forwarding_address: u32,
pub external_route_tag: u32,
#[nom(Parse = "parse_ospf_external_tos_routes(header.length)")]
pub tos_list: Vec<OspfExternalTosRoute>,
}
impl OspfNSSAExternalLinkAdvertisement {
pub fn forwarding_address(&self) -> Ipv4Addr {
Ipv4Addr::from(self.forwarding_address)
}
pub fn network_mask(&self) -> Ipv4Addr {
Ipv4Addr::from(self.network_mask)
}
}
#[derive(Debug, NomBE)]
pub struct OspfOpaqueLinkAdvertisement {
#[nom(
Verify = "header.link_state_type == OspfLinkStateType::OpaqueLinkLocalScope ||
header.link_state_type == OspfLinkStateType::OpaqueAreaLocalScope ||
header.link_state_type == OspfLinkStateType::OpaqueASWideScope"
)]
pub header: OspfLinkStateAdvertisementHeader,
pub data: Vec<u8>,
}
impl OspfOpaqueLinkAdvertisement {
pub fn opaque_type(&self) -> u8 {
(self.header.link_state_id >> 24) as u8
}
pub fn opaque_id(&self) -> u32 {
self.header.link_state_id & 0xff_ffff
}
}