rbroccoli 1.1.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.
@@ -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