packetfu 1.0.0 → 1.0.2.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +1 -1
- data/README +3 -0
- data/examples/packetfu-shell.rb +5 -3
- data/lib/packetfu.rb +48 -63
- data/lib/packetfu/packet.rb +144 -206
- data/lib/packetfu/pcap.rb +5 -5
- data/lib/packetfu/{arp.rb → protos/arp.rb} +17 -2
- data/lib/packetfu/{eth.rb → protos/eth.rb} +15 -4
- data/lib/packetfu/protos/hsrp.rb +200 -0
- data/lib/packetfu/{icmp.rb → protos/icmp.rb} +20 -1
- data/lib/packetfu/{invalid.rb → protos/invalid.rb} +14 -0
- data/lib/packetfu/{ip.rb → protos/ip.rb} +29 -0
- data/lib/packetfu/{ipv6.rb → protos/ipv6.rb} +16 -1
- data/lib/packetfu/{tcp.rb → protos/tcp.rb} +26 -2
- data/lib/packetfu/{udp.rb → protos/udp.rb} +25 -1
- data/lib/packetfu/structfu.rb +10 -3
- data/lib/packetfu/version.rb +50 -0
- data/test/all_tests.rb +33 -30
- data/test/arp_test.pcap +0 -0
- data/test/eth_test.pcap +0 -0
- data/test/icmp_test.pcap +0 -0
- data/test/ip_test.pcap +0 -0
- data/test/packetfu_spec.rb +70 -0
- data/test/sample-ipv6.pcap +0 -0
- data/test/sample_hsrp_pcapr.cap +0 -0
- data/test/structfu_spec.rb +338 -0
- data/test/tcp_test.pcap +0 -0
- data/test/test_arp.rb +0 -0
- data/test/test_eth.rb +2 -1
- data/test/test_hsrp.rb +71 -0
- data/test/test_icmp.rb +0 -0
- data/test/test_ip6.rb +0 -0
- data/test/test_octets.rb +0 -0
- data/test/test_packet.rb +137 -3
- data/test/test_structfu.rb +0 -0
- data/test/test_tcp.rb +0 -0
- data/test/test_udp.rb +0 -0
- data/test/udp_test.pcap +0 -0
- metadata +52 -20
- data/TODO +0 -25
data/lib/packetfu/pcap.rb
CHANGED
@@ -266,8 +266,8 @@ module PacketFu
|
|
266
266
|
# that readfile clears any existing packets, since that seems to be the
|
267
267
|
# typical use.
|
268
268
|
def readfile(file)
|
269
|
-
|
270
|
-
self.read!
|
269
|
+
fdata = File.open(file, "rb") {|f| f.read}
|
270
|
+
self.read! fdata
|
271
271
|
end
|
272
272
|
|
273
273
|
# file_to_array() translates a libpcap file into an array of packets.
|
@@ -416,7 +416,7 @@ module PacketFu
|
|
416
416
|
|
417
417
|
# set_byte_order is pretty much totally deprecated.
|
418
418
|
def set_byte_order(byte_order)
|
419
|
-
PacketFu.instance_variable_set(
|
419
|
+
PacketFu.instance_variable_set(:@byte_order,byte_order)
|
420
420
|
return true
|
421
421
|
end
|
422
422
|
|
@@ -450,7 +450,7 @@ module PacketFu
|
|
450
450
|
arr = args[:arr] || args[:array] || []
|
451
451
|
ts = args[:ts] || args[:timestamp] || Time.now.to_i
|
452
452
|
ts_inc = args[:ts_inc] || args[:timestamp_increment]
|
453
|
-
pkts = PcapFile.new.array_to_file(:endian => PacketFu.instance_variable_get(
|
453
|
+
pkts = PcapFile.new.array_to_file(:endian => PacketFu.instance_variable_get(:@byte_order),
|
454
454
|
:arr => arr,
|
455
455
|
:ts => ts,
|
456
456
|
:ts_inc => ts_inc)
|
@@ -468,7 +468,7 @@ module PacketFu
|
|
468
468
|
append = args[:append]
|
469
469
|
Read.set_byte_order(byte_order) if [:big, :little].include? byte_order
|
470
470
|
pf = PcapFile.new
|
471
|
-
pf.array_to_file(:endian => PacketFu.instance_variable_get(
|
471
|
+
pf.array_to_file(:endian => PacketFu.instance_variable_get(:@byte_order),
|
472
472
|
:arr => arr,
|
473
473
|
:ts => ts,
|
474
474
|
:ts_inc => ts_inc)
|
@@ -173,13 +173,29 @@ module PacketFu
|
|
173
173
|
|
174
174
|
attr_accessor :eth_header, :arp_header
|
175
175
|
|
176
|
+
def self.can_parse?(str)
|
177
|
+
return false unless EthPacket.can_parse? str
|
178
|
+
return false unless str.size >= 28
|
179
|
+
return false unless str[12,2] == "\x08\x06"
|
180
|
+
true
|
181
|
+
end
|
182
|
+
|
183
|
+
def read(str=nil,args={})
|
184
|
+
raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
|
185
|
+
@eth_header.read(str)
|
186
|
+
@arp_header.read(str[14,str.size])
|
187
|
+
@eth_header.body = @arp_header
|
188
|
+
super(args)
|
189
|
+
self
|
190
|
+
end
|
191
|
+
|
176
192
|
def initialize(args={})
|
177
193
|
@eth_header = EthHeader.new(args).read(args[:eth])
|
178
194
|
@arp_header = ARPHeader.new(args).read(args[:arp])
|
179
195
|
@eth_header.eth_proto = "\x08\x06"
|
180
196
|
@eth_header.body=@arp_header
|
181
197
|
|
182
|
-
# Please send more flavors to todb
|
198
|
+
# Please send more flavors to todb+packetfu@planb-security.net.
|
183
199
|
# Most of these initial fingerprints come from one (1) sample.
|
184
200
|
case (args[:flavor].nil?) ? :nil : args[:flavor].to_s.downcase.intern
|
185
201
|
when :windows; @arp_header.body = "\x00" * 64 # 64 bytes of padding
|
@@ -197,7 +213,6 @@ module PacketFu
|
|
197
213
|
|
198
214
|
@headers = [@eth_header, @arp_header]
|
199
215
|
super
|
200
|
-
|
201
216
|
end
|
202
217
|
|
203
218
|
# Generates summary data for ARP packets.
|
@@ -245,10 +245,15 @@ module PacketFu
|
|
245
245
|
class EthPacket < Packet
|
246
246
|
attr_accessor :eth_header
|
247
247
|
|
248
|
-
def
|
249
|
-
|
250
|
-
|
251
|
-
|
248
|
+
def self.can_parse?(str)
|
249
|
+
str.size >= 14
|
250
|
+
end
|
251
|
+
|
252
|
+
def read(str=nil,args={})
|
253
|
+
raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
|
254
|
+
@eth_header.read(str)
|
255
|
+
super(args)
|
256
|
+
return self
|
252
257
|
end
|
253
258
|
|
254
259
|
# Does nothing, really, since there's no length or
|
@@ -257,6 +262,12 @@ module PacketFu
|
|
257
262
|
@headers[0].inspect
|
258
263
|
end
|
259
264
|
|
265
|
+
def initialize(args={})
|
266
|
+
@eth_header = EthHeader.new(args).read(args[:eth])
|
267
|
+
@headers = [@eth_header]
|
268
|
+
super
|
269
|
+
end
|
270
|
+
|
260
271
|
end
|
261
272
|
|
262
273
|
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
module PacketFu
|
2
|
+
|
3
|
+
# HSRPHeader is a complete HSRP struct, used in HSRPPacket. HSRP is typically used for
|
4
|
+
# fault-tolerant default gateway in IP routing environment.
|
5
|
+
#
|
6
|
+
# For more on HSRP packets, see http://www.networksorcery.com/enp/protocol/hsrp.htm
|
7
|
+
#
|
8
|
+
# Submitted by fropert@packetfault.org. Thanks, Francois!
|
9
|
+
#
|
10
|
+
# ==== Header Definition
|
11
|
+
#
|
12
|
+
# Int8 :hsrp_version Default: 0 # Version
|
13
|
+
# Int8 :hsrp_opcode # Opcode
|
14
|
+
# Int8 :hsrp_state # State
|
15
|
+
# Int8 :hsrp_hellotime Default: 3 # Hello Time
|
16
|
+
# Int8 :hsrp_holdtime Default: 10 # Hold Time
|
17
|
+
# Int8 :hsrp_priority # Priority
|
18
|
+
# Int8 :hsrp_group # Group
|
19
|
+
# Int8 :hsrp_reserved Default: 0 # Reserved
|
20
|
+
# String :hsrp_password # Authentication Data
|
21
|
+
# Octets :hsrp_vip # Virtual IP Address
|
22
|
+
# String :body
|
23
|
+
class HSRPHeader < Struct.new(:hsrp_version, :hsrp_opcode, :hsrp_state,
|
24
|
+
:hsrp_hellotime, :hsrp_holdtime,
|
25
|
+
:hsrp_priority, :hsrp_group,
|
26
|
+
:hsrp_reserved, :hsrp_password,
|
27
|
+
:hsrp_vip, :body)
|
28
|
+
|
29
|
+
include StructFu
|
30
|
+
|
31
|
+
def initialize(args={})
|
32
|
+
super(
|
33
|
+
Int8.new(args[:hsrp_version] || 0),
|
34
|
+
Int8.new(args[:hsrp_opcode]),
|
35
|
+
Int8.new(args[:hsrp_state]),
|
36
|
+
Int8.new(args[:hsrp_hellotime] || 3),
|
37
|
+
Int8.new(args[:hsrp_holdtime] || 10),
|
38
|
+
Int8.new(args[:hsrp_priority]),
|
39
|
+
Int8.new(args[:hsrp_group]),
|
40
|
+
Int8.new(args[:hsrp_reserved] || 0),
|
41
|
+
StructFu::String.new.read(args[:hsrp_password] || "cisco\x00\x00\x00"),
|
42
|
+
Octets.new.read(args[:hsrp_vip] || ("\x00" * 4)),
|
43
|
+
StructFu::String.new.read(args[:body])
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the object in string form.
|
48
|
+
def to_s
|
49
|
+
self.to_a.map {|x| x.to_s}.join
|
50
|
+
end
|
51
|
+
|
52
|
+
# Reads a string to populate the object.
|
53
|
+
def read(str)
|
54
|
+
force_binary(str)
|
55
|
+
return self if str.nil?
|
56
|
+
self[:hsrp_version].read(str[0,1])
|
57
|
+
self[:hsrp_opcode].read(str[1,1])
|
58
|
+
self[:hsrp_state].read(str[2,1])
|
59
|
+
self[:hsrp_hellotime].read(str[3,1])
|
60
|
+
self[:hsrp_holdtime].read(str[4,1])
|
61
|
+
self[:hsrp_priority].read(str[5,1])
|
62
|
+
self[:hsrp_group].read(str[6,1])
|
63
|
+
self[:hsrp_reserved].read(str[7,1])
|
64
|
+
self[:hsrp_password].read(str[8,8])
|
65
|
+
self[:hsrp_vip].read(str[16,4])
|
66
|
+
self[:body].read(str[20,str.size]) if str.size > 20
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
# Setter for the type.
|
71
|
+
def hsrp_version=(i); typecast i; end
|
72
|
+
# Getter for the type.
|
73
|
+
def hsrp_version; self[:hsrp_version].to_i; end
|
74
|
+
# Setter for the type.
|
75
|
+
def hsrp_opcode=(i); typecast i; end
|
76
|
+
# Getter for the type.
|
77
|
+
def hsrp_opcode; self[:hsrp_opcode].to_i; end
|
78
|
+
# Setter for the type.
|
79
|
+
def hsrp_state=(i); typecast i; end
|
80
|
+
# Getter for the type.
|
81
|
+
def hsrp_state; self[:hsrp_state].to_i; end
|
82
|
+
# Setter for the type.
|
83
|
+
def hsrp_hellotime=(i); typecast i; end
|
84
|
+
# Getter for the type.
|
85
|
+
def hsrp_hellotime; self[:hsrp_hellotime].to_i; end
|
86
|
+
# Setter for the type.
|
87
|
+
def hsrp_holdtime=(i); typecast i; end
|
88
|
+
# Getter for the type.
|
89
|
+
def hsrp_holdtime; self[:hsrp_holdtime].to_i; end
|
90
|
+
# Setter for the type.
|
91
|
+
def hsrp_priority=(i); typecast i; end
|
92
|
+
# Getter for the type.
|
93
|
+
def hsrp_priority; self[:hsrp_priority].to_i; end
|
94
|
+
# Setter for the type.
|
95
|
+
def hsrp_group=(i); typecast i; end
|
96
|
+
# Getter for the type.
|
97
|
+
def hsrp_group; self[:hsrp_group].to_i; end
|
98
|
+
# Setter for the type.
|
99
|
+
def hsrp_reserved=(i); typecast i; end
|
100
|
+
# Getter for the type.
|
101
|
+
def hsrp_reserved; self[:hsrp_reserved].to_i; end
|
102
|
+
|
103
|
+
def hsrp_addr=(addr)
|
104
|
+
self[:hsrp_vip].read_quad(addr)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Returns a more readable IP source address.
|
108
|
+
def hsrp_addr
|
109
|
+
self[:hsrp_vip].to_x
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
# HSRPPacket is used to construct HSRP Packets. They contain an EthHeader, an IPHeader, and a UDPHeader.
|
116
|
+
#
|
117
|
+
# == Example
|
118
|
+
#
|
119
|
+
# hsrp_pkt.new
|
120
|
+
# hsrp_pkt.hsrp_opcode = 0
|
121
|
+
# hsrp_pkt.hsrp_state = 16
|
122
|
+
# hsrp_pkt.hsrp_priority = 254
|
123
|
+
# hsrp_pkt.hsrp_group = 1
|
124
|
+
# hsrp_pkt.hsrp_vip = 10.100.100.254
|
125
|
+
# hsrp_pkt.recalc
|
126
|
+
# hsrp_pkt.to_f('/tmp/hsrp.pcap')
|
127
|
+
#
|
128
|
+
# == Parameters
|
129
|
+
#
|
130
|
+
# :eth
|
131
|
+
# A pre-generated EthHeader object.
|
132
|
+
# :ip
|
133
|
+
# A pre-generated IPHeader object.
|
134
|
+
# :udp
|
135
|
+
# A pre-generated UDPHeader object.
|
136
|
+
# :flavor
|
137
|
+
# TODO: HSRP packets don't tend have any flavor.
|
138
|
+
# :config
|
139
|
+
# A hash of return address details, often the output of Utils.whoami?
|
140
|
+
class HSRPPacket < Packet
|
141
|
+
|
142
|
+
attr_accessor :eth_header, :ip_header, :udp_header, :hsrp_header
|
143
|
+
|
144
|
+
def self.can_parse?(str)
|
145
|
+
return false unless str.size >= 54
|
146
|
+
return false unless EthPacket.can_parse? str
|
147
|
+
return false unless IPPacket.can_parse? str
|
148
|
+
return false unless UDPPacket.can_parse? str
|
149
|
+
temp_packet = UDPPacket.new
|
150
|
+
temp_packet.read(str)
|
151
|
+
if temp_packet.ip_ttl == 1 and [temp_packet.udp_sport,temp_packet.udp_dport] == [1985,1985]
|
152
|
+
return true
|
153
|
+
else
|
154
|
+
return false
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def read(str=nil, args={})
|
159
|
+
raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
|
160
|
+
@eth_header.read(str)
|
161
|
+
@ip_header.read(str[14,str.size])
|
162
|
+
@eth_header.body = @ip_header
|
163
|
+
@udp_header.read(str[14+(@ip_header.ip_hlen),str.size])
|
164
|
+
@ip_header.body = @udp_header
|
165
|
+
@hsrp_header.read(str[14+(@ip_header.ip_hlen)+8,str.size])
|
166
|
+
@udp_header.body = @hsrp_header
|
167
|
+
super(args)
|
168
|
+
self
|
169
|
+
end
|
170
|
+
|
171
|
+
def initialize(args={})
|
172
|
+
@eth_header = EthHeader.new(args).read(args[:eth])
|
173
|
+
@ip_header = IPHeader.new(args).read(args[:ip])
|
174
|
+
@ip_header.ip_proto = 0x11
|
175
|
+
@udp_header = UDPHeader.new(args).read(args[:udp])
|
176
|
+
@hsrp_header = HSRPHeader.new(args).read(args[:hsrp])
|
177
|
+
@udp_header.body = @hsrp_header
|
178
|
+
@ip_header.body = @udp_header
|
179
|
+
@eth_header.body = @ip_header
|
180
|
+
@headers = [@eth_header, @ip_header, @udp_header, @hsrp_header]
|
181
|
+
super
|
182
|
+
end
|
183
|
+
|
184
|
+
# Peek provides summary data on packet contents.
|
185
|
+
def peek(args={})
|
186
|
+
peek_data = ["H "]
|
187
|
+
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}"
|
193
|
+
peek_data.join
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
# vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
|
@@ -114,7 +114,26 @@ module PacketFu
|
|
114
114
|
class ICMPPacket < Packet
|
115
115
|
|
116
116
|
attr_accessor :eth_header, :ip_header, :icmp_header
|
117
|
-
|
117
|
+
|
118
|
+
def self.can_parse?(str)
|
119
|
+
return false unless str.size >= 54
|
120
|
+
return false unless EthPacket.can_parse? str
|
121
|
+
return false unless IPPacket.can_parse? str
|
122
|
+
return false unless str[23,1] == "\x01"
|
123
|
+
return true
|
124
|
+
end
|
125
|
+
|
126
|
+
def read(str=nil, args={})
|
127
|
+
raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
|
128
|
+
@eth_header.read(str)
|
129
|
+
@ip_header.read(str[14,str.size])
|
130
|
+
@eth_header.body = @ip_header
|
131
|
+
@icmp_header.read(str[14+(@ip_header.ip_hlen),str.size])
|
132
|
+
@ip_header.body = @icmp_header
|
133
|
+
super(args)
|
134
|
+
self
|
135
|
+
end
|
136
|
+
|
118
137
|
def initialize(args={})
|
119
138
|
@eth_header = EthHeader.new(args).read(args[:eth])
|
120
139
|
@ip_header = IPHeader.new(args).read(args[:ip])
|
@@ -30,6 +30,20 @@ module PacketFu
|
|
30
30
|
class InvalidPacket < Packet
|
31
31
|
attr_accessor :invalid_header
|
32
32
|
|
33
|
+
# Any packet is potentially an invalid packet
|
34
|
+
def self.can_parse?(str)
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.layer
|
39
|
+
0
|
40
|
+
end
|
41
|
+
|
42
|
+
def read(str=nil,args={})
|
43
|
+
@invalid_header.read(str)
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
33
47
|
def initialize(args={})
|
34
48
|
@invalid_header = (args[:invalid] || InvalidHeader.new)
|
35
49
|
@headers = [@invalid_header]
|
@@ -175,6 +175,11 @@ module PacketFu
|
|
175
175
|
(ip_hl * 4) + body.to_s.length
|
176
176
|
end
|
177
177
|
|
178
|
+
# Return the claimed header length
|
179
|
+
def ip_hlen
|
180
|
+
(ip_hl * 4)
|
181
|
+
end
|
182
|
+
|
178
183
|
# Calculate the true checksum of the packet.
|
179
184
|
# (Yes, this is the long way to do it, but it's e-z-2-read for mathtards like me.)
|
180
185
|
def ip_calc_sum
|
@@ -289,6 +294,30 @@ module PacketFu
|
|
289
294
|
|
290
295
|
attr_accessor :eth_header, :ip_header
|
291
296
|
|
297
|
+
def self.can_parse?(str)
|
298
|
+
return false unless str.size >= 34
|
299
|
+
return false unless EthPacket.can_parse? str
|
300
|
+
if str[12,2] == "\x08\x00"
|
301
|
+
if 1.respond_to? :ord
|
302
|
+
ipv = str[14,1][0].ord >> 4
|
303
|
+
else
|
304
|
+
ipv = str[14,1][0] >> 4
|
305
|
+
end
|
306
|
+
return true if ipv == 4
|
307
|
+
else
|
308
|
+
return false
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def read(str=nil, args={})
|
313
|
+
raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
|
314
|
+
@eth_header.read(str)
|
315
|
+
@ip_header.read(str[14,str.size])
|
316
|
+
@eth_header.body = @ip_header
|
317
|
+
super(args)
|
318
|
+
self
|
319
|
+
end
|
320
|
+
|
292
321
|
# Creates a new IPPacket object.
|
293
322
|
def initialize(args={})
|
294
323
|
@eth_header = EthHeader.new(args).read(args[:eth])
|
@@ -203,12 +203,27 @@ module PacketFu
|
|
203
203
|
|
204
204
|
attr_accessor :eth_header, :ipv6_header
|
205
205
|
|
206
|
+
def self.can_parse?(str)
|
207
|
+
return false unless EthPacket.can_parse? str
|
208
|
+
return false unless str.size >= 54
|
209
|
+
return false unless str[12,2] == "\x86\xdd"
|
210
|
+
true
|
211
|
+
end
|
212
|
+
|
213
|
+
def read(str=nil,args={})
|
214
|
+
raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
|
215
|
+
@eth_header.read(str)
|
216
|
+
@ipv6_header.read(str[14,str.size])
|
217
|
+
@eth_header.body = @ipv6_header
|
218
|
+
super(args)
|
219
|
+
self
|
220
|
+
end
|
221
|
+
|
206
222
|
def initialize(args={})
|
207
223
|
@eth_header = (args[:eth] || EthHeader.new)
|
208
224
|
@ipv6_header = (args[:ipv6] || IPv6Header.new)
|
209
225
|
@eth_header.eth_proto = 0x86dd
|
210
226
|
@eth_header.body=@ipv6_header
|
211
|
-
|
212
227
|
@headers = [@eth_header, @ipv6_header]
|
213
228
|
super
|
214
229
|
end
|
@@ -920,8 +920,32 @@ module PacketFu
|
|
920
920
|
# A hash of return address details, often the output of Utils.whoami?
|
921
921
|
class TCPPacket < Packet
|
922
922
|
|
923
|
-
attr_accessor :eth_header, :ip_header, :tcp_header
|
924
|
-
|
923
|
+
attr_accessor :eth_header, :ip_header, :tcp_header
|
924
|
+
|
925
|
+
def self.can_parse?(str)
|
926
|
+
return false unless str.size >= 54
|
927
|
+
return false unless EthPacket.can_parse? str
|
928
|
+
return false unless IPPacket.can_parse? str
|
929
|
+
return false unless str[23,1] == "\x06"
|
930
|
+
return true
|
931
|
+
end
|
932
|
+
|
933
|
+
def read(str=nil, args={})
|
934
|
+
raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
|
935
|
+
@eth_header.read(str)
|
936
|
+
@ip_header.read(str[14,str.size])
|
937
|
+
@eth_header.body = @ip_header
|
938
|
+
if args[:strip]
|
939
|
+
tcp_len = str[16,2].unpack("n")[0] - 20
|
940
|
+
@tcp_header.read(str[14+(@ip_header.ip_hlen),tcp_len])
|
941
|
+
else
|
942
|
+
@tcp_header.read(str[14+(@ip_header.ip_hlen),str.size])
|
943
|
+
end
|
944
|
+
@ip_header.body = @tcp_header
|
945
|
+
super(args)
|
946
|
+
self
|
947
|
+
end
|
948
|
+
|
925
949
|
def initialize(args={})
|
926
950
|
@eth_header = (args[:eth] || EthHeader.new)
|
927
951
|
@ip_header = (args[:ip] || IPHeader.new)
|