mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
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.
191 lines
5.8 KiB
Go
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{}
|
|
}
|