ospf_parser/
ospfv3.rs

1use crate::ospfv2::*;
2use crate::parser::{parse_ospf_vec_u32, parse_ospfv3_router_links, take_vec_u8};
3use nom::combinator::cond;
4use nom::number::streaming::{be_u24, be_u32};
5use nom_derive::*;
6use rusticata_macros::newtype_enum;
7use std::net::Ipv4Addr;
8
9/// An OSPF version 3 packet
10#[derive(Debug)]
11pub enum Ospfv3Packet {
12    Hello(OspfHellov3Packet),
13    DatabaseDescription(Ospfv3DatabaseDescriptionPacket),
14    LinkStateRequest(Ospfv3LinkStateRequestPacket),
15    LinkStateUpdate(Ospfv3LinkStateUpdatePacket),
16    LinkStateAcknowledgment(Ospfv3LinkStateAcknowledgmentPacket),
17}
18
19/// The OSPF v3 packet header
20///
21/// Every OSPF packet starts with a standard 16-byte header.  Together
22/// with the encapsulating IPv6 headers, the OSPF header contains all the
23/// information necessary to determine whether the packet should be
24/// accepted for further processing.  This determination is described in
25/// Section 4.2.2.
26#[derive(Debug, NomBE)]
27pub struct Ospfv3PacketHeader {
28    #[nom(Verify = "*version == 3")]
29    pub version: u8,
30    pub packet_type: OspfPacketType,
31    pub packet_length: u16,
32    pub router_id: u32,
33    pub area_id: u32,
34    pub checksum: u16,
35    pub instance_id: u8,
36    pub reserved: u8,
37}
38
39impl Ospfv3PacketHeader {
40    pub fn source_router(&self) -> Ipv4Addr {
41        Ipv4Addr::from(self.router_id)
42    }
43}
44
45/// The Hello packet (v3)
46///
47/// Hello packets are OSPF packet type 1.  These packets are sent
48/// periodically on all interfaces (including virtual links) in order to
49/// establish and maintain neighbor relationships.  In addition, Hello
50/// packets are multicast on those links having a multicast or broadcast
51/// capability, enabling dynamic discovery of neighboring routers.
52///
53/// All routers connected to a common link must agree on certain
54/// parameters (HelloInterval and RouterDeadInterval).  These parameters
55/// are included in Hello packets allowing differences to inhibit the
56/// forming of neighbor relationships.  The Hello packet also contains
57/// fields used in Designated Router election (Designated Router ID and
58/// Backup Designated Router ID), and fields used to detect bidirectional
59/// communication (the Router IDs of all neighbors whose Hellos have been
60/// recently received).
61#[derive(Debug, NomBE)]
62pub struct OspfHellov3Packet {
63    #[nom(Verify = "header.packet_type == OspfPacketType::Hello")]
64    pub header: Ospfv3PacketHeader,
65    pub interface_id: u32,
66    pub router_priority: u8,
67    #[nom(Parse = "be_u24")]
68    pub options: u32,
69    pub hello_interval: u16,
70    pub router_dead_interval: u16,
71    pub designated_router: u32,
72    pub backup_designated_router: u32,
73    // limit parsing to (length-xxx) bytes
74    #[nom(Parse = "parse_ospf_vec_u32(header.packet_length, 36)")]
75    pub neighbor_list: Vec<u32>,
76}
77
78impl OspfHellov3Packet {
79    pub fn designated_router(&self) -> Ipv4Addr {
80        Ipv4Addr::from(self.designated_router)
81    }
82
83    pub fn backup_designated_router(&self) -> Ipv4Addr {
84        Ipv4Addr::from(self.backup_designated_router)
85    }
86}
87
88/// The Database Description packet (v3)
89///
90/// Database Description packets are OSPF packet type 2.  These packets
91/// are exchanged when an adjacency is being initialized.  They describe
92/// the contents of the link-state database.  Multiple packets may be
93/// used to describe the database.  For this purpose, a poll-response
94/// procedure is used.  One of the routers is designated to be the master
95/// and the other is the slave.  The master sends Database Description
96/// packets (polls) that are acknowledged by Database Description packets
97/// sent by the slave (responses).  The responses are linked to the polls
98/// via the packets' DD sequence numbers.
99#[derive(Debug, NomBE)]
100pub struct Ospfv3DatabaseDescriptionPacket {
101    #[nom(Verify = "header.packet_type == OspfPacketType::DatabaseDescription")]
102    pub header: Ospfv3PacketHeader,
103    pub reserved0: u8,
104    #[nom(Parse = "be_u24")]
105    pub options: u32,
106    pub if_mtu: u16,
107    pub reserved: u8,
108    pub db_description: u8,
109    pub dd_sequence_number: u32,
110    pub lsa_headers: Vec<Ospfv3LinkStateAdvertisementHeader>,
111}
112
113/// The Link State Request packet (v3)
114///
115/// Link State Request packets are OSPF packet type 3.  After exchanging
116/// Database Description packets with a neighboring router, a router may
117/// find that parts of its link-state database are out-of-date.  The Link
118/// State Request packet is used to request the pieces of the neighbor's
119/// database that are more up-to-date.  Multiple Link State Request
120/// packets may need to be used.
121///
122/// A router that sends a Link State Request packet has in mind the
123/// precise instance of the database pieces it is requesting.  Each
124/// instance is defined by its LS sequence number, LS checksum, and LS
125/// age, although these fields are not specified in the Link State
126/// Request packet itself.  The router may receive even more recent LSA
127/// instances in response.
128///
129/// The sending of Link State Request packets is documented in Section
130/// 10.9 of [OSPFV2].  The reception of Link State Request packets is
131/// documented in Section 10.7 of [OSPFV2].
132#[derive(Debug, NomBE)]
133pub struct Ospfv3LinkStateRequestPacket {
134    #[nom(Verify = "header.packet_type == OspfPacketType::LinkStateRequest")]
135    pub header: Ospfv3PacketHeader,
136    pub requests: Vec<OspfLinkStateRequest>,
137}
138
139/// The Link State Update packet
140///
141/// Link State Update packets are OSPF packet type 4.  These packets
142/// implement the flooding of LSAs.  Each Link State Update packet
143/// carries a collection of LSAs one hop further from their origin.
144/// Several LSAs may be included in a single packet.
145///
146/// Link State Update packets are multicast on those physical networks
147/// that support multicast/broadcast.  In order to make the flooding
148/// procedure reliable, flooded LSAs are acknowledged in Link State
149/// Acknowledgment packets.  If retransmission of certain LSAs is
150/// necessary, the retransmitted LSAs are always carried by unicast Link
151/// State Update packets.  For more information on the reliable flooding
152/// of LSAs, consult Section 4.5.
153#[derive(Debug, NomBE)]
154pub struct Ospfv3LinkStateUpdatePacket {
155    #[nom(Verify = "header.packet_type == OspfPacketType::LinkStateUpdate")]
156    pub header: Ospfv3PacketHeader,
157    pub num_advertisements: u32,
158    #[nom(Count = "num_advertisements")]
159    pub lsa: Vec<Ospfv3LinkStateAdvertisement>,
160}
161
162/// The Link State Acknowledgment packet
163///
164/// Link State Acknowledgment packets are OSPF packet type 5.  To make
165/// the flooding of LSAs reliable, flooded LSAs are explicitly or
166/// implicitly acknowledged.  Explicit acknowledgment is accomplished
167/// through the sending and receiving of Link State Acknowledgment
168/// packets.  The sending of Link State Acknowledgment packets is
169/// documented in Section 13.5 of [OSPFV2].  The reception of Link State
170/// Acknowledgment packets is documented in Section 13.7 of [OSPFV2].
171///
172/// Multiple LSAs MAY be acknowledged in a single Link State
173/// Acknowledgment packet.  Depending on the state of the sending
174/// interface and the sender of the corresponding Link State Update
175/// packet, a Link State Acknowledgment packet is sent to the multicast
176/// address AllSPFRouters, the multicast address AllDRouters, or to a
177/// neighbor's unicast address (see Section 13.5 of [OSPFV2] for
178/// details).
179#[derive(Debug, NomBE)]
180pub struct Ospfv3LinkStateAcknowledgmentPacket {
181    #[nom(Verify = "header.packet_type == OspfPacketType::LinkStateAcknowledgment")]
182    pub header: Ospfv3PacketHeader,
183    pub lsa_headers: Vec<Ospfv3LinkStateAdvertisementHeader>,
184}
185
186#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, NomBE)]
187pub struct Ospfv3LinkStateType(pub u16);
188
189newtype_enum! {
190impl display Ospfv3LinkStateType {
191    RouterLSA = 0x2001,
192    NetworkLSA = 0x2002,
193    InterAreaPrefixLSA = 0x2003,
194    InterAreaRouterLSA = 0x2004,
195    ASExternalLSA = 0x4005,
196    NSSALSA = 0x2007,
197    LinkLSA = 0x0008,
198    IntraAreaPrefixLSA = 0x2009,
199}
200}
201
202/// The Link State Advertisement header
203///
204/// All LSAs begin with a common 20-byte header.  This header contains
205/// enough information to uniquely identify the LSA (LS type, Link State
206/// ID, and Advertising Router).  Multiple instances of the LSA may exist
207/// in the routing domain at the same time.  It is then necessary to
208/// determine which instance is more recent.  This is accomplished by
209/// examining the LS age, LS sequence number, and LS checksum fields that
210/// are also contained in the LSA header.
211#[derive(Debug, NomBE)]
212pub struct Ospfv3LinkStateAdvertisementHeader {
213    pub ls_age: u16,
214    pub link_state_type: Ospfv3LinkStateType,
215    pub link_state_id: u32,
216    pub advertising_router: u32,
217    pub ls_seq_number: u32,
218    pub ls_checksum: u16,
219    pub length: u16,
220}
221
222impl Ospfv3LinkStateAdvertisementHeader {
223    pub fn link_state_id(&self) -> Ipv4Addr {
224        Ipv4Addr::from(self.link_state_id)
225    }
226
227    pub fn advertising_router(&self) -> Ipv4Addr {
228        Ipv4Addr::from(self.advertising_router)
229    }
230}
231
232/// Link state advertisements (v3)
233#[derive(Debug)]
234pub enum Ospfv3LinkStateAdvertisement {
235    Router(Ospfv3RouterLSA),
236    Network(Ospfv3NetworkLSA),
237    InterAreaPrefix(Ospfv3InterAreaPrefixLSA),
238    InterAreaRouter(Ospfv3InterAreaRouterLSA),
239    ASExternal(Ospfv3ASExternalLSA),
240    NSSA(Ospfv3NSSALSA),
241    Link(Ospfv3LinkLSA),
242    IntraAreaPrefix(Ospfv3IntraAreaPrefixLSA),
243}
244
245/// Router links advertisements (v3)
246///
247/// Router links advertisements are the Type 1 link state
248/// advertisements.  Each router in an area originates a router links
249/// advertisement.  The advertisement describes the state and cost of
250/// the router's links (i.e., interfaces) to the area.  All of the
251/// router's links to the area must be described in a single router
252/// links advertisement.  For details concerning the construction of
253/// router links advertisements, see Section 12.4.1.
254#[derive(Debug, NomBE)]
255pub struct Ospfv3RouterLSA {
256    #[nom(Verify = "header.link_state_type == Ospfv3LinkStateType::RouterLSA")]
257    pub header: Ospfv3LinkStateAdvertisementHeader,
258    pub flags: u8,
259    #[nom(Parse = "be_u24")]
260    pub options: u32,
261    // limit parsing to (length-xxx) bytes
262    #[nom(Parse = "parse_ospfv3_router_links(header.length)")]
263    pub links: Vec<Ospfv3RouterLink>,
264}
265
266#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, NomBE)]
267pub struct Ospfv3RouterLinkType(pub u8);
268
269newtype_enum! {
270impl display Ospfv3RouterLinkType {
271    PointToPoint = 1,
272    Transit = 2,
273    Virtual = 4,
274}
275}
276
277/// OSPF router link (i.e., interface)
278#[derive(Debug, NomBE)]
279pub struct Ospfv3RouterLink {
280    pub link_type: Ospfv3RouterLinkType,
281    pub reserved: u8,
282    pub metric: u16,
283    pub interface_id: u32,
284    pub neighbor_interface_id: u32,
285    pub neighbor_router_id: u32,
286}
287
288impl Ospfv3RouterLink {
289    pub fn interface_id(&self) -> Ipv4Addr {
290        Ipv4Addr::from(self.interface_id)
291    }
292
293    pub fn neighbor_interface_id(&self) -> Ipv4Addr {
294        Ipv4Addr::from(self.neighbor_interface_id)
295    }
296
297    pub fn neighbor_router_id(&self) -> Ipv4Addr {
298        Ipv4Addr::from(self.neighbor_router_id)
299    }
300}
301
302/// Network links advertisements (v3)
303///
304/// Network-LSAs have LS type equal to 0x2002.  A network-LSA is
305/// originated for each broadcast and NBMA link in the area that includes
306/// two or more adjacent routers.  The network-LSA is originated by the
307/// link's Designated Router.  The LSA describes all routers attached to
308/// the link including the Designated Router itself.  The LSA's Link
309/// State ID field is set to the Interface ID that the Designated Router
310/// has been advertising in Hello packets on the link.
311///
312/// The distance from the network to all attached routers is zero.  This
313/// is why the Metric fields need not be specified in the network-LSA.
314/// For details concerning the construction of network-LSAs, see
315/// Section 4.4.3.3.
316#[derive(Debug, NomBE)]
317pub struct Ospfv3NetworkLSA {
318    #[nom(Verify = "header.link_state_type == Ospfv3LinkStateType::NetworkLSA")]
319    pub header: Ospfv3LinkStateAdvertisementHeader,
320    pub reserved: u8,
321    #[nom(Parse = "be_u24")]
322    pub options: u32,
323    // limit parsing to (length-xxx) bytes
324    #[nom(Parse = "parse_ospf_vec_u32(header.length, 24)")]
325    pub attached_routers: Vec<u32>,
326}
327
328impl Ospfv3NetworkLSA {
329    pub fn iter_attached_routers(&self) -> impl Iterator<Item = Ipv4Addr> + '_ {
330        self.attached_routers.iter().map(|&u| Ipv4Addr::from(u))
331    }
332}
333
334/// Inter-Area-Prefix-LSAs (v3)
335///
336/// Inter-area-prefix-LSAs have LS type equal to 0x2003.  These LSAs are
337/// the IPv6 equivalent of OSPF for IPv4's type 3 summary-LSAs (see
338/// Section 12.4.3 of [OSPFV2]).  Originated by area border routers, they
339/// describe routes to IPv6 address prefixes that belong to other areas.
340/// A separate inter-area-prefix-LSA is originated for each IPv6 address
341/// prefix.  For details concerning the construction of inter-area-
342/// prefix-LSAs, see Section 4.4.3.4.
343///
344/// For stub areas, inter-area-prefix-LSAs can also be used to describe a
345/// (per-area) default route.  Default summary routes are used in stub
346/// areas instead of flooding a complete set of external routes.  When
347/// describing a default summary route, the inter-area-prefix-LSA's
348/// PrefixLength is set to 0.
349#[derive(Debug, NomBE)]
350pub struct Ospfv3InterAreaPrefixLSA {
351    #[nom(Verify = "header.link_state_type == Ospfv3LinkStateType::InterAreaPrefixLSA")]
352    pub header: Ospfv3LinkStateAdvertisementHeader,
353    pub reserved0: u8,
354    #[nom(Parse = "be_u24")]
355    pub metric: u32,
356    pub prefix: Ospfv3IPv6AddressPrefix,
357}
358
359#[derive(Debug, NomBE)]
360pub struct Ospfv3IPv6AddressPrefix {
361    pub prefix_length: u8,
362    pub prefix_options: u8,
363    pub reserved: u16,
364    #[nom(Parse = "take_vec_u8(prefix_length / 8)")]
365    pub address_prefix: Vec<u8>,
366}
367
368/// Inter-Area-Router-LSAs (v3)
369///
370/// Inter-area-router-LSAs have LS type equal to 0x2004.  These LSAs are
371/// the IPv6 equivalent of OSPF for IPv4's type 4 summary-LSAs (see
372/// Section 12.4.3 of [OSPFV2]).  Originated by area border routers, they
373/// describe routes to AS boundary routers in other areas.  To see why it
374/// is necessary to advertise the location of each ASBR, consult Section
375/// 16.4 in [OSPFV2].  Each LSA describes a route to a single router.
376/// For details concerning the construction of inter-area-router-LSAs,
377/// see Section 4.4.3.5.
378#[derive(Debug, NomBE)]
379pub struct Ospfv3InterAreaRouterLSA {
380    #[nom(Verify = "header.link_state_type == Ospfv3LinkStateType::InterAreaRouterLSA")]
381    pub header: Ospfv3LinkStateAdvertisementHeader,
382    pub reserved0: u8,
383    #[nom(Parse = "be_u24")]
384    pub options: u32,
385    pub reserved1: u8,
386    #[nom(Parse = "be_u24")]
387    pub metric: u32,
388    pub destination_router_id: u32,
389}
390
391/// AS-External-LSAs
392///
393/// AS-external-LSAs have LS type equal to 0x4005.  These LSAs are
394/// originated by AS boundary routers and describe destinations external
395/// to the AS.  Each LSA describes a route to a single IPv6 address
396/// prefix.  For details concerning the construction of AS-external-LSAs,
397/// see Section 4.4.3.6.
398///
399/// AS-external-LSAs can be used to describe a default route.  Default
400/// routes are used when no specific route exists to the destination.
401/// When describing a default route, the AS-external-LSA's PrefixLength
402/// is set to 0.
403#[derive(Debug, NomBE)]
404pub struct Ospfv3ASExternalLSA {
405    #[nom(
406        Verify = "header.link_state_type == Ospfv3LinkStateType::ASExternalLSA ||
407             header.link_state_type == Ospfv3LinkStateType::NSSALSA"
408    )]
409    pub header: Ospfv3LinkStateAdvertisementHeader,
410    pub flags: u8,
411    #[nom(Parse = "be_u24")]
412    pub metric: u32,
413    pub address_prefix: Ospfv3IPv6AddressPrefix,
414    #[nom(Parse = "cond(flags & 0b10 != 0, take_vec_u8(16))")]
415    pub forwarding_address: Option<Vec<u8>>,
416    #[nom(Parse = "cond(flags & 0b01 != 0, be_u32)")]
417    pub external_route_tag: Option<u32>,
418    #[nom(Parse = "cond(address_prefix.reserved != 0, be_u32)")]
419    pub referenced_link_state_id: Option<u32>,
420}
421
422/// NSSA-LSAs
423///
424/// NSSA-LSAs have LS type equal to 0x2007.  These LSAs are originated by
425/// AS boundary routers within an NSSA and describe destinations external
426/// to the AS that may or may not be propagated outside the NSSA (refer
427/// to [NSSA]).  Other than the LS type, their format is exactly the same
428/// as AS-external LSAs as described in Appendix A.4.7.
429///
430/// A global IPv6 address MUST be selected as forwarding address for
431/// NSSA-LSAs that are to be propagated by NSSA area border routers.  The
432/// selection should proceed the same as OSPFv2 NSSA support [NSSA] with
433/// additional checking to ensure IPv6 link-local address are not
434/// selected.
435type Ospfv3NSSALSA = Ospfv3ASExternalLSA;
436
437/// Link-LSAs
438///
439/// Link-LSAs have LS type equal to 0x0008.  A router originates a
440/// separate link-LSA for each attached physical link.  These LSAs have
441/// link-local flooding scope; they are never flooded beyond the
442/// associated link.  Link-LSAs have three purposes:
443///
444/// 1.  They provide the router's link-local address to all other routers
445///     attached to the link.
446///
447/// 2.  They inform other routers attached to the link of a list of IPv6
448///     prefixes to associate with the link.
449///
450/// 3.  They allow the router to advertise a collection of Options bits
451///     in the network-LSA originated by the Designated Router on a
452///     broadcast or NBMA link.
453///
454/// For details concerning the construction of links-LSAs, see
455/// Section 4.4.3.8.
456///
457/// A link-LSA's Link State ID is set equal to the originating router's
458/// Interface ID on the link.
459#[derive(Debug, NomBE)]
460pub struct Ospfv3LinkLSA {
461    #[nom(Verify = "header.link_state_type == Ospfv3LinkStateType::LinkLSA")]
462    pub header: Ospfv3LinkStateAdvertisementHeader,
463    pub router_priority: u8,
464    #[nom(Parse = "be_u24")]
465    pub options: u32,
466    #[nom(Parse = "take_vec_u8(16)")]
467    pub link_local_interface_address: Vec<u8>,
468    pub num_prefixes: u32,
469    #[nom(Count = "num_prefixes")]
470    pub address_prefixes: Vec<Ospfv3IPv6AddressPrefix>,
471}
472
473/// Intra-Area-Prefix-LSAs
474///
475/// Intra-area-prefix-LSAs have LS type equal to 0x2009.  A router uses
476/// intra-area-prefix-LSAs to advertise one or more IPv6 address prefixes
477/// that are associated with a local router address, an attached stub
478/// network segment, or an attached transit network segment.  In IPv4,
479/// the first two were accomplished via the router's router-LSA and the
480/// last via a network-LSA.  In OSPF for IPv6, all addressing information
481/// that was advertised in router-LSAs and network-LSAs has been removed
482/// and is now advertised in intra-area-prefix-LSAs.  For details
483/// concerning the construction of intra-area-prefix-LSA, see
484/// Section 4.4.3.9.
485///
486/// A router can originate multiple intra-area-prefix-LSAs for each
487/// router or transit network.  Each such LSA is distinguished by its
488/// unique Link State ID.
489#[derive(Debug, NomBE)]
490pub struct Ospfv3IntraAreaPrefixLSA {
491    #[nom(Verify = "header.link_state_type == Ospfv3LinkStateType::IntraAreaPrefixLSA")]
492    pub header: Ospfv3LinkStateAdvertisementHeader,
493    pub num_prefixes: u16,
494    pub referenced_ls_type: u16,
495    pub referenced_link_state_id: u32,
496    pub referenced_advertising_router: u32,
497    #[nom(Count = "num_prefixes")]
498    pub address_prefixes: Vec<Ospfv3IPv6AddressPrefix>,
499}