packetfu 1.0.0 → 1.0.2.pre

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.
@@ -127,7 +127,31 @@ module PacketFu
127
127
  class UDPPacket < Packet
128
128
 
129
129
  attr_accessor :eth_header, :ip_header, :udp_header
130
-
130
+
131
+ def self.can_parse?(str)
132
+ return false unless str.size >= 54
133
+ return false unless EthPacket.can_parse? str
134
+ return false unless IPPacket.can_parse? str
135
+ return false unless str[23,1] == "\x11"
136
+ return true
137
+ end
138
+
139
+ def read(str=nil, args={})
140
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
141
+ @eth_header.read(str)
142
+ @ip_header.read(str[14,str.size])
143
+ @eth_header.body = @ip_header
144
+ if args[:strip]
145
+ udp_len = str[16,2].unpack("n")[0] - 20
146
+ @udp_header.read(str[14+(@ip_header.ip_hlen),udp_len])
147
+ else
148
+ @udp_header.read(str[14+(@ip_header.ip_hlen),str.size])
149
+ end
150
+ @ip_header.body = @udp_header
151
+ super(args)
152
+ self
153
+ end
154
+
131
155
  def initialize(args={})
132
156
  @eth_header = EthHeader.new(args).read(args[:eth])
133
157
  @ip_header = IPHeader.new(args).read(args[:ip])
@@ -2,6 +2,7 @@
2
2
  # to create meaningful binary data.
3
3
 
4
4
  module StructFu
5
+
5
6
  # Normally, self.size and self.length will refer to the Struct
6
7
  # size as an array. It's a hassle to redefine, so this introduces some
7
8
  # shorthand to get at the size of the resultant string.
@@ -106,6 +107,7 @@ module StructFu
106
107
 
107
108
  # Returns a two byte value as a packed string.
108
109
  def to_s
110
+ @packstr = (self.e == :big) ? "n" : "v"
109
111
  [(self.v || self.d)].pack(@packstr)
110
112
  end
111
113
 
@@ -113,10 +115,12 @@ module StructFu
113
115
 
114
116
  # Int16be is a two byte value in big-endian format.
115
117
  class Int16be < Int16
118
+ undef :endian=
116
119
  end
117
120
 
118
121
  # Int16le is a two byte value in little-endian format.
119
122
  class Int16le < Int16
123
+ undef :endian=
120
124
  def initialize(v=nil, e=:little)
121
125
  super(v,e)
122
126
  @packstr = (self.e == :big) ? "n" : "v"
@@ -132,6 +136,7 @@ module StructFu
132
136
 
133
137
  # Returns a four byte value as a packed string.
134
138
  def to_s
139
+ @packstr = (self.e == :big) ? "N" : "V"
135
140
  [(self.v || self.d)].pack(@packstr)
136
141
  end
137
142
 
@@ -139,10 +144,12 @@ module StructFu
139
144
 
140
145
  # Int32be is a four byte value in big-endian format.
141
146
  class Int32be < Int32
147
+ undef :endian=
142
148
  end
143
149
 
144
150
  # Int32le is a four byte value in little-endian format.
145
151
  class Int32le < Int32
152
+ undef :endian=
146
153
  def initialize(v=nil, e=:little)
147
154
  super(v,e)
148
155
  end
@@ -166,11 +173,11 @@ module StructFu
166
173
  class IntString < Struct.new(:int, :string, :mode)
167
174
 
168
175
  def initialize(string='',int=Int8,mode=nil)
169
- unless int.respond_to?(:ancestors) && int.ancestors.include?(StructFu::Int)
170
- raise StandardError, "Invalid length (#{int.inspect}) associated with this String."
171
- else
176
+ if int < Int
172
177
  super(int.new,string,mode)
173
178
  calc
179
+ else
180
+ raise "IntStrings need a StructFu::Int for a length."
174
181
  end
175
182
  end
176
183
 
@@ -0,0 +1,50 @@
1
+ module PacketFu
2
+
3
+ # Version 1.0.0 was released July 31, 2010
4
+ # Version 1.0.1 is unreleased.
5
+ VERSION = "1.0.2"
6
+
7
+ def self.version
8
+ VERSION
9
+ end
10
+
11
+ # Returns the version in a binary format for easy comparisons.
12
+ def self.binarize_version(str)
13
+ if(str.respond_to?(:split) && str =~ /^[0-9]+(\.([0-9]+)(\.[0-9]+)?)?\..+$/)
14
+ bin_major,bin_minor,bin_teeny = str.split(/\x2e/).map {|x| x.to_i}
15
+ bin_version = (bin_major.to_i << 16) + (bin_minor.to_i << 8) + bin_teeny.to_i
16
+ else
17
+ raise ArgumentError, "Compare version malformed. Should be \x22x.y.z\x22"
18
+ end
19
+ end
20
+
21
+ # Returns true if the version is equal to or greater than the compare version.
22
+ # If the current version of PacketFu is "0.3.1" for example:
23
+ #
24
+ # PacketFu.at_least? "0" # => true
25
+ # PacketFu.at_least? "0.2.9" # => true
26
+ # PacketFu.at_least? "0.3" # => true
27
+ # PacketFu.at_least? "1" # => true after 1.0's release
28
+ # PacketFu.at_least? "1.12" # => false
29
+ # PacketFu.at_least? "2" # => false
30
+ def self.at_least?(str)
31
+ this_version = binarize_version(self.version)
32
+ ask_version = binarize_version(str)
33
+ this_version >= ask_version
34
+ end
35
+
36
+ # Returns true if the current version is older than the compare version.
37
+ def self.older_than?(str)
38
+ return false if str == self.version
39
+ this_version = binarize_version(self.version)
40
+ ask_version = binarize_version(str)
41
+ this_version < ask_version
42
+ end
43
+
44
+ # Returns true if the current version is newer than the compare version.
45
+ def self.newer_than?(str)
46
+ return false if str == self.version
47
+ !self.older_than?(str)
48
+ end
49
+
50
+ end
data/test/all_tests.rb CHANGED
@@ -1,37 +1,40 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # This test suite passes on:
4
- # ruby-1.8.6-p399 [ x86_64 ]
5
- # ruby-1.8.7-p174 [ x86_64 ]
6
- # ruby-1.8.7-p249 [ x86_64 ]
7
- # ruby-1.9.1-p378 [ x86_64 ]
8
- # PacketFu (but not pcaprub) passes on:
9
- # ruby-1.9.2-head [ x86_64 ]
10
-
11
- require 'test/unit'
12
- $: << File.expand_path(File.dirname(__FILE__) + "/../lib/")
13
- require 'packetfu'
3
+ # Tested on:
4
+ #
5
+ # ruby-1.9.3-head [ x86_64 ]
6
+ # ruby-1.9.1-p378 [ x86_64 ]
7
+ # ruby-1.8.6-p399 [ x86_64 ]
8
+ # ruby-1.8.7-p334 [ x86_64 ]
9
+ # ruby-1.9.2-p180 [ x86_64 ]
14
10
 
15
- #Note that the Ruby stock unit tester runs this all out
16
- #of order, does funny things with class variables, etc.
11
+ # Okay so the regular test/unit stuff screws up some of my
12
+ # meta magic. I need to move these over to spec and see
13
+ # if they're any better. In the meantime, behold my
14
+ # ghetto test exec()'er. It all passes with this,
15
+ # so I'm just going to go ahead and assume the testing
16
+ # methodolgy is flawed. TODO: rewrite all this for spec
17
+ # and incidentally get the gem to test like it's supposed
18
+ # to.
17
19
 
18
- require 'test_structfu'
19
- require 'test_pcap'
20
- require 'test_invalid'
21
- require 'test_eth' # Creates eth_test.pcap
22
- require 'test_octets'
23
- require 'test_packet'
24
- require 'test_arp' # Creates arp_test.pcap
25
- require 'test_ip' # Creates ip_test.pcap
26
- require 'test_icmp' # Creates icmp_test.pcap
27
- require 'test_udp' # Creates udp_test.pcap
28
- require 'test_tcp'
29
- require 'test_ip6'
20
+ $:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib/")
21
+ require 'packetfu'
22
+ dir = Dir.new(File.dirname(__FILE__))
30
23
 
31
- if Process.euid.zero?
32
- require 'test_inject'
33
- else
34
- $stderr.puts "** WARNING ** test_inject not tested, needs root access."
35
- end
24
+ dir.each { |file|
25
+ next unless File.file? file
26
+ next unless file[/^test_.*rb$/]
27
+ next if file == $0
28
+ puts "Running #{file}..."
29
+ cmd = %x{ruby #{file}}
30
+ if cmd[/ 0 failures/] && cmd[/ 0 errors/]
31
+ puts "#{file}: All passed"
32
+ else
33
+ puts "File: #{file} had failures or errors:"
34
+ puts "-" * 80
35
+ puts cmd
36
+ puts "-" * 80
37
+ end
38
+ }
36
39
 
37
40
  # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
Binary file
Binary file
Binary file
data/test/ip_test.pcap ADDED
Binary file
@@ -0,0 +1,70 @@
1
+ require File.join("..","lib","packetfu")
2
+
3
+ describe PacketFu, "version information" do
4
+ it "reports a version number" do
5
+ PacketFu::VERSION.should == "1.0.2"
6
+ end
7
+ its(:version) {should eq PacketFu::VERSION}
8
+
9
+ it "can compare version strings" do
10
+ PacketFu.binarize_version("1.2.3").should == 0x010203
11
+ PacketFu.binarize_version("3.0").should == 0x030000
12
+ PacketFu.at_least?("1.0").should be_true
13
+ PacketFu.at_least?("4.0").should be_false
14
+ PacketFu.older_than?("4.0").should be_true
15
+ PacketFu.newer_than?("1.0").should be_true
16
+ end
17
+
18
+ it "can handle .pre versions" do
19
+ PacketFu.binarize_version("1.7.6.pre").should == 0x010706
20
+ PacketFu.at_least?("0.9.0.pre").should be_true
21
+ end
22
+ end
23
+
24
+ describe PacketFu, "instance variables" do
25
+ it "should have a bunch of instance variables" do
26
+ PacketFu.instance_variable_get(:@byte_order).should == :little
27
+ PacketFu.instance_variable_get(:@pcaprub_loaded).should_not be_nil
28
+ end
29
+ end
30
+
31
+ describe PacketFu, "pcaprub deps" do
32
+ it "should check for pcaprub" do
33
+ begin
34
+ has_pcap = false
35
+ require 'pcaprub'
36
+ has_pcap = true
37
+ rescue LoadError
38
+ end
39
+ if has_pcap
40
+ PacketFu.instance_variable_get(:@pcaprub_loaded).should be_true
41
+ else
42
+ PacketFu.instance_variable_get(:@pcaprub_loaded).should be_false
43
+ end
44
+ end
45
+ end
46
+
47
+ describe PacketFu, "protocol requires" do
48
+ it "should have some protocols defined" do
49
+ PacketFu::EthPacket.should_not be_nil
50
+ PacketFu::IPPacket.should_not be_nil
51
+ PacketFu::TCPPacket.should_not be_nil
52
+ expect { PacketFu::FakePacket }.to raise_error
53
+ end
54
+ end
55
+
56
+ describe PacketFu, "packet class list management" do
57
+ class FooPacket; end
58
+ class BarPacket; end
59
+ PacketFu.add_packet_class(FooPacket)
60
+ PacketFu.add_packet_class(BarPacket)
61
+ its(:packet_classes) {should include(FooPacket) and include(BarPacket)}
62
+ it "should disallow non-classes as packet classes" do
63
+ expect { PacketFu.add_packet_class("A String") }.to raise_error
64
+ end
65
+ its(:packet_prefixes) {should include("foo") and include("bar")}
66
+ it "should disallow nonstandard packet class names" do
67
+ class PacketBaz; end
68
+ expect { PacketFu.add_packet_class(PacketBaz) }.to raise_error
69
+ end
70
+ end
Binary file
Binary file
@@ -0,0 +1,338 @@
1
+ require File.join("..","lib","packetfu")
2
+
3
+ describe StructFu, "mixin methods" do
4
+
5
+ before :each do
6
+ class StructClass
7
+ include StructFu
8
+ end
9
+ @sc = StructClass.new
10
+ end
11
+
12
+ it "should provide the basic StructFu methods" do
13
+ @sc.respond_to?(:sz).should be_true
14
+ @sc.respond_to?(:len).should be_true
15
+ @sc.respond_to?(:typecast).should be_true
16
+ @sc.respond_to?(:body=).should be_true
17
+ end
18
+ end
19
+
20
+ describe StructFu::Int, "basic Int class" do
21
+
22
+ before :each do
23
+ @int = StructFu::Int.new(8)
24
+ end
25
+
26
+ it "should have an initial state" do
27
+ new_int = StructFu::Int.new
28
+ new_int.value.should be_nil
29
+ new_int.endian.should be_nil
30
+ new_int.width.should be_nil
31
+ new_int.default.should == 0
32
+ end
33
+
34
+ it "should raise when to_s'ed directly" do
35
+ expect { @int.to_s}.to raise_error
36
+ end
37
+
38
+ it "should have a value of 8" do
39
+ @int.value.should == 8
40
+ @int.to_i.should == 8
41
+ @int.to_f.to_s.should == "8.0"
42
+ end
43
+
44
+ it "should read an integer" do
45
+ @int.read(7)
46
+ @int.to_i.should == 7
47
+ end
48
+
49
+ end
50
+
51
+ describe StructFu::Int8, "one byte value" do
52
+
53
+ before :each do
54
+ @int = StructFu::Int8.new(11)
55
+ end
56
+
57
+ it "should have an initial state" do
58
+ new_int = StructFu::Int8.new
59
+ new_int.value.should be_nil
60
+ new_int.endian.should be_nil
61
+ new_int.width.should == 1
62
+ new_int.default.should == 0
63
+ end
64
+
65
+ it "should print a one character packed string" do
66
+ @int.to_s.should == "\x0b"
67
+ end
68
+
69
+ it "should have a value of 11" do
70
+ @int.value.should == 11
71
+ @int.to_i.should == 11
72
+ @int.to_f.to_s.should == "11.0"
73
+ end
74
+
75
+ it "should reset with a new integer" do
76
+ @int.read(2)
77
+ @int.to_i.should == 2
78
+ @int.to_s.should == "\x02"
79
+ @int.read(254)
80
+ @int.to_i.should == 254
81
+ @int.to_s.should == "\xfe"
82
+ end
83
+
84
+ end
85
+
86
+ describe StructFu::Int16, "two byte value" do
87
+
88
+ before :each do
89
+ @int = StructFu::Int16.new(11)
90
+ end
91
+
92
+ it "should have an initial state" do
93
+ new_int = StructFu::Int16.new
94
+ new_int.value.should be_nil
95
+ new_int.endian.should == :big
96
+ new_int.width.should == 2
97
+ new_int.default.should == 0
98
+ end
99
+
100
+ it "should print a two character packed string" do
101
+ @int.to_s.should == "\x00\x0b"
102
+ end
103
+
104
+ it "should have a value of 11" do
105
+ @int.value.should == 11
106
+ @int.to_i.should == 11
107
+ @int.to_f.to_s.should == "11.0"
108
+ end
109
+
110
+ it "should reset with a new integer" do
111
+ @int.read(2)
112
+ @int.to_i.should == 2
113
+ @int.to_s.should == "\x00\x02"
114
+ @int.read(254)
115
+ @int.to_i.should == 254
116
+ @int.to_s.should == "\x00\xfe"
117
+ end
118
+
119
+ it "should be able to set endianness" do
120
+ int_be = StructFu::Int16.new(11,:big)
121
+ int_be.to_s.should == "\x00\x0b"
122
+ int_le = StructFu::Int16.new(11,:little)
123
+ int_le.to_s.should == "\x0b\x00"
124
+ end
125
+
126
+ it "should be able to switch endianness" do
127
+ @int.endian.should == :big
128
+ @int.to_s.should == "\x00\x0b"
129
+ @int.endian = :little
130
+ @int.endian.should == :little
131
+ @int.read(11)
132
+ @int.to_s.should == "\x0b\x00"
133
+ end
134
+
135
+ end
136
+
137
+ describe StructFu::Int16le, "2 byte little-endian value" do
138
+
139
+ before :each do
140
+ @int = StructFu::Int16le.new(11)
141
+ end
142
+
143
+ it "should behave pretty much like any other 16 bit int" do
144
+ @int.to_s.should == "\x0b\x00"
145
+ end
146
+
147
+ it "should raise when you try to change endianness" do
148
+ expect { @int.endian = :big }.to raise_error
149
+ expect { @int.endian = :little }.to raise_error
150
+ end
151
+
152
+ end
153
+
154
+ describe StructFu::Int16be, "2 byte big-endian value" do
155
+
156
+ before :each do
157
+ @int = StructFu::Int16be.new(11)
158
+ end
159
+
160
+ it "should behave pretty much like any other 16 bit int" do
161
+ @int.to_s.should == "\x00\x0b"
162
+ end
163
+
164
+ it "should raise when you try to change endianness" do
165
+ expect { @int.endian = :big }.to raise_error
166
+ expect { @int.endian = :little }.to raise_error
167
+ end
168
+
169
+ end
170
+
171
+ describe StructFu::Int32, "four byte value" do
172
+
173
+ before :each do
174
+ @int = StructFu::Int32.new(11)
175
+ end
176
+
177
+ it "should have an initial state" do
178
+ new_int = StructFu::Int32.new
179
+ new_int.value.should be_nil
180
+ new_int.endian.should == :big
181
+ new_int.width.should == 4
182
+ new_int.default.should == 0
183
+ end
184
+
185
+ it "should print a four character packed string" do
186
+ @int.to_s.should == "\x00\x00\x00\x0b"
187
+ end
188
+
189
+ it "should have a value of 11" do
190
+ @int.value.should == 11
191
+ @int.to_i.should == 11
192
+ @int.to_f.to_s.should == "11.0"
193
+ end
194
+
195
+ it "should reset with a new integer" do
196
+ @int.read(2)
197
+ @int.to_i.should == 2
198
+ @int.to_s.should == "\x00\x00\x00\x02"
199
+ @int.read(254)
200
+ @int.to_i.should == 254
201
+ @int.to_s.should == "\x00\x00\x00\xfe"
202
+ end
203
+
204
+ it "should be able to set endianness" do
205
+ int_be = StructFu::Int32.new(11,:big)
206
+ int_be.to_s.should == "\x00\x00\x00\x0b"
207
+ int_le = StructFu::Int32.new(11,:little)
208
+ int_le.to_s.should == "\x0b\x00\x00\x00"
209
+ end
210
+
211
+ it "should be able to switch endianness" do
212
+ @int.endian.should == :big
213
+ @int.to_s.should == "\x00\x00\x00\x0b"
214
+ @int.endian = :little
215
+ @int.endian.should == :little
216
+ @int.read(11)
217
+ @int.to_s.should == "\x0b\x00\x00\x00"
218
+ end
219
+
220
+ end
221
+
222
+ describe StructFu::Int32le, "4 byte little-endian value" do
223
+
224
+ before :each do
225
+ @int = StructFu::Int32le.new(11)
226
+ end
227
+
228
+ it "should behave pretty much like any other 32 bit int" do
229
+ @int.to_s.should == "\x0b\x00\x00\x00"
230
+ end
231
+
232
+ it "should raise when you try to change endianness" do
233
+ expect { @int.endian = :big }.to raise_error
234
+ expect { @int.endian = :little }.to raise_error
235
+ end
236
+
237
+ end
238
+
239
+ describe StructFu::Int32be, "4 byte big-endian value" do
240
+
241
+ before :each do
242
+ @int = StructFu::Int32be.new(11)
243
+ end
244
+
245
+ it "should behave pretty much like any other 32 bit int" do
246
+ @int.to_s.should == "\x00\x00\x00\x0b"
247
+ end
248
+
249
+ it "should raise when you try to change endianness" do
250
+ expect { @int.endian = :big }.to raise_error
251
+ expect { @int.endian = :little }.to raise_error
252
+ end
253
+
254
+ end
255
+
256
+ describe StructFu::String, "a sligtly more special String" do
257
+
258
+ before :each do
259
+ @str = StructFu::String.new("Oi, a string")
260
+ end
261
+
262
+ it "should behave pretty much like a string" do
263
+ @str.should be_kind_of(String)
264
+ end
265
+
266
+ it "should have a read method" do
267
+ @str.should respond_to(:read)
268
+ end
269
+
270
+ it "should read data like other StructFu things" do
271
+ @str.read("hello")
272
+ @str.should == "hello"
273
+ end
274
+
275
+ end
276
+
277
+ describe StructFu::IntString do
278
+
279
+ it "should be" do
280
+ StructFu::IntString.should be
281
+ end
282
+
283
+ it "should have a length and value" do
284
+ istr = StructFu::IntString.new("Avast!")
285
+ istr.to_s.should == "\x06Avast!"
286
+ end
287
+
288
+ it "should have a 16-bit length and a value" do
289
+ istr = StructFu::IntString.new("Avast!",StructFu::Int16)
290
+ istr.to_s.should == "\x00\x06Avast!"
291
+ end
292
+
293
+ it "should have a 32-bit length and a value" do
294
+ istr = StructFu::IntString.new("Avast!",StructFu::Int32)
295
+ istr.to_s.should == "\x00\x00\x00\x06Avast!"
296
+ end
297
+
298
+ before :each do
299
+ @istr = StructFu::IntString.new("Avast!",StructFu::Int32)
300
+ end
301
+
302
+ it "should report the correct length with a new string" do
303
+ @istr.to_s.should == "\x00\x00\x00\x06Avast!"
304
+ @istr.string = "Ahoy!"
305
+ @istr.to_s.should == "\x00\x00\x00\x05Ahoy!"
306
+ end
307
+
308
+ it "should report the correct length with a new string" do
309
+ @istr.string = "Ahoy!"
310
+ @istr.to_s.should == "\x00\x00\x00\x05Ahoy!"
311
+ end
312
+
313
+ it "should keep the old length with a new string" do
314
+ @istr[:string] = "Ahoy!"
315
+ @istr.to_s.should == "\x00\x00\x00\x06Ahoy!"
316
+ end
317
+
318
+ it "should allow for adjusting the length manually" do
319
+ @istr.len = 16
320
+ @istr.to_s.should == "\x00\x00\x00\x10Avast!"
321
+ end
322
+
323
+ it "should read in an expected string" do
324
+ data = "\x00\x00\x00\x09Yo ho ho!"
325
+ @istr.read(data)
326
+ @istr.to_s.should == data
327
+ end
328
+
329
+ it "should raise when a string is too short" do
330
+ data = "\x01A"
331
+ expect { @istr.read(data) }.to raise_error
332
+ end
333
+
334
+ # So far, not implemented anywhere. In fact, none of this IntString
335
+ # business is. Ah well.
336
+ it "should parse when something actually needs it"
337
+
338
+ end