2021-05-22 16:12:26 -07:00
|
|
|
package sflow
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
"github.com/netsampler/goflow2/v2/decoders/utils"
|
2021-05-22 16:12:26 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
FORMAT_EXT_SWITCH = 1001
|
|
|
|
FORMAT_EXT_ROUTER = 1002
|
|
|
|
FORMAT_EXT_GATEWAY = 1003
|
|
|
|
FORMAT_RAW_PKT = 1
|
|
|
|
FORMAT_ETH = 2
|
|
|
|
FORMAT_IPV4 = 3
|
|
|
|
FORMAT_IPV6 = 4
|
|
|
|
)
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
type DecoderError struct {
|
|
|
|
Err error
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
func (e *DecoderError) Error() string {
|
|
|
|
return fmt.Sprintf("sFlow %s", e.Err.Error())
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
func (e *DecoderError) Unwrap() error {
|
|
|
|
return e.Err
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
type FlowError struct {
|
|
|
|
Format uint32
|
|
|
|
Seq uint32
|
|
|
|
Err error
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
func (e *FlowError) Error() string {
|
|
|
|
return fmt.Sprintf("[format:%d seq:%d] %s", e.Format, e.Seq, e.Err.Error())
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
func (e *FlowError) Unwrap() error {
|
|
|
|
return e.Err
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
type RecordError struct {
|
|
|
|
DataFormat uint32
|
|
|
|
Err error
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
func (e *RecordError) Error() string {
|
|
|
|
return fmt.Sprintf("[data-format:%d] %s", e.DataFormat, e.Err.Error())
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
func (e *RecordError) Unwrap() error {
|
|
|
|
return e.Err
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
func DecodeIP(payload *bytes.Buffer) (uint32, []byte, error) {
|
|
|
|
var ipVersion uint32
|
|
|
|
if err := utils.BinaryDecoder(payload, &ipVersion); err != nil {
|
|
|
|
return 0, nil, fmt.Errorf("DecodeIP: [%w]", err)
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
var ip []byte
|
|
|
|
if ipVersion == 1 {
|
|
|
|
ip = make([]byte, 4)
|
|
|
|
} else if ipVersion == 2 {
|
|
|
|
ip = make([]byte, 16)
|
|
|
|
} else {
|
|
|
|
return ipVersion, ip, fmt.Errorf("DecodeIP: unknown IP version %d", ipVersion)
|
|
|
|
}
|
|
|
|
if payload.Len() >= len(ip) {
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload, ip); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return 0, nil, fmt.Errorf("DecodeIP: [%w]", err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return ipVersion, ip, fmt.Errorf("DecodeIP: truncated data (need %d, got %d)", len(ip), payload.Len())
|
|
|
|
}
|
|
|
|
return ipVersion, ip, nil
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeCounterRecord(header *RecordHeader, payload *bytes.Buffer) (CounterRecord, error) {
|
|
|
|
counterRecord := CounterRecord{
|
|
|
|
Header: *header,
|
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
switch header.DataFormat {
|
2021-05-22 16:12:26 -07:00
|
|
|
case 1:
|
2023-08-09 19:47:20 -07:00
|
|
|
var ifCounters IfCounters
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&ifCounters.IfIndex,
|
|
|
|
&ifCounters.IfType,
|
|
|
|
&ifCounters.IfSpeed,
|
|
|
|
&ifCounters.IfDirection,
|
|
|
|
&ifCounters.IfStatus,
|
|
|
|
&ifCounters.IfInOctets,
|
|
|
|
&ifCounters.IfInUcastPkts,
|
|
|
|
&ifCounters.IfInMulticastPkts,
|
|
|
|
&ifCounters.IfInBroadcastPkts,
|
|
|
|
&ifCounters.IfInDiscards,
|
|
|
|
&ifCounters.IfInErrors,
|
|
|
|
&ifCounters.IfInUnknownProtos,
|
|
|
|
&ifCounters.IfOutOctets,
|
|
|
|
&ifCounters.IfOutUcastPkts,
|
|
|
|
&ifCounters.IfOutMulticastPkts,
|
|
|
|
&ifCounters.IfOutBroadcastPkts,
|
|
|
|
&ifCounters.IfOutDiscards,
|
|
|
|
&ifCounters.IfOutErrors,
|
|
|
|
&ifCounters.IfPromiscuousMode,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return counterRecord, &RecordError{header.DataFormat, err}
|
2021-09-24 05:46:39 +02:00
|
|
|
}
|
2021-05-22 16:12:26 -07:00
|
|
|
counterRecord.Data = ifCounters
|
|
|
|
case 2:
|
2023-08-09 19:47:20 -07:00
|
|
|
var ethernetCounters EthernetCounters
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
ðernetCounters.Dot3StatsAlignmentErrors,
|
|
|
|
ðernetCounters.Dot3StatsFCSErrors,
|
|
|
|
ðernetCounters.Dot3StatsSingleCollisionFrames,
|
|
|
|
ðernetCounters.Dot3StatsMultipleCollisionFrames,
|
|
|
|
ðernetCounters.Dot3StatsSQETestErrors,
|
|
|
|
ðernetCounters.Dot3StatsDeferredTransmissions,
|
|
|
|
ðernetCounters.Dot3StatsLateCollisions,
|
|
|
|
ðernetCounters.Dot3StatsExcessiveCollisions,
|
|
|
|
ðernetCounters.Dot3StatsInternalMacTransmitErrors,
|
|
|
|
ðernetCounters.Dot3StatsCarrierSenseErrors,
|
|
|
|
ðernetCounters.Dot3StatsFrameTooLongs,
|
|
|
|
ðernetCounters.Dot3StatsInternalMacReceiveErrors,
|
|
|
|
ðernetCounters.Dot3StatsSymbolErrors,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return counterRecord, &RecordError{header.DataFormat, err}
|
2021-09-24 05:46:39 +02:00
|
|
|
}
|
2021-05-22 16:12:26 -07:00
|
|
|
counterRecord.Data = ethernetCounters
|
|
|
|
default:
|
2023-08-09 19:47:20 -07:00
|
|
|
var rawRecord RawRecord
|
|
|
|
rawRecord.Data = payload.Bytes()
|
|
|
|
counterRecord.Data = rawRecord
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return counterRecord, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeFlowRecord(header *RecordHeader, payload *bytes.Buffer) (FlowRecord, error) {
|
|
|
|
flowRecord := FlowRecord{
|
|
|
|
Header: *header,
|
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
var err error
|
|
|
|
switch header.DataFormat {
|
2021-05-22 16:12:26 -07:00
|
|
|
case FORMAT_EXT_SWITCH:
|
|
|
|
extendedSwitch := ExtendedSwitch{}
|
2023-09-04 03:19:41 -07:00
|
|
|
err := utils.BinaryDecoder(payload, &extendedSwitch.SrcVlan, &extendedSwitch.SrcPriority, &extendedSwitch.DstVlan, &extendedSwitch.DstPriority)
|
2021-05-22 16:12:26 -07:00
|
|
|
if err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
flowRecord.Data = extendedSwitch
|
|
|
|
case FORMAT_RAW_PKT:
|
|
|
|
sampledHeader := SampledHeader{}
|
2023-08-09 19:47:20 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&sampledHeader.Protocol,
|
|
|
|
&sampledHeader.FrameLength,
|
|
|
|
&sampledHeader.Stripped,
|
2023-09-04 03:19:41 -07:00
|
|
|
&sampledHeader.OriginalLength,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
sampledHeader.HeaderData = payload.Bytes()
|
|
|
|
flowRecord.Data = sampledHeader
|
|
|
|
case FORMAT_IPV4:
|
2023-08-09 19:47:20 -07:00
|
|
|
sampledIP := SampledIPv4{
|
|
|
|
SampledIPBase: SampledIPBase{
|
|
|
|
SrcIP: make([]byte, 4),
|
|
|
|
DstIP: make([]byte, 4),
|
|
|
|
},
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&sampledIP.SampledIPBase.Length,
|
|
|
|
&sampledIP.SampledIPBase.Protocol,
|
|
|
|
sampledIP.SampledIPBase.SrcIP,
|
|
|
|
sampledIP.SampledIPBase.DstIP,
|
|
|
|
&sampledIP.SampledIPBase.SrcPort,
|
|
|
|
&sampledIP.SampledIPBase.DstPort,
|
|
|
|
&sampledIP.SampledIPBase.TcpFlags,
|
|
|
|
&sampledIP.Tos,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
flowRecord.Data = sampledIP
|
2021-05-22 16:12:26 -07:00
|
|
|
case FORMAT_IPV6:
|
2023-08-09 19:47:20 -07:00
|
|
|
sampledIP := SampledIPv6{
|
|
|
|
SampledIPBase: SampledIPBase{
|
|
|
|
SrcIP: make([]byte, 16),
|
|
|
|
DstIP: make([]byte, 16),
|
|
|
|
},
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&sampledIP.SampledIPBase.Length,
|
|
|
|
&sampledIP.SampledIPBase.Protocol,
|
|
|
|
sampledIP.SampledIPBase.SrcIP,
|
|
|
|
sampledIP.SampledIPBase.DstIP,
|
|
|
|
&sampledIP.SampledIPBase.SrcPort,
|
|
|
|
&sampledIP.SampledIPBase.DstPort,
|
|
|
|
&sampledIP.SampledIPBase.TcpFlags,
|
|
|
|
&sampledIP.Priority,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
flowRecord.Data = sampledIP
|
2021-05-22 16:12:26 -07:00
|
|
|
case FORMAT_EXT_ROUTER:
|
|
|
|
extendedRouter := ExtendedRouter{}
|
2023-08-09 19:47:20 -07:00
|
|
|
if extendedRouter.NextHopIPVersion, extendedRouter.NextHop, err = DecodeIP(payload); err != nil {
|
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&extendedRouter.SrcMaskLen,
|
|
|
|
&extendedRouter.DstMaskLen,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
flowRecord.Data = extendedRouter
|
|
|
|
case FORMAT_EXT_GATEWAY:
|
|
|
|
extendedGateway := ExtendedGateway{}
|
2023-08-09 19:47:20 -07:00
|
|
|
if extendedGateway.NextHopIPVersion, extendedGateway.NextHop, err = DecodeIP(payload); err != nil {
|
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&extendedGateway.AS,
|
|
|
|
&extendedGateway.SrcAS,
|
|
|
|
&extendedGateway.SrcPeerAS,
|
|
|
|
&extendedGateway.ASDestinations,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2022-01-26 17:24:35 +01:00
|
|
|
var asPath []uint32
|
2021-05-22 16:12:26 -07:00
|
|
|
if extendedGateway.ASDestinations != 0 {
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&extendedGateway.ASPathType,
|
|
|
|
&extendedGateway.ASPathLength,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
|
|
|
}
|
|
|
|
// protection for as-path length
|
|
|
|
if extendedGateway.ASPathLength > 1000 {
|
|
|
|
return flowRecord, &RecordError{header.DataFormat, fmt.Errorf("as-path length of %d seems quite large", extendedGateway.ASPathLength)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
if int(extendedGateway.ASPathLength) > payload.Len()-4 {
|
2023-08-09 19:47:20 -07:00
|
|
|
return flowRecord, &RecordError{header.DataFormat, fmt.Errorf("invalid AS path length: %d", extendedGateway.ASPathLength)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
asPath = make([]uint32, extendedGateway.ASPathLength) // max size of 1000 for protection
|
2021-05-22 16:12:26 -07:00
|
|
|
if len(asPath) > 0 {
|
2023-08-09 19:47:20 -07:00
|
|
|
if err := utils.BinaryDecoder(payload, asPath); err != nil {
|
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
extendedGateway.ASPath = asPath
|
|
|
|
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&extendedGateway.CommunitiesLength,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
|
|
|
}
|
|
|
|
// protection for communities length
|
|
|
|
if extendedGateway.CommunitiesLength > 1000 {
|
|
|
|
return flowRecord, &RecordError{header.DataFormat, fmt.Errorf("communities length of %d seems quite large", extendedGateway.ASPathLength)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
if int(extendedGateway.CommunitiesLength) > payload.Len()-4 {
|
2023-08-09 19:47:20 -07:00
|
|
|
return flowRecord, &RecordError{header.DataFormat, fmt.Errorf("invalid communities length: %d", extendedGateway.ASPathLength)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
communities := make([]uint32, extendedGateway.CommunitiesLength) // max size of 1000 for protection
|
2021-05-22 16:12:26 -07:00
|
|
|
if len(communities) > 0 {
|
2023-08-09 19:47:20 -07:00
|
|
|
if err := utils.BinaryDecoder(payload, communities); err != nil {
|
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
if err := utils.BinaryDecoder(payload, &extendedGateway.LocalPref); err != nil {
|
|
|
|
return flowRecord, &RecordError{header.DataFormat, err}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
extendedGateway.Communities = communities
|
|
|
|
|
|
|
|
flowRecord.Data = extendedGateway
|
|
|
|
default:
|
2023-08-09 19:47:20 -07:00
|
|
|
var rawRecord RawRecord
|
|
|
|
rawRecord.Data = payload.Bytes()
|
|
|
|
flowRecord.Data = rawRecord
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
return flowRecord, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeSample(header *SampleHeader, payload *bytes.Buffer) (interface{}, error) {
|
2023-08-09 19:47:20 -07:00
|
|
|
format := header.Format
|
2021-05-22 16:12:26 -07:00
|
|
|
var sample interface{}
|
|
|
|
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&header.SampleSequenceNumber,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return sample, fmt.Errorf("header seq [%w]", err)
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
seq := header.SampleSequenceNumber
|
2021-05-22 16:12:26 -07:00
|
|
|
if format == FORMAT_RAW_PKT || format == FORMAT_ETH {
|
|
|
|
var sourceId uint32
|
2023-08-09 19:47:20 -07:00
|
|
|
if err := utils.BinaryDecoder(payload, &sourceId); err != nil {
|
|
|
|
return sample, &FlowError{format, seq, fmt.Errorf("header source [%w]", err)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
header.SourceIdType = sourceId >> 24
|
|
|
|
header.SourceIdValue = sourceId & 0x00ffffff
|
2021-05-22 16:12:26 -07:00
|
|
|
} else if format == FORMAT_IPV4 || format == FORMAT_IPV6 {
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&header.SourceIdType,
|
|
|
|
&header.SourceIdValue,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return sample, &FlowError{format, seq, fmt.Errorf("header source [%w]", err)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
} else {
|
2023-08-09 19:47:20 -07:00
|
|
|
return sample, &FlowError{format, seq, fmt.Errorf("unknown format %d", format)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var recordsCount uint32
|
|
|
|
var flowSample FlowSample
|
|
|
|
var counterSample CounterSample
|
|
|
|
var expandedFlowSample ExpandedFlowSample
|
|
|
|
if format == FORMAT_RAW_PKT {
|
|
|
|
flowSample = FlowSample{
|
|
|
|
Header: *header,
|
|
|
|
}
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&flowSample.SamplingRate,
|
|
|
|
&flowSample.SamplePool,
|
|
|
|
&flowSample.Drops,
|
|
|
|
&flowSample.Input,
|
|
|
|
&flowSample.Output,
|
|
|
|
&flowSample.FlowRecordsCount,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return sample, &FlowError{format, seq, fmt.Errorf("raw [%w]", err)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
recordsCount = flowSample.FlowRecordsCount
|
2023-08-09 19:47:20 -07:00
|
|
|
if recordsCount > 1000 { // protection against ddos
|
|
|
|
return sample, &FlowError{format, seq, fmt.Errorf("too many flow records: %d", recordsCount)}
|
|
|
|
}
|
|
|
|
flowSample.Records = make([]FlowRecord, recordsCount) // max size of 1000 for protection
|
2021-05-22 16:12:26 -07:00
|
|
|
sample = flowSample
|
|
|
|
} else if format == FORMAT_ETH || format == FORMAT_IPV6 {
|
2023-08-09 19:47:20 -07:00
|
|
|
if err := utils.BinaryDecoder(payload, &recordsCount); err != nil {
|
|
|
|
return sample, &FlowError{format, seq, fmt.Errorf("eth [%w]", err)}
|
|
|
|
}
|
|
|
|
if recordsCount > 1000 { // protection against ddos
|
|
|
|
return sample, &FlowError{format, seq, fmt.Errorf("too many flow records: %d", recordsCount)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
counterSample = CounterSample{
|
|
|
|
Header: *header,
|
|
|
|
CounterRecordsCount: recordsCount,
|
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
counterSample.Records = make([]CounterRecord, recordsCount) // max size of 1000 for protection
|
2021-05-22 16:12:26 -07:00
|
|
|
sample = counterSample
|
|
|
|
} else if format == FORMAT_IPV4 {
|
|
|
|
expandedFlowSample = ExpandedFlowSample{
|
|
|
|
Header: *header,
|
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&expandedFlowSample.SamplingRate,
|
|
|
|
&expandedFlowSample.SamplePool,
|
|
|
|
&expandedFlowSample.Drops,
|
|
|
|
&expandedFlowSample.InputIfFormat,
|
|
|
|
&expandedFlowSample.InputIfValue,
|
|
|
|
&expandedFlowSample.OutputIfFormat,
|
|
|
|
&expandedFlowSample.OutputIfValue,
|
2023-09-04 03:19:41 -07:00
|
|
|
&expandedFlowSample.FlowRecordsCount,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return sample, &FlowError{format, seq, fmt.Errorf("IPv4 [%w]", err)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
recordsCount = expandedFlowSample.FlowRecordsCount
|
|
|
|
expandedFlowSample.Records = make([]FlowRecord, recordsCount)
|
|
|
|
sample = expandedFlowSample
|
|
|
|
}
|
|
|
|
for i := 0; i < int(recordsCount) && payload.Len() >= 8; i++ {
|
|
|
|
recordHeader := RecordHeader{}
|
2023-09-04 03:19:41 -07:00
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&recordHeader.DataFormat,
|
|
|
|
&recordHeader.Length,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return sample, &FlowError{format, seq, fmt.Errorf("record header [%w]", err)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
if int(recordHeader.Length) > payload.Len() {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
recordReader := bytes.NewBuffer(payload.Next(int(recordHeader.Length)))
|
|
|
|
if format == FORMAT_RAW_PKT || format == FORMAT_IPV4 {
|
|
|
|
record, err := DecodeFlowRecord(&recordHeader, recordReader)
|
|
|
|
if err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return sample, &FlowError{format, seq, fmt.Errorf("record [%w]", err)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
if format == FORMAT_RAW_PKT {
|
|
|
|
flowSample.Records[i] = record
|
|
|
|
} else if format == FORMAT_IPV4 {
|
|
|
|
expandedFlowSample.Records[i] = record
|
|
|
|
}
|
|
|
|
} else if format == FORMAT_ETH || format == FORMAT_IPV6 {
|
|
|
|
record, err := DecodeCounterRecord(&recordHeader, recordReader)
|
|
|
|
if err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return sample, &FlowError{format, seq, fmt.Errorf("counter [%w]", err)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
|
|
|
counterSample.Records[i] = record
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sample, nil
|
|
|
|
}
|
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
func DecodeMessageVersion(payload *bytes.Buffer, packetV5 *Packet) error {
|
2021-05-22 16:12:26 -07:00
|
|
|
var version uint32
|
2023-08-09 19:47:20 -07:00
|
|
|
if err := utils.BinaryDecoder(payload, &version); err != nil {
|
|
|
|
return &DecoderError{err}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
packetV5.Version = version
|
|
|
|
|
|
|
|
if version != 5 {
|
|
|
|
return &DecoderError{fmt.Errorf("unknown version %d", version)}
|
|
|
|
}
|
|
|
|
return DecodeMessage(payload, packetV5)
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeMessage(payload *bytes.Buffer, packetV5 *Packet) error {
|
|
|
|
if err := utils.BinaryDecoder(payload, &packetV5.IPVersion); err != nil {
|
|
|
|
return &DecoderError{err}
|
|
|
|
}
|
|
|
|
var ip []byte
|
|
|
|
if packetV5.IPVersion == 1 {
|
|
|
|
ip = make([]byte, 4)
|
|
|
|
if err := utils.BinaryDecoder(payload, ip); err != nil {
|
|
|
|
return &DecoderError{fmt.Errorf("IPv4 [%w]", err)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
} else if packetV5.IPVersion == 2 {
|
|
|
|
ip = make([]byte, 16)
|
|
|
|
if err := utils.BinaryDecoder(payload, ip); err != nil {
|
|
|
|
return &DecoderError{fmt.Errorf("IPv6 [%w]", err)}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
} else {
|
|
|
|
return &DecoderError{fmt.Errorf("unknown IP version %d", packetV5.IPVersion)}
|
|
|
|
}
|
2021-05-22 16:12:26 -07:00
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
packetV5.AgentIP = ip
|
|
|
|
if err := utils.BinaryDecoder(payload,
|
|
|
|
&packetV5.SubAgentId,
|
|
|
|
&packetV5.SequenceNumber,
|
|
|
|
&packetV5.Uptime,
|
2023-09-04 03:19:41 -07:00
|
|
|
&packetV5.SamplesCount,
|
|
|
|
); err != nil {
|
2023-08-09 19:47:20 -07:00
|
|
|
return &DecoderError{err}
|
|
|
|
}
|
|
|
|
if packetV5.SamplesCount > 1000 {
|
|
|
|
return &DecoderError{fmt.Errorf("too many samples: %d", packetV5.SamplesCount)}
|
|
|
|
}
|
2021-05-22 16:12:26 -07:00
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
packetV5.Samples = make([]interface{}, int(packetV5.SamplesCount)) // max size of 1000 for protection
|
|
|
|
for i := 0; i < int(packetV5.SamplesCount) && payload.Len() >= 8; i++ {
|
|
|
|
header := SampleHeader{}
|
|
|
|
if err := utils.BinaryDecoder(payload, &header.Format, &header.Length); err != nil {
|
|
|
|
return &DecoderError{fmt.Errorf("header [%w]", err)}
|
|
|
|
}
|
|
|
|
if int(header.Length) > payload.Len() {
|
|
|
|
break
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
sampleReader := bytes.NewBuffer(payload.Next(int(header.Length)))
|
2021-05-22 16:12:26 -07:00
|
|
|
|
2023-08-09 19:47:20 -07:00
|
|
|
sample, err := DecodeSample(&header, sampleReader)
|
|
|
|
if err != nil {
|
|
|
|
return &DecoderError{fmt.Errorf("sample [%w]", err)}
|
|
|
|
} else {
|
|
|
|
packetV5.Samples[i] = sample
|
|
|
|
}
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|
2023-08-09 19:47:20 -07:00
|
|
|
|
|
|
|
return nil
|
2021-05-22 16:12:26 -07:00
|
|
|
}
|