packetgen 2.8.7 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +0 -1
  3. data/README.md +5 -4
  4. data/lib/packetgen.rb +6 -12
  5. data/lib/packetgen/capture.rb +43 -39
  6. data/lib/packetgen/config.rb +0 -1
  7. data/lib/packetgen/deprecation.rb +1 -1
  8. data/lib/packetgen/header.rb +9 -9
  9. data/lib/packetgen/header/asn1_base.rb +10 -10
  10. data/lib/packetgen/header/base.rb +42 -101
  11. data/lib/packetgen/header/dhcp/option.rb +5 -11
  12. data/lib/packetgen/header/dhcpv6/duid.rb +2 -0
  13. data/lib/packetgen/header/dhcpv6/option.rb +2 -19
  14. data/lib/packetgen/header/dhcpv6/options.rb +7 -0
  15. data/lib/packetgen/header/dns.rb +5 -23
  16. data/lib/packetgen/header/dns/name.rb +1 -0
  17. data/lib/packetgen/header/dns/qdsection.rb +1 -0
  18. data/lib/packetgen/header/dns/question.rb +3 -7
  19. data/lib/packetgen/header/dns/rr.rb +3 -0
  20. data/lib/packetgen/header/dns/rrsection.rb +1 -0
  21. data/lib/packetgen/header/dot11.rb +1 -17
  22. data/lib/packetgen/header/dot1x.rb +1 -0
  23. data/lib/packetgen/header/eap.rb +4 -7
  24. data/lib/packetgen/header/eth.rb +2 -0
  25. data/lib/packetgen/header/http/headers.rb +3 -0
  26. data/lib/packetgen/header/http/request.rb +5 -4
  27. data/lib/packetgen/header/http/response.rb +5 -4
  28. data/lib/packetgen/header/icmp.rb +6 -0
  29. data/lib/packetgen/header/icmpv6.rb +6 -0
  30. data/lib/packetgen/header/igmpv3/mq.rb +2 -0
  31. data/lib/packetgen/header/ip.rb +32 -30
  32. data/lib/packetgen/header/ip/addr.rb +1 -0
  33. data/lib/packetgen/header/ip/option.rb +23 -20
  34. data/lib/packetgen/header/ip/options.rb +11 -24
  35. data/lib/packetgen/header/ipv6.rb +45 -34
  36. data/lib/packetgen/header/ipv6/addr.rb +2 -0
  37. data/lib/packetgen/header/ipv6/hop_by_hop.rb +7 -31
  38. data/lib/packetgen/header/mdns.rb +1 -0
  39. data/lib/packetgen/header/mldv2/mlq.rb +2 -0
  40. data/lib/packetgen/header/ospfv2/lsa.rb +15 -25
  41. data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +1 -1
  42. data/lib/packetgen/header/ospfv3/lsa.rb +8 -25
  43. data/lib/packetgen/header/snmp.rb +2 -0
  44. data/lib/packetgen/header/tcp.rb +23 -2
  45. data/lib/packetgen/header/tcp/option.rb +51 -52
  46. data/lib/packetgen/header/tcp/options.rb +17 -52
  47. data/lib/packetgen/header/tftp.rb +3 -0
  48. data/lib/packetgen/header/udp.rb +8 -0
  49. data/lib/packetgen/packet.rb +119 -102
  50. data/lib/packetgen/pcapng/block.rb +4 -10
  51. data/lib/packetgen/pcapng/epb.rb +4 -4
  52. data/lib/packetgen/pcapng/file.rb +7 -3
  53. data/lib/packetgen/pcapng/idb.rb +2 -2
  54. data/lib/packetgen/pcapng/shb.rb +3 -3
  55. data/lib/packetgen/pcapng/spb.rb +1 -8
  56. data/lib/packetgen/pcapng/unknown_block.rb +0 -7
  57. data/lib/packetgen/types.rb +1 -0
  58. data/lib/packetgen/types/array.rb +73 -71
  59. data/lib/packetgen/types/cstring.rb +1 -1
  60. data/lib/packetgen/types/enum.rb +3 -3
  61. data/lib/packetgen/types/fields.rb +66 -106
  62. data/lib/packetgen/types/int.rb +9 -5
  63. data/lib/packetgen/types/length_from.rb +45 -0
  64. data/lib/packetgen/types/oui.rb +2 -0
  65. data/lib/packetgen/types/string.rb +10 -16
  66. data/lib/packetgen/types/tlv.rb +7 -15
  67. data/lib/packetgen/utils.rb +8 -8
  68. data/lib/packetgen/utils/arp_spoofer.rb +1 -2
  69. data/lib/packetgen/version.rb +1 -1
  70. metadata +3 -21
  71. data/lib/packetgen/header/crypto.rb +0 -62
  72. data/lib/packetgen/header/esp.rb +0 -413
  73. data/lib/packetgen/header/ike.rb +0 -243
  74. data/lib/packetgen/header/ike/auth.rb +0 -165
  75. data/lib/packetgen/header/ike/cert.rb +0 -76
  76. data/lib/packetgen/header/ike/certreq.rb +0 -66
  77. data/lib/packetgen/header/ike/id.rb +0 -99
  78. data/lib/packetgen/header/ike/ke.rb +0 -79
  79. data/lib/packetgen/header/ike/nonce.rb +0 -40
  80. data/lib/packetgen/header/ike/notify.rb +0 -176
  81. data/lib/packetgen/header/ike/payload.rb +0 -315
  82. data/lib/packetgen/header/ike/sa.rb +0 -561
  83. data/lib/packetgen/header/ike/sk.rb +0 -261
  84. data/lib/packetgen/header/ike/ts.rb +0 -270
  85. data/lib/packetgen/header/ike/vendor_id.rb +0 -39
  86. data/lib/packetgen/header/netbios.rb +0 -20
  87. data/lib/packetgen/header/netbios/datagram.rb +0 -105
  88. data/lib/packetgen/header/netbios/name.rb +0 -67
  89. data/lib/packetgen/header/netbios/session.rb +0 -64
@@ -37,13 +37,6 @@ module PacketGen
37
37
  @fields.key?(:options) && @fields[:options].sz > 0
38
38
  end
39
39
 
40
- # @deprecated Use {#options?} instead.
41
- # @return [Boolean]
42
- def has_options?
43
- Deprecation.deprecated(self.class, __method__, 'options?')
44
- options?
45
- end
46
-
47
40
  # Calculate block length and update :block_len and block_len2 fields
48
41
  # @return [void]
49
42
  def recalc_block_len
@@ -56,8 +49,8 @@ module PacketGen
56
49
  # @return [void]
57
50
  def pad_field(*fields)
58
51
  fields.each do |field|
59
- unless (@fields[field].size % 4).zero?
60
- @fields[field] << "\x00" * (4 - (@fields[field].size % 4))
52
+ unless (@fields[field].sz % 4).zero?
53
+ @fields[field] << "\x00" * (4 - (@fields[field].sz % 4))
61
54
  end
62
55
  end
63
56
  end
@@ -72,13 +65,14 @@ module PacketGen
72
65
  unless %i[little big].include? endian
73
66
  raise ArgumentError, "unknown endianness for #{self.class}"
74
67
  end
68
+
75
69
  @endian = endian
76
70
  @fields.each { |_f, v| v.endian = endian if v.is_a?(Types::Int) }
77
71
  endian
78
72
  end
79
73
 
80
74
  def check_len_coherency
81
- unless self[:block_len].to_i == self[:block_len2].to_i
75
+ unless self.block_len == self.block_len2
82
76
  raise InvalidFileError, 'Incoherency in Block length'
83
77
  end
84
78
  end
@@ -96,10 +96,10 @@ module PacketGen
96
96
  self[:tsl].read io.read(4)
97
97
  self[:cap_len].read io.read(4)
98
98
  self[:orig_len].read io.read(4)
99
- self[:data].read io.read(self[:cap_len].to_i)
99
+ self[:data].read io.read(self.cap_len)
100
100
  data_pad_len = (4 - (self[:cap_len].to_i % 4)) % 4
101
101
  io.read data_pad_len
102
- options_len = self[:block_len].to_i - self[:cap_len].to_i - data_pad_len
102
+ options_len = self.block_len - self.cap_len - data_pad_len
103
103
  options_len -= MIN_SIZE
104
104
  self[:options].read io.read(options_len)
105
105
  self[:block_len2].read io.read(4)
@@ -111,7 +111,7 @@ module PacketGen
111
111
  # Return timestamp as a Time object
112
112
  # @return [Time]
113
113
  def timestamp
114
- Time.at((self[:tsh].to_i << 32 | self[:tsl].to_i) * ts_resol)
114
+ Time.at((self.tsh << 32 | self.tsl) * ts_resol)
115
115
  end
116
116
 
117
117
  # Return the object as a String
@@ -125,7 +125,7 @@ module PacketGen
125
125
  private
126
126
 
127
127
  def ts_resol
128
- if @interface.nil?
128
+ if !defined?(@interface) || @interface.nil?
129
129
  1E-6
130
130
  else
131
131
  @interface.ts_resol
@@ -66,10 +66,14 @@ module PacketGen
66
66
  end
67
67
 
68
68
  return unless blk
69
+
69
70
  count = 0
70
71
  @sections.each do |section|
71
72
  section.interfaces.each do |intf|
72
- intf.packets.each { |pkt| count += 1; yield pkt }
73
+ intf.packets.each do |pkt|
74
+ count += 1
75
+ yield pkt
76
+ end
73
77
  end
74
78
  end
75
79
  count
@@ -347,8 +351,8 @@ module PacketGen
347
351
  shb << block
348
352
  block.section = shb
349
353
  when EPB
350
- shb.interfaces[block.interface_id.to_i] << block
351
- block.interface = shb.interfaces[block.interface_id.to_i]
354
+ shb.interfaces[block.interface_id] << block
355
+ block.interface = shb.interfaces[block.interface_id]
352
356
  when SPB
353
357
  shb.interfaces[0] << block
354
358
  block.interface = shb.interfaces[0]
@@ -83,7 +83,7 @@ module PacketGen
83
83
  self[:link_type].read io.read(2)
84
84
  self[:reserved].read io.read(2)
85
85
  self[:snaplen].read io.read(4)
86
- self[:options].read io.read(self[:block_len].to_i - MIN_SIZE)
86
+ self[:options].read io.read(self.block_len - MIN_SIZE)
87
87
  self[:block_len2].read io.read(4)
88
88
 
89
89
  check_len_coherency
@@ -105,7 +105,7 @@ module PacketGen
105
105
  if @options_decoded && !force
106
106
  @ts_resol
107
107
  else
108
- packstr = @endian == :little ? 'v' : 'n'
108
+ packstr = endian == :little ? 'v' : 'n'
109
109
  idx = 0
110
110
  options = self[:options]
111
111
 
@@ -130,7 +130,7 @@ module PacketGen
130
130
  self[:ver_major].read io.read(2)
131
131
  self[:ver_minor].read io.read(2)
132
132
  self[:section_len].read io.read(8)
133
- self[:options].read io.read(self[:block_len].to_i - MIN_SIZE)
133
+ self[:options].read io.read(self.block_len - MIN_SIZE)
134
134
  self[:block_len2].read io.read(4)
135
135
 
136
136
  check_len_coherency
@@ -149,8 +149,8 @@ module PacketGen
149
149
  # @return [String]
150
150
  def to_s
151
151
  body = @interfaces.map(&:to_s).join
152
- unless self[:section_len].to_i == SECTION_LEN_UNDEFINED
153
- self.section_len.value = body.size
152
+ unless self.section_len == SECTION_LEN_UNDEFINED
153
+ self.section_len = body.size
154
154
  end
155
155
  pad_field :options
156
156
  recalc_block_len
@@ -56,13 +56,6 @@ module PacketGen
56
56
  false
57
57
  end
58
58
 
59
- # @deprecated Use {#options?} instead.
60
- # @return [false]
61
- def has_options?
62
- Deprecation.deprecated(self.class, __method__, 'options?')
63
- options?
64
- end
65
-
66
59
  # Reads a String or a IO to populate the object
67
60
  # @param [::String,IO] str_or_io
68
61
  # @return [self]
@@ -90,7 +83,7 @@ module PacketGen
90
83
  self[:block_len2].read io.read(4)
91
84
 
92
85
  check_len_coherency
93
- self.type = self[:type] || PcapNG::IDB_TYPE.to_i
86
+ self.type ||= PcapNG::IDB_TYPE.to_i
94
87
  self
95
88
  end
96
89
 
@@ -40,13 +40,6 @@ module PacketGen
40
40
  false
41
41
  end
42
42
 
43
- # @deprecated Use {#options?} instead.
44
- # @return [false]
45
- def has_options?
46
- Deprecation.deprecated(self.class, __method__, 'options?')
47
- options?
48
- end
49
-
50
43
  # Reads a String or a IO to populate the object
51
44
  # @param [::String,IO] str_or_io
52
45
  # @return [self]
@@ -9,6 +9,7 @@ module PacketGen
9
9
  end
10
10
  end
11
11
 
12
+ require_relative 'types/length_from'
12
13
  require_relative 'types/int'
13
14
  require_relative 'types/enum'
14
15
  require_relative 'types/string'
@@ -5,6 +5,8 @@
5
5
 
6
6
  # frozen_string_literal: true
7
7
 
8
+ require 'forwardable'
9
+
8
10
  module PacketGen
9
11
  module Types
10
12
  # @abstract Base class to define set of {Fields} subclasses.
@@ -14,20 +16,66 @@ module PacketGen
14
16
  #
15
17
  # A default method is defined by {Array}: it calls constructor of class defined
16
18
  # by {.set_of}.
19
+ #
20
+ # == #real_type
21
+ # Subclasses should define private method +#real_type+ is {.set_of} type
22
+ # may be subclassed. This method should return real class to use. It
23
+ # takes an only argument, which is of type given by {.set_of}.
24
+ #
25
+ # Default behaviour of this method is to argument's class.
26
+ #
17
27
  # @author Sylvain Daubert
18
28
  class Array
29
+ extend Forwardable
30
+
31
+ # @!method [](index)
32
+ # Return the element at +index+.
33
+ # @param [integer] index
34
+ # @return [Object]
35
+ # @!method clear
36
+ # Clear array.
37
+ # @return [void]
38
+ # @!method each
39
+ # Calls the given block once for each element in self, passing that
40
+ # element as a parameter. Returns the array itself.
41
+ # @return [Array]
42
+ # @method empty?
43
+ # Return +true+ if contains no element.
44
+ # @return [Booelan]
45
+ # @!method first
46
+ # Return first element
47
+ # @return [Object]
48
+ # @!method last
49
+ # Return last element.
50
+ # @return [Object]
51
+ # @!method size
52
+ # Get number of element in array
53
+ # @return [Integer]
54
+ def_delegators :@array, :[], :clear, :each, :empty?, :first, :last, :size
55
+ alias length size
56
+
19
57
  include Enumerable
58
+ include LengthFrom
20
59
 
21
60
  # Separator used in {#to_human}.
22
61
  # May be ovverriden by subclasses
23
62
  HUMAN_SEPARATOR = ','
24
63
 
25
- # Define type of objects in set. Used by {#read} and {#push}.
26
- # @param [Class] klass
27
- # @return [void]
28
64
  # rubocop:disable Naming/AccessorMethodName
29
- def self.set_of(klass)
30
- @klass = klass
65
+ class <<self
66
+ # Get class set with {.set_of}.
67
+ # @return [Class]
68
+ # @since 3.0.0
69
+ def set_of_klass
70
+ @klass
71
+ end
72
+
73
+ # Define type of objects in set. Used by {#read} and {#push}.
74
+ # @param [Class] klass
75
+ # @return [void]
76
+ def set_of(klass)
77
+ @klass = klass
78
+ end
31
79
  end
32
80
  # rubocop:enable Naming/AccessorMethodName
33
81
 
@@ -36,6 +84,7 @@ module PacketGen
36
84
  def initialize(options={})
37
85
  @counter = options[:counter]
38
86
  @array = []
87
+ initialize_length_from(options)
39
88
  end
40
89
 
41
90
  # Initialize array for copy:
@@ -44,26 +93,13 @@ module PacketGen
44
93
  @array = @array.dup
45
94
  end
46
95
 
47
- # Return the element at +index+.
48
- # @param [integer] index
49
- # @return [Object]
50
- def [](index)
51
- @array[index]
52
- end
53
-
54
96
  def ==(other)
55
- case other
56
- when Array
57
- @array == other.to_a
58
- else
59
- @array == other
60
- end
61
- end
62
-
63
- # Clear array.
64
- # @return [void]
65
- def clear
66
- @array.clear
97
+ @array == case other
98
+ when Array
99
+ other.to_a
100
+ else
101
+ other
102
+ end
67
103
  end
68
104
 
69
105
  # Clear array. Reset associated counter, if any.
@@ -91,31 +127,6 @@ module PacketGen
91
127
  deleted
92
128
  end
93
129
 
94
- # Calls the given block once for each element in self, passing that
95
- # element as a parameter. Returns the array itself.
96
- # @return [Array]
97
- def each
98
- @array.each { |el| yield el }
99
- end
100
-
101
- # Return +true+ if contains no element.
102
- # @return [Booelan]
103
- def empty?
104
- @array.empty?
105
- end
106
-
107
- # Return first element
108
- # @return [Object]
109
- def first
110
- @array.first
111
- end
112
-
113
- # Return last element.
114
- # @return [Object]
115
- def last
116
- @array.last
117
- end
118
-
119
130
  # @abstract depend on private method +#record_from_hash+ which should be
120
131
  # declared by subclasses.
121
132
  # Add an object to this array
@@ -150,10 +161,13 @@ module PacketGen
150
161
  clear
151
162
  return self if str.nil?
152
163
  return self if @counter && @counter.to_i.zero?
153
- force_binary str
154
- klass = self.class.class_eval { @klass }
164
+
165
+ str = read_with_length_from(str)
166
+ klass = self.class.set_of_klass
155
167
  until str.empty?
156
168
  obj = klass.new.read(str)
169
+ real_klass = real_type(obj)
170
+ obj = real_klass.new.read(str) unless real_klass == klass
157
171
  @array << obj
158
172
  str.slice!(0, obj.sz)
159
173
  break if @counter && self.size == @counter.to_i
@@ -161,13 +175,6 @@ module PacketGen
161
175
  self
162
176
  end
163
177
 
164
- # Get number of element in array
165
- # @return [Integer]
166
- def size
167
- @array.size
168
- end
169
- alias length size
170
-
171
178
  # Get size in bytes
172
179
  # @return [Integer]
173
180
  def sz
@@ -192,22 +199,17 @@ module PacketGen
192
199
  @array.map(&:to_human).join(self.class::HUMAN_SEPARATOR)
193
200
  end
194
201
 
195
- # Force binary encoding for +str+
196
- # @param [String] str
197
- # @return [String] binary encoded string
198
- def force_binary(str)
199
- PacketGen.force_binary str
200
- end
201
-
202
202
  private
203
203
 
204
204
  def record_from_hash(obj)
205
- obj_klass = self.class.class_eval { @klass }
206
- if obj_klass
207
- obj_klass.new(obj)
208
- else
209
- raise NotImplementedError, 'class should define #record_from_hash or declare type of elements in set with .set_of'
210
- end
205
+ obj_klass = self.class.set_of_klass
206
+ return obj_klass.new(obj) if obj_klass
207
+
208
+ raise NotImplementedError, 'class should define #record_from_hash or declare type of elements in set with .set_of'
209
+ end
210
+
211
+ def real_type(obj)
212
+ obj.class
211
213
  end
212
214
  end
213
215
 
@@ -32,7 +32,7 @@ module PacketGen
32
32
  # get null-terminated string
33
33
  # @return [String]
34
34
  def to_s
35
- if @static_length.is_a? Integer
35
+ if defined?(@static_length) && @static_length.is_a?(Integer)
36
36
  if self.size >= @static_length
37
37
  s = self[0, @static_length]
38
38
  s[-1] = "\x00".encode(s.encoding)
@@ -45,9 +45,10 @@ module PacketGen
45
45
  end
46
46
 
47
47
  # Setter for value attribute
48
- # @param [Integer, String,nil] value value as an Integer or as a String
48
+ # @param [#to_i, String,nil] value value as an Integer or as a String
49
49
  # from enumration
50
50
  # @return [Integer]
51
+ # @raise [ArgumentError] String value is unknown
51
52
  def value=(value)
52
53
  ival = case value
53
54
  when NilClass
@@ -56,8 +57,7 @@ module PacketGen
56
57
  raise ArgumentError, "#{value.inspect} not in enumeration" unless @enum.key? value
57
58
  @enum[value]
58
59
  else
59
- raise ArgumentError, "#{value.inspect} not in enumeration" unless @enum.value? value
60
- value
60
+ value.to_i
61
61
  end
62
62
  @value = ival
63
63
  end
@@ -49,7 +49,7 @@ module PacketGen
49
49
  # define_field :type, PacketGen::Types::Int16le
50
50
  # # define a string field
51
51
  # define_field :body, PacketGen::Types::String
52
- # # define afield using a complex type (Fields subclass)
52
+ # # define a field using a complex type (Fields subclass)
53
53
  # define_field :mac_addr, PacketGen::Eth::MacAddr
54
54
  #
55
55
  # This example creates six methods on our Fields subclass: +#type+, +#type=+,
@@ -59,20 +59,22 @@ module PacketGen
59
59
  # * +:default+ gives default field value. It may be a simple value (an Integer
60
60
  # for an Int field, for example) or a lambda,
61
61
  # * +:builder+ to give a builder/constructor lambda to create field. The lambda
62
- # takes one argument: {Fields} subclass object owning field,
62
+ # takes 2 argument: {Fields} subclass object owning field, and type class as passes
63
+ # as second argument to .define_field,
63
64
  # * +:optional+ to define this field as optional. This option takes a lambda
64
- # parameter used to say if this field is present or not,
65
+ # parameter used to say if this field is present or not. The lambda takes an argument
66
+ # ({Fields} subclass object owning field),
65
67
  # * +:enum+ to define Hash enumeration for an {Enum} type.
66
68
  # For example:
67
69
  # # 32-bit integer field defaulting to 1
68
70
  # define_field :type, PacketGen::Types::Int32, default: 1
69
71
  # # 16-bit integer field, created with a random value. Each instance of this
70
72
  # # object will have a different value.
71
- # define_field :id, PacketGen::Types::Int16, default: ->{ rand(65535) }
73
+ # define_field :id, PacketGen::Types::Int16, default: ->(obj) { rand(65535) }
72
74
  # # a size field
73
75
  # define_field :body_size, PacketGen::Types::Int16
74
76
  # # String field which length is taken from body_size field
75
- # define_field :body, PacketGen::Types::String, builder: ->(obj, type) { type.new('', length_from: obj[:body_size]) }
77
+ # define_field :body, PacketGen::Types::String, builder: ->(obj, type) { type.new(length_from: obj[:body_size]) }
76
78
  # # 16-bit enumeration type. As :default not specified, default to first value of enum
77
79
  # define_field :type_class, PacketGen::Types::Int16Enum, enum: { 'class1' => 1, 'class2' => 2}
78
80
  # # optional field. Only present if another field has a certain value
@@ -92,8 +94,19 @@ module PacketGen
92
94
  # to access Boolean RSV, MF and DF flags from +frag+ field,
93
95
  # * +#fragment_offset+ and +#fragment_offset=+ to access 13-bit integer fragment
94
96
  # offset subfield from +frag+ field.
97
+ #
98
+ # == Creating a new field class from another one
99
+ # Some methods may help in this case:
100
+ # * {.define_field_before} to define a new field before an existing one,
101
+ # * {.define_field_after} to define a new field after an existing onr,
102
+ # * {.remove_field} to remove an existing field,
103
+ # * {.uptade_fied} to change options of a field (but not its type),
104
+ # * {.remove_bit_fields_on} to remove a bit fields definition.
105
+ #
95
106
  # @author Sylvain Daubert
96
107
  class Fields
108
+ # @private
109
+ FieldDef = Struct.new(:type, :default, :builder, :optional, :enum, :options)
97
110
  # @private field names, ordered as they were declared
98
111
  @ordered_fields = []
99
112
  # @private field definitions
@@ -112,6 +125,7 @@ module PacketGen
112
125
  end
113
126
  ordered = @ordered_fields.clone
114
127
  bf = @bit_fields.clone
128
+
115
129
  klass.class_eval do
116
130
  @ordered_fields = ordered
117
131
  @field_defs = field_defs
@@ -157,26 +171,32 @@ module PacketGen
157
171
  if type < Types::Enum
158
172
  define << "def #{name}; self[:#{name}].to_i; end"
159
173
  define << "def #{name}=(val) self[:#{name}].value = val; end"
160
- elsif type < Types::Int
161
- define << "def #{name}; self[:#{name}].to_i; end"
162
- define << "def #{name}=(val) self[:#{name}].read val; end"
163
- elsif type.instance_methods.include?(:to_human) &&
164
- type.instance_methods.include?(:from_human)
165
- define << "def #{name}; self[:#{name}].to_human; end"
166
- define << "def #{name}=(val) self[:#{name}].from_human val; end"
167
174
  else
168
- define << "def #{name}; self[:#{name}]; end\n"
169
- define << "def #{name}=(val) self[:#{name}].read val; end"
175
+ define << "def #{name}\n" \
176
+ " if self[:#{name}].respond_to?(:to_human) && self[:#{name}].respond_to?(:from_human)\n" \
177
+ " self[:#{name}].to_human\n" \
178
+ " else\n" \
179
+ " self[:#{name}]\n" \
180
+ " end\n" \
181
+ "end"
182
+ define << "def #{name}=(val)\n" \
183
+ " if self[:#{name}].respond_to?(:to_human) && self[:#{name}].respond_to?(:from_human)\n" \
184
+ " self[:#{name}].from_human val\n" \
185
+ " else\n" \
186
+ " self[:#{name}].read val\n" \
187
+ " end\n" \
188
+ "end"
170
189
  end
171
190
 
172
191
  define.delete(1) if type.instance_methods.include? "#{name}=".to_sym
173
192
  define.delete(0) if type.instance_methods.include? name
174
193
  class_eval define.join("\n")
175
- @field_defs[name] = [type, options.delete(:default),
176
- options.delete(:builder),
177
- options.delete(:optional),
178
- options.delete(:enum),
179
- options]
194
+ @field_defs[name] = FieldDef.new(type,
195
+ options.delete(:default),
196
+ options.delete(:builder),
197
+ options.delete(:optional),
198
+ options.delete(:enum),
199
+ options)
180
200
  fields << name
181
201
  end
182
202
 
@@ -229,16 +249,6 @@ module PacketGen
229
249
  undef_method "#{name}=" if method_defined?("#{name}=")
230
250
  end
231
251
 
232
- # Delete a previously defined field
233
- # @param [Symbol] name
234
- # @return [void]
235
- # @deprecated Use {.remove_field} instead.
236
- # @since 2.8.4 deprecated
237
- def delete_field(name)
238
- Deprecation.deprecated(self, __method__, 'remove_field', klass_method: true)
239
- remove_field name
240
- end
241
-
242
252
  # Update a previously defined field
243
253
  # @param [Symbol] field field name to create
244
254
  # @param [Hash] options See {.define_field}.
@@ -249,11 +259,11 @@ module PacketGen
249
259
  def update_field(field, options)
250
260
  raise ArgumentError, "unkown #{field} field for #{self}" unless @field_defs.key?(field)
251
261
 
252
- @field_defs[field][1] = options.delete(:default) if options.key?(:default)
253
- @field_defs[field][2] = options.delete(:builder) if options.key?(:builder)
254
- @field_defs[field][3] = options.delete(:optional) if options.key?(:optional)
255
- @field_defs[field][4] = options.delete(:enum) if options.key?(:enum)
256
- @field_defs[field][5].merge!(options)
262
+ @field_defs[field].default = options.delete(:default) if options.key?(:default)
263
+ @field_defs[field].builder = options.delete(:builder) if options.key?(:builder)
264
+ @field_defs[field].optional = options.delete(:optional) if options.key?(:optional)
265
+ @field_defs[field].enum = options.delete(:enum) if options.key?(:enum)
266
+ @field_defs[field].options.merge!(options)
257
267
  end
258
268
 
259
269
  # Define a bitfield on given attribute
@@ -279,7 +289,7 @@ module PacketGen
279
289
  attr_def = @field_defs[attr]
280
290
  raise ArgumentError, "unknown #{attr} field" if attr_def.nil?
281
291
 
282
- type = attr_def.first
292
+ type = attr_def.type
283
293
  unless type < Types::Int
284
294
  raise TypeError, "#{attr} is not a PacketGen::Types::Int"
285
295
  end
@@ -344,12 +354,12 @@ module PacketGen
344
354
 
345
355
  fields.each do |field, size|
346
356
  undef_method "#{field}="
347
- undef_method(size == 1 ? "#{field}?" : "#{field}")
357
+ undef_method(size == 1 ? "#{field}?" : field)
348
358
  end
349
359
  end
350
360
  end
351
361
 
352
- # Create a new header object
362
+ # Create a new fields object
353
363
  # @param [Hash] options Keys are symbols. They should have name of object
354
364
  # attributes, as defined by {.define_field} and by {.define_bit_fields_on}.
355
365
  def initialize(options={})
@@ -358,9 +368,14 @@ module PacketGen
358
368
 
359
369
  field_defs = self.class.class_eval { @field_defs }
360
370
  self.class.fields.each do |field|
361
- ary = field_defs[field]
362
- type, default, builder, optional, enum, field_options = ary
371
+ type = field_defs[field].type
372
+ default = field_defs[field].default
363
373
  default = default.to_proc.call(self) if default.is_a?(Proc)
374
+ builder = field_defs[field].builder
375
+ optional = field_defs[field].optional
376
+ enum = field_defs[field].enum
377
+ field_options = field_defs[field].options
378
+
364
379
  @fields[field] = if builder
365
380
  builder.call(self, type)
366
381
  elsif enum
@@ -374,17 +389,6 @@ module PacketGen
374
389
  value = options[field] || default
375
390
  if value.class <= type
376
391
  @fields[field] = value
377
- elsif type < Types::Enum
378
- case value
379
- when ::String
380
- @fields[field].value = value
381
- else
382
- @fields[field].read(value)
383
- end
384
- elsif type < Types::Int
385
- @fields[field].read(value)
386
- elsif type <= Types::String
387
- @fields[field].read(value)
388
392
  elsif @fields[field].respond_to? :from_human
389
393
  @fields[field].from_human(value)
390
394
  end
@@ -430,12 +434,6 @@ module PacketGen
430
434
  @optional_fields.key? field
431
435
  end
432
436
 
433
- # @deprecated Use {#optional?} instead.
434
- def is_optional?(field)
435
- Deprecation.deprecated(self.class, __method__, 'optional?', klass_method: true)
436
- optional? field
437
- end
438
-
439
437
  # Say if an optional field is present
440
438
  # @return [Boolean]
441
439
  def present?(field)
@@ -444,14 +442,6 @@ module PacketGen
444
442
  @optional_fields[field].call(self)
445
443
  end
446
444
 
447
- # Say if an optional field is present
448
- # @return [Boolean]
449
- # @deprecated Use {#present?} instead.
450
- def is_present?(field)
451
- Deprecation.deprecated(self.class, __method__, 'present?', klass_method: true)
452
- present? field
453
- end
454
-
455
445
  # Populate object from a binary string
456
446
  # @param [String] str
457
447
  # @return [Fields] self
@@ -463,17 +453,10 @@ module PacketGen
463
453
  fields.each do |field|
464
454
  next unless present?(field)
465
455
 
466
- obj = nil
467
- if self[field].respond_to? :width
468
- width = self[field].width
469
- obj = self[field].read str[start, width]
470
- start += width
471
- elsif self[field].respond_to? :sz
472
- obj = self[field].read str[start..-1]
473
- size = self[field].sz
474
- start += size
456
+ obj = self[field].read str[start..-1]
457
+ if self[field].respond_to? :sz
458
+ start += self[field].sz
475
459
  else
476
- obj = self[field].read str[start..-1]
477
460
  start = str.size
478
461
  end
479
462
  self[field] = obj unless obj == self[field]
@@ -496,7 +479,7 @@ module PacketGen
496
479
  next if attr == :body
497
480
  next unless present?(attr)
498
481
 
499
- result = yield(attr)if block_given?
482
+ result = yield(attr) if block_given?
500
483
  str << (result || Inspect.inspect_attribute(attr, self[attr], 1))
501
484
  end
502
485
  str
@@ -521,36 +504,6 @@ module PacketGen
521
504
  Hash[fields.map { |f| [f, @fields[f].to_human] }]
522
505
  end
523
506
 
524
- # Used to set body as value of body object.
525
- # @param [String,Int,Fields,nil] value
526
- # @return [void]
527
- # @raise [BodyError] no body on given object
528
- # @raise [ArgumentError] cannot cram +body+ in +:body+ field
529
- # @deprecated
530
- def body=(value)
531
- Deprecation.deprecated(self.class, __method__)
532
- raise BodyError, 'no body field' unless @fields.key? :body
533
-
534
- case body
535
- when ::String
536
- self[:body].read value
537
- when Int, Fields
538
- self[:body] = value
539
- when NilClass
540
- self[:body] = Types::String.new.read('')
541
- else
542
- raise ArgumentError, "Can't cram a #{body.class} in a :body field"
543
- end
544
- end
545
-
546
- # Force str to binary encoding
547
- # @param [String] str
548
- # @return [String]
549
- # @deprecated Will be a private method
550
- def force_binary(str)
551
- PacketGen.force_binary(str)
552
- end
553
-
554
507
  # Get offset of given field in {Fields} structure.
555
508
  # @param [Symbol] field
556
509
  # @return [Integer]
@@ -581,9 +534,16 @@ module PacketGen
581
534
  # @return [void]
582
535
  def initialize_copy(_other)
583
536
  fields = {}
584
- @fields.each { |k,v| fields[k] = v.dup }
537
+ @fields.each { |k, v| fields[k] = v.dup }
585
538
  @fields = fields
586
539
  end
540
+
541
+ # Force str to binary encoding
542
+ # @param [String] str
543
+ # @return [String]
544
+ def force_binary(str)
545
+ PacketGen.force_binary(str)
546
+ end
587
547
  end
588
548
  end
589
549
  end