Files
akvorado/inlet/flow/decoder/netflow/decode.go
Vincent Bernat 1ec89aac1f build: fix various lint issues
revive default configuration has changed in 1.3.0. Some stuff is a bit
silly (like empty blocks), but I find it easier to follow that than to
try to tweak the configuration.
2023-03-21 00:01:13 +01:00

191 lines
5.8 KiB
Go

// SPDX-FileCopyrightText: 2023 Free Mobile
// SPDX-FileCopyrightText: 2021 NetSampler
// SPDX-License-Identifier: AGPL-3.0-only AND BSD-3-Clause
package netflow
import (
"encoding/binary"
"net/netip"
"akvorado/common/helpers"
"akvorado/common/schema"
"github.com/netsampler/goflow2/decoders/netflow"
"github.com/netsampler/goflow2/producer"
)
func (nd *Decoder) decode(msgDec interface{}, samplingRateSys producer.SamplingRateSystem) []*schema.FlowMessage {
flowMessageSet := []*schema.FlowMessage{}
var obsDomainID uint32
var dataFlowSet []netflow.DataFlowSet
var optionsDataFlowSet []netflow.OptionsDataFlowSet
switch msgDecConv := msgDec.(type) {
case netflow.NFv9Packet:
dataFlowSet, _, _, optionsDataFlowSet = producer.SplitNetFlowSets(msgDecConv)
obsDomainID = msgDecConv.SourceId
case netflow.IPFIXPacket:
dataFlowSet, _, _, optionsDataFlowSet = producer.SplitIPFIXSets(msgDecConv)
obsDomainID = msgDecConv.ObservationDomainId
default:
return nil
}
// Get sampling rate
samplingRate, found := producer.SearchNetFlowOptionDataSets(optionsDataFlowSet)
if samplingRateSys != nil {
if found {
samplingRateSys.AddSamplingRate(10, obsDomainID, samplingRate)
} else {
samplingRate, _ = samplingRateSys.GetSamplingRate(10, obsDomainID)
}
}
// Parse fields
for _, dataFlowSetItem := range dataFlowSet {
for _, record := range dataFlowSetItem.Records {
flow := nd.decodeRecord(record.Values)
if flow != nil {
flow.SamplingRate = samplingRate
flowMessageSet = append(flowMessageSet, flow)
}
}
}
return flowMessageSet
}
func (nd *Decoder) decodeRecord(fields []netflow.DataField) *schema.FlowMessage {
var etype uint16
bf := &schema.FlowMessage{}
for _, field := range fields {
v, ok := field.Value.([]byte)
if !ok {
continue
}
if field.PenProvided {
continue
}
switch field.Type {
// Statistics
case netflow.NFV9_FIELD_IN_BYTES, netflow.NFV9_FIELD_OUT_BYTES:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnBytes, decodeUNumber(v))
case netflow.NFV9_FIELD_IN_PKTS, netflow.NFV9_FIELD_OUT_PKTS:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnPackets, decodeUNumber(v))
// L3
case netflow.NFV9_FIELD_IPV4_SRC_ADDR:
etype = helpers.ETypeIPv4
bf.SrcAddr = decodeIP(v)
case netflow.NFV9_FIELD_IPV4_DST_ADDR:
etype = helpers.ETypeIPv4
bf.DstAddr = decodeIP(v)
case netflow.NFV9_FIELD_IPV6_SRC_ADDR:
etype = helpers.ETypeIPv6
bf.SrcAddr = decodeIP(v)
case netflow.NFV9_FIELD_IPV6_DST_ADDR:
etype = helpers.ETypeIPv6
bf.DstAddr = decodeIP(v)
case netflow.NFV9_FIELD_SRC_MASK, netflow.NFV9_FIELD_IPV6_SRC_MASK:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnSrcNetMask, decodeUNumber(v))
case netflow.NFV9_FIELD_DST_MASK, netflow.NFV9_FIELD_IPV6_DST_MASK:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnDstNetMask, decodeUNumber(v))
case netflow.NFV9_FIELD_IPV4_NEXT_HOP, netflow.NFV9_FIELD_BGP_IPV4_NEXT_HOP, netflow.NFV9_FIELD_IPV6_NEXT_HOP, netflow.NFV9_FIELD_BGP_IPV6_NEXT_HOP:
bf.NextHop = decodeIP(v)
// L4
case netflow.NFV9_FIELD_L4_SRC_PORT:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnSrcPort, decodeUNumber(v))
case netflow.NFV9_FIELD_L4_DST_PORT:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnDstPort, decodeUNumber(v))
case netflow.NFV9_FIELD_PROTOCOL:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnProto, decodeUNumber(v))
// Network
case netflow.NFV9_FIELD_SRC_AS:
bf.SrcAS = uint32(decodeUNumber(v))
case netflow.NFV9_FIELD_DST_AS:
bf.DstAS = uint32(decodeUNumber(v))
// Interfaces
case netflow.NFV9_FIELD_INPUT_SNMP:
bf.InIf = uint32(decodeUNumber(v))
case netflow.NFV9_FIELD_OUTPUT_SNMP:
bf.OutIf = uint32(decodeUNumber(v))
// Remaining
case netflow.NFV9_FIELD_FORWARDING_STATUS:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnForwardingStatus, decodeUNumber(v))
default:
if !nd.d.Schema.IsDisabled(schema.ColumnGroupNAT) {
// NAT
switch field.Type {
case netflow.IPFIX_FIELD_postNATSourceIPv4Address:
nd.d.Schema.ProtobufAppendIP(bf, schema.ColumnSrcAddrNAT, decodeIP(v))
case netflow.IPFIX_FIELD_postNATDestinationIPv4Address:
nd.d.Schema.ProtobufAppendIP(bf, schema.ColumnDstAddrNAT, decodeIP(v))
case netflow.IPFIX_FIELD_postNAPTSourceTransportPort:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnSrcPortNAT, decodeUNumber(v))
case netflow.IPFIX_FIELD_postNAPTDestinationTransportPort:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnDstPortNAT, decodeUNumber(v))
}
}
if !nd.d.Schema.IsDisabled(schema.ColumnGroupL2) {
// L2
switch field.Type {
case netflow.NFV9_FIELD_SRC_VLAN:
bf.SrcVlan = uint16(decodeUNumber(v))
case netflow.NFV9_FIELD_DST_VLAN:
bf.DstVlan = uint16(decodeUNumber(v))
case netflow.NFV9_FIELD_IN_SRC_MAC:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnSrcMAC, decodeUNumber(v))
case netflow.NFV9_FIELD_IN_DST_MAC:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnDstMAC, decodeUNumber(v))
case netflow.NFV9_FIELD_OUT_SRC_MAC:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnSrcMAC, decodeUNumber(v))
case netflow.NFV9_FIELD_OUT_DST_MAC:
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnDstMAC, decodeUNumber(v))
}
}
}
}
nd.d.Schema.ProtobufAppendVarint(bf, schema.ColumnEType, uint64(etype))
return bf
}
func decodeUNumber(b []byte) uint64 {
var o uint64
l := len(b)
switch l {
case 1:
o = uint64(b[0])
case 2:
o = uint64(binary.BigEndian.Uint16(b))
case 4:
o = uint64(binary.BigEndian.Uint32(b))
case 8:
o = binary.BigEndian.Uint64(b)
default:
if l < 8 {
var iter uint
for i := range b {
o |= uint64(b[i]) << uint(8*(uint(l)-iter-1))
iter++
}
} else {
return 0
}
}
return o
}
func decodeIP(b []byte) netip.Addr {
if ip, ok := netip.AddrFromSlice(b); ok {
return netip.AddrFrom16(ip.As16())
}
return netip.Addr{}
}