From 6d143acf3e78281873f87e2f315d8b212d863a88 Mon Sep 17 00:00:00 2001 From: Paul Stahmleder Date: Thu, 26 Feb 2026 20:01:48 +0100 Subject: [PATCH] Fix v5 inByte/inPackets handling --- formatter/ntopng_json.go | 21 +++++++++++++++++---- formatter/ntopng_tlv.go | 21 +++++++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/formatter/ntopng_json.go b/formatter/ntopng_json.go index 818c482..1649693 100644 --- a/formatter/ntopng_json.go +++ b/formatter/ntopng_json.go @@ -59,11 +59,24 @@ func (d *NtopngJson) toJSON(extFlow *proto.ExtendedFlowMessage) ([]byte, error) // Stats + direction // goflow2 only supports unidirectional flows. There is no Direction field and only one // Bytes/Packets field. Data flow is always Src -> Dst. + // + // For NetFlow v9/IPFIX, bytes/packets arrive via the mapping.yaml remapping into the + // custom ExtendedFlowMessage fields (200-203). For NetFlow v5 (fixed format), the + // producer bypasses that remapping and writes directly to FlowMessage.Bytes/Packets, + // so fall back to those when the custom fields are unpopulated. + inBytes := uint64(extFlow.InBytes) + if inBytes == 0 { + inBytes = baseFlow.Bytes + } + inPackets := uint64(extFlow.InPackets) + if inPackets == 0 { + inPackets = baseFlow.Packets + } retmap[strconv.Itoa(netflow.NFV9_FIELD_DIRECTION)] = 0 - retmap[strconv.Itoa(netflow.NFV9_FIELD_IN_BYTES)] = extFlow.InBytes - retmap[strconv.Itoa(netflow.NFV9_FIELD_IN_PKTS)] = extFlow.InPackets - retmap[strconv.Itoa(netflow.NFV9_FIELD_OUT_BYTES)] = extFlow.OutBytes - retmap[strconv.Itoa(netflow.NFV9_FIELD_OUT_PKTS)] = extFlow.OutPackets + retmap[strconv.Itoa(netflow.NFV9_FIELD_IN_BYTES)] = inBytes + retmap[strconv.Itoa(netflow.NFV9_FIELD_IN_PKTS)] = inPackets + retmap[strconv.Itoa(netflow.NFV9_FIELD_OUT_BYTES)] = uint64(extFlow.OutBytes) + retmap[strconv.Itoa(netflow.NFV9_FIELD_OUT_PKTS)] = uint64(extFlow.OutPackets) // Goflow2 protobuf provides time in ns, but it ntopng expects time in seconds. retmap[strconv.Itoa(netflow.NFV9_FIELD_FIRST_SWITCHED)] = uint32(baseFlow.TimeFlowStartNs / 1_000_000_000) diff --git a/formatter/ntopng_tlv.go b/formatter/ntopng_tlv.go index 6a20180..6608114 100644 --- a/formatter/ntopng_tlv.go +++ b/formatter/ntopng_tlv.go @@ -115,12 +115,25 @@ func (d *NtopngTlv) toTLV(extFlow *proto.ExtendedFlowMessage) ([]byte, error) { // Stats + direction // goflow2 only supports unidirectional flows. There is no Direction field and only one // Bytes/Packets field. Data flow is always Src -> Dst + // + // For NetFlow v9/IPFIX, bytes/packets arrive via the mapping.yaml remapping into the + // custom ExtendedFlowMessage fields (200-203). For NetFlow v5 (fixed format), the + // producer bypasses that remapping and writes directly to FlowMessage.Bytes/Packets, + // so fall back to those when the custom fields are unpopulated. + inBytes := uint64(extFlow.InBytes) + if inBytes == 0 { + inBytes = baseFlow.Bytes + } + inPackets := uint64(extFlow.InPackets) + if inPackets == 0 { + inPackets = baseFlow.Packets + } items = append(items, ndpiItem{Key: netflow.NFV9_FIELD_DIRECTION, Value: 0}, - ndpiItem{Key: netflow.NFV9_FIELD_IN_BYTES, Value: extFlow.InBytes}, - ndpiItem{Key: netflow.NFV9_FIELD_IN_PKTS, Value: extFlow.InPackets}, - ndpiItem{Key: netflow.NFV9_FIELD_OUT_BYTES, Value: extFlow.OutBytes}, - ndpiItem{Key: netflow.NFV9_FIELD_OUT_PKTS, Value: extFlow.OutPackets}, + ndpiItem{Key: netflow.NFV9_FIELD_IN_BYTES, Value: inBytes}, + ndpiItem{Key: netflow.NFV9_FIELD_IN_PKTS, Value: inPackets}, + ndpiItem{Key: netflow.NFV9_FIELD_OUT_BYTES, Value: uint64(extFlow.OutBytes)}, + ndpiItem{Key: netflow.NFV9_FIELD_OUT_PKTS, Value: uint64(extFlow.OutPackets)}, ) // Goflow2 protobuf provides time in ns, but it ntopng expects time in seconds. items = append(items,