packetfu 1.0.2.pre → 1.0.3.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.
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ # This just allows you to eyeball the dissection stuff to make sure it's all right.
3
+ # Some day, there will be a proper test for it.
4
+
5
+ fname = ARGV[0] || "../test/sample.pcap"
6
+ sleep_interval = ARGV[1] || 1
7
+
8
+ require File.join("..","lib","packetfu")
9
+ puts "Loaded: PacketFu v#{PacketFu.version}"
10
+ # $: << File.join(File.expand_path(File.dirname(__FILE__)),"..","lib")
11
+
12
+ include PacketFu
13
+
14
+ packets = PcapFile.file_to_array fname
15
+ packets.each do |packet|
16
+ puts "_" * 75
17
+ puts packet.inspect
18
+ puts "_" * 75
19
+ pkt = Packet.parse(packet)
20
+ puts pkt.dissect
21
+ sleep sleep_interval
22
+ end
data/lib/packetfu.rb CHANGED
@@ -60,6 +60,13 @@ module PacketFu
60
60
  @packet_classes.sort! {|x,y| x.name <=> y.name}
61
61
  end
62
62
 
63
+ def self.remove_packet_class(klass)
64
+ raise "Need a class" unless klass.kind_of? Class
65
+ @packet_classes ||= []
66
+ @packet_classes.delete klass
67
+ @packet_classes
68
+ end
69
+
63
70
  def self.packet_classes
64
71
  @packet_classes || []
65
72
  end
@@ -162,11 +162,71 @@ module PacketFu
162
162
  end
163
163
  end
164
164
 
165
+ # Packets are bundles of lots of objects, so copying them
166
+ # is a little complicated -- a dup of a packet is actually
167
+ # full of pass-by-reference stuff in the @headers, so
168
+ # if you change one, you're changing all this copies, too.
169
+ #
170
+ # Normally, this doesn't seem to be a big deal, and it's
171
+ # a pretty decent performance tradeoff. But, if you're going
172
+ # to be creating a template packet to base a bunch of slightly
173
+ # different ones off of (like a fuzzer might), you'll want
174
+ # to use clone()
175
+ def clone
176
+ Marshal.load(Marshal.dump(self))
177
+ end
178
+
179
+ # If two packets are represented as the same binary string, and
180
+ # they're both actually PacketFu packets of the same sort, they're equal.
181
+ #
182
+ # The intuitive result is that a packet of a higher layer (like DNSPacket)
183
+ # can be equal to a packet of a lower level (like UDPPacket) as long as
184
+ # the bytes are equal (this can come up if a transport-layer packet has
185
+ # a hand-crafted payload that is identical to what would have been created
186
+ # by using an application layer packet)
187
+ def ==(other)
188
+ return false unless other.kind_of? self.class
189
+ return false unless other.respond_to? :to_s
190
+ self.to_s == other.to_s
191
+ end
192
+
165
193
  # Peek provides summary data on packet contents.
166
- # Each packet type should provide its own peek method, and shouldn't exceed 80 characters wide (for
167
- # easy reading in normal irb shells). If they don't, this default summary will step in.
194
+ #
195
+ # Each packet type should provide a peek_format.
168
196
  def peek(args={})
169
- peek_data = ["? "]
197
+ idx = @headers.reverse.map {|h| h.respond_to? peek_format}.index(true)
198
+ if idx
199
+ @headers.reverse[idx].peek_format
200
+ else
201
+ peek_format
202
+ end
203
+ end
204
+
205
+ # The peek_format is used to display a single line
206
+ # of packet data useful for eyeballing. It should not exceed
207
+ # 80 characters. The Packet superclass defines an example
208
+ # peek_format, but it should hardly ever be triggered, since
209
+ # peek traverses the @header list in reverse to find a suitable
210
+ # format.
211
+ #
212
+ # == Format
213
+ #
214
+ # * A one or two character protocol initial. It should be unique
215
+ # * The packet size
216
+ # * Useful data in a human-usable form.
217
+ #
218
+ # Ideally, related peek_formats will all line up with each other
219
+ # when printed to the screen.
220
+ #
221
+ # == Example
222
+ #
223
+ # tcp_packet.peek
224
+ # #=> "T 1054 10.10.10.105:55000 -> 192.168.145.105:80 [......] S:adc7155b|I:8dd0"
225
+ # tcp_packet.peek.size
226
+ # #=> 79
227
+ #
228
+ def peek_format
229
+ peek_data = ["? "]
170
230
  peek_data << "%-5d" % self.to_s.size
171
231
  peek_data << "%68s" % self.to_s[0,34].unpack("H*")[0]
172
232
  peek_data.join
@@ -281,6 +341,67 @@ module PacketFu
281
341
  end
282
342
  end
283
343
 
344
+ def dissection_table
345
+ table = []
346
+ @headers.each_with_index do |header,table_idx|
347
+ proto = header.class.name.sub(/^.*::/,"")
348
+ table << [proto]
349
+ header.class.members.each do |elem|
350
+ elem_sym = RUBY_VERSION[/^1\.8/] ? elem.to_sym : elem
351
+ next if elem_sym == :body
352
+ elem_type_value = []
353
+ elem_type_value[0] = elem
354
+ readable_element = "#{elem}_readable"
355
+ if header.respond_to? readable_element
356
+ elem_type_value[1] = header.send(readable_element)
357
+ else
358
+ elem_type_value[1] = header.send(elem)
359
+ end
360
+ elem_type_value[2] = header[elem.to_sym].class.name
361
+ table[table_idx] ||= []
362
+ table[table_idx] << elem_type_value
363
+ end
364
+ end
365
+ table
366
+ end
367
+
368
+ # Renders the dissection_table suitable for screen printing. Can take
369
+ # one or two arguments. If just the one, only that layer will be displayed
370
+ # take either a range or a number -- if a range, only protos within
371
+ # that range will be rendered. If an integer, only that proto
372
+ # will be rendered.
373
+ def dissect(min=nil,max=nil)
374
+ table = self.dissection_table
375
+ widest = (0..2).map {|i| table.map {|x| x.map {|y| y[i].size}}.flatten.sort.last}
376
+ table_formatted = ""
377
+ begin
378
+ if min
379
+ layer_min = min.to_i
380
+ layer_max = max ? max.to_i : layer_min
381
+ table_range = (layer_min..layer_max)
382
+ else
383
+ layer_min = min
384
+ end
385
+ rescue => e
386
+ raise ArgumentError, "Method `dissect' accepts one or two to_i-able arguments"
387
+ end
388
+ header_line_width = widest.inject {|sum,i| sum ? sum + i : i} + 2
389
+ table.each_with_index do |proto_table,proto_idx|
390
+ if layer_min
391
+ next unless table_range.member? proto_idx
392
+ end
393
+ table_formatted << "--#{proto_table.first}"
394
+ table_formatted << "-" * (header_line_width - proto_table.first.size) << "\n"
395
+ proto_table[1,proto_table.size].each do |elem,value,type|
396
+ table_formatted << " %-#{widest[0]}s " % elem
397
+ table_formatted << "%-#{widest[1]}s " % value.to_s
398
+ table_formatted << type << "\n"
399
+ end
400
+ end
401
+ table_formatted << ("-" * header_line_width)
402
+ table_formatted
403
+ end
404
+
284
405
  alias :orig_kind_of? :kind_of?
285
406
 
286
407
  def kind_of?(klass)
@@ -330,7 +451,13 @@ module PacketFu
330
451
  alias_method :protocol, :proto
331
452
  alias_method :length, :size
332
453
 
454
+ # the Packet class should not be instantiated directly, since it's an
455
+ # abstract class that real packet types inherit from. Sadly, this
456
+ # makes the Packet class more difficult to test directly.
333
457
  def initialize(args={})
458
+ if self.class.name =~ /(::|^)PacketFu::Packet$/
459
+ raise NoMethodError, "method `new' called for abstract class #{self.class.name}"
460
+ end
334
461
  if args[:config]
335
462
  args[:config].each_pair do |k,v|
336
463
  case k
@@ -385,10 +512,10 @@ module PacketFu
385
512
 
386
513
  end # class Packet
387
514
 
388
- @@inspect_style = :pretty
515
+ @inspect_style = :pretty
389
516
 
390
- # If @@inspect_style is :ugly, set the inspect method to the usual inspect.
391
- # By default, @@inspect_style is :pretty. This default may change if people
517
+ # If @inspect_style is :ugly, set the inspect method to the usual inspect.
518
+ # By default, @inspect_style is :pretty. This default may change if people
392
519
  # hate it.
393
520
  # Since PacketFu is designed with irb in mind, the normal inspect is way too
394
521
  # verbose when new packets are created, and it ruins the aesthetics of the
@@ -416,12 +543,12 @@ module PacketFu
416
543
  # => #<PacketFu::TCPPacket:0xb7aaf96c @ip_header=#<struct PacketFu::IPHeader ip_v=4, ip_hl=5, ip_tos=#<struct StructFu::Int8 value=nil, endian=nil, width=1, default=0>, ip_len=#<struct StructFu::Int16 value=20, endian=:big, width=2, default=0>, ip_id=#<struct StructFu::Int16 value=58458, endian=:big, width=2, default=0>, ip_frag=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, ip_ttl=#<struct StructFu::Int8 value=32, endian=nil, width=1, default=0>, ip_proto=#<struct StructFu::Int8 value=6, endian=nil, width=1, default=0>, ip_sum=#<struct StructFu::Int16 value=65535, endian=:big, width=2, default=0>, ip_src=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, ip_dst=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, body=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">>, @tcp_header=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">, @eth_header=#<struct PacketFu::EthHeader eth_dst=#<struct PacketFu::EthMac oui=#<struct PacketFu::EthOui b0=nil, b1=nil, b2=nil, b3=nil, b4=nil, b5=nil, local=0, multicast=nil, oui=428>, nic=#<struct PacketFu::EthNic n0=nil, n1=nil, n2=nil>>, eth_src=#<struct PacketFu::EthMac oui=#<struct PacketFu::EthOui b0=nil, b1=nil, b2=nil, b3=nil, b4=nil, b5=nil, local=0, multicast=nil, oui=428>, nic=#<struct PacketFu::EthNic n0=nil, n1=nil, n2=nil>>, eth_proto=#<struct StructFu::Int16 value=2048, endian=:big, width=2, default=0>, body=#<struct PacketFu::IPHeader ip_v=4, ip_hl=5, ip_tos=#<struct StructFu::Int8 value=nil, endian=nil, width=1, default=0>, ip_len=#<struct StructFu::Int16 value=20, endian=:big, width=2, default=0>, ip_id=#<struct StructFu::Int16 value=58458, endian=:big, width=2, default=0>, ip_frag=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, ip_ttl=#<struct StructFu::Int8 value=32, endian=nil, width=1, default=0>, ip_proto=#<struct StructFu::Int8 value=6, endian=nil, width=1, default=0>, ip_sum=#<struct StructFu::Int16 value=65535, endian=:big, width=2, default=0>, ip_src=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, ip_dst=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, body=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">>>, @headers=[#<struct PacketFu::EthHeader eth_dst=#<struct PacketFu::EthMac oui=#<struct PacketFu::EthOui b0=nil, b1=nil, b2=nil, b3=nil, b4=nil, b5=nil, local=0, multicast=nil, oui=428>, nic=#<struct PacketFu::EthNic n0=nil, n1=nil, n2=nil>>, eth_src=#<struct PacketFu::EthMac oui=#<struct PacketFu::EthOui b0=nil, b1=nil, b2=nil, b3=nil, b4=nil, b5=nil, local=0, multicast=nil, oui=428>, nic=#<struct PacketFu::EthNic n0=nil, n1=nil, n2=nil>>, eth_proto=#<struct StructFu::Int16 value=2048, endian=:big, width=2, default=0>, body=#<struct PacketFu::IPHeader ip_v=4, ip_hl=5, ip_tos=#<struct StructFu::Int8 value=nil, endian=nil, width=1, default=0>, ip_len=#<struct StructFu::Int16 value=20, endian=:big, width=2, default=0>, ip_id=#<struct StructFu::Int16 value=58458, endian=:big, width=2, default=0>, ip_frag=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, ip_ttl=#<struct StructFu::Int8 value=32, endian=nil, width=1, default=0>, ip_proto=#<struct StructFu::Int8 value=6, endian=nil, width=1, default=0>, ip_sum=#<struct StructFu::Int16 value=65535, endian=:big, width=2, default=0>, ip_src=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, ip_dst=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, body=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">>>, #<struct PacketFu::IPHeader ip_v=4, ip_hl=5, ip_tos=#<struct StructFu::Int8 value=nil, endian=nil, width=1, default=0>, ip_len=#<struct StructFu::Int16 value=20, endian=:big, width=2, default=0>, ip_id=#<struct StructFu::Int16 value=58458, endian=:big, width=2, default=0>, ip_frag=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, ip_ttl=#<struct StructFu::Int8 value=32, endian=nil, width=1, default=0>, ip_proto=#<struct StructFu::Int8 value=6, endian=nil, width=1, default=0>, ip_sum=#<struct StructFu::Int16 value=65535, endian=:big, width=2, default=0>, ip_src=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, ip_dst=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, body=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">>, #<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">]>
417
544
  # irb(main):004:0>
418
545
  def toggle_inspect
419
- if @@inspect_style == :pretty
546
+ if @inspect_style == :pretty
420
547
  eval("class Packet; def inspect; super; end; end")
421
- @@inspect_style = :ugly
548
+ @inspect_style = :ugly
422
549
  else
423
550
  eval("class Packet; def inspect; self.proto.join('|') + \"\n\" + self.inspect_hex; end; end")
424
- @@inspect_style = :pretty
551
+ @inspect_style = :pretty
425
552
  end
426
553
  end
427
554
 
data/lib/packetfu/pcap.rb CHANGED
@@ -274,9 +274,6 @@ module PacketFu
274
274
  # Note that this strips out pcap timestamps -- if you'd like to retain
275
275
  # timestamps and other libpcap file information, you will want to
276
276
  # use read() instead.
277
- #
278
- # Note, invoking this requires the somewhat clumsy sytax of,
279
- # PcapFile.new.file_to_array(:f => 'filename.pcap')
280
277
  def file_to_array(args={})
281
278
  filename = args[:filename] || args[:file] || args[:f]
282
279
  if filename
@@ -291,6 +288,10 @@ module PacketFu
291
288
 
292
289
  alias_method :f2a, :file_to_array
293
290
 
291
+ def self.file_to_array(fname)
292
+ PcapFile.new.file_to_array(:f => fname)
293
+ end
294
+
294
295
  # Takes an array of packets (as generated by file_to_array), and writes them
295
296
  # to a file. Valid arguments are:
296
297
  #
@@ -77,7 +77,7 @@ module PacketFu
77
77
  # Setter for the ARP protocol length.
78
78
  def arp_proto_len=(i); typecast i; end
79
79
  # Getter for the ARP protocol length.
80
- def arp_proto; self[:arp_proto].to_i; end
80
+ def arp_proto_len; self[:arp_proto_len].to_i; end
81
81
  # Setter for the ARP opcode.
82
82
  def arp_opcode=(i); typecast i; end
83
83
  # Getter for the ARP opcode.
@@ -143,6 +143,17 @@ module PacketFu
143
143
  self[:arp_dst_ip].to_x
144
144
  end
145
145
 
146
+ # Readability aliases
147
+
148
+ alias :arp_src_mac_readable :arp_saddr_mac
149
+ alias :arp_dst_mac_readable :arp_daddr_mac
150
+ alias :arp_src_ip_readable :arp_saddr_ip
151
+ alias :arp_dst_ip_readable :arp_daddr_ip
152
+
153
+ def arp_proto_readable
154
+ "0x%04x" % arp_proto
155
+ end
156
+
146
157
  end # class ARPHeader
147
158
 
148
159
  # ARPPacket is used to construct ARP packets. They contain an EthHeader and an ARPHeader.
@@ -216,8 +227,8 @@ module PacketFu
216
227
  end
217
228
 
218
229
  # Generates summary data for ARP packets.
219
- def peek(args={})
220
- peek_data = ["A "]
230
+ def peek_format
231
+ peek_data = ["A "]
221
232
  peek_data << "%-5d" % self.to_s.size
222
233
  peek_data << arp_saddr_mac
223
234
  peek_data << "(#{arp_saddr_ip})"
@@ -229,6 +229,15 @@ module PacketFu
229
229
  EthHeader.str2mac(self[:eth_dst].to_s)
230
230
  end
231
231
 
232
+ # Readability aliases
233
+
234
+ alias :eth_dst_readable :eth_daddr
235
+ alias :eth_src_readable :eth_saddr
236
+
237
+ def eth_proto_readable
238
+ "0x%04x" % eth_proto
239
+ end
240
+
232
241
  end
233
242
 
234
243
  # EthPacket is used to construct Ethernet packets. They contain an
@@ -109,6 +109,13 @@ module PacketFu
109
109
  self[:hsrp_vip].to_x
110
110
  end
111
111
 
112
+ # Readability aliases
113
+
114
+ alias :hsrp_vip_readable :hsrp_addr
115
+
116
+ def hsrp_password_readable
117
+ hsrp_password.to_s.inspect
118
+ end
112
119
 
113
120
  end
114
121
 
@@ -182,14 +189,13 @@ module PacketFu
182
189
  end
183
190
 
184
191
  # Peek provides summary data on packet contents.
185
- def peek(args={})
186
- peek_data = ["H "]
192
+ def peek_format
193
+ peek_data = ["UH "]
187
194
  peek_data << "%-5d" % self.to_s.size
188
- peek_data << "%-21s" % "#{self.hsrp_vip}:#{self.hsrp_group}:#{self.hsrp_password}"
189
- peek_data << "%23s" % "U:"
190
- peek_data << "%-21s" % "#{self.ip_saddr}:#{self.udp_sport}"
191
- peek_data << "->"
192
- peek_data << "%21s" % "#{self.ip_daddr}:#{self.udp_dport}"
195
+ peek_data << "%-16s" % self.hsrp_addr
196
+ peek_data << "%-4d" % self.hsrp_group
197
+ peek_data << "%-35s" % self.hsrp_password_readable
198
+ peek_data << "%-15s" % self.ip_saddr
193
199
  peek_data.join
194
200
  end
195
201
 
@@ -83,6 +83,12 @@ module PacketFu
83
83
  end
84
84
  end
85
85
 
86
+ # Readability aliases
87
+
88
+ def icmp_sum_readable
89
+ "0x%04x" % icmp_sum
90
+ end
91
+
86
92
  end
87
93
 
88
94
  # ICMPPacket is used to construct ICMP Packets. They contain an EthHeader, an IPHeader, and a ICMPHeader.
@@ -148,8 +154,8 @@ module PacketFu
148
154
  end
149
155
 
150
156
  # Peek provides summary data on packet contents.
151
- def peek(args={})
152
- peek_data = ["C "] # I is taken by IP
157
+ def peek_format
158
+ peek_data = ["IC "] # I is taken by IP
153
159
  peek_data << "%-5d" % self.to_s.size
154
160
  type = case self.icmp_type.to_i
155
161
  when 8
@@ -261,6 +261,19 @@ module PacketFu
261
261
  end
262
262
  end
263
263
 
264
+ # Readability aliases
265
+
266
+ alias :ip_src_readable :ip_saddr
267
+ alias :ip_dst_readable :ip_daddr
268
+
269
+ def ip_id_readable
270
+ "0x%04x" % ip_id
271
+ end
272
+
273
+ def ip_sum_readable
274
+ "0x%04x" % ip_sum
275
+ end
276
+
264
277
  end
265
278
 
266
279
  # IPPacket is used to construct IP packets. They contain an EthHeader, an IPHeader, and usually
@@ -329,8 +342,8 @@ module PacketFu
329
342
  end
330
343
 
331
344
  # Peek provides summary data on packet contents.
332
- def peek(args={})
333
- peek_data = ["I "]
345
+ def peek_format
346
+ peek_data = ["I "]
334
347
  peek_data << "%-5d" % to_s.size
335
348
  peek_data << "%-21s" % "#{ip_saddr}"
336
349
  peek_data << "->"
@@ -182,6 +182,11 @@ module PacketFu
182
182
  self[:ipv6_dst].read_x(str)
183
183
  end
184
184
 
185
+ # Readability aliases
186
+
187
+ alias :ipv6_src_readable :ipv6_saddr
188
+ alias :ipv6_dst_readable :ipv6_daddr
189
+
185
190
  end # class IPv6Header
186
191
 
187
192
  # IPv6Packet is used to construct IPv6 Packets. They contain an EthHeader and an IPv6Header, and in
@@ -230,7 +235,7 @@ module PacketFu
230
235
 
231
236
  # Peek provides summary data on packet contents.
232
237
  def peek(args={})
233
- peek_data = ["6 "]
238
+ peek_data = ["6 "]
234
239
  peek_data << "%-5d" % self.to_s.size
235
240
  peek_data << "%-31s" % self.ipv6_saddr
236
241
  peek_data << "-> "
@@ -842,6 +842,15 @@ module PacketFu
842
842
  self[:tcp_opts].decode
843
843
  end
844
844
 
845
+ # Gets a more readable flags list
846
+ def tcp_flags_dotmap
847
+ dotmap = tcp_flags.members.map do |flag|
848
+ status = self.tcp_flags.send flag
849
+ status == 0 ? "." : flag.to_s.upcase[0]
850
+ end
851
+ dotmap.join
852
+ end
853
+
845
854
  # Sets a more readable option list.
846
855
  def tcp_options=(arg)
847
856
  self[:tcp_opts].encode arg
@@ -887,6 +896,26 @@ module PacketFu
887
896
  end
888
897
  end
889
898
 
899
+ # Readability aliases
900
+
901
+ alias :tcp_flags_readable :tcp_flags_dotmap
902
+
903
+ def tcp_ack_readable
904
+ "0x%08x" % tcp_ack
905
+ end
906
+
907
+ def tcp_seq_readable
908
+ "0x%08x" % tcp_seq
909
+ end
910
+
911
+ def tcp_sum_readable
912
+ "0x%04x" % tcp_sum
913
+ end
914
+
915
+ def tcp_opts_readable
916
+ tcp_options
917
+ end
918
+
890
919
  end
891
920
 
892
921
  # TCPPacket is used to construct TCP packets. They contain an EthHeader, an IPHeader, and a TCPHeader.
@@ -1057,20 +1086,17 @@ module PacketFu
1057
1086
  end
1058
1087
  end
1059
1088
 
1060
- # Peek provides summary data on packet contents.
1061
- def peek(args={})
1062
- peek_data = ["T "]
1089
+ # TCP packets are denoted by a "T ", followed by size,
1090
+ # source and dest information, packet flags, sequence
1091
+ # number, and IPID.
1092
+ def peek_format
1093
+ peek_data = ["T "]
1063
1094
  peek_data << "%-5d" % self.to_s.size
1064
1095
  peek_data << "%-21s" % "#{self.ip_saddr}:#{self.tcp_src}"
1065
1096
  peek_data << "->"
1066
1097
  peek_data << "%21s" % "#{self.ip_daddr}:#{self.tcp_dst}"
1067
1098
  flags = ' ['
1068
- flags << (self.tcp_flags.urg.zero? ? "." : "U")
1069
- flags << (self.tcp_flags.ack.zero? ? "." : "A")
1070
- flags << (self.tcp_flags.psh.zero? ? "." : "P")
1071
- flags << (self.tcp_flags.rst.zero? ? "." : "R")
1072
- flags << (self.tcp_flags.syn.zero? ? "." : "S")
1073
- flags << (self.tcp_flags.fin.zero? ? "." : "F")
1099
+ flags << self.tcp_flags_dotmap
1074
1100
  flags << '] '
1075
1101
  peek_data << flags
1076
1102
  peek_data << "S:"
@@ -97,6 +97,12 @@ module PacketFu
97
97
  self.udp_dst=(arg)
98
98
  end
99
99
 
100
+ # Readability aliases
101
+
102
+ def udp_sum_readable
103
+ "0x%04x" % udp_sum
104
+ end
105
+
100
106
  end
101
107
 
102
108
  # UDPPacket is used to construct UDP Packets. They contain an EthHeader, an IPHeader, and a UDPHeader.
@@ -216,8 +222,8 @@ module PacketFu
216
222
  end
217
223
 
218
224
  # Peek provides summary data on packet contents.
219
- def peek(args={})
220
- peek_data = ["U "]
225
+ def peek_format
226
+ peek_data = ["U "]
221
227
  peek_data << "%-5d" % self.to_s.size
222
228
  peek_data << "%-21s" % "#{self.ip_saddr}:#{self.udp_sport}"
223
229
  peek_data << "->"
@@ -33,6 +33,11 @@ module StructFu
33
33
  end
34
34
  end
35
35
 
36
+ # Handle deep copies correctly
37
+ def clone
38
+ Marshal.load(Marshal.dump(self))
39
+ end
40
+
36
41
  # Ints all have a value, an endianness, and a default value.
37
42
  # Note that the signedness of Int values are implicit as
38
43
  # far as the subclasses are concerned; to_i and to_f will
@@ -1,8 +1,7 @@
1
1
  module PacketFu
2
2
 
3
- # Version 1.0.0 was released July 31, 2010
4
- # Version 1.0.1 is unreleased.
5
- VERSION = "1.0.2"
3
+ # Check the repo's for version release histories
4
+ VERSION = "1.0.3"
6
5
 
7
6
  def self.version
8
7
  VERSION
@@ -0,0 +1,15 @@
1
+ # This just allows you to eyeball the dissection stuff to make sure it's all right.
2
+
3
+ require File.join("..","lib","packetfu")
4
+ puts "Loaded: PacketFu v#{PacketFu.version}"
5
+ # $: << File.join(File.expand_path(File.dirname(__FILE__)),"..","lib")
6
+
7
+ include PacketFu
8
+
9
+ packets = PcapFile.file_to_array "test/sample2.pcap"
10
+ packets.each do |packet|
11
+ puts packet.inspect
12
+ pkt = Packet.parse(packet)
13
+ puts pkt.dissect
14
+ sleep 1
15
+ end
data/test/icmp_test.pcap CHANGED
Binary file
data/test/ip_test.pcap CHANGED
Binary file
@@ -0,0 +1,72 @@
1
+ require File.join("..","lib","packetfu")
2
+
3
+ describe PacketFu::Packet, "abstract packet class behavior" do
4
+
5
+ before(:all) do
6
+ class PacketFu::FooPacket < PacketFu::Packet; end
7
+ class PacketFu::BarPacket < PacketFu::Packet; end
8
+ end
9
+
10
+ it "should not be instantiated" do
11
+ expect { PacketFu::Packet.new }.to raise_error(NoMethodError)
12
+ end
13
+
14
+ it "should allow subclasses to instantiate" do
15
+ expect { PacketFu::FooPacket.new }. to be
16
+ PacketFu.packet_classes.include?(PacketFu::FooPacket).should be_true
17
+ end
18
+
19
+ it "should register packet classes with PacketFu" do
20
+ PacketFu.packet_classes {should include(FooPacket) }
21
+ PacketFu.packet_classes {should include(BarPacket) }
22
+ end
23
+
24
+ it "should disallow badly named subclasses" do
25
+ expect {
26
+ class PacketFu::PacketNot < PacketFu::Packet
27
+ end
28
+ }.to raise_error
29
+ PacketFu.packet_classes.include?(PacketFu::PacketNot).should be_false
30
+ PacketFu.packet_classes {should_not include(PacketNot) }
31
+ end
32
+
33
+ before(:each) do
34
+ @tcp_packet = PacketFu::TCPPacket.new
35
+ @tcp_packet.ip_saddr = "10.10.10.10"
36
+ end
37
+
38
+ it "should shallow copy with dup()" do
39
+ p2 = @tcp_packet.dup
40
+ p2.ip_saddr = "20.20.20.20"
41
+ p2.ip_saddr.should == @tcp_packet.ip_saddr
42
+ p2.headers[1].object_id.should == @tcp_packet.headers[1].object_id
43
+ end
44
+
45
+ it "should deep copy with clone()" do
46
+ p3 = @tcp_packet.clone
47
+ p3.ip_saddr = "30.30.30.30"
48
+ p3.ip_saddr.should_not == @tcp_packet.ip_saddr
49
+ p3.headers[1].object_id.should_not == @tcp_packet.headers[1].object_id
50
+ end
51
+
52
+ it "should have senisble equality" do
53
+ p4 = @tcp_packet.dup
54
+ p4.should == @tcp_packet
55
+ p5 = @tcp_packet.clone
56
+ p5.should == @tcp_packet
57
+ end
58
+
59
+ # It's actually kinda hard to manually create identical TCP packets
60
+ it "should be possible to manually create identical packets" do
61
+ p6 = @tcp_packet.clone
62
+ p6.should == @tcp_packet
63
+ p7 = PacketFu::TCPPacket.new
64
+ p7.ip_saddr = p6.ip_saddr
65
+ p7.ip_id = p6.ip_id
66
+ p7.tcp_seq = p6.tcp_seq
67
+ p7.tcp_src = p6.tcp_src
68
+ p7.tcp_sum = p6.tcp_sum
69
+ p7.should == p6
70
+ end
71
+
72
+ end
@@ -0,0 +1,12 @@
1
+ require File.join("..","lib","packetfu")
2
+
3
+ PacketFu.packet_classes.each do |pclass|
4
+ describe pclass, "peek format" do
5
+ it "will display sensible peek information" do
6
+ p = pclass.new
7
+ p.respond_to?(:peek).should be_true
8
+ p.peek.size.should be_<=(80), p.peek.inspect
9
+ p.peek.should match(/^[A-Z0-9?]../)
10
+ end
11
+ end
12
+ end
@@ -54,17 +54,31 @@ describe PacketFu, "protocol requires" do
54
54
  end
55
55
 
56
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)}
57
+
58
+ before(:all) do
59
+ class PacketFu::FooPacket < PacketFu::Packet; end
60
+ class PacketFu::BarPacket < PacketFu::Packet; end
61
+ class PacketFu::PacketBaz; end
62
+ end
63
+
64
+ it "should allow packet class registration" do
65
+ PacketFu.add_packet_class(PacketFu::FooPacket).should be_kind_of Array
66
+ PacketFu.add_packet_class(PacketFu::BarPacket).should be_kind_of Array
67
+ end
68
+
69
+ its(:packet_classes) {should include(PacketFu::FooPacket)}
70
+
62
71
  it "should disallow non-classes as packet classes" do
63
72
  expect { PacketFu.add_packet_class("A String") }.to raise_error
64
73
  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
74
+
75
+ its(:packet_prefixes) {should include("bar")}
76
+
77
+ # Don't really have much utility for this right now.
78
+ it "should allow packet class deregistration" do
79
+ PacketFu.remove_packet_class(PacketFu::BarPacket)
80
+ PacketFu.packet_prefixes.should_not include("bar")
81
+ PacketFu.add_packet_class(PacketFu::BarPacket)
69
82
  end
83
+
70
84
  end
data/test/ptest.rb CHANGED
@@ -4,7 +4,13 @@ require 'pcaprub'
4
4
  require 'packetfu'
5
5
  include PacketFu
6
6
 
7
- puts Pcap.lookupdev
7
+ if Process.euid.zero?
8
+ puts ">> Interface: " << Pcap.lookupdev
9
+ else
10
+ puts ">> No interface access"
11
+ end
12
+ puts ">> Version: " << PacketFu.version
13
+
8
14
  # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
9
15
 
10
16
 
@@ -331,8 +331,4 @@ describe StructFu::IntString do
331
331
  expect { @istr.read(data) }.to raise_error
332
332
  end
333
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
334
  end
data/test/tcp_test.pcap CHANGED
Binary file
data/test/udp_test.pcap CHANGED
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: packetfu
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1344461223
4
+ hash: -1237194367
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 2
9
+ - 3
10
10
  - pre
11
- version: 1.0.2.pre
11
+ version: 1.0.3.pre
12
12
  platform: ruby
13
13
  authors:
14
14
  - Tod Beardsley
@@ -88,6 +88,7 @@ files:
88
88
  - test/udp_test.pcap
89
89
  - test/sample2.pcap
90
90
  - test/sample.pcap
91
+ - test/dissect_thinger.rb
91
92
  - test/test_ip6.rb
92
93
  - test/all_tests.rb
93
94
  - test/test_invalid.rb
@@ -103,6 +104,7 @@ files:
103
104
  - test/arp_test.pcap
104
105
  - test/test_inject.rb
105
106
  - test/test_eth.rb
107
+ - test/packet_spec.rb
106
108
  - test/sample-ipv6.pcap
107
109
  - test/test_hsrp.rb
108
110
  - test/test_structfu.rb
@@ -111,8 +113,10 @@ files:
111
113
  - test/eth_test.pcap
112
114
  - test/test_ip.rb
113
115
  - test/structfu_spec.rb
116
+ - test/packet_subclasses_spec.rb
114
117
  - examples/oui.txt
115
118
  - examples/uniqpcap.rb
119
+ - examples/dissect_thinger.rb
116
120
  - examples/examples.rb
117
121
  - examples/simple-stats.rb
118
122
  - examples/arphood.rb