Skip to main content

netgauze_parse_utils/
common.rs

1// Copyright (C) 2026-present The NetGauze Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12// implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::error::ParseError;
17use crate::reader::SliceReader;
18use crate::traits::{ParseFrom, ParseFromWithTwoInputs};
19use ipnet::{Ipv4Net, Ipv6Net};
20use serde::{Deserialize, Serialize};
21use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
22
23pub(crate) const IPV4_LEN: u8 = 4;
24pub(crate) const IPV6_LEN: u8 = 16;
25
26#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)]
27pub enum Ipv4PrefixParsingError {
28    #[error("failed to parse IPv4 prefix: {0}")]
29    Parse(#[from] ParseError),
30
31    #[error("invalid prefix length {prefix_len} at byte offset {offset} (must be 0–32)")]
32    InvalidIpv4PrefixLen { offset: usize, prefix_len: u8 },
33}
34
35impl<'a> ParseFromWithTwoInputs<'a, u8, usize> for Ipv4Net {
36    type Error = Ipv4PrefixParsingError;
37
38    fn parse(
39        cur: &mut SliceReader<'a>,
40        prefix_len: u8,
41        prefix_offset: usize,
42    ) -> Result<Self, Self::Error> {
43        // The prefix value must fall into the octet boundary, even if the prefix_len
44        // doesn't. For example,
45        // prefix_len=24 => prefix_size=24 while prefix_len=19 => prefix_size=24
46        let prefix_size = if prefix_len >= u8::MAX - 7 {
47            u8::MAX
48        } else {
49            prefix_len.div_ceil(8)
50        };
51        let prefix = cur.read_bytes(prefix_size.min(4) as usize)?;
52        // Fill the rest of bits with zeros if
53        let mut network = [0; 4];
54        prefix.iter().enumerate().for_each(|(i, v)| network[i] = *v);
55        let addr = Ipv4Addr::from(network);
56        match Ipv4Net::new(addr, prefix_len) {
57            Ok(net) => Ok(net),
58            Err(_) => Err(Ipv4PrefixParsingError::InvalidIpv4PrefixLen {
59                offset: prefix_offset,
60                prefix_len,
61            }),
62        }
63    }
64}
65
66impl<'a> ParseFrom<'a> for Ipv4Net {
67    type Error = Ipv4PrefixParsingError;
68
69    fn parse(cur: &mut SliceReader<'a>) -> Result<Self, Self::Error> {
70        let offset = cur.offset();
71        let prefix_len = cur.read_u8()?;
72        ParseFromWithTwoInputs::parse(cur, prefix_len, offset)
73    }
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)]
77pub enum Ipv6PrefixParsingError {
78    #[error("failed to parse IPv6 prefix: {0}")]
79    Parse(#[from] ParseError),
80
81    #[error("invalid prefix length {prefix_len} at byte offset {offset} (must be 0–128)")]
82    InvalidIpv6PrefixLen { offset: usize, prefix_len: u8 },
83}
84
85impl<'a> ParseFromWithTwoInputs<'a, u8, usize> for Ipv6Net {
86    type Error = Ipv6PrefixParsingError;
87
88    fn parse(
89        cur: &mut SliceReader<'a>,
90        prefix_len: u8,
91        prefix_offset: usize,
92    ) -> Result<Self, Self::Error> {
93        // The prefix value must fall into the octet boundary, even if the prefix_len
94        // doesn't. For example,
95        // prefix_len=24 => prefix_size=24 while prefix_len=19 => prefix_size=24
96        let prefix_size = if prefix_len >= u8::MAX - 7 {
97            u8::MAX
98        } else {
99            prefix_len.div_ceil(8)
100        };
101        let prefix = cur.read_bytes(prefix_size.min(16) as usize)?;
102        // Fill the rest of bits with zeros if
103        let mut network = [0; 16];
104        prefix.iter().enumerate().for_each(|(i, v)| network[i] = *v);
105        let addr = Ipv6Addr::from(network);
106
107        match Ipv6Net::new(addr, prefix_len) {
108            Ok(net) => Ok(net),
109            Err(_) => Err(Ipv6PrefixParsingError::InvalidIpv6PrefixLen {
110                offset: prefix_offset,
111                prefix_len,
112            }),
113        }
114    }
115}
116
117impl<'a> ParseFrom<'a> for Ipv6Net {
118    type Error = Ipv6PrefixParsingError;
119
120    fn parse(cur: &mut SliceReader<'a>) -> Result<Self, Self::Error> {
121        let offset = cur.offset();
122        let prefix_len = cur.read_u8()?;
123        ParseFromWithTwoInputs::parse(cur, prefix_len, offset)
124    }
125}
126
127#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)]
128pub enum IpAddrParsingError {
129    #[error("IP address parsing error: {0}")]
130    Parse(#[from] ParseError),
131
132    #[error("Invalid IP address length `{length}` at offset {offset}")]
133    InvalidIpAddressLength { offset: usize, length: u8 },
134}
135
136impl<'a> ParseFrom<'a> for IpAddr {
137    type Error = IpAddrParsingError;
138    fn parse(cur: &mut SliceReader<'a>) -> Result<Self, Self::Error> {
139        let offset = cur.offset();
140        let ip_len = cur.read_u8()?;
141        match ip_len {
142            IPV4_LEN => {
143                let addr = cur.read_u32_be()?;
144                Ok(IpAddr::V4(Ipv4Addr::from(addr)))
145            }
146            IPV6_LEN => {
147                let addr = cur.read_u128_be()?;
148                Ok(IpAddr::V6(Ipv6Addr::from(addr)))
149            }
150            _ => Err(IpAddrParsingError::InvalidIpAddressLength {
151                offset,
152                length: ip_len,
153            }),
154        }
155    }
156}
157
158#[cfg(test)]
159mod tests {
160    use super::*;
161
162    #[test]
163    fn ipv4_slash24_octet_aligned() {
164        let data = [192, 168, 1];
165        let expected = Ok(Ipv4Net::new_assert(Ipv4Addr::new(192, 168, 1, 0), 24));
166
167        let mut r = SliceReader::new(&data);
168        let parsed = <Ipv4Net as ParseFromWithTwoInputs<'_, u8, usize>>::parse(&mut r, 24, 0);
169
170        assert_eq!(parsed, expected);
171    }
172
173    #[test]
174    fn ipv4_slash0_reads_no_bytes() {
175        let data: [u8; 0] = [];
176        let expected = Ok(Ipv4Net::new_assert(Ipv4Addr::UNSPECIFIED, 0));
177
178        let mut r = SliceReader::new(&data);
179        let parsed = <Ipv4Net as ParseFromWithTwoInputs<'_, u8, usize>>::parse(&mut r, 0, 0);
180
181        assert_eq!(parsed, expected);
182    }
183
184    #[test]
185    fn ipv4_slash32_full_address() {
186        let data = [10, 20, 30, 40];
187        let expected = Ok(Ipv4Net::new_assert(Ipv4Addr::new(10, 20, 30, 40), 32));
188
189        let mut r = SliceReader::new(&data);
190        let parsed = <Ipv4Net as ParseFromWithTwoInputs<'_, u8, usize>>::parse(&mut r, 32, 0);
191
192        assert_eq!(parsed, expected);
193    }
194
195    #[test]
196    fn ipv4_non_octet_boundary_slash19_consumes_three_bytes() {
197        // /19 => 19.div_ceil(8) = 3 bytes; the 4th byte must stay unread.
198        let data = [10, 0, 32, 0xFF];
199        let expected = Ok(Ipv4Net::new_assert(Ipv4Addr::new(10, 0, 32, 0), 19));
200
201        let mut r = SliceReader::new(&data);
202        let parsed = <Ipv4Net as ParseFromWithTwoInputs<'_, u8, usize>>::parse(&mut r, 19, 0);
203
204        assert_eq!(parsed, expected);
205        assert_eq!(r.as_slice(), &[0xFF]);
206    }
207
208    #[test]
209    fn ipv4_prefix_len_out_of_range() {
210        // Needs >= 4 bytes so the read succeeds and Ipv4Net::new is what rejects.
211        let data = [1, 2, 3, 4, 5];
212        let expected = Err(Ipv4PrefixParsingError::InvalidIpv4PrefixLen {
213            offset: 7,
214            prefix_len: 33,
215        });
216
217        let mut r = SliceReader::new(&data);
218        let parsed = <Ipv4Net as ParseFromWithTwoInputs<'_, u8, usize>>::parse(&mut r, 33, 7);
219
220        assert_eq!(parsed, expected);
221    }
222
223    #[test]
224    fn ipv4_truncated_body() {
225        let data = [192, 168]; // /24 needs 3 bytes, only 2 present
226        let expected = Err(Ipv4PrefixParsingError::Parse(ParseError::eof(0, 3, 2)));
227
228        let mut r = SliceReader::new(&data);
229        let parsed = <Ipv4Net as ParseFromWithTwoInputs<'_, u8, usize>>::parse(&mut r, 24, 0);
230
231        eprintln!("E: {}", expected.clone().unwrap_err());
232        assert_eq!(parsed, expected);
233    }
234
235    #[test]
236    fn ipv4_parsefrom_reads_len_then_body() {
237        let data = [24, 192, 168, 1];
238        let expected = Ok(Ipv4Net::new_assert(Ipv4Addr::new(192, 168, 1, 0), 24));
239
240        let mut r = SliceReader::new(&data);
241        let parsed = <Ipv4Net as ParseFrom<'_>>::parse(&mut r);
242
243        assert_eq!(parsed, expected);
244        assert_eq!(r.offset(), 4); // 1 length byte + 3 body bytes
245    }
246
247    #[test]
248    fn ipv4_parsefrom_consumes_only_its_own_entry() {
249        // NLRI-loop semantics: the next entry stays intact for the caller.
250        let data = [16, 10, 1, /* next entry: */ 8, 172];
251        let expected = Ok(Ipv4Net::new_assert(Ipv4Addr::new(10, 1, 0, 0), 16));
252
253        let mut r = SliceReader::new(&data);
254        let parsed = <Ipv4Net as ParseFrom<'_>>::parse(&mut r);
255
256        assert_eq!(parsed, expected);
257        assert_eq!(r.as_slice(), &[8, 172]);
258    }
259
260    #[test]
261    fn ipv6_slash64_consumes_eight_bytes() {
262        let data = [0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0xFF];
263        let expected = Ok(Ipv6Net::new_assert(
264            Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0),
265            64,
266        ));
267
268        let mut r = SliceReader::new(&data);
269        let parsed = <Ipv6Net as ParseFromWithTwoInputs<'_, u8, usize>>::parse(&mut r, 64, 0);
270
271        assert_eq!(parsed, expected);
272        assert_eq!(r.as_slice(), &[0xFF]);
273    }
274
275    #[test]
276    fn ipv6_slash128_full_address() {
277        let data = [0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
278        let expected = Ok(Ipv6Net::new_assert(
279            Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 1),
280            128,
281        ));
282
283        let mut r = SliceReader::new(&data);
284        let parsed = <Ipv6Net as ParseFromWithTwoInputs<'_, u8, usize>>::parse(&mut r, 128, 0);
285
286        assert_eq!(parsed, expected);
287    }
288
289    #[test]
290    fn ipv6_slash0_reads_no_bytes() {
291        let data: [u8; 0] = [];
292        let expected = Ok(Ipv6Net::new_assert(Ipv6Addr::UNSPECIFIED, 0));
293
294        let mut r = SliceReader::new(&data);
295        let parsed = <Ipv6Net as ParseFromWithTwoInputs<'_, u8, usize>>::parse(&mut r, 0, 0);
296
297        assert_eq!(parsed, expected);
298    }
299
300    #[test]
301    fn ipv6_prefix_len_out_of_range() {
302        let data = [0u8; 16];
303        let expected = Err(Ipv6PrefixParsingError::InvalidIpv6PrefixLen {
304            offset: 3,
305            prefix_len: 129,
306        });
307
308        let mut r = SliceReader::new(&data);
309        let parsed = <Ipv6Net as ParseFromWithTwoInputs<'_, u8, usize>>::parse(&mut r, 129, 3);
310
311        assert_eq!(parsed, expected);
312    }
313
314    #[test]
315    fn ipv6_parsefrom_reads_len_then_body() {
316        let data = [64, 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0];
317        let expected = Ok(Ipv6Net::new_assert(
318            Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0),
319            64,
320        ));
321
322        let mut r = SliceReader::new(&data);
323        let parsed = <Ipv6Net as ParseFrom<'_>>::parse(&mut r);
324
325        assert_eq!(parsed, expected);
326        assert_eq!(r.offset(), 9); // 1 + 8
327    }
328
329    #[test]
330    fn ipaddr_v4() {
331        let data = [4, 10, 0, 0, 1];
332        let expected = Ok(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)));
333
334        let mut r = SliceReader::new(&data);
335        let parsed = <IpAddr as ParseFrom<'_>>::parse(&mut r);
336
337        assert_eq!(parsed, expected);
338        assert_eq!(r.offset(), 5);
339    }
340
341    #[test]
342    fn ipaddr_v6() {
343        let data = [
344            16, 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
345        ];
346        let expected = Ok(IpAddr::V6(Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 1)));
347
348        let mut r = SliceReader::new(&data);
349        let parsed = <IpAddr as ParseFrom<'_>>::parse(&mut r);
350
351        assert_eq!(parsed, expected);
352        assert_eq!(r.offset(), 17);
353    }
354
355    #[test]
356    fn ipaddr_invalid_length_tag() {
357        let data = [5, 1, 2, 3, 4, 5]; // 5 is neither 4 nor 16
358        let expected = Err(IpAddrParsingError::InvalidIpAddressLength {
359            offset: 0,
360            length: 5,
361        });
362
363        let mut r = SliceReader::new(&data);
364        let parsed = <IpAddr as ParseFrom<'_>>::parse(&mut r);
365
366        assert_eq!(parsed, expected);
367    }
368
369    #[test]
370    fn ipaddr_v4_truncated_body() {
371        let data = [4, 10, 0]; // claims v4 but only 2 address bytes follow
372        let expected = Err(IpAddrParsingError::Parse(ParseError::eof(1, 4, 2)));
373
374        let mut r = SliceReader::new(&data);
375        let parsed = <IpAddr as ParseFrom<'_>>::parse(&mut r);
376
377        assert_eq!(parsed, expected);
378    }
379}