Skip to content

Commit

Permalink
sflow decodeExtendedRouterFlowRecord was missing address type detecti…
Browse files Browse the repository at this point in the history
…on, and decoding was off by 4 bytes if ExtendedRouterFlowRecord was not the last sample
  • Loading branch information
Jonathan Thurman committed Sep 6, 2017
1 parent 728d569 commit 9b17b2c
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 5 deletions.
17 changes: 15 additions & 2 deletions layers/sflow.go
Expand Up @@ -1034,7 +1034,10 @@ type SFlowExtendedRouterFlowRecord struct {
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Next Hop |
// | IP version of next hop router (1=v4|2=v6) |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / Next Hop address (v4=4byte|v6=16byte) /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Next Hop Source Mask |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Expand All @@ -1044,11 +1047,21 @@ type SFlowExtendedRouterFlowRecord struct {
func decodeExtendedRouterFlowRecord(data *[]byte) (SFlowExtendedRouterFlowRecord, error) {
er := SFlowExtendedRouterFlowRecord{}
var fdf SFlowFlowDataFormat
var ipType uint32

*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
er.EnterpriseID, er.Format = fdf.decode()
*data, er.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, er.NextHop = (*data)[4:], (*data)[:4]
*data, ipType = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])

if ipType == 1 {
*data, er.NextHop = (*data)[4:], (*data)[:4]
} else if ipType == 2 {
*data, er.NextHop = (*data)[16:], (*data)[:16]
} else {
return er, fmt.Errorf("Unknown Next Hop IP type: %d", ipType)
}

*data, er.NextHopSourceMask = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, er.NextHopDestinationMask = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return er, nil
Expand Down
76 changes: 73 additions & 3 deletions layers/sflow_test.go
Expand Up @@ -230,8 +230,9 @@ var SFlowTestPacket5 = []byte{
0x00, 0x00, 0x03, 0x34, 0x00, 0x00, 0x56, 0x02,
0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xea,
0x00, 0x00, 0x00, 0x0c, 0xc0, 0xa8, 0x01, 0x21,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01,
0xc0, 0xa8, 0x01, 0x21, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x80,
}

// expanded flow sample - Ipv4 Tunnel Ingress record
Expand Down Expand Up @@ -261,6 +262,23 @@ var SFlowTestPacket7 = []byte{
0x00, 0x00, 0x00, 0x00,
}

// expanded flow sample - extended router flow record IPv6 next hop
var SFlowTestPacket8 = []byte{
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
0xc0, 0xa8, 0x01, 0x12, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x7e, 0x32, 0xe0, 0xe4, 0x7c,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x01, 0x23,
0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x03, 0x34, 0x00, 0x00, 0x56, 0x02,
0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xea,
0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x02,
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,
}

func TestDecodeUDPSFlow(t *testing.T) {
p := gopacket.NewPacket(SFlowTestPacket1, LayerTypeEthernet, gopacket.Default)
if p.ErrorLayer() != nil {
Expand Down Expand Up @@ -1004,7 +1022,7 @@ func TestDecodeExtendedRouterFlow(t *testing.T) {
SFlowBaseFlowRecord: SFlowBaseFlowRecord{
EnterpriseID: 0x0,
Format: SFlowTypeExtendedRouterFlow,
FlowDataLength: 0xc,
FlowDataLength: 0x10,
},
NextHop: []byte{0xc0, 0xa8, 0x01, 0x21},
NextHopSourceMask: 0xffffffff,
Expand All @@ -1019,6 +1037,58 @@ func TestDecodeExtendedRouterFlow(t *testing.T) {
}
}

func TestDecodeExtendedRouterFlowIPv6(t *testing.T) {
p := gopacket.NewPacket(SFlowTestPacket8, LayerTypeSFlow, gopacket.Default)

if p.ErrorLayer() != nil {
t.Error("Failed to decode packet:", p.ErrorLayer().Error())
}
checkLayers(p, []gopacket.LayerType{LayerTypeSFlow}, t)

got := p.ApplicationLayer().(*SFlowDatagram)

want := &SFlowDatagram{
DatagramVersion: uint32(5),
AgentAddress: []byte{0xc0, 0xa8, 0x01, 0x12},
SubAgentID: uint32(0x00),
SequenceNumber: uint32(0x027e),
AgentUptime: uint32(0x32e0e47c),
SampleCount: uint32(1),
FlowSamples: []SFlowFlowSample{
SFlowFlowSample{
Format: SFlowTypeFlowSample,
SampleLength: 0x34,
SequenceNumber: 0x123,
SourceIDClass: 0x00,
SourceIDIndex: 0x1d,
SamplingRate: 0x100,
SamplePool: 0x334,
Dropped: 0x5602,
InputInterfaceFormat: 0x00,
InputInterface: 0x1d,
OutputInterfaceFormat: 0x00,
OutputInterface: 0x04,
RecordCount: 0x01,
Records: []SFlowRecord{
SFlowExtendedRouterFlowRecord{
SFlowBaseFlowRecord: SFlowBaseFlowRecord{
EnterpriseID: 0x0,
Format: SFlowTypeExtendedRouterFlow,
FlowDataLength: 0x1c,
},
NextHop: []byte{0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
NextHopSourceMask: 0xffffffff,
NextHopDestinationMask: 0xffffff80,
},
},
},
},
}
if !reflect.DeepEqual(want, got) {
t.Errorf("SFlow layer mismatch, \nwant:\n\n%#v\ngot:\n\n\n%#v\n\n", want, got)
}
}

func TestDecodeExtendedIpv4TunnelIngressFlow(t *testing.T) {
p := gopacket.NewPacket(SFlowTestPacket6, LayerTypeSFlow, gopacket.Default)

Expand Down

0 comments on commit 9b17b2c

Please sign in to comment.