logstash-codec-netflow 2.0.5 → 2.1.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 +15 -0
- data/CONTRIBUTORS +12 -0
- data/Gemfile +1 -1
- data/LICENSE +1 -1
- data/README.md +12 -3
- data/lib/logstash/codecs/netflow.rb +314 -32
- data/lib/logstash/codecs/netflow/iana2yaml.rb +77 -0
- data/lib/logstash/codecs/netflow/ipfix.yaml +2333 -0
- data/lib/logstash/codecs/netflow/netflow.yaml +86 -2
- data/lib/logstash/codecs/netflow/util.rb +77 -10
- data/logstash-codec-netflow.gemspec +4 -3
- data/spec/codecs/ipfix.dat +0 -0
- data/spec/codecs/netflow5_test_invalid01.dat +0 -0
- data/spec/codecs/netflow5_test_invalid02.dat +0 -0
- data/spec/codecs/netflow9_test_invalid01.dat +0 -0
- data/spec/codecs/netflow9_test_macaddr_data.dat +0 -0
- data/spec/codecs/netflow9_test_macaddr_tpl.dat +0 -0
- data/spec/codecs/netflow9_test_nprobe_data.dat +0 -0
- data/spec/codecs/netflow9_test_nprobe_tpl.dat +0 -0
- data/spec/codecs/netflow9_test_softflowd_tpl_data.dat +0 -0
- data/spec/codecs/netflow9_test_valid01.dat +0 -0
- data/spec/codecs/netflow9_test_valid_cisco_asa_data.dat +0 -0
- data/spec/codecs/netflow9_test_valid_cisco_asa_tpl.dat +0 -0
- data/spec/codecs/netflow_spec.rb +524 -53
- metadata +49 -25
- data/spec/codecs/netflow9.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: 918358ce2cdaac6c82befb4288a60dbf12bd582d
|
4
|
+
data.tar.gz: 801135d166dc217611ca6a079eee87f27df9a0d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4eb4a32af83f1485e23aca07ad96795988980e4da059c328e3870fb346482d7d0709248ff3d9c78e559f85f7b26b40ca036cbf80a7e6d406b83dab844a725b33
|
7
|
+
data.tar.gz: 6e9b9e41db2f5df5483eb66b0657a58ea4ff2ce594d64bb22d04337004bd3e68cb96057a86273ce73d77136d9d71cac3d6e53d0841e7ef74f0d5dbd4c290c367
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,26 @@
|
|
1
|
+
## 2.1.0
|
2
|
+
|
3
|
+
- Added IPFIX support
|
4
|
+
- Fixed exception if Netflow data contains MAC addresses (issue #26, issue #34)
|
5
|
+
- Fixed exceptions when receiving invalid Netflow v5 and v9 data (issue #17, issue 18)
|
6
|
+
- Fixed decoding Netflow templates from multiple (non-identical) exporters
|
7
|
+
- Add support for Cisco ASA fields
|
8
|
+
- Add support for Netflow 9 options template with scope fields
|
9
|
+
|
1
10
|
# 2.0.5
|
11
|
+
|
2
12
|
- Depend on logstash-core-plugin-api instead of logstash-core, removing the need to mass update plugins on major releases of logstash
|
13
|
+
|
3
14
|
# 2.0.4
|
15
|
+
|
4
16
|
- New dependency requirements for logstash-core for the 5.0 release
|
17
|
+
|
5
18
|
## 2.0.3
|
19
|
+
|
6
20
|
- Fixed JSON compare flaw in specs
|
7
21
|
|
8
22
|
## 2.0.0
|
23
|
+
|
9
24
|
- Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
|
10
25
|
instead of using Thread.raise on the plugins' threads. Ref: https://github.com/elastic/logstash/pull/3895
|
11
26
|
- Dependency on logstash-core update to 2.0
|
data/CONTRIBUTORS
CHANGED
@@ -3,12 +3,24 @@ reports, or in general have helped logstash along its way.
|
|
3
3
|
|
4
4
|
Contributors:
|
5
5
|
* Aaron Mildenstein (untergeek)
|
6
|
+
* Adam Kaminski (thimslugga)
|
6
7
|
* Colin Surprenant (colinsurprenant)
|
7
8
|
* Jordan Sissel (jordansissel)
|
9
|
+
* Jorrit Folmer (jorritfolmer)
|
8
10
|
* Matt Dainty (bodgit)
|
11
|
+
* Paul Warren (pwarren)
|
9
12
|
* Pier-Hugues Pellerin (ph)
|
13
|
+
* Pulkit Agrawal (propulkit)
|
10
14
|
* Richard Pijnenburg (electrical)
|
15
|
+
* Salvador Ferrer (salva-ferrer)
|
16
|
+
* Will Rigby (wrigby)
|
17
|
+
* Rojuinex
|
11
18
|
* debadair
|
19
|
+
* hkshirish
|
20
|
+
* jstopinsek
|
21
|
+
|
22
|
+
Maintainer:
|
23
|
+
* Jorrit Folmer (jorritfolmer)
|
12
24
|
|
13
25
|
Note: If you've sent us patches, bug reports, or otherwise contributed to
|
14
26
|
Logstash, and you aren't on the list above and want to be, please let us know
|
data/Gemfile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
-
gemspec
|
2
|
+
gemspec
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# Logstash Plugin
|
2
2
|
|
3
|
-
[](http://build-eu-00.elastic.co/view/LS%20Plugins/view/LS%20Codecs/job/logstash-plugin-codec-netflow-unit/)
|
3
|
+
[](https://travis-ci.org/logstash-plugins/logstash-codec-netflow)
|
5
4
|
|
6
5
|
This is a plugin for [Logstash](https://github.com/elastic/logstash).
|
7
6
|
|
@@ -56,7 +55,12 @@ gem "logstash-filter-awesome", :path => "/your/local/logstash-filter-awesome"
|
|
56
55
|
```
|
57
56
|
- Install plugin
|
58
57
|
```sh
|
58
|
+
# Logstash 2.3 and higher
|
59
|
+
bin/logstash-plugin install --no-verify
|
60
|
+
|
61
|
+
# Prior to Logstash 2.3
|
59
62
|
bin/plugin install --no-verify
|
63
|
+
|
60
64
|
```
|
61
65
|
- Run Logstash with your plugin
|
62
66
|
```sh
|
@@ -74,7 +78,12 @@ gem build logstash-filter-awesome.gemspec
|
|
74
78
|
```
|
75
79
|
- Install the plugin from the Logstash home
|
76
80
|
```sh
|
77
|
-
|
81
|
+
# Logstash 2.3 and higher
|
82
|
+
bin/logstash-plugin install --no-verify
|
83
|
+
|
84
|
+
# Prior to Logstash 2.3
|
85
|
+
bin/plugin install --no-verify
|
86
|
+
|
78
87
|
```
|
79
88
|
- Start Logstash and proceed to test the plugin
|
80
89
|
|
@@ -3,7 +3,59 @@ require "logstash/filters/base"
|
|
3
3
|
require "logstash/namespace"
|
4
4
|
require "logstash/timestamp"
|
5
5
|
|
6
|
-
# The "netflow" codec is for decoding Netflow v5/v9 flows.
|
6
|
+
# The "netflow" codec is used for decoding Netflow v5/v9/v10 (IPFIX) flows.
|
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
|
+
|
7
59
|
class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
8
60
|
config_name "netflow"
|
9
61
|
|
@@ -14,7 +66,7 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
14
66
|
config :target, :validate => :string, :default => "netflow"
|
15
67
|
|
16
68
|
# Specify which Netflow versions you will accept.
|
17
|
-
config :versions, :validate => :array, :default => [5, 9]
|
69
|
+
config :versions, :validate => :array, :default => [5, 9, 10]
|
18
70
|
|
19
71
|
# Override YAML file containing Netflow field definitions
|
20
72
|
#
|
@@ -31,10 +83,36 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
31
83
|
# - :skip
|
32
84
|
#
|
33
85
|
# See <https://github.com/logstash-plugins/logstash-codec-netflow/blob/master/lib/logstash/codecs/netflow/netflow.yaml> for the base set.
|
34
|
-
config :
|
86
|
+
config :netflow_definitions, :validate => :path
|
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
|
35
105
|
|
36
106
|
NETFLOW5_FIELDS = ['version', 'flow_seq_num', 'engine_type', 'engine_id', 'sampling_algorithm', 'sampling_interval', 'flow_records']
|
37
107
|
NETFLOW9_FIELDS = ['version', 'flow_seq_num']
|
108
|
+
NETFLOW9_SCOPES = {
|
109
|
+
1 => :scope_system,
|
110
|
+
2 => :scope_interface,
|
111
|
+
3 => :scope_line_card,
|
112
|
+
4 => :scope_netflow_cache,
|
113
|
+
5 => :scope_template,
|
114
|
+
}
|
115
|
+
IPFIX_FIELDS = ['version']
|
38
116
|
SWITCHED = /_switched$/
|
39
117
|
FLOWSET_ID = "flowset_id"
|
40
118
|
|
@@ -45,29 +123,19 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
45
123
|
|
46
124
|
def register
|
47
125
|
require "logstash/codecs/netflow/util"
|
48
|
-
@
|
126
|
+
@netflow_templates = Vash.new()
|
127
|
+
@ipfix_templates = Vash.new()
|
49
128
|
|
50
129
|
# Path to default Netflow v9 field definitions
|
51
130
|
filename = ::File.expand_path('netflow/netflow.yaml', ::File.dirname(__FILE__))
|
131
|
+
@netflow_fields = load_definitions(filename, @netflow_definitions)
|
52
132
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
raise "#{self.class.name}: Bad syntax in definitions file #{filename}"
|
57
|
-
end
|
58
|
-
|
59
|
-
# Allow the user to augment/override/rename the supported Netflow fields
|
60
|
-
if @definitions
|
61
|
-
raise "#{self.class.name}: definitions file #{@definitions} does not exists" unless File.exists?(@definitions)
|
62
|
-
begin
|
63
|
-
@fields.merge!(YAML.load_file(@definitions))
|
64
|
-
rescue Exception => e
|
65
|
-
raise "#{self.class.name}: Bad syntax in definitions file #{@definitions}"
|
66
|
-
end
|
67
|
-
end
|
133
|
+
# Path to default IPFIX field definitions
|
134
|
+
filename = ::File.expand_path('netflow/ipfix.yaml', ::File.dirname(__FILE__))
|
135
|
+
@ipfix_fields = load_definitions(filename, @ipfix_definitions)
|
68
136
|
end # def register
|
69
137
|
|
70
|
-
def decode(payload, &block)
|
138
|
+
def decode(payload, metadata = nil, &block)
|
71
139
|
header = Header.read(payload)
|
72
140
|
|
73
141
|
unless @versions.include?(header.version)
|
@@ -83,11 +151,22 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
83
151
|
elsif header.version == 9
|
84
152
|
flowset = Netflow9PDU.read(payload)
|
85
153
|
flowset.records.each do |record|
|
86
|
-
|
154
|
+
if metadata != nil
|
155
|
+
decode_netflow9(flowset, record, metadata).each{|event| yield(event)}
|
156
|
+
else
|
157
|
+
decode_netflow9(flowset, record).each{|event| yield(event)}
|
158
|
+
end
|
159
|
+
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) }
|
87
164
|
end
|
88
165
|
else
|
89
166
|
@logger.warn("Unsupported Netflow version v#{header.version}")
|
90
167
|
end
|
168
|
+
rescue BinData::ValidityError, IOError => e
|
169
|
+
@logger.warn("Invalid netflow packet received (#{e})")
|
91
170
|
end
|
92
171
|
|
93
172
|
private
|
@@ -125,9 +204,11 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
125
204
|
end
|
126
205
|
|
127
206
|
LogStash::Event.new(event)
|
207
|
+
rescue BinData::ValidityError, IOError => e
|
208
|
+
@logger.warn("Invalid netflow packet received (#{e})")
|
128
209
|
end
|
129
210
|
|
130
|
-
def decode_netflow9(flowset, record)
|
211
|
+
def decode_netflow9(flowset, record, metadata = nil)
|
131
212
|
events = []
|
132
213
|
|
133
214
|
case record.flowset_id
|
@@ -143,10 +224,14 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
143
224
|
end
|
144
225
|
# We get this far, we have a list of fields
|
145
226
|
#key = "#{flowset.source_id}|#{event["source"]}|#{template.template_id}"
|
146
|
-
|
147
|
-
|
227
|
+
if metadata != nil
|
228
|
+
key = "#{flowset.source_id}|#{template.template_id}|#{metadata["host"]}|#{metadata["port"]}"
|
229
|
+
else
|
230
|
+
key = "#{flowset.source_id}|#{template.template_id}"
|
231
|
+
end
|
232
|
+
@netflow_templates[key, @cache_ttl] = BinData::Struct.new(:endian => :big, :fields => fields)
|
148
233
|
# Purge any expired templates
|
149
|
-
@
|
234
|
+
@netflow_templates.cleanup!
|
150
235
|
end
|
151
236
|
end
|
152
237
|
when 1
|
@@ -154,6 +239,9 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
154
239
|
record.flowset_data.templates.each do |template|
|
155
240
|
catch (:field) do
|
156
241
|
fields = []
|
242
|
+
template.scope_fields.each do |field|
|
243
|
+
fields << [uint_field(0, field.field_length), NETFLOW9_SCOPES[field.field_type]]
|
244
|
+
end
|
157
245
|
template.option_fields.each do |field|
|
158
246
|
entry = netflow_field_for(field.field_type, field.field_length)
|
159
247
|
throw :field unless entry
|
@@ -161,17 +249,25 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
161
249
|
end
|
162
250
|
# We get this far, we have a list of fields
|
163
251
|
#key = "#{flowset.source_id}|#{event["source"]}|#{template.template_id}"
|
164
|
-
|
165
|
-
|
252
|
+
if metadata != nil
|
253
|
+
key = "#{flowset.source_id}|#{template.template_id}|#{metadata["host"]}|#{metadata["port"]}"
|
254
|
+
else
|
255
|
+
key = "#{flowset.source_id}|#{template.template_id}"
|
256
|
+
end
|
257
|
+
@netflow_templates[key, @cache_ttl] = BinData::Struct.new(:endian => :big, :fields => fields)
|
166
258
|
# Purge any expired templates
|
167
|
-
@
|
259
|
+
@netflow_templates.cleanup!
|
168
260
|
end
|
169
261
|
end
|
170
262
|
when 256..65535
|
171
263
|
# Data flowset
|
172
264
|
#key = "#{flowset.source_id}|#{event["source"]}|#{record.flowset_id}"
|
173
|
-
|
174
|
-
|
265
|
+
if metadata != nil
|
266
|
+
key = "#{flowset.source_id}|#{record.flowset_id}|#{metadata["host"]}|#{metadata["port"]}"
|
267
|
+
else
|
268
|
+
key = "#{flowset.source_id}|#{record.flowset_id}"
|
269
|
+
end
|
270
|
+
template = @netflow_templates[key]
|
175
271
|
|
176
272
|
unless template
|
177
273
|
#@logger.warn("No matching template for flow id #{record.flowset_id} from #{event["source"]}")
|
@@ -224,6 +320,158 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
224
320
|
end
|
225
321
|
|
226
322
|
events
|
323
|
+
rescue BinData::ValidityError, IOError => e
|
324
|
+
@logger.warn("Invalid netflow packet received (#{e})")
|
325
|
+
end
|
326
|
+
|
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.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
|
227
475
|
end
|
228
476
|
|
229
477
|
def uint_field(length, default)
|
@@ -232,8 +480,8 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
232
480
|
end # def uint_field
|
233
481
|
|
234
482
|
def netflow_field_for(type, length)
|
235
|
-
if @
|
236
|
-
field = @
|
483
|
+
if @netflow_fields.include?(type)
|
484
|
+
field = @netflow_fields[type].clone
|
237
485
|
if field.is_a?(Array)
|
238
486
|
|
239
487
|
field[0] = uint_field(length, field[0]) if field[0].is_a?(Integer)
|
@@ -259,4 +507,38 @@ class LogStash::Codecs::Netflow < LogStash::Codecs::Base
|
|
259
507
|
nil
|
260
508
|
end
|
261
509
|
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
|
262
544
|
end # class LogStash::Filters::Netflow
|