Skip to content

Commit

Permalink
NetFlow: Allow for zero scope fields in options template
Browse files Browse the repository at this point in the history
NetFlow v9 spec allows for options templates that contain no scope
fields. The netflow input was treating this case as an error and
discarding the template, but that is only applicable to IPFIX.
  • Loading branch information
adriansr committed Jan 14, 2020
1 parent dd553b3 commit 326f661
Showing 5 changed files with 16 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
@@ -230,6 +230,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
- Fix SSL config in input.yml for Filebeat httpjson input in the MISP module. {pull}14767[14767]
- Check content-type when creating new reader in s3 input. {pull}15252[15252] {issue}15225[15225]
- Fix session reset detection and a crash in Netflow input. {pull}14904[14904]
- netflow v9: Allow for options templates without scope fields. {pull}15449[15449]

*Heartbeat*

1 change: 1 addition & 0 deletions x-pack/filebeat/input/netflow/decoder/ipfix/decoder.go
Original file line number Diff line number Diff line change
@@ -108,6 +108,7 @@ func (d DecoderIPFIX) ReadOptionsTemplateFlowSet(buf *bytes.Buffer) (templates [
}
template.ID = tID
template.ScopeFields = scopeCount
template.IsOptions = true
templates = append(templates, &template)
}
return templates, nil
5 changes: 4 additions & 1 deletion x-pack/filebeat/input/netflow/decoder/template/template.go
Original file line number Diff line number Diff line change
@@ -29,6 +29,9 @@ type Template struct {
Length int
VariableLength bool
ScopeFields int
// IsOptions signals that this is an options template. Previously
// ScopeFields>0 was used for this, but that's unreliable under v9.
IsOptions bool
}

type FieldTemplate struct {
@@ -84,7 +87,7 @@ func (t *Template) Apply(data *bytes.Buffer, n int) ([]record.Record, error) {
}
}
makeFn := t.makeFlow
if t.ScopeFields > 0 {
if t.IsOptions {
makeFn = t.makeOptions
}
events := make([]record.Record, 0, alloc)
Original file line number Diff line number Diff line change
@@ -313,6 +313,7 @@ func TestOptionsTemplate_Apply(t *testing.T) {
record: Template{
Length: 7,
ScopeFields: 1,
IsOptions: true,
Fields: []FieldTemplate{
{Length: 4, Info: &fields.Field{Name: "sourceIPv4Address", Decoder: fields.Ipv4Address}},
{Length: 2, Info: &fields.Field{Name: "destinationTransportPort", Decoder: fields.Unsigned16}},
@@ -343,6 +344,7 @@ func TestOptionsTemplate_Apply(t *testing.T) {
record: Template{
Length: 7,
ScopeFields: 2,
IsOptions: true,
Fields: []FieldTemplate{
{Length: 4, Info: &fields.Field{Name: "sourceIPv4Address", Decoder: fields.Ipv4Address}},
{Length: 2, Info: &fields.Field{Name: "destinationTransportPort", Decoder: fields.Unsigned16}},
@@ -386,6 +388,7 @@ func TestOptionsTemplate_Apply(t *testing.T) {
record: Template{
Length: 7,
ScopeFields: 3,
IsOptions: true,
Fields: []FieldTemplate{
{Length: 4, Info: &fields.Field{Name: "sourceIPv4Address", Decoder: fields.Ipv4Address}},
{Length: 2, Info: &fields.Field{Name: "destinationTransportPort", Decoder: fields.Unsigned16}},
@@ -415,6 +418,7 @@ func TestOptionsTemplate_Apply(t *testing.T) {
record: Template{
Length: 7,
ScopeFields: 1,
IsOptions: true,
Fields: []FieldTemplate{
{Length: 4, Info: &fields.Field{Name: "sourceIPv4Address", Decoder: fields.Ipv4Address}},
{Length: 2, Info: &fields.Field{Name: "destinationTransportPort", Decoder: fields.Unsigned16}},
@@ -446,6 +450,7 @@ func TestOptionsTemplate_Apply(t *testing.T) {
record: Template{
Length: 7,
ScopeFields: 2,
IsOptions: true,
Fields: []FieldTemplate{
{Length: 4, Info: &fields.Field{Name: "sourceIPv4Address", Decoder: fields.Ipv4Address}},
{Length: 2, Info: &fields.Field{Name: "destinationTransportPort", Decoder: fields.Unsigned16}},
@@ -489,6 +494,7 @@ func TestOptionsTemplate_Apply(t *testing.T) {
record: Template{
Length: 6,
ScopeFields: 1,
IsOptions: true,
VariableLength: true,
Fields: []FieldTemplate{
{Length: 4, Info: &fields.Field{Name: "sourceIPv4Address", Decoder: fields.Ipv4Address}},
@@ -522,6 +528,7 @@ func TestOptionsTemplate_Apply(t *testing.T) {
record: Template{
Length: 6,
ScopeFields: 1,
IsOptions: true,
VariableLength: true,
Fields: []FieldTemplate{
{Length: 4, Info: &fields.Field{Name: "sourceIPv4Address", Decoder: fields.Ipv4Address}},
@@ -571,6 +578,7 @@ func TestOptionsTemplate_Apply(t *testing.T) {
Length: 6,
VariableLength: true,
ScopeFields: 2,
IsOptions: true,
Fields: []FieldTemplate{
{Length: 4, Info: &fields.Field{Name: "sourceIPv4Address", Decoder: fields.Ipv4Address}},
{Length: VariableLength, Info: &fields.Field{Name: "vpnIdentifier", Decoder: fields.OctetArray}},
3 changes: 2 additions & 1 deletion x-pack/filebeat/input/netflow/decoder/v9/decoder.go
Original file line number Diff line number Diff line change
@@ -184,7 +184,7 @@ func (d DecoderV9) ReadOptionsTemplateFlowSet(buf *bytes.Buffer) (templates []*t
if buf.Len() < int(length) {
return nil, io.EOF
}
if scopeLen == 0 || scopeLen&3 != 0 || optsLen&3 != 0 {
if (scopeLen+optsLen) == 0 || scopeLen&3 != 0 || optsLen&3 != 0 {
return nil, fmt.Errorf("bad length for options template. scope=%d options=%d", scopeLen, optsLen)
}
template, err := ReadFields(d, buf, (scopeLen+optsLen)/4)
@@ -193,6 +193,7 @@ func (d DecoderV9) ReadOptionsTemplateFlowSet(buf *bytes.Buffer) (templates []*t
}
template.ID = tID
template.ScopeFields = scopeLen / 4
template.IsOptions = true
templates = append(templates, &template)
}
return templates, nil

0 comments on commit 326f661

Please sign in to comment.