packetgen 3.1.5 → 3.1.6

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