dorothy2 0.0.3 → 1.0.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,118 @@
1
+ # "THE BEER-WARE LICENSE" (Revision 42):
2
+ # Mu[http://www.mudynamics.com] wrote this file. As long as you retain this
3
+ # notice you can do whatever you want with this stuff. If we meet some day,
4
+ # and you think this stuff is worth it, you can buy us a beer in return.
5
+ #
6
+ # All about pcapr
7
+ # * http://www.pcapr.net
8
+ # * http://groups.google.com/group/pcapr-forum
9
+ # * http://twitter.com/pcapr
10
+ #
11
+ # Mu Dynamics
12
+ # * http://www.mudynamics.com
13
+ # * http://labs.mudynamics.com
14
+
15
+ require 'mu/xtractr'
16
+ require 'test/unit'
17
+
18
+ module Mu
19
+ class Xtractr
20
+ class Views
21
+ class Count
22
+ class Test < Test::Unit::TestCase
23
+ attr_reader :xtractr
24
+ attr_reader :count
25
+
26
+ def setup
27
+ @xtractr = Xtractr.new
28
+ @count = xtractr.flows('flow.service:DNS').count('dns.qry.name').first
29
+ end
30
+
31
+ def test_attributes
32
+ assert_kind_of(Field, count.field)
33
+ assert_equal('ax.search.itunes.apple.com', count.value)
34
+ assert_equal(8, count.count)
35
+ end
36
+
37
+ def test_object
38
+ object = count.object
39
+ assert_kind_of(Field::Value, object)
40
+ assert_equal('dns.qry.name', object.field.name)
41
+ assert_equal('ax.search.itunes.apple.com', object.value)
42
+ end
43
+
44
+ def test_packets
45
+ packets = count.packets
46
+ assert_equal("dns.qry.name:\"ax.search.itunes.apple.com\"", packets.q)
47
+ end
48
+
49
+ def test_each_packet
50
+ count.each_packet do |pkt|
51
+ assert_kind_of(Packet, pkt)
52
+ values = pkt['dns.qry.name']
53
+ assert_equal(1, values.size)
54
+ assert_equal('ax.search.itunes.apple.com', values[0])
55
+ end
56
+ end
57
+
58
+ def test_sum
59
+ sums = count.object.sum('pkt.src', 'pkt.length')
60
+ assert_equal(2, sums.length)
61
+ end
62
+
63
+ def test_inspect
64
+ assert_nothing_raised { count.inspect }
65
+ end
66
+ end
67
+ end # Count
68
+
69
+ class Sum
70
+ class Test < Test::Unit::TestCase
71
+ attr_reader :xtractr
72
+ attr_reader :sum
73
+
74
+ def setup
75
+ @xtractr = Xtractr.new
76
+ @sum = xtractr.flows('flow.service:DNS').sum('dns.qry.name', 'flow.bytes').first
77
+ end
78
+
79
+ def test_attributes
80
+ assert_kind_of(Field, sum.field)
81
+ assert_equal('ax.search.itunes.apple.com', sum.value)
82
+ assert_equal(1220, sum.sum)
83
+ end
84
+
85
+ def test_object
86
+ object = sum.object
87
+ assert_kind_of(Field::Value, object)
88
+ assert_equal('dns.qry.name', object.field.name)
89
+ assert_equal('ax.search.itunes.apple.com', object.value)
90
+ end
91
+
92
+ def test_packets
93
+ packets = sum.packets
94
+ assert_equal("dns.qry.name:\"ax.search.itunes.apple.com\"", packets.q)
95
+ end
96
+
97
+ def test_each_packet
98
+ sum.each_packet do |pkt|
99
+ assert_kind_of(Packet, pkt)
100
+ values = pkt['dns.qry.name']
101
+ assert_equal(1, values.size)
102
+ assert_equal('ax.search.itunes.apple.com', values[0])
103
+ end
104
+ end
105
+
106
+ def test_count
107
+ counts = sum.object.count('pkt.service')
108
+ assert_equal(1, counts.length)
109
+ end
110
+
111
+ def test_inspect
112
+ assert_nothing_raised { sum.inspect }
113
+ end
114
+ end
115
+ end # Sum
116
+ end # Views
117
+ end # Xtractr
118
+ end # Mu
@@ -0,0 +1,151 @@
1
+ # "THE BEER-WARE LICENSE" (Revision 42):
2
+ # Mu[http://www.mudynamics.com] wrote this file. As long as you retain this
3
+ # notice you can do whatever you want with this stuff. If we meet some day,
4
+ # and you think this stuff is worth it, you can buy us a beer in return.
5
+ #
6
+ # All about pcapr
7
+ # * http://www.pcapr.net
8
+ # * http://groups.google.com/group/pcapr-forum
9
+ # * http://twitter.com/pcapr
10
+ #
11
+ # Mu Dynamics
12
+ # * http://www.mudynamics.com
13
+ # * http://labs.mudynamics.com
14
+
15
+ require 'mu/xtractr'
16
+ require 'test/unit'
17
+
18
+ module Mu
19
+ class Xtractr
20
+ class Test < Test::Unit::TestCase
21
+ attr_reader :xtractr
22
+
23
+ def setup
24
+ @xtractr = Xtractr.new
25
+ end
26
+
27
+ def test_about
28
+ about = xtractr.about
29
+ assert_equal(1778, about.packets)
30
+ assert_equal(32, about.flows)
31
+ assert_equal(12, about.hosts)
32
+ assert_equal(5, about.services)
33
+ assert_equal(171.172, about.duration)
34
+ end
35
+
36
+ def test_hosts
37
+ hosts = xtractr.hosts
38
+ assert_equal(12, hosts.size)
39
+ hosts.each { |host| assert_instance_of(Host, host) }
40
+ assert_equal(8, xtractr.hosts(/^8.18/).size)
41
+ assert_equal(8, xtractr.hosts('8.18').size)
42
+ assert_equal(1, xtractr.hosts(/^4.2/).size)
43
+ assert_equal(1, xtractr.hosts('4.2').size)
44
+ end
45
+
46
+ def test_host
47
+ [
48
+ '4.2.2.1',
49
+ '8.18.65.67',
50
+ '8.18.65.32',
51
+ '8.18.65.58',
52
+ '8.18.65.82',
53
+ '8.18.65.27',
54
+ '8.18.65.10',
55
+ '8.18.65.88',
56
+ '8.18.65.89',
57
+ '66.235.132.121',
58
+ '192.168.1.10',
59
+ '224.0.0.251',
60
+ ].each do |address|
61
+ assert_nothing_raised { xtractr.host address }
62
+ end
63
+
64
+ assert_raise(ArgumentError) { xtractr.host '1.1.1.1' }
65
+ end
66
+
67
+ def test_services
68
+ services = xtractr.services
69
+ assert_equal(5, services.size)
70
+ services.each { |service| assert_instance_of(Service, service) }
71
+ assert_equal(2, xtractr.services(/HTTP/).size)
72
+ assert_equal(2, xtractr.services('HTTP').size)
73
+ assert_equal(2, xtractr.services('http').size)
74
+ end
75
+
76
+ def test_service
77
+ [ 'DNS', 'TCP', 'HTTP', 'HTTP/XML', 'MDNS' ].each do |name|
78
+ assert_nothing_raised { xtractr.service name }
79
+ assert_nothing_raised { xtractr.service name.downcase }
80
+ end
81
+
82
+ assert_raise(ArgumentError) { xtractr.service 'blah' }
83
+ end
84
+
85
+ def test_fields
86
+ fields = xtractr.fields
87
+ assert_equal(170, fields.size)
88
+ fields.each { |field| assert_instance_of(Field, field) }
89
+ assert_equal(12, xtractr.fields(/^pkt\./).size)
90
+ assert_equal(12, xtractr.fields("PKT.").size)
91
+ assert_equal(12, xtractr.fields("pkt.").size)
92
+ end
93
+
94
+ def test_field
95
+ [
96
+ 'pkt.src', 'pkt.dst', 'pkt.flow', 'pkt.id', 'pkt.pcap', 'pkt.first',
97
+ 'pkt.dir', 'pkt.time', 'pkt.offset', 'pkt.length', 'pkt.service',
98
+ 'pkt.title'
99
+ ].each do |name|
100
+ assert_nothing_raised { xtractr.field name }
101
+ end
102
+ assert_raise(ArgumentError) { xtractr.field 'blah' }
103
+ end
104
+
105
+ def test_flows
106
+ flows = xtractr.flows
107
+ assert_kind_of(Flows, flows)
108
+ assert_equal('*', flows.q)
109
+
110
+ flows = xtractr.flows 'blah:foo'
111
+ assert_equal('blah:foo', flows.q)
112
+
113
+ flows = xtractr.flows 1..10
114
+ assert_equal('flow.id:[1 10]', flows.q)
115
+
116
+ flows = xtractr.flows 1...10
117
+ assert_equal('flow.id:[1 9]', flows.q)
118
+ end
119
+
120
+ def test_flow
121
+ flow = xtractr.flow 1
122
+ assert_kind_of(Flow, flow)
123
+
124
+ assert_raise(ArgumentError) do
125
+ flow = xtractr.flow xtractr.about.flows+1
126
+ end
127
+ end
128
+
129
+ def test_packets
130
+ packets = xtractr.packets
131
+ assert_kind_of(Packets, packets)
132
+ assert_equal('*', packets.q)
133
+
134
+ packets = xtractr.packets 'blah:foo'
135
+ assert_equal('blah:foo', packets.q)
136
+
137
+ packets = xtractr.packets 1..10
138
+ assert_equal('pkt.id:[1 10]', packets.q)
139
+
140
+ packets = xtractr.packets 1...10
141
+ assert_equal('pkt.id:[1 9]', packets.q)
142
+ end
143
+
144
+ def test_packet
145
+ pkt = xtractr.packet 1
146
+ assert_kind_of(Packet, pkt)
147
+ assert_equal(1, pkt.id)
148
+ end
149
+ end
150
+ end # Xtractr
151
+ end # Mu
@@ -0,0 +1,19 @@
1
+ # "THE BEER-WARE LICENSE" (Revision 42):
2
+ # Mu[http://www.mudynamics.com] wrote this file. As long as you retain this
3
+ # notice you can do whatever you want with this stuff. If we meet some day,
4
+ # and you think this stuff is worth it, you can buy us a beer in return.
5
+ #
6
+ # All about pcapr
7
+ # * http://www.pcapr.net
8
+ # * http://groups.google.com/group/pcapr-forum
9
+ # * http://twitter.com/pcapr
10
+ #
11
+ # Mu Dynamics
12
+ # * http://www.mudynamics.com
13
+ # * http://labs.mudynamics.com
14
+
15
+ require 'test/unit'
16
+
17
+ Dir.glob('mu/xtractr/test/**/tc*.rb').each do |file|
18
+ require file
19
+ end
@@ -0,0 +1,204 @@
1
+ # "THE BEER-WARE LICENSE" (Revision 42):
2
+ # Mu[http://www.mudynamics.com] wrote this file. As long as you retain this
3
+ # notice you can do whatever you want with this stuff. If we meet some day,
4
+ # and you think this stuff is worth it, you can buy us a beer in return.
5
+ #
6
+ # All about pcapr
7
+ # * http://www.pcapr.net
8
+ # * http://groups.google.com/group/pcapr-forum
9
+ # * http://twitter.com/pcapr
10
+ #
11
+ # Mu Dynamics
12
+ # * http://www.mudynamics.com
13
+ # * http://labs.mudynamics.com
14
+
15
+ module Mu
16
+ class Xtractr
17
+ # See http://labs.mudynamics.com/2009/04/03/interactive-couchdb/ for a quick
18
+ # tutorial on how Map/Reduce works.
19
+ class Views # :nodoc:
20
+ # = Count
21
+ # Count contains the results of doing a map/reduce on either flows or
22
+ # packets. Each count contains the field on which the map/reduce was
23
+ # performed, the unique value as all as the count of that value in the
24
+ # flows or packets. For example to count the unique source IP address of
25
+ # HTTP flows in the first five minutes of the index, you would do:
26
+ #
27
+ # xtractr.flows('flow.service:HTTP flow.duration:[1 300]').count('flow.src')
28
+ class Count
29
+ attr_reader :xtractr # :nodoc:
30
+
31
+ # Returns the field used for counting.
32
+ attr_reader :field
33
+
34
+ # Returns the unique value of the field.
35
+ attr_reader :value
36
+
37
+ # Returns the count of the field/value.
38
+ attr_reader :count
39
+
40
+ def initialize xtractr, field, value, count # :nodoc:
41
+ @xtractr = xtractr
42
+ @field = field
43
+ @value = value
44
+ @count = count
45
+ end
46
+
47
+ # Returns a Field::Value object that can be used for further method
48
+ # chaining.
49
+ # xtractr.flows.count('flow.src').first.object.count('flow.service')
50
+ def object
51
+ Field::Value.new xtractr, "key" => field.name, "value" => value
52
+ end
53
+
54
+ # Fetch the list of packets that contain this field value.
55
+ # xtractr.flows.count('flow.src').first.packets.each { |pkt ... }
56
+ def packets q=nil
57
+ object.packets q
58
+ end
59
+
60
+ # Iterate over each packet that contains this field value.
61
+ # xtractr.flows.count('flow.src').first.each_packet { |pkt ... }
62
+ def each_packet(q=nil, &blk) # :yields: packet
63
+ packets(q).each(&blk)
64
+ return self
65
+ end
66
+
67
+ # Sum the numeric values of vfield, keyed by the unique values of
68
+ # kfield. This is used for method chaining.
69
+ # xtractr.flows.count('flow.src').first.sum('flow.service', 'flow.bytes')
70
+ def sum kfield, vfield
71
+ object.sum kfield, vfield
72
+ end
73
+
74
+ def inspect # :nodoc:
75
+ "#<count #{value} #{count}>"
76
+ end
77
+ end
78
+
79
+ # = Sum
80
+ # Sum contains the results of doing a map/reduce on either flows or
81
+ # packets. Each sum contains the field on which the map/reduce was
82
+ # performed, the unique value as all as the sum of that value in the
83
+ # flows or packets. For example to count the bytes sent in HTTP flows
84
+ # keyed by the source IP address, you would do:
85
+ #
86
+ # xtractr.flows('flow.service:HTTP').count('flow.src', 'flow.bytes')
87
+ class Sum
88
+ attr_reader :xtractr # :nodoc:
89
+
90
+ # Returns the field used for summing.
91
+ attr_reader :field
92
+
93
+ # Returns the unique value used as the map/reduce key.
94
+ attr_reader :value
95
+
96
+ # Returns the aggregate computed sum.
97
+ attr_reader :sum
98
+
99
+ def initialize xtractr, field, value, sum # :nodoc:
100
+ @xtractr = xtractr
101
+ @field = field
102
+ @value = value
103
+ @sum = sum
104
+ end
105
+
106
+ # Returns a Field::Value object that can be used for further method
107
+ # chaining. In the following example, we first compute the top talkers
108
+ # (based on the bytes sent) and then use the topmost talker to count
109
+ # the list of unique services.
110
+ # xtractr.flows.sum('flow.src', 'flow.bytes').first.object.count('flow.service')
111
+ def object
112
+ Field::Value.new xtractr, "key" => field.name, "value" => value
113
+ end
114
+
115
+ # Fetch the list of packets that contain this field value.
116
+ # xtractr.flows.sum('flow.src', 'flow.bytes').first.packets.each { |pkt ... }
117
+ def packets q=nil
118
+ object.packets q
119
+ end
120
+
121
+ # Iterate over each packet that contains this field value.
122
+ # xtractr.flows.sum('flow.src', 'flow.bytes').first.each_packet { |pkt ... }
123
+ def each_packet q=nil, &blk
124
+ packets(q).each(&blk)
125
+ return self
126
+ end
127
+
128
+ # Count the unique values of the specified field amongst all the packets
129
+ # that matched the query.
130
+ # xtractr.flows.sum('flow.src', 'flow.bytes').first.count('flow.service')
131
+ def count _field
132
+ object.count _field
133
+ end
134
+
135
+ def inspect # :nodoc:
136
+ "#<sum #{value} #{sum}>"
137
+ end
138
+ end
139
+
140
+ def self.count xtractr, field, url, opts={} # :nodoc:
141
+ field = Field.new(xtractr, field) if field.is_a? String
142
+ name = field.name.gsub /^(pkt|flow)\./, ''
143
+ _opts = opts.dup
144
+ _opts[:r] = <<-EOS
145
+ ({
146
+ map: function(_pf) {
147
+ _pf.values("#{name}", function(_value) {
148
+ if (_value) {
149
+ if (typeof(_value) === 'string') {
150
+ if (_value.length > 1024) {
151
+ _value = _value.slice(0,1024);
152
+ }
153
+ }
154
+ emit(_value, 1);
155
+ }
156
+ });
157
+ },
158
+ reduce: function(_key, _values) {
159
+ return sum(_values);
160
+ }
161
+ })
162
+ EOS
163
+ result = xtractr.json url, _opts
164
+ result['rows'].map do |row|
165
+ Views::Count.new(xtractr, field, row['key'], row['value'])
166
+ end.sort { |a, b| b.count <=> a.count }
167
+ end
168
+
169
+ def self.sum xtractr, kfield, vfield, url, opts={} # :nodoc:
170
+ kfield = Field.new(xtractr, kfield) if kfield.is_a? String
171
+ vfield = Field.new(xtractr, vfield) if vfield.is_a? String
172
+ kname = kfield.name.gsub /^(pkt|flow)\./, ''
173
+ vname = vfield.name.gsub /^(pkt|flow)\./, ''
174
+ _opts = opts.dup
175
+ _opts[:r] = <<-EOS
176
+ ({
177
+ map: function(_pf) {
178
+ var _key = _pf["#{kname}"];
179
+ if (_key) {
180
+ if (typeof(_key) === 'string') {
181
+ if (_key.length > 1024) {
182
+ _key = _key.slice(0,1024);
183
+ }
184
+ }
185
+ _pf.values("#{vname}", function(_val) {
186
+ if (typeof(_val) === 'number') {
187
+ emit(_key, _val);
188
+ }
189
+ });
190
+ }
191
+ },
192
+ reduce: function(_key, _values) {
193
+ return sum(_values);
194
+ }
195
+ })
196
+ EOS
197
+ result = xtractr.json url, _opts
198
+ result['rows'].map do |row|
199
+ Views::Sum.new(xtractr, kfield, row['key'], row['value'])
200
+ end.sort { |a, b| b.sum <=> a.sum }
201
+ end
202
+ end
203
+ end # Xtractr
204
+ end # Mu