broccoli 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +21 -0
- data/README +44 -0
- data/examples/broconn.bro +26 -0
- data/examples/broconn.rb +47 -0
- data/examples/broenum.rb +122 -0
- data/examples/brohose.bro +30 -0
- data/examples/brohose.rb +169 -0
- data/examples/broping-record.bro +56 -0
- data/examples/broping.bro +37 -0
- data/examples/broping.rb +148 -0
- data/examples/dns_requests.rb +35 -0
- data/ext/broccoli/autogen.sh +3 -0
- data/ext/broccoli/broccoli.i +507 -0
- data/ext/broccoli/broccoli_wrap.c +6125 -0
- data/ext/broccoli/extconf.rb +16 -0
- data/ext/broccoli/post-clean.rb +3 -0
- data/ext/broccoli/pre-config.rb +5 -0
- data/ext/broccoli/test/broconftest.rb +12 -0
- data/ext/broccoli/test/test.rb +174 -0
- data/lib/Bro/connection.rb +78 -0
- data/lib/Bro/event.rb +34 -0
- data/lib/Bro/record.rb +71 -0
- data/lib/bro.rb +87 -0
- data/setup.rb +1585 -0
- metadata +66 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
if ex = find_executable("broccoli-config")
|
4
|
+
$CFLAGS << " " + `#{ex} --cflags`.chomp
|
5
|
+
$LDFLAGS << " " + `#{ex} --libs`.chomp
|
6
|
+
else
|
7
|
+
raise "You need to have 'broccoli-config' in your path!"
|
8
|
+
end
|
9
|
+
|
10
|
+
if have_header("broccoli.h") and
|
11
|
+
# check the broccoli library for the existence
|
12
|
+
# of the new event registration function
|
13
|
+
have_library("broccoli", "bro_event_registry_add_compact") and
|
14
|
+
have_library("ssl")
|
15
|
+
create_makefile("broccoli")
|
16
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# Please don't try to read too much into this file. It's mostly my
|
2
|
+
# internal test file while I'm building the C binding.
|
3
|
+
#
|
4
|
+
# Check out the examples directory for better examples that use the ruby
|
5
|
+
# library I've built overtop the C bindings.
|
6
|
+
|
7
|
+
require './broccoli_ext'
|
8
|
+
include Broccoli_ext
|
9
|
+
Broccoli_ext::bro_debug_calltrace=false
|
10
|
+
Broccoli_ext::bro_debug_messages=false
|
11
|
+
|
12
|
+
STDOUT.sync = true
|
13
|
+
|
14
|
+
#a= Broccoli_ext::BroString.new
|
15
|
+
#a.str_val="asdf"
|
16
|
+
|
17
|
+
host_str = "127.0.0.1:12345"
|
18
|
+
|
19
|
+
bc = bro_conn_new_str(host_str, BRO_CFLAG_NONE)
|
20
|
+
puts "Connection? #{bc}"
|
21
|
+
#puts " Connected" unless bro_conn_connect(bc).zero?
|
22
|
+
|
23
|
+
###
|
24
|
+
# Test BroString Creation
|
25
|
+
###
|
26
|
+
|
27
|
+
module SWIG
|
28
|
+
class TYPE_p_bro_conn
|
29
|
+
def method_missing(meth, *args)
|
30
|
+
return bro_conn_data_get(self, meth.id2name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class TYPE_p_bro_record
|
35
|
+
# I need to build a full record typemapper to deal with this correctly.
|
36
|
+
|
37
|
+
def method_missing(meth, *args)
|
38
|
+
#return bro_record_get_named_val(self, meth.id2name, BRO_TYPE_STRING)
|
39
|
+
end
|
40
|
+
|
41
|
+
def [](position)
|
42
|
+
#return bro_record_get_nth_val(self, position, BRO_TYPE_STRING)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
###
|
50
|
+
# Test Record Creation
|
51
|
+
###
|
52
|
+
#rec = bro_record_new()
|
53
|
+
#puts "Ruby: Inserting data into the record"
|
54
|
+
##time = bro_util_current_time()
|
55
|
+
##puts "Ruby: Current time: #{time}"
|
56
|
+
#bro_record_add_val(rec, "seq", BRO_TYPE_IPADDR, 213054988)
|
57
|
+
#puts "Ruby: Getting the data back out"
|
58
|
+
##puts bro_record_get_named_val(rec, "seq", BRO_TYPE_COUNT);
|
59
|
+
#puts " " + bro_record_get_nth_val(rec, 0, BRO_TYPE_IPADDR).to_s
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
###
|
64
|
+
# Test Callback creation
|
65
|
+
###
|
66
|
+
|
67
|
+
# Ideal :)
|
68
|
+
#bro_ruby_typemap_new("pong", [8,19,0])
|
69
|
+
#build_typemap("pong", [:conn,:record])
|
70
|
+
|
71
|
+
#while 1
|
72
|
+
# ev = bro_event_new("ping")
|
73
|
+
# bro_event_free(ev)
|
74
|
+
# #GC.start
|
75
|
+
#end
|
76
|
+
|
77
|
+
bro_pong_record = Proc.new do |conn, rec|
|
78
|
+
now = bro_util_current_time()
|
79
|
+
puts "Pong_record callback"
|
80
|
+
puts rec
|
81
|
+
|
82
|
+
seq = bro_record_get_nth_val(rec, 0, BRO_TYPE_COUNT)
|
83
|
+
src_time = bro_record_get_nth_val(rec, 1, BRO_TYPE_TIME)
|
84
|
+
dst_time = bro_record_get_nth_val(rec, 2, BRO_TYPE_TIME)
|
85
|
+
|
86
|
+
puts "pong event from #{host_str}: seq=#{seq}, time=#{dst_time-src_time}/#{now-src_time} s"
|
87
|
+
end
|
88
|
+
|
89
|
+
bro_pong = Proc.new do |conn, src_time, dst_time, seq|
|
90
|
+
puts "Pong callback!"
|
91
|
+
now = bro_util_current_time()
|
92
|
+
puts "pong event from #{host_str}: seq=#{seq}, time=#{dst_time-src_time}/#{now-src_time} s"
|
93
|
+
end
|
94
|
+
|
95
|
+
new_connection = Proc.new do |conn|
|
96
|
+
puts "Saw a connection!"
|
97
|
+
end
|
98
|
+
|
99
|
+
dns_request = Proc.new do |conn, msg, query, qtype, qclass|
|
100
|
+
#$count = $count+1
|
101
|
+
#puts "msg: #{msg}"
|
102
|
+
#puts "query: #{query}"
|
103
|
+
#puts "qtype: #{qtype}"
|
104
|
+
#puts "qclass: #{qclass}"
|
105
|
+
#puts "service: #{conn.blah}"
|
106
|
+
#puts "Query output class: #{query.class}"
|
107
|
+
#answers = bro_record_get_nth_val(msg, 11, BRO_TYPE_COUNT).to_s
|
108
|
+
#puts "Number of dns answers: #{answers}"
|
109
|
+
#puts "Query: #{query} - Query type: #{qtype} - Query class: #{qclass}"
|
110
|
+
end
|
111
|
+
|
112
|
+
#puts "Registering callback..."
|
113
|
+
#bro_event_registry_add(bc, "dns_A_reply", dns_reply)
|
114
|
+
|
115
|
+
bro_event_registry_add(bc, "dns_request", ["dns_request", [19, 19, 8, 3, 3], dns_request])
|
116
|
+
|
117
|
+
#bro_event_registry_add(bc, "pong", ["pong", {"pong", [19]}, bro_pong_record])
|
118
|
+
#bro_event_registry_add(bc, "pong", ["pong", {"pong", [6,6,3]}, bro_pong])
|
119
|
+
|
120
|
+
#bro_event_registry_add(bc, "wootback", [[8], wootback])
|
121
|
+
|
122
|
+
#bro_event_registry_add(bc, "new_connection", ["new_connection", {"new_connection", [19]}, new_connection])
|
123
|
+
#bro_event_registry_add(bc, "return_memory", return_memory)
|
124
|
+
|
125
|
+
#puts "Done Registering callback..."
|
126
|
+
puts "Connected" if bro_conn_connect(bc)
|
127
|
+
|
128
|
+
while(1)
|
129
|
+
#puts "Checking input"
|
130
|
+
$count = 0
|
131
|
+
bro_conn_process_input(bc)
|
132
|
+
puts "*" * ($count/2)
|
133
|
+
|
134
|
+
sleep 0.5
|
135
|
+
|
136
|
+
GC.start
|
137
|
+
end
|
138
|
+
exit
|
139
|
+
|
140
|
+
###
|
141
|
+
# Testing record creation and event sending
|
142
|
+
###
|
143
|
+
record = false
|
144
|
+
(1..100).each do |seq|
|
145
|
+
bro_conn_process_input(bc)
|
146
|
+
#puts "Creating event"
|
147
|
+
ev = bro_event_new("ping")
|
148
|
+
timestamp = bro_util_current_time()
|
149
|
+
if(record)
|
150
|
+
rec = bro_record_new()
|
151
|
+
bro_record_add_val(rec, "seq", BRO_TYPE_COUNT, seq)
|
152
|
+
bro_record_add_val(rec, "src_time", BRO_TYPE_TIME, timestamp)
|
153
|
+
bro_event_add_val(ev, BRO_TYPE_RECORD, rec)
|
154
|
+
else
|
155
|
+
bro_event_add_val(ev, BRO_TYPE_TIME, timestamp)
|
156
|
+
bro_event_add_val(ev, BRO_TYPE_COUNT, seq)
|
157
|
+
end
|
158
|
+
|
159
|
+
puts "Sending ping..."
|
160
|
+
bro_event_send(bc, ev)
|
161
|
+
# May not need to call this anymore either
|
162
|
+
#bro_event_free(ev)
|
163
|
+
sleep 1
|
164
|
+
#GC.start
|
165
|
+
end
|
166
|
+
|
167
|
+
#while(1) do
|
168
|
+
# ev = bro_event_new "show_memory"
|
169
|
+
# puts "Sending event"
|
170
|
+
# puts bro_event_send(bc, ev)
|
171
|
+
# sleep 1
|
172
|
+
# puts "Processing input..."
|
173
|
+
# puts bro_conn_process_input(bc)
|
174
|
+
#end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# This gives a nice interface for retrieving fields from connections
|
2
|
+
module SWIG
|
3
|
+
class TYPE_p_bro_conn
|
4
|
+
def method_missing(meth, *args)
|
5
|
+
return Broccoli::bro_conn_data_get(self, meth.id2name)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module Bro
|
11
|
+
class Connection
|
12
|
+
include Broccoli
|
13
|
+
|
14
|
+
def initialize(hp, flags=nil)
|
15
|
+
flags ||= (BRO_CFLAG_RECONNECT | BRO_CFLAG_ALWAYS_QUEUE)
|
16
|
+
@bc = bro_conn_new_str(hp, flags)
|
17
|
+
@io_object = nil
|
18
|
+
@event_blocks = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def disconnect
|
22
|
+
bro_conn_delete(@bc)
|
23
|
+
end
|
24
|
+
|
25
|
+
def connect
|
26
|
+
bro_conn_connect(@bc)
|
27
|
+
end
|
28
|
+
|
29
|
+
def connected?
|
30
|
+
bro_conn_alive?(@bc)
|
31
|
+
end
|
32
|
+
|
33
|
+
def process_input
|
34
|
+
bro_conn_process_input(@bc)
|
35
|
+
end
|
36
|
+
|
37
|
+
def queue_length
|
38
|
+
bro_event_queue_length(@bc)
|
39
|
+
end
|
40
|
+
|
41
|
+
def queue_length_max
|
42
|
+
bro_event_queue_length_max(@bc)
|
43
|
+
end
|
44
|
+
|
45
|
+
def queue_flush
|
46
|
+
bro_event_queue_flush(@bc)
|
47
|
+
end
|
48
|
+
|
49
|
+
def send(event)
|
50
|
+
# .ev is the real event pointer
|
51
|
+
bro_event_send(@bc, event.ev)
|
52
|
+
end
|
53
|
+
|
54
|
+
def wait
|
55
|
+
unless @io_object
|
56
|
+
fd = bro_conn_get_fd(@bc)
|
57
|
+
return false if fd < 0
|
58
|
+
@io_object = IO.new(fd)
|
59
|
+
@io_object.sync = true # don't buffer
|
60
|
+
end
|
61
|
+
# block until there is data
|
62
|
+
if @io_object.closed?
|
63
|
+
puts "ERROR: connection lost!"
|
64
|
+
exit -1
|
65
|
+
else
|
66
|
+
IO.select([@io_object])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def event_handler(event, &callback)
|
71
|
+
bro_event_registry_add_compact(@bc, event, callback)
|
72
|
+
# Re-request all events if we're already connected.
|
73
|
+
bro_event_registry_request(@bc) if connected?
|
74
|
+
end
|
75
|
+
alias :event_handler_for :event_handler
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
data/lib/Bro/event.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Bro
|
2
|
+
|
3
|
+
class Event
|
4
|
+
include Broccoli
|
5
|
+
attr_reader :ev
|
6
|
+
|
7
|
+
def initialize(name)
|
8
|
+
@ev = bro_event_new(name)
|
9
|
+
# Kill the BroEvent when the ruby object is garbage collected
|
10
|
+
ObjectSpace.define_finalizer(self, Event.create_finalizer(@ev))
|
11
|
+
end
|
12
|
+
|
13
|
+
# Insert a value into an event.
|
14
|
+
def insert(value, type, type_name=nil)
|
15
|
+
value = value.rec if type == :record
|
16
|
+
bro_event_add_val(@ev, [Bro::TYPES[type], type_name, value])
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Free the underlying C event data structure. User's are likely
|
22
|
+
# never going to need this call.
|
23
|
+
def free
|
24
|
+
bro_event_free(@ev)
|
25
|
+
end
|
26
|
+
|
27
|
+
# When the garbage collector comes around, make sure the C structure
|
28
|
+
# is freed.
|
29
|
+
def self.create_finalizer(event)
|
30
|
+
proc { bro_event_free(event) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/lib/Bro/record.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# This gives a nice interface for retrieving fields from records
|
2
|
+
module SWIG
|
3
|
+
class TYPE_p_bro_record
|
4
|
+
include Broccoli
|
5
|
+
|
6
|
+
# .id is a method for all ruby objects. Move it out of the way for records.
|
7
|
+
alias :orig_id :id
|
8
|
+
def id
|
9
|
+
return method_missing(:id)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Retrieve record value by name
|
13
|
+
def method_missing(meth, *args)
|
14
|
+
bro_record_get_named_val(self, meth.id2name)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Retrieve record value by position
|
18
|
+
def [](pos)
|
19
|
+
bro_record_get_nth_val(self, pos.to_i)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
module Bro
|
26
|
+
class Record
|
27
|
+
include Broccoli
|
28
|
+
attr_accessor :rec
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
@rec = bro_record_new()
|
32
|
+
# Kill the BroRecord when the ruby object is garbage collected
|
33
|
+
ObjectSpace.define_finalizer(self, Record.create_finalizer(@rec))
|
34
|
+
end
|
35
|
+
|
36
|
+
# .id is a method for all ruby objects. Move it out of the way for records.
|
37
|
+
alias :orig_id :id
|
38
|
+
def id
|
39
|
+
return method_missing(:id)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Forward any missing methods on to the actual record object
|
43
|
+
def method_missing(meth)
|
44
|
+
@rec.send(meth)
|
45
|
+
end
|
46
|
+
|
47
|
+
def insert(name, value, type, type_name=nil)
|
48
|
+
value = value.rec if type == :record
|
49
|
+
bro_record_add_val(@rec, name.to_s, [Bro::TYPES[type], type_name, value])
|
50
|
+
end
|
51
|
+
|
52
|
+
def insert_at(pos, value, type, type_name=nil)
|
53
|
+
value = value.rec if type == :record
|
54
|
+
bro_record_set_nth_val(@rec, pos, [Bro::TYPES[type], type_name, value])
|
55
|
+
end
|
56
|
+
alias :insert_at_position :insert_at
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def free
|
61
|
+
bro_record_free(@rec)
|
62
|
+
end
|
63
|
+
|
64
|
+
# When the garbage collector comes around,
|
65
|
+
# make sure the C structure is freed.
|
66
|
+
def self.create_finalizer(record)
|
67
|
+
proc { bro_record_free(record) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
data/lib/bro.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'broccoli'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
require 'bro/connection'
|
5
|
+
require 'bro/event'
|
6
|
+
require 'bro/record'
|
7
|
+
|
8
|
+
module Bro
|
9
|
+
include Broccoli
|
10
|
+
|
11
|
+
TYPES = {:unknown => BRO_TYPE_UNKNOWN, # not really sure how this should be handled.
|
12
|
+
:bool => BRO_TYPE_BOOL,
|
13
|
+
:int => BRO_TYPE_INT,
|
14
|
+
:count => BRO_TYPE_COUNT,
|
15
|
+
:counter => BRO_TYPE_COUNTER,
|
16
|
+
:double => BRO_TYPE_DOUBLE,
|
17
|
+
:time => BRO_TYPE_TIME,
|
18
|
+
:interval => BRO_TYPE_INTERVAL,
|
19
|
+
:string => BRO_TYPE_STRING,
|
20
|
+
:enum => BRO_TYPE_ENUM,
|
21
|
+
:timer => BRO_TYPE_TIMER,
|
22
|
+
:port => BRO_TYPE_PORT,
|
23
|
+
:addr => BRO_TYPE_IPADDR,
|
24
|
+
:net => BRO_TYPE_NET,
|
25
|
+
:subnet => BRO_TYPE_SUBNET,
|
26
|
+
:record => BRO_TYPE_RECORD,
|
27
|
+
# These are not handled by the ruby binding.
|
28
|
+
:packet => BRO_TYPE_PACKET,
|
29
|
+
:max => BRO_TYPE_MAX,
|
30
|
+
# All types below are NOT handled by broccoli.
|
31
|
+
:pattern => BRO_TYPE_PATTERN,
|
32
|
+
:any => BRO_TYPE_ANY,
|
33
|
+
:table => BRO_TYPE_TABLE,
|
34
|
+
:union => BRO_TYPE_UNION,
|
35
|
+
:list => BRO_TYPE_LIST,
|
36
|
+
:func => BRO_TYPE_FUNC,
|
37
|
+
:file => BRO_TYPE_FILE,
|
38
|
+
:vector => BRO_TYPE_VECTOR,
|
39
|
+
:error => BRO_TYPE_ERROR
|
40
|
+
}
|
41
|
+
|
42
|
+
def Bro.current_time_f
|
43
|
+
Broccoli::bro_util_current_time
|
44
|
+
end
|
45
|
+
|
46
|
+
def Bro.current_time
|
47
|
+
Time.at( current_time_f() )
|
48
|
+
end
|
49
|
+
|
50
|
+
def Bro.debug_calltrace=(v)
|
51
|
+
Broccoli::bro_debug_calltrace=v
|
52
|
+
end
|
53
|
+
|
54
|
+
def Bro.debug_messages=(v)
|
55
|
+
Broccoli::bro_debug_messages=v
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Broccoli::BroPort
|
60
|
+
@@protocols = {0=>'ip', 1=>'icmp', 2=>'igmp', 3=>'ggp', 4=>'ipv4',
|
61
|
+
6=>'tcp', 7=>'st', 8=>'egp', 9=>'pigp', 10=>'rccmon',
|
62
|
+
11=>'nvpii', 12=>'pup', 13=>'argus', 14=>'emcon',
|
63
|
+
15=>'xnet', 16=>'chaos', 17=>'udp', 18=>'mux', 19=>'meas',
|
64
|
+
20=>'hmp', 21=>'prm', 22=>'idp', 23=>'trunk1', 24=>'trunk2',
|
65
|
+
25=>'leaf1', 26=>'leaf2', 27=>'rdp', 28=>'irtp', 29=>'tp',
|
66
|
+
30=>'blt', 31=>'nsp', 32=>'inp', 33=>'sep', 34=>'3pc',
|
67
|
+
35=>'idpr', 36=>'xtp', 37=>'ddp', 38=>'cmtp', 39=>'tpxx',
|
68
|
+
40=>'il', 41=>'ipv6', 42=>'sdrp', 43=>'routing',
|
69
|
+
44=>'fragment', 45=>'idrp', 46=>'rsvp', 47=>'gre', 48=>'mhrp',
|
70
|
+
49=>'bha', 50=>'esp', 51=>'ah', 52=>'inlsp', 53=>'swipe',
|
71
|
+
54=>'nhrp', 58=>'icmpv6', 59=>'nonext', 60=>'dstopts',
|
72
|
+
61=>'ahip', 62=>'cftp', 63=>'hello', 64=>'satexpak',
|
73
|
+
65=>'kryptolan', 66=>'rvd', 67=>'ippc', 68=>'adfs',
|
74
|
+
69=>'satmon', 70=>'visa', 71=>'ipcv', 72=>'cpnx', 73=>'cphb',
|
75
|
+
74=>'wsn', 75=>'pvp', 76=>'brsatmon', 77=>'nd', 78=>'wbmon',
|
76
|
+
79=>'wbexpak', 80=>'eon', 81=>'vmtp', 82=>'svmtp',
|
77
|
+
83=>'vines', 84=>'ttp', 85=>'igp', 86=>'dgp', 87=>'tcf',
|
78
|
+
88=>'igrp', 89=>'ospfigp', 90=>'srpc', 91=>'larp', 92=>'mtp',
|
79
|
+
93=>'ax25', 94=>'ipeip', 95=>'micp', 96=>'sccsp',
|
80
|
+
97=>'etherip', 98=>'encap', 99=>'apes', 100=>'gmtp',
|
81
|
+
103=>'pim', 108=>'ipcomp', 113=>'pgm', 254=>'divert',
|
82
|
+
255=>'raw'}
|
83
|
+
def to_s
|
84
|
+
#"#{port_num}/#{@@protocols[port_proto]}"
|
85
|
+
port_num.to_s
|
86
|
+
end
|
87
|
+
end
|