packetgen 2.8.7 → 3.0.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 (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
@@ -70,6 +70,7 @@ module PacketGen
70
70
  packet.instance_eval "def mdnsize() @headers[#{mdns_idx}].mdnsize; end"
71
71
  return unless packet.is? 'UDP'
72
72
  return unless packet.udp.sport.zero?
73
+
73
74
  packet.udp.sport = UDP_PORT
74
75
  end
75
76
  end
@@ -121,6 +121,8 @@ module PacketGen
121
121
  self[:max_resp_delay].value = MLDv2.encode(value)
122
122
  end
123
123
 
124
+ undef qqic, qqic=
125
+
124
126
  # Get QQIC value
125
127
  # @note May return a different value from value previously set, as a
126
128
  # float encoding is used to encode big values. See {IGMPv3.decode}.
@@ -74,7 +74,7 @@ module PacketGen
74
74
 
75
75
  # @return [String]
76
76
  def to_human
77
- "Link<type:#{type},metric:#{metric},id:#{id},data:#{data}>"
77
+ "<type:#{type},metric:#{metric},id:#{id},data:#{data}>"
78
78
  end
79
79
  end
80
80
 
@@ -129,7 +129,8 @@ module PacketGen
129
129
  # @!attribute routers
130
130
  # List of routers in network
131
131
  # @return [IP::ArrayOfAddr]
132
- define_field :routers, IP::ArrayOfAddr
132
+ define_field :routers, IP::ArrayOfAddr,
133
+ builder: ->(h, t) { t.new(length_from: -> { h.length - 24 }) }
133
134
  end
134
135
 
135
136
  # This class handles external links in {LSAASExternal LSA AS-External payloads}.
@@ -153,6 +154,11 @@ module PacketGen
153
154
  # @!attribute tos
154
155
  # @return [Integer]
155
156
  define_bit_fields_on :u8, :e_flag, :tos, 7
157
+
158
+ # @return [String]
159
+ def to_human
160
+ "<type:#{e_flag? ? 2 : 1},tos:#{tos},metric:#{metric},fwaddr:#{forwarding_addr},tag:#{ext_route_tag}>"
161
+ end
156
162
  end
157
163
 
158
164
  # This class defines a specialized {Types::Array array} to handle series
@@ -176,14 +182,15 @@ module PacketGen
176
182
  # @!attribute externals
177
183
  # List of external destinations
178
184
  # @return [ArrayOfExternal]
179
- define_field :externals, ArrayOfExternal
185
+ define_field :externals, ArrayOfExternal,
186
+ builder: ->(h, t) { t.new(length_from: -> { h.length - 24 }) }
180
187
  end
181
188
 
182
189
  # This class defines a specialized {Types::Array array} to handle series
183
190
  # of {LSA LSAs}. It recognizes known LSA types and infers correct type.
184
191
  # @author Sylvain Daubert
185
192
  class ArrayOfLSA < Types::Array
186
- set_of LSA
193
+ set_of LSAHeader
187
194
 
188
195
  # @param [Hash] options
189
196
  # @option options [Types::Int] counter Int object used as a counter for this set
@@ -194,27 +201,6 @@ module PacketGen
194
201
  @only_headers = options[:only_headers] || false
195
202
  end
196
203
 
197
- # Populate object from a string
198
- # @param [String] str
199
- # @return [self]
200
- def read(str)
201
- clear
202
- return self if str.nil?
203
- return self if @counter && @counter.to_i.zero?
204
- force_binary str
205
- until str.empty?
206
- lsa = LSAHeader.new.read(str)
207
- unless @only_headers
208
- klass = get_lsa_class_by_human_type(lsa.human_type)
209
- lsa = klass.new.read(str[0...lsa.length])
210
- end
211
- self.push lsa
212
- str.slice!(0, lsa.sz)
213
- break if @counter && (self.size == @counter.to_i)
214
- end
215
- self
216
- end
217
-
218
204
  private
219
205
 
220
206
  def record_from_hash(hsh)
@@ -245,6 +231,10 @@ module PacketGen
245
231
  LSA
246
232
  end
247
233
  end
234
+
235
+ def real_type(lsah)
236
+ @only_headers ? lsah.class : get_lsa_class_by_human_type(lsah.human_type)
237
+ end
248
238
  end
249
239
  end
250
240
  end
@@ -33,7 +33,7 @@ module PacketGen
33
33
  # @!attribute prefix
34
34
  # IPv6 Prefix as an array of 32-bit words
35
35
  # @return [Prefix]
36
- define_field :prefix, Types::ArrayOfInt32
36
+ define_field :prefix, Types::ArrayOfInt32, builder: ->(h, t) { t.new(length_from: -> { h.length / 8 }) }
37
37
 
38
38
  # @!attribute dn_opt
39
39
  # This bit controls an inter-area-prefix-LSAs or AS-external-LSAs
@@ -72,7 +72,7 @@ module PacketGen
72
72
  OSPFv3.define_options(self)
73
73
  # @attribute links
74
74
  # @return [ArrayOfLink]
75
- define_field :links, ArrayOfLink
75
+ define_field :links, ArrayOfLink, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:links) }) }
76
76
 
77
77
  # @!attribute nt_flag
78
78
  # @return [Boolean]
@@ -103,7 +103,7 @@ module PacketGen
103
103
  # @!attribute routers
104
104
  # List of routers attached to the link.
105
105
  # @return [IP::ArrayOfAddr]
106
- define_field :routers, IP::ArrayOfAddr
106
+ define_field :routers, IP::ArrayOfAddr, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:routers) }) }
107
107
  end
108
108
 
109
109
  # This class handles OSPFv3 LSA Intra-Area-Prefix payloads.
@@ -175,7 +175,7 @@ module PacketGen
175
175
  # @!attribute prefixes
176
176
  # List of IPv6 prefixes to be associated with the link.
177
177
  # @return [ArrayOfIPv6Prefix]
178
- define_field :prefixes, ArrayOfIPv6Prefix
178
+ define_field :prefixes, ArrayOfIPv6Prefix, builder: ->(h, t) { t.new(counter: h[:prefix_count]) }
179
179
  end
180
180
 
181
181
  # This class defines a specialized {Types::Array array} to handle series
@@ -183,7 +183,7 @@ module PacketGen
183
183
  # and infers correct type.
184
184
  # @author Sylvain Daubert
185
185
  class ArrayOfLSA < Types::Array
186
- set_of LSA
186
+ set_of LSAHeader
187
187
 
188
188
  # @param [Hash] options
189
189
  # @option options [Types::Int] counter Int object used as a counter for this set
@@ -194,27 +194,6 @@ module PacketGen
194
194
  @only_headers = options[:only_headers] || false
195
195
  end
196
196
 
197
- # Populate object from a string
198
- # @param [String] str
199
- # @return [self]
200
- def read(str)
201
- clear
202
- return self if str.nil?
203
- return self if @counter && @counter.to_i.zero?
204
- force_binary str
205
- until str.empty?
206
- lsa = LSAHeader.new.read(str)
207
- unless @only_headers
208
- klass = get_lsa_class_by_human_type(lsa.human_type)
209
- lsa = klass.new.read(str[0...lsa.length])
210
- end
211
- self.push lsa
212
- str.slice!(0, lsa.sz)
213
- break if @counter && (self.size == @counter.to_i)
214
- end
215
- self
216
- end
217
-
218
197
  private
219
198
 
220
199
  def record_from_hash(hsh)
@@ -245,6 +224,10 @@ module PacketGen
245
224
  LSA
246
225
  end
247
226
  end
227
+
228
+ def real_type(lsah)
229
+ @only_headers ? lsah.class : get_lsa_class_by_human_type(lsah.human_type)
230
+ end
248
231
  end
249
232
  end
250
233
  end
@@ -259,6 +259,7 @@ module PacketGen
259
259
  super
260
260
  data.chosen = options[:chosen_pdu] if options[:chosen_pdu]
261
261
  return unless options[:pdu]
262
+
262
263
  data.root.value[data.chosen] = data.root.chosen_value.class.new(options[:pdu])
263
264
  end
264
265
 
@@ -307,6 +308,7 @@ module PacketGen
307
308
  def added_to_packet(packet)
308
309
  return unless packet.is? 'UDP'
309
310
  return unless packet.udp.sport.zero?
311
+
310
312
  packet.udp.sport = packet.udp.dport
311
313
  end
312
314
  end
@@ -7,6 +7,26 @@
7
7
 
8
8
  module PacketGen
9
9
  module Header
10
+ # TCP header ({https://tools.ietf.org/html/rfc793 RFC 793})
11
+ # 0 1 2 3
12
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
13
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14
+ # | Source Port | Destination Port |
15
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16
+ # | Sequence Number |
17
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18
+ # | Acknowledgment Number |
19
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20
+ # | Data | |U|A|P|R|S|F| |
21
+ # | Offset| Reserved |R|C|S|S|Y|I| Window |
22
+ # | | |G|K|H|T|N|N| |
23
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24
+ # | Checksum | Urgent Pointer |
25
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26
+ # | Options | Padding |
27
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28
+ # | data |
29
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
10
30
  # A TCP header consists of:
11
31
  # * a source port ({#sport}, {Types::Int16} type),
12
32
  # * a destination port ({#dport}, +Int16+ type),
@@ -78,7 +98,7 @@ module PacketGen
78
98
  # @!attribute seqnum
79
99
  # 32-bit TCP sequence number
80
100
  # @return [Integer]
81
- define_field :seqnum, Types::Int32, default: ->(h) { rand(2**32) }
101
+ define_field :seqnum, Types::Int32, default: ->(_) { rand(2**32) }
82
102
  # @!attribute acknum
83
103
  # 32-bit TCP acknowledgement number
84
104
  # @return [Integer]
@@ -174,6 +194,7 @@ module PacketGen
174
194
  # @return [self]
175
195
  def read(str)
176
196
  return self if str.nil?
197
+
177
198
  force_binary str
178
199
  self[:sport].read str[0, 2]
179
200
  self[:dport].read str[2, 2]
@@ -212,7 +233,7 @@ module PacketGen
212
233
  shift = Inspect.shift_level
213
234
  str = Inspect.inspect_attribute(attr, self[attr])
214
235
  doff = Inspect.int_dec_hex(data_offset, 1)
215
- str<< shift << Inspect::FMT_ATTR % ['', 'data_offset', doff]
236
+ str << shift << Inspect::FMT_ATTR % ['', 'data_offset', doff]
216
237
  str << shift << Inspect::FMT_ATTR % ['', 'reserved', reserved]
217
238
  flags = ''.dup
218
239
  %w[ns cwr ece urg ack psh rst syn fin].each do |fl|
@@ -10,7 +10,7 @@ module PacketGen
10
10
  class TCP
11
11
  # Base class to describe a TCP option
12
12
  # @author Sylvain Daubert
13
- class Option < Base
13
+ class Option < Types::Fields
14
14
  # EOL option value
15
15
  EOL_KIND = 0
16
16
  # NOP option value
@@ -37,10 +37,11 @@ module PacketGen
37
37
  # @!attribute length
38
38
  # Option length
39
39
  # @return [Integer] 8-bit option length
40
- define_field :length, Types::Int8
40
+ define_field :length, Types::Int8, optional: ->(h) { h.length? }
41
41
  # @!attribute value
42
42
  # @return [Integer,String] option value
43
- define_field :value, Types::String
43
+ define_field :value, Types::String, optional: ->(h) { h.length? && h.length > 2 },
44
+ builder: ->(h, t) { t.new(length_from: -> { h.length - 2 }) }
44
45
 
45
46
  # @param [hash] options
46
47
  # @option options [Integer] :kind
@@ -59,40 +60,21 @@ module PacketGen
59
60
  end
60
61
  self[:value] = klass.new(options[:value])
61
62
  when NilClass
62
- self[:value] = Types::String.new
63
+ # Nothing to do
63
64
  else
64
65
  self[:value] = Types::String.new.read(options[:value])
65
66
  self[:length].read(self[:value].sz + 2) unless options[:length]
66
67
  end
67
68
  end
68
69
 
69
- # Read a TCP option from a string
70
- # @param [String] str binary string
71
- # @return [self]
72
- def read(str)
73
- return self if str.nil?
74
- force_binary str
75
- self[:kind].read str[0, 1]
76
- if str[1, 1]
77
- self[:length].read str[1, 1]
78
- self[:value].read str[2, length - 2] if str[2, 1] && length > 2
79
- end
80
- self
81
- end
82
-
83
70
  # Say if given option has a length field.
84
71
  # @return [Boolean]
85
72
  # @since 2.7.0
86
73
  def length?
87
- self[:kind].value && kind >= 2
74
+ kind >= 2
88
75
  end
89
76
 
90
- # @deprecated Use {#length?}.
91
- # @return [Boolean]
92
- def has_length?
93
- Deprecation.deprecated(self.class, __method__, 'length?')
94
- length?
95
- end
77
+ undef value
96
78
 
97
79
  # Getter for value attribute
98
80
  # @return [String, Integer]
@@ -105,19 +87,32 @@ module PacketGen
105
87
  end
106
88
  end
107
89
 
90
+ alias old_set_value value=
91
+ # Setter for value attribute
92
+ # @param[String,Integer]
93
+ # @return [String, Integer]
94
+ def value=(v)
95
+ case self[:value]
96
+ when Types::Int
97
+ self.length = 2 + self[:value].sz
98
+ when String
99
+ self.length = 2 + Types::String.new.read(v).sz
100
+ end
101
+ self[:value].read v
102
+ v
103
+ end
104
+
108
105
  # Get binary string
109
106
  # @return [String]
110
107
  def to_s
111
- str = self[:kind].to_s
112
- str << self[:length].to_s unless self[:length].value.nil?
113
- str << self[:value].to_s if length > 2
114
- str
108
+ self.length = 2 + self[:value].sz if length?
109
+ super
115
110
  end
116
111
 
117
112
  # Get option as a human readable string
118
113
  # @return [String]
119
114
  def to_human
120
- str = self.class == Option ? "unk-#{kind}" : self.class.to_s.sub(/.*::/, '')
115
+ str = self.class == Option ? +"unk-#{kind}" : self.class.to_s.sub(/.*::/, '')
121
116
  if (length > 2) && !self[:value].to_s.empty?
122
117
  str << ":#{self[:value].to_s.inspect}"
123
118
  end
@@ -135,27 +130,25 @@ module PacketGen
135
130
  # End Of Option TCP option
136
131
  # @author Sylvain Daubert
137
132
  class EOL < Option
138
- # @see Option#initialize
139
- def initialize(options={})
140
- super options.merge!(kind: EOL_KIND)
141
- end
133
+ update_field :kind, default: EOL_KIND
142
134
  end
143
135
 
144
136
  # No OPeration TCP option
145
137
  # @author Sylvain Daubert
146
138
  class NOP < Option
147
139
  # @see Option#initialize
148
- def initialize(options={})
149
- super options.merge!(kind: NOP_KIND)
150
- end
140
+ update_field :kind, default: NOP_KIND
151
141
  end
152
142
 
153
143
  # Maximum Segment Size TCP option
154
144
  # @author Sylvain Daubert
155
145
  class MSS < Option
146
+ update_field :kind, default: MSS_KIND
147
+ update_field :length, default: 4
148
+
156
149
  # @see Option#initialize
157
150
  def initialize(options={})
158
- super options.merge!(kind: MSS_KIND, length: 4)
151
+ super
159
152
  self[:value] = Types::Int16.new(options[:value])
160
153
  end
161
154
 
@@ -168,9 +161,12 @@ module PacketGen
168
161
  # Window Size TCP option
169
162
  # @author Sylvain Daubert
170
163
  class WS < Option
164
+ update_field :kind, default: WS_KIND
165
+ update_field :length, default: 3
166
+
171
167
  # @see Option#initialize
172
168
  def initialize(options={})
173
- super options.merge!(kind: WS_KIND, length: 3)
169
+ super
174
170
  self[:value] = Types::Int8.new(options[:value])
175
171
  end
176
172
 
@@ -183,28 +179,25 @@ module PacketGen
183
179
  # Selective Acknowledgment OK TCP option
184
180
  # @author Sylvain Daubert
185
181
  class SACKOK < Option
186
- # @see Option#initialize
187
- def initialize(options={})
188
- super options.merge!(kind: SACKOK_KIND, length: 2)
189
- end
182
+ update_field :kind, default: SACKOK_KIND
183
+ update_field :length, default: 2
190
184
  end
191
185
 
192
186
  # Selective Acknowledgment TCP option
193
187
  # @author Sylvain Daubert
194
188
  class SACK < Option
195
- # @see Option#initialize
196
- def initialize(options={})
197
- super options.merge!(kind: SACK_KIND)
198
- self[:length].read(2) if self[:value].to_s == ''
199
- end
189
+ update_field :kind, default: SACK_KIND
200
190
  end
201
191
 
202
192
  # Echo TCP option
203
193
  # @author Sylvain Daubert
204
194
  class ECHO < Option
195
+ update_field :kind, default: ECHO_KIND
196
+ update_field :length, default: 6
197
+
205
198
  # @see Option#initialize
206
199
  def initialize(options={})
207
- super options.merge!(kind: ECHO_KIND, length: 6)
200
+ super
208
201
  self[:value] = Types::Int32.new(options[:value])
209
202
  end
210
203
 
@@ -217,9 +210,12 @@ module PacketGen
217
210
  # Echo Reply TCP option
218
211
  # @author Sylvain Daubert
219
212
  class ECHOREPLY < Option
213
+ update_field :kind, default: ECHOREPLY_KIND
214
+ update_field :length, default: 6
215
+
220
216
  # @see Option#initialize
221
217
  def initialize(options={})
222
- super options.merge!(kind: ECHOREPLY_KIND, length: 6)
218
+ super
223
219
  self[:value] = Types::Int32.new(options[:value])
224
220
  end
225
221
 
@@ -232,10 +228,13 @@ module PacketGen
232
228
  # Timestamp TCP option
233
229
  # @author Sylvain Daubert
234
230
  class TS < Option
231
+ update_field :kind, default: TS_KIND
232
+ update_field :length, default: 10
233
+
235
234
  # @see Option#initialize
236
235
  def initialize(options={})
237
- super options.merge!(kind: TS_KIND, length: 10)
238
- self[:value] = Types::String.new.read(options[:value] || "\0" * 8)
236
+ super
237
+ self[:value].read(options[:value] || "\0" * 8)
239
238
  end
240
239
 
241
240
  # @return [String]