use crate::ospfv2::*;
use crate::parser::{parse_ospf_vec_u32, parse_ospfv3_router_links, take_vec_u8};
use nom::combinator::cond;
use nom::number::streaming::{be_u24, be_u32};
use nom_derive::*;
use rusticata_macros::newtype_enum;
use std::net::Ipv4Addr;
#[derive(Debug)]
pub enum Ospfv3Packet {
Hello(OspfHellov3Packet),
DatabaseDescription(Ospfv3DatabaseDescriptionPacket),
LinkStateRequest(Ospfv3LinkStateRequestPacket),
LinkStateUpdate(Ospfv3LinkStateUpdatePacket),
LinkStateAcknowledgment(Ospfv3LinkStateAcknowledgmentPacket),
}
#[derive(Debug, NomBE)]
pub struct Ospfv3PacketHeader {
#[nom(Verify = "*version == 3")]
pub version: u8,
pub packet_type: OspfPacketType,
pub packet_length: u16,
pub router_id: u32,
pub area_id: u32,
pub checksum: u16,
pub instance_id: u8,
pub reserved: u8,
}
impl Ospfv3PacketHeader {
pub fn source_router(&self) -> Ipv4Addr {
Ipv4Addr::from(self.router_id)
}
}
#[derive(Debug, NomBE)]
pub struct OspfHellov3Packet {
#[nom(Verify = "header.packet_type == OspfPacketType::Hello")]
pub header: Ospfv3PacketHeader,
pub interface_id: u32,
pub router_priority: u8,
#[nom(Parse = "be_u24")]
pub options: u32,
pub hello_interval: u16,
pub router_dead_interval: u16,
pub designated_router: u32,
pub backup_designated_router: u32,
#[nom(Parse = "parse_ospf_vec_u32(header.packet_length, 36)")]
pub neighbor_list: Vec<u32>,
}
impl OspfHellov3Packet {
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 Ospfv3DatabaseDescriptionPacket {
#[nom(Verify = "header.packet_type == OspfPacketType::DatabaseDescription")]
pub header: Ospfv3PacketHeader,
pub reserved0: u8,
#[nom(Parse = "be_u24")]
pub options: u32,
pub if_mtu: u16,
pub reserved: u8,
pub db_description: u8,
pub dd_sequence_number: u32,
pub lsa_headers: Vec<Ospfv3LinkStateAdvertisementHeader>,
}
#[derive(Debug, NomBE)]
pub struct Ospfv3LinkStateRequestPacket {
#[nom(Verify = "header.packet_type == OspfPacketType::LinkStateRequest")]
pub header: Ospfv3PacketHeader,
pub requests: Vec<OspfLinkStateRequest>,
}
#[derive(Debug, NomBE)]
pub struct Ospfv3LinkStateUpdatePacket {
#[nom(Verify = "header.packet_type == OspfPacketType::LinkStateUpdate")]
pub header: Ospfv3PacketHeader,
pub num_advertisements: u32,
#[nom(Count = "num_advertisements")]
pub lsa: Vec<Ospfv3LinkStateAdvertisement>,
}
#[derive(Debug, NomBE)]
pub struct Ospfv3LinkStateAcknowledgmentPacket {
#[nom(Verify = "header.packet_type == OspfPacketType::LinkStateAcknowledgment")]
pub header: Ospfv3PacketHeader,
pub lsa_headers: Vec<Ospfv3LinkStateAdvertisementHeader>,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, NomBE)]
pub struct Ospfv3LinkStateType(pub u16);
newtype_enum! {
impl display Ospfv3LinkStateType {
RouterLSA = 0x2001,
NetworkLSA = 0x2002,
InterAreaPrefixLSA = 0x2003,
InterAreaRouterLSA = 0x2004,
ASExternalLSA = 0x4005,
NSSALSA = 0x2007,
LinkLSA = 0x0008,
IntraAreaPrefixLSA = 0x2009,
}
}
#[derive(Debug, NomBE)]
pub struct Ospfv3LinkStateAdvertisementHeader {
pub ls_age: u16,
pub link_state_type: Ospfv3LinkStateType,
pub link_state_id: u32,
pub advertising_router: u32,
pub ls_seq_number: u32,
pub ls_checksum: u16,
pub length: u16,
}
impl Ospfv3LinkStateAdvertisementHeader {
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 Ospfv3LinkStateAdvertisement {
Router(Ospfv3RouterLSA),
Network(Ospfv3NetworkLSA),
InterAreaPrefix(Ospfv3InterAreaPrefixLSA),
InterAreaRouter(Ospfv3InterAreaRouterLSA),
ASExternal(Ospfv3ASExternalLSA),
NSSA(Ospfv3NSSALSA),
Link(Ospfv3LinkLSA),
IntraAreaPrefix(Ospfv3IntraAreaPrefixLSA),
}
#[derive(Debug, NomBE)]
pub struct Ospfv3RouterLSA {
#[nom(Verify = "header.link_state_type == Ospfv3LinkStateType::RouterLSA")]
pub header: Ospfv3LinkStateAdvertisementHeader,
pub flags: u8,
#[nom(Parse = "be_u24")]
pub options: u32,
#[nom(Parse = "parse_ospfv3_router_links(header.length)")]
pub links: Vec<Ospfv3RouterLink>,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, NomBE)]
pub struct Ospfv3RouterLinkType(pub u8);
newtype_enum! {
impl display Ospfv3RouterLinkType {
PointToPoint = 1,
Transit = 2,
Virtual = 4,
}
}
#[derive(Debug, NomBE)]
pub struct Ospfv3RouterLink {
pub link_type: Ospfv3RouterLinkType,
pub reserved: u8,
pub metric: u16,
pub interface_id: u32,
pub neighbor_interface_id: u32,
pub neighbor_router_id: u32,
}
impl Ospfv3RouterLink {
pub fn interface_id(&self) -> Ipv4Addr {
Ipv4Addr::from(self.interface_id)
}
pub fn neighbor_interface_id(&self) -> Ipv4Addr {
Ipv4Addr::from(self.neighbor_interface_id)
}
pub fn neighbor_router_id(&self) -> Ipv4Addr {
Ipv4Addr::from(self.neighbor_router_id)
}
}
#[derive(Debug, NomBE)]
pub struct Ospfv3NetworkLSA {
#[nom(Verify = "header.link_state_type == Ospfv3LinkStateType::NetworkLSA")]
pub header: Ospfv3LinkStateAdvertisementHeader,
pub reserved: u8,
#[nom(Parse = "be_u24")]
pub options: u32,
#[nom(Parse = "parse_ospf_vec_u32(header.length, 24)")]
pub attached_routers: Vec<u32>,
}
impl Ospfv3NetworkLSA {
pub fn iter_attached_routers(&self) -> impl Iterator<Item = Ipv4Addr> + '_ {
self.attached_routers.iter().map(|&u| Ipv4Addr::from(u))
}
}
#[derive(Debug, NomBE)]
pub struct Ospfv3InterAreaPrefixLSA {
#[nom(Verify = "header.link_state_type == Ospfv3LinkStateType::InterAreaPrefixLSA")]
pub header: Ospfv3LinkStateAdvertisementHeader,
pub reserved0: u8,
#[nom(Parse = "be_u24")]
pub metric: u32,
pub prefix: Ospfv3IPv6AddressPrefix,
}
#[derive(Debug, NomBE)]
pub struct Ospfv3IPv6AddressPrefix {
pub prefix_length: u8,
pub prefix_options: u8,
pub reserved: u16,
#[nom(Parse = "take_vec_u8(prefix_length / 8)")]
pub address_prefix: Vec<u8>,
}
#[derive(Debug, NomBE)]
pub struct Ospfv3InterAreaRouterLSA {
#[nom(Verify = "header.link_state_type == Ospfv3LinkStateType::InterAreaRouterLSA")]
pub header: Ospfv3LinkStateAdvertisementHeader,
pub reserved0: u8,
#[nom(Parse = "be_u24")]
pub options: u32,
pub reserved1: u8,
#[nom(Parse = "be_u24")]
pub metric: u32,
pub destination_router_id: u32,
}
#[derive(Debug, NomBE)]
pub struct Ospfv3ASExternalLSA {
#[nom(
Verify = "header.link_state_type == Ospfv3LinkStateType::ASExternalLSA ||
header.link_state_type == Ospfv3LinkStateType::NSSALSA"
)]
pub header: Ospfv3LinkStateAdvertisementHeader,
pub flags: u8,
#[nom(Parse = "be_u24")]
pub metric: u32,
pub address_prefix: Ospfv3IPv6AddressPrefix,
#[nom(Parse = "cond(flags & 0b10 != 0, take_vec_u8(16))")]
pub forwarding_address: Option<Vec<u8>>,
#[nom(Parse = "cond(flags & 0b01 != 0, be_u32)")]
pub external_route_tag: Option<u32>,
#[nom(Parse = "cond(address_prefix.reserved != 0, be_u32)")]
pub referenced_link_state_id: Option<u32>,
}
type Ospfv3NSSALSA = Ospfv3ASExternalLSA;
#[derive(Debug, NomBE)]
pub struct Ospfv3LinkLSA {
#[nom(Verify = "header.link_state_type == Ospfv3LinkStateType::LinkLSA")]
pub header: Ospfv3LinkStateAdvertisementHeader,
pub router_priority: u8,
#[nom(Parse = "be_u24")]
pub options: u32,
#[nom(Parse = "take_vec_u8(16)")]
pub link_local_interface_address: Vec<u8>,
pub num_prefixes: u32,
#[nom(Count = "num_prefixes")]
pub address_prefixes: Vec<Ospfv3IPv6AddressPrefix>,
}
#[derive(Debug, NomBE)]
pub struct Ospfv3IntraAreaPrefixLSA {
#[nom(Verify = "header.link_state_type == Ospfv3LinkStateType::IntraAreaPrefixLSA")]
pub header: Ospfv3LinkStateAdvertisementHeader,
pub num_prefixes: u16,
pub referenced_ls_type: u16,
pub referenced_link_state_id: u32,
pub referenced_advertising_router: u32,
#[nom(Count = "num_prefixes")]
pub address_prefixes: Vec<Ospfv3IPv6AddressPrefix>,
}