netgauze_flow_pkt/
netflow.rs

1// Copyright (C) 2023-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::{
17    ie::{
18        Field, InformationElementDataType, InformationElementSemantics, InformationElementTemplate,
19        InformationElementUnits,
20    },
21    DataSetId, FieldSpecifier,
22};
23use chrono::{DateTime, Utc};
24use serde::{Deserialize, Serialize};
25use std::{collections::HashMap, ops::Range};
26
27pub const NETFLOW_V9_VERSION: u16 = 9;
28
29/// A value of 0 is reserved for Template Sets
30pub(crate) const NETFLOW_TEMPLATE_SET_ID: u16 = 0;
31
32/// A value of 3 is reserved for Options Template Sets
33pub(crate) const NETFLOW_OPTIONS_TEMPLATE_SET_ID: u16 = 1;
34
35/// Simpler template that is used to decode data records
36#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
37#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
38pub struct DecodingTemplate {
39    pub scope_fields_specs: Box<[ScopeFieldSpecifier]>,
40    pub fields_specs: Box<[FieldSpecifier]>,
41
42    /// Number of Data Records processed using this template
43    pub processed_count: u64,
44}
45
46impl DecodingTemplate {
47    pub const fn new(
48        scope_fields_specs: Box<[ScopeFieldSpecifier]>,
49        fields_specs: Box<[FieldSpecifier]>,
50    ) -> Self {
51        Self {
52            scope_fields_specs,
53            fields_specs,
54            processed_count: 0,
55        }
56    }
57
58    /// Increment Data Record count by one
59    pub const fn increment_processed_count(&mut self) {
60        self.processed_count = self.processed_count.wrapping_add(1);
61    }
62
63    /// Get the current processed Data Record count
64    pub const fn processed_count(&self) -> u64 {
65        self.processed_count
66    }
67
68    /// Get the current processed Data Record count and reset the value to zero
69    pub const fn reset_processed_count(&mut self) -> u64 {
70        let prev = self.processed_count;
71        self.processed_count = 0;
72        prev
73    }
74}
75
76/// Cache to store templates needed for decoding data packets
77pub type TemplatesMap = HashMap<u16, DecodingTemplate>;
78
79///
80/// ```text
81/// +--------+-------------------------------------------+
82/// |        | +----------+ +---------+ +----------+     |
83/// | Packet | | Template | | Data    | | Options  |     |
84/// | Header | | FlowSet  | | FlowSet | | Template | ... |
85/// |        | |          | |         | | FlowSet  |     |
86/// |        | +----------+ +---------+ +----------+     |
87/// +--------+-------------------------------------------+
88/// ```
89/// ```text
90/// 0                   1                   2                   3
91/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
92/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
93/// |       Version Number          |            Count              |
94/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95/// |                           sysUpTime                           |
96/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97/// |                           UNIX Secs                           |
98/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99/// |                       Sequence Number                         |
100/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101/// |                        Source ID                              |
102/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
104#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
105pub struct NetFlowV9Packet {
106    version: u16,
107    sys_up_time: u32,
108    #[cfg_attr(feature = "fuzz", arbitrary(with = crate::arbitrary_datetime))]
109    unix_time: DateTime<Utc>,
110    sequence_number: u32,
111    source_id: u32,
112    sets: Box<[Set]>,
113}
114
115impl NetFlowV9Packet {
116    pub fn new(
117        sys_up_time: u32,
118        unix_time: DateTime<Utc>,
119        sequence_number: u32,
120        source_id: u32,
121        sets: Box<[Set]>,
122    ) -> Self {
123        Self {
124            version: NETFLOW_V9_VERSION,
125            sys_up_time,
126            unix_time,
127            sequence_number,
128            source_id,
129            sets,
130        }
131    }
132
133    pub const fn version(&self) -> u16 {
134        self.version
135    }
136
137    pub const fn sys_up_time(&self) -> u32 {
138        self.sys_up_time
139    }
140
141    pub const fn unix_time(&self) -> DateTime<Utc> {
142        self.unix_time
143    }
144
145    pub const fn sequence_number(&self) -> u32 {
146        self.sequence_number
147    }
148
149    pub const fn source_id(&self) -> u32 {
150        self.source_id
151    }
152
153    pub const fn sets(&self) -> &[Set] {
154        &self.sets
155    }
156}
157
158#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
159#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
160pub enum Set {
161    Template(Box<[TemplateRecord]>),
162    OptionsTemplate(Box<[OptionsTemplateRecord]>),
163    Data {
164        id: DataSetId,
165        records: Box<[DataRecord]>,
166    },
167}
168
169impl Set {
170    pub const fn id(&self) -> u16 {
171        match self {
172            Self::Template(_) => NETFLOW_TEMPLATE_SET_ID,
173            Self::OptionsTemplate(_) => NETFLOW_OPTIONS_TEMPLATE_SET_ID,
174            Self::Data { id, records: _ } => id.0,
175        }
176    }
177}
178
179#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
180#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
181pub struct TemplateRecord {
182    id: u16,
183    field_specifiers: Box<[FieldSpecifier]>,
184}
185
186impl TemplateRecord {
187    pub const fn new(id: u16, field_specifiers: Box<[FieldSpecifier]>) -> Self {
188        Self {
189            id,
190            field_specifiers,
191        }
192    }
193
194    /// Each Template Record is given a unique Template ID in the range 256 to
195    /// 65535.
196    ///
197    /// TODO (AH): do we need to check for template IDs < 256,
198    /// see [RFC 7011](https://www.rfc-editor.org/rfc/rfc7011#section-3.4.1)
199    pub const fn id(&self) -> u16 {
200        self.id
201    }
202
203    /// List of [`FieldSpecifier`] defined in the template.
204    pub const fn field_specifiers(&self) -> &[FieldSpecifier] {
205        &self.field_specifiers
206    }
207}
208
209#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
210#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
211pub struct OptionsTemplateRecord {
212    id: u16,
213    scope_field_specifiers: Box<[ScopeFieldSpecifier]>,
214    field_specifiers: Box<[FieldSpecifier]>,
215}
216
217impl OptionsTemplateRecord {
218    pub const fn new(
219        id: u16,
220        scope_field_specifiers: Box<[ScopeFieldSpecifier]>,
221        field_specifiers: Box<[FieldSpecifier]>,
222    ) -> Self {
223        Self {
224            id,
225            scope_field_specifiers,
226            field_specifiers,
227        }
228    }
229
230    pub const fn id(&self) -> u16 {
231        self.id
232    }
233
234    pub const fn scope_field_specifiers(&self) -> &[ScopeFieldSpecifier] {
235        &self.scope_field_specifiers
236    }
237
238    pub const fn field_specifiers(&self) -> &[FieldSpecifier] {
239        &self.field_specifiers
240    }
241}
242
243#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
244#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
245pub struct DataRecord {
246    scope_fields: Box<[ScopeField]>,
247    fields: Box<[Field]>,
248}
249
250impl DataRecord {
251    pub const fn new(scope_fields: Box<[ScopeField]>, fields: Box<[Field]>) -> Self {
252        Self {
253            scope_fields,
254            fields,
255        }
256    }
257
258    pub const fn scope_fields(&self) -> &[ScopeField] {
259        &self.scope_fields
260    }
261
262    pub const fn fields(&self) -> &[Field] {
263        &self.fields
264    }
265}
266
267#[derive(Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
268#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
269pub enum ScopeField {
270    Unknown { pen: u32, id: u16, value: Box<[u8]> },
271    System(System),
272    Interface(Interface),
273    LineCard(LineCard),
274    Cache(Cache),
275    Template(Template),
276}
277
278impl ScopeField {
279    pub const fn ie(&self) -> ScopeIE {
280        match self {
281            Self::Unknown { pen, id, value: _ } => ScopeIE::Unknown { pen: *pen, id: *id },
282            Self::System(_) => ScopeIE::System,
283            Self::Interface(_) => ScopeIE::Interface,
284            Self::LineCard(_) => ScopeIE::LineCard,
285            Self::Cache(_) => ScopeIE::Cache,
286            Self::Template(_) => ScopeIE::Template,
287        }
288    }
289}
290
291#[derive(Default, Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
292#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
293pub struct ScopeFields {
294    #[serde(skip_serializing_if = "Option::is_none")]
295    pub system: Option<Vec<System>>,
296    #[serde(skip_serializing_if = "Option::is_none")]
297    pub interface: Option<Vec<Interface>>,
298    #[serde(skip_serializing_if = "Option::is_none")]
299    pub line_card: Option<Vec<LineCard>>,
300    #[serde(skip_serializing_if = "Option::is_none")]
301    pub cache: Option<Vec<Cache>>,
302    #[serde(skip_serializing_if = "Option::is_none")]
303    pub template: Option<Vec<Template>>,
304}
305
306impl From<Box<[ScopeField]>> for ScopeFields {
307    fn from(fields: Box<[ScopeField]>) -> Self {
308        let mut out = ScopeFields::default();
309        for field in fields {
310            match field {
311                ScopeField::Unknown { .. } => {}
312                ScopeField::System(system) => {
313                    if out.system.is_none() {
314                        out.system = Some(Vec::with_capacity(1));
315                    }
316                    if let Some(inner) = out.system.as_mut() {
317                        inner.push(system)
318                    }
319                }
320                ScopeField::Interface(interface) => {
321                    if out.interface.is_none() {
322                        out.interface = Some(Vec::with_capacity(1));
323                    }
324                    if let Some(inner) = out.interface.as_mut() {
325                        inner.push(interface)
326                    }
327                }
328                ScopeField::LineCard(line_card) => {
329                    if out.line_card.is_none() {
330                        out.line_card = Some(Vec::with_capacity(1));
331                    }
332                    if let Some(inner) = out.line_card.as_mut() {
333                        inner.push(line_card)
334                    }
335                }
336                ScopeField::Cache(cache) => {
337                    if out.cache.is_none() {
338                        out.cache = Some(Vec::with_capacity(1));
339                    }
340                    if let Some(inner) = out.cache.as_mut() {
341                        inner.push(cache)
342                    }
343                }
344                ScopeField::Template(template) => {
345                    if out.template.is_none() {
346                        out.template = Some(Vec::with_capacity(1));
347                    }
348                    if let Some(inner) = out.template.as_mut() {
349                        inner.push(template)
350                    }
351                }
352            }
353        }
354        out
355    }
356}
357
358#[derive(Eq, Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
359#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
360pub struct System(pub u32);
361
362#[derive(Eq, Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
363#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
364pub struct Interface(pub u32);
365
366#[derive(Eq, Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
367#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
368pub struct LineCard(pub u32);
369
370#[derive(Eq, Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
371#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
372pub struct Cache(pub Box<[u8]>);
373
374#[derive(Eq, Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
375#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
376pub struct Template(pub Box<[u8]>);
377
378#[derive(Copy, Eq, Clone, PartialEq, Hash, Debug, serde::Serialize, serde::Deserialize)]
379#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
380pub enum ScopeIE {
381    Unknown { pen: u32, id: u16 },
382    System,
383    Interface,
384    LineCard,
385    Cache,
386    Template,
387}
388
389impl From<(u32, u16)> for ScopeIE {
390    fn from(value: (u32, u16)) -> Self {
391        let (pen, id) = value;
392        match value {
393            (0, 1) => ScopeIE::System,
394            (0, 2) => ScopeIE::Interface,
395            (0, 3) => ScopeIE::LineCard,
396            (0, 4) => ScopeIE::Cache,
397            (0, 5) => ScopeIE::Template,
398            _ => ScopeIE::Unknown { pen, id },
399        }
400    }
401}
402
403impl InformationElementTemplate for ScopeIE {
404    fn semantics(&self) -> Option<InformationElementSemantics> {
405        match self {
406            Self::System => Some(InformationElementSemantics::identifier),
407            Self::Interface => Some(InformationElementSemantics::identifier),
408            Self::LineCard => Some(InformationElementSemantics::identifier),
409            _ => None,
410        }
411    }
412
413    fn data_type(&self) -> InformationElementDataType {
414        match self {
415            Self::System => InformationElementDataType::octetArray,
416            Self::Interface => InformationElementDataType::unsigned32,
417            Self::LineCard => InformationElementDataType::unsigned32,
418            Self::Cache => InformationElementDataType::octetArray,
419            Self::Template => InformationElementDataType::octetArray,
420            Self::Unknown { .. } => InformationElementDataType::octetArray,
421        }
422    }
423
424    fn value_range(&self) -> Option<Range<u64>> {
425        None
426    }
427
428    fn units(&self) -> Option<InformationElementUnits> {
429        None
430    }
431
432    fn id(&self) -> u16 {
433        match self {
434            Self::Unknown { id, .. } => *id,
435            Self::System => 1,
436            Self::Interface => 2,
437            Self::LineCard => 3,
438            Self::Cache => 4,
439            Self::Template => 5,
440        }
441    }
442
443    fn pen(&self) -> u32 {
444        match self {
445            Self::Unknown { pen, .. } => *pen,
446            _ => 0,
447        }
448    }
449}
450
451#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
452#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
453pub struct ScopeFieldSpecifier {
454    element_id: ScopeIE,
455    length: u16,
456}
457
458impl ScopeFieldSpecifier {
459    pub const fn new(element_id: ScopeIE, length: u16) -> Self {
460        Self { element_id, length }
461    }
462
463    pub const fn element_id(&self) -> ScopeIE {
464        self.element_id
465    }
466
467    pub const fn length(&self) -> u16 {
468        self.length
469    }
470}
471
472#[cfg(test)]
473mod tests {
474    use super::*;
475
476    #[test]
477    fn test_scope_fields_from() {
478        let fields: Box<[ScopeField]> = Box::new([
479            ScopeField::System(System(1)),
480            ScopeField::Interface(Interface(2)),
481            ScopeField::LineCard(LineCard(3)),
482            ScopeField::Cache(Cache(Box::new([1, 2, 3]))),
483            ScopeField::Template(Template(Box::new([1, 2, 3]))),
484        ]);
485        let scope_fields = ScopeFields::from(fields);
486        assert_eq!(scope_fields.system.unwrap().len(), 1);
487        assert_eq!(scope_fields.interface.unwrap().len(), 1);
488        assert_eq!(scope_fields.line_card.unwrap().len(), 1);
489        assert_eq!(scope_fields.cache.unwrap().len(), 1);
490        assert_eq!(scope_fields.template.unwrap().len(), 1);
491    }
492
493    #[test]
494    fn test_scope_ie_from() {
495        let ie = ScopeIE::from((0, 1));
496        assert_eq!(ie, ScopeIE::System);
497        let ie = ScopeIE::from((0, 2));
498        assert_eq!(ie, ScopeIE::Interface);
499        let ie = ScopeIE::from((0, 3));
500        assert_eq!(ie, ScopeIE::LineCard);
501        let ie = ScopeIE::from((0, 4));
502        assert_eq!(ie, ScopeIE::Cache);
503        let ie = ScopeIE::from((0, 5));
504        assert_eq!(ie, ScopeIE::Template);
505        let ie = ScopeIE::from((1, 1));
506        assert_eq!(ie, ScopeIE::Unknown { pen: 1, id: 1 });
507    }
508
509    #[test]
510    fn test_scope_ie_id() {
511        let ie = ScopeIE::System;
512        assert_eq!(ie.id(), 1);
513        let ie = ScopeIE::Interface;
514        assert_eq!(ie.id(), 2);
515        let ie = ScopeIE::LineCard;
516        assert_eq!(ie.id(), 3);
517        let ie = ScopeIE::Cache;
518        assert_eq!(ie.id(), 4);
519        let ie = ScopeIE::Template;
520        assert_eq!(ie.id(), 5);
521        let ie = ScopeIE::Unknown { pen: 1, id: 1 };
522        assert_eq!(ie.id(), 1);
523    }
524
525    #[test]
526    fn test_scope_ie_pen() {
527        let ie = ScopeIE::System;
528        assert_eq!(ie.pen(), 0);
529        let ie = ScopeIE::Interface;
530        assert_eq!(ie.pen(), 0);
531        let ie = ScopeIE::LineCard;
532        assert_eq!(ie.pen(), 0);
533        let ie = ScopeIE::Cache;
534        assert_eq!(ie.pen(), 0);
535        let ie = ScopeIE::Template;
536        assert_eq!(ie.pen(), 0);
537        let ie = ScopeIE::Unknown { pen: 1, id: 1 };
538        assert_eq!(ie.pen(), 1);
539    }
540
541    #[test]
542    fn test_scope_ie_data_type() {
543        let ie = ScopeIE::System;
544        assert_eq!(ie.data_type(), InformationElementDataType::octetArray);
545        let ie = ScopeIE::Interface;
546        assert_eq!(ie.data_type(), InformationElementDataType::unsigned32);
547        let ie = ScopeIE::LineCard;
548        assert_eq!(ie.data_type(), InformationElementDataType::unsigned32);
549        let ie = ScopeIE::Cache;
550        assert_eq!(ie.data_type(), InformationElementDataType::octetArray);
551        let ie = ScopeIE::Template;
552        assert_eq!(ie.data_type(), InformationElementDataType::octetArray);
553        let ie = ScopeIE::Unknown { pen: 1, id: 1 };
554        assert_eq!(ie.data_type(), InformationElementDataType::octetArray);
555    }
556
557    #[test]
558    fn test_scope_ie_semantics() {
559        let ie = ScopeIE::System;
560        assert_eq!(
561            ie.semantics(),
562            Some(InformationElementSemantics::identifier)
563        );
564        let ie = ScopeIE::Interface;
565        assert_eq!(
566            ie.semantics(),
567            Some(InformationElementSemantics::identifier)
568        );
569        let ie = ScopeIE::LineCard;
570        assert_eq!(
571            ie.semantics(),
572            Some(InformationElementSemantics::identifier)
573        );
574        let ie = ScopeIE::Cache;
575        assert_eq!(ie.semantics(), None);
576        let ie = ScopeIE::Template;
577        assert_eq!(ie.semantics(), None);
578        let ie = ScopeIE::Unknown { pen: 1, id: 1 };
579        assert_eq!(ie.semantics(), None);
580    }
581
582    #[test]
583    fn test_scope_ie_value_range() {
584        let ie = ScopeIE::System;
585        assert_eq!(ie.value_range(), None);
586        let ie = ScopeIE::Interface;
587        assert_eq!(ie.value_range(), None);
588        let ie = ScopeIE::LineCard;
589        assert_eq!(ie.value_range(), None);
590        let ie = ScopeIE::Cache;
591        assert_eq!(ie.value_range(), None);
592        let ie = ScopeIE::Template;
593        assert_eq!(ie.value_range(), None);
594        let ie = ScopeIE::Unknown { pen: 1, id: 1 };
595        assert_eq!(ie.value_range(), None);
596    }
597
598    #[test]
599    fn test_scope_ie_units() {
600        let ie = ScopeIE::System;
601        assert_eq!(ie.units(), None);
602        let ie = ScopeIE::Interface;
603        assert_eq!(ie.units(), None);
604        let ie = ScopeIE::LineCard;
605        assert_eq!(ie.units(), None);
606        let ie = ScopeIE::Cache;
607        assert_eq!(ie.units(), None);
608        let ie = ScopeIE::Template;
609        assert_eq!(ie.units(), None);
610        let ie = ScopeIE::Unknown { pen: 1, id: 1 };
611        assert_eq!(ie.units(), None);
612    }
613
614    #[test]
615    fn test_scope_field_specifier_new() {
616        let ie = ScopeIE::System;
617        let length = 1;
618        let field_specifier = ScopeFieldSpecifier::new(ie, length);
619        assert_eq!(field_specifier.element_id(), ie);
620        assert_eq!(field_specifier.length(), length);
621    }
622}