packetgen 3.1.4 → 3.2.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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -1
  3. data/bin/pgconsole +1 -0
  4. data/lib/packetgen.rb +19 -3
  5. data/lib/packetgen/capture.rb +30 -9
  6. data/lib/packetgen/config.rb +15 -9
  7. data/lib/packetgen/deprecation.rb +1 -1
  8. data/lib/packetgen/header/asn1_base.rb +19 -9
  9. data/lib/packetgen/header/base.rb +68 -70
  10. data/lib/packetgen/header/dhcpv6/duid.rb +3 -1
  11. data/lib/packetgen/header/dhcpv6/option.rb +4 -12
  12. data/lib/packetgen/header/dns/name.rb +18 -7
  13. data/lib/packetgen/header/dns/qdsection.rb +1 -1
  14. data/lib/packetgen/header/dns/question.rb +2 -0
  15. data/lib/packetgen/header/dot11.rb +25 -38
  16. data/lib/packetgen/header/dot11/data.rb +28 -34
  17. data/lib/packetgen/header/dot1x.rb +1 -14
  18. data/lib/packetgen/header/eap.rb +14 -17
  19. data/lib/packetgen/header/eth.rb +5 -6
  20. data/lib/packetgen/header/http/headers.rb +4 -2
  21. data/lib/packetgen/header/http/request.rb +37 -18
  22. data/lib/packetgen/header/http/response.rb +11 -5
  23. data/lib/packetgen/header/http/verbs.rb +1 -1
  24. data/lib/packetgen/header/igmpv3/group_record.rb +2 -0
  25. data/lib/packetgen/header/ip.rb +27 -26
  26. data/lib/packetgen/header/ip/addr.rb +3 -1
  27. data/lib/packetgen/header/ip/option.rb +4 -4
  28. data/lib/packetgen/header/ipv6/addr.rb +2 -0
  29. data/lib/packetgen/header/mldv2/mcast_address_record.rb +2 -0
  30. data/lib/packetgen/header/ospfv2/ls_request.rb +2 -0
  31. data/lib/packetgen/header/ospfv2/lsa.rb +13 -3
  32. data/lib/packetgen/header/ospfv2/lsa_header.rb +2 -1
  33. data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +2 -0
  34. data/lib/packetgen/header/ospfv3/ls_request.rb +2 -0
  35. data/lib/packetgen/header/ospfv3/lsa.rb +9 -3
  36. data/lib/packetgen/header/ospfv3/lsa_header.rb +2 -1
  37. data/lib/packetgen/header/snmp.rb +3 -2
  38. data/lib/packetgen/header/tcp.rb +1 -20
  39. data/lib/packetgen/header/tcp/option.rb +8 -6
  40. data/lib/packetgen/inspect.rb +1 -17
  41. data/lib/packetgen/packet.rb +10 -6
  42. data/lib/packetgen/pcapng.rb +11 -11
  43. data/lib/packetgen/pcapng/block.rb +15 -2
  44. data/lib/packetgen/pcapng/epb.rb +22 -15
  45. data/lib/packetgen/pcapng/file.rb +166 -81
  46. data/lib/packetgen/pcapng/idb.rb +7 -9
  47. data/lib/packetgen/pcapng/shb.rb +35 -28
  48. data/lib/packetgen/pcapng/spb.rb +16 -12
  49. data/lib/packetgen/pcapng/unknown_block.rb +3 -11
  50. data/lib/packetgen/pcaprub_wrapper.rb +25 -11
  51. data/lib/packetgen/types.rb +1 -0
  52. data/lib/packetgen/types/abstract_tlv.rb +3 -1
  53. data/lib/packetgen/types/array.rb +17 -10
  54. data/lib/packetgen/types/cstring.rb +56 -19
  55. data/lib/packetgen/types/enum.rb +4 -0
  56. data/lib/packetgen/types/fieldable.rb +65 -0
  57. data/lib/packetgen/types/fields.rb +180 -113
  58. data/lib/packetgen/types/int.rb +15 -1
  59. data/lib/packetgen/types/int_string.rb +8 -0
  60. data/lib/packetgen/types/length_from.rb +18 -10
  61. data/lib/packetgen/types/oui.rb +2 -0
  62. data/lib/packetgen/types/string.rb +58 -7
  63. data/lib/packetgen/types/tlv.rb +2 -0
  64. data/lib/packetgen/unknown_packet.rb +84 -0
  65. data/lib/packetgen/utils.rb +6 -7
  66. data/lib/packetgen/version.rb +1 -1
  67. metadata +18 -15
@@ -6,6 +6,8 @@
6
6
  # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
7
7
  # This program is published under MIT license.
8
8
 
9
+ # rubocop:disable Metrics/ClassLength
10
+
9
11
  module PacketGen
10
12
  # An object of type {Packet} handles a network packet. This packet may contain
11
13
  # multiple protocol headers, starting from MAC layer or from Network (OSI) layer.
@@ -77,10 +79,10 @@ module PacketGen
77
79
  # @yieldparam [Packet,String] packet if a block is given, yield each
78
80
  # captured packet (Packet or raw data String, depending on +:parse+ option)
79
81
  # @return [Array<Packet>] captured packet
80
- def self.capture(**kwargs)
81
- capture = Capture.new(kwargs)
82
- if block_given?
83
- capture.start { |packet| yield packet }
82
+ def self.capture(**kwargs, &block)
83
+ capture = Capture.new(**kwargs)
84
+ if block
85
+ capture.start(&block)
84
86
  else
85
87
  capture.start
86
88
  end
@@ -214,7 +216,7 @@ module PacketGen
214
216
  # @return [Array] see return from {PcapNG::File#to_file}
215
217
  # @see File
216
218
  def to_f(filename)
217
- PcapNG::File.new.array_to_file(file: filename, array: [self])
219
+ PcapNG::File.new.read_array([self]).to_f(filename)
218
220
  end
219
221
  alias write to_f
220
222
 
@@ -285,7 +287,7 @@ module PacketGen
285
287
  if first_header.nil?
286
288
  # No decoding forced for first header. Have to guess it!
287
289
  first_header = guess_first_header(binary_str)
288
- raise ParseError, 'cannot identify first header in string' if first_header.nil?
290
+ raise ParseError, "cannot identify first header in string: #{binary_str.inspect}" if first_header.nil?
289
291
  end
290
292
 
291
293
  add first_header
@@ -522,5 +524,7 @@ module PacketGen
522
524
  end
523
525
  end
524
526
 
527
+ # rubocop:enable Metrics/ClassLength
528
+
525
529
  require_relative 'headerable'
526
530
  require_relative 'header'
@@ -13,13 +13,13 @@ module PacketGen
13
13
  # @author Sylvain Daubert
14
14
  module PcapNG
15
15
  # Section Header Block type number
16
- SHB_TYPE = Types::Int32.new(0x0A0D0D0A, :little)
16
+ SHB_TYPE = Types::Int32.new(0x0A0D0D0A, :little).freeze
17
17
  # Interface Description Block type number
18
- IDB_TYPE = Types::Int32.new(1, :little)
18
+ IDB_TYPE = Types::Int32.new(1, :little).freeze
19
19
  # Simple Packet Block type number
20
- SPB_TYPE = Types::Int32.new(3, :little)
20
+ SPB_TYPE = Types::Int32.new(3, :little).freeze
21
21
  # Enhanced Packet Block type number
22
- EPB_TYPE = Types::Int32.new(6, :little)
22
+ EPB_TYPE = Types::Int32.new(6, :little).freeze
23
23
 
24
24
  # IEEE 802.3 Ethernet (10Mb, 100Mb, 1000Mb, and up)
25
25
  LINKTYPE_ETHERNET = 1
@@ -46,10 +46,10 @@ module PacketGen
46
46
  end
47
47
  end
48
48
 
49
- require_relative 'pcapng/block.rb'
50
- require_relative 'pcapng/unknown_block.rb'
51
- require_relative 'pcapng/shb.rb'
52
- require_relative 'pcapng/idb.rb'
53
- require_relative 'pcapng/epb.rb'
54
- require_relative 'pcapng/spb.rb'
55
- require_relative 'pcapng/file.rb'
49
+ require_relative 'pcapng/block'
50
+ require_relative 'pcapng/unknown_block'
51
+ require_relative 'pcapng/shb'
52
+ require_relative 'pcapng/idb'
53
+ require_relative 'pcapng/epb'
54
+ require_relative 'pcapng/spb'
55
+ require_relative 'pcapng/file'
@@ -49,7 +49,9 @@ module PacketGen
49
49
  # @return [void]
50
50
  def pad_field(*fields)
51
51
  fields.each do |field|
52
- @fields[field] << "\x00" * (4 - (@fields[field].sz % 4)) unless (@fields[field].sz % 4).zero?
52
+ obj = @fields[field]
53
+ pad_size = (obj.sz % 4).zero? ? 0 : (4 - (obj.sz % 4))
54
+ obj << "\x00" * pad_size
53
55
  end
54
56
  end
55
57
 
@@ -59,7 +61,7 @@ module PacketGen
59
61
  # Must be called by all subclass #initialize method.
60
62
  # @param [:little, :big] endian
61
63
  # @return [:little, :big] returns endian
62
- def set_endianness(endian)
64
+ def endianness(endian)
63
65
  raise ArgumentError, "unknown endianness for #{self.class}" unless %i[little big].include?(endian)
64
66
 
65
67
  @endian = endian
@@ -76,6 +78,17 @@ module PacketGen
76
78
 
77
79
  StringIO.new(force_binary(str_or_io.to_s))
78
80
  end
81
+
82
+ def remove_padding(io, data_len)
83
+ data_pad_len = (4 - (data_len % 4)) % 4
84
+ io.read data_pad_len
85
+ data_pad_len
86
+ end
87
+
88
+ def read_blocklen2_and_check(io)
89
+ self[:block_len2].read io.read(4)
90
+ check_len_coherency
91
+ end
79
92
  end
80
93
  end
81
94
  end
@@ -73,7 +73,7 @@ module PacketGen
73
73
  # @option options [Integer] :block_len2 block total length
74
74
  def initialize(options={})
75
75
  super
76
- set_endianness(options[:endian] || :little)
76
+ endianness(options[:endian] || :little)
77
77
  recalc_block_len
78
78
  self.type = options[:type] || PcapNG::EPB_TYPE.to_i
79
79
  end
@@ -85,22 +85,13 @@ module PacketGen
85
85
  io = to_io(str_or_io)
86
86
  return self if io.eof?
87
87
 
88
- self[:type].read io.read(4)
89
- self[:block_len].read io.read(4)
90
- self[:interface_id].read io.read(4)
91
- self[:tsh].read io.read(4)
92
- self[:tsl].read io.read(4)
93
- self[:cap_len].read io.read(4)
94
- self[:orig_len].read io.read(4)
88
+ %i[type block_len interface_id tsh tsl cap_len orig_len].each do |attr|
89
+ self[attr].read io.read(self[attr].sz)
90
+ end
95
91
  self[:data].read io.read(self.cap_len)
96
- data_pad_len = (4 - (self[:cap_len].to_i % 4)) % 4
97
- io.read data_pad_len
98
- options_len = self.block_len - self.cap_len - data_pad_len
99
- options_len -= MIN_SIZE
100
- self[:options].read io.read(options_len)
101
- self[:block_len2].read io.read(4)
92
+ read_options(io)
93
+ read_blocklen2_and_check(io)
102
94
 
103
- check_len_coherency
104
95
  self
105
96
  end
106
97
 
@@ -110,6 +101,16 @@ module PacketGen
110
101
  Time.at((self.tsh << 32 | self.tsl) * ts_resol)
111
102
  end
112
103
 
104
+ # Set timestamp from a Time object
105
+ # @param [Time] time
106
+ # @return [Time] time
107
+ def timestamp=(time)
108
+ tstamp = (time.to_r / ts_resol).to_i
109
+ self.tsh = (tstamp & 0xffffffff00000000) >> 32
110
+ self.tsl = tstamp & 0xffffffff
111
+ time
112
+ end
113
+
113
114
  # Return the object as a String
114
115
  # @return [String]
115
116
  def to_s
@@ -127,6 +128,12 @@ module PacketGen
127
128
  @interface.ts_resol
128
129
  end
129
130
  end
131
+
132
+ def read_options(io)
133
+ data_pad_len = remove_padding(io, self.cap_len)
134
+ options_len = self.block_len - self.cap_len - data_pad_len - MIN_SIZE
135
+ self[:options].read io.read(options_len)
136
+ end
130
137
  end
131
138
  end
132
139
  end
@@ -22,9 +22,9 @@ module PacketGen
22
22
 
23
23
  # @private
24
24
  BLOCK_TYPES = Hash[
25
- PcapNG.constants(false).select { |c| c.to_s =~ /_TYPE/ }.map do |c|
25
+ PcapNG.constants(false).select { |c| c.to_s.include?('_TYPE') }.map do |c|
26
26
  type_value = PcapNG.const_get(c).to_i
27
- klass = PcapNG.const_get(c.to_s[0..-6]) # use delete_suffix('_TYPE') when support for Ruby 2.4 will stop
27
+ klass = PcapNG.const_get(c.to_s[0..-6]) # @todo use delete_suffix('_TYPE') when support for Ruby 2.4 will stop
28
28
  [type_value, klass]
29
29
  end
30
30
  ].freeze
@@ -68,20 +68,13 @@ module PacketGen
68
68
  def readfile(fname, &blk)
69
69
  raise ArgumentError, "cannot read file #{fname}" unless ::File.readable?(fname)
70
70
 
71
- ::File.open(fname, 'rb') do |f|
72
- parse_section(f) until f.eof?
73
- end
74
-
71
+ ::File.open(fname, 'rb') { |f| parse_section(f) until f.eof? }
75
72
  return unless blk
76
73
 
77
74
  count = 0
78
- @sections.each do |section|
79
- section.interfaces.each do |intf|
80
- intf.packets.each do |pkt|
81
- count += 1
82
- yield pkt
83
- end
84
- end
75
+ each_packet_with_interface do |pkt, _itf|
76
+ count += 1
77
+ yield pkt
85
78
  end
86
79
  count
87
80
  end
@@ -98,12 +91,10 @@ module PacketGen
98
91
  # @return [Integer] number of packets
99
92
  # @raise [ArgumentError] cannot read +fname+
100
93
  def read_packet_bytes(fname, &blk)
101
- count = 0
102
94
  packets = [] unless blk
103
95
 
104
- readfile(fname) do |packet|
96
+ count = readfile(fname) do |packet|
105
97
  if blk
106
- count += 1
107
98
  yield packet.data.to_s, packet.interface.link_type
108
99
  else
109
100
  packets << packet.data.to_s
@@ -124,19 +115,11 @@ module PacketGen
124
115
  # @return [Integer] number of packets
125
116
  # @raise [ArgumentError] cannot read +fname+
126
117
  def read_packets(fname, &blk)
127
- count = 0
128
118
  packets = [] unless blk
129
119
 
130
- read_packet_bytes(fname) do |packet, link_type|
131
- first_header = KNOWN_LINK_TYPES[link_type]
132
- parsed_pkt = if first_header.nil?
133
- # unknown link type, try to guess
134
- Packet.parse(packet)
135
- else
136
- Packet.parse(packet, first_header: first_header)
137
- end
120
+ count = read_packet_bytes(fname) do |packet, link_type|
121
+ parsed_pkt = parse_packet(packet, link_type)
138
122
  if blk
139
- count += 1
140
123
  yield parsed_pkt
141
124
  else
142
125
  packets << parsed_pkt
@@ -158,6 +141,8 @@ module PacketGen
158
141
  @sections.clear
159
142
  end
160
143
 
144
+ # @deprecated
145
+ # Prefer use of {#to_a} or {#to_h}.
161
146
  # Translates a {File} into an array of packets.
162
147
  # @param [Hash] options
163
148
  # @option options [String] :file if given, object is cleared and filename
@@ -167,37 +152,59 @@ module PacketGen
167
152
  # as value. There is one hash per packet.
168
153
  # @return [Array<Packet>,Array<Hash>]
169
154
  def file_to_array(options={})
170
- Deprecation.deprecated_option(self.class, __method__, :filename) if options[:filename]
171
- Deprecation.deprecated_option(self.class, __method__, :keep_ts) if options[:keep_ts]
155
+ Deprecation.deprecated(self.class, __method__)
172
156
 
173
- filename = options[:filename] || options[:file]
174
- reread filename
157
+ file = options[:file] || options[:filename]
158
+ reread file
175
159
 
176
160
  ary = []
177
- @sections.each do |section|
178
- section.interfaces.each do |itf|
179
- blk = if options[:keep_timestamps] || options[:keep_ts]
180
- proc { |pkt| { pkt.timestamp => pkt.data.to_s } }
181
- else
182
- proc { |pkt| pkt.data.to_s }
183
- end
184
- ary.concat(itf.packets.map(&blk))
185
- end
161
+ blk = if options[:keep_timestamps] || options[:keep_ts]
162
+ proc { |pkt| { pkt.timestamp => pkt.data.to_s } }
163
+ else
164
+ proc { |pkt| pkt.data.to_s }
165
+ end
166
+ each_packet_with_interface do |pkt, _itf|
167
+ ary << blk.call(pkt)
186
168
  end
169
+
170
+ ary
171
+ end
172
+
173
+ # Translates a {File} into an array of packets.
174
+ # @return [Array<Packet>]
175
+ # @since 3.1.6
176
+ def to_a
177
+ ary = []
178
+ each_packet_with_interface do |pkt, itf|
179
+ ary << parse_packet(pkt.data.to_s, itf.link_type)
180
+ end
181
+
187
182
  ary
188
183
  end
189
184
 
185
+ # Translates a {File} into a hash with timestamps as keys.
186
+ # @note Only packets from {EPB} sections are extracted, as {SPB} ones do not have timestamp.
187
+ # @return [Hash{Time => Packet}]
188
+ # @since 3.1.6
189
+ def to_h
190
+ hsh = {}
191
+ each_packet_with_interface do |pkt, itf|
192
+ next if pkt.is_a?(SPB)
193
+
194
+ hsh[pkt.timestamp] = parse_packet(pkt.data.to_s, itf.link_type)
195
+ end
196
+
197
+ hsh
198
+ end
199
+
190
200
  # Writes the {File} to a file.
191
201
  # @param [Hash] options
192
202
  # @option options [Boolean] :append (default: +false+) if set to +true+,
193
203
  # the packets are appended to the file, rather than overwriting it
194
204
  # @return [Array] array of 2 elements: filename and size written
205
+ # @todo for 4.0, replace +options+ by +append+ kwarg
195
206
  def to_file(filename, options={})
196
- mode = if options[:append] && ::File.exist?(filename)
197
- 'ab'
198
- else
199
- 'wb'
200
- end
207
+ mode = (options[:append] && ::File.exist?(filename)) ? 'ab' : 'wb'
201
208
  ::File.open(filename, mode) { |f| f.write(self.to_s) }
202
209
  [filename, self.to_s.size]
203
210
  end
@@ -217,6 +224,7 @@ module PacketGen
217
224
  self.to_file(filename.to_s, append: true)
218
225
  end
219
226
 
227
+ # @deprecated Prefer use of {#read_array} or {#read_hash}.
220
228
  # @overload array_to_file(ary)
221
229
  # Update {File} object with packets.
222
230
  # @param [Array] ary as generated by {#file_to_array} or Array of Packet objects.
@@ -238,12 +246,10 @@ module PacketGen
238
246
  filename, ary, ts, ts_inc, append = array_to_file_options(options)
239
247
 
240
248
  section = create_new_shb_section
241
- ts_resol = section.interfaces.last.ts_resol
242
249
 
243
- ts_add_val = 0 # value to add to ts in Array case
244
250
  ary.each do |pkt|
245
- classify_block(section, epb_from_pkt(pkt, section.endian, ts, ts_resol, ts_add_val))
246
- ts_add_val += ts_inc
251
+ classify_block(section, epb_from_pkt(pkt, section, ts))
252
+ ts += ts_inc
247
253
  end
248
254
 
249
255
  if filename
@@ -253,6 +259,54 @@ module PacketGen
253
259
  end
254
260
  end
255
261
 
262
+ # Update current object from an array of packets
263
+ # @param [Array<Packet>] packets
264
+ # @param [Time, nil] timestamp initial timestamp, used for first packet
265
+ # @param [Numeric, nil] ts_inc timestamp increment, in seconds, to increment
266
+ # initial timestamp for each packet
267
+ # @return [self]
268
+ # @note if +timestamp+ and/or +ts_inc+ are nil, {SPB} sections are created
269
+ # for each packet, else {EPB} ones are used
270
+ # @since 3.1.6
271
+ def read_array(packets, timestamp: nil, ts_inc: nil)
272
+ ts = timestamp
273
+ section = create_new_shb_section
274
+ packets.each do |pkt|
275
+ block = create_block_from_pkt(pkt, section, ts, ts_inc)
276
+ classify_block(section, block)
277
+ ts = update_ts(ts, ts_inc)
278
+ end
279
+ self
280
+ end
281
+
282
+ # Update current object from a hash of packets and timestamps
283
+ # @param [Hash{Time => Packet}] hsh
284
+ # @return [self]
285
+ # @since 3.1.6
286
+ def read_hash(hsh)
287
+ section = create_new_shb_section
288
+ hsh.each do |ts, pkt|
289
+ block = create_block_from_pkt(pkt, section, ts, 0)
290
+ classify_block(section, block)
291
+ end
292
+ self
293
+ end
294
+
295
+ # @return [String]
296
+ # @since 3.1.6
297
+ def inspect
298
+ str = +''
299
+ sections.each do |section|
300
+ str << section.inspect
301
+ section.interfaces.each do |itf|
302
+ str << itf.inspect
303
+ itf.packets.each { |block| str << block.inspect }
304
+ end
305
+ end
306
+
307
+ str
308
+ end
309
+
256
310
  private
257
311
 
258
312
  # Parse a section. A section is made of at least a SHB. It than may contain
@@ -260,8 +314,7 @@ module PacketGen
260
314
  # @param [IO] io
261
315
  # @return [void]
262
316
  def parse_section(io)
263
- shb = SHB.new
264
- shb = parse_shb(shb, io)
317
+ shb = parse_shb(SHB.new, io)
265
318
  raise InvalidFileError, 'no Section header found' unless shb.is_a?(SHB)
266
319
 
267
320
  to_parse = if shb.section_len.to_i != 0xffffffffffffffff
@@ -294,17 +347,18 @@ module PacketGen
294
347
  # @param [SHB] shb header of current section
295
348
  # @return [Block]
296
349
  def parse(type, io, shb)
297
- klass = if BLOCK_TYPES.key?(type.to_i)
298
- BLOCK_TYPES[type.to_i]
299
- else
300
- UnknownBlock
301
- end
302
-
303
- block = klass.new(endian: shb.endian)
350
+ block = guess_block_type(type).new(endian: shb.endian)
304
351
  classify_block shb, block
305
352
  block.read(io)
306
353
  end
307
354
 
355
+ # Guess class to use from type
356
+ # @param [Types::Int] type
357
+ # @return [Block]
358
+ def guess_block_type(type)
359
+ BLOCK_TYPES.key?(type.to_i) ? BLOCK_TYPES[type.to_i] : UnknownBlock
360
+ end
361
+
308
362
  # Classify block from its type
309
363
  # @param [SHB] shb header of current section
310
364
  # @param [Block] block block to classify
@@ -315,16 +369,11 @@ module PacketGen
315
369
  @sections << block
316
370
  when IDB
317
371
  shb << block
318
- block.section = shb
319
- when EPB
320
- shb.interfaces[block.interface_id] << block
321
- block.interface = shb.interfaces[block.interface_id]
322
- when SPB
323
- shb.interfaces[0] << block
324
- block.interface = shb.interfaces[0]
372
+ when SPB, EPB
373
+ ifid = block.is_a?(EPB) ? block.interface_id : 0
374
+ shb.interfaces[ifid] << block
325
375
  else
326
- shb.unknown_blocks << block
327
- block.section = shb
376
+ shb.add_unknown_block(block)
328
377
  end
329
378
  end
330
379
 
@@ -341,9 +390,9 @@ module PacketGen
341
390
 
342
391
  # Extract and check options for #array_to_file
343
392
  def array_to_file_options_from_hash(options)
344
- Deprecation.deprecated_option(self.class, :array_to_file, :filename) if options[:filename]
345
- Deprecation.deprecated_option(self.class, :array_to_file, :arr) if options[:arr]
346
- Deprecation.deprecated_option(self.class, :array_to_file, :ts) if options[:ts]
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
347
396
 
348
397
  filename = options[:filename] || options[:file]
349
398
  ary = options[:array] || options[:arr]
@@ -368,10 +417,8 @@ module PacketGen
368
417
  # Compute tsh and tsl from ts
369
418
  def calc_ts(timeslot, ts_resol)
370
419
  this_ts = (timeslot / ts_resol).to_i
371
- this_tsh = this_ts >> 32
372
- this_tsl = this_ts & 0xffffffff
373
420
 
374
- [this_tsh, this_tsl]
421
+ [this_ts >> 32, this_ts & 0xffffffff]
375
422
  end
376
423
 
377
424
  def reread(filename)
@@ -381,18 +428,34 @@ module PacketGen
381
428
  readfile filename
382
429
  end
383
430
 
384
- def epb_from_pkt(pkt, endian, ts, ts_resol, ts_add_val)
385
- case pkt
386
- when Hash
387
- this_ts = pkt.keys.first.to_i
388
- this_data = pkt.values.first.to_s
431
+ def create_block_from_pkt(pkt, section, timestamp, ts_inc)
432
+ if timestamp.nil? || ts_inc.nil?
433
+ spb_from_pkt(pkt, section)
389
434
  else
390
- this_ts = (ts + ts_add_val).to_i
391
- this_data = pkt.to_s
435
+ epb_from_pkt(pkt, section, timestamp)
392
436
  end
437
+ end
438
+
439
+ def spb_from_pkt(pkt, section)
440
+ pkt_s = pkt.to_s
441
+ size = pkt_s.size
442
+ SPB.new(endian: section.endian,
443
+ block_len: size,
444
+ orig_len: size,
445
+ data: pkt_s)
446
+ end
447
+
448
+ # @todo remove hash case when #array_to_file will be removed
449
+ def epb_from_pkt(pkt, section, timestamp)
450
+ this_ts, this_data = case pkt
451
+ when Hash
452
+ [pkt.keys.first.to_i, pkt.values.first.to_s]
453
+ else
454
+ [timestamp.to_r, pkt.to_s]
455
+ end
393
456
  this_cap_len = this_data.size
394
- this_tsh, this_tsl = calc_ts(this_ts, ts_resol)
395
- EPB.new(endian: endian,
457
+ this_tsh, this_tsl = calc_ts(this_ts, section.interfaces.last.ts_resol)
458
+ EPB.new(endian: section.endian,
396
459
  interface_id: 0,
397
460
  tsh: this_tsh,
398
461
  tsl: this_tsl,
@@ -400,6 +463,28 @@ module PacketGen
400
463
  orig_len: this_cap_len,
401
464
  data: this_data)
402
465
  end
466
+
467
+ def update_ts(timestamp, ts_inc)
468
+ return nil if timestamp.nil? || ts_inc.nil?
469
+
470
+ timestamp + ts_inc
471
+ end
472
+
473
+ # Iterate over each xPB with its associated interface
474
+ # @return [void]
475
+ # @yieldparam [String] xpb
476
+ # @yieldparam [IDB] itf
477
+ def each_packet_with_interface
478
+ sections.each do |section|
479
+ section.interfaces.each do |itf|
480
+ itf.packets.each { |xpb| yield xpb, itf }
481
+ end
482
+ end
483
+ end
484
+
485
+ def parse_packet(data, link_type)
486
+ Packet.parse(data, first_header: KNOWN_LINK_TYPES[link_type])
487
+ end
403
488
  end
404
489
  end
405
490
  end