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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/packetgen/header/arp.rb +54 -125
  4. data/lib/packetgen/header/base.rb +175 -0
  5. data/lib/packetgen/header/dns/name.rb +110 -0
  6. data/lib/packetgen/header/dns/opt.rb +137 -0
  7. data/lib/packetgen/header/dns/option.rb +17 -0
  8. data/lib/packetgen/header/dns/qdsection.rb +39 -0
  9. data/lib/packetgen/header/dns/question.rb +129 -0
  10. data/lib/packetgen/header/dns/rr.rb +89 -0
  11. data/lib/packetgen/header/dns/rrsection.rb +72 -0
  12. data/lib/packetgen/header/dns.rb +276 -0
  13. data/lib/packetgen/header/esp.rb +38 -70
  14. data/lib/packetgen/header/eth.rb +35 -106
  15. data/lib/packetgen/header/icmp.rb +19 -70
  16. data/lib/packetgen/header/icmpv6.rb +3 -3
  17. data/lib/packetgen/header/ip.rb +54 -210
  18. data/lib/packetgen/header/ipv6.rb +73 -164
  19. data/lib/packetgen/header/tcp/option.rb +34 -50
  20. data/lib/packetgen/header/tcp/options.rb +19 -20
  21. data/lib/packetgen/header/tcp.rb +66 -129
  22. data/lib/packetgen/header/udp.rb +31 -88
  23. data/lib/packetgen/header.rb +5 -10
  24. data/lib/packetgen/inspect.rb +5 -4
  25. data/lib/packetgen/packet.rb +74 -57
  26. data/lib/packetgen/pcapng/block.rb +49 -7
  27. data/lib/packetgen/pcapng/epb.rb +36 -34
  28. data/lib/packetgen/pcapng/file.rb +24 -8
  29. data/lib/packetgen/pcapng/idb.rb +28 -33
  30. data/lib/packetgen/pcapng/shb.rb +35 -39
  31. data/lib/packetgen/pcapng/spb.rb +18 -27
  32. data/lib/packetgen/pcapng/unknown_block.rb +11 -21
  33. data/lib/packetgen/pcapng.rb +9 -7
  34. data/lib/packetgen/types/array.rb +56 -0
  35. data/lib/packetgen/types/fields.rb +325 -0
  36. data/lib/packetgen/types/int.rb +164 -0
  37. data/lib/packetgen/types/int_string.rb +69 -0
  38. data/lib/packetgen/types/string.rb +36 -0
  39. data/lib/packetgen/types/tlv.rb +41 -0
  40. data/lib/packetgen/types.rb +13 -0
  41. data/lib/packetgen/version.rb +1 -1
  42. data/lib/packetgen.rb +1 -1
  43. metadata +19 -6
  44. data/lib/packetgen/header/header_class_methods.rb +0 -106
  45. data/lib/packetgen/header/header_methods.rb +0 -73
  46. data/lib/packetgen/structfu.rb +0 -363
@@ -9,7 +9,7 @@ module PacketGen
9
9
  INSPECT_MAX_WIDTH = 70
10
10
 
11
11
  # Format to inspect attribute
12
- INSPECT_FMT_ATTR = "%7s %12s: %s\n"
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] hex_size
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 {StructFu::Int}: show value as integer and in
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? StructFu::Int
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"
@@ -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
- pkt = new
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 [StructFu]
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
- add_header(next_header, prev_header) if prev_header and next_header
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::HeaderMethods] header
336
- # @param [Header::HeaderMethods] previous_header
313
+ # @param [Header::Base] header
314
+ # @param [Header::Base] previous_header
337
315
  # @return [void]
338
- def add_header(header, previous_header=nil)
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? or bindings.empty?
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
- prev_header[bindings.first.key].read bindings.first.value
351
- prev_header.body = 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
- # Mixin module to declare some common methods for block classes.
10
- module Block
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
- self[:options].size > 0
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 = to_a.map(&:to_s).join.size
22
- self[:block_len].value = self[:block_len2].value = len
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 self[field].size % 4 == 0
31
- self[field] << "\x00" * (4 - (self[field].size % 4))
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
@@ -19,18 +19,42 @@ module PacketGen
19
19
  # String :data
20
20
  # String :options
21
21
  # Int32 :block_len2
22
- class EPB < Struct.new(:type, :block_len, :interface_id, :tsh, :tsl,
23
- :cap_len, :orig_len, :data, :options, :block_len2)
24
- include StructFu
25
- include Block
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
- # Minimum EPB size
33
- MIN_SIZE = 8*4
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
- @endian = set_endianness(options[:endian] || :little)
51
- init_fields(options)
52
- super(options[:type], options[:block_len], options[:interface_id], options[:tsh],
53
- options[:tsl], options[:cap_len], options[:orig_len], options[:data],
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
- unless self[:block_len].to_i == self[:block_len2].to_i
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
- to_a.map(&:to_s).join
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 Packet.parse(packet)
128
+ yield parsed_pkt
113
129
  else
114
- packets << Packet.parse(packet)
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 = StructFu::Int32.new(0, shb.endian).read(io.read(4))
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 = StructFu::Int32.new(0, shb.endian).read(section.read(4))
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 = StructFu::Int32.new(0, shb.endian).read(io.read(4))
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 [StructFu::Int32] type
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]
@@ -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 < Struct.new(:type, :block_len, :link_type, :reserved,
20
- :snaplen, :options, :block_len2)
21
- include StructFu
22
- include Block
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
- # Minimum IDB size
32
- MIN_SIZE = 5*4
33
-
34
- # Option code for if_tsresol option
35
- OPTION_IF_TSRESOL = 9
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
- @endian = set_endianness(options[:endian] || :little)
61
+ super
62
+ set_endianness(options[:endian] || :little)
49
63
  @packets = []
50
64
  @options_decoded = false
51
- init_fields(options)
52
- super(options[:type], options[:block_len], options[:link_type], options[:reserved],
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
- unless self[:block_len].to_i == self[:block_len2].to_i
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
- to_a.map(&:to_s).join + @packets.map(&:to_s).join
139
+ fields.map { |f| @fields[f].to_s }.join << @packets.map(&:to_s).join
145
140
  end
146
141
 
147
142
  end