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}