fluent-plugin-sflow 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ require 'bindata'
2
+ require 'eventmachine'
3
+ require 'yaml'
4
+
5
+ dir = File.expand_path(File.join(File.dirname(__FILE__), 'sflow'))
6
+ ['config','models/ipv4header', 'models/tcpheader', 'models/udpheader', 'models/protocol', 'models/binary_models','parsers/parsers','storage/storage', 'collector','snmp/iface_names'].each do |req|
7
+ require File.join(dir, req)
8
+ end
9
+
10
+ Process.daemon(true) if $daemonize == true
@@ -0,0 +1,69 @@
1
+ class SflowCollector
2
+ module Collector
3
+ Thread.abort_on_exception=true
4
+ require 'socket'
5
+ def post_init
6
+ puts "Server listening."
7
+ end
8
+
9
+ def receive_data(data)
10
+ operation = proc do
11
+ begin
12
+ if data != nil
13
+ sflow = SflowParser.parse_packet(data)
14
+ end
15
+ rescue Exception => e
16
+ puts Time.now
17
+ puts sflow.inspect
18
+ puts e.message
19
+ puts e.backtrace
20
+ end
21
+ end
22
+
23
+ callback = proc do |sflow|
24
+ begin
25
+ if sflow != nil
26
+ SflowStorage.send_udpjson(sflow)
27
+ end
28
+ rescue Exception => e
29
+ puts Time.now
30
+ puts sflow.inspect if sflow != nil
31
+ puts e.message
32
+ puts e.backtrace
33
+ end
34
+ end
35
+
36
+ EM.defer(operation,callback)
37
+
38
+ end
39
+ end
40
+
41
+ def self.start_collector(bind_ip = '0.0.0.0', bind_port = 6343)
42
+ begin
43
+ config = SflowConfig.new
44
+ if config.logstash_host and config.logstash_port
45
+ puts "Connecting to Logstash: #{config.logstash_host}:#{config.logstash_port}"
46
+ $logstash = UDPSocket.new
47
+ $logstash.connect(config.logstash_host, config.logstash_port)
48
+ else
49
+ puts "no host:port given"
50
+ exit 1
51
+ end
52
+ $switch_hash = config.switch_hash
53
+ if config.switch_hash != nil
54
+ $switchportnames = SNMPwalk.new(config.switch_hash.each_key)
55
+ end
56
+ EventMachine::run do
57
+ EventMachine::open_datagram_socket(bind_ip, bind_port, Collector)
58
+ end
59
+ rescue Exception => e
60
+ puts Time.now
61
+ puts e.message
62
+ puts e.backtrace
63
+ raise "unable to start sflow collector"
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+
@@ -0,0 +1,15 @@
1
+ class SflowConfig
2
+ attr_reader :switch_hash
3
+ attr_reader :logstash_host
4
+ attr_reader :logstash_port
5
+ attr_reader :daemonize
6
+
7
+ def initialize
8
+ config = YAML.load_file("etc/config.yaml")
9
+ @switch_hash = config['switch']
10
+ @logstash_host = config['logstash_host']
11
+ @logstash_port = config['logstash_port']
12
+ @daemonize = config['daemonize']
13
+ end
14
+ end
15
+
@@ -0,0 +1,176 @@
1
+ class Header < BinData::Record
2
+ endian :big
3
+ uint32 :version
4
+ uint32 :address_type
5
+ uint32 :agent_address
6
+ uint32 :sub_agent_id
7
+ uint32 :seq_number
8
+ uint32 :sys_uptime
9
+ uint32 :num_samples
10
+ array :flow_samples, :initial_length => :num_samples do
11
+ uint16 :enterprise_std
12
+ uint16 :sflow_sample_type
13
+ uint32 :sample_length
14
+ string :sample_data, :length => :sample_length
15
+ end
16
+ end
17
+
18
+ class Sflow5sampleheader1 < BinData::Record
19
+ endian :big
20
+ uint32 :seq_number
21
+ uint32 :source_id_type
22
+ uint32 :sampling_rate
23
+ uint32 :sample_pool
24
+ uint32 :dropped_packets
25
+ uint32 :i_iface_value
26
+ uint32 :o_iface_value
27
+ uint32 :num_records
28
+ array :records, :initial_length => :num_records do
29
+ uint16 :enterprise
30
+ uint16 :format
31
+ uint32 :flow_length
32
+ string :record_data, :length => :flow_length
33
+ end
34
+
35
+ end
36
+
37
+ class Sflow5sampleheader3 < BinData::Record
38
+ endian :big
39
+ uint32 :seq_number
40
+ uint32 :source_id_type
41
+ uint32 :source_id_index
42
+ uint32 :sampling_rate
43
+ uint32 :sample_pool
44
+ uint32 :dropped_packets
45
+ uint32 :i_iface_format
46
+ uint32 :i_iface_value
47
+ uint32 :o_iface_format
48
+ uint32 :o_iface_value
49
+ uint32 :num_records
50
+ array :records, :initial_length => :num_records do
51
+ uint16 :enterprise
52
+ uint16 :format
53
+ uint32 :flow_length
54
+ string :record_data, :length => :flow_length
55
+ end
56
+
57
+ end
58
+
59
+
60
+ class Sflow5counterheader4 < BinData::Record
61
+ endian :big
62
+ uint32 :seq_number
63
+ uint32 :source_id_type
64
+ uint32 :source_id_index
65
+ uint32 :num_records
66
+ array :records, :initial_length => :num_records do
67
+ uint16 :enterprise
68
+ uint16 :format
69
+ uint32 :record_length
70
+ string :record_data, :length => :record_length
71
+ end
72
+ end
73
+
74
+ class Sflow5counterheader2 < BinData::Record
75
+ endian :big
76
+ uint32 :seq_number
77
+ uint32 :source_id_type
78
+ uint32 :num_records
79
+ array :records, :initial_length => :num_records do
80
+ uint16 :enterprise
81
+ uint16 :format
82
+ uint32 :record_length
83
+ string :record_data, :length => :record_length
84
+ end
85
+ end
86
+
87
+
88
+ class Sflow5rawpacket < BinData::Record
89
+ endian :big
90
+ uint32 :header_protocol
91
+ uint32 :frame_length
92
+ uint32 :payload
93
+ uint32 :xy
94
+ array :rawpacket_data, :read_until => :eof do
95
+ string :data, :length => 1
96
+ end
97
+ end
98
+
99
+ class Sflow5extswitch < BinData::Record
100
+ endian :big
101
+ uint32 :src_vlan
102
+ uint32 :src_priority
103
+ uint32 :dst_vlan
104
+ uint32 :dst_priority
105
+ end
106
+
107
+ class Sflow5genericcounter < BinData::Record
108
+ endian :big
109
+ uint32 :int_index
110
+ uint32 :int_type
111
+ uint64 :int_speed
112
+ uint32 :int_direction
113
+ uint16 :int_admin_status
114
+ uint16 :int_oper_status
115
+ uint64 :input_octets
116
+ uint32 :input_packets
117
+ uint32 :input_packets_multi
118
+ uint32 :input_packets_broad
119
+ uint32 :input_packets_discard
120
+ uint32 :input_packets_error
121
+ uint32 :unknown_proto
122
+ uint64 :output_octets
123
+ uint32 :output_packets
124
+ uint32 :output_packets_multi
125
+ uint32 :output_packets_broad
126
+ uint32 :output_packets_discard
127
+ uint32 :output_packets_error
128
+ uint32 :prom_mode
129
+ end
130
+
131
+ class Sflow5ethcounter < BinData::Record
132
+ endian :big
133
+ uint32 :alignment_errors
134
+ uint32 :fcs_errors
135
+ uint32 :single_collision_frames
136
+ uint32 :multi_collision_frames
137
+ uint32 :sqe_test_errors
138
+ uint32 :deffered_transmission
139
+ uint32 :late_collision
140
+ uint32 :excessive_collision
141
+ uint32 :internal_mac_transmit_errors
142
+ uint32 :carrier_sense_errors
143
+ uint32 :frame_too_long
144
+ uint32 :internal_mac_receive_errors
145
+ uint32 :symbol_errors
146
+ end
147
+
148
+ class Sflow5rawpacketheaderEthernet < BinData::Record
149
+ endian :big
150
+ string :eth_src, :length => 6
151
+ string :eth_dst, :length => 6
152
+ uint16 :eth_type
153
+ array :ethernetdata, :read_until => :eof do
154
+ string :data, :length => 1
155
+ end
156
+ end
157
+
158
+ class Sflow5rawpacketdata < BinData::Record
159
+ endian :big
160
+ string :eth, :length => 14
161
+ string :vlan_tag, :length => 2
162
+ string :vlan_tag_p, :length => 2
163
+ string :vlana, :length => 2
164
+ string :vlanb, :length => 2
165
+ string :ip_packet, :length => 40
166
+ end
167
+
168
+ class Sflow5rawpacketdataVLAN < BinData::Record
169
+ endian :big
170
+ uint16 :prio
171
+ uint16 :type
172
+ array :vlandata, :read_until => :eof do
173
+ string :data, :length => 1
174
+ end
175
+ end
176
+
@@ -0,0 +1,69 @@
1
+ # coding: utf-8
2
+ require_relative 'protocol'
3
+
4
+ # TODO: チェックサムを確認する
5
+ class IPv4Header
6
+
7
+ attr_reader :version,:header_length,:packet_length,:identification,:frag_dont,:frag_more,:frag_offset,:ttl,:protocol,:checksum,:sndr_addr,:dest_addr,
8
+ :data_length
9
+
10
+ def initialize(packet,offset=0)
11
+ @packet = packet.force_encoding("ASCII-8BIT")
12
+ @offset = offset
13
+ header = packet.unpack("x#{offset}n10")
14
+ @version = header[0] >> 12
15
+ @header_length = ((header[0] >> 8) & 0x0f)*4
16
+ @packet_length = header[1]
17
+ @identification = header[2]
18
+ @frag_dont = (header[3] >> 14) & 0x01 != 0
19
+ @frag_more = (header[3] >> 13) & 0x01 != 0
20
+ @frag_offset = header[3] & 0x1fff
21
+ @ttl = header[4] >> 8
22
+ @protocol = header[4] & 0x00ff
23
+ @checksum = header[5]
24
+ @sndr_addr = ip_to_s(packet[12..15])
25
+ @dest_addr = ip_to_s(packet[16..19])
26
+ @data_length = @packet_length - @header_length
27
+
28
+ @virtual_header = packet[12..19] + [0,6,@data_length].pack("CCn")
29
+
30
+ end
31
+
32
+ def upper
33
+ upper_header = Protocol.to_class(@protocol)
34
+ offset = @offset+@header_length
35
+ upper_header.new(@packet,offset,@data_length,self)
36
+ end
37
+
38
+ def data
39
+ start = @offset+@header_length
40
+ @packet[start..start+@data_length]
41
+ end
42
+
43
+ def get_virtual_header
44
+ @virtual_header
45
+ end
46
+
47
+ def ip_to_s(ip)
48
+ ip = ip.unpack("n2")
49
+ sprintf("%d.%d.%d.%d",ip[0]>>8,ip[0]&0x00ff,ip[1]>>8,ip[1]&0x00ff)
50
+ end
51
+
52
+ def to_s
53
+ "IPv4 Header\n" <<
54
+ " Version : #{@version}\n" <<
55
+ " Header Length : #{@header_length}\n" <<
56
+ " Packet Length : #{@packet_length}\n" <<
57
+ " Identification : #{@identification}\n" <<
58
+ " Don't fragment : #{@frag_dont}\n" <<
59
+ " More fragments : #{@frag_more}\n" <<
60
+ " Fragment Offset : #{@frag_offset}\n" <<
61
+ " TTL : #{@ttl}\n" <<
62
+ " Protocol : #{Protocol.to_s(@protocol)}\n" <<
63
+ " Header Checksum : #{@checksum}\n" <<
64
+ " Sender Address : #{@sndr_addr}\n" <<
65
+ " Destination Address: #{@dest_addr}\n" <<
66
+ " (Data Length) : #{@data_length}"
67
+ end
68
+
69
+ end
@@ -0,0 +1,47 @@
1
+ require_relative 'ipv4header'
2
+ require_relative 'udpheader'
3
+ require_relative 'tcpheader'
4
+
5
+ class Protocol
6
+ ICMP = 0x01
7
+ IGMP = 0x02
8
+ TCP = 0x06
9
+ UDP = 0x11
10
+ IPv6 = 0x29
11
+
12
+ def self.to_class protocol
13
+ case protocol
14
+ when Protocol::ICMP
15
+ raise "ICMP is not supported"
16
+ when Protocol::IGMP
17
+ raise "IGMP is not supported"
18
+ when Protocol::TCP
19
+ TCPHeader
20
+ when Protocol::UDP
21
+ UDPHeader
22
+ when Protocol::IPv6
23
+ raise "IPv6 is not supported"
24
+ else
25
+ raise "Protocol:"+sprintf("0x%2X",protocol)+" is not supported"
26
+ end
27
+ end
28
+
29
+ def self.to_s protocol
30
+ case protocol
31
+ when Protocol::ICMP
32
+ "ICMP"
33
+ when Protocol::IGMP
34
+ "IGMP"
35
+ when Protocol::TCP
36
+ "TCP"
37
+ when Protocol::UDP
38
+ "UDP"
39
+ when Protocol::IPv6
40
+ "IPv6"
41
+ else
42
+ sprintf("0x%2X",protocol)
43
+ end
44
+ end
45
+
46
+ end
47
+
@@ -0,0 +1,82 @@
1
+ class TCPHeader
2
+
3
+ attr_reader :sndr_port,:dest_port,:seq_num,:ack_num,:header_length,
4
+ :urg,:ack,:psh,:rst,:syn,:fin,:win_size,:checksum,:emgcy_ptr,
5
+ :packet_length,:data_length,:lower
6
+
7
+ def initialize(packet,offset=0,length=nil,lower=nil)
8
+ @packet = packet.force_encoding("ASCII-8BIT")
9
+ @offset = offset
10
+ @length = length || packet.bytesize-offset
11
+ header = packet.unpack("x#{offset}n2N2n4")
12
+ @sndr_port = header[0]
13
+ @dest_port = header[1]
14
+ @seq_num = header[2]
15
+ @ack_num = header[3]
16
+ @header_length = (header[4]>>12)*4
17
+ @urg = (header[4] & 0b100000) != 0
18
+ @ack = (header[4] & 0b010000) != 0
19
+ @psh = (header[4] & 0b001000) != 0
20
+ @rst = (header[4] & 0b000100) != 0
21
+ @syn = (header[4] & 0b000010) != 0
22
+ @fin = (header[4] & 0b000001) != 0
23
+ @win_size = header[5]
24
+ @checksum = header[6]
25
+ @emgcy_ptr = header[7]
26
+
27
+ @packet_length = @length
28
+ @data_length = @packet_length-@header_length
29
+
30
+ @lower = lower
31
+
32
+ # check checksum
33
+ calc_cs = false
34
+ if calc_cs
35
+ tmp = @packet[@offset..@offset+@length]
36
+ if (tmp.length % 2) != 0
37
+ tmp += "\0"
38
+ end
39
+ data = @lower.get_virtual_header + tmp
40
+ sum = 0
41
+ list = data.unpack("n*")
42
+ list.each do |d|
43
+ sum += d
44
+ end
45
+ sum = (sum & 0xffff) + (sum >> 16)
46
+ sum = (sum & 0xffff) + (sum >> 16)
47
+ raise if sum != 65535
48
+ end
49
+
50
+
51
+
52
+
53
+ end
54
+
55
+ def data
56
+ if(@data_length>0)
57
+ @packet[@offset+@header_length..@offset+@length]
58
+ else
59
+ ""
60
+ end
61
+ end
62
+
63
+ def to_s
64
+ "TCP Header\n" <<
65
+ " Sender Port : #{@sndr_port}\n" <<
66
+ " Destination Port: #{@dest_port}\n" <<
67
+ " Sequence Number : #{@seq_num}\n" <<
68
+ " ACK Number : #{@ack_num}\n" <<
69
+ " Header Length : #{@header_length}\n" <<
70
+ " URG : #{@urg}\n" <<
71
+ " ACK : #{@ack}\n" <<
72
+ " PSH : #{@psh}\n" <<
73
+ " RST : #{@rst}\n" <<
74
+ " SYN : #{@syn}\n" <<
75
+ " FIN : #{@fin}\n" <<
76
+ " Window Size : #{@win_size}\n" <<
77
+ " Checksum : #{@checksum}\n" <<
78
+ " Emergency Ptr : #{@emgcy_ptr}\n" <<
79
+ " (Packet Length) : #{@packet_length}\n" <<
80
+ " (Data Length) : #{@data_length}"
81
+ end
82
+ end