rbroccoli 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ require 'mkmf'
2
+
3
+ if ex = find_executable("broccoli-config")
4
+ $CFLAGS << " " + `#{ex} --cflags`.chomp
5
+ $LDFLAGS << " " + `#{ex} --libs`.chomp
6
+ else
7
+ puts "You need to have broccoli-config in your path!"
8
+ exit(-1)
9
+ end
10
+
11
+ if have_header("broccoli.h") and
12
+ have_library("broccoli") and
13
+ have_library("ssl")
14
+ create_makefile('broccoli_ext')
15
+ end
@@ -0,0 +1,3 @@
1
+
2
+ File.delete 'mkmf.log' if File.exists? 'mkmf.log'
3
+ File.delete 'Makefile' if File.exists? 'Makefile'
@@ -0,0 +1,5 @@
1
+ bc = `which broccoli-config`
2
+ unless bc.length > 0
3
+ puts "You need to have broccoli-config in your path!"
4
+ exit(-1)
5
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'broccoli_ext'
4
+ include Broccoli_ext
5
+
6
+ peer = bro_conf_get_str("PeerName")
7
+ puts "Peer: #{peer}"
8
+
9
+ ret, port = bro_conf_get_int("PeerPort")
10
+ if(ret)
11
+ puts "PeerPort: #{ret}"
12
+ 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,73 @@
1
+ require 'broccoli_ext'
2
+
3
+ module Bro
4
+ class Connection
5
+ include Broccoli_ext
6
+
7
+ def initialize(hp, flags=nil)
8
+ flags = (BRO_CFLAG_RECONNECT | BRO_CFLAG_ALWAYS_QUEUE) if flags.nil?
9
+ @bc = bro_conn_new_str(hp, flags)
10
+ @io_object = nil
11
+ @event_blocks = []
12
+ end
13
+
14
+ def delete
15
+ bro_conn_delete(@bc)
16
+ end
17
+
18
+ def connect
19
+ bro_conn_connect(@bc)
20
+ end
21
+
22
+ def connected?
23
+ bro_conn_alive?(@bc)
24
+ end
25
+
26
+ def process_input
27
+ bro_conn_process_input(@bc)
28
+ end
29
+
30
+ def queue_length
31
+ bro_event_queue_length(@bc)
32
+ end
33
+
34
+ def flush
35
+ bro_event_queue_flush(@bc)
36
+ end
37
+
38
+ def send(event)
39
+ # .ev is the real event pointer
40
+ bro_event_send(@bc, event.ev)
41
+ end
42
+
43
+ def wait
44
+ unless @io_object
45
+ fd = bro_conn_get_fd(@bc)
46
+ return false if fd < 0
47
+ @io_object = IO.new(fd)
48
+ end
49
+ # block until there is data
50
+ select([@io_object])
51
+ end
52
+
53
+ def event_handler(event, mapping=nil, &block)
54
+ # This lets me pass the proc object and the event name into the callback
55
+ # It needs to be done so that the typemapper can map types before
56
+ # calling the proc object.
57
+ # TODO: maybe make this less hacky?
58
+ Bro::Typemap.define_event(event, mapping) unless mapping.nil?
59
+
60
+ typemap = Bro::Typemap.get(:callback, event)
61
+
62
+ event_block = [event, typemap, block]
63
+ @event_blocks << event_block
64
+
65
+ bro_event_registry_add(@bc, event, event_block)
66
+
67
+ # Re-request all events if we're already connected.
68
+ bro_event_registry_request(@bc) if connected?
69
+ end
70
+ alias :event_handler_for :event_handler
71
+
72
+ end
73
+ end
data/lib/Bro/event.rb ADDED
@@ -0,0 +1,34 @@
1
+ module Bro
2
+
3
+ class Event
4
+ include Broccoli_ext
5
+ attr_reader :ev
6
+
7
+ def initialize(name)
8
+ @event_name = name
9
+ @ev = bro_event_new(name)
10
+ @current_val = 0
11
+ ObjectSpace.define_finalizer(self, Event.create_finalizer(@ev))
12
+ end
13
+
14
+ def insert(value)
15
+ name_type, int_type = Bro::Typemap.get(:callback, @event_name, @current_val)
16
+ #puts "(#{@ev}, #{int_type}, #{value})"
17
+ # TODO: Yikes! more hacks to get this thing working
18
+ value = value.rec if int_type == Broccoli_ext::BRO_TYPE_RECORD
19
+ bro_event_add_val(@ev, int_type, value)
20
+ @current_val += 1
21
+ end
22
+
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,60 @@
1
+ module Bro
2
+
3
+ class Record
4
+ include Broccoli_ext
5
+ attr_accessor :rec
6
+
7
+ def initialize(type=nil)
8
+ @type = type
9
+ @rec = bro_record_new()
10
+ if type
11
+ @rec.record_type = type
12
+ else
13
+ # Generate a "unique" name for this record since no type was given
14
+ # It allows the record to read back it's own values by storing types
15
+ # as it is created.
16
+ @rec.record_type = rand().to_s
17
+ # TODO: abstract into typemapper
18
+ $bro_global_typemap[:record][@rec.record_type] = {}
19
+ end
20
+ @current_val = 0
21
+ ObjectSpace.define_finalizer(self, Record.create_finalizer(@rec))
22
+ end
23
+
24
+ def method_missing(meth)
25
+ @rec.send(meth)
26
+ end
27
+
28
+ def insert(name, value, value_type=nil)
29
+ if value_type.nil? and @rec.record_type.nil?
30
+ raise "No type inferred.. type must be given"
31
+ end
32
+ if not value_type
33
+ name_type, int_type = Bro::Typemap.get(:record, @type, name)
34
+ else
35
+ int_type = Bro::Typemap.get_int_type(value_type)
36
+ # TODO: needs to be abstracted into the typemapper
37
+ $bro_global_typemap[:record][@rec.record_type][name.to_sym] = value_type
38
+ end
39
+ #puts "(#{@rec}, #{name.to_s}, #{int_type}, #{value})"
40
+ Broccoli_ext::bro_record_add_val(@rec, name.to_s, int_type, value)
41
+ @current_val += 1
42
+ end
43
+
44
+ def []=(key, val, type)
45
+ int_type = Bro::Typemap.get_int_type(type)
46
+ Broccoli_ext::bro_record_set_nth_val(@rec, key, int_type, val)
47
+ end
48
+
49
+ def free
50
+ bro_record_free(@rec)
51
+ end
52
+
53
+ # When the garbage collector comes around,
54
+ # make sure the C structure is freed.
55
+ def self.create_finalizer(record)
56
+ proc { bro_record_free(record) }
57
+ end
58
+ end
59
+
60
+ end
@@ -0,0 +1,158 @@
1
+ require 'yaml'
2
+ require 'time'
3
+
4
+ module Bro
5
+ module Typemap
6
+
7
+ DATA_TYPEMAP = {:bool => 1,
8
+ :int => 2,
9
+ :count => 3,
10
+ :counter => 4,
11
+ :double => 5,
12
+ :time => 6,
13
+ :interval => 7,
14
+ :string => 8,
15
+ :pattern => 9,
16
+ :enum => 10,
17
+ :timer => 11,
18
+ :port => 12,
19
+ :addr => 13,
20
+ :net => 14,
21
+ :subnet => 15,
22
+ :record => 19
23
+ }
24
+
25
+
26
+ def Typemap.get_int_type(type)
27
+ type_code = DATA_TYPEMAP[type]
28
+ if type_code.nil?
29
+ Broccoli_ext::BRO_TYPE_RECORD
30
+ else
31
+ type_code
32
+ end
33
+ end
34
+
35
+ # TODO: this is an utter mess
36
+ def Typemap.get(typemap, name, key=nil)
37
+ if key
38
+ if typemap == :record and key.class == Fixnum
39
+ # this is especially bad
40
+ foo = $bro_global_typemap[typemap][name].to_a[key][1]
41
+ elsif typemap == :callback and key.class == Fixnum
42
+ foo = $bro_global_typemap[typemap][name][key]
43
+ else
44
+ foo = $bro_global_typemap[typemap][name.to_sym][key.to_sym]
45
+ end
46
+ return [foo, get_int_type(foo)]
47
+ else
48
+ foo = $bro_global_typemap[typemap][name]
49
+ return foo.inject([]) { |out, t| out << get_int_type(t) }
50
+ end
51
+ end
52
+
53
+ def Typemap.insert(typemap_type, name, map)
54
+ $bro_global_typemap[typemap_type][name] = map
55
+ end
56
+
57
+ def Typemap.define_event(event, mapping)
58
+ map = mapping.collect { |m| m.to_sym }
59
+ Bro::Typemap.insert(:callback, event, map)
60
+ end
61
+
62
+ def Typemap.define_record(record_name, mapping)
63
+ new_mapping = {}
64
+ mapping.each { |k,v| new_mapping[k.to_sym] = v.to_sym}
65
+ Bro::Typemap.insert(:record, record_name.to_sym, new_mapping)
66
+ end
67
+
68
+ def Typemap.load
69
+ $bro_global_typemap = {}
70
+ if __FILE__.match(File.join("gems", "rbroccoli"))
71
+ # Gem installed
72
+ dir = File.join(File.dirname(__FILE__), '..', '..', 'data', 'bro')
73
+ else
74
+ # Native install
75
+ $:.each do |path|
76
+ if m = path.match(File.join("lib", "ruby"))
77
+ # Supporting native install
78
+ tmp_dir = File.join(m.pre_match, "share", "bro")
79
+ if File.exists?(tmp_dir)
80
+ dir = tmp_dir
81
+ break
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ if !dir
88
+ # Check if it isn't installed
89
+ dir = File.join(File.dirname(__FILE__), '..', '..', 'data', 'bro')
90
+ end
91
+ $bro_global_typemap[:callback] = YAML.load_file("#{dir}/callback-typemaps.yml")
92
+ $bro_global_typemap[:record] = YAML.load_file("#{dir}/record-typemaps.yml")
93
+ end
94
+
95
+ # This needs the event.bif.bro file to generate its callback
96
+ # typemappings for the default bro events.
97
+ # Distributions will have these files prebuilt for the appropriate
98
+ # version of Bro.
99
+ def Typemap.generate_callback_file(input_filename, output_filename)
100
+ f = open(input_filename)
101
+
102
+ output = {}
103
+ f.each_line do |line|
104
+ match = line.match(/^global\s+(.*?):\s+event\((.*)\)/)
105
+ if match
106
+ types = []
107
+ event = match[1]
108
+ match[2].split(", ").each { |i| types << i.split(": ")[1].to_sym }
109
+ output[event] = types
110
+ end
111
+ end
112
+ yaml = open(output_filename, "w")
113
+ yaml.puts "# This file was autogenerated on #{Time.now}"
114
+ yaml.puts "# Please do not edit!"
115
+ yaml.puts output.to_yaml
116
+ end
117
+
118
+ # This will generate a typemapper for records from the
119
+ # bro.init file.
120
+ def Typemap.generate_record_file(input_filename, output_filename)
121
+ f = open(input_filename)
122
+
123
+ output = {}
124
+ fields = {}
125
+ record_type = ''
126
+ inside_def = false
127
+ f.each_line do |line|
128
+ if line =~ /type (\S+?): record/
129
+ record_type = $1
130
+ inside_def = true
131
+ end
132
+
133
+ if inside_def and line =~ /(\S+): (\S+);/
134
+ fields[$1.to_sym] = $2.to_sym;
135
+ end
136
+
137
+ if line =~ /^\};/
138
+ if inside_def
139
+ output[record_type.to_sym] = fields
140
+ fields = {}
141
+ inside_def = false
142
+ end
143
+ end
144
+ end
145
+ yaml = open(output_filename, "w")
146
+ yaml.puts "# This file was autogenerated on #{Time.now}"
147
+ yaml.puts "# Please do not edit!"
148
+ yaml.puts output.to_yaml
149
+ end
150
+ end
151
+ end
152
+
153
+ # This is just to get the yaml stuff loaded into the global typemapper hash
154
+ begin
155
+ Bro::Typemap.load
156
+ rescue
157
+ STDERR.puts "Typemap files not found!"
158
+ end