Skip to content

fix: correct NetFlow v9 Count and frame boundaries - #302

Merged
mikemiles-dev merged 1 commit into
mikemiles-dev:mainfrom
ktsaou:fix/v9-count-framing
Jul 22, 2026
Merged

fix: correct NetFlow v9 Count and frame boundaries#302
mikemiles-dev merged 1 commit into
mikemiles-dev:mainfrom
ktsaou:fix/v9-count-framing

Conversation

@ktsaou

@ktsaou ktsaou commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Problem

NetFlow v9 Count is the total number of Template, Options Template, and Data records in an Export Packet. The parser instead used it as the number of FlowSets to parse.

That caused valid FlowSets to be left unread when the declared record count was smaller than the FlowSet count. The outer parser then treated those remaining FlowSet bytes as another packet. Pending-flow replay also rewrote the received Count as a FlowSet count, and serialization emitted a FlowSet count rather than a record count.

NetFlow v9 has no packet-length field, so Count cannot delimit the packet. The complete caller-provided transport frame is the only available byte boundary.

Change

  • Parse FlowSets to the end of one caller-delimited v9 Export Packet.
  • Preserve the exporter-declared Count during parsing and pending replay.
  • Recompute Count from the records actually emitted during serialization.
  • Reject record-count and FlowSet-length overflow during serialization.
  • Reject header-only v9 Export Packets.
  • Add a configurable positive v9 frame-size limit, defaulting to 65,535 bytes.
  • Correct legacy tests and fixtures that concatenated separately framed v9 packets or contained bytes outside declared FlowSet lengths.

Protocol basis

RFC 3954 section 5.1 defines Count as the sum of Template, Options Template, and Data records. nfdump and GoFlow2 likewise traverse FlowSets to the caller-provided packet boundary.

Compatibility

The configuration API is additive. Parsing behavior intentionally changes where the previous behavior depended on treating Count as a FlowSet count:

  • Pass exactly one transport-delimited v9 Export Packet per parse_bytes or iter_packets call.
  • Concatenated v9 packets are no longer accepted because v9 has no field that can separate them.
  • Trailing bytes that do not form a complete FlowSet are rejected.
  • Header-only packets and serialization with no emit-able FlowSet are rejected.
  • A parsed packet retains the Count received on the wire, including after pending replay; serialization recomputes the true emitted record count.

Self-delimiting IPFIX, NetFlow v5, and NetFlow v7 batching is unchanged.

Tests

Four core regression tests fail against unmodified main and pass with this change. The final focused suite contains nine tests covering Count semantics, caller framing, pending replay, serialization, overflow, empty packets, default/configured frame limits, invalid configuration, and pre-template-state rejection.

The complete project validation passes:

  • formatting
  • Clippy with warnings denied
  • build
  • all unit and integration tests
  • documentation tests
  • README synchronization
  • benchmark compilation
  • focused tests without default features

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes NetFlow v9 semantics by treating header Count as exporter-declared record metadata (not a FlowSet count) and by parsing FlowSets to the end of the caller-delimited v9 export-packet frame. Adds a configurable v9 maximum frame size (default 65,535 bytes), updates serialization to recompute record count, and refreshes tests/fixtures/docs to reflect framing rules and stricter boundary validation.

Changes:

  • Parse v9 FlowSets to the end of the caller-provided frame and preserve exporter-declared header.count during parsing/pending replay.
  • Serialize v9 by recomputing header.count as the total emitted record count; reject empty packets and u16 overflow for record count / FlowSet length.
  • Add/propagate a configurable v9 max-frame-size limit and update tests, snapshots, README, and SECURITY guidance accordingly.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/v9_count_framing.rs New regression tests covering v9 Count semantics, framing, pending replay, serialization overflow, and frame-size limits.
src/variable_versions/v9/types.rs Stops using header.count to delimit FlowSet parsing; clarifies Header::count meaning in docs.
src/variable_versions/v9/serializer.rs Recomputes header.count as record count; adds overflow checks and rejects packets with no emittable FlowSet.
src/variable_versions/v9/parser.rs Adds v9 frame-size enforcement and header-only rejection; parses FlowSets to end-of-frame; preserves exporter-declared count.
src/variable_versions/mod.rs Re-exports the new default v9 frame-size constant.
src/variable_versions/config.rs Introduces DEFAULT_MAX_V9_FRAME_SIZE_BYTES and ConfigError::InvalidV9FrameSize.
src/tests.rs Updates legacy/base tests to avoid concatenated v9 frames and to remove bytes beyond declared FlowSet lengths.
src/snapshots/netflow_parser__tests__restored_legacy_tests__it_parses_v9_ipv6flowlabel.snap Snapshot update reflecting test refactor/expectations.
src/snapshots/netflow_parser__tests__restored_legacy_tests__it_parses_multiple_packets.snap Snapshot update reflecting test refactor/expectations.
src/snapshots/netflow_parser__tests__base_tests__v9_example_from_integration_test.snap Snapshot update reflecting corrected v9 Count semantics and fixture trimming.
src/snapshots/netflow_parser__tests__base_tests__v9_example_from_integration_test_2.snap Snapshot update reflecting corrected v9 Count semantics and fixture trimming.
src/lib.rs Adds builder option for v9 max frame size; updates parse/iter docs to emphasize v9 framing constraints.
SECURITY.md Documents the new default v9 frame-size DoS mitigation.
README.md Documents v9 frame-boundary requirements and configuration example for max frame size.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/variable_versions/v9/parser.rs
@ktsaou
ktsaou force-pushed the fix/v9-count-framing branch from 103aec5 to 44959d7 Compare July 21, 2026 08:13
@mikemiles-dev

Copy link
Copy Markdown
Owner

Can you rebase?

@ktsaou
ktsaou force-pushed the fix/v9-count-framing branch from 44959d7 to 48eaaa4 Compare July 22, 2026 07:26
@ktsaou

ktsaou commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

rebased

@mikemiles-dev
mikemiles-dev merged commit adff4b4 into mikemiles-dev:main Jul 22, 2026
6 checks passed
@ktsaou ktsaou mentioned this pull request Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants