packetgen 3.3.2 → 4.0.0
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.
- checksums.yaml +4 -4
- data/README.md +37 -21
- data/lib/packetgen/capture.rb +2 -2
- data/lib/packetgen/config.rb +0 -1
- data/lib/packetgen/deprecation.rb +7 -7
- data/lib/packetgen/header/arp.rb +13 -13
- data/lib/packetgen/header/asn1_base.rb +1 -1
- data/lib/packetgen/header/base.rb +17 -18
- data/lib/packetgen/header/bootp.rb +32 -34
- data/lib/packetgen/header/dhcp/option.rb +19 -19
- data/lib/packetgen/header/dhcp/options.rb +1 -1
- data/lib/packetgen/header/dhcp.rb +3 -3
- data/lib/packetgen/header/dhcpv6/duid.rb +16 -16
- data/lib/packetgen/header/dhcpv6/option.rb +53 -53
- data/lib/packetgen/header/dhcpv6/options.rb +1 -1
- data/lib/packetgen/header/dhcpv6/relay.rb +5 -5
- data/lib/packetgen/header/dhcpv6.rb +6 -6
- data/lib/packetgen/header/dns/name.rb +14 -10
- data/lib/packetgen/header/dns/opt.rb +2 -2
- data/lib/packetgen/header/dns/option.rb +11 -11
- data/lib/packetgen/header/dns/qdsection.rb +1 -1
- data/lib/packetgen/header/dns/question.rb +6 -8
- data/lib/packetgen/header/dns/rr.rb +56 -43
- data/lib/packetgen/header/dns/rrsection.rb +4 -4
- data/lib/packetgen/header/dns.rb +27 -30
- data/lib/packetgen/header/dot11/control.rb +11 -11
- data/lib/packetgen/header/dot11/data.rb +20 -20
- data/lib/packetgen/header/dot11/element.rb +4 -4
- data/lib/packetgen/header/dot11/management.rb +8 -8
- data/lib/packetgen/header/dot11/sub_mngt.rb +39 -53
- data/lib/packetgen/header/dot11.rb +88 -93
- data/lib/packetgen/header/dot1q.rb +10 -12
- data/lib/packetgen/header/dot1x.rb +9 -9
- data/lib/packetgen/header/eap/fast.rb +4 -4
- data/lib/packetgen/header/eap/md5.rb +6 -6
- data/lib/packetgen/header/eap/tls.rb +13 -15
- data/lib/packetgen/header/eap/ttls.rb +13 -15
- data/lib/packetgen/header/eap.rb +22 -22
- data/lib/packetgen/header/eth.rb +18 -18
- data/lib/packetgen/header/gre.rb +8 -10
- data/lib/packetgen/header/http/headers.rb +2 -2
- data/lib/packetgen/header/http/request.rb +17 -16
- data/lib/packetgen/header/http/response.rb +18 -17
- data/lib/packetgen/header/http/verbs.rb +1 -3
- data/lib/packetgen/header/icmp.rb +8 -8
- data/lib/packetgen/header/icmpv6.rb +3 -3
- data/lib/packetgen/header/igmp.rb +8 -8
- data/lib/packetgen/header/igmpv3/group_record.rb +12 -12
- data/lib/packetgen/header/igmpv3/mq.rb +16 -18
- data/lib/packetgen/header/igmpv3/mr.rb +4 -4
- data/lib/packetgen/header/igmpv3.rb +7 -7
- data/lib/packetgen/header/ip/addr.rb +13 -13
- data/lib/packetgen/header/ip/option.rb +31 -33
- data/lib/packetgen/header/ip/options.rb +1 -1
- data/lib/packetgen/header/ip.rb +37 -72
- data/lib/packetgen/header/ipv6/addr.rb +14 -14
- data/lib/packetgen/header/ipv6/extension.rb +8 -8
- data/lib/packetgen/header/ipv6/hop_by_hop.rb +9 -9
- data/lib/packetgen/header/ipv6.rb +20 -22
- data/lib/packetgen/header/llc.rb +17 -17
- data/lib/packetgen/header/mdns.rb +1 -1
- data/lib/packetgen/header/mld.rb +6 -6
- data/lib/packetgen/header/mldv2/mcast_address_record.rb +11 -11
- data/lib/packetgen/header/mldv2/mlq.rb +21 -23
- data/lib/packetgen/header/mldv2/mlr.rb +8 -8
- data/lib/packetgen/header/ospfv2/db_description.rb +11 -12
- data/lib/packetgen/header/ospfv2/hello.rb +11 -11
- data/lib/packetgen/header/ospfv2/ls_ack.rb +1 -1
- data/lib/packetgen/header/ospfv2/ls_request.rb +9 -9
- data/lib/packetgen/header/ospfv2/ls_update.rb +3 -3
- data/lib/packetgen/header/ospfv2/lsa.rb +54 -58
- data/lib/packetgen/header/ospfv2/lsa_header.rb +9 -9
- data/lib/packetgen/header/ospfv2.rb +27 -29
- data/lib/packetgen/header/ospfv3/db_description.rb +13 -14
- data/lib/packetgen/header/ospfv3/hello.rb +12 -12
- data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +17 -19
- data/lib/packetgen/header/ospfv3/ls_ack.rb +2 -2
- data/lib/packetgen/header/ospfv3/ls_request.rb +9 -9
- data/lib/packetgen/header/ospfv3/ls_update.rb +4 -4
- data/lib/packetgen/header/ospfv3/lsa.rb +48 -51
- data/lib/packetgen/header/ospfv3/lsa_header.rb +9 -9
- data/lib/packetgen/header/ospfv3.rb +25 -27
- data/lib/packetgen/header/sctp/chunk.rb +44 -41
- data/lib/packetgen/header/sctp/error.rb +52 -52
- data/lib/packetgen/header/sctp/parameter.rb +38 -38
- data/lib/packetgen/header/sctp.rb +5 -5
- data/lib/packetgen/header/snmp.rb +2 -2
- data/lib/packetgen/header/tcp/option.rb +45 -39
- data/lib/packetgen/header/tcp/options.rb +2 -2
- data/lib/packetgen/header/tcp.rb +55 -44
- data/lib/packetgen/header/tftp.rb +16 -16
- data/lib/packetgen/header/udp.rb +8 -8
- data/lib/packetgen/header.rb +9 -10
- data/lib/packetgen/headerable.rb +13 -3
- data/lib/packetgen/inspect.rb +2 -2
- data/lib/packetgen/packet.rb +54 -37
- data/lib/packetgen/pcap.rb +15 -4
- data/lib/packetgen/pcapng/block.rb +18 -17
- data/lib/packetgen/pcapng/epb.rb +13 -15
- data/lib/packetgen/pcapng/file.rb +3 -97
- data/lib/packetgen/pcapng/idb.rb +9 -11
- data/lib/packetgen/pcapng/shb.rb +13 -15
- data/lib/packetgen/pcapng/spb.rb +8 -10
- data/lib/packetgen/pcapng/unknown_block.rb +6 -17
- data/lib/packetgen/pcapng.rb +4 -4
- data/lib/packetgen/pcaprub_wrapper.rb +17 -1
- data/lib/packetgen/proto.rb +1 -1
- data/lib/packetgen/unknown_packet.rb +2 -2
- data/lib/packetgen/utils/arp_spoofer.rb +18 -19
- data/lib/packetgen/utils.rb +2 -2
- data/lib/packetgen/version.rb +1 -1
- data/lib/packetgen.rb +4 -3
- metadata +34 -29
- data/lib/packetgen/types/abstract_tlv.rb +0 -278
- data/lib/packetgen/types/array.rb +0 -287
- data/lib/packetgen/types/cstring.rb +0 -109
- data/lib/packetgen/types/enum.rb +0 -171
- data/lib/packetgen/types/fieldable.rb +0 -66
- data/lib/packetgen/types/fields.rb +0 -622
- data/lib/packetgen/types/int.rb +0 -473
- data/lib/packetgen/types/int_string.rb +0 -102
- data/lib/packetgen/types/length_from.rb +0 -54
- data/lib/packetgen/types/oui.rb +0 -52
- data/lib/packetgen/types/string.rb +0 -97
- data/lib/packetgen/types/tlv.rb +0 -161
- data/lib/packetgen/types.rb +0 -26
data/lib/packetgen/packet.rb
CHANGED
@@ -61,20 +61,20 @@ module PacketGen
|
|
61
61
|
# @param [Hash] options specific options for +protocol+
|
62
62
|
# @return [Packet]
|
63
63
|
def self.gen(protocol, options={})
|
64
|
-
self.new.add
|
64
|
+
self.new.add(protocol, options)
|
65
65
|
end
|
66
66
|
|
67
67
|
# Parse a binary string and generate a Packet from it.
|
68
68
|
# # auto-detect first header
|
69
|
-
# Packet.parse
|
69
|
+
# Packet.parse(str)
|
70
70
|
# # force decoding a Ethernet header for first header
|
71
|
-
# Packet.parse
|
71
|
+
# Packet.parse(str, first_header: 'Eth')
|
72
72
|
# @param [String] binary_str
|
73
73
|
# @param [String,nil] first_header First protocol header. +nil+ means discover it!
|
74
74
|
# @return [Packet]
|
75
75
|
# @raise [ArgumentError] +first_header+ is an unknown header
|
76
76
|
def self.parse(binary_str, first_header: nil)
|
77
|
-
new.parse
|
77
|
+
new.parse(binary_str, first_header: first_header)
|
78
78
|
end
|
79
79
|
|
80
80
|
# Capture packets from wire.
|
@@ -112,16 +112,23 @@ module PacketGen
|
|
112
112
|
Pcap.read(filename)
|
113
113
|
end
|
114
114
|
|
115
|
-
# Write packets to +filename
|
115
|
+
# Write packets to +filename+, as pcap or PcapNG file
|
116
116
|
#
|
117
117
|
# For more options, see {PcapNG::File}.
|
118
118
|
# @param [String] filename
|
119
119
|
# @param [Array<Packet>] packets packets to write
|
120
120
|
# @return [void]
|
121
|
+
# @since 4.0.0 write a pcap file if filename extension is +.pcap+
|
122
|
+
# @author Sylvain Daubert
|
123
|
+
# @author LemonTree55 (pcap)
|
121
124
|
def self.write(filename, packets)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
+
if filename.end_with?('.pcap')
|
126
|
+
Pcap.write(filename, packets)
|
127
|
+
else
|
128
|
+
pf = PcapNG::File.new
|
129
|
+
pf.read_array(packets)
|
130
|
+
pf.to_f(filename)
|
131
|
+
end
|
125
132
|
end
|
126
133
|
|
127
134
|
# @private
|
@@ -142,7 +149,7 @@ module PacketGen
|
|
142
149
|
# options[:packet]= self is speedier than options.merge(packet: self)
|
143
150
|
options[:packet] = self
|
144
151
|
header = klass.new(options)
|
145
|
-
add_header
|
152
|
+
add_header(header)
|
146
153
|
self
|
147
154
|
end
|
148
155
|
|
@@ -159,7 +166,7 @@ module PacketGen
|
|
159
166
|
# options[:packet]= self is speedier than options.merge(packet: self)
|
160
167
|
options[:packet] = self
|
161
168
|
header = klass.new(options)
|
162
|
-
add_header
|
169
|
+
add_header(header, previous_header: prev)
|
163
170
|
idx = headers.index(prev) + 1
|
164
171
|
headers[idx, 0] = header
|
165
172
|
header[:body] = nxt
|
@@ -173,7 +180,7 @@ module PacketGen
|
|
173
180
|
# @return [Boolean]
|
174
181
|
# @raise [ArgumentError] unknown protocol
|
175
182
|
def is?(protocol)
|
176
|
-
klass = check_protocol
|
183
|
+
klass = check_protocol(protocol)
|
177
184
|
headers.any?(klass)
|
178
185
|
end
|
179
186
|
|
@@ -181,7 +188,7 @@ module PacketGen
|
|
181
188
|
# @return [void]
|
182
189
|
def calc_checksum
|
183
190
|
headers.reverse_each do |header|
|
184
|
-
header.calc_checksum if header.respond_to?
|
191
|
+
header.calc_checksum if header.respond_to?(:calc_checksum)
|
185
192
|
end
|
186
193
|
end
|
187
194
|
|
@@ -189,21 +196,24 @@ module PacketGen
|
|
189
196
|
# @return [void]
|
190
197
|
def calc_length
|
191
198
|
headers.reverse_each do |header|
|
192
|
-
header.calc_length if header.respond_to?
|
199
|
+
header.calc_length if header.respond_to?(:calc_length)
|
193
200
|
end
|
194
201
|
end
|
195
202
|
|
196
203
|
# Recalculate all calculatable fields (for now: length and checksum)
|
197
204
|
# @return [void]
|
205
|
+
# @author LemonTree55
|
198
206
|
def calc
|
199
|
-
|
200
|
-
|
207
|
+
headers.reverse_each do |header|
|
208
|
+
header.calc_length if header.respond_to?(:calc_length)
|
209
|
+
header.calc_checksum if header.respond_to?(:calc_checksum)
|
210
|
+
end
|
201
211
|
end
|
202
212
|
|
203
213
|
# Get packet body
|
204
214
|
# @return [Types]
|
205
215
|
def body
|
206
|
-
last_header[:body] if last_header.respond_to?
|
216
|
+
last_header[:body] if last_header.respond_to?(:body)
|
207
217
|
end
|
208
218
|
|
209
219
|
# Set packet body
|
@@ -229,7 +239,7 @@ module PacketGen
|
|
229
239
|
alias write to_f
|
230
240
|
|
231
241
|
# Send packet on wire. Use first header +#to_w+ method.
|
232
|
-
# @param [String] iface interface name. Default to first non-loopback interface
|
242
|
+
# @param [String,nil] iface interface name. Default to first non-loopback interface
|
233
243
|
# @param [Boolean] calc if +true+, call {#calc} on packet before sending it.
|
234
244
|
# @param [Integer] number number of times to send the packets
|
235
245
|
# @param [Integer,Float] interval time, in seconds, between sending 2 packets
|
@@ -239,12 +249,12 @@ module PacketGen
|
|
239
249
|
def to_w(iface=nil, calc: true, number: 1, interval: 1)
|
240
250
|
iface ||= PacketGen.default_iface
|
241
251
|
|
242
|
-
if first_header.respond_to?
|
252
|
+
if first_header.respond_to?(:to_w)
|
243
253
|
self.calc if calc
|
244
254
|
|
245
255
|
number.times do
|
246
256
|
first_header.to_w(iface)
|
247
|
-
sleep
|
257
|
+
sleep(interval) if number > 1
|
248
258
|
end
|
249
259
|
else
|
250
260
|
type = first_header.protocol_name
|
@@ -257,12 +267,12 @@ module PacketGen
|
|
257
267
|
# @param [Boolean] parsing set to +true+ to not update last current header field
|
258
268
|
# from binding with first other's one. Use only when current header field
|
259
269
|
# has its value set accordingly.
|
260
|
-
# @return [self] +self+ with new headers from +other+
|
270
|
+
# @return [self] +self+ updated with new headers from +other+
|
261
271
|
# @raise [BindingError] do not known how to encapsulate
|
262
272
|
# @since 1.1.0
|
263
273
|
def encapsulate(other, parsing: false)
|
264
274
|
other.headers.each_with_index do |h, i|
|
265
|
-
add_header
|
275
|
+
add_header(h, parsing: i.positive? || parsing)
|
266
276
|
end
|
267
277
|
end
|
268
278
|
|
@@ -286,8 +296,8 @@ module PacketGen
|
|
286
296
|
|
287
297
|
# Parse a binary string and populate Packet from it.
|
288
298
|
# @param [String] binary_str
|
289
|
-
# @param [String,nil] first_header First protocol header. +nil+ means discover it!
|
290
|
-
# @return [
|
299
|
+
# @param [String,nil] first_header First protocol header name. +nil+ means discover it!
|
300
|
+
# @return [self]
|
291
301
|
# @raise [ParseError] +first_header+ is an unknown header
|
292
302
|
# @raise [BindingError] unknwon binding between some headers
|
293
303
|
def parse(binary_str, first_header: nil)
|
@@ -299,7 +309,7 @@ module PacketGen
|
|
299
309
|
raise ParseError, "cannot identify first header in string: #{binary_str.inspect}" if first_header.nil?
|
300
310
|
end
|
301
311
|
|
302
|
-
add
|
312
|
+
add(first_header)
|
303
313
|
headers[-1, 1] = last_header.read(binary_str)
|
304
314
|
|
305
315
|
# Decode upper headers recursively
|
@@ -317,12 +327,14 @@ module PacketGen
|
|
317
327
|
str << Inspect.inspect_body(body)
|
318
328
|
end
|
319
329
|
|
330
|
+
# Check equality at binary level
|
320
331
|
# @param [Packet] other
|
321
332
|
# @return [Boolean]
|
322
333
|
def ==(other)
|
323
334
|
to_s == other.to_s
|
324
335
|
end
|
325
336
|
|
337
|
+
# +true+ is {#==} is +true+ with another packet, or if +other+ is a protocol name String, whose protocol is in Packet.
|
326
338
|
# @param [Packet] other
|
327
339
|
# @return [Boolean]
|
328
340
|
# @since 3.1.2
|
@@ -331,13 +343,13 @@ module PacketGen
|
|
331
343
|
when PacketGen::Packet
|
332
344
|
self == other
|
333
345
|
when String
|
334
|
-
is?
|
346
|
+
is?(other)
|
335
347
|
else
|
336
348
|
false
|
337
349
|
end
|
338
350
|
end
|
339
351
|
|
340
|
-
# Invert all possible
|
352
|
+
# Invert all possible attributes.in packet to create a reply.
|
341
353
|
# @return [self]
|
342
354
|
# @since 2.7.0
|
343
355
|
def reply!
|
@@ -363,7 +375,7 @@ module PacketGen
|
|
363
375
|
def initialize_copy(_other)
|
364
376
|
@headers = headers.map(&:dup)
|
365
377
|
headers.each do |header|
|
366
|
-
add_magic_header_method
|
378
|
+
add_magic_header_method(header)
|
367
379
|
end
|
368
380
|
invalidate_header_cache
|
369
381
|
end
|
@@ -410,17 +422,20 @@ module PacketGen
|
|
410
422
|
end
|
411
423
|
|
412
424
|
# @overload header(klass, layer=1)
|
425
|
+
# Get a header given its class and its layer (example: IP-in-IP encapsulation)
|
413
426
|
# @param [Class] klass
|
414
427
|
# @param [Integer] layer
|
415
428
|
# @overload header(klass, options={})
|
429
|
+
# Get a header given its class, and set some attributes
|
416
430
|
# @param [String] klass
|
417
|
-
# @param [Hash] options
|
418
|
-
# @raise [ArgumentError] unknown
|
419
|
-
# @return [Header::Base]
|
431
|
+
# @param [Hash] options attributes to set
|
432
|
+
# @raise [ArgumentError] unknown attribute
|
433
|
+
# @return [Header::Base,nil]
|
420
434
|
def header(klass, arg)
|
421
435
|
layer = arg.is_a?(Integer) ? arg : 1
|
422
436
|
header = find_header(klass, layer)
|
423
|
-
return
|
437
|
+
return nil if header.nil?
|
438
|
+
return header unless arg.is_a?(Hash)
|
424
439
|
|
425
440
|
arg.each do |key, value|
|
426
441
|
raise ArgumentError, "unknown #{key} attribute for #{klass}" unless header.respond_to?(:"#{key}=")
|
@@ -434,12 +449,14 @@ module PacketGen
|
|
434
449
|
# Get header from cache, or find it in packet
|
435
450
|
# @param [Class] klass
|
436
451
|
# @param [Integer] layer
|
437
|
-
# @return [Header::Base]
|
452
|
+
# @return [Header::Base,nil]
|
438
453
|
def find_header(klass, layer)
|
439
454
|
header = fetch_header_from_cache(klass, layer)
|
440
455
|
return header if header
|
441
456
|
|
442
|
-
header = headers.select { |h| h.is_a?
|
457
|
+
header = headers.select { |h| h.is_a?(klass) }[layer - 1]
|
458
|
+
return nil if header.nil?
|
459
|
+
|
443
460
|
add_header_to_cache(header, klass, layer)
|
444
461
|
header
|
445
462
|
end
|
@@ -468,9 +485,9 @@ module PacketGen
|
|
468
485
|
header.packet = self
|
469
486
|
headers << header unless previous_header
|
470
487
|
|
471
|
-
return if respond_to?
|
488
|
+
return if respond_to?(header.method_name)
|
472
489
|
|
473
|
-
add_magic_header_method
|
490
|
+
add_magic_header_method(header)
|
474
491
|
end
|
475
492
|
|
476
493
|
# Bind +header+ to +prev_header+.
|
@@ -497,7 +514,7 @@ module PacketGen
|
|
497
514
|
|
498
515
|
# Try to guess header from +binary_str+
|
499
516
|
# @param [String] binary_str
|
500
|
-
# @return [String] header/protocol name
|
517
|
+
# @return [String,nil] header/protocol name, or nil if cannot be guessed
|
501
518
|
def guess_first_header(binary_str)
|
502
519
|
first_header = nil
|
503
520
|
Header.all.each do |hklass|
|
@@ -529,7 +546,7 @@ module PacketGen
|
|
529
546
|
nheader = nheader.read(last_known_hdr.body)
|
530
547
|
next unless nheader.parse?
|
531
548
|
|
532
|
-
add_header
|
549
|
+
add_header(nheader, parsing: true)
|
533
550
|
break if last_header == last_known_hdr
|
534
551
|
end
|
535
552
|
end
|
data/lib/packetgen/pcap.rb
CHANGED
@@ -8,8 +8,7 @@
|
|
8
8
|
require_relative 'pcaprub_wrapper'
|
9
9
|
|
10
10
|
module PacketGen
|
11
|
-
# Module to read PCAP files
|
12
|
-
# @author Sylvain Daubert
|
11
|
+
# Module to read/write PCAP files
|
13
12
|
# @api private
|
14
13
|
# @since 3.1.4
|
15
14
|
module Pcap
|
@@ -17,14 +16,26 @@ module PacketGen
|
|
17
16
|
# @param [String] filename
|
18
17
|
# @return [Array<Packet>]
|
19
18
|
# @author Kent Gruber
|
19
|
+
# @author LemonTree55
|
20
20
|
def self.read(filename)
|
21
21
|
packets = []
|
22
|
-
PCAPRUBWrapper.read_pcap(filename: filename) do |
|
23
|
-
|
22
|
+
PCAPRUBWrapper.read_pcap(filename: filename) do |raw_packet|
|
23
|
+
packet = PacketGen.parse(raw_packet.to_s)
|
24
|
+
next if packet.nil?
|
24
25
|
|
25
26
|
packets << packet
|
26
27
|
end
|
27
28
|
packets
|
28
29
|
end
|
30
|
+
|
31
|
+
# Write binary packets to a PCAP file
|
32
|
+
# @param [String] filename
|
33
|
+
# @param [Array<String>] packets
|
34
|
+
# @return [void]
|
35
|
+
# @since 4.0.0
|
36
|
+
# @author LemonTree55
|
37
|
+
def self.write(filename, packets)
|
38
|
+
PCAPRUBWrapper.pcap_write(filename, packets.map(&:to_s))
|
39
|
+
end
|
29
40
|
end
|
30
41
|
end
|
@@ -10,63 +10,64 @@ module PacketGen
|
|
10
10
|
module PcapNG
|
11
11
|
# @abstract Base class for all block types
|
12
12
|
# @author Sylvain Daubert
|
13
|
-
class Block <
|
13
|
+
class Block < BinStruct::Struct
|
14
14
|
# @return [:little, :big]
|
15
15
|
attr_accessor :endian
|
16
16
|
|
17
17
|
# @!attribute type
|
18
18
|
# 32-bit block type
|
19
19
|
# @return [Integer]
|
20
|
-
|
20
|
+
define_attr :type, BinStruct::Int32
|
21
21
|
# @!attribute block_len
|
22
22
|
# 32-bit block length
|
23
23
|
# @return [Integer]
|
24
|
-
|
25
|
-
# @!attribute
|
24
|
+
define_attr :block_len, BinStruct::Int32
|
25
|
+
# @!attribute block_len2
|
26
26
|
# 32-bit block length
|
27
27
|
# @return [Integer]
|
28
|
-
|
28
|
+
define_attr :block_len2, BinStruct::Int32
|
29
29
|
|
30
30
|
def initialize(options={})
|
31
31
|
super
|
32
|
+
endianness(options[:endian] || :little)
|
33
|
+
recalc_block_len
|
32
34
|
end
|
33
35
|
|
34
36
|
# Has this block option?
|
35
37
|
# @return [Boolean]
|
36
38
|
# @since 2.7.0
|
37
39
|
def options?
|
38
|
-
@
|
40
|
+
@attributes.key?(:options) && @attributes[:options].sz.positive?
|
39
41
|
end
|
40
42
|
|
41
|
-
# Calculate block length and update
|
43
|
+
# Calculate block length and update +block_len+ and +block_len2+ fields
|
42
44
|
# @return [void]
|
43
45
|
def recalc_block_len
|
44
|
-
len =
|
46
|
+
len = attributes.map { |f| @attributes[f].to_s }.join.size
|
45
47
|
self.block_len = self.block_len2 = len
|
46
48
|
end
|
47
49
|
|
48
50
|
# Pad given field to 32 bit boundary, if needed
|
49
|
-
# @param [Array<Symbol>] fields
|
51
|
+
# @param [Array<Symbol>] fields fields to pad
|
50
52
|
# @return [void]
|
53
|
+
# @author LemonTree55
|
51
54
|
def pad_field(*fields)
|
52
55
|
fields.each do |field|
|
53
|
-
obj = @
|
54
|
-
|
55
|
-
obj << "\x00" * pad_size
|
56
|
+
obj = @attributes[field]
|
57
|
+
obj << "\x00" * -(obj.sz % -4)
|
56
58
|
end
|
57
59
|
end
|
58
60
|
|
59
61
|
private
|
60
62
|
|
61
63
|
# Set the endianness for the various Int classes handled by self.
|
62
|
-
# Must be called by all subclass #initialize method.
|
63
64
|
# @param [:little, :big] endian
|
64
65
|
# @return [:little, :big] returns endian
|
65
66
|
def endianness(endian)
|
66
67
|
raise ArgumentError, "unknown endianness for #{self.class}" unless %i[little big].include?(endian)
|
67
68
|
|
68
69
|
@endian = endian
|
69
|
-
@
|
70
|
+
@attributes.each_value { |v| v.endian = endian if v.is_a?(BinStruct::Int) }
|
70
71
|
endian
|
71
72
|
end
|
72
73
|
|
@@ -75,19 +76,19 @@ module PacketGen
|
|
75
76
|
end
|
76
77
|
|
77
78
|
def to_io(str_or_io)
|
78
|
-
return str_or_io if str_or_io.respond_to?
|
79
|
+
return str_or_io if str_or_io.respond_to?(:read)
|
79
80
|
|
80
81
|
StringIO.new(force_binary(str_or_io.to_s))
|
81
82
|
end
|
82
83
|
|
83
84
|
def remove_padding(io, data_len)
|
84
85
|
data_pad_len = (4 - (data_len % 4)) % 4
|
85
|
-
io.read
|
86
|
+
io.read(data_pad_len)
|
86
87
|
data_pad_len
|
87
88
|
end
|
88
89
|
|
89
90
|
def read_blocklen2_and_check(io)
|
90
|
-
self[:block_len2].read
|
91
|
+
self[:block_len2].read(io.read(4))
|
91
92
|
check_len_coherency
|
92
93
|
end
|
93
94
|
end
|
data/lib/packetgen/pcapng/epb.rb
CHANGED
@@ -34,29 +34,29 @@ module PacketGen
|
|
34
34
|
# @!attribute interface_id
|
35
35
|
# 32-bit interface ID
|
36
36
|
# @return [Integer]
|
37
|
-
|
37
|
+
define_attr_before :block_len2, :interface_id, BinStruct::Int32, default: 0
|
38
38
|
# @!attribute tsh
|
39
39
|
# high 32-bit timestamp value
|
40
40
|
# @return [Integer]
|
41
|
-
|
41
|
+
define_attr_before :block_len2, :tsh, BinStruct::Int32, default: 0
|
42
42
|
# @!attribute tsl
|
43
43
|
# low 32-bit imestamp value
|
44
44
|
# @return [Integer]
|
45
|
-
|
45
|
+
define_attr_before :block_len2, :tsl, BinStruct::Int32, default: 0
|
46
46
|
# @!attribute cap_len
|
47
47
|
# 32-bit capture length
|
48
48
|
# @return [Integer]
|
49
|
-
|
49
|
+
define_attr_before :block_len2, :cap_len, BinStruct::Int32, default: 0
|
50
50
|
# @!attribute orig_len
|
51
51
|
# 32-bit original length
|
52
52
|
# @return [Integer]
|
53
|
-
|
53
|
+
define_attr_before :block_len2, :orig_len, BinStruct::Int32, default: 0
|
54
54
|
# @!attribute data
|
55
|
-
# @return [
|
56
|
-
|
55
|
+
# @return [BinStruct::String]
|
56
|
+
define_attr_before :block_len2, :data, BinStruct::String
|
57
57
|
# @!attribute options
|
58
|
-
# @return [
|
59
|
-
|
58
|
+
# @return [BinStruct::String]
|
59
|
+
define_attr_before :block_len2, :options, BinStruct::String
|
60
60
|
|
61
61
|
# @param [Hash] options
|
62
62
|
# @option options [:little, :big] :endian set block endianness
|
@@ -74,8 +74,6 @@ module PacketGen
|
|
74
74
|
# @option options [Integer] :block_len2 block total length
|
75
75
|
def initialize(options={})
|
76
76
|
super
|
77
|
-
endianness(options[:endian] || :little)
|
78
|
-
recalc_block_len
|
79
77
|
self.type = options[:type] || PcapNG::EPB_TYPE.to_i
|
80
78
|
end
|
81
79
|
|
@@ -87,9 +85,9 @@ module PacketGen
|
|
87
85
|
return self if io.eof?
|
88
86
|
|
89
87
|
%i[type block_len interface_id tsh tsl cap_len orig_len].each do |attr|
|
90
|
-
self[attr].read
|
88
|
+
self[attr].read(io.read(self[attr].sz))
|
91
89
|
end
|
92
|
-
self[:data].read
|
90
|
+
self[:data].read(io.read(self.cap_len))
|
93
91
|
read_options(io)
|
94
92
|
read_blocklen2_and_check(io)
|
95
93
|
|
@@ -115,7 +113,7 @@ module PacketGen
|
|
115
113
|
# Return the object as a String
|
116
114
|
# @return [String]
|
117
115
|
def to_s
|
118
|
-
pad_field
|
116
|
+
pad_field(:data, :options)
|
119
117
|
recalc_block_len
|
120
118
|
super
|
121
119
|
end
|
@@ -133,7 +131,7 @@ module PacketGen
|
|
133
131
|
def read_options(io)
|
134
132
|
data_pad_len = remove_padding(io, self.cap_len)
|
135
133
|
options_len = self.block_len - self.cap_len - data_pad_len - MIN_SIZE
|
136
|
-
self[:options].read
|
134
|
+
self[:options].read(io.read(options_len))
|
137
135
|
end
|
138
136
|
end
|
139
137
|
end
|
@@ -140,35 +140,6 @@ module PacketGen
|
|
140
140
|
@sections.clear
|
141
141
|
end
|
142
142
|
|
143
|
-
# @deprecated
|
144
|
-
# Prefer use of {#to_a} or {#to_h}.
|
145
|
-
# Translates a {File} into an array of packets.
|
146
|
-
# @param [Hash] options
|
147
|
-
# @option options [String] :file if given, object is cleared and filename
|
148
|
-
# is analyzed before generating array. Else, array is generated from +self+
|
149
|
-
# @option options [Boolean] :keep_timestamps if +true+ (default value: +false+),
|
150
|
-
# generates an array of hashes, each one with timestamp as key and packet
|
151
|
-
# as value. There is one hash per packet.
|
152
|
-
# @return [Array<Packet>,Array<Hash>]
|
153
|
-
def file_to_array(options={})
|
154
|
-
Deprecation.deprecated(self.class, __method__)
|
155
|
-
|
156
|
-
file = options[:file] || options[:filename]
|
157
|
-
reread file
|
158
|
-
|
159
|
-
ary = []
|
160
|
-
blk = if options[:keep_timestamps] || options[:keep_ts]
|
161
|
-
proc { |pkt| { pkt.timestamp => pkt.data.to_s } }
|
162
|
-
else
|
163
|
-
proc { |pkt| pkt.data.to_s }
|
164
|
-
end
|
165
|
-
each_packet_with_interface do |pkt, _itf|
|
166
|
-
ary << blk.call(pkt)
|
167
|
-
end
|
168
|
-
|
169
|
-
ary
|
170
|
-
end
|
171
|
-
|
172
143
|
# Translates a {File} into an array of packets.
|
173
144
|
# @return [Array<Packet>]
|
174
145
|
# @since 3.1.6
|
@@ -223,41 +194,6 @@ module PacketGen
|
|
223
194
|
self.to_file(filename.to_s, append: true)
|
224
195
|
end
|
225
196
|
|
226
|
-
# @deprecated Prefer use of {#read_array} or {#read_hash}.
|
227
|
-
# @overload array_to_file(ary)
|
228
|
-
# Update {File} object with packets.
|
229
|
-
# @param [Array] ary as generated by {#file_to_array} or Array of Packet objects.
|
230
|
-
# Update {File} object without writing file on disk
|
231
|
-
# @return [self]
|
232
|
-
# @overload array_to_file(options={})
|
233
|
-
# Update {File} and/or write it to a file
|
234
|
-
# @param [Hash] options
|
235
|
-
# @option options [String] :file file written on disk only if given
|
236
|
-
# @option options [Array] :array can either be an array of packet data,
|
237
|
-
# or a hash-value pair of timestamp => data.
|
238
|
-
# @option options [Time] :timestamp set an initial timestamp
|
239
|
-
# @option options [Integer] :ts_inc set the increment between timestamps.
|
240
|
-
# Defaults to 1
|
241
|
-
# @option options [Boolean] :append if +true+, append packets to the end of
|
242
|
-
# the file
|
243
|
-
# @return [Array] see return value from {#to_file}
|
244
|
-
def array_to_file(options={})
|
245
|
-
filename, ary, ts, ts_inc, append = array_to_file_options(options)
|
246
|
-
|
247
|
-
section = create_new_shb_section
|
248
|
-
|
249
|
-
ary.each do |pkt|
|
250
|
-
classify_block(section, epb_from_pkt(pkt, section, ts))
|
251
|
-
ts += ts_inc
|
252
|
-
end
|
253
|
-
|
254
|
-
if filename
|
255
|
-
self.to_f(filename, append: append)
|
256
|
-
else
|
257
|
-
self
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
197
|
# Update current object from an array of packets
|
262
198
|
# @param [Array<Packet>] packets
|
263
199
|
# @param [Time, nil] timestamp initial timestamp, used for first packet
|
@@ -335,13 +271,13 @@ module PacketGen
|
|
335
271
|
# @param [IO] io stream from which parse SHB
|
336
272
|
# @return [SHB]
|
337
273
|
def parse_shb(shb, io)
|
338
|
-
type =
|
274
|
+
type = BinStruct::Int32.new(value: 0, endian: shb.endian).read(io.read(4))
|
339
275
|
io.seek(-4, IO::SEEK_CUR)
|
340
276
|
parse(type, io, shb)
|
341
277
|
end
|
342
278
|
|
343
279
|
# Parse a block from its type
|
344
|
-
# @param [
|
280
|
+
# @param [BinStruct::Int32] type
|
345
281
|
# @param [IO] io stream from which parse block
|
346
282
|
# @param [SHB] shb header of current section
|
347
283
|
# @return [Block]
|
@@ -352,7 +288,7 @@ module PacketGen
|
|
352
288
|
end
|
353
289
|
|
354
290
|
# Guess class to use from type
|
355
|
-
# @param [
|
291
|
+
# @param [BinStruct::Int] type
|
356
292
|
# @return [Block]
|
357
293
|
def guess_block_type(type)
|
358
294
|
BLOCK_TYPES.key?(type.to_i) ? BLOCK_TYPES[type.to_i] : UnknownBlock
|
@@ -376,36 +312,6 @@ module PacketGen
|
|
376
312
|
end
|
377
313
|
end
|
378
314
|
|
379
|
-
def array_to_file_options(options)
|
380
|
-
case options
|
381
|
-
when Hash
|
382
|
-
array_to_file_options_from_hash(options)
|
383
|
-
when Array
|
384
|
-
[nil, options, Time.now, 1, false]
|
385
|
-
else
|
386
|
-
raise ArgumentError, 'unknown argument. Need either a Hash or Array'
|
387
|
-
end
|
388
|
-
end
|
389
|
-
|
390
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
391
|
-
# Extract and check options for #array_to_file
|
392
|
-
def array_to_file_options_from_hash(options)
|
393
|
-
%i[filename arr ts].each do |deprecated_opt|
|
394
|
-
Deprecation.deprecated_option(self.class, :array_to_file, deprecated_opt) if options[deprecated_opt]
|
395
|
-
end
|
396
|
-
|
397
|
-
filename = options[:filename] || options[:file]
|
398
|
-
ary = options[:array] || options[:arr]
|
399
|
-
raise ArgumentError, ':array parameter needs to be an array' unless ary.is_a? Array
|
400
|
-
|
401
|
-
ts = options[:timestamp] || options[:ts] || Time.now
|
402
|
-
ts_inc = options[:ts_inc] || 1
|
403
|
-
append = !options[:append].nil?
|
404
|
-
|
405
|
-
[filename, ary, ts, ts_inc, append]
|
406
|
-
end
|
407
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
408
|
-
|
409
315
|
def create_new_shb_section
|
410
316
|
section = SHB.new
|
411
317
|
@sections << section
|