refactor: v2 (#150)

This commit is contained in:
Louis
2023-08-09 19:47:20 -07:00
committed by GitHub
parent 1298b9408d
commit ae56e41786
75 changed files with 4905 additions and 4828 deletions

View File

@@ -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, &ethernetCounters)
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, &ethernetCounters); 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
}