packetgen 3.1.5 → 3.1.6

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/bin/pgconsole +1 -0
  3. data/lib/packetgen.rb +2 -2
  4. data/lib/packetgen/capture.rb +9 -0
  5. data/lib/packetgen/header/base.rb +68 -70
  6. data/lib/packetgen/header/dhcpv6/duid.rb +3 -1
  7. data/lib/packetgen/header/dhcpv6/option.rb +3 -1
  8. data/lib/packetgen/header/dns/name.rb +18 -7
  9. data/lib/packetgen/header/dns/question.rb +2 -0
  10. data/lib/packetgen/header/dot11.rb +23 -6
  11. data/lib/packetgen/header/dot11/data.rb +9 -5
  12. data/lib/packetgen/header/eap.rb +3 -2
  13. data/lib/packetgen/header/eth.rb +4 -8
  14. data/lib/packetgen/header/http/headers.rb +3 -4
  15. data/lib/packetgen/header/http/request.rb +32 -17
  16. data/lib/packetgen/header/http/response.rb +1 -1
  17. data/lib/packetgen/header/http/verbs.rb +1 -1
  18. data/lib/packetgen/header/igmpv3/group_record.rb +2 -0
  19. data/lib/packetgen/header/ip.rb +27 -26
  20. data/lib/packetgen/header/ip/addr.rb +2 -3
  21. data/lib/packetgen/header/ip/option.rb +4 -4
  22. data/lib/packetgen/header/ipv6/addr.rb +1 -2
  23. data/lib/packetgen/header/mldv2/mcast_address_record.rb +2 -0
  24. data/lib/packetgen/header/ospfv2/ls_request.rb +2 -0
  25. data/lib/packetgen/header/ospfv2/lsa.rb +6 -0
  26. data/lib/packetgen/header/ospfv2/lsa_header.rb +2 -1
  27. data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +2 -0
  28. data/lib/packetgen/header/ospfv3/ls_request.rb +2 -0
  29. data/lib/packetgen/header/ospfv3/lsa.rb +2 -0
  30. data/lib/packetgen/header/ospfv3/lsa_header.rb +2 -1
  31. data/lib/packetgen/header/snmp.rb +3 -2
  32. data/lib/packetgen/header/tcp/option.rb +8 -6
  33. data/lib/packetgen/packet.rb +7 -3
  34. data/lib/packetgen/pcapng.rb +11 -11
  35. data/lib/packetgen/pcapng/block.rb +15 -2
  36. data/lib/packetgen/pcapng/epb.rb +22 -15
  37. data/lib/packetgen/pcapng/file.rb +164 -81
  38. data/lib/packetgen/pcapng/idb.rb +7 -9
  39. data/lib/packetgen/pcapng/shb.rb +35 -28
  40. data/lib/packetgen/pcapng/spb.rb +16 -12
  41. data/lib/packetgen/pcapng/unknown_block.rb +3 -11
  42. data/lib/packetgen/pcaprub_wrapper.rb +8 -8
  43. data/lib/packetgen/types.rb +1 -0
  44. data/lib/packetgen/types/abstract_tlv.rb +2 -3
  45. data/lib/packetgen/types/array.rb +15 -9
  46. data/lib/packetgen/types/cstring.rb +38 -17
  47. data/lib/packetgen/types/fieldable.rb +65 -0
  48. data/lib/packetgen/types/fields.rb +91 -56
  49. data/lib/packetgen/types/int.rb +2 -2
  50. data/lib/packetgen/types/int_string.rb +7 -2
  51. data/lib/packetgen/types/length_from.rb +18 -10
  52. data/lib/packetgen/types/oui.rb +1 -2
  53. data/lib/packetgen/types/string.rb +45 -8
  54. data/lib/packetgen/types/tlv.rb +1 -2
  55. data/lib/packetgen/utils.rb +2 -2
  56. data/lib/packetgen/version.rb +1 -1
  57. metadata +13 -12
  58. data/lib/packetgen/inspectable.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 476cbc2bd2b9fb254ea40fe0a07a4d703a0fc36e4accc823de7e83b640d95a2d
4
- data.tar.gz: 375f31ea90589b2b0c0b257b8a3efaa66715e8b369c542124fe3dcac283d9221
3
+ metadata.gz: d8959dbe60df80490d1ac31eaf40b05a206860bf6bed306997a66ca9c77dfb0b
4
+ data.tar.gz: 4615a1084f86e4b0ab216b3766dbde7d1b0b2b1e3c2e6b0d2e1a63aba1ff7bd6
5
5
  SHA512:
6
- metadata.gz: c518ff72cf70227c8f9ef38cce97ba5036eb3229051d38172ba947898b9051f508670d1e0106bac0f5edf577fe1450d5f71db557aa6968b7e3998945a87177d7
7
- data.tar.gz: 9382d6f8a7542c8988dec0aaf92940f1518885133bf9e7c835478e787546309410c7e7bcfb4525c13fb7479a9cad9a7ece3e30a3d3c6bbb4f081c1cc48b7f02e
6
+ metadata.gz: 636f0dcea926b57cb7ec7a824744dfbcab9c6ddbb7f6749d8fda8f63fec410d20dcf199f362ae63878104725e94c7075d17f94b3f0dc8458b3d975e9521343da
7
+ data.tar.gz: 50e679400b1f882fbe2d3bc9e3ba5e01bb24dbe4a83b3372b999cbe0d1565703a7fc6afc08c437900e23b92c549c46ad422e3e76140254034c8840ba3a8ecb2e
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'packetgen'
4
5
  require 'packetgen/config'
@@ -32,6 +32,7 @@ module PacketGen
32
32
  attr_reader :hdr
33
33
 
34
34
  def initialize(prev_hdr, hdr)
35
+ super()
35
36
  @prev_hdr = prev_hdr
36
37
  @hdr = hdr
37
38
  end
@@ -66,7 +67,7 @@ module PacketGen
66
67
  # @yieldparam [Packet] packet
67
68
  # @return [Array<Packet>]
68
69
  def self.capture(**kwargs)
69
- Packet.capture(kwargs) { |packet| yield packet if block_given? }
70
+ Packet.capture(**kwargs) { |packet| yield packet if block_given? }
70
71
  end
71
72
 
72
73
  # Shortcut for {Packet.read}
@@ -121,7 +122,6 @@ end
121
122
 
122
123
  require 'packetgen/deprecation'
123
124
  require 'packetgen/inspect'
124
- require 'packetgen/inspectable'
125
125
  require 'packetgen/types'
126
126
  require 'packetgen/pcapng'
127
127
  require 'packetgen/pcap'
@@ -15,6 +15,8 @@ module PacketGen
15
15
 
16
16
  attr_reader :filter, :cap_thread, :snaplen, :promisc, :monitor
17
17
 
18
+ # rubocop:disable Metrics/ParameterLists
19
+
18
20
  public
19
21
 
20
22
  # Get captured packets.
@@ -86,6 +88,9 @@ module PacketGen
86
88
 
87
89
  private
88
90
 
91
+ # rubocop:disable Metrics/CyclomaticComplexity
92
+ # rubocop:disable Metrics/PerceivedComplexity
93
+
89
94
  def set_options(iface, max, timeout, filter, promisc, parse, snaplen, monitor)
90
95
  @max = max if max
91
96
  @filter = filter unless filter.nil?
@@ -97,6 +102,10 @@ module PacketGen
97
102
  @monitor = monitor unless monitor.nil?
98
103
  end
99
104
 
105
+ # rubocop:enable Metrics/CyclomaticComplexity
106
+ # rubocop:enable Metrics/PerceivedComplexity
107
+ # rubocop:enable Metrics/ParameterLists
108
+
100
109
  def capture_args
101
110
  h = { iface: iface, filter: filter, monitor: monitor }
102
111
  h[:snaplen] = snaplen unless snaplen.nil?
@@ -99,10 +99,8 @@ module PacketGen
99
99
 
100
100
  # each iterator
101
101
  # @return [void]
102
- def each
103
- @bindings.each do |b|
104
- yield b
105
- end
102
+ def each(&block)
103
+ @bindings.each(&block)
106
104
  end
107
105
 
108
106
  # @return [Boolean]
@@ -144,74 +142,74 @@ module PacketGen
144
142
  klass.class_eval { @known_headers = {} }
145
143
  end
146
144
 
147
- # Bind a upper header to current one.
148
- # @param [Class] header_klass header class to bind to current class
149
- # @param [Hash] args current class fields and their value when +header_klass+
150
- # is embedded in current class.
151
- #
152
- # Given value may be a lambda, whose alone argument is the value extracted
153
- # from header field (or +nil+ when lambda is used to set field while adding
154
- # a header).
155
- #
156
- # Special key +procs+ may be used to set 2 lambdas, the former to set
157
- # fields, the latter to check bindings. This may be used when multiple and
158
- # non-trivial checks should be made.
159
- # @return [void]
160
- # @example Basic examples
161
- # # Bind Header2 to Header1 when field1 from Header1 has a value of 42
162
- # Header1.bind Header2, field1: 42
163
- # # Bind Header3 to Header1 when field1 from Header1 has a value of 43
164
- # # and field2 has value 43 or 44
165
- # Header1.bind Header3, field1: 43, field2: 43
166
- # Header1.bind Header3, field1: 43, field2: 44
167
- # @example Defining a binding on a field using a lambda.
168
- # # Bind Header4 to Header1 when field1 from Header1 has a value
169
- # # greater or equal to 44. When adding a Header2 to a Header1
170
- # # with Packet#add, force value to 44.
171
- # Header1.bind Header4, field1: ->(v) { v.nil? ? 44 : v >= 44 }
172
- # @example Defining a binding using procs key
173
- # # Bind Header5 to Header1 when field1 from Header1 has a value of 41
174
- # # and first two bytes of header1's body are null.
175
- # # When adding a Header2 to a Header1 with Packet#add, force value to 44.
176
- # Header1.bind Header5, procs: [->(hdr) { hdr.field1 = 41 }
177
- # ->(hdr) { hdr.field1 == 41 && hdr.body[0..1] == "\x00\x00" }]
178
- # @since 2.7.0
179
- def self.bind(header_klass, args={})
180
- if @known_headers[header_klass].nil?
181
- bindings = Bindings.new
182
- @known_headers[header_klass] = bindings
183
- else
184
- bindings = @known_headers[header_klass]
185
- end
186
- bindings.new_set
187
- args.each do |key, value|
188
- bindings << if key == :procs
189
- ProcBinding.new(value)
190
- else
191
- Binding.new(key, value)
192
- end
193
- end
194
- end
145
+ class <<self
146
+ # @api private
147
+ # Get known headers
148
+ # @return [Hash] keys: header classes, values: hashes
149
+ attr_reader :known_headers
195
150
 
196
- # Helper method to calculate length of +hdr+ and set its +length+ field.
197
- # To be used by +#calc_length+ in Base subclasses.
198
- # @param [Base] hdr
199
- # @param [Boolean] header_in_size if +true+ header is included in length,
200
- # if +false+, only +body+ is taken into account
201
- def self.calculate_and_set_length(hdr, header_in_size: true)
202
- length = if header_in_size
203
- hdr.sz
204
- else
205
- hdr[:body].sz
206
- end
207
- hdr.length = length
208
- end
151
+ # Bind a upper header to current one.
152
+ # @param [Class] header_klass header class to bind to current class
153
+ # @param [Hash] args current class fields and their value when +header_klass+
154
+ # is embedded in current class.
155
+ #
156
+ # Given value may be a lambda, whose alone argument is the value extracted
157
+ # from header field (or +nil+ when lambda is used to set field while adding
158
+ # a header).
159
+ #
160
+ # Special key +procs+ may be used to set 2 lambdas, the former to set
161
+ # fields, the latter to check bindings. This may be used when multiple and
162
+ # non-trivial checks should be made.
163
+ # @return [void]
164
+ # @example Basic examples
165
+ # # Bind Header2 to Header1 when field1 from Header1 has a value of 42
166
+ # Header1.bind Header2, field1: 42
167
+ # # Bind Header3 to Header1 when field1 from Header1 has a value of 43
168
+ # # and field2 has value 43 or 44
169
+ # Header1.bind Header3, field1: 43, field2: 43
170
+ # Header1.bind Header3, field1: 43, field2: 44
171
+ # @example Defining a binding on a field using a lambda.
172
+ # # Bind Header4 to Header1 when field1 from Header1 has a value
173
+ # # greater or equal to 44. When adding a Header2 to a Header1
174
+ # # with Packet#add, force value to 44.
175
+ # Header1.bind Header4, field1: ->(v) { v.nil? ? 44 : v >= 44 }
176
+ # @example Defining a binding using procs key
177
+ # # Bind Header5 to Header1 when field1 from Header1 has a value of 41
178
+ # # and first two bytes of header1's body are null.
179
+ # # When adding a Header2 to a Header1 with Packet#add, force value to 44.
180
+ # Header1.bind Header5, procs: [->(hdr) { hdr.field1 = 41 }
181
+ # ->(hdr) { hdr.field1 == 41 && hdr.body[0..1] == "\x00\x00" }]
182
+ # @since 2.7.0
183
+ def bind(header_klass, args={})
184
+ if @known_headers[header_klass].nil?
185
+ bindings = Bindings.new
186
+ @known_headers[header_klass] = bindings
187
+ else
188
+ bindings = @known_headers[header_klass]
189
+ end
190
+ bindings.new_set
191
+ args.each do |key, value|
192
+ bindings << if key == :procs
193
+ ProcBinding.new(value)
194
+ else
195
+ Binding.new(key, value)
196
+ end
197
+ end
198
+ end
209
199
 
210
- # @api private
211
- # Get known headers
212
- # @return [Hash] keys: header classes, values: hashes
213
- def self.known_headers
214
- @known_headers
200
+ # Helper method to calculate length of +hdr+ and set its +length+ field.
201
+ # To be used by +#calc_length+ in Base subclasses.
202
+ # @param [Base] hdr
203
+ # @param [Boolean] header_in_size if +true+ header is included in length,
204
+ # if +false+, only +body+ is taken into account
205
+ def calculate_and_set_length(hdr, header_in_size: true)
206
+ length = if header_in_size
207
+ hdr.sz
208
+ else
209
+ hdr[:body].sz
210
+ end
211
+ hdr.length = length
212
+ end
215
213
  end
216
214
 
217
215
  # @see Types::Fields#initialize
@@ -11,6 +11,8 @@ module PacketGen
11
11
  # @abstract Base class for DUID (DHCP Unique ID)
12
12
  # @author Sylvain Daubert
13
13
  class DUID < Types::Fields
14
+ include Types::Fieldable
15
+
14
16
  TYPES = {
15
17
  'DUID-LLT' => 1,
16
18
  'DUID-EN' => 2,
@@ -34,7 +36,7 @@ module PacketGen
34
36
  # @param [String] str
35
37
  # @return [DUID]
36
38
  def read(str)
37
- if self.class == DUID
39
+ if self.instance_of?(DUID)
38
40
  super
39
41
  case type
40
42
  when 1
@@ -17,6 +17,8 @@ module PacketGen
17
17
  # field to replace it by specific option field(s).
18
18
  # @author Sylvain Daubert
19
19
  class Option < Types::Fields
20
+ include Types::Fieldable
21
+
20
22
  # @!attribute type
21
23
  # 16-bit option type
22
24
  # @return [Integer]
@@ -85,7 +87,7 @@ module PacketGen
85
87
  # Get human-readable {#type}
86
88
  # @return [String]
87
89
  def human_type
88
- if self.class == Option
90
+ if self.instance_of?(Option)
89
91
  "option#{type}"
90
92
  else
91
93
  self.class.to_s.sub(/.*::/, '')
@@ -43,28 +43,32 @@ module PacketGen
43
43
  self << Types::IntString.new
44
44
  end
45
45
 
46
+ # Clear name
47
+ # @return [void]
48
+ def clear
49
+ super
50
+ @pointer = nil
51
+ @pointer_name = nil
52
+ end
53
+
46
54
  # Read a sequence of label from a string
47
55
  # @param [String] str binary string
48
56
  # @return [Name] self
49
57
  def read(str)
50
- @pointer = nil
51
- @pointer_name = nil
52
58
  clear
53
59
  return self if str.nil?
54
60
 
55
61
  PacketGen.force_binary str
56
62
  start = 0
57
63
  loop do
58
- index = str[start, 2].unpack('n').first
64
+ index = str[start, 2].unpack1('n')
59
65
  if pointer? index
60
66
  # Pointer on another label
61
67
  @pointer = str[start, 2]
62
68
  break
63
69
  else
64
- label = Types::IntString.new
65
- label.read(str[start..-1])
70
+ label = add_label_from(str[start..-1])
66
71
  start += label.sz
67
- self << label
68
72
  break if label.length.zero? || str[start..-1].length.zero?
69
73
  end
70
74
  end
@@ -101,7 +105,7 @@ module PacketGen
101
105
  return nil unless @pointer
102
106
  return @pointer_name if @pointer_name
103
107
 
104
- index = @pointer.unpack('n').first
108
+ index = @pointer.unpack1('n')
105
109
  mask = ~POINTER_MASK & 0xffff
106
110
  ptr = index & mask
107
111
  name = Name.new
@@ -112,6 +116,13 @@ module PacketGen
112
116
  def record_from_hash(_hsh)
113
117
  raise NotImplementedError, "not supported by #{self.class}"
114
118
  end
119
+
120
+ def add_label_from(str)
121
+ label = Types::IntString.new
122
+ label.read(str)
123
+ self << label
124
+ label
125
+ end
115
126
  end
116
127
  end
117
128
  end
@@ -11,6 +11,8 @@ module PacketGen
11
11
  # DNS Question
12
12
  # @author Sylvain Daubert
13
13
  class Question < Types::Fields
14
+ include Types::Fieldable
15
+
14
16
  # Ressource Record types
15
17
  TYPES = {
16
18
  'A' => 1,
@@ -280,7 +280,7 @@ module PacketGen
280
280
  def read(str)
281
281
  fcs = Dot11.fcs?
282
282
 
283
- if self.class == Dot11
283
+ if self.instance_of? Dot11
284
284
  return self if str.nil?
285
285
 
286
286
  force_binary str
@@ -323,7 +323,7 @@ module PacketGen
323
323
 
324
324
  # @return [String]
325
325
  def inspect
326
- str = if self.class == Dot11
326
+ str = if self.instance_of? Dot11
327
327
  Inspect.dashed_line("#{self.class} #{human_type}", 1)
328
328
  elsif self.respond_to? :human_subtype
329
329
  Inspect.dashed_line("#{self.class} #{human_subtype}", 1)
@@ -360,27 +360,44 @@ module PacketGen
360
360
 
361
361
  private
362
362
 
363
- def define_applicable_fields
363
+ def remove_from_applicable_fields(fields)
364
+ fields = [fields] unless fields.is_a? Array
365
+ @applicable_fields -= fields
366
+ end
367
+
368
+ def handle_mac4
364
369
  if to_ds? && from_ds?
365
370
  @applicable_fields[6, 0] = :mac4 unless @applicable_fields.include? :mac4
366
371
  else
367
- @applicable_fields -= %i[mac4]
372
+ remove_from_applicable_fields :mac4
368
373
  end
374
+ end
375
+
376
+ def handle_ht_ctrl
369
377
  if order?
370
378
  unless @applicable_fields.include? :ht_ctrl
371
379
  idx = @applicable_fields.index(:body)
372
380
  @applicable_fields[idx, 0] = :ht_ctrl
373
381
  end
374
382
  else
375
- @applicable_fields -= %i[ht_ctrl]
383
+ remove_from_applicable_fields %i[ht_ctrl]
376
384
  end
385
+ end
386
+
387
+ def handle_fcs
377
388
  if Dot11.fcs?
378
389
  @applicable_fields << :fcs unless @applicable_fields.include? :fcs
379
390
  else
380
- @applicable_fields -= %i[fcs]
391
+ remove_from_applicable_fields :fcs
381
392
  end
382
393
  end
383
394
 
395
+ def define_applicable_fields
396
+ handle_mac4
397
+ handle_ht_ctrl
398
+ handle_fcs
399
+ end
400
+
384
401
  def private_read(str, fcs)
385
402
  self[:frame_ctrl].read str[0, 2]
386
403
  define_applicable_fields
@@ -44,22 +44,22 @@ module PacketGen
44
44
  case ds
45
45
  when 0
46
46
  # MAC1: RA/DA, MAC2: TA/SA
47
- self[:mac1], self[:mac2] = self[:mac2], self[:mac1]
47
+ invert_mac :mac1, :mac2
48
48
  when 1
49
49
  # MAC1: RA/BSSID, MAC2: TA/SA, MAC3: DA
50
- self[:mac2], self[:mac1] = self[:mac1], self[:mac2]
50
+ invert_mac :mac1, :mac2
51
51
  self.to_ds = false
52
52
  self.from_ds = true
53
53
  when 2
54
54
  # MAC1: RA/DA, MAC2: BSSID, MAC3: SA or BSSID
55
- self[:mac1], self[:mac2] = self[:mac2], self[:mac1]
55
+ invert_mac :mac1, :mac2
56
56
  self.to_ds = true
57
57
  self.from_ds = false
58
58
  when 3
59
59
  # MAC1: RA, MAC2: TA
60
- self[:mac1], self[:mac2] = self[:mac2], self[:mac1]
60
+ invert_mac :mac1, :mac2
61
61
  # MAC3: DA, MAC4: SA
62
- self[:mac4], self[:mac3] = self[:mac3], self[:mac4]
62
+ invert_mac :mac3, :mac4
63
63
  end
64
64
  self
65
65
  end
@@ -135,6 +135,10 @@ module PacketGen
135
135
  @applicable_fields -= %i[qos_ctrl]
136
136
  end
137
137
  end
138
+
139
+ def invert_mac(mac1, mac2)
140
+ self[mac1], self[mac2] = self[mac2], self[mac1]
141
+ end
138
142
  end
139
143
  end
140
144
  end
@@ -95,7 +95,8 @@ module PacketGen
95
95
  # This field is present only for Request or Response packets,
96
96
  # with type different from Expanded Types (254).
97
97
  # @return [Integer] 8-bit request or response type
98
- define_field :type, Types::Int8Enum, enum: TYPES,
98
+ define_field :type, Types::Int8Enum,
99
+ enum: TYPES,
99
100
  optional: ->(eap) { eap.type? }
100
101
 
101
102
  # @!attribute vendor_id
@@ -131,7 +132,7 @@ module PacketGen
131
132
  # may be determined
132
133
  def read(str)
133
134
  super str
134
- return self unless self.class == EAP
135
+ return self unless self.instance_of?(EAP)
135
136
  return self unless type?
136
137
 
137
138
  case self.type