packetgen 1.2.0 → 1.3.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 +2 -2
- data/lib/packetgen/header/arp.rb +54 -125
- data/lib/packetgen/header/base.rb +175 -0
- data/lib/packetgen/header/dns/name.rb +110 -0
- data/lib/packetgen/header/dns/opt.rb +137 -0
- data/lib/packetgen/header/dns/option.rb +17 -0
- data/lib/packetgen/header/dns/qdsection.rb +39 -0
- data/lib/packetgen/header/dns/question.rb +129 -0
- data/lib/packetgen/header/dns/rr.rb +89 -0
- data/lib/packetgen/header/dns/rrsection.rb +72 -0
- data/lib/packetgen/header/dns.rb +276 -0
- data/lib/packetgen/header/esp.rb +38 -70
- data/lib/packetgen/header/eth.rb +35 -106
- data/lib/packetgen/header/icmp.rb +19 -70
- data/lib/packetgen/header/icmpv6.rb +3 -3
- data/lib/packetgen/header/ip.rb +54 -210
- data/lib/packetgen/header/ipv6.rb +73 -164
- data/lib/packetgen/header/tcp/option.rb +34 -50
- data/lib/packetgen/header/tcp/options.rb +19 -20
- data/lib/packetgen/header/tcp.rb +66 -129
- data/lib/packetgen/header/udp.rb +31 -88
- data/lib/packetgen/header.rb +5 -10
- data/lib/packetgen/inspect.rb +5 -4
- data/lib/packetgen/packet.rb +74 -57
- data/lib/packetgen/pcapng/block.rb +49 -7
- data/lib/packetgen/pcapng/epb.rb +36 -34
- data/lib/packetgen/pcapng/file.rb +24 -8
- data/lib/packetgen/pcapng/idb.rb +28 -33
- data/lib/packetgen/pcapng/shb.rb +35 -39
- data/lib/packetgen/pcapng/spb.rb +18 -27
- data/lib/packetgen/pcapng/unknown_block.rb +11 -21
- data/lib/packetgen/pcapng.rb +9 -7
- data/lib/packetgen/types/array.rb +56 -0
- data/lib/packetgen/types/fields.rb +325 -0
- data/lib/packetgen/types/int.rb +164 -0
- data/lib/packetgen/types/int_string.rb +69 -0
- data/lib/packetgen/types/string.rb +36 -0
- data/lib/packetgen/types/tlv.rb +41 -0
- data/lib/packetgen/types.rb +13 -0
- data/lib/packetgen/version.rb +1 -1
- data/lib/packetgen.rb +1 -1
- metadata +19 -6
- data/lib/packetgen/header/header_class_methods.rb +0 -106
- data/lib/packetgen/header/header_methods.rb +0 -73
- data/lib/packetgen/structfu.rb +0 -363
data/lib/packetgen/inspect.rb
CHANGED
@@ -9,7 +9,7 @@ module PacketGen
|
|
9
9
|
INSPECT_MAX_WIDTH = 70
|
10
10
|
|
11
11
|
# Format to inspect attribute
|
12
|
-
INSPECT_FMT_ATTR = "%
|
12
|
+
INSPECT_FMT_ATTR = "%10s %12s: %s\n"
|
13
13
|
|
14
14
|
# Create a dashed line with +obj+ class writing in it
|
15
15
|
# @param [String] name
|
@@ -26,7 +26,7 @@ module PacketGen
|
|
26
26
|
end
|
27
27
|
|
28
28
|
# @param [#to_i] value
|
29
|
-
# @param [Integer]
|
29
|
+
# @param [Integer] hexsize
|
30
30
|
# @return [String]
|
31
31
|
def self.int_dec_hex(value, hexsize)
|
32
32
|
"%-10s (0x%0#{hexsize}x)" % [value.to_i, value.to_i]
|
@@ -34,7 +34,7 @@ module PacketGen
|
|
34
34
|
|
35
35
|
# Format an attribute for +#inspect+.
|
36
36
|
# 3 cases are handled:
|
37
|
-
# * attribute value is a {
|
37
|
+
# * attribute value is a {Types::Int}: show value as integer and in
|
38
38
|
# hexdecimal format,
|
39
39
|
# * attribute value responds to +#to_human+: call it,
|
40
40
|
# * else, +#to_s+ is used to format attribute value.
|
@@ -44,7 +44,7 @@ module PacketGen
|
|
44
44
|
# @return [String]
|
45
45
|
def self.inspect_attribute(attr, value, level=1)
|
46
46
|
str = shift_level(level)
|
47
|
-
val = if value.is_a?
|
47
|
+
val = if value.is_a? Types::Int
|
48
48
|
int_dec_hex(value, value.to_s.size * 2)
|
49
49
|
elsif value.respond_to? :to_human
|
50
50
|
value.to_human
|
@@ -57,6 +57,7 @@ module PacketGen
|
|
57
57
|
# @param [#to_s] body
|
58
58
|
# @return [String]
|
59
59
|
def self.inspect_body(body)
|
60
|
+
return '' if body.nil?
|
60
61
|
str = dashed_line('Body', 2)
|
61
62
|
str << (0..15).to_a.map { |v| " %02d" % v}.join << "\n"
|
62
63
|
str << '-' * INSPECT_MAX_WIDTH << "\n"
|
data/lib/packetgen/packet.rb
CHANGED
@@ -65,54 +65,7 @@ module PacketGen
|
|
65
65
|
# @return [Packet]
|
66
66
|
# @raise [ArgumentError] +first_header+ is an unknown header
|
67
67
|
def self.parse(binary_str, first_header: nil)
|
68
|
-
|
69
|
-
|
70
|
-
if first_header.nil?
|
71
|
-
# No decoding forced for first header. Have to guess it!
|
72
|
-
Header.all.each do |hklass|
|
73
|
-
hdr = hklass.new
|
74
|
-
hdr.read binary_str
|
75
|
-
# First header is found when:
|
76
|
-
# * for one known header,
|
77
|
-
# * it exists a known binding with a upper header
|
78
|
-
hklass.known_headers.each do |nh, bindings|
|
79
|
-
bindings.each do |binding|
|
80
|
-
if hdr.send(binding.key) == binding.value
|
81
|
-
first_header = hklass.to_s.gsub(/.*::/, '')
|
82
|
-
break
|
83
|
-
end
|
84
|
-
break unless first_header.nil?
|
85
|
-
end
|
86
|
-
end
|
87
|
-
break unless first_header.nil?
|
88
|
-
end
|
89
|
-
if first_header.nil?
|
90
|
-
raise ParseError, 'cannot identify first header in string'
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
pkt.add(first_header)
|
95
|
-
pkt.headers.last.read binary_str
|
96
|
-
|
97
|
-
# Decode upper headers recursively
|
98
|
-
decode_packet_bottom_up = true
|
99
|
-
while decode_packet_bottom_up do
|
100
|
-
last_known_hdr = pkt.headers.last
|
101
|
-
last_known_hdr.class.known_headers.each do |nh, bindings|
|
102
|
-
bindings.each do |binding|
|
103
|
-
if last_known_hdr.send(binding.key) == binding.value
|
104
|
-
str = last_known_hdr.body
|
105
|
-
pkt.add nh.to_s.gsub(/.*::/, '')
|
106
|
-
pkt.headers.last.read str
|
107
|
-
break
|
108
|
-
end
|
109
|
-
end
|
110
|
-
break unless last_known_hdr == pkt.headers.last
|
111
|
-
end
|
112
|
-
decode_packet_bottom_up = (pkt.headers.last != last_known_hdr)
|
113
|
-
end
|
114
|
-
|
115
|
-
pkt
|
68
|
+
new.parse binary_str, first_header: first_header
|
116
69
|
end
|
117
70
|
|
118
71
|
# Capture packets from +iface+
|
@@ -206,9 +159,9 @@ module PacketGen
|
|
206
159
|
end
|
207
160
|
|
208
161
|
# Get packet body
|
209
|
-
# @return [
|
162
|
+
# @return [Types]
|
210
163
|
def body
|
211
|
-
@headers.last.body
|
164
|
+
@headers.last.body if @headers.last.respond_to? :body
|
212
165
|
end
|
213
166
|
|
214
167
|
# Set packet body
|
@@ -268,12 +221,37 @@ module PacketGen
|
|
268
221
|
prev_header = idx > 0 ? @headers[idx - 1] : nil
|
269
222
|
next_header = (idx+1) < @headers.size ? @headers[idx + 1] : nil
|
270
223
|
@headers.delete_at(idx)
|
271
|
-
|
224
|
+
if prev_header and next_header
|
225
|
+
add_header(next_header, previous_header: prev_header)
|
226
|
+
end
|
272
227
|
end
|
273
228
|
rescue ArgumentError => ex
|
274
229
|
raise FormatError, ex.message
|
275
230
|
end
|
276
231
|
|
232
|
+
# Parse a binary string and populate Packet from it.
|
233
|
+
# @param [String] binary_str
|
234
|
+
# @param [String,nil] first_header First protocol header. +nil+ means discover it!
|
235
|
+
# @return [Packet] self
|
236
|
+
# @raise [ArgumentError] +first_header+ is an unknown header
|
237
|
+
def parse(binary_str, first_header: nil)
|
238
|
+
@headers.clear
|
239
|
+
|
240
|
+
if first_header.nil?
|
241
|
+
# No decoding forced for first header. Have to guess it!
|
242
|
+
first_header = guess_first_header(binary_str)
|
243
|
+
if first_header.nil?
|
244
|
+
raise ParseError, 'cannot identify first header in string'
|
245
|
+
end
|
246
|
+
end
|
247
|
+
add first_header
|
248
|
+
@headers[-1, 1] = @headers.last.read(binary_str)
|
249
|
+
|
250
|
+
# Decode upper headers recursively
|
251
|
+
decode_bottom_up
|
252
|
+
self
|
253
|
+
end
|
254
|
+
|
277
255
|
# @return [String]
|
278
256
|
def inspect
|
279
257
|
str = Inspect.dashed_line(self.class)
|
@@ -332,23 +310,23 @@ module PacketGen
|
|
332
310
|
end
|
333
311
|
|
334
312
|
# Add a header to packet
|
335
|
-
# @param [Header::
|
336
|
-
# @param [Header::
|
313
|
+
# @param [Header::Base] header
|
314
|
+
# @param [Header::Base] previous_header
|
337
315
|
# @return [void]
|
338
|
-
def add_header(header, previous_header
|
316
|
+
def add_header(header, previous_header: nil, parsing: false)
|
339
317
|
protocol = header.protocol_name
|
340
318
|
prev_header = previous_header || @headers.last
|
341
319
|
if prev_header
|
342
320
|
bindings = prev_header.class.known_headers[header.class]
|
343
|
-
if bindings.nil?
|
321
|
+
if bindings.nil?
|
344
322
|
msg = "#{prev_header.class} knowns no layer association with #{protocol}. "
|
345
323
|
msg << "Try #{prev_header.class}.bind_layer(PacketGen::Header::#{protocol}, "
|
346
324
|
msg << "#{prev_header.protocol_name.downcase}_proto_field: "
|
347
325
|
msg << "value_for_#{protocol.downcase})"
|
348
326
|
raise ArgumentError, msg
|
349
327
|
end
|
350
|
-
|
351
|
-
prev_header
|
328
|
+
bindings.set(prev_header) if !bindings.empty? and !parsing
|
329
|
+
prev_header[:body] = header
|
352
330
|
end
|
353
331
|
header.packet = self
|
354
332
|
@headers << header unless previous_header
|
@@ -357,6 +335,45 @@ module PacketGen
|
|
357
335
|
"header(#{header.class}, arg); end"
|
358
336
|
end
|
359
337
|
end
|
338
|
+
|
339
|
+
def guess_first_header(binary_str)
|
340
|
+
first_header = nil
|
341
|
+
Header.all.each do |hklass|
|
342
|
+
hdr = hklass.new
|
343
|
+
# #read may return another object (more specific class)
|
344
|
+
hdr = hdr.read(binary_str)
|
345
|
+
# First header is found when:
|
346
|
+
# * for one known header,
|
347
|
+
# * it exists a known binding with a upper header
|
348
|
+
search_header(hdr) do
|
349
|
+
first_header = hklass.to_s.gsub(/.*::/, '')
|
350
|
+
end
|
351
|
+
break unless first_header.nil?
|
352
|
+
end
|
353
|
+
first_header
|
354
|
+
end
|
355
|
+
|
356
|
+
def decode_bottom_up
|
357
|
+
decode_packet_bottom_up = true
|
358
|
+
while decode_packet_bottom_up do
|
359
|
+
last_known_hdr = @headers.last
|
360
|
+
search_header(last_known_hdr) do |nh|
|
361
|
+
str = last_known_hdr.body
|
362
|
+
add_header nh.new, parsing: true
|
363
|
+
@headers[-1, 1] = @headers.last.read(str)
|
364
|
+
end
|
365
|
+
decode_packet_bottom_up = (@headers.last != last_known_hdr)
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
def search_header(hdr)
|
370
|
+
hdr.class.known_headers.each do |nh, bindings|
|
371
|
+
if bindings.check?(hdr)
|
372
|
+
yield nh
|
373
|
+
break
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
360
377
|
end
|
361
378
|
end
|
362
379
|
|
@@ -6,20 +6,41 @@
|
|
6
6
|
module PacketGen
|
7
7
|
module PcapNG
|
8
8
|
|
9
|
-
#
|
10
|
-
|
9
|
+
# @abstract Base class for all block types
|
10
|
+
# @author Sylvain Daubert
|
11
|
+
class Block < Types::Fields
|
12
|
+
|
13
|
+
# @return [:little, :big]
|
14
|
+
attr_accessor :endian
|
15
|
+
|
16
|
+
# @!attribute type
|
17
|
+
# 32-bit block type
|
18
|
+
# @return [Integer]
|
19
|
+
define_field :type, Types::Int32
|
20
|
+
# @!attribute block_len
|
21
|
+
# 32-bit block length
|
22
|
+
# @return [Integer]
|
23
|
+
define_field :block_len, Types::Int32
|
24
|
+
# @!attribute block_len
|
25
|
+
# 32-bit block length
|
26
|
+
# @return [Integer]
|
27
|
+
define_field :block_len2, Types::Int32
|
28
|
+
|
29
|
+
def initialize(options={})
|
30
|
+
super
|
31
|
+
end
|
11
32
|
|
12
33
|
# Has this block option?
|
13
34
|
# @return [Boolean]
|
14
35
|
def has_options?
|
15
|
-
|
36
|
+
@fields.has_key?(:options) && @fields[:options].sz > 0
|
16
37
|
end
|
17
38
|
|
18
39
|
# Calculate block length and update :block_len and block_len2 fields
|
19
40
|
# @return [void]
|
20
41
|
def recalc_block_len
|
21
|
-
len =
|
22
|
-
self
|
42
|
+
len = fields.map { |f| @fields[f].to_s }.join.size
|
43
|
+
self.block_len = self.block_len2 = len
|
23
44
|
end
|
24
45
|
|
25
46
|
# Pad given field to 32 bit boundary, if needed
|
@@ -27,11 +48,32 @@ module PacketGen
|
|
27
48
|
# @return [void]
|
28
49
|
def pad_field(*fields)
|
29
50
|
fields.each do |field|
|
30
|
-
unless
|
31
|
-
|
51
|
+
unless @fields[field].size % 4 == 0
|
52
|
+
@fields[field] << "\x00" * (4 - (@fields[field].size % 4))
|
32
53
|
end
|
33
54
|
end
|
34
55
|
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Set the endianness for the various Int classes handled by self.
|
60
|
+
# Must be called by all subclass #initialize method.
|
61
|
+
# @param [:little, :big] e
|
62
|
+
# @return [:little, :big] returns e
|
63
|
+
def set_endianness(e)
|
64
|
+
unless [:little, :big].include? e
|
65
|
+
raise ArgumentError, "unknown endianness for #{self.class}"
|
66
|
+
end
|
67
|
+
@endian = e
|
68
|
+
@fields.each { |f_, v| v.endian = e if v.is_a?(Types::Int) }
|
69
|
+
e
|
70
|
+
end
|
71
|
+
|
72
|
+
def check_len_coherency
|
73
|
+
unless self[:block_len].to_i == self[:block_len2].to_i
|
74
|
+
raise InvalidFileError, 'Incoherency in Block length'
|
75
|
+
end
|
76
|
+
end
|
35
77
|
end
|
36
78
|
end
|
37
79
|
end
|
data/lib/packetgen/pcapng/epb.rb
CHANGED
@@ -19,18 +19,42 @@ module PacketGen
|
|
19
19
|
# String :data
|
20
20
|
# String :options
|
21
21
|
# Int32 :block_len2
|
22
|
-
class EPB <
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
class EPB < Block
|
23
|
+
|
24
|
+
# Minimum EPB size
|
25
|
+
MIN_SIZE = 8*4
|
26
26
|
|
27
27
|
# @return [:little, :big]
|
28
28
|
attr_accessor :endian
|
29
29
|
# @return [IPB]
|
30
30
|
attr_accessor :interface
|
31
31
|
|
32
|
-
#
|
33
|
-
|
32
|
+
# @!attribute interface_id
|
33
|
+
# 32-bit interface ID
|
34
|
+
# @return [Integer]
|
35
|
+
define_field_before :block_len2, :interface_id, Types::Int32, default: 0
|
36
|
+
# @!attribute tsh
|
37
|
+
# high 32-bit timestamp value
|
38
|
+
# @return [Integer]
|
39
|
+
define_field_before :block_len2, :tsh, Types::Int32, default: 0
|
40
|
+
# @!attribute tsl
|
41
|
+
# low 32-bit imestamp value
|
42
|
+
# @return [Integer]
|
43
|
+
define_field_before :block_len2, :tsl, Types::Int32, default: 0
|
44
|
+
# @!attribute cap_len
|
45
|
+
# 32-bit capture length
|
46
|
+
# @return [Integer]
|
47
|
+
define_field_before :block_len2, :cap_len, Types::Int32, default: 0
|
48
|
+
# @!attribute orig_len
|
49
|
+
# 32-bit original length
|
50
|
+
# @return [Integer]
|
51
|
+
define_field_before :block_len2, :orig_len, Types::Int32, default: 0
|
52
|
+
# @!attribute data
|
53
|
+
# @return [Types::String]
|
54
|
+
define_field_before :block_len2, :data, Types::String
|
55
|
+
# @!attribute options
|
56
|
+
# @return [Types::String]
|
57
|
+
define_field_before :block_len2, :options, Types::String
|
34
58
|
|
35
59
|
# @param [Hash] options
|
36
60
|
# @option options [:little, :big] :endian set block endianness
|
@@ -47,29 +71,10 @@ module PacketGen
|
|
47
71
|
# @option options [::String] :options
|
48
72
|
# @option options [Integer] :block_len2 block total length
|
49
73
|
def initialize(options={})
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
options[:options], options[:block_len2])
|
55
|
-
end
|
56
|
-
|
57
|
-
# Used by {#initialize} to set the initial fields
|
58
|
-
# @param [Hash] options
|
59
|
-
# @see #initialize possible options
|
60
|
-
# @return [Hash] return +options+
|
61
|
-
def init_fields(options={})
|
62
|
-
options[:type] = @int32.new(options[:type] || PcapNG::EPB_TYPE.to_i)
|
63
|
-
options[:block_len] = @int32.new(options[:block_len] || MIN_SIZE)
|
64
|
-
options[:interface_id] = @int32.new(options[:interface_id] || 0)
|
65
|
-
options[:tsh] = @int32.new(options[:tsh] || 0)
|
66
|
-
options[:tsl] = @int32.new(options[:tsl] || 0)
|
67
|
-
options[:cap_len] = @int32.new(options[:cap_len] || 0)
|
68
|
-
options[:orig_len] = @int32.new(options[:orig_len] || 0)
|
69
|
-
options[:data] = StructFu::String.new(options[:data] || '')
|
70
|
-
options[:options] = StructFu::String.new(options[:options] || '')
|
71
|
-
options[:block_len2] = @int32.new(options[:block_len2] || MIN_SIZE)
|
72
|
-
options
|
74
|
+
super
|
75
|
+
set_endianness(options[:endian] || :little)
|
76
|
+
recalc_block_len
|
77
|
+
self.type = options[:type] || PcapNG::EPB_TYPE.to_i
|
73
78
|
end
|
74
79
|
|
75
80
|
# Reads a String or a IO to populate the object
|
@@ -98,10 +103,7 @@ module PacketGen
|
|
98
103
|
self[:options].read io.read(options_len)
|
99
104
|
self[:block_len2].read io.read(4)
|
100
105
|
|
101
|
-
|
102
|
-
raise InvalidFileError, 'Incoherency in Extended Packet Block'
|
103
|
-
end
|
104
|
-
|
106
|
+
check_len_coherency
|
105
107
|
self
|
106
108
|
end
|
107
109
|
|
@@ -116,7 +118,7 @@ module PacketGen
|
|
116
118
|
def to_s
|
117
119
|
pad_field :data, :options
|
118
120
|
recalc_block_len
|
119
|
-
|
121
|
+
fields.map { |f| @fields[f].to_s }.join
|
120
122
|
end
|
121
123
|
|
122
124
|
|
@@ -8,6 +8,14 @@ module PacketGen
|
|
8
8
|
|
9
9
|
# PcapNG::File is a complete Pcap-NG file handler.
|
10
10
|
class File
|
11
|
+
|
12
|
+
# Known link types
|
13
|
+
KNOWN_LINK_TYPES = {
|
14
|
+
LINKTYPE_ETHERNET => 'Eth',
|
15
|
+
LINKTYPE_IPV4 => 'IP',
|
16
|
+
LINKTYPE_IPV6 => 'IPv6'
|
17
|
+
}
|
18
|
+
|
11
19
|
# Get file sections
|
12
20
|
# @return [Array]
|
13
21
|
attr_accessor :sections
|
@@ -74,6 +82,7 @@ module PacketGen
|
|
74
82
|
# @overload read_packet_bytes(fname)
|
75
83
|
# @param [String] fname pcapng file name
|
76
84
|
# @yieldparam [String] raw packet raw data
|
85
|
+
# @yieldparam [Integer] interface's link_type from which packet was captured
|
77
86
|
# @return [Integer] number of packets
|
78
87
|
# @raise [ArgumentError] cannot read +fname+
|
79
88
|
def read_packet_bytes(fname, &blk)
|
@@ -83,7 +92,7 @@ module PacketGen
|
|
83
92
|
readfile(fname) do |packet|
|
84
93
|
if blk
|
85
94
|
count += 1
|
86
|
-
yield packet.data.to_s
|
95
|
+
yield packet.data.to_s, packet.interface.link_type
|
87
96
|
else
|
88
97
|
packets << packet.data.to_s
|
89
98
|
end
|
@@ -106,12 +115,19 @@ module PacketGen
|
|
106
115
|
count = 0
|
107
116
|
packets = [] unless blk
|
108
117
|
|
109
|
-
read_packet_bytes(fname) do |packet|
|
118
|
+
read_packet_bytes(fname) do |packet, link_type|
|
119
|
+
first_header = KNOWN_LINK_TYPES[link_type]
|
120
|
+
parsed_pkt = if first_header.nil?
|
121
|
+
# unknown link type, try to guess
|
122
|
+
Packet.parse(packet)
|
123
|
+
else
|
124
|
+
Packet.parse(packet, first_header: first_header)
|
125
|
+
end
|
110
126
|
if blk
|
111
127
|
count += 1
|
112
|
-
yield
|
128
|
+
yield parsed_pkt
|
113
129
|
else
|
114
|
-
packets <<
|
130
|
+
packets << parsed_pkt
|
115
131
|
end
|
116
132
|
end
|
117
133
|
|
@@ -277,7 +293,7 @@ module PacketGen
|
|
277
293
|
# @return [void]
|
278
294
|
def parse_section(io)
|
279
295
|
shb = SHB.new
|
280
|
-
type =
|
296
|
+
type = Types::Int32.new(0, shb.endian).read(io.read(4))
|
281
297
|
io.seek(-4, IO::SEEK_CUR)
|
282
298
|
shb = parse(type, io, shb)
|
283
299
|
raise InvalidFileError, 'no Section header found' unless shb.is_a?(SHB)
|
@@ -287,7 +303,7 @@ module PacketGen
|
|
287
303
|
section = StringIO.new(io.read(shb.section_len.to_i))
|
288
304
|
while !section.eof? do
|
289
305
|
shb = @sections.last
|
290
|
-
type =
|
306
|
+
type = Types::Int32.new(0, shb.endian).read(section.read(4))
|
291
307
|
section.seek(-4, IO::SEEK_CUR)
|
292
308
|
block = parse(type, section, shb)
|
293
309
|
end
|
@@ -295,7 +311,7 @@ module PacketGen
|
|
295
311
|
# section length is undefined
|
296
312
|
while !io.eof?
|
297
313
|
shb = @sections.last
|
298
|
-
type =
|
314
|
+
type = Types::Int32.new(0, shb.endian).read(io.read(4))
|
299
315
|
io.seek(-4, IO::SEEK_CUR)
|
300
316
|
block = parse(type, io, shb)
|
301
317
|
end
|
@@ -303,7 +319,7 @@ module PacketGen
|
|
303
319
|
end
|
304
320
|
|
305
321
|
# Parse a block from its type
|
306
|
-
# @param [
|
322
|
+
# @param [Types::Int32] type
|
307
323
|
# @param [IO] io stream from which parse block
|
308
324
|
# @param [SHB] shb header of current section
|
309
325
|
# @return [void]
|
data/lib/packetgen/pcapng/idb.rb
CHANGED
@@ -16,10 +16,13 @@ module PacketGen
|
|
16
16
|
# Int64 :snaplen Default: 0 (no limit)
|
17
17
|
# String :options
|
18
18
|
# Int32 :block_len2
|
19
|
-
class IDB <
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
class IDB < Block
|
20
|
+
|
21
|
+
# Minimum IDB size
|
22
|
+
MIN_SIZE = 5*4
|
23
|
+
|
24
|
+
# Option code for if_tsresol option
|
25
|
+
OPTION_IF_TSRESOL = 9
|
23
26
|
|
24
27
|
# @return [:little, :big]
|
25
28
|
attr_accessor :endian
|
@@ -28,11 +31,21 @@ module PacketGen
|
|
28
31
|
# @return [Array<EPB,SPB>]
|
29
32
|
attr_accessor :packets
|
30
33
|
|
31
|
-
#
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
# @!attribute link_type
|
35
|
+
# 16-bit link type
|
36
|
+
# @return [Integer]
|
37
|
+
define_field_before :block_len2, :link_type, Types::Int16, default: 1
|
38
|
+
# @!attribute reserved
|
39
|
+
# 16-bit reserved field
|
40
|
+
# @return [Integer]
|
41
|
+
define_field_before :block_len2, :reserved, Types::Int16, default: 0
|
42
|
+
# @!attribute snaplen
|
43
|
+
# 32-bit snap length
|
44
|
+
# @return [Integer]
|
45
|
+
define_field_before :block_len2, :snaplen, Types::Int32, default: 0
|
46
|
+
# @!attribute options
|
47
|
+
# @return [Types::String]
|
48
|
+
define_field_before :block_len2, :options, Types::String
|
36
49
|
|
37
50
|
# @param [Hash] options
|
38
51
|
# @option options [:little, :big] :endian set block endianness
|
@@ -45,27 +58,12 @@ module PacketGen
|
|
45
58
|
# @option options [::String] :options
|
46
59
|
# @option options [Integer] :block_len2 block total length
|
47
60
|
def initialize(options={})
|
48
|
-
|
61
|
+
super
|
62
|
+
set_endianness(options[:endian] || :little)
|
49
63
|
@packets = []
|
50
64
|
@options_decoded = false
|
51
|
-
|
52
|
-
|
53
|
-
options[:snaplen], options[:options], options[:block_len2])
|
54
|
-
end
|
55
|
-
|
56
|
-
# Used by {#initialize} to set the initial fields
|
57
|
-
# @see #initialize possible options
|
58
|
-
# @param [Hash] options
|
59
|
-
# @return [Hash] return +options+
|
60
|
-
def init_fields(options={})
|
61
|
-
options[:type] = @int32.new(options[:type] || PcapNG::IDB_TYPE.to_i)
|
62
|
-
options[:block_len] = @int32.new(options[:block_len] || MIN_SIZE)
|
63
|
-
options[:link_type] = @int16.new(options[:link_type] || 1)
|
64
|
-
options[:reserved] = @int16.new(options[:reserved] || 0)
|
65
|
-
options[:snaplen] = @int32.new(options[:snaplen] || 0)
|
66
|
-
options[:options] = StructFu::String.new(options[:options] || '')
|
67
|
-
options[:block_len2] = @int32.new(options[:block_len2] || MIN_SIZE)
|
68
|
-
options
|
65
|
+
recalc_block_len
|
66
|
+
self.type = options[:type] || PcapNG::IDB_TYPE.to_i
|
69
67
|
end
|
70
68
|
|
71
69
|
# Reads a String or a IO to populate the object
|
@@ -87,10 +85,7 @@ module PacketGen
|
|
87
85
|
self[:options].read io.read(self[:block_len].to_i - MIN_SIZE)
|
88
86
|
self[:block_len2].read io.read(4)
|
89
87
|
|
90
|
-
|
91
|
-
raise InvalidFileError, 'Incoherency in Interface Description Block'
|
92
|
-
end
|
93
|
-
|
88
|
+
check_len_coherency
|
94
89
|
self
|
95
90
|
end
|
96
91
|
|
@@ -141,7 +136,7 @@ module PacketGen
|
|
141
136
|
def to_s
|
142
137
|
pad_field :options
|
143
138
|
recalc_block_len
|
144
|
-
|
139
|
+
fields.map { |f| @fields[f].to_s }.join << @packets.map(&:to_s).join
|
145
140
|
end
|
146
141
|
|
147
142
|
end
|