logstash-codec-netflow 2.1.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -19
- data/CONTRIBUTORS +0 -12
- data/Gemfile +2 -0
- data/lib/logstash/codecs/netflow.rb +27 -277
- data/lib/logstash/codecs/netflow/util.rb +6 -60
- data/logstash-codec-netflow.gemspec +3 -4
- data/spec/codecs/netflow_spec.rb +20 -265
- metadata +27 -29
- data/lib/logstash/codecs/netflow/iana2yaml.rb +0 -77
- data/lib/logstash/codecs/netflow/ipfix.yaml +0 -2333
- data/spec/codecs/ipfix.dat +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95e7e7d16a47ec1ae4535979d9792b6051e6d36f
|
4
|
+
data.tar.gz: b101a6c29ebc0fa9d65ade94fb14160cd7a1df33
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 776e788d36ccdb7c30844b7f4b7925eb7c4fc5a5c40371b3330376bb00b659a4338a312160634813dfe4d6f14d98fbf4f9d83c9da3533ec954c8460b749a7e04
|
7
|
+
data.tar.gz: 135bdba032f43b7855c4bf63fcf3468b40eb8faaefbb70ef9ada0ff63e2561cc230dcc87671d7f92afac0d702b1b406cccf46192ac4f12a15a351c46bb897f80
|
data/CHANGELOG.md
CHANGED
@@ -1,30 +1,13 @@
|
|
1
|
-
##
|
2
|
-
|
3
|
-
- Small update due to breaking change in BinData gem (issue #41)
|
4
|
-
|
5
|
-
## 2.1.0
|
6
|
-
|
7
|
-
- Added IPFIX support
|
8
|
-
- Fixed exception if Netflow data contains MAC addresses (issue #26, issue #34)
|
9
|
-
- Fixed exceptions when receiving invalid Netflow v5 and v9 data (issue #17, issue 18)
|
10
|
-
- Fixed decoding Netflow templates from multiple (non-identical) exporters
|
11
|
-
- Add support for Cisco ASA fields
|
12
|
-
- Add support for Netflow 9 options template with scope fields
|
13
|
-
|
1
|
+
## 3.0.0
|
2
|
+
- Update the plugin to the version 2.0 of the plugin api, this change is required for Logstash 5.0 compatibility. See https://github.com/elastic/logstash/issues/5141
|
14
3
|
# 2.0.5
|
15
|
-
|
16
4
|
- Depend on logstash-core-plugin-api instead of logstash-core, removing the need to mass update plugins on major releases of logstash
|
17
|
-
|
18
5
|
# 2.0.4
|
19
|
-
|
20
6
|
- New dependency requirements for logstash-core for the 5.0 release
|
21
|
-
|
22
7
|
## 2.0.3
|
23
|
-
|
24
8
|
- Fixed JSON compare flaw in specs
|
25
9
|
|
26
10
|
## 2.0.0
|
27
|
-
|
28
11
|
- Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
|
29
12
|
instead of using Thread.raise on the plugins' threads. Ref: https://github.com/elastic/logstash/pull/3895
|
30
13
|
- Dependency on logstash-core update to 2.0
|
data/CONTRIBUTORS
CHANGED
@@ -3,24 +3,12 @@ reports, or in general have helped logstash along its way.
|
|
3
3
|
|
4
4
|
Contributors:
|
5
5
|
* Aaron Mildenstein (untergeek)
|
6
|
-
* Adam Kaminski (thimslugga)
|
7
6
|
* Colin Surprenant (colinsurprenant)
|
8
7
|
* Jordan Sissel (jordansissel)
|
9
|
-
* Jorrit Folmer (jorritfolmer)
|
10
8
|
* Matt Dainty (bodgit)
|
11
|
-
* Paul Warren (pwarren)
|
12
9
|
* Pier-Hugues Pellerin (ph)
|
13
|
-
* Pulkit Agrawal (propulkit)
|
14
10
|
* Richard Pijnenburg (electrical)
|
15
|
-
* Salvador Ferrer (salva-ferrer)
|
16
|
-
* Will Rigby (wrigby)
|
17
|
-
* Rojuinex
|
18
11
|
* debadair
|
19
|
-
* hkshirish
|
20
|
-
* jstopinsek
|
21
|
-
|
22
|
-
Maintainer:
|
23
|
-
* Jorrit Folmer (jorritfolmer)
|
24
12
|
|
25
13
|
Note: If you've sent us patches, bug reports, or otherwise contributed to
|
26
14
|
Logstash, and you aren't on the list above and want to be, please let us know
|
data/Gemfile
CHANGED
@@ -3,59 +3,7 @@ require "logstash/filters/base"
|
|
3
3
|
require "logstash/namespace"
|
4
4
|
require "logstash/timestamp"
|
5
5
|
|
6
|
-
# The "netflow" codec is
|
7
|
-
#
|
8
|
-
# ==== Supported Netflow/IPFIX exporters
|
9
|
-
#
|
10
|
-
# The following Netflow/IPFIX exporters are known to work with the most recent version of the netflow codec:
|
11
|
-
#
|
12
|
-
# [cols="6,^2,^2,^2,12",options="header"]
|
13
|
-
# |===========================================================================================
|
14
|
-
# |Netflow exporter | v5 | v9 | IPFIX | Remarks
|
15
|
-
# |Softflowd | y | y | y | IPFIX supported in https://github.com/djmdjm/softflowd
|
16
|
-
# |nProbe | y | y | y |
|
17
|
-
# |ipt_NETFLOW | y | y | y |
|
18
|
-
# |Cisco ASA | | y | |
|
19
|
-
# |Cisco IOS 12.x | | y | |
|
20
|
-
# |fprobe | y | | |
|
21
|
-
# |===========================================================================================
|
22
|
-
#
|
23
|
-
# ==== Usage
|
24
|
-
#
|
25
|
-
# Example Logstash configuration:
|
26
|
-
#
|
27
|
-
# [source]
|
28
|
-
# -----------------------------
|
29
|
-
# input {
|
30
|
-
# udp {
|
31
|
-
# host => localhost
|
32
|
-
# port => 2055
|
33
|
-
# codec => netflow {
|
34
|
-
# versions => [5, 9]
|
35
|
-
# }
|
36
|
-
# type => netflow
|
37
|
-
# }
|
38
|
-
# udp {
|
39
|
-
# host => localhost
|
40
|
-
# port => 4739
|
41
|
-
# codec => netflow {
|
42
|
-
# versions => [10]
|
43
|
-
# target => ipfix
|
44
|
-
# }
|
45
|
-
# type => ipfix
|
46
|
-
# }
|
47
|
-
# tcp {
|
48
|
-
# host => localhost
|
49
|
-
# port => 4739
|
50
|
-
# codec => netflow {
|
51
|
-
# versions => [10]
|
52
|
-
# target => ipfix
|
53
|
-
# }
|
54
|
-
# type => ipfix
|
55
|
-
# }
|
56
|
-
# }
|
57
|
-
# -----------------------------
|
58
|
-
|
6
|
+
# The "netflow" codec is for decoding Netflow v5/v9 flows.
|
59
7
|
class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
60
8
|
config_name "netflow"
|
61
9
|
|
@@ -66,7 +14,7 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
66
14
|
config :target, :validate => :string, :default => "netflow"
|
67
15
|
|
68
16
|
# Specify which Netflow versions you will accept.
|
69
|
-
config :versions, :validate => :array, :default => [5, 9
|
17
|
+
config :versions, :validate => :array, :default => [5, 9]
|
70
18
|
|
71
19
|
# Override YAML file containing Netflow field definitions
|
72
20
|
#
|
@@ -83,25 +31,7 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
83
31
|
# - :skip
|
84
32
|
#
|
85
33
|
# See <https://github.com/logstash-plugins/logstash-codec-netflow/blob/master/lib/logstash/codecs/netflow/netflow.yaml> for the base set.
|
86
|
-
config :
|
87
|
-
|
88
|
-
# Override YAML file containing IPFIX field definitions
|
89
|
-
#
|
90
|
-
# Very similar to the Netflow version except there is a top level Private
|
91
|
-
# Enterprise Number (PEN) key added:
|
92
|
-
#
|
93
|
-
# ---
|
94
|
-
# pen:
|
95
|
-
# id:
|
96
|
-
# - :uintN or :ip4_addr or :ip6_addr or :mac_addr or :string
|
97
|
-
# - :name
|
98
|
-
# id:
|
99
|
-
# - :skip
|
100
|
-
#
|
101
|
-
# There is an implicit PEN 0 for the standard fields.
|
102
|
-
#
|
103
|
-
# See <https://github.com/logstash-plugins/logstash-codec-netflow/blob/master/lib/logstash/codecs/netflow/ipfix.yaml> for the base set.
|
104
|
-
config :ipfix_definitions, :validate => :path
|
34
|
+
config :definitions, :validate => :path
|
105
35
|
|
106
36
|
NETFLOW5_FIELDS = ['version', 'flow_seq_num', 'engine_type', 'engine_id', 'sampling_algorithm', 'sampling_interval', 'flow_records']
|
107
37
|
NETFLOW9_FIELDS = ['version', 'flow_seq_num']
|
@@ -112,7 +42,6 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
112
42
|
4 => :scope_netflow_cache,
|
113
43
|
5 => :scope_template,
|
114
44
|
}
|
115
|
-
IPFIX_FIELDS = ['version']
|
116
45
|
SWITCHED = /_switched$/
|
117
46
|
FLOWSET_ID = "flowset_id"
|
118
47
|
|
@@ -123,16 +52,26 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
123
52
|
|
124
53
|
def register
|
125
54
|
require "logstash/codecs/netflow/util"
|
126
|
-
@
|
127
|
-
@ipfix_templates = Vash.new()
|
55
|
+
@templates = Vash.new()
|
128
56
|
|
129
57
|
# Path to default Netflow v9 field definitions
|
130
58
|
filename = ::File.expand_path('netflow/netflow.yaml', ::File.dirname(__FILE__))
|
131
|
-
@netflow_fields = load_definitions(filename, @netflow_definitions)
|
132
59
|
|
133
|
-
|
134
|
-
|
135
|
-
|
60
|
+
begin
|
61
|
+
@fields = YAML.load_file(filename)
|
62
|
+
rescue Exception => e
|
63
|
+
raise "#{self.class.name}: Bad syntax in definitions file #{filename}"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Allow the user to augment/override/rename the supported Netflow fields
|
67
|
+
if @definitions
|
68
|
+
raise "#{self.class.name}: definitions file #{@definitions} does not exists" unless File.exists?(@definitions)
|
69
|
+
begin
|
70
|
+
@fields.merge!(YAML.load_file(@definitions))
|
71
|
+
rescue Exception => e
|
72
|
+
raise "#{self.class.name}: Bad syntax in definitions file #{@definitions}"
|
73
|
+
end
|
74
|
+
end
|
136
75
|
end # def register
|
137
76
|
|
138
77
|
def decode(payload, metadata = nil, &block)
|
@@ -157,11 +96,6 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
157
96
|
decode_netflow9(flowset, record).each{|event| yield(event)}
|
158
97
|
end
|
159
98
|
end
|
160
|
-
elsif header.version == 10
|
161
|
-
flowset = IpfixPDU.read(payload)
|
162
|
-
flowset.records.each do |record|
|
163
|
-
decode_ipfix(flowset, record).each { |event| yield(event) }
|
164
|
-
end
|
165
99
|
else
|
166
100
|
@logger.warn("Unsupported Netflow version v#{header.version}")
|
167
101
|
end
|
@@ -217,7 +151,7 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
217
151
|
record.flowset_data.templates.each do |template|
|
218
152
|
catch (:field) do
|
219
153
|
fields = []
|
220
|
-
template.
|
154
|
+
template.fields.each do |field|
|
221
155
|
entry = netflow_field_for(field.field_type, field.field_length)
|
222
156
|
throw :field unless entry
|
223
157
|
fields += entry
|
@@ -229,9 +163,9 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
229
163
|
else
|
230
164
|
key = "#{flowset.source_id}|#{template.template_id}"
|
231
165
|
end
|
232
|
-
@
|
166
|
+
@templates[key, @cache_ttl] = BinData::Struct.new(:endian => :big, :fields => fields)
|
233
167
|
# Purge any expired templates
|
234
|
-
@
|
168
|
+
@templates.cleanup!
|
235
169
|
end
|
236
170
|
end
|
237
171
|
when 1
|
@@ -254,9 +188,9 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
254
188
|
else
|
255
189
|
key = "#{flowset.source_id}|#{template.template_id}"
|
256
190
|
end
|
257
|
-
@
|
191
|
+
@templates[key, @cache_ttl] = BinData::Struct.new(:endian => :big, :fields => fields)
|
258
192
|
# Purge any expired templates
|
259
|
-
@
|
193
|
+
@templates.cleanup!
|
260
194
|
end
|
261
195
|
end
|
262
196
|
when 256..65535
|
@@ -267,7 +201,7 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
267
201
|
else
|
268
202
|
key = "#{flowset.source_id}|#{record.flowset_id}"
|
269
203
|
end
|
270
|
-
template = @
|
204
|
+
template = @templates[key]
|
271
205
|
|
272
206
|
unless template
|
273
207
|
#@logger.warn("No matching template for flow id #{record.flowset_id} from #{event["source"]}")
|
@@ -324,164 +258,14 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
324
258
|
@logger.warn("Invalid netflow packet received (#{e})")
|
325
259
|
end
|
326
260
|
|
327
|
-
def decode_ipfix(flowset, record)
|
328
|
-
events = []
|
329
|
-
|
330
|
-
case record.flowset_id
|
331
|
-
when 2
|
332
|
-
# Template flowset
|
333
|
-
record.flowset_data.templates.each do |template|
|
334
|
-
catch (:field) do
|
335
|
-
fields = []
|
336
|
-
template.record_fields.each do |field|
|
337
|
-
field_type = field.field_type
|
338
|
-
field_length = field.field_length
|
339
|
-
enterprise_id = field.enterprise ? field.enterprise_id : 0
|
340
|
-
|
341
|
-
if field.field_length == 0xffff
|
342
|
-
# FIXME
|
343
|
-
@logger.warn("Cowardly refusing to deal with variable length encoded field", :type => field_type, :enterprise => enterprise_id)
|
344
|
-
throw :field
|
345
|
-
end
|
346
|
-
|
347
|
-
if enterprise_id == 0
|
348
|
-
case field_type
|
349
|
-
when 291, 292, 293
|
350
|
-
# FIXME
|
351
|
-
@logger.warn("Cowardly refusing to deal with complex data types", :type => field_type, :enterprise => enterprise_id)
|
352
|
-
throw :field
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
entry = ipfix_field_for(field_type, enterprise_id, field.field_length)
|
357
|
-
throw :field unless entry
|
358
|
-
fields += entry
|
359
|
-
end
|
360
|
-
# FIXME Source IP address required in key
|
361
|
-
key = "#{flowset.observation_domain_id}|#{template.template_id}"
|
362
|
-
@ipfix_templates[key, @cache_ttl] = BinData::Struct.new(:endian => :big, :fields => fields)
|
363
|
-
# Purge any expired templates
|
364
|
-
@ipfix_templates.cleanup!
|
365
|
-
end
|
366
|
-
end
|
367
|
-
when 3
|
368
|
-
# Options template flowset
|
369
|
-
record.flowset_data.templates.each do |template|
|
370
|
-
catch (:field) do
|
371
|
-
fields = []
|
372
|
-
(template.scope_fields.to_ary + template.option_fields.to_ary).each do |field|
|
373
|
-
field_type = field.field_type
|
374
|
-
field_length = field.field_length
|
375
|
-
enterprise_id = field.enterprise ? field.enterprise_id : 0
|
376
|
-
|
377
|
-
if field.field_length == 0xffff
|
378
|
-
# FIXME
|
379
|
-
@logger.warn("Cowardly refusing to deal with variable length encoded field", :type => field_type, :enterprise => enterprise_id)
|
380
|
-
throw :field
|
381
|
-
end
|
382
|
-
|
383
|
-
if enterprise_id == 0
|
384
|
-
case field_type
|
385
|
-
when 291, 292, 293
|
386
|
-
# FIXME
|
387
|
-
@logger.warn("Cowardly refusing to deal with complex data types", :type => field_type, :enterprise => enterprise_id)
|
388
|
-
throw :field
|
389
|
-
end
|
390
|
-
end
|
391
|
-
|
392
|
-
entry = ipfix_field_for(field_type, enterprise_id, field.field_length)
|
393
|
-
throw :field unless entry
|
394
|
-
fields += entry
|
395
|
-
end
|
396
|
-
# FIXME Source IP address required in key
|
397
|
-
key = "#{flowset.observation_domain_id}|#{template.template_id}"
|
398
|
-
@ipfix_templates[key, @cache_ttl] = BinData::Struct.new(:endian => :big, :fields => fields)
|
399
|
-
# Purge any expired templates
|
400
|
-
@ipfix_templates.cleanup!
|
401
|
-
end
|
402
|
-
end
|
403
|
-
when 256..65535
|
404
|
-
# Data flowset
|
405
|
-
key = "#{flowset.observation_domain_id}|#{record.flowset_id}"
|
406
|
-
template = @ipfix_templates[key]
|
407
|
-
|
408
|
-
unless template
|
409
|
-
@logger.warn("No matching template for flow id #{record.flowset_id}")
|
410
|
-
next
|
411
|
-
end
|
412
|
-
|
413
|
-
array = BinData::Array.new(:type => template, :read_until => :eof)
|
414
|
-
records = array.read(record.flowset_data)
|
415
|
-
|
416
|
-
records.each do |r|
|
417
|
-
event = {
|
418
|
-
LogStash::Event::TIMESTAMP => LogStash::Timestamp.at(flowset.unix_sec),
|
419
|
-
@target => {}
|
420
|
-
}
|
421
|
-
|
422
|
-
IPFIX_FIELDS.each do |f|
|
423
|
-
event[@target][f] = flowset[f].snapshot
|
424
|
-
end
|
425
|
-
|
426
|
-
r.each_pair do |k, v|
|
427
|
-
case k.to_s
|
428
|
-
when /^flow(?:Start|End)Seconds$/
|
429
|
-
event[@target][k.to_s] = LogStash::Timestamp.at(v.snapshot).to_iso8601
|
430
|
-
when /^flow(?:Start|End)(Milli|Micro|Nano)seconds$/
|
431
|
-
divisor =
|
432
|
-
case $1
|
433
|
-
when 'Milli'
|
434
|
-
1_000
|
435
|
-
when 'Micro'
|
436
|
-
1_000_000
|
437
|
-
when 'Nano'
|
438
|
-
1_000_000_000
|
439
|
-
end
|
440
|
-
event[@target][k.to_s] = LogStash::Timestamp.at(v.snapshot.to_f / divisor).to_iso8601
|
441
|
-
else
|
442
|
-
event[@target][k.to_s] = v.snapshot
|
443
|
-
end
|
444
|
-
end
|
445
|
-
|
446
|
-
events << LogStash::Event.new(event)
|
447
|
-
end
|
448
|
-
else
|
449
|
-
@logger.warn("Unsupported flowset id #{record.flowset_id}")
|
450
|
-
end
|
451
|
-
|
452
|
-
events
|
453
|
-
rescue BinData::ValidityError => e
|
454
|
-
@logger.warn("Invalid IPFIX packet received (#{e})")
|
455
|
-
end
|
456
|
-
|
457
|
-
def load_definitions(defaults, extra)
|
458
|
-
begin
|
459
|
-
fields = YAML.load_file(defaults)
|
460
|
-
rescue Exception => e
|
461
|
-
raise "#{self.class.name}: Bad syntax in definitions file #{defaults}"
|
462
|
-
end
|
463
|
-
|
464
|
-
# Allow the user to augment/override/rename the default fields
|
465
|
-
if extra
|
466
|
-
raise "#{self.class.name}: definitions file #{extra} does not exist" unless File.exists?(extra)
|
467
|
-
begin
|
468
|
-
fields.merge!(YAML.load_file(extra))
|
469
|
-
rescue Exception => e
|
470
|
-
raise "#{self.class.name}: Bad syntax in definitions file #{extra}"
|
471
|
-
end
|
472
|
-
end
|
473
|
-
|
474
|
-
fields
|
475
|
-
end
|
476
|
-
|
477
261
|
def uint_field(length, default)
|
478
262
|
# If length is 4, return :uint32, etc. and use default if length is 0
|
479
263
|
("uint" + (((length > 0) ? length : default) * 8).to_s).to_sym
|
480
264
|
end # def uint_field
|
481
265
|
|
482
266
|
def netflow_field_for(type, length)
|
483
|
-
if @
|
484
|
-
field = @
|
267
|
+
if @fields.include?(type)
|
268
|
+
field = @fields[type].clone
|
485
269
|
if field.is_a?(Array)
|
486
270
|
|
487
271
|
field[0] = uint_field(length, field[0]) if field[0].is_a?(Integer)
|
@@ -507,38 +291,4 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
507
291
|
nil
|
508
292
|
end
|
509
293
|
end # def netflow_field_for
|
510
|
-
|
511
|
-
def ipfix_field_for(type, enterprise, length)
|
512
|
-
if @ipfix_fields.include?(enterprise)
|
513
|
-
if @ipfix_fields[enterprise].include?(type)
|
514
|
-
field = @ipfix_fields[enterprise][type].clone
|
515
|
-
else
|
516
|
-
@logger.warn("Unsupported enterprise field", :type => type, :enterprise => enterprise, :length => length)
|
517
|
-
end
|
518
|
-
else
|
519
|
-
@logger.warn("Unsupported enterprise", :enterprise => enterprise)
|
520
|
-
end
|
521
|
-
|
522
|
-
return nil unless field
|
523
|
-
|
524
|
-
if field.is_a?(Array)
|
525
|
-
case field[0]
|
526
|
-
when :skip
|
527
|
-
field += [nil, {:length => length}]
|
528
|
-
when :string
|
529
|
-
field += [{:length => length, :trim_padding => true}]
|
530
|
-
when :uint64
|
531
|
-
field[0] = uint_field(length, 8)
|
532
|
-
when :uint32
|
533
|
-
field[0] = uint_field(length, 4)
|
534
|
-
when :uint16
|
535
|
-
field[0] = uint_field(length, 2)
|
536
|
-
end
|
537
|
-
|
538
|
-
@logger.debug("Definition complete", :field => field)
|
539
|
-
[field]
|
540
|
-
else
|
541
|
-
@logger.warn("Definition should be an array", :field => field)
|
542
|
-
end
|
543
|
-
end
|
544
294
|
end # class LogStash::Filters::Netflow
|