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.
- data/examples/dissect_thinger.rb +22 -0
- data/lib/packetfu.rb +7 -0
- data/lib/packetfu/packet.rb +136 -9
- data/lib/packetfu/pcap.rb +4 -3
- data/lib/packetfu/protos/arp.rb +14 -3
- data/lib/packetfu/protos/eth.rb +9 -0
- data/lib/packetfu/protos/hsrp.rb +13 -7
- data/lib/packetfu/protos/icmp.rb +8 -2
- data/lib/packetfu/protos/ip.rb +15 -2
- data/lib/packetfu/protos/ipv6.rb +6 -1
- data/lib/packetfu/protos/tcp.rb +35 -9
- data/lib/packetfu/protos/udp.rb +8 -2
- data/lib/packetfu/structfu.rb +5 -0
- data/lib/packetfu/version.rb +2 -3
- data/test/dissect_thinger.rb +15 -0
- data/test/icmp_test.pcap +0 -0
- data/test/ip_test.pcap +0 -0
- data/test/packet_spec.rb +72 -0
- data/test/packet_subclasses_spec.rb +12 -0
- data/test/packetfu_spec.rb +23 -9
- data/test/ptest.rb +7 -1
- data/test/structfu_spec.rb +0 -4
- data/test/tcp_test.pcap +0 -0
- data/test/udp_test.pcap +0 -0
- metadata +7 -3
@@ -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
|
data/lib/packetfu/packet.rb
CHANGED
@@ -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
|
-
#
|
167
|
-
#
|
194
|
+
#
|
195
|
+
# Each packet type should provide a peek_format.
|
168
196
|
def peek(args={})
|
169
|
-
|
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
|
-
|
515
|
+
@inspect_style = :pretty
|
389
516
|
|
390
|
-
# If
|
391
|
-
# By default,
|
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
|
546
|
+
if @inspect_style == :pretty
|
420
547
|
eval("class Packet; def inspect; super; end; end")
|
421
|
-
|
548
|
+
@inspect_style = :ugly
|
422
549
|
else
|
423
550
|
eval("class Packet; def inspect; self.proto.join('|') + \"\n\" + self.inspect_hex; end; end")
|
424
|
-
|
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
|
#
|
data/lib/packetfu/protos/arp.rb
CHANGED
@@ -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
|
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
|
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})"
|
data/lib/packetfu/protos/eth.rb
CHANGED
@@ -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
|
data/lib/packetfu/protos/hsrp.rb
CHANGED
@@ -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
|
186
|
-
peek_data = ["
|
192
|
+
def peek_format
|
193
|
+
peek_data = ["UH "]
|
187
194
|
peek_data << "%-5d" % self.to_s.size
|
188
|
-
peek_data << "%-
|
189
|
-
peek_data << "
|
190
|
-
peek_data << "%-
|
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
|
|
data/lib/packetfu/protos/icmp.rb
CHANGED
@@ -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
|
152
|
-
peek_data = ["
|
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
|
data/lib/packetfu/protos/ip.rb
CHANGED
@@ -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
|
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 << "->"
|
data/lib/packetfu/protos/ipv6.rb
CHANGED
@@ -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 << "-> "
|
data/lib/packetfu/protos/tcp.rb
CHANGED
@@ -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
|
-
#
|
1061
|
-
|
1062
|
-
|
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 <<
|
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:"
|
data/lib/packetfu/protos/udp.rb
CHANGED
@@ -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
|
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 << "->"
|
data/lib/packetfu/structfu.rb
CHANGED
@@ -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
|
data/lib/packetfu/version.rb
CHANGED
@@ -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
|
data/test/packet_spec.rb
ADDED
@@ -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
|
data/test/packetfu_spec.rb
CHANGED
@@ -54,17 +54,31 @@ describe PacketFu, "protocol requires" do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
describe PacketFu, "packet class list management" do
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
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
|
|
data/test/structfu_spec.rb
CHANGED
@@ -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:
|
4
|
+
hash: -1237194367
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
|
-
-
|
9
|
+
- 3
|
10
10
|
- pre
|
11
|
-
version: 1.0.
|
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
|