1#[cfg(feature = "codec")]
45pub mod codec;
46pub mod ie;
47pub mod ipfix;
48pub mod netflow;
49#[cfg(feature = "serde")]
50pub mod wire;
51
52use crate::ie::*;
53use serde::{Deserialize, Serialize};
54use std::ops::Deref;
55use strum_macros::EnumDiscriminants;
56
57#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, EnumDiscriminants)]
58#[strum_discriminants(derive(Hash), name(FlowInfoType))]
59pub enum FlowInfo {
60 NetFlowV9(netflow::NetFlowV9Packet),
61 IPFIX(ipfix::IpfixPacket),
62}
63
64impl FlowInfo {
65 pub const fn export_time(&self) -> chrono::DateTime<chrono::Utc> {
66 match self {
67 Self::IPFIX(packet) => packet.export_time(),
68 Self::NetFlowV9(packet) => packet.unix_time(),
69 }
70 }
71
72 pub const fn sequence_number(&self) -> u32 {
73 match self {
74 Self::IPFIX(packet) => packet.sequence_number(),
75 Self::NetFlowV9(packet) => packet.sequence_number(),
76 }
77 }
78
79 pub const fn observation_domain_id(&self) -> u32 {
80 match self {
81 Self::IPFIX(packet) => packet.observation_domain_id(),
82 Self::NetFlowV9(packet) => packet.source_id(),
83 }
84 }
85
86 pub fn data_record_fields(&self) -> impl Iterator<Item = (DataSetId, &[Field])> {
89 match self {
90 Self::IPFIX(pkt) => either::Either::Left(
91 pkt.sets()
92 .iter()
93 .flat_map(|set| {
94 if let ipfix::Set::Data { id, records } = set {
95 Some(records.iter().map(move |record| (*id, record.fields())))
96 } else {
97 None
98 }
99 })
100 .flatten(),
101 ),
102 Self::NetFlowV9(pkt) => either::Either::Right(
103 pkt.sets()
104 .iter()
105 .flat_map(|set| {
106 if let netflow::Set::Data { id, records } = set {
107 Some(records.iter().map(move |record| (*id, record.fields())))
108 } else {
109 None
110 }
111 })
112 .flatten(),
113 ),
114 }
115 }
116}
117
118#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize, strum_macros::Display)]
120pub enum FieldSpecifierError {
121 #[strum(to_string = "Invalid length specified {0} for IE: {1:?}")]
123 InvalidLength(u16, IE),
124}
125
126impl std::error::Error for FieldSpecifierError {}
127
128#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
140#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
141pub struct FieldSpecifier {
142 element_id: IE,
143 length: u16,
144}
145
146impl FieldSpecifier {
147 pub fn new(element_id: IE, length: u16) -> Result<Self, FieldSpecifierError> {
148 if let Some(range) = element_id.length_range()
149 && !range.contains(&length)
150 {
151 return Err(FieldSpecifierError::InvalidLength(length, element_id));
152 };
153 Ok(Self { element_id, length })
154 }
155
156 pub const fn element_id(&self) -> IE {
157 self.element_id
158 }
159
160 pub const fn length(&self) -> u16 {
161 self.length
162 }
163}
164
165#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, strum_macros::Display)]
166pub enum DataSetIdError {
167 #[strum(serialize = "Invalid data set id specified: {0}")]
168 InvalidId(u16),
169}
170
171impl std::error::Error for DataSetIdError {}
172
173#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
174#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
175pub struct DataSetId(u16);
176
177pub(crate) const DATA_SET_MIN_ID: u16 = 256;
179
180impl DataSetId {
181 pub const fn new(id: u16) -> Result<Self, DataSetIdError> {
182 if id < DATA_SET_MIN_ID {
183 Err(DataSetIdError::InvalidId(id))
184 } else {
185 Ok(Self(id))
186 }
187 }
188
189 #[inline]
190 pub const fn id(&self) -> u16 {
191 self.0
192 }
193}
194
195impl Deref for DataSetId {
196 type Target = u16;
197
198 fn deref(&self) -> &Self::Target {
199 &self.0
200 }
201}
202
203#[cfg(feature = "fuzz")]
204fn arbitrary_datetime(
205 u: &mut arbitrary::Unstructured<'_>,
206) -> arbitrary::Result<chrono::DateTime<chrono::Utc>> {
207 use chrono::TimeZone;
208 loop {
209 let seconds = u.int_in_range(0..=i64::MAX)?;
210 if let chrono::LocalResult::Single(tt) = chrono::Utc.timestamp_opt(seconds, 0) {
211 return Ok(tt);
212 }
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219 use crate::ie::protocolIdentifier;
220 use crate::ipfix::IpfixPacket;
221 use crate::netflow::NetFlowV9Packet;
222 use chrono::{TimeZone, Utc};
223 use netgauze_iana::tcp::TCPHeaderFlags;
224
225 #[test]
226 fn test_flow_info_api() {
227 let export_time = Utc.with_ymd_and_hms(2024, 6, 20, 14, 0, 0).unwrap();
228 let sequence_number = 2;
229 let observation_domain = 100;
230 let ipfix_data = IpfixPacket::new(
231 export_time,
232 sequence_number,
233 observation_domain,
234 Box::new([ipfix::Set::Data {
235 id: DataSetId::new(400).unwrap(),
236 records: Box::new([]),
237 }]),
238 );
239 let netflow_data = NetFlowV9Packet::new(
240 45646,
241 export_time,
242 sequence_number,
243 observation_domain,
244 Box::new([netflow::Set::Data {
245 id: DataSetId::new(400).unwrap(),
246 records: Box::new([]),
247 }]),
248 );
249
250 let flow_ipfix = FlowInfo::IPFIX(ipfix_data.clone());
251 let flow_netflow = FlowInfo::NetFlowV9(netflow_data.clone());
252
253 assert_eq!(ipfix_data.export_time(), export_time);
254 assert_eq!(ipfix_data.sequence_number(), sequence_number);
255 assert_eq!(ipfix_data.observation_domain_id(), observation_domain);
256 assert_eq!(netflow_data.unix_time(), export_time);
257 assert_eq!(netflow_data.sequence_number(), sequence_number);
258 assert_eq!(netflow_data.source_id(), observation_domain);
259 assert_eq!(flow_ipfix.export_time(), export_time);
260 assert_eq!(flow_ipfix.sequence_number(), sequence_number);
261 assert_eq!(flow_ipfix.observation_domain_id(), observation_domain);
262 assert_eq!(flow_netflow.export_time(), export_time);
263 assert_eq!(flow_netflow.sequence_number(), sequence_number);
264 assert_eq!(flow_netflow.observation_domain_id(), observation_domain);
265 }
266
267 #[test]
268 fn test_supports_arithmetic() {
269 assert!(!IE::mplsLabelStackSection.supports_arithmetic_ops());
271 assert!(!IE::paddingOctets.supports_arithmetic_ops());
272 assert!(IE::destinationIPv4PrefixLength.supports_arithmetic_ops());
274 assert!(IE::flowActiveTimeout.supports_arithmetic_ops());
275 assert!(IE::distinctCountOfSourceIPv4Address.supports_arithmetic_ops());
276 assert!(IE::postMCastPacketDeltaCount.supports_arithmetic_ops());
277 assert!(!IE::ipv6ExtensionHeadersFull.supports_arithmetic_ops());
278 assert!(IE::mibObjectValueInteger.supports_arithmetic_ops());
279 assert!(IE::absoluteError.supports_arithmetic_ops());
280 assert!(!IE::ipClassOfService.supports_arithmetic_ops());
283 assert!(!IE::egressInterface.supports_arithmetic_ops());
284 assert!(!IE::forwardingStatus.supports_arithmetic_ops());
285 assert!(!IE::dataRecordsReliability.supports_arithmetic_ops());
287 assert!(!IE::observationTimeSeconds.supports_arithmetic_ops());
289 assert!(!IE::observationTimeMilliseconds.supports_arithmetic_ops());
290 assert!(!IE::observationTimeNanoseconds.supports_arithmetic_ops());
291 assert!(!IE::observationTimeMicroseconds.supports_arithmetic_ops());
292 assert!(!IE::sourceIPv4Address.supports_arithmetic_ops());
294 assert!(!IE::sourceIPv6Address.supports_arithmetic_ops());
295 assert!(!IE::bgpSourceCommunityList.supports_arithmetic_ops());
297 assert!(!IE::ipv6ExtensionHeaderTypeCountList.supports_arithmetic_ops());
298 assert!(!IE::subTemplateMultiList.supports_arithmetic_ops());
299 }
300
301 #[test]
302 fn test_supports_bitwise_ops() {
303 assert!(IE::mplsLabelStackSection.supports_bitwise_ops());
305 assert!(IE::paddingOctets.supports_bitwise_ops());
306 assert!(IE::destinationIPv4PrefixLength.supports_bitwise_ops());
308 assert!(IE::flowActiveTimeout.supports_bitwise_ops());
309 assert!(IE::distinctCountOfSourceIPv4Address.supports_bitwise_ops());
310 assert!(IE::postMCastPacketDeltaCount.supports_bitwise_ops());
311 assert!(IE::ipv6ExtensionHeadersFull.supports_bitwise_ops());
312 assert!(IE::mibObjectValueInteger.supports_bitwise_ops());
313 assert!(IE::ipClassOfService.supports_bitwise_ops());
316 assert!(IE::egressInterface.supports_bitwise_ops());
317 assert!(IE::forwardingStatus.supports_bitwise_ops());
318 assert!(IE::dataRecordsReliability.supports_bitwise_ops());
320 assert!(!IE::observationTimeSeconds.supports_bitwise_ops());
322 assert!(!IE::observationTimeMilliseconds.supports_bitwise_ops());
323 assert!(!IE::observationTimeNanoseconds.supports_bitwise_ops());
324 assert!(!IE::observationTimeMicroseconds.supports_bitwise_ops());
325 assert!(IE::sourceIPv4Address.supports_bitwise_ops());
327 assert!(IE::sourceIPv6Address.supports_bitwise_ops());
328 }
329
330 #[test]
331 fn test_supports_comparison_ops() {
332 assert!(!IE::mplsLabelStackSection.supports_comparison_ops());
334 assert!(!IE::paddingOctets.supports_comparison_ops());
335 assert!(IE::destinationIPv4PrefixLength.supports_comparison_ops());
337 assert!(IE::flowActiveTimeout.supports_comparison_ops());
338 assert!(IE::distinctCountOfSourceIPv4Address.supports_comparison_ops());
339 assert!(IE::postMCastPacketDeltaCount.supports_comparison_ops());
340 assert!(!IE::ipv6ExtensionHeadersFull.supports_comparison_ops());
341 assert!(IE::mibObjectValueInteger.supports_comparison_ops());
342 assert!(IE::ipClassOfService.supports_comparison_ops());
345 assert!(IE::egressInterface.supports_comparison_ops());
346 assert!(IE::forwardingStatus.supports_comparison_ops());
347 assert!(!IE::dataRecordsReliability.supports_comparison_ops());
349 assert!(IE::observationTimeSeconds.supports_comparison_ops());
351 assert!(IE::observationTimeMilliseconds.supports_comparison_ops());
352 assert!(IE::observationTimeNanoseconds.supports_comparison_ops());
353 assert!(IE::observationTimeMicroseconds.supports_comparison_ops());
354 assert!(IE::sourceIPv4Address.supports_comparison_ops());
356 assert!(IE::sourceIPv6Address.supports_comparison_ops());
357 }
358
359 #[test]
360 fn test_field_add() {
361 let mut octet1 = Field::octetDeltaCount(100);
362 let octet2 = Field::octetDeltaCount(200);
363 let packet1 = Field::packetDeltaCount(300);
364
365 let result_err1 = octet1.add_field(&packet1);
366 let result_err2 = octet1.add_assign_field(&packet1);
367 let result = octet1.add_field(&octet2).expect("add field");
368 octet1
369 .add_assign_field(&octet2)
370 .expect("add field mut failed");
371 let expected = Field::octetDeltaCount(300);
372 let expected_err = Some(FieldOperationError::InapplicableAdd(
373 IE::octetDeltaCount,
374 IE::packetDeltaCount,
375 ));
376
377 assert_eq!(result, expected);
378 assert_eq!(octet1, expected);
379 assert_eq!(result_err1.err(), expected_err);
380 assert_eq!(result_err2.err(), expected_err);
381 }
382
383 #[test]
384 fn test_field_min() {
385 let mut field1 = Field::octetDeltaCount(100);
386 let field2 = Field::octetDeltaCount(200);
387 let packet1 = Field::packetDeltaCount(300);
388
389 let result_err1 = field1.min_field(&packet1);
390 let result_err2 = field1.min_assign_field(&packet1);
391 let result = field1.min_field(&field2).expect("min field");
392 field1
393 .min_assign_field(&field2)
394 .expect("min field mut failed");
395 let expected = Field::octetDeltaCount(100);
396 let expected_err = Some(FieldOperationError::InapplicableMin(
397 IE::octetDeltaCount,
398 IE::packetDeltaCount,
399 ));
400
401 assert_eq!(result, expected);
402 assert_eq!(field1, expected);
403 assert_eq!(result_err1.err(), expected_err);
404 assert_eq!(result_err2.err(), expected_err);
405 }
406
407 #[test]
408 fn test_field_max() {
409 let mut field1 = Field::octetDeltaCount(100);
410 let field2 = Field::octetDeltaCount(200);
411 let packet1 = Field::packetDeltaCount(300);
412
413 let result_err1 = field1.max_field(&packet1);
414 let result_err2 = field1.max_assign_field(&packet1);
415 let result = field1.max_field(&field2).expect("max field");
416 field1
417 .max_assign_field(&field2)
418 .expect("max field mut failed");
419 let expected = Field::octetDeltaCount(200);
420 let expected_err = Some(FieldOperationError::InapplicableMax(
421 IE::octetDeltaCount,
422 IE::packetDeltaCount,
423 ));
424
425 assert_eq!(result, expected);
426 assert_eq!(field1, expected);
427 assert_eq!(result_err1.err(), expected_err);
428 assert_eq!(result_err2.err(), expected_err);
429 }
430
431 #[test]
432 fn test_field_bitwise_or() {
433 let mut field1 = Field::octetDeltaCount(100);
434 let field2 = Field::octetDeltaCount(200);
435 let packet1 = Field::packetDeltaCount(300);
436
437 let result_err1 = field1.bitwise_or_field(&packet1);
438 let result_err2 = field1.bitwise_or_assign_field(&packet1);
439 let result = field1.bitwise_or_field(&field2).expect("bitwise or field");
440 field1
441 .bitwise_or_assign_field(&field2)
442 .expect("bitwise or field mut failed");
443 let expected = Field::octetDeltaCount(236);
444 let expected_err = Some(FieldOperationError::InapplicableBitwise(
445 IE::octetDeltaCount,
446 IE::packetDeltaCount,
447 ));
448
449 assert_eq!(result, expected);
450 assert_eq!(field1, expected);
451 assert_eq!(result_err1.err(), expected_err);
452 assert_eq!(result_err2.err(), expected_err);
453 }
454
455 #[test]
456 fn test_field_bitwise_or_tcp_control_bits() {
457 let mut field1 = Field::tcpControlBits(TCPHeaderFlags::from(0x01u8));
458 let field2 = Field::tcpControlBits(TCPHeaderFlags::from(0x02u8));
459 let packet1 = Field::packetDeltaCount(300);
460
461 let result_err1 = field1.bitwise_or_field(&packet1);
462 let result_err2 = field1.bitwise_or_assign_field(&packet1);
463 let result = field1.bitwise_or_field(&field2).expect("bitwise or field");
464 field1
465 .bitwise_or_assign_field(&field2)
466 .expect("bitwise or field mut failed");
467 let expected = Field::tcpControlBits(TCPHeaderFlags::from(0x03u8));
468 let expected_err = Some(FieldOperationError::InapplicableBitwise(
469 IE::tcpControlBits,
470 IE::packetDeltaCount,
471 ));
472
473 assert_eq!(result, expected);
474 assert_eq!(field1, expected);
475 assert_eq!(result_err1.err(), expected_err);
476 assert_eq!(result_err2.err(), expected_err);
477 }
478
479 #[test]
480 fn test_field_bitwise_or_protocol_identifier() {
481 let mut field1 = Field::protocolIdentifier(protocolIdentifier::ICMP);
482 let field2 = Field::protocolIdentifier(protocolIdentifier::IGMP);
483 let packet1 = Field::packetDeltaCount(300);
484
485 let result_err1 = field1.bitwise_or_field(&packet1);
486 let result_err2 = field1.bitwise_or_assign_field(&packet1);
487 let result = field1.bitwise_or_field(&field2).expect("bitwise or field");
488 field1
489 .bitwise_or_assign_field(&field2)
490 .expect("bitwise or field mut failed");
491 let expected = Field::protocolIdentifier(protocolIdentifier::from(0x03u8));
492 let expected_err = Some(FieldOperationError::InapplicableBitwise(
493 IE::protocolIdentifier,
494 IE::packetDeltaCount,
495 ));
496
497 assert_eq!(result, expected);
498 assert_eq!(field1, expected);
499 assert_eq!(result_err1.err(), expected_err);
500 assert_eq!(result_err2.err(), expected_err);
501 }
502
503 #[test]
504 fn test_vmware_ops() {
505 let mut vendor_field1 = vmware::Field::averageLatency(100);
506 let vendor_field2 = vmware::Field::averageLatency(200);
507 let vendor_other_field = vmware::Field::algControlFlowId(123);
508
509 let result_err1 = vendor_field1.add_field(&vendor_other_field);
510 let result_err2 = vendor_field1.add_assign_field(&vendor_other_field);
511 let result = vendor_field1.add_field(&vendor_field2).expect("add field");
512 vendor_field1
513 .add_assign_field(&vendor_field2)
514 .expect("add field");
515 let expected = vmware::Field::averageLatency(300);
516 let expected_err = Some(vmware::FieldOperationError::InapplicableAdd(
517 vmware::IE::averageLatency,
518 vmware::IE::algControlFlowId,
519 ));
520
521 assert_eq!(result, expected);
522 assert_eq!(vendor_field1, expected);
523 assert_eq!(result_err1.err(), expected_err);
524 assert_eq!(result_err2.err(), expected_err);
525 }
526
527 #[test]
528 fn test_vendor_field_add() {
529 let mut field1 = Field::VMWare(vmware::Field::averageLatency(100));
530 let field2 = Field::VMWare(vmware::Field::averageLatency(200));
531 let other_field = Field::VMWare(vmware::Field::algControlFlowId(123));
532
533 let result_err1 = field1.add_field(&other_field);
534 let result_err2 = field1.add_assign_field(&other_field);
535 let result = field1.add_field(&field2).expect("add field");
536 field1.add_assign_field(&field2).expect("add field");
537 let expected = Field::VMWare(vmware::Field::averageLatency(300));
538 let expected_err = Some(FieldOperationError::InapplicableAdd(
539 IE::VMWare(vmware::IE::averageLatency),
540 IE::VMWare(vmware::IE::algControlFlowId),
541 ));
542
543 assert_eq!(result, expected);
544 assert_eq!(field1, expected);
545 assert_eq!(result_err1.err(), expected_err);
546 assert_eq!(result_err2.err(), expected_err);
547 }
548
549 #[test]
550 fn test_vendor_field_min() {
551 let mut field1 = Field::VMWare(vmware::Field::averageLatency(100));
552 let field2 = Field::VMWare(vmware::Field::averageLatency(200));
553 let other_field = Field::VMWare(vmware::Field::algControlFlowId(123));
554
555 let result_err1 = field1.min_field(&other_field);
556 let result_err2 = field1.min_assign_field(&other_field);
557 let result = field1.min_field(&field2).expect("min field");
558 field1.min_assign_field(&field2).expect("min field");
559 let expected = Field::VMWare(vmware::Field::averageLatency(100));
560 let expected_err = Some(FieldOperationError::InapplicableMin(
561 IE::VMWare(vmware::IE::averageLatency),
562 IE::VMWare(vmware::IE::algControlFlowId),
563 ));
564
565 assert_eq!(result, expected);
566 assert_eq!(field1, expected);
567 assert_eq!(result_err1.err(), expected_err);
568 assert_eq!(result_err2.err(), expected_err);
569 }
570
571 #[test]
572 fn test_vendor_field_max() {
573 let mut field1 = Field::VMWare(vmware::Field::averageLatency(100));
574 let field2 = Field::VMWare(vmware::Field::averageLatency(200));
575 let other_field = Field::VMWare(vmware::Field::algControlFlowId(123));
576
577 let result_err1 = field1.max_field(&other_field);
578 let result_err2 = field1.max_assign_field(&other_field);
579 let result = field1.max_field(&field2).expect("max field");
580 field1.max_assign_field(&field2).expect("max field");
581 let expected = Field::VMWare(vmware::Field::averageLatency(200));
582 let expected_err = Some(FieldOperationError::InapplicableMax(
583 IE::VMWare(vmware::IE::averageLatency),
584 IE::VMWare(vmware::IE::algControlFlowId),
585 ));
586
587 assert_eq!(result, expected);
588 assert_eq!(field1, expected);
589 assert_eq!(result_err1.err(), expected_err);
590 assert_eq!(result_err2.err(), expected_err);
591 }
592
593 #[test]
594 fn test_vendor_field_bitwise_or() {
595 let mut field1 = Field::VMWare(vmware::Field::algControlFlowId(100));
596 let field2 = Field::VMWare(vmware::Field::algControlFlowId(200));
597 let other_field = Field::VMWare(vmware::Field::averageLatency(123));
598
599 let result_err1 = field1.bitwise_or_field(&other_field);
600 let result_err2 = field1.bitwise_or_field(&other_field);
601 let result = field1.bitwise_or_field(&field2).expect("bitwise or field");
602 field1
603 .bitwise_or_assign_field(&field2)
604 .expect("bitwise or field");
605 let expected = Field::VMWare(vmware::Field::algControlFlowId(236));
606 let expected_err = Some(FieldOperationError::InapplicableBitwise(
607 IE::VMWare(vmware::IE::algControlFlowId),
608 IE::VMWare(vmware::IE::averageLatency),
609 ));
610
611 assert_eq!(result, expected);
612 assert_eq!(field1, expected);
613 assert_eq!(result_err1.err(), expected_err);
614 assert_eq!(result_err2.err(), expected_err);
615 }
616}