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
@@ -71,6 +71,10 @@ module PacketGen
71
71
  def to_human
72
72
  @enum.key(to_i) || "<unknown:#{@value}>"
73
73
  end
74
+
75
+ def format_inspect
76
+ format_str % [to_human, to_i]
77
+ end
74
78
  end
75
79
 
76
80
  # Enumeration on one byte. See {Enum}.
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of PacketGen
4
+ # See https://github.com/sdaubert/packetgen for more informations
5
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
6
+ # This program is published under MIT license.
7
+
8
+ module PacketGen
9
+ module Types
10
+ # Mixin to define minimal API for a class to be embbeded as a field in
11
+ # {Fields} type.
12
+ #
13
+ # == Optional methods
14
+ # These methods may, optionally, be defined by fieldable types:
15
+ # * +from_human+ to load data from a human-readable string.
16
+ # @author Sylvain Daubert
17
+ # @since 3.1.6
18
+ module Fieldable
19
+ # Get type name
20
+ # @return [String]
21
+ def type_name
22
+ self.class.to_s.split('::').last
23
+ end
24
+
25
+ # rubocop:disable Lint/UselessMethodDefinition
26
+ # These methods are defined for documentation.
27
+
28
+ # Populate object from a binary string
29
+ # @param [String] str
30
+ # @return [Fields] self
31
+ # @abstract subclass should overload it.
32
+ def read(str)
33
+ super
34
+ end
35
+
36
+ # Return object as a binary string
37
+ # @return [String]
38
+ # @abstract subclass should overload it.
39
+ def to_s
40
+ super
41
+ end
42
+
43
+ # Size of object as binary string
44
+ # @return [Integer]
45
+ def sz
46
+ to_s.size
47
+ end
48
+
49
+ # Return a human-readbale string
50
+ # @return [String]
51
+ # @abstract subclass should overload it.
52
+ def to_human
53
+ super
54
+ end
55
+
56
+ # rubocop:enable Lint/UselessMethodDefinition
57
+
58
+ # Format object when inspecting a {Field} object
59
+ # @return [String]
60
+ def format_inspect
61
+ to_human
62
+ end
63
+ end
64
+ end
65
+ end
@@ -5,6 +5,8 @@
5
5
  # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
6
6
  # This program is published under MIT license.
7
7
 
8
+ # rubocop:disable Metrics/ClassLength
9
+
8
10
  module PacketGen
9
11
  module Types
10
12
  # @abstract Set of fields
@@ -13,8 +15,7 @@ module PacketGen
13
15
  #
14
16
  # == Basics
15
17
  # A {Fields} subclass is generaly composed of multiple binary fields. These fields
16
- # have each a given type. All types from {Types} module are supported, and all
17
- # {Fields} subclasses may also be used as field type.
18
+ # have each a given type. All {Fieldable} types are supported.
18
19
  #
19
20
  # To define a new subclass, it has to inherit from {Fields}. And some class
20
21
  # methods have to be used to declare attributes/fields:
@@ -119,17 +120,23 @@ module PacketGen
119
120
  # @return [Hash]
120
121
  # @since 3.1.0
121
122
  attr_reader :field_defs
123
+ # Get bit fields defintions for this class
124
+ # @return [Hash]
125
+ # @since 3.1.5
126
+ attr_reader :bit_fields
122
127
 
123
128
  # On inheritage, create +@field_defs+ class variable
124
129
  # @param [Class] klass
125
130
  # @return [void]
126
131
  def inherited(klass)
132
+ super
133
+
127
134
  field_defs = {}
128
135
  @field_defs.each do |k, v|
129
136
  field_defs[k] = v.clone
130
137
  end
131
138
  ordered = @ordered_fields.clone
132
- bf = @bit_fields.clone
139
+ bf = bit_fields.clone
133
140
 
134
141
  klass.class_eval do
135
142
  @ordered_fields = ordered
@@ -158,7 +165,7 @@ module PacketGen
158
165
  # bs[value1] # => Types::Int8
159
166
  # bs.value1 # => Integer
160
167
  # @param [Symbol] name field name
161
- # @param [Object] type class or instance
168
+ # @param [Fieldable] type class or instance
162
169
  # @param [Hash] options Unrecognized options are passed to object builder if
163
170
  # +:builder+ option is not set.
164
171
  # @option options [Object] :default default value. May be a proc. This lambda
@@ -172,44 +179,22 @@ module PacketGen
172
179
  # Define enumeration: hash's keys are +String+, and values are +Integer+.
173
180
  # @return [void]
174
181
  def define_field(name, type, options={})
175
- define = []
176
- if type < Types::Enum
177
- define << "def #{name}; self[:#{name}].to_i; end"
178
- define << "def #{name}=(val) self[:#{name}].value = val; end"
179
- else
180
- define << "def #{name}\n" \
181
- " if self[:#{name}].respond_to?(:to_human) && self[:#{name}].respond_to?(:from_human)\n" \
182
- " self[:#{name}].to_human\n" \
183
- " else\n" \
184
- " self[:#{name}]\n" \
185
- " end\n" \
186
- 'end'
187
- define << "def #{name}=(val)\n" \
188
- " if self[:#{name}].respond_to?(:to_human) && self[:#{name}].respond_to?(:from_human)\n" \
189
- " self[:#{name}].from_human val\n" \
190
- " else\n" \
191
- " self[:#{name}].read val\n" \
192
- " end\n" \
193
- 'end'
194
- end
195
-
196
- define.delete_at(1) if instance_methods.include? "#{name}=".to_sym
197
- define.delete_at(0) if instance_methods.include? name
198
- class_eval define.join("\n")
182
+ fields << name
199
183
  field_defs[name] = FieldDef.new(type,
200
184
  options.delete(:default),
201
185
  options.delete(:builder),
202
186
  options.delete(:optional),
203
187
  options.delete(:enum),
204
188
  options)
205
- fields << name
189
+
190
+ add_methods(name, type)
206
191
  end
207
192
 
208
193
  # Define a field, before another one
209
194
  # @param [Symbol,nil] other field name to create a new one before. If +nil+,
210
195
  # new field is appended.
211
196
  # @param [Symbol] name field name to create
212
- # @param [Object] type class or instance
197
+ # @param [Fieldable] type class or instance
213
198
  # @param [Hash] options See {.define_field}.
214
199
  # @return [void]
215
200
  # @see .define_field
@@ -228,7 +213,7 @@ module PacketGen
228
213
  # @param [Symbol,nil] other field name to create a new one after. If +nil+,
229
214
  # new field is appended.
230
215
  # @param [Symbol] name field name to create
231
- # @param [Object] type class or instance
216
+ # @param [Fieldable] type class or instance
232
217
  # @param [Hash] options See {.define_field}.
233
218
  # @return [void]
234
219
  # @see .define_field
@@ -262,12 +247,12 @@ module PacketGen
262
247
  # @raise [ArgumentError] unknown +field+
263
248
  # @since 2.8.4
264
249
  def update_field(field, options)
265
- raise ArgumentError, "unkown #{field} field for #{self}" unless field_defs.key?(field)
250
+ check_existence_of field
251
+
252
+ %i[default builder optional enum].each do |property|
253
+ field_defs_property_from(field, property, options)
254
+ end
266
255
 
267
- field_defs[field].default = options.delete(:default) if options.key?(:default)
268
- field_defs[field].builder = options.delete(:builder) if options.key?(:builder)
269
- field_defs[field].optional = options.delete(:optional) if options.key?(:optional)
270
- field_defs[field].enum = options.delete(:enum) if options.key?(:enum)
271
256
  field_defs[field].options.merge!(options)
272
257
  end
273
258
 
@@ -289,61 +274,29 @@ module PacketGen
289
274
  # subclass)
290
275
  # @param [Array] args list of bitfield names. Name may be followed
291
276
  # by bitfield size. If no size is given, 1 bit is assumed.
277
+ # @raise [ArgumentError] unknown +attr+
292
278
  # @return [void]
293
279
  def define_bit_fields_on(attr, *args)
294
- attr_def = field_defs[attr]
295
- raise ArgumentError, "unknown #{attr} field" if attr_def.nil?
280
+ check_existence_of attr
296
281
 
297
- type = attr_def.type
282
+ type = field_defs[attr].type
298
283
  raise TypeError, "#{attr} is not a PacketGen::Types::Int" unless type < Types::Int
299
284
 
300
285
  total_size = type.new.width * 8
301
286
  idx = total_size - 1
302
287
 
303
- field = args.shift
304
- while field
288
+ until args.empty?
289
+ field = args.shift
305
290
  next unless field.is_a? Symbol
306
291
 
307
- size = if args.first.is_a? Integer
308
- args.shift
309
- else
310
- 1
311
- end
292
+ size = size_from(args)
293
+
312
294
  unless field == :_
313
- shift = idx - (size - 1)
314
- field_mask = (2**size - 1) << shift
315
- clear_mask = (2**total_size - 1) & (~field_mask & (2**total_size - 1))
316
-
317
- if size == 1
318
- class_eval <<-METHODS
319
- def #{field}?
320
- val = (self[:#{attr}].to_i & #{field_mask}) >> #{shift}
321
- val != 0
322
- end
323
- def #{field}=(v)
324
- val = v ? 1 : 0
325
- self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask}
326
- self[:#{attr}].value |= val << #{shift}
327
- end
328
- METHODS
329
- else
330
- class_eval <<-METHODS
331
- def #{field}
332
- (self[:#{attr}].to_i & #{field_mask}) >> #{shift}
333
- end
334
- def #{field}=(v)
335
- self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask}
336
- self[:#{attr}].value |= (v & #{2**size - 1}) << #{shift}
337
- end
338
- METHODS
339
- end
340
-
341
- @bit_fields[attr] = {} if @bit_fields[attr].nil?
342
- @bit_fields[attr][field] = size
295
+ add_bit_methods(attr, field, size, total_size, idx)
296
+ register_bit_field_size(attr, field, size)
343
297
  end
344
298
 
345
299
  idx -= size
346
- field = args.shift
347
300
  end
348
301
  end
349
302
 
@@ -352,7 +305,7 @@ module PacketGen
352
305
  # @return [void]
353
306
  # @since 2.8.4
354
307
  def remove_bit_fields_on(attr)
355
- fields = @bit_fields.delete(attr)
308
+ fields = bit_fields.delete(attr)
356
309
  return if fields.nil?
357
310
 
358
311
  fields.each do |field, size|
@@ -360,6 +313,98 @@ module PacketGen
360
313
  undef_method(size == 1 ? "#{field}?" : field)
361
314
  end
362
315
  end
316
+
317
+ private
318
+
319
+ def add_methods(name, type)
320
+ define = []
321
+ if type < Types::Enum
322
+ define << "def #{name}; self[:#{name}].to_i; end"
323
+ define << "def #{name}=(val) self[:#{name}].value = val; end"
324
+ else
325
+ define << "def #{name}\n" \
326
+ " to_and_from_human?(:#{name}) ? self[:#{name}].to_human : self[:#{name}]\n" \
327
+ 'end'
328
+ define << "def #{name}=(val)\n" \
329
+ " to_and_from_human?(:#{name}) ? self[:#{name}].from_human(val) : self[:#{name}].read(val)\n" \
330
+ 'end'
331
+ end
332
+
333
+ define.delete_at(1) if instance_methods.include? "#{name}=".to_sym
334
+ define.delete_at(0) if instance_methods.include? name
335
+ class_eval define.join("\n")
336
+ end
337
+
338
+ def add_bit_methods(attr, name, size, total_size, idx)
339
+ shift = idx - (size - 1)
340
+
341
+ if size == 1
342
+ add_single_bit_methods(attr, name, size, total_size, shift)
343
+ else
344
+ add_multibit_methods(attr, name, size, total_size, shift)
345
+ end
346
+ end
347
+
348
+ def compute_field_mask(size, shift)
349
+ (2**size - 1) << shift
350
+ end
351
+
352
+ def compute_clear_mask(total_size, field_mask)
353
+ (2**total_size - 1) & (~field_mask & (2**total_size - 1))
354
+ end
355
+
356
+ def add_single_bit_methods(attr, name, size, total_size, shift)
357
+ field_mask = compute_field_mask(size, shift)
358
+ clear_mask = compute_clear_mask(total_size, field_mask)
359
+
360
+ class_eval <<-METHODS
361
+ def #{name}?
362
+ val = (self[:#{attr}].to_i & #{field_mask}) >> #{shift}
363
+ val != 0
364
+ end
365
+ def #{name}=(v)
366
+ val = v ? 1 : 0
367
+ self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask}
368
+ self[:#{attr}].value |= val << #{shift}
369
+ end
370
+ METHODS
371
+ end
372
+
373
+ def add_multibit_methods(attr, name, size, total_size, shift)
374
+ field_mask = compute_field_mask(size, shift)
375
+ clear_mask = compute_clear_mask(total_size, field_mask)
376
+
377
+ class_eval <<-METHODS
378
+ def #{name}
379
+ (self[:#{attr}].to_i & #{field_mask}) >> #{shift}
380
+ end
381
+ def #{name}=(v)
382
+ self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask}
383
+ self[:#{attr}].value |= (v & #{2**size - 1}) << #{shift}
384
+ end
385
+ METHODS
386
+ end
387
+
388
+ def register_bit_field_size(attr, field, size)
389
+ bit_fields[attr] = {} if bit_fields[attr].nil?
390
+ bit_fields[attr][field] = size
391
+ end
392
+
393
+ def field_defs_property_from(field, property, options)
394
+ field_defs[field].send("#{property}=", options.delete(property)) if options.key?(property)
395
+ end
396
+
397
+ def size_from(args)
398
+ if args.first.is_a? Integer
399
+ args.shift
400
+ else
401
+ 1
402
+ end
403
+ end
404
+
405
+ def check_existence_of(field)
406
+ raise ArgumentError, "unknown #{field} field for #{self}" unless field_defs.key?(field)
407
+ end
363
408
  end
364
409
 
365
410
  # Create a new fields object
@@ -369,36 +414,13 @@ module PacketGen
369
414
  @fields = {}
370
415
  @optional_fields = {}
371
416
 
372
- field_defs = self.class.field_defs
373
417
  self.class.fields.each do |field|
374
- type = field_defs[field].type
375
- default = field_defs[field].default
376
- default = default.to_proc.call(self) if default.is_a?(Proc)
377
- builder = field_defs[field].builder
378
- optional = field_defs[field].optional
379
- enum = field_defs[field].enum
380
- field_options = field_defs[field].options
381
-
382
- @fields[field] = if builder
383
- builder.call(self, type)
384
- elsif enum
385
- type.new(enum)
386
- elsif !field_options.empty?
387
- type.new(field_options)
388
- else
389
- type.new
390
- end
391
-
392
- value = options[field] || default
393
- if value.class <= type
394
- @fields[field] = value
395
- elsif @fields[field].respond_to? :from_human
396
- @fields[field].from_human(value)
397
- end
398
-
399
- @optional_fields[field] = optional if optional
418
+ build_field field
419
+ initialize_value field, options[field]
420
+ initialize_optional field
400
421
  end
401
- self.class.class_eval { @bit_fields }.each do |_, hsh|
422
+
423
+ self.class.bit_fields.each do |_, hsh|
402
424
  hsh.each_key do |bit_field|
403
425
  self.send "#{bit_field}=", options[bit_field] if options[bit_field]
404
426
  end
@@ -407,7 +429,7 @@ module PacketGen
407
429
 
408
430
  # Get field object
409
431
  # @param [Symbol] field
410
- # @return [Object]
432
+ # @return [Fieldable]
411
433
  def [](field)
412
434
  @fields[field]
413
435
  end
@@ -427,6 +449,7 @@ module PacketGen
427
449
  end
428
450
 
429
451
  # Get all optional field name
452
+ # @return[Array<Symbol>,nil]
430
453
  def optional_fields
431
454
  @optional_fields.keys
432
455
  end
@@ -457,11 +480,7 @@ module PacketGen
457
480
  next unless present?(field)
458
481
 
459
482
  obj = self[field].read str[start..-1]
460
- if self[field].respond_to? :sz
461
- start += self[field].sz
462
- else
463
- start = str.size
464
- end
483
+ start += self[field].sz
465
484
  self[field] = obj unless obj == self[field]
466
485
  end
467
486
 
@@ -528,7 +547,7 @@ module PacketGen
528
547
  # @return [Hash,nil] keys: bit fields, values: their size in bits
529
548
  # @since 2.8.3
530
549
  def bits_on(field)
531
- self.class.class_eval { @bit_fields }[field]
550
+ self.class.bit_fields[field]
532
551
  end
533
552
 
534
553
  private
@@ -547,6 +566,54 @@ module PacketGen
547
566
  def force_binary(str)
548
567
  PacketGen.force_binary(str)
549
568
  end
569
+
570
+ # @param [Symbol] attr attribute
571
+ # @return [Boolean] +tru+e if #from_human and #to_human are both defined for given attribute
572
+ def to_and_from_human?(attr)
573
+ self[attr].respond_to?(:to_human) && self[attr].respond_to?(:from_human)
574
+ end
575
+
576
+ def field_defs
577
+ self.class.field_defs
578
+ end
579
+
580
+ # rubocop:disable Metrics/AbcSize
581
+ def build_field(field)
582
+ type = field_defs[field].type
583
+
584
+ @fields[field] = if field_defs[field].builder
585
+ field_defs[field].builder.call(self, type)
586
+ elsif field_defs[field].enum
587
+ type.new(field_defs[field].enum)
588
+ elsif !field_defs[field].options.empty?
589
+ type.new(field_defs[field].options)
590
+ else
591
+ type.new
592
+ end
593
+ end
594
+ # rubocop:enable Metrics/AbcSize
595
+
596
+ def initialize_value(field, val)
597
+ type = field_defs[field].type
598
+ default = field_defs[field].default
599
+ default = default.to_proc.call(self) if default.is_a?(Proc)
600
+
601
+ value = val || default
602
+ if value.class <= type
603
+ @fields[field] = value
604
+ elsif @fields[field].respond_to? :from_human
605
+ @fields[field].from_human(value)
606
+ else
607
+ @fields[field].read(value)
608
+ end
609
+ end
610
+
611
+ def initialize_optional(field)
612
+ optional = field_defs[field].optional
613
+ @optional_fields[field] = optional if optional
614
+ end
550
615
  end
551
616
  end
552
617
  end
618
+
619
+ # rubocop:enable Metrics/ClassLength