logstash-codec-sflow 0.1.0 → 0.2.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/README.md +1 -1
- data/lib/logstash/codecs/sflow/flow_record.rb +8 -1
- data/lib/logstash/codecs/sflow/packet_header.rb +100 -0
- data/lib/logstash/codecs/sflow/sample.rb +7 -7
- data/lib/logstash/codecs/sflow/util.rb +0 -1
- data/lib/logstash/codecs/sflow.rb +116 -31
- data/logstash-codec-sflow.gemspec +1 -1
- data/spec/codecs/sflow/ethernet_ipv4_over_udp_header.dat +0 -0
- data/spec/codecs/sflow/ipv4_over_tcp_header.dat +0 -0
- data/spec/codecs/sflow/packet_header_spec.rb +94 -0
- data/spec/codecs/sflow/tcp.dat +0 -0
- data/spec/codecs/sflow/udp.dat +0 -0
- data/spec/codecs/sflow_1_counters_sample.dat +0 -0
- data/spec/codecs/sflow_flow_sample.dat +0 -0
- data/spec/codecs/sflow_spec.rb +13 -10
- metadata +15 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9773b581653d998b843923848706abfe5851dad
|
4
|
+
data.tar.gz: 92c48583c7b35ecdf55bd707e4196b671149cc91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74eb65d450dbc9b1dc05dd784a1d0b7efca1eb8f82cc09d978049d672a98802dbdcd36ce652475baa31222c9cfadb5c814a7bed2277845584db6c1ecb8877331
|
7
|
+
data.tar.gz: 68dcb680539c692397aeaecaa4cc7f80fa5f381f7852450115e9b27c09609b19cf9acd3f822bc648d1c20defa63cd79944fea6ebd0bb20f8c630b8155eeaa943
|
data/README.md
CHANGED
@@ -65,7 +65,7 @@ bundle exec rspec
|
|
65
65
|
|
66
66
|
- Edit Logstash `tools/Gemfile` and add the local plugin path, for example:
|
67
67
|
```ruby
|
68
|
-
gem "logstash-
|
68
|
+
gem "logstash-codec-sflow", :path => "/your/local/logstash-filter-awesome"
|
69
69
|
```
|
70
70
|
- Update Logstash dependencies
|
71
71
|
```sh
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'bindata'
|
4
4
|
require 'logstash/codecs/sflow/util'
|
5
|
+
require 'logstash/codecs/sflow/packet_header'
|
5
6
|
|
6
7
|
class RawPacketHeader < BinData::Record
|
7
8
|
endian :big
|
@@ -9,14 +10,20 @@ class RawPacketHeader < BinData::Record
|
|
9
10
|
uint32 :frame_length
|
10
11
|
uint32 :stripped
|
11
12
|
uint32 :header_size
|
12
|
-
|
13
|
+
choice :sample_header, :selection => :protocol do
|
14
|
+
ethernet_header 1, :size_header => lambda { header_size * 8 }
|
15
|
+
ip_header 11, :size_header => lambda { header_size * 8 }
|
16
|
+
skip :default, :length => :header_size
|
17
|
+
end
|
13
18
|
end
|
14
19
|
|
15
20
|
class EthernetFrameData < BinData::Record
|
16
21
|
endian :big
|
17
22
|
uint32 :packet_length
|
18
23
|
mac_address :src_mac
|
24
|
+
skip :length => 2
|
19
25
|
mac_address :dst_mac
|
26
|
+
skip :length => 2
|
20
27
|
uint32 :type
|
21
28
|
end
|
22
29
|
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'bindata'
|
4
|
+
require 'logstash/codecs/sflow/util'
|
5
|
+
|
6
|
+
|
7
|
+
class TcpHeader < BinData::Record
|
8
|
+
mandatory_parameter :size_header
|
9
|
+
|
10
|
+
endian :big
|
11
|
+
uint16 :src_port
|
12
|
+
uint16 :dst_port
|
13
|
+
uint32 :tcp_seq_number
|
14
|
+
uint32 :tcp_ack_number
|
15
|
+
bit4 :tcp_header_length # times 4
|
16
|
+
bit3 :tcp_reserved
|
17
|
+
bit1 :tcp_is_nonce
|
18
|
+
bit1 :tcp_is_cwr
|
19
|
+
bit1 :tcp_is_ecn_echo
|
20
|
+
bit1 :tcp_is_urgent
|
21
|
+
bit1 :tcp_is_ack
|
22
|
+
bit1 :tcp_is_push
|
23
|
+
bit1 :tcp_is_reset
|
24
|
+
bit1 :tcp_is_syn
|
25
|
+
bit1 :tcp_is_fin
|
26
|
+
uint16 :tcp_window_size
|
27
|
+
uint16 :tcp_checksum
|
28
|
+
uint16 :tcp_urgent_pointer
|
29
|
+
array :tcp_options, :initial_length => lambda { (((tcp_header_length * 4) - 20)/4).ceil }, :onlyif => :is_options? do
|
30
|
+
string :tcp_option, :length => 4, :pad_byte => "\0"
|
31
|
+
end
|
32
|
+
bit :nbits => lambda { size_header - (tcp_header_length * 4 * 8) }
|
33
|
+
|
34
|
+
def is_options?
|
35
|
+
tcp_header_length.to_i > 5
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class UdpHeader < BinData::Record
|
40
|
+
endian :big
|
41
|
+
uint16 :src_port
|
42
|
+
uint16 :dst_port
|
43
|
+
uint16 :udp_length
|
44
|
+
uint16 :udp_checksum
|
45
|
+
skip :length => lambda { udp_length - 64 } #skip udp data
|
46
|
+
end
|
47
|
+
|
48
|
+
class IPV4Header < BinData::Record
|
49
|
+
mandatory_parameter :size_header
|
50
|
+
|
51
|
+
endian :big
|
52
|
+
bit4 :ip_header_length # times 4
|
53
|
+
bit6 :ip_dscp
|
54
|
+
bit2 :ip_ecn
|
55
|
+
uint16 :ip_total_length
|
56
|
+
uint16 :ip_identification
|
57
|
+
bit3 :ip_flags
|
58
|
+
bit13 :ip_fragment_offset
|
59
|
+
uint8 :ip_ttl
|
60
|
+
uint8 :ip_protocol
|
61
|
+
uint16 :ip_checksum
|
62
|
+
ip4_addr :src_ip
|
63
|
+
ip4_addr :dst_ip
|
64
|
+
array :ip_options, :initial_length => lambda { (((ip_header_length * 4) - 20)/4).ceil }, :onlyif => :is_options? do
|
65
|
+
string :ip_option, :length => 4, :pad_byte => "\0"
|
66
|
+
end
|
67
|
+
choice :layer4, :selection => :ip_protocol do
|
68
|
+
tcp_header 6, :size_header => lambda { size_header - (ip_header_length * 4 * 8) }
|
69
|
+
udp_header 17
|
70
|
+
bit :default, :nbits => lambda { size_header - (ip_header_length * 4 * 8) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def is_options?
|
74
|
+
ip_header_length.to_i > 5
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class IPHeader < BinData::Record
|
79
|
+
mandatory_parameter :size_header
|
80
|
+
|
81
|
+
endian :big
|
82
|
+
bit4 :ip_version
|
83
|
+
choice :header, :selection => :ip_version do
|
84
|
+
ipv4_header 4, :size_header => :size_header
|
85
|
+
bit :default, :nbits => lambda { size_header - 4 }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class EthernetHeader < BinData::Record
|
90
|
+
mandatory_parameter :size_header
|
91
|
+
|
92
|
+
endian :big
|
93
|
+
mac_address :eth_dst
|
94
|
+
mac_address :eth_src
|
95
|
+
uint16 :eth_type
|
96
|
+
choice :layer3, :selection => :eth_type do
|
97
|
+
ip_header 2048, :size_header => lambda { size_header - (14 * 8) }
|
98
|
+
bit :default, :nbits => lambda { size_header - (14 * 8) }
|
99
|
+
end
|
100
|
+
end
|
@@ -19,13 +19,13 @@ class FlowSample < BinData::Record
|
|
19
19
|
bit20 :record_entreprise
|
20
20
|
bit12 :record_format
|
21
21
|
uint32 :record_length
|
22
|
-
choice :record_data, :selection =>
|
23
|
-
raw_packet_header 1
|
24
|
-
ethernet_frame_data 2
|
25
|
-
ip4_data 3
|
26
|
-
ip6_data 4
|
27
|
-
extended_switch_data 1001
|
28
|
-
extended_router_data 1002
|
22
|
+
choice :record_data, :selection => lambda { "#{record_entreprise}-#{record_format}" } do
|
23
|
+
raw_packet_header "0-1"
|
24
|
+
ethernet_frame_data "0-2"
|
25
|
+
ip4_data "0-3"
|
26
|
+
ip6_data "0-4"
|
27
|
+
extended_switch_data "0-1001"
|
28
|
+
extended_router_data "0-1002"
|
29
29
|
skip :default, :length => :record_length
|
30
30
|
end
|
31
31
|
end
|
@@ -1,21 +1,30 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require
|
3
|
-
require
|
2
|
+
require 'logstash/codecs/base'
|
3
|
+
require 'logstash/namespace'
|
4
4
|
|
5
5
|
# The "sflow" codec is for decoding sflow v5 flows.
|
6
6
|
class LogStash::Codecs::Sflow < LogStash::Codecs::Base
|
7
|
-
config_name
|
7
|
+
config_name 'sflow'
|
8
8
|
|
9
9
|
# Specify which sflow must not be send in the event
|
10
|
-
config :
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
config :optional_removed_field, :validate => :array, :default => ['sflow_version', 'ip_version', 'header_size',
|
11
|
+
'ip_header_length', 'ip_dscp', 'ip_ecn',
|
12
|
+
'ip_total_length', 'ip_identification', 'ip_flags',
|
13
|
+
'ip_fragment_offset', 'ip_ttl', 'ip_checksum',
|
14
|
+
'ip_options', 'tcp_seq_number', 'tcp_ack_number',
|
15
|
+
'tcp_header_length', 'tcp_reserved', 'tcp_is_nonce',
|
16
|
+
'tcp_is_cwr', 'tcp_is_ecn_echo', 'tcp_is_urgent',
|
17
|
+
'tcp_is_ack', 'tcp_is_push', 'tcp_is_reset',
|
18
|
+
'tcp_is_syn', 'tcp_is_fin', 'tcp_window_size',
|
19
|
+
'tcp_checksum', 'tcp_urgent_pointer', 'tcp_options']
|
14
20
|
|
15
21
|
|
16
22
|
def initialize(params = {})
|
17
23
|
super(params)
|
18
24
|
@threadsafe = false
|
25
|
+
@removed_field = ['record_length', 'record_count', 'record_entreprise', 'record_format', 'sample_entreprise',
|
26
|
+
'sample_format', 'sample_length', 'sample_count', 'sample_header', 'layer3', 'layer4',
|
27
|
+
'tcp_nbits', 'ip_nbits'] | @optional_removed_field
|
19
28
|
end
|
20
29
|
|
21
30
|
# def initialize
|
@@ -29,56 +38,132 @@ class LogStash::Codecs::Sflow < LogStash::Codecs::Base
|
|
29
38
|
|
30
39
|
public
|
31
40
|
def decode(payload)
|
41
|
+
|
32
42
|
decoded = SFlow.read(payload)
|
33
43
|
|
34
44
|
events = []
|
35
45
|
|
36
46
|
decoded['samples'].each do |sample|
|
47
|
+
#Treat case with no flow decoded (Unknown flow)
|
37
48
|
if sample['sample_data'].to_s.eql? ''
|
38
49
|
@logger.warn("Unknown sample entreprise #{sample['sample_entreprise'].to_s} - format #{sample['sample_format'].to_s}")
|
39
50
|
next
|
40
51
|
end
|
41
|
-
sample['sample_data']['records'].each do |record|
|
42
|
-
# Ensure that some data exist for the record
|
43
|
-
if record['record_data'].to_s.eql? ''
|
44
|
-
@logger.warn("Unknown record entreprise #{record['record_entreprise'].to_s}, format #{record['record_format'].to_s}")
|
45
|
-
next
|
46
|
-
end
|
47
52
|
|
53
|
+
#treat sample flow
|
54
|
+
if sample['sample_entreprise'] == 0 && sample['sample_format'] == 1
|
48
55
|
# Create the logstash event
|
49
56
|
event = {
|
50
57
|
LogStash::Event::TIMESTAMP => LogStash::Timestamp.now
|
51
58
|
}
|
59
|
+
sample['sample_data']['records'].each do |record|
|
60
|
+
# Ensure that some data exist for the record
|
61
|
+
if record['record_data'].to_s.eql? ''
|
62
|
+
@logger.warn("Unknown record entreprise #{record['record_entreprise'].to_s}, format #{record['record_format'].to_s}")
|
63
|
+
next
|
64
|
+
end
|
52
65
|
|
53
|
-
|
54
|
-
|
55
|
-
|
66
|
+
decoded.each_pair do |k, v|
|
67
|
+
unless k.to_s.eql? 'samples' or @removed_field.include? k.to_s
|
68
|
+
event["#{k}"] = v
|
69
|
+
end
|
56
70
|
end
|
57
|
-
end
|
58
71
|
|
59
|
-
|
60
|
-
|
61
|
-
|
72
|
+
sample.each_pair do |k, v|
|
73
|
+
unless k.to_s.eql? 'sample_data' or @removed_field.include? k.to_s
|
74
|
+
event["#{k}"] = v
|
75
|
+
end
|
62
76
|
end
|
63
|
-
end
|
64
77
|
|
65
|
-
|
66
|
-
|
67
|
-
|
78
|
+
sample['sample_data'].each_pair do |k, v|
|
79
|
+
unless k.to_s.eql? 'records' or @removed_field.include? k.to_s
|
80
|
+
event["#{k}"] = v
|
81
|
+
end
|
68
82
|
end
|
83
|
+
|
84
|
+
record.each_pair do |k, v|
|
85
|
+
unless k.to_s.eql? 'record_data' or @removed_field.include? k.to_s
|
86
|
+
event["#{k}"] = v
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
record['record_data'].each_pair do |k, v|
|
91
|
+
unless k.to_s.eql? 'record_data' or @removed_field.include? k.to_s
|
92
|
+
event["#{k}"] = v
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
unless record['record_data']['sample_header'].to_s.eql? ''
|
97
|
+
record['record_data']['sample_header'].each_pair do |k, v|
|
98
|
+
unless k.to_s.eql? 'record_data' or @removed_field.include? k.to_s
|
99
|
+
event["#{k}"] = v
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
if record['record_data']['sample_header'].has_key?("layer3")
|
104
|
+
record['record_data']['sample_header']['layer3']['header'].each_pair do |k, v|
|
105
|
+
unless k.to_s.eql? 'record_data' or @removed_field.include? k.to_s
|
106
|
+
event["#{k}"] = v
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
unless record['record_data']['sample_header']['layer3']['header']['layer4'].to_s.eql? ''
|
112
|
+
record['record_data']['sample_header']['layer3']['header']['layer4'].each_pair do |k, v|
|
113
|
+
unless k.to_s.eql? 'record_data' or @removed_field.include? k.to_s
|
114
|
+
event["#{k}"] = v
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
69
120
|
end
|
121
|
+
events.push(event)
|
122
|
+
|
123
|
+
#treat counter flow
|
124
|
+
elsif sample['sample_entreprise'] == 0 && sample['sample_format'] == 2
|
125
|
+
sample['sample_data']['records'].each do |record|
|
126
|
+
# Ensure that some data exist for the record
|
127
|
+
if record['record_data'].to_s.eql? ''
|
128
|
+
@logger.warn("Unknown record entreprise #{record['record_entreprise'].to_s}, format #{record['record_format'].to_s}")
|
129
|
+
next
|
130
|
+
end
|
131
|
+
|
132
|
+
# Create the logstash event
|
133
|
+
event = {
|
134
|
+
LogStash::Event::TIMESTAMP => LogStash::Timestamp.now
|
135
|
+
}
|
136
|
+
|
137
|
+
decoded.each_pair do |k, v|
|
138
|
+
unless k.to_s.eql? 'samples' or @removed_field.include? k.to_s
|
139
|
+
event["#{k}"] = v
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
sample.each_pair do |k, v|
|
144
|
+
unless k.to_s.eql? 'sample_data' or @removed_field.include? k.to_s
|
145
|
+
event["#{k}"] = v
|
146
|
+
end
|
147
|
+
end
|
70
148
|
|
71
|
-
|
72
|
-
|
149
|
+
sample['sample_data'].each_pair do |k, v|
|
150
|
+
unless k.to_s.eql? 'records' or @removed_field.include? k.to_s
|
151
|
+
event["#{k}"] = v
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
record.each_pair do |k, v|
|
156
|
+
unless k.to_s.eql? 'record_data' or @removed_field.include? k.to_s
|
157
|
+
event["#{k}"] = v
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
record['record_data'].each_pair do |k, v|
|
73
162
|
event["#{k}"] = v
|
74
163
|
end
|
75
|
-
end
|
76
164
|
|
77
|
-
|
78
|
-
event["#{k}"] = v
|
165
|
+
events.push(event)
|
79
166
|
end
|
80
|
-
|
81
|
-
events.push(event)
|
82
167
|
end
|
83
168
|
end
|
84
169
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-codec-sflow'
|
4
|
-
s.version = '0.
|
4
|
+
s.version = '0.2.0'
|
5
5
|
s.licenses = ['Apache License (2.0)']
|
6
6
|
s.summary = "The sflow codec is for decoding SFlow v5 flows."
|
7
7
|
s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
|
Binary file
|
Binary file
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "logstash/devutils/rspec/spec_helper"
|
4
|
+
require "logstash/codecs/sflow/packet_header"
|
5
|
+
|
6
|
+
describe UdpHeader do
|
7
|
+
it "should decode udp header" do
|
8
|
+
payload = IO.read(File.join(File.dirname(__FILE__), "udp.dat"), :mode => "rb")
|
9
|
+
decoded = UdpHeader.read(payload)
|
10
|
+
|
11
|
+
decoded["src_port"].to_s.should eq("20665")
|
12
|
+
decoded["dst_port"].to_s.should eq("514")
|
13
|
+
decoded["udp_length"].to_s.should eq("147")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
describe TcpHeader do
|
19
|
+
it "should decode tcp header" do
|
20
|
+
payload = IO.read(File.join(File.dirname(__FILE__), "tcp.dat"), :mode => "rb")
|
21
|
+
decoded = TcpHeader.new(:size_header => payload.bytesize * 8).read(payload)
|
22
|
+
|
23
|
+
decoded["src_port"].to_s.should eq("5672")
|
24
|
+
decoded["dst_port"].to_s.should eq("59451")
|
25
|
+
decoded["tcp_seq_number"].to_s.should eq("2671357038")
|
26
|
+
decoded["tcp_ack_number"].to_s.should eq("2651945969")
|
27
|
+
(decoded["tcp_header_length"].to_i*4).to_s.should eq("32")
|
28
|
+
decoded["tcp_is_nonce"].to_s.should eq("0")
|
29
|
+
decoded["tcp_is_cwr"].to_s.should eq("0")
|
30
|
+
decoded["tcp_is_ecn_echo"].to_s.should eq("0")
|
31
|
+
decoded["tcp_is_urgent"].to_s.should eq("0")
|
32
|
+
decoded["tcp_is_ack"].to_s.should eq("1")
|
33
|
+
decoded["tcp_is_push"].to_s.should eq("1")
|
34
|
+
decoded["tcp_is_reset"].to_s.should eq("0")
|
35
|
+
decoded["tcp_is_syn"].to_s.should eq("0")
|
36
|
+
decoded["tcp_is_fin"].to_s.should eq("0")
|
37
|
+
decoded["tcp_window_size"].to_s.should eq("147")
|
38
|
+
decoded["tcp_checksum"].to_s.should eq("13042")
|
39
|
+
decoded["tcp_urgent_pointer"].to_s.should eq("0")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
describe IPHeader do
|
45
|
+
it "should decode ipv4 over tcp header" do
|
46
|
+
payload = IO.read(File.join(File.dirname(__FILE__), "ipv4_over_tcp_header.dat"), :mode => "rb")
|
47
|
+
decoded = IPHeader.new(:size_header => payload.bytesize * 8).read(payload)
|
48
|
+
|
49
|
+
decoded["ip_version"].to_s.should eq("4")
|
50
|
+
decoded["header"]["ip_header_length"].to_s.should eq("5")
|
51
|
+
decoded["header"]["ip_dscp"].to_s.should eq("0")
|
52
|
+
decoded["header"]["ip_ecn"].to_s.should eq("0")
|
53
|
+
decoded["header"]["ip_total_length"].to_s.should eq("476")
|
54
|
+
decoded["header"]["ip_identification"].to_s.should eq("30529")
|
55
|
+
decoded["header"]["ip_flags"].to_s.should eq("2")
|
56
|
+
decoded["header"]["ip_fragment_offset"].to_s.should eq("0")
|
57
|
+
decoded["header"]["ip_ttl"].to_s.should eq("62")
|
58
|
+
decoded["header"]["ip_protocol"].to_s.should eq("6")
|
59
|
+
decoded["header"]["ip_checksum"].to_s.should eq("37559")
|
60
|
+
decoded["header"]["src_ip"].to_s.should eq("10.243.27.17")
|
61
|
+
decoded["header"]["dst_ip"].to_s.should eq("10.243.0.45")
|
62
|
+
decoded["header"]["layer4"]["src_port"].to_s.should eq("5672")
|
63
|
+
decoded["header"]["layer4"]["dst_port"].to_s.should eq("59451")
|
64
|
+
decoded["header"]["layer4"]["tcp_seq_number"].to_s.should eq("2671357038")
|
65
|
+
decoded["header"]["layer4"]["tcp_ack_number"].to_s.should eq("2651945969")
|
66
|
+
(decoded["header"]["layer4"]["tcp_header_length"].to_i*4).to_s.should eq("32")
|
67
|
+
decoded["header"]["layer4"]["tcp_is_nonce"].to_s.should eq("0")
|
68
|
+
decoded["header"]["layer4"]["tcp_is_cwr"].to_s.should eq("0")
|
69
|
+
decoded["header"]["layer4"]["tcp_is_ecn_echo"].to_s.should eq("0")
|
70
|
+
decoded["header"]["layer4"]["tcp_is_urgent"].to_s.should eq("0")
|
71
|
+
decoded["header"]["layer4"]["tcp_is_ack"].to_s.should eq("1")
|
72
|
+
decoded["header"]["layer4"]["tcp_is_push"].to_s.should eq("1")
|
73
|
+
decoded["header"]["layer4"]["tcp_is_reset"].to_s.should eq("0")
|
74
|
+
decoded["header"]["layer4"]["tcp_is_syn"].to_s.should eq("0")
|
75
|
+
decoded["header"]["layer4"]["tcp_is_fin"].to_s.should eq("0")
|
76
|
+
decoded["header"]["layer4"]["tcp_window_size"].to_s.should eq("147")
|
77
|
+
decoded["header"]["layer4"]["tcp_checksum"].to_s.should eq("13042")
|
78
|
+
decoded["header"]["layer4"]["tcp_urgent_pointer"].to_s.should eq("0")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
describe EthernetHeader do
|
84
|
+
it "should decode ipv4 over udp header" do
|
85
|
+
payload = IO.read(File.join(File.dirname(__FILE__), "ethernet_ipv4_over_udp_header.dat"), :mode => "rb")
|
86
|
+
decoded = EthernetHeader.new(:size_header => payload.bytesize * 8).read(payload)
|
87
|
+
|
88
|
+
decoded["eth_dst"].to_s.should eq("00:23:e9:78:16:c6")
|
89
|
+
decoded["eth_src"].to_s.should eq("58:f3:9c:81:4b:81")
|
90
|
+
decoded["eth_type"].to_s.should eq("2048")
|
91
|
+
decoded["layer3"]["header"]["dst_ip"].to_s.should eq("10.243.27.9")
|
92
|
+
decoded["layer3"]["header"]["layer4"]["dst_port"].to_s.should eq("514")
|
93
|
+
end
|
94
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/spec/codecs/sflow_spec.rb
CHANGED
@@ -2,19 +2,22 @@
|
|
2
2
|
|
3
3
|
require "logstash/devutils/rspec/spec_helper"
|
4
4
|
require "logstash/codecs/sflow"
|
5
|
+
require "logstash/codecs/sflow/datagram"
|
5
6
|
|
6
|
-
describe
|
7
|
-
|
8
|
-
@subject = LogStash::Codecs::Sflow.new
|
7
|
+
describe SFlow do
|
8
|
+
it "should decode sflow counters" do
|
9
9
|
payload = IO.read(File.join(File.dirname(__FILE__), "sflow_counters_sample.dat"), :mode => "rb")
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
decoded = SFlow.read(payload)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should decode sflow 1 counters" do
|
14
|
+
payload = IO.read(File.join(File.dirname(__FILE__), "sflow_1_counters_sample.dat"), :mode => "rb")
|
15
|
+
decoded = SFlow.read(payload)
|
13
16
|
end
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
|
19
|
+
it "should decode sflow sample" do
|
20
|
+
payload = IO.read(File.join(File.dirname(__FILE__), "sflow_flow_sample.dat"), :mode => "rb")
|
21
|
+
decoded = SFlow.read(payload)
|
19
22
|
end
|
20
23
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-codec-sflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicolas Fraison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-12-
|
11
|
+
date: 2015-12-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -74,9 +74,16 @@ files:
|
|
74
74
|
- lib/logstash/codecs/sflow/counter_record.rb
|
75
75
|
- lib/logstash/codecs/sflow/datagram.rb
|
76
76
|
- lib/logstash/codecs/sflow/flow_record.rb
|
77
|
+
- lib/logstash/codecs/sflow/packet_header.rb
|
77
78
|
- lib/logstash/codecs/sflow/sample.rb
|
78
79
|
- lib/logstash/codecs/sflow/util.rb
|
79
80
|
- logstash-codec-sflow.gemspec
|
81
|
+
- spec/codecs/sflow/ethernet_ipv4_over_udp_header.dat
|
82
|
+
- spec/codecs/sflow/ipv4_over_tcp_header.dat
|
83
|
+
- spec/codecs/sflow/packet_header_spec.rb
|
84
|
+
- spec/codecs/sflow/tcp.dat
|
85
|
+
- spec/codecs/sflow/udp.dat
|
86
|
+
- spec/codecs/sflow_1_counters_sample.dat
|
80
87
|
- spec/codecs/sflow_counters_sample.dat
|
81
88
|
- spec/codecs/sflow_flow_sample.dat
|
82
89
|
- spec/codecs/sflow_spec.rb
|
@@ -107,6 +114,12 @@ signing_key:
|
|
107
114
|
specification_version: 4
|
108
115
|
summary: The sflow codec is for decoding SFlow v5 flows.
|
109
116
|
test_files:
|
117
|
+
- spec/codecs/sflow/ethernet_ipv4_over_udp_header.dat
|
118
|
+
- spec/codecs/sflow/ipv4_over_tcp_header.dat
|
119
|
+
- spec/codecs/sflow/packet_header_spec.rb
|
120
|
+
- spec/codecs/sflow/tcp.dat
|
121
|
+
- spec/codecs/sflow/udp.dat
|
122
|
+
- spec/codecs/sflow_1_counters_sample.dat
|
110
123
|
- spec/codecs/sflow_counters_sample.dat
|
111
124
|
- spec/codecs/sflow_flow_sample.dat
|
112
125
|
- spec/codecs/sflow_spec.rb
|