broccoli 1.3.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.
- 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
|