mirror of
https://github.com/openobserve/goflow2.git
synced 2025-10-25 00:53:58 +00:00
refactor: v2 (#150)
This commit is contained in:
@@ -2,10 +2,9 @@ package sflow
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/netsampler/goflow2/decoders/utils"
|
||||
"github.com/netsampler/goflow2/v2/decoders/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -18,95 +17,49 @@ const (
|
||||
FORMAT_IPV6 = 4
|
||||
)
|
||||
|
||||
type ErrorDecodingSFlow struct {
|
||||
msg string
|
||||
type DecoderError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func NewErrorDecodingSFlow(msg string) *ErrorDecodingSFlow {
|
||||
return &ErrorDecodingSFlow{
|
||||
msg: msg,
|
||||
}
|
||||
func (e *DecoderError) Error() string {
|
||||
return fmt.Sprintf("sFlow %s", e.Err.Error())
|
||||
}
|
||||
|
||||
func (e *ErrorDecodingSFlow) Error() string {
|
||||
return fmt.Sprintf("Error decoding sFlow: %v", e.msg)
|
||||
func (e *DecoderError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
type ErrorDataFormat struct {
|
||||
dataformat uint32
|
||||
type FlowError struct {
|
||||
Format uint32
|
||||
Seq uint32
|
||||
Err error
|
||||
}
|
||||
|
||||
func NewErrorDataFormat(dataformat uint32) *ErrorDataFormat {
|
||||
return &ErrorDataFormat{
|
||||
dataformat: dataformat,
|
||||
}
|
||||
func (e *FlowError) Error() string {
|
||||
return fmt.Sprintf("[format:%d seq:%d] %s", e.Format, e.Seq, e.Err.Error())
|
||||
}
|
||||
|
||||
func (e *ErrorDataFormat) Error() string {
|
||||
return fmt.Sprintf("Unknown data format %v", e.dataformat)
|
||||
func (e *FlowError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
type ErrorIPVersion struct {
|
||||
version uint32
|
||||
type RecordError struct {
|
||||
DataFormat uint32
|
||||
Err error
|
||||
}
|
||||
|
||||
func NewErrorIPVersion(version uint32) *ErrorIPVersion {
|
||||
return &ErrorIPVersion{
|
||||
version: version,
|
||||
}
|
||||
func (e *RecordError) Error() string {
|
||||
return fmt.Sprintf("[data-format:%d] %s", e.DataFormat, e.Err.Error())
|
||||
}
|
||||
|
||||
func (e *ErrorIPVersion) Error() string {
|
||||
return fmt.Sprintf("Unknown IP version: %v", e.version)
|
||||
}
|
||||
|
||||
type ErrorVersion struct {
|
||||
version uint32
|
||||
}
|
||||
|
||||
func NewErrorVersion(version uint32) *ErrorVersion {
|
||||
return &ErrorVersion{
|
||||
version: version,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ErrorVersion) Error() string {
|
||||
return fmt.Sprintf("Unknown sFlow version %v (supported v5)", e.version)
|
||||
}
|
||||
|
||||
func DecodeCounterRecord(header *RecordHeader, payload *bytes.Buffer) (CounterRecord, error) {
|
||||
counterRecord := CounterRecord{
|
||||
Header: *header,
|
||||
}
|
||||
switch (*header).DataFormat {
|
||||
case 1:
|
||||
ifCounters := IfCounters{}
|
||||
err := utils.BinaryDecoder(payload, &ifCounters)
|
||||
if err != nil {
|
||||
return counterRecord, err
|
||||
}
|
||||
counterRecord.Data = ifCounters
|
||||
case 2:
|
||||
ethernetCounters := EthernetCounters{}
|
||||
err := utils.BinaryDecoder(payload, ðernetCounters)
|
||||
if err != nil {
|
||||
return counterRecord, err
|
||||
}
|
||||
counterRecord.Data = ethernetCounters
|
||||
default:
|
||||
counterRecord.Data = &FlowRecordRaw{
|
||||
Data: payload.Next(int(header.Length)),
|
||||
}
|
||||
}
|
||||
|
||||
return counterRecord, nil
|
||||
func (e *RecordError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
func DecodeIP(payload *bytes.Buffer) (uint32, []byte, error) {
|
||||
var ipVersion uint32
|
||||
err := utils.BinaryDecoder(payload, &ipVersion)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
if err := utils.BinaryDecoder(payload, &ipVersion); err != nil {
|
||||
return 0, nil, fmt.Errorf("DecodeIP: [%w]", err)
|
||||
}
|
||||
var ip []byte
|
||||
if ipVersion == 1 {
|
||||
@@ -114,173 +67,181 @@ func DecodeIP(payload *bytes.Buffer) (uint32, []byte, error) {
|
||||
} else if ipVersion == 2 {
|
||||
ip = make([]byte, 16)
|
||||
} else {
|
||||
return ipVersion, ip, NewErrorIPVersion(ipVersion)
|
||||
return ipVersion, ip, fmt.Errorf("DecodeIP: unknown IP version %d", ipVersion)
|
||||
}
|
||||
if payload.Len() >= len(ip) {
|
||||
err := utils.BinaryDecoder(payload, &ip)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
if err := utils.BinaryDecoder(payload, &ip); err != nil {
|
||||
return 0, nil, fmt.Errorf("DecodeIP: [%w]", err)
|
||||
}
|
||||
} else {
|
||||
return ipVersion, ip, NewErrorDecodingSFlow(fmt.Sprintf("Not enough data: %v, needs %v.", payload.Len(), len(ip)))
|
||||
return ipVersion, ip, fmt.Errorf("DecodeIP: truncated data (need %d, got %d)", len(ip), payload.Len())
|
||||
}
|
||||
return ipVersion, ip, nil
|
||||
}
|
||||
|
||||
func DecodeCounterRecord(header *RecordHeader, payload *bytes.Buffer) (CounterRecord, error) {
|
||||
counterRecord := CounterRecord{
|
||||
Header: *header,
|
||||
}
|
||||
switch header.DataFormat {
|
||||
case 1:
|
||||
var ifCounters IfCounters
|
||||
if err := utils.BinaryDecoder(payload, &ifCounters); err != nil {
|
||||
return counterRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
counterRecord.Data = ifCounters
|
||||
case 2:
|
||||
var ethernetCounters EthernetCounters
|
||||
if err := utils.BinaryDecoder(payload, ðernetCounters); err != nil {
|
||||
return counterRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
counterRecord.Data = ethernetCounters
|
||||
default:
|
||||
var rawRecord RawRecord
|
||||
rawRecord.Data = payload.Bytes()
|
||||
counterRecord.Data = rawRecord
|
||||
}
|
||||
|
||||
return counterRecord, nil
|
||||
}
|
||||
|
||||
func DecodeFlowRecord(header *RecordHeader, payload *bytes.Buffer) (FlowRecord, error) {
|
||||
flowRecord := FlowRecord{
|
||||
Header: *header,
|
||||
}
|
||||
switch (*header).DataFormat {
|
||||
var err error
|
||||
switch header.DataFormat {
|
||||
case FORMAT_EXT_SWITCH:
|
||||
extendedSwitch := ExtendedSwitch{}
|
||||
err := utils.BinaryDecoder(payload, &extendedSwitch)
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
return flowRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
flowRecord.Data = extendedSwitch
|
||||
case FORMAT_RAW_PKT:
|
||||
sampledHeader := SampledHeader{}
|
||||
err := utils.BinaryDecoder(payload, &(sampledHeader.Protocol), &(sampledHeader.FrameLength), &(sampledHeader.Stripped), &(sampledHeader.OriginalLength))
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
if err := utils.BinaryDecoder(payload,
|
||||
&sampledHeader.Protocol,
|
||||
&sampledHeader.FrameLength,
|
||||
&sampledHeader.Stripped,
|
||||
&sampledHeader.OriginalLength); err != nil {
|
||||
return flowRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
sampledHeader.HeaderData = payload.Bytes()
|
||||
flowRecord.Data = sampledHeader
|
||||
case FORMAT_IPV4:
|
||||
sampledIPBase := SampledIP_Base{
|
||||
SrcIP: make([]byte, 4),
|
||||
DstIP: make([]byte, 4),
|
||||
sampledIP := SampledIPv4{
|
||||
SampledIPBase: SampledIPBase{
|
||||
SrcIP: make([]byte, 4),
|
||||
DstIP: make([]byte, 4),
|
||||
},
|
||||
}
|
||||
err := utils.BinaryDecoder(payload, &sampledIPBase)
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
if err := utils.BinaryDecoder(payload, &sampledIP.SampledIPBase, &sampledIP.Tos); err != nil {
|
||||
return flowRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
sampledIPv4 := SampledIPv4{
|
||||
Base: sampledIPBase,
|
||||
}
|
||||
err = utils.BinaryDecoder(payload, &(sampledIPv4.Tos))
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
}
|
||||
flowRecord.Data = sampledIPv4
|
||||
flowRecord.Data = sampledIP
|
||||
case FORMAT_IPV6:
|
||||
sampledIPBase := SampledIP_Base{
|
||||
SrcIP: make([]byte, 16),
|
||||
DstIP: make([]byte, 16),
|
||||
sampledIP := SampledIPv6{
|
||||
SampledIPBase: SampledIPBase{
|
||||
SrcIP: make([]byte, 16),
|
||||
DstIP: make([]byte, 16),
|
||||
},
|
||||
}
|
||||
err := utils.BinaryDecoder(payload, &sampledIPBase)
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
if err := utils.BinaryDecoder(payload, &sampledIP.SampledIPBase, &sampledIP.Priority); err != nil {
|
||||
return flowRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
sampledIPv6 := SampledIPv6{
|
||||
Base: sampledIPBase,
|
||||
}
|
||||
err = utils.BinaryDecoder(payload, &(sampledIPv6.Priority))
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
}
|
||||
flowRecord.Data = sampledIPv6
|
||||
flowRecord.Data = sampledIP
|
||||
case FORMAT_EXT_ROUTER:
|
||||
extendedRouter := ExtendedRouter{}
|
||||
|
||||
ipVersion, ip, err := DecodeIP(payload)
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
if extendedRouter.NextHopIPVersion, extendedRouter.NextHop, err = DecodeIP(payload); err != nil {
|
||||
return flowRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
extendedRouter.NextHopIPVersion = ipVersion
|
||||
extendedRouter.NextHop = ip
|
||||
err = utils.BinaryDecoder(payload, &(extendedRouter.SrcMaskLen), &(extendedRouter.DstMaskLen))
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
if err := utils.BinaryDecoder(payload, &extendedRouter.SrcMaskLen, &extendedRouter.DstMaskLen); err != nil {
|
||||
return flowRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
flowRecord.Data = extendedRouter
|
||||
case FORMAT_EXT_GATEWAY:
|
||||
extendedGateway := ExtendedGateway{}
|
||||
ipVersion, ip, err := DecodeIP(payload)
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
if extendedGateway.NextHopIPVersion, extendedGateway.NextHop, err = DecodeIP(payload); err != nil {
|
||||
return flowRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
extendedGateway.NextHopIPVersion = ipVersion
|
||||
extendedGateway.NextHop = ip
|
||||
err = utils.BinaryDecoder(payload, &(extendedGateway.AS), &(extendedGateway.SrcAS), &(extendedGateway.SrcPeerAS),
|
||||
&(extendedGateway.ASDestinations))
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
if err := utils.BinaryDecoder(payload, &extendedGateway.AS, &extendedGateway.SrcAS, &extendedGateway.SrcPeerAS,
|
||||
&extendedGateway.ASDestinations); err != nil {
|
||||
return flowRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
var asPath []uint32
|
||||
if extendedGateway.ASDestinations != 0 {
|
||||
err := utils.BinaryDecoder(payload, &(extendedGateway.ASPathType), &(extendedGateway.ASPathLength))
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
if err := utils.BinaryDecoder(payload, &extendedGateway.ASPathType, &extendedGateway.ASPathLength); err != nil {
|
||||
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)}
|
||||
}
|
||||
if int(extendedGateway.ASPathLength) > payload.Len()-4 {
|
||||
return flowRecord, errors.New(fmt.Sprintf("Invalid AS path length: %v.", extendedGateway.ASPathLength))
|
||||
return flowRecord, &RecordError{header.DataFormat, fmt.Errorf("invalid AS path length: %d", extendedGateway.ASPathLength)}
|
||||
}
|
||||
asPath = make([]uint32, extendedGateway.ASPathLength)
|
||||
asPath = make([]uint32, extendedGateway.ASPathLength) // max size of 1000 for protection
|
||||
if len(asPath) > 0 {
|
||||
err = utils.BinaryDecoder(payload, asPath)
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
if err := utils.BinaryDecoder(payload, asPath); err != nil {
|
||||
return flowRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
}
|
||||
}
|
||||
extendedGateway.ASPath = asPath
|
||||
|
||||
err = utils.BinaryDecoder(payload, &(extendedGateway.CommunitiesLength))
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
if err := utils.BinaryDecoder(payload, &extendedGateway.CommunitiesLength); err != nil {
|
||||
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)}
|
||||
}
|
||||
if int(extendedGateway.CommunitiesLength) > payload.Len()-4 {
|
||||
return flowRecord, errors.New(fmt.Sprintf("Invalid Communities length: %v.", extendedGateway.ASPathLength))
|
||||
return flowRecord, &RecordError{header.DataFormat, fmt.Errorf("invalid communities length: %d", extendedGateway.ASPathLength)}
|
||||
}
|
||||
communities := make([]uint32, extendedGateway.CommunitiesLength)
|
||||
communities := make([]uint32, extendedGateway.CommunitiesLength) // max size of 1000 for protection
|
||||
if len(communities) > 0 {
|
||||
err = utils.BinaryDecoder(payload, communities)
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
if err := utils.BinaryDecoder(payload, communities); err != nil {
|
||||
return flowRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
}
|
||||
err = utils.BinaryDecoder(payload, &(extendedGateway.LocalPref))
|
||||
if err != nil {
|
||||
return flowRecord, err
|
||||
if err := utils.BinaryDecoder(payload, &extendedGateway.LocalPref); err != nil {
|
||||
return flowRecord, &RecordError{header.DataFormat, err}
|
||||
}
|
||||
extendedGateway.Communities = communities
|
||||
|
||||
flowRecord.Data = extendedGateway
|
||||
default:
|
||||
//return flowRecord, errors.New(fmt.Sprintf("Unknown data format %v.", (*header).DataFormat))
|
||||
flowRecord.Data = &FlowRecordRaw{
|
||||
Data: payload.Next(int(header.Length)),
|
||||
}
|
||||
var rawRecord RawRecord
|
||||
rawRecord.Data = payload.Bytes()
|
||||
flowRecord.Data = rawRecord
|
||||
}
|
||||
return flowRecord, nil
|
||||
}
|
||||
|
||||
func DecodeSample(header *SampleHeader, payload *bytes.Buffer) (interface{}, error) {
|
||||
format := (*header).Format
|
||||
format := header.Format
|
||||
var sample interface{}
|
||||
|
||||
err := utils.BinaryDecoder(payload, &((*header).SampleSequenceNumber))
|
||||
if err != nil {
|
||||
return sample, err
|
||||
if err := utils.BinaryDecoder(payload, &header.SampleSequenceNumber); err != nil {
|
||||
return sample, fmt.Errorf("header seq [%w]", err)
|
||||
}
|
||||
seq := header.SampleSequenceNumber
|
||||
if format == FORMAT_RAW_PKT || format == FORMAT_ETH {
|
||||
var sourceId uint32
|
||||
err = utils.BinaryDecoder(payload, &sourceId)
|
||||
if err != nil {
|
||||
return sample, err
|
||||
if err := utils.BinaryDecoder(payload, &sourceId); err != nil {
|
||||
return sample, &FlowError{format, seq, fmt.Errorf("header source [%w]", err)}
|
||||
}
|
||||
|
||||
(*header).SourceIdType = sourceId >> 24
|
||||
(*header).SourceIdValue = sourceId & 0x00ffffff
|
||||
header.SourceIdType = sourceId >> 24
|
||||
header.SourceIdValue = sourceId & 0x00ffffff
|
||||
} else if format == FORMAT_IPV4 || format == FORMAT_IPV6 {
|
||||
err = utils.BinaryDecoder(payload, &((*header).SourceIdType), &((*header).SourceIdValue))
|
||||
if err != nil {
|
||||
return sample, err
|
||||
if err := utils.BinaryDecoder(payload, &header.SourceIdType, &header.SourceIdValue); err != nil {
|
||||
return sample, &FlowError{format, seq, fmt.Errorf("header source [%w]", err)}
|
||||
}
|
||||
} else {
|
||||
return nil, NewErrorDataFormat(format)
|
||||
return sample, &FlowError{format, seq, fmt.Errorf("unknown format %d", format)}
|
||||
}
|
||||
|
||||
var recordsCount uint32
|
||||
@@ -291,34 +252,43 @@ func DecodeSample(header *SampleHeader, payload *bytes.Buffer) (interface{}, err
|
||||
flowSample = FlowSample{
|
||||
Header: *header,
|
||||
}
|
||||
err = utils.BinaryDecoder(payload, &(flowSample.SamplingRate), &(flowSample.SamplePool),
|
||||
&(flowSample.Drops), &(flowSample.Input), &(flowSample.Output), &(flowSample.FlowRecordsCount))
|
||||
if err != nil {
|
||||
return sample, err
|
||||
if err := utils.BinaryDecoder(payload, &flowSample.SamplingRate, &flowSample.SamplePool,
|
||||
&flowSample.Drops, &flowSample.Input, &flowSample.Output, &flowSample.FlowRecordsCount); err != nil {
|
||||
return sample, &FlowError{format, seq, fmt.Errorf("raw [%w]", err)}
|
||||
}
|
||||
recordsCount = flowSample.FlowRecordsCount
|
||||
flowSample.Records = make([]FlowRecord, recordsCount)
|
||||
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
|
||||
sample = flowSample
|
||||
} else if format == FORMAT_ETH || format == FORMAT_IPV6 {
|
||||
err = utils.BinaryDecoder(payload, &recordsCount)
|
||||
if err != nil {
|
||||
return sample, err
|
||||
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)}
|
||||
}
|
||||
counterSample = CounterSample{
|
||||
Header: *header,
|
||||
CounterRecordsCount: recordsCount,
|
||||
}
|
||||
counterSample.Records = make([]CounterRecord, recordsCount)
|
||||
counterSample.Records = make([]CounterRecord, recordsCount) // max size of 1000 for protection
|
||||
sample = counterSample
|
||||
} else if format == FORMAT_IPV4 {
|
||||
expandedFlowSample = ExpandedFlowSample{
|
||||
Header: *header,
|
||||
}
|
||||
err = utils.BinaryDecoder(payload, &(expandedFlowSample.SamplingRate), &(expandedFlowSample.SamplePool),
|
||||
&(expandedFlowSample.Drops), &(expandedFlowSample.InputIfFormat), &(expandedFlowSample.InputIfValue),
|
||||
&(expandedFlowSample.OutputIfFormat), &(expandedFlowSample.OutputIfValue), &(expandedFlowSample.FlowRecordsCount))
|
||||
if err != nil {
|
||||
return sample, err
|
||||
if err := utils.BinaryDecoder(payload,
|
||||
&expandedFlowSample.SamplingRate,
|
||||
&expandedFlowSample.SamplePool,
|
||||
&expandedFlowSample.Drops,
|
||||
&expandedFlowSample.InputIfFormat,
|
||||
&expandedFlowSample.InputIfValue,
|
||||
&expandedFlowSample.OutputIfFormat,
|
||||
&expandedFlowSample.OutputIfValue,
|
||||
&expandedFlowSample.FlowRecordsCount); err != nil {
|
||||
return sample, &FlowError{format, seq, fmt.Errorf("IPv4 [%w]", err)}
|
||||
}
|
||||
recordsCount = expandedFlowSample.FlowRecordsCount
|
||||
expandedFlowSample.Records = make([]FlowRecord, recordsCount)
|
||||
@@ -326,9 +296,8 @@ func DecodeSample(header *SampleHeader, payload *bytes.Buffer) (interface{}, err
|
||||
}
|
||||
for i := 0; i < int(recordsCount) && payload.Len() >= 8; i++ {
|
||||
recordHeader := RecordHeader{}
|
||||
err = utils.BinaryDecoder(payload, &(recordHeader.DataFormat), &(recordHeader.Length))
|
||||
if err != nil {
|
||||
return sample, err
|
||||
if err := utils.BinaryDecoder(payload, &recordHeader.DataFormat, &recordHeader.Length); err != nil {
|
||||
return sample, &FlowError{format, seq, fmt.Errorf("record header [%w]", err)}
|
||||
}
|
||||
if int(recordHeader.Length) > payload.Len() {
|
||||
break
|
||||
@@ -337,7 +306,7 @@ func DecodeSample(header *SampleHeader, payload *bytes.Buffer) (interface{}, err
|
||||
if format == FORMAT_RAW_PKT || format == FORMAT_IPV4 {
|
||||
record, err := DecodeFlowRecord(&recordHeader, recordReader)
|
||||
if err != nil {
|
||||
continue
|
||||
return sample, &FlowError{format, seq, fmt.Errorf("record [%w]", err)}
|
||||
}
|
||||
if format == FORMAT_RAW_PKT {
|
||||
flowSample.Records[i] = record
|
||||
@@ -347,7 +316,7 @@ func DecodeSample(header *SampleHeader, payload *bytes.Buffer) (interface{}, err
|
||||
} else if format == FORMAT_ETH || format == FORMAT_IPV6 {
|
||||
record, err := DecodeCounterRecord(&recordHeader, recordReader)
|
||||
if err != nil {
|
||||
continue
|
||||
return sample, &FlowError{format, seq, fmt.Errorf("counter [%w]", err)}
|
||||
}
|
||||
counterSample.Records[i] = record
|
||||
}
|
||||
@@ -355,63 +324,68 @@ func DecodeSample(header *SampleHeader, payload *bytes.Buffer) (interface{}, err
|
||||
return sample, nil
|
||||
}
|
||||
|
||||
func DecodeMessage(payload *bytes.Buffer) (interface{}, error) {
|
||||
func DecodeMessageVersion(payload *bytes.Buffer, packetV5 *Packet) error {
|
||||
var version uint32
|
||||
err := utils.BinaryDecoder(payload, &version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err := utils.BinaryDecoder(payload, &version); err != nil {
|
||||
return &DecoderError{err}
|
||||
}
|
||||
packetV5 := Packet{}
|
||||
if version == 5 {
|
||||
packetV5.Version = version
|
||||
err = utils.BinaryDecoder(payload, &(packetV5.IPVersion))
|
||||
if err != nil {
|
||||
return packetV5, err
|
||||
}
|
||||
var ip []byte
|
||||
if packetV5.IPVersion == 1 {
|
||||
ip = make([]byte, 4)
|
||||
err = utils.BinaryDecoder(payload, ip)
|
||||
if err != nil {
|
||||
return packetV5, err
|
||||
}
|
||||
} else if packetV5.IPVersion == 2 {
|
||||
ip = make([]byte, 16)
|
||||
err = utils.BinaryDecoder(payload, ip)
|
||||
if err != nil {
|
||||
return packetV5, err
|
||||
}
|
||||
} else {
|
||||
return nil, NewErrorIPVersion(packetV5.IPVersion)
|
||||
}
|
||||
packetV5.Version = version
|
||||
|
||||
packetV5.AgentIP = ip
|
||||
err = utils.BinaryDecoder(payload, &(packetV5.SubAgentId), &(packetV5.SequenceNumber), &(packetV5.Uptime), &(packetV5.SamplesCount))
|
||||
if err != nil {
|
||||
return packetV5, err
|
||||
}
|
||||
packetV5.Samples = make([]interface{}, int(packetV5.SamplesCount))
|
||||
for i := 0; i < int(packetV5.SamplesCount) && payload.Len() >= 8; i++ {
|
||||
header := SampleHeader{}
|
||||
err = utils.BinaryDecoder(payload, &(header.Format), &(header.Length))
|
||||
if err != nil {
|
||||
return packetV5, err
|
||||
}
|
||||
if int(header.Length) > payload.Len() {
|
||||
break
|
||||
}
|
||||
sampleReader := bytes.NewBuffer(payload.Next(int(header.Length)))
|
||||
|
||||
sample, err := DecodeSample(&header, sampleReader)
|
||||
if err != nil {
|
||||
continue
|
||||
} else {
|
||||
packetV5.Samples[i] = sample
|
||||
}
|
||||
}
|
||||
|
||||
return packetV5, nil
|
||||
} else {
|
||||
return nil, NewErrorVersion(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)}
|
||||
}
|
||||
} else if packetV5.IPVersion == 2 {
|
||||
ip = make([]byte, 16)
|
||||
if err := utils.BinaryDecoder(payload, ip); err != nil {
|
||||
return &DecoderError{fmt.Errorf("IPv6 [%w]", err)}
|
||||
}
|
||||
} else {
|
||||
return &DecoderError{fmt.Errorf("unknown IP version %d", packetV5.IPVersion)}
|
||||
}
|
||||
|
||||
packetV5.AgentIP = ip
|
||||
if err := utils.BinaryDecoder(payload,
|
||||
&packetV5.SubAgentId,
|
||||
&packetV5.SequenceNumber,
|
||||
&packetV5.Uptime,
|
||||
&packetV5.SamplesCount); err != nil {
|
||||
return &DecoderError{err}
|
||||
}
|
||||
if packetV5.SamplesCount > 1000 {
|
||||
return &DecoderError{fmt.Errorf("too many samples: %d", packetV5.SamplesCount)}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
sampleReader := bytes.NewBuffer(payload.Next(int(header.Length)))
|
||||
|
||||
sample, err := DecodeSample(&header, sampleReader)
|
||||
if err != nil {
|
||||
return &DecoderError{fmt.Errorf("sample [%w]", err)}
|
||||
} else {
|
||||
packetV5.Samples[i] = sample
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user