packetfu 1.0.2.pre → 1.0.3.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -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