Skip to main content

ipfix_parser/parsers/
mod.rs

1//! IPFIX parser
2//!
3//! This module provides parsing functionality for IPFIX Messages.
4//! All data is in network byte order (big-endian) as per RFC 7011 Section 6.1.
5//!
6//! IPFIX Messages are length-delimited, so parsing works on byte slices and
7//! every read is bounds-checked: malformed input returns a [`ParseError`],
8//! never panics.
9
10mod decoder;
11mod error;
12mod value;
13
14pub use decoder::{parse_message, parse_messages, Decoder, DecoderConfig, Transport};
15pub use error::{ParseError, Result};
16
17/// Bounds-checked big-endian reader over a byte slice
18#[derive(Debug, Clone)]
19pub(crate) struct Cursor<'a> {
20    data: &'a [u8],
21    pos: usize,
22}
23
24impl<'a> Cursor<'a> {
25    pub(crate) fn new(data: &'a [u8]) -> Self {
26        Self { data, pos: 0 }
27    }
28
29    /// Number of unread octets
30    pub(crate) fn remaining(&self) -> usize {
31        self.data.len() - self.pos
32    }
33
34    pub(crate) fn is_empty(&self) -> bool {
35        self.remaining() == 0
36    }
37
38    /// Read `n` octets
39    pub(crate) fn read_bytes(&mut self, n: usize, context: &'static str) -> Result<&'a [u8]> {
40        if n > self.remaining() {
41            return Err(ParseError::Truncated {
42                context,
43                needed: n,
44                available: self.remaining(),
45            });
46        }
47        let bytes = &self.data[self.pos..self.pos + n];
48        self.pos += n;
49        Ok(bytes)
50    }
51
52    /// Read all remaining octets
53    pub(crate) fn read_rest(&mut self) -> &'a [u8] {
54        let bytes = &self.data[self.pos..];
55        self.pos = self.data.len();
56        bytes
57    }
58
59    pub(crate) fn read_u8(&mut self, context: &'static str) -> Result<u8> {
60        Ok(self.read_bytes(1, context)?[0])
61    }
62
63    pub(crate) fn read_u16(&mut self, context: &'static str) -> Result<u16> {
64        let b = self.read_bytes(2, context)?;
65        Ok(u16::from_be_bytes([b[0], b[1]]))
66    }
67
68    pub(crate) fn read_u32(&mut self, context: &'static str) -> Result<u32> {
69        let b = self.read_bytes(4, context)?;
70        Ok(u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
71    }
72
73    /// Read a variable-length Information Element length prefix
74    /// (RFC 7011 Section 7): one octet if < 255, otherwise 255 followed by a
75    /// two-octet length.
76    pub(crate) fn read_variable_length(&mut self, context: &'static str) -> Result<usize> {
77        let first = self.read_u8(context)?;
78        if first < 255 {
79            Ok(first as usize)
80        } else {
81            Ok(self.read_u16(context)? as usize)
82        }
83    }
84
85    /// Read a Field Specifier (RFC 7011 Section 3.2), also used by the
86    /// basicList header (RFC 6313 Section 4.5.1)
87    pub(crate) fn read_field_id(&mut self, context: &'static str) -> Result<(u16, bool)> {
88        let raw = self.read_u16(context)?;
89        Ok((raw & 0x7FFF, raw & 0x8000 != 0))
90    }
91}