1use 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
29pub(crate) const NETFLOW_TEMPLATE_SET_ID: u16 = 0;
31
32pub(crate) const NETFLOW_OPTIONS_TEMPLATE_SET_ID: u16 = 1;
34
35#[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 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 pub const fn increment_processed_count(&mut self) {
60 self.processed_count = self.processed_count.wrapping_add(1);
61 }
62
63 pub const fn processed_count(&self) -> u64 {
65 self.processed_count
66 }
67
68 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
76pub type TemplatesMap = HashMap<u16, DecodingTemplate>;
78
79#[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 pub const fn id(&self) -> u16 {
200 self.id
201 }
202
203 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}