packetgen 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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