ospf_parser/
ospfv2.rs

1use crate::parser::{parse_ospf_external_tos_routes, parse_ospf_tos_routes, parse_ospf_vec_u32};
2use nom::number::streaming::be_u24;
3use nom_derive::*;
4use rusticata_macros::newtype_enum;
5use std::net::Ipv4Addr;
6
7#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, NomBE)]
8pub struct OspfPacketType(pub u8);
9
10newtype_enum! {
11impl display OspfPacketType {
12    Hello = 1,
13    DatabaseDescription = 2,
14    LinkStateRequest = 3,
15    LinkStateUpdate = 4,
16    LinkStateAcknowledgment = 5,
17}
18}
19
20/// An OSPF version 2 packet
21#[derive(Debug)]
22pub enum Ospfv2Packet {
23    Hello(OspfHelloPacket),
24    DatabaseDescription(OspfDatabaseDescriptionPacket),
25    LinkStateRequest(OspfLinkStateRequestPacket),
26    LinkStateUpdate(OspfLinkStateUpdatePacket),
27    LinkStateAcknowledgment(OspfLinkStateAcknowledgmentPacket),
28}
29
30/// The OSPF packet header
31///
32/// Every OSPF packet starts with a common 24 byte header.  This header
33/// contains all the necessary information to determine whether the
34/// packet should be accepted for further processing.  This
35/// determination is described in Section 8.2 of the specification.
36#[derive(Debug, NomBE)]
37pub struct Ospfv2PacketHeader {
38    #[nom(Verify = "*version == 2")]
39    pub version: u8,
40    pub packet_type: OspfPacketType,
41    pub packet_length: u16,
42    pub router_id: u32,
43    pub area_id: u32,
44    pub checksum: u16,
45    pub au_type: u16,
46    pub authentication: u64,
47}
48
49impl Ospfv2PacketHeader {
50    pub fn source_router(&self) -> Ipv4Addr {
51        Ipv4Addr::from(self.router_id)
52    }
53}
54
55/// The Hello packet
56///
57/// Hello packets are OSPF packet type 1.  These packets are sent
58/// periodically on all interfaces (including virtual links) in order to
59/// establish and maintain neighbor relationships.  In addition, Hello
60/// Packets are multicast on those physical networks having a multicast
61/// or broadcast capability, enabling dynamic discovery of neighboring
62/// routers.
63///
64/// All routers connected to a common network must agree on certain
65/// parameters (Network mask, HelloInterval and RouterDeadInterval).
66/// These parameters are included in Hello packets, so that differences
67/// can inhibit the forming of neighbor relationships. A detailed
68/// explanation of the receive processing for Hello packets is presented
69/// in Section 10.5.  The sending of Hello packets is covered in Section
70/// 9.5.
71#[derive(Debug, NomBE)]
72pub struct OspfHelloPacket {
73    #[nom(Verify = "header.packet_type == OspfPacketType::Hello")]
74    pub header: Ospfv2PacketHeader,
75    pub network_mask: u32,
76    pub hello_interval: u16,
77    pub options: u8,
78    pub router_priority: u8,
79    pub router_dead_interval: u32,
80    pub designated_router: u32,
81    pub backup_designated_router: u32,
82    // limit parsing to (length-xxx) bytes
83    #[nom(Parse = "parse_ospf_vec_u32(header.packet_length, 44)")]
84    pub neighbor_list: Vec<u32>,
85}
86
87impl OspfHelloPacket {
88    pub fn network_mask(&self) -> Ipv4Addr {
89        Ipv4Addr::from(self.network_mask)
90    }
91
92    pub fn designated_router(&self) -> Ipv4Addr {
93        Ipv4Addr::from(self.designated_router)
94    }
95
96    pub fn backup_designated_router(&self) -> Ipv4Addr {
97        Ipv4Addr::from(self.backup_designated_router)
98    }
99}
100
101/// The Database Description packet
102///
103/// Database Description packets are OSPF packet type 2.  These packets
104/// are exchanged when an adjacency is being initialized.  They describe
105/// the contents of the topological database.  Multiple packets may be
106/// used to describe the database.  For this purpose a poll-response
107/// procedure is used.  One of the routers is designated to be master,
108/// the other a slave.  The master sends Database Description packets
109/// (polls) which are acknowledged by Database Description packets sent
110/// by the slave (responses).  The responses are linked to the polls via
111/// the packets' DD sequence numbers.
112#[derive(Debug, NomBE)]
113pub struct OspfDatabaseDescriptionPacket {
114    #[nom(Verify = "header.packet_type == OspfPacketType::DatabaseDescription")]
115    pub header: Ospfv2PacketHeader,
116    pub if_mtu: u16,
117    pub options: u8,
118    pub flags: u8,
119    pub dd_sequence_number: u32,
120    pub lsa_headers: Vec<OspfLinkStateAdvertisementHeader>,
121}
122
123/// The Link State Request packet
124///
125/// Link State Request packets are OSPF packet type 3.  After exchanging
126/// Database Description packets with a neighboring router, a router may
127/// find that parts of its topological database are out of date.  The
128/// Link State Request packet is used to request the pieces of the
129/// neighbor's database that are more up to date.  Multiple Link State
130/// Request packets may need to be used.  The sending of Link State
131/// Request packets is the last step in bringing up an adjacency.
132///
133/// A router that sends a Link State Request packet has in mind the
134/// precise instance of the database pieces it is requesting, defined by
135/// LS sequence number, LS checksum, and LS age, although these fields
136/// are not specified in the Link State Request Packet itself.  The
137/// router may receive even more recent instances in response.
138///
139/// The sending of Link State Request packets is documented in Section
140/// 10.9.  The reception of Link State Request packets is documented in
141/// Section 10.7.
142#[derive(Debug, NomBE)]
143pub struct OspfLinkStateRequestPacket {
144    #[nom(Verify = "header.packet_type == OspfPacketType::LinkStateRequest")]
145    pub header: Ospfv2PacketHeader,
146    pub requests: Vec<OspfLinkStateRequest>,
147}
148
149#[derive(Debug, NomBE)]
150pub struct OspfLinkStateRequest {
151    // XXX should be a OspfLinkStateType, but it is only an u8
152    pub link_state_type: u32,
153    pub link_state_id: u32,
154    pub advertising_router: u32,
155}
156
157impl OspfLinkStateRequest {
158    pub fn link_state_id(&self) -> Ipv4Addr {
159        Ipv4Addr::from(self.link_state_id)
160    }
161
162    pub fn advertising_router(&self) -> Ipv4Addr {
163        Ipv4Addr::from(self.advertising_router)
164    }
165}
166
167/// The Link State Update packet
168///
169/// Link State Update packets are OSPF packet type 4.  These packets
170/// implement the flooding of link state advertisements.  Each Link
171/// State Update packet carries a collection of link state
172/// advertisements one hop further from its origin.  Several link state
173/// advertisements may be included in a single packet.
174///
175/// Link State Update packets are multicast on those physical networks
176/// that support multicast/broadcast.  In order to make the flooding
177/// procedure reliable, flooded advertisements are acknowledged in Link
178/// State Acknowledgment packets.  If retransmission of certain
179/// advertisements is necessary, the retransmitted advertisements are
180/// always carried by unicast Link State Update packets.  For more
181/// information on the reliable flooding of link state advertisements,
182/// consult Section 13.
183#[derive(Debug, NomBE)]
184pub struct OspfLinkStateUpdatePacket {
185    #[nom(Verify = "header.packet_type == OspfPacketType::LinkStateUpdate")]
186    pub header: Ospfv2PacketHeader,
187    pub num_advertisements: u32,
188    #[nom(Count = "num_advertisements")]
189    pub lsa: Vec<OspfLinkStateAdvertisement>,
190}
191
192/// The Link State Acknowledgment packet
193///
194/// Link State Acknowledgment Packets are OSPF packet type 5.  To make
195/// the flooding of link state advertisements reliable, flooded
196/// advertisements are explicitly acknowledged.  This acknowledgment is
197/// accomplished through the sending and receiving of Link State
198/// Acknowledgment packets.  Multiple link state advertisements can be
199/// acknowledged in a single Link State Acknowledgment packet.
200///
201/// Depending on the state of the sending interface and the source of
202/// the advertisements being acknowledged, a Link State Acknowledgment
203/// packet is sent either to the multicast address AllSPFRouters, to the
204/// multicast address AllDRouters, or as a unicast.  The sending of Link
205/// State Acknowledgement packets is documented in Section 13.5.  The
206/// reception of Link State Acknowledgement packets is documented in
207/// Section 13.7.
208///
209/// The format of this packet is similar to that of the Data Description
210/// packet.  The body of both packets is simply a list of link state
211/// advertisement headers.
212#[derive(Debug, NomBE)]
213pub struct OspfLinkStateAcknowledgmentPacket {
214    #[nom(Verify = "header.packet_type == OspfPacketType::LinkStateAcknowledgment")]
215    pub header: Ospfv2PacketHeader,
216    pub lsa_headers: Vec<OspfLinkStateAdvertisementHeader>,
217}
218
219#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, NomBE)]
220pub struct OspfLinkStateType(pub u8);
221
222newtype_enum! {
223impl display OspfLinkStateType {
224    RouterLinks = 1,
225    NetworkLinks = 2,
226    SummaryLinkIpNetwork = 3,
227    SummaryLinkAsbr = 4,
228    ASExternalLink = 5,
229    NSSAASExternal = 7,
230    OpaqueLinkLocalScope = 9,
231    OpaqueAreaLocalScope = 10,
232    OpaqueASWideScope = 11,
233}
234}
235
236/// The Link State Advertisement header
237///
238/// All link state advertisements begin with a common 20 byte header.
239/// This header contains enough information to uniquely identify the
240/// advertisement (LS type, Link State ID, and Advertising Router).
241/// Multiple instances of the link state advertisement may exist in the
242/// routing domain at the same time.  It is then necessary to determine
243/// which instance is more recent.  This is accomplished by examining
244/// the LS age, LS sequence number and LS checksum fields that are also
245/// contained in the link state advertisement header.
246#[derive(Debug, NomBE)]
247pub struct OspfLinkStateAdvertisementHeader {
248    pub ls_age: u16,
249    pub options: u8,
250    pub link_state_type: OspfLinkStateType,
251    pub link_state_id: u32,
252    pub advertising_router: u32,
253    pub ls_seq_number: u32,
254    pub ls_checksum: u16,
255    pub length: u16,
256}
257
258impl OspfLinkStateAdvertisementHeader {
259    pub fn link_state_id(&self) -> Ipv4Addr {
260        Ipv4Addr::from(self.link_state_id)
261    }
262
263    pub fn advertising_router(&self) -> Ipv4Addr {
264        Ipv4Addr::from(self.advertising_router)
265    }
266}
267
268/// Link state advertisements
269#[derive(Debug)]
270pub enum OspfLinkStateAdvertisement {
271    RouterLinks(OspfRouterLinksAdvertisement),
272    NetworkLinks(OspfNetworkLinksAdvertisement),
273    SummaryLinkIpNetwork(OspfSummaryLinkAdvertisement),
274    SummaryLinkAsbr(OspfSummaryLinkAdvertisement),
275    ASExternalLink(OspfASExternalLinkAdvertisement),
276    NSSAASExternal(OspfNSSAExternalLinkAdvertisement),
277    OpaqueLinkLocalScope(OspfOpaqueLinkAdvertisement),
278    OpaqueAreaLocalScope(OspfOpaqueLinkAdvertisement),
279    OpaqueASWideScope(OspfOpaqueLinkAdvertisement),
280}
281
282/// Router links advertisements
283///
284/// Router links advertisements are the Type 1 link state
285/// advertisements.  Each router in an area originates a router links
286/// advertisement.  The advertisement describes the state and cost of
287/// the router's links (i.e., interfaces) to the area.  All of the
288/// router's links to the area must be described in a single router
289/// links advertisement.  For details concerning the construction of
290/// router links advertisements, see Section 12.4.1.
291#[derive(Debug, NomBE)]
292pub struct OspfRouterLinksAdvertisement {
293    #[nom(Verify = "header.link_state_type == OspfLinkStateType::RouterLinks")]
294    pub header: OspfLinkStateAdvertisementHeader,
295    pub flags: u16,
296    pub num_links: u16,
297    #[nom(Count = "num_links")]
298    pub links: Vec<OspfRouterLink>,
299}
300
301#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, NomBE)]
302pub struct OspfRouterLinkType(pub u8);
303
304newtype_enum! {
305impl display OspfRouterLinkType {
306    PointToPoint = 1,
307    Transit = 2,
308    Stub = 3,
309    Virtual = 4,
310}
311}
312
313/// OSPF router link (i.e., interface)
314#[derive(Debug, NomBE)]
315pub struct OspfRouterLink {
316    pub link_id: u32,
317    pub link_data: u32,
318    pub link_type: OspfRouterLinkType,
319    pub num_tos: u8,
320    pub tos_0_metric: u16,
321    #[nom(Count = "num_tos")]
322    pub tos_list: Vec<OspfRouterTOS>,
323}
324
325impl OspfRouterLink {
326    pub fn link_id(&self) -> Ipv4Addr {
327        Ipv4Addr::from(self.link_id)
328    }
329
330    pub fn link_data(&self) -> Ipv4Addr {
331        Ipv4Addr::from(self.link_data)
332    }
333}
334
335/// OSPF Router Type Of Service (TOS)
336#[derive(Debug, NomBE)]
337pub struct OspfRouterTOS {
338    pub tos: u8,
339    pub reserved: u8,
340    pub metric: u16,
341}
342
343/// Network links advertisements
344///
345/// Network links advertisements are the Type 2 link state
346/// advertisements.  A network links advertisement is originated for
347/// each transit network in the area.  A transit network is a multi-
348/// access network that has more than one attached router.  The network
349/// links advertisement is originated by the network's Designated
350/// Router.  The advertisement describes all routers attached to the
351/// network, including the Designated Router itself.  The
352/// advertisement's Link State ID field lists the IP interface address
353/// of the Designated Router.
354///
355/// The distance from the network to all attached routers is zero, for
356/// all Types of Service.  This is why the TOS and metric fields need
357/// not be specified in the network links advertisement.  For details
358/// concerning the construction of network links advertisements, see
359/// Section 12.4.2.
360#[derive(Debug, NomBE)]
361pub struct OspfNetworkLinksAdvertisement {
362    #[nom(Verify = "header.link_state_type == OspfLinkStateType::NetworkLinks")]
363    pub header: OspfLinkStateAdvertisementHeader,
364    pub network_mask: u32,
365    // limit parsing to (length-xxx) bytes
366    #[nom(Parse = "parse_ospf_vec_u32(header.length, 24)")]
367    pub attached_routers: Vec<u32>,
368}
369
370impl OspfNetworkLinksAdvertisement {
371    pub fn network_mask(&self) -> Ipv4Addr {
372        Ipv4Addr::from(self.network_mask)
373    }
374
375    pub fn iter_attached_routers(&self) -> impl Iterator<Item = Ipv4Addr> + '_ {
376        self.attached_routers.iter().map(|&u| Ipv4Addr::from(u))
377    }
378}
379
380/// Summary link advertisements
381///
382/// Summary link advertisements are the Type 3 and 4 link state
383/// advertisements.  These advertisements are originated by area border
384/// routers.  A separate summary link advertisement is made for each
385/// destination (known to the router) which belongs to the AS, yet is
386/// outside the area.  For details concerning the construction of
387/// summary link advertisements, see Section 12.4.3.
388///
389/// Type 3 link state advertisements are used when the destination is an
390/// IP network.  In this case the advertisement's Link State ID field is
391/// an IP network number (if necessary, the Link State ID can also have
392/// one or more of the network's "host" bits set; see Appendix F for
393/// details). When the destination is an AS boundary router, a Type 4
394/// advertisement is used, and the Link State ID field is the AS
395/// boundary router's OSPF Router ID.  (To see why it is necessary to
396/// advertise the location of each ASBR, consult Section 16.4.)  Other
397/// than the difference in the Link State ID field, the format of Type 3
398/// and 4 link state advertisements is identical.
399#[derive(Debug, NomBE)]
400pub struct OspfSummaryLinkAdvertisement {
401    #[nom(
402        Verify = "header.link_state_type == OspfLinkStateType::SummaryLinkIpNetwork ||
403        header.link_state_type == OspfLinkStateType::SummaryLinkAsbr"
404    )]
405    pub header: OspfLinkStateAdvertisementHeader,
406    pub network_mask: u32,
407    pub tos: u8,
408    #[nom(Parse = "be_u24")]
409    pub metric: u32,
410    // limit parsing to (length-xxx) bytes
411    #[nom(Parse = "parse_ospf_tos_routes(header.length)")]
412    pub tos_routes: Vec<OspfTosRoute>,
413}
414
415impl OspfSummaryLinkAdvertisement {
416    pub fn network_mask(&self) -> Ipv4Addr {
417        Ipv4Addr::from(self.network_mask)
418    }
419}
420
421#[derive(Debug, NomBE)]
422pub struct OspfTosRoute {
423    pub tos: u8,
424    #[nom(Parse = "be_u24")]
425    pub metric: u32,
426}
427
428/// AS external link advertisements
429///
430/// AS external link advertisements are the Type 5 link state
431/// advertisements.  These advertisements are originated by AS boundary
432/// routers.  A separate advertisement is made for each destination
433/// (known to the router) which is external to the AS.  For details
434/// concerning the construction of AS external link advertisements, see
435/// Section 12.4.3.
436///
437/// AS external link advertisements usually describe a particular
438/// external destination.  For these advertisements the Link State ID
439/// field specifies an IP network number (if necessary, the Link State
440/// ID can also have one or more of the network's "host" bits set; see
441/// Appendix F for details).  AS external link advertisements are also
442/// used to describe a default route.  Default routes are used when no
443/// specific route exists to the destination.  When describing a default
444/// route, the Link State ID is always set to DefaultDestination
445/// (0.0.0.0) and the Network Mask is set to 0.0.0.0.
446#[derive(Debug, NomBE)]
447pub struct OspfASExternalLinkAdvertisement {
448    #[nom(Verify = "header.link_state_type == OspfLinkStateType::ASExternalLink")]
449    pub header: OspfLinkStateAdvertisementHeader,
450    pub network_mask: u32,
451    pub external_and_reserved: u8,
452    #[nom(Parse = "be_u24")]
453    pub metric: u32,
454    pub forwarding_address: u32,
455    pub external_route_tag: u32,
456    // limit parsing to (length-xxx) bytes
457    #[nom(Parse = "parse_ospf_external_tos_routes(header.length)")]
458    pub tos_list: Vec<OspfExternalTosRoute>,
459}
460
461impl OspfASExternalLinkAdvertisement {
462    pub fn forwarding_address(&self) -> Ipv4Addr {
463        Ipv4Addr::from(self.forwarding_address)
464    }
465    pub fn network_mask(&self) -> Ipv4Addr {
466        Ipv4Addr::from(self.network_mask)
467    }
468}
469
470#[derive(Debug, NomBE)]
471pub struct OspfExternalTosRoute {
472    pub tos: u8,
473    #[nom(Parse = "be_u24")]
474    pub metric: u32,
475    pub forwarding_address: u32,
476    pub external_route_tag: u32,
477}
478
479impl OspfExternalTosRoute {
480    pub fn forwarding_address(&self) -> Ipv4Addr {
481        Ipv4Addr::from(self.forwarding_address)
482    }
483}
484
485/// NSSA AS-External LSA (type 7, rfc1587, rfc3101)
486#[derive(Debug, NomBE)]
487pub struct OspfNSSAExternalLinkAdvertisement {
488    #[nom(Verify = "header.link_state_type == OspfLinkStateType::NSSAASExternal")]
489    pub header: OspfLinkStateAdvertisementHeader,
490    pub network_mask: u32,
491    pub external_and_tos: u8,
492    #[nom(Parse = "be_u24")]
493    pub metric: u32,
494    pub forwarding_address: u32,
495    pub external_route_tag: u32,
496    // limit parsing to (length-xxx) bytes
497    #[nom(Parse = "parse_ospf_external_tos_routes(header.length)")]
498    pub tos_list: Vec<OspfExternalTosRoute>,
499}
500
501impl OspfNSSAExternalLinkAdvertisement {
502    pub fn forwarding_address(&self) -> Ipv4Addr {
503        Ipv4Addr::from(self.forwarding_address)
504    }
505    pub fn network_mask(&self) -> Ipv4Addr {
506        Ipv4Addr::from(self.network_mask)
507    }
508}
509
510/// The Opaque LSA (RFC5250)
511///
512/// Opaque LSAs are Type 9, 10, and 11 link state advertisements.  These
513/// advertisements MAY be used directly by OSPF or indirectly by some
514/// application wishing to distribute information throughout the OSPF
515/// domain.  The function of the Opaque LSA option is to provide for
516/// future OSPF extensibility.
517///
518/// Opaque LSAs contain some number of octets (of application-specific
519/// data) padded to 32-bit alignment.  Like any other LSA, the Opaque LSA
520/// uses the link-state database distribution mechanism for flooding this
521/// information throughout the topology.  However, the Opaque LSA has a
522/// flooding scope associated with it so that the scope of flooding may
523/// be link-local (type-9), area-local (type-10), or the entire OSPF
524/// routing domain (type-11).  Section 3 of this document describes the
525/// flooding procedures for the Opaque LSA.
526#[derive(Debug, NomBE)]
527pub struct OspfOpaqueLinkAdvertisement {
528    #[nom(
529        Verify = "header.link_state_type == OspfLinkStateType::OpaqueLinkLocalScope ||
530        header.link_state_type == OspfLinkStateType::OpaqueAreaLocalScope ||
531        header.link_state_type == OspfLinkStateType::OpaqueASWideScope"
532    )]
533    pub header: OspfLinkStateAdvertisementHeader,
534    pub data: Vec<u8>,
535}
536
537impl OspfOpaqueLinkAdvertisement {
538    pub fn opaque_type(&self) -> u8 {
539        (self.header.link_state_id >> 24) as u8
540    }
541
542    pub fn opaque_id(&self) -> u32 {
543        self.header.link_state_id & 0xff_ffff
544    }
545}