ospf_parser/
parser.rs

1use crate::ospfv2::*;
2use crate::ospfv3::*;
3use nom::bytes::streaming::take;
4use nom::combinator::{complete, map, peek};
5use nom::error::{make_error, ErrorKind};
6use nom::multi::many0;
7use nom::number::complete::be_u32 as be_u32_complete;
8use nom::number::streaming::{be_u16, be_u32};
9pub use nom::IResult;
10use nom_derive::Parse;
11
12pub fn parse_ospfv2_packet(input: &[u8]) -> IResult<&[u8], Ospfv2Packet> {
13    let (_, word) = peek(be_u16)(input)?;
14    let b0 = (word >> 8) as u8;
15    let b1 = (word & 0xff) as u8;
16    if b0 != 2 {
17        return Err(nom::Err::Error(make_error(input, ErrorKind::Tag)));
18    }
19    match OspfPacketType(b1) {
20        OspfPacketType::Hello => map(OspfHelloPacket::parse, Ospfv2Packet::Hello)(input),
21        OspfPacketType::DatabaseDescription => map(
22            OspfDatabaseDescriptionPacket::parse,
23            Ospfv2Packet::DatabaseDescription,
24        )(input),
25        OspfPacketType::LinkStateRequest => map(
26            OspfLinkStateRequestPacket::parse,
27            Ospfv2Packet::LinkStateRequest,
28        )(input),
29        OspfPacketType::LinkStateUpdate => map(
30            OspfLinkStateUpdatePacket::parse,
31            Ospfv2Packet::LinkStateUpdate,
32        )(input),
33        OspfPacketType::LinkStateAcknowledgment => map(
34            OspfLinkStateAcknowledgmentPacket::parse,
35            Ospfv2Packet::LinkStateAcknowledgment,
36        )(input),
37        _ => Err(nom::Err::Error(make_error(input, ErrorKind::Tag))),
38    }
39}
40
41pub fn parse_ospfv3_packet(input: &[u8]) -> IResult<&[u8], Ospfv3Packet> {
42    let (_, word) = peek(be_u16)(input)?;
43    let b0 = (word >> 8) as u8;
44    let b1 = (word & 0xff) as u8;
45    if b0 != 3 {
46        return Err(nom::Err::Error(make_error(input, ErrorKind::Tag)));
47    }
48    match OspfPacketType(b1) {
49        OspfPacketType::Hello => map(OspfHellov3Packet::parse, Ospfv3Packet::Hello)(input),
50        OspfPacketType::DatabaseDescription => map(
51            Ospfv3DatabaseDescriptionPacket::parse,
52            Ospfv3Packet::DatabaseDescription,
53        )(input),
54        OspfPacketType::LinkStateRequest => map(
55            Ospfv3LinkStateRequestPacket::parse,
56            Ospfv3Packet::LinkStateRequest,
57        )(input),
58        OspfPacketType::LinkStateUpdate => map(
59            Ospfv3LinkStateUpdatePacket::parse,
60            Ospfv3Packet::LinkStateUpdate,
61        )(input),
62        OspfPacketType::LinkStateAcknowledgment => map(
63            Ospfv3LinkStateAcknowledgmentPacket::parse,
64            Ospfv3Packet::LinkStateAcknowledgment,
65        )(input),
66        _ => Err(nom::Err::Error(make_error(input, ErrorKind::Tag))),
67    }
68}
69
70pub fn parse_ospfv2_packet_header(input: &[u8]) -> IResult<&[u8], Ospfv2PacketHeader> {
71    Ospfv2PacketHeader::parse(input)
72}
73
74pub fn parse_ospfv2_hello_packet(input: &[u8]) -> IResult<&[u8], OspfHelloPacket> {
75    OspfHelloPacket::parse(input)
76}
77
78pub fn parse_ospfv2_database_description_packet(
79    input: &[u8],
80) -> IResult<&[u8], OspfDatabaseDescriptionPacket> {
81    OspfDatabaseDescriptionPacket::parse(input)
82}
83
84pub fn parse_ospfv2_link_state_request_packet(
85    input: &[u8],
86) -> IResult<&[u8], OspfLinkStateRequestPacket> {
87    OspfLinkStateRequestPacket::parse(input)
88}
89
90impl<'a> Parse<&'a [u8]> for OspfLinkStateAdvertisement {
91    fn parse(input: &[u8]) -> IResult<&[u8], OspfLinkStateAdvertisement> {
92        let (_, word) = peek(be_u32)(input)?;
93        let ls_type = (word & 0xff) as u8;
94        match OspfLinkStateType(ls_type) {
95            OspfLinkStateType::RouterLinks => map(
96                OspfRouterLinksAdvertisement::parse,
97                OspfLinkStateAdvertisement::RouterLinks,
98            )(input),
99            OspfLinkStateType::NetworkLinks => map(
100                OspfNetworkLinksAdvertisement::parse,
101                OspfLinkStateAdvertisement::NetworkLinks,
102            )(input),
103            OspfLinkStateType::SummaryLinkIpNetwork => map(
104                OspfSummaryLinkAdvertisement::parse,
105                OspfLinkStateAdvertisement::SummaryLinkIpNetwork,
106            )(input),
107            OspfLinkStateType::SummaryLinkAsbr => map(
108                OspfSummaryLinkAdvertisement::parse,
109                OspfLinkStateAdvertisement::SummaryLinkAsbr,
110            )(input),
111            OspfLinkStateType::ASExternalLink => map(
112                OspfASExternalLinkAdvertisement::parse,
113                OspfLinkStateAdvertisement::ASExternalLink,
114            )(input),
115            OspfLinkStateType::NSSAASExternal => map(
116                OspfNSSAExternalLinkAdvertisement::parse,
117                OspfLinkStateAdvertisement::NSSAASExternal,
118            )(input),
119            OspfLinkStateType::OpaqueLinkLocalScope => map(
120                OspfOpaqueLinkAdvertisement::parse,
121                OspfLinkStateAdvertisement::OpaqueLinkLocalScope,
122            )(input),
123            OspfLinkStateType::OpaqueAreaLocalScope => map(
124                OspfOpaqueLinkAdvertisement::parse,
125                OspfLinkStateAdvertisement::OpaqueAreaLocalScope,
126            )(input),
127            OspfLinkStateType::OpaqueASWideScope => map(
128                OspfOpaqueLinkAdvertisement::parse,
129                OspfLinkStateAdvertisement::OpaqueASWideScope,
130            )(input),
131            _ => Err(nom::Err::Error(make_error(input, ErrorKind::Tag))),
132        }
133    }
134}
135
136impl<'a> Parse<&'a [u8]> for Ospfv3LinkStateAdvertisement {
137    fn parse(input: &[u8]) -> IResult<&[u8], Ospfv3LinkStateAdvertisement> {
138        let (_, word) = peek(be_u32)(input)?;
139        let ls_type = (word & 0xffff) as u16;
140        match Ospfv3LinkStateType(ls_type) {
141            Ospfv3LinkStateType::RouterLSA => {
142                map(Ospfv3RouterLSA::parse, Ospfv3LinkStateAdvertisement::Router)(input)
143            }
144            Ospfv3LinkStateType::NetworkLSA => map(
145                Ospfv3NetworkLSA::parse,
146                Ospfv3LinkStateAdvertisement::Network,
147            )(input),
148            Ospfv3LinkStateType::InterAreaPrefixLSA => map(
149                Ospfv3InterAreaPrefixLSA::parse,
150                Ospfv3LinkStateAdvertisement::InterAreaPrefix,
151            )(input),
152            Ospfv3LinkStateType::InterAreaRouterLSA => map(
153                Ospfv3InterAreaRouterLSA::parse,
154                Ospfv3LinkStateAdvertisement::InterAreaRouter,
155            )(input),
156            Ospfv3LinkStateType::ASExternalLSA => map(
157                Ospfv3ASExternalLSA::parse,
158                Ospfv3LinkStateAdvertisement::ASExternal,
159            )(input),
160            Ospfv3LinkStateType::NSSALSA => map(
161                Ospfv3ASExternalLSA::parse,
162                Ospfv3LinkStateAdvertisement::NSSA,
163            )(input),
164            Ospfv3LinkStateType::LinkLSA => {
165                map(Ospfv3LinkLSA::parse, Ospfv3LinkStateAdvertisement::Link)(input)
166            }
167            Ospfv3LinkStateType::IntraAreaPrefixLSA => map(
168                Ospfv3IntraAreaPrefixLSA::parse,
169                Ospfv3LinkStateAdvertisement::IntraAreaPrefix,
170            )(input),
171            _ => Err(nom::Err::Error(make_error(input, ErrorKind::Tag))),
172        }
173    }
174}
175
176pub(crate) fn parse_ospf_vec_u32(
177    packet_length: u16,
178    offset: usize,
179) -> impl Fn(&[u8]) -> IResult<&[u8], Vec<u32>> {
180    move |input: &[u8]| parse_ospf_vec_u32_f(input, packet_length, offset)
181}
182
183fn parse_ospf_vec_u32_f(
184    input: &[u8],
185    packet_length: u16,
186    offset: usize,
187) -> IResult<&[u8], Vec<u32>> {
188    if packet_length as usize == offset {
189        return Ok((input, Vec::new()));
190    }
191    if (packet_length as usize) < offset || packet_length as usize - offset > input.len() {
192        return Err(nom::Err::Error(make_error(input, ErrorKind::LengthValue)));
193    }
194    let (data, rem) = input.split_at(packet_length as usize - offset);
195    let (_, routers) = many0(be_u32_complete)(data)?;
196    Ok((rem, routers))
197}
198
199pub(crate) fn parse_ospf_external_tos_routes(
200    packet_length: u16,
201) -> impl Fn(&[u8]) -> IResult<&[u8], Vec<OspfExternalTosRoute>> {
202    move |input: &[u8]| parse_ospf_external_tos_routes_f(input, packet_length)
203}
204
205fn parse_ospf_external_tos_routes_f(
206    input: &[u8],
207    packet_length: u16,
208) -> IResult<&[u8], Vec<OspfExternalTosRoute>> {
209    if packet_length == 36 {
210        return Ok((input, Vec::new()));
211    }
212    // 36 is the offset of the first external TOS Route
213    if packet_length < 36 || packet_length as usize - 36 > input.len() {
214        return Err(nom::Err::Error(make_error(input, ErrorKind::LengthValue)));
215    }
216    let (data_routes, rem) = input.split_at(packet_length as usize - 36);
217    let (_, routes) = many0(complete(OspfExternalTosRoute::parse))(data_routes)?;
218    Ok((rem, routes))
219}
220
221pub(crate) fn parse_ospf_tos_routes(
222    packet_length: u16,
223) -> impl Fn(&[u8]) -> IResult<&[u8], Vec<OspfTosRoute>> {
224    move |input: &[u8]| parse_ospf_tos_routes_f(input, packet_length)
225}
226
227fn parse_ospf_tos_routes_f(input: &[u8], packet_length: u16) -> IResult<&[u8], Vec<OspfTosRoute>> {
228    if packet_length == 28 {
229        return Ok((input, Vec::new()));
230    }
231    // 28 is the offset of the first TOS Route
232    if packet_length < 28 || packet_length as usize - 28 > input.len() {
233        return Err(nom::Err::Error(make_error(input, ErrorKind::LengthValue)));
234    }
235    let (data_routes, rem) = input.split_at(packet_length as usize - 28);
236    let (_, routes) = many0(complete(OspfTosRoute::parse))(data_routes)?;
237    Ok((rem, routes))
238}
239
240pub(crate) fn parse_ospfv3_router_links(
241    packet_length: u16,
242) -> impl Fn(&[u8]) -> IResult<&[u8], Vec<Ospfv3RouterLink>> {
243    move |input: &[u8]| parse_ospfv3_router_links_f(input, packet_length)
244}
245
246fn parse_ospfv3_router_links_f(
247    input: &[u8],
248    packet_length: u16,
249) -> IResult<&[u8], Vec<Ospfv3RouterLink>> {
250    if packet_length == 24 {
251        return Ok((input, Vec::new()));
252    }
253    if packet_length < 24 || packet_length as usize - 24 > input.len() {
254        return Err(nom::Err::Error(make_error(input, ErrorKind::LengthValue)));
255    }
256    let (data, rem) = input.split_at(packet_length as usize - 24);
257    let (_, v) = many0(complete(Ospfv3RouterLink::parse))(data)?;
258    Ok((rem, v))
259}
260
261pub(crate) fn take_vec_u8(length: u8) -> impl Fn(&[u8]) -> IResult<&[u8], Vec<u8>> {
262    move |input: &[u8]| map(take(length), |b: &[u8]| b.to_vec())(input)
263}