packetgen 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/packetgen/header/arp.rb +54 -125
  4. data/lib/packetgen/header/base.rb +175 -0
  5. data/lib/packetgen/header/dns/name.rb +110 -0
  6. data/lib/packetgen/header/dns/opt.rb +137 -0
  7. data/lib/packetgen/header/dns/option.rb +17 -0
  8. data/lib/packetgen/header/dns/qdsection.rb +39 -0
  9. data/lib/packetgen/header/dns/question.rb +129 -0
  10. data/lib/packetgen/header/dns/rr.rb +89 -0
  11. data/lib/packetgen/header/dns/rrsection.rb +72 -0
  12. data/lib/packetgen/header/dns.rb +276 -0
  13. data/lib/packetgen/header/esp.rb +38 -70
  14. data/lib/packetgen/header/eth.rb +35 -106
  15. data/lib/packetgen/header/icmp.rb +19 -70
  16. data/lib/packetgen/header/icmpv6.rb +3 -3
  17. data/lib/packetgen/header/ip.rb +54 -210
  18. data/lib/packetgen/header/ipv6.rb +73 -164
  19. data/lib/packetgen/header/tcp/option.rb +34 -50
  20. data/lib/packetgen/header/tcp/options.rb +19 -20
  21. data/lib/packetgen/header/tcp.rb +66 -129
  22. data/lib/packetgen/header/udp.rb +31 -88
  23. data/lib/packetgen/header.rb +5 -10
  24. data/lib/packetgen/inspect.rb +5 -4
  25. data/lib/packetgen/packet.rb +74 -57
  26. data/lib/packetgen/pcapng/block.rb +49 -7
  27. data/lib/packetgen/pcapng/epb.rb +36 -34
  28. data/lib/packetgen/pcapng/file.rb +24 -8
  29. data/lib/packetgen/pcapng/idb.rb +28 -33
  30. data/lib/packetgen/pcapng/shb.rb +35 -39
  31. data/lib/packetgen/pcapng/spb.rb +18 -27
  32. data/lib/packetgen/pcapng/unknown_block.rb +11 -21
  33. data/lib/packetgen/pcapng.rb +9 -7
  34. data/lib/packetgen/types/array.rb +56 -0
  35. data/lib/packetgen/types/fields.rb +325 -0
  36. data/lib/packetgen/types/int.rb +164 -0
  37. data/lib/packetgen/types/int_string.rb +69 -0
  38. data/lib/packetgen/types/string.rb +36 -0
  39. data/lib/packetgen/types/tlv.rb +41 -0
  40. data/lib/packetgen/types.rb +13 -0
  41. data/lib/packetgen/version.rb +1 -1
  42. data/lib/packetgen.rb +1 -1
  43. metadata +19 -6
  44. data/lib/packetgen/header/header_class_methods.rb +0 -106
  45. data/lib/packetgen/header/header_methods.rb +0 -73
  46. data/lib/packetgen/structfu.rb +0 -363
@@ -8,10 +8,10 @@ module PacketGen
8
8
  module Header
9
9
 
10
10
  # A IP header consists of:
11
- # * a first byte ({#u8} of {Int8} type) composed of:
11
+ # * a first byte ({#u8} of {Types::Int8} type) composed of:
12
12
  # * a 4-bit {#version} field,
13
13
  # * a 4-bit IP header length ({#ihl}) field,
14
- # * a total length ({#length}, {Int16} type),
14
+ # * a total length ({#length}, {Types::Int16} type),
15
15
  # * a ID ({#id}, +Int16+ type),
16
16
  # * a {#frag} worg (+Int16+) composed of:
17
17
  # * 3 1-bit flags ({#flag_rsv}, {#flag_df} and {#flag_mf}),
@@ -21,7 +21,7 @@ module PacketGen
21
21
  # * a {#checksum} field (+Int16+),
22
22
  # * a source IP address ({#src}, {Addr} type),
23
23
  # * a destination IP ddress ({#dst}, +Addr+ type),
24
- # * and a {#body} ({String} type).
24
+ # * and a {#body} ({Types::String} type).
25
25
  #
26
26
  # == Create a IP header
27
27
  # # standalone
@@ -58,32 +58,26 @@ module PacketGen
58
58
  # ip.dst = '127.0.0.2'
59
59
  # ip.body.read 'this is a body'
60
60
  # @author Sylvain Daubert
61
- class IP < Struct.new(:u8, :tos, :length, :id, :frag, :ttl,
62
- :protocol, :checksum, :src, :dst, :body)
63
- include StructFu
64
- include HeaderMethods
65
- extend HeaderClassMethods
61
+ class IP < Base
66
62
 
67
63
  # IP address, as a group of 4 bytes
68
64
  # @author Sylvain Daubert
69
- class Addr < Struct.new(:a1, :a2, :a3, :a4)
70
- include StructFu
65
+ class Addr < Base
66
+ # @!attribute a1
67
+ # @return [Integer] IP address first byte
68
+ define_field :a1, Types::Int8
69
+ # @!attribute a2
70
+ # @return [Integer] IP address seconf byte
71
+ define_field :a2, Types::Int8
72
+ # @!attribute a3
73
+ # @return [Integer] IP address third byte
74
+ define_field :a3, Types::Int8
75
+ # @!attribute a4
76
+ # @return [Integer] IP address fourth byte
77
+ define_field :a4, Types::Int8
71
78
 
72
79
  IPV4_ADDR_REGEX = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/
73
80
 
74
- # @param [Hash] options
75
- # @option options [Integer] :a1
76
- # @option options [Integer] :a2
77
- # @option options [Integer] :a3
78
- # @option options [Integer] :a4
79
- def initialize(options={})
80
- super Int8.new(options[:a1]),
81
- Int8.new(options[:a2]),
82
- Int8.new(options[:a3]),
83
- Int8.new(options[:a4])
84
-
85
- end
86
-
87
81
  # Read a dotted address
88
82
  # @param [String] str
89
83
  # @return [self]
@@ -99,27 +93,10 @@ module PacketGen
99
93
  self
100
94
  end
101
95
 
102
- # Read a Addr from a string
103
- # @param [String] str binary string
104
- # @return [self]
105
- def read(str)
106
- return self if str.nil?
107
- raise ParseError, 'string too short for IP::Addr' if str.size < self.sz
108
- force_binary str
109
- [:a1, :a2, :a3, :a4].each_with_index do |byte, i|
110
- self[byte].read str[i, 1]
111
- end
112
- end
113
-
114
- [:a1, :a2, :a3, :a4].each do |sym|
115
- class_eval "def #{sym}; self[:#{sym}].to_i; end\n" \
116
- "def #{sym}=(v); self[:#{sym}].read v; end"
117
- end
118
-
119
96
  # Addr in human readable form (dotted format)
120
97
  # @return [String]
121
98
  def to_human
122
- members.map { |m| "#{self[m].to_i}" }.join('.')
99
+ fields.map { |f| "#{self[f].to_i}" }.join('.')
123
100
  end
124
101
 
125
102
  # Addr as an integer
@@ -130,32 +107,41 @@ module PacketGen
130
107
  end
131
108
  end
132
109
 
133
- # @param [Hash] options
134
- # @option options [Integer] :version
135
- # @option options [Integer] :ihl this header size in 4-byte words
136
- # @option options [Integer] :tos
137
- # @option options [Integer] :length IP packet length, including this header
138
- # @option options [Integer] :id
139
- # @option options [Integer] :frag
140
- # @option options [Integer] :ttl
141
- # @option options [Integer] :protocol
142
- # @option options [Integer] :checksum IP header checksum
143
- # @option options [String] :src IP source dotted address
144
- # @option options [String] :dst IP destination dotted address
145
- def initialize(options={})
146
- super Int8.new(((options[:version] || 4) << 4) | (options[:ihl] || 5)),
147
- Int8.new(options[:tos] || 0),
148
- Int16.new(options[:length] || 20),
149
- Int16.new(options[:id] || rand(65535)),
150
- Int16.new(options[:frag] || 0),
151
- Int8.new(options[:ttl] || 64),
152
- Int8.new(options[:protocol]),
153
- Int16.new(options[:checksum] || 0),
154
- Addr.new.from_human(options[:src] || '127.0.0.1'),
155
- Addr.new.from_human(options[:dst] || '127.0.0.1'),
156
- StructFu::String.new.read(options[:body])
157
- end
158
-
110
+ # @!attribute u8
111
+ # First byte of IP header. May be accessed through {#version} and {#ihl}.
112
+ # @return [Integer] first byte of IP header.
113
+ define_field :u8, Types::Int8, default: 0x45
114
+ # @!attribute tos
115
+ # @return [Integer] 8-bit Type of Service value
116
+ define_field :tos, Types::Int8, default: 0
117
+ # @!attribute length
118
+ # @return [Integer] 16-bit IP total length
119
+ define_field :length, Types::Int16, default: 20
120
+ # @!attribute id
121
+ # @return [Integer] 16-bit ID
122
+ define_field :id, Types::Int16, default: -> { rand(65535) }
123
+ # @!attribute frag
124
+ # @return [Integer] 16-bit frag word
125
+ define_field :frag, Types::Int16, default: 0
126
+ # @!attribute ttl
127
+ # @return [Integer] 8-bit Time To Live value
128
+ define_field :ttl, Types::Int8, default: 64
129
+ # @!attribute protocol
130
+ # @return [Integer] 8-bit upper protocol value
131
+ define_field :protocol, Types::Int8
132
+ # @!attribute checksum
133
+ # @return [Integer] 16-bit IP header checksum
134
+ define_field :checksum, Types::Int16, default: 0
135
+ # @!attribute src
136
+ # @return [Addr] source IP address
137
+ define_field :src, Addr, default: '127.0.0.1'
138
+ # @!attribute dst
139
+ # @return [Addr] destination IP address
140
+ define_field :dst, Addr, default: '127.0.0.1'
141
+ # @!attribute body
142
+ # @return [Types::String,Header::Base]
143
+ define_field :body, Types::String
144
+
159
145
  # @!attribute version
160
146
  # @return [Integer] 4-bit version attribute
161
147
  # @!attribute ihl
@@ -172,28 +158,7 @@ module PacketGen
172
158
  # @return [Integer] 13-bit fragment offset
173
159
  define_bit_fields_on :frag, :flag_rsv, :flag_df, :flag_mf, :fragment_offset, 13
174
160
 
175
- # Read a IP header from a string
176
- # @param [String] str binary string
177
- # @return [self]
178
- def read(str)
179
- return self if str.nil?
180
- raise ParseError, 'string too short for IP' if str.size < self.sz
181
- force_binary str
182
- self[:u8].read str[0, 1]
183
- self[:tos].read str[1, 1]
184
- self[:length].read str[2, 2]
185
- self[:id].read str[4, 2]
186
- self[:frag].read str[6, 2]
187
- self[:ttl].read str[8, 1]
188
- self[:protocol].read str[9, 1]
189
- self[:checksum].read str[10, 2]
190
- self[:src].read str[12, 4]
191
- self[:dst].read str[16, 4]
192
- self[:body].read str[20..-1]
193
- self
194
- end
195
-
196
- # Compute checksum and set +checksum+ field
161
+ # Compute checksum and set +checksum+ field
197
162
  # @return [Integer]
198
163
  def calc_checksum
199
164
  checksum = (self[:u8].to_i << 8) | self.tos
@@ -216,127 +181,6 @@ module PacketGen
216
181
  self[:length].value = self.sz
217
182
  end
218
183
 
219
- # Getter for TOS attribute
220
- # @return [Integer]
221
- def tos
222
- self[:tos].to_i
223
- end
224
-
225
- # Setter for TOS attribute
226
- # @param [Integer] tos
227
- # @return [Integer]
228
- def tos=(tos)
229
- self[:tos].value = tos
230
- end
231
-
232
- # Getter for length attribute
233
- # @return [Integer]
234
- def length
235
- self[:length].to_i
236
- end
237
-
238
- # Setter for length attribute
239
- # @param [Integer] length
240
- # @return [Integer]
241
- def length=(length)
242
- self[:length].value = length
243
- end
244
-
245
- # Getter for id attribute
246
- # @return [Integer]
247
- def id
248
- self[:id].to_i
249
- end
250
-
251
- # Setter for id attribute
252
- # @param [Integer] id
253
- # @return [Integer]
254
- def id=(id)
255
- self[:id].value = id
256
- end
257
-
258
- # Getter for frag attribute
259
- # @return [Integer]
260
- def frag
261
- self[:frag].to_i
262
- end
263
-
264
- # Setter for frag attribute
265
- # @param [Integer] frag
266
- # @return [Integer]
267
- def frag=(frag)
268
- self[:frag].value = frag
269
- end
270
-
271
- # Getter for ttl attribute
272
- # @return [Integer]
273
- def ttl
274
- self[:ttl].to_i
275
- end
276
-
277
- # Setter for ttl attribute
278
- # @param [Integer] ttl
279
- # @return [Integer]
280
- def ttl=(ttl)
281
- self[:ttl].value = ttl
282
- end
283
-
284
- # Getter for protocol attribute
285
- # @return [Integer]
286
- def protocol
287
- self[:protocol].to_i
288
- end
289
-
290
- # Setter for protocol attribute
291
- # @param [Integer] protocol
292
- # @return [Integer]
293
- def protocol=(protocol)
294
- self[:protocol].value = protocol
295
- end
296
-
297
- # Getter for checksum attribute
298
- # @return [Integer]
299
- def checksum
300
- self[:checksum].to_i
301
- end
302
-
303
- # Setter for checksum attribute
304
- # @param [Integer] checksum
305
- # @return [Integer]
306
- def checksum=(checksum)
307
- self[:checksum].value = checksum
308
- end
309
-
310
- # Get IP source address
311
- # @return [String] dotted address
312
- def src
313
- self[:src].to_human
314
- end
315
- alias :source :src
316
-
317
- # Set IP source address
318
- # @param [String] addr dotted IP address
319
- # @return [String]
320
- def src=(addr)
321
- self[:src].from_human addr
322
- end
323
- alias :source= :src=
324
-
325
- # Get IP destination address
326
- # @return [String] dotted address
327
- def dst
328
- self[:dst].to_human
329
- end
330
- alias :destination :dst
331
-
332
- # Set IP destination address
333
- # @param [String] addr dotted IP address
334
- # @return [String]
335
- def dst=(addr)
336
- self[:dst].from_human addr
337
- end
338
- alias :destination= :dst=
339
-
340
184
  # Get IP part of pseudo header checksum.
341
185
  # @return [Integer]
342
186
  def pseudo_header_checksum
@@ -9,12 +9,12 @@ module PacketGen
9
9
  module Header
10
10
 
11
11
  # A IPv6 header consists of:
12
- # * a first 32-bit word ({#u32}, of {Int32} type) composoed of:
12
+ # * a first 32-bit word ({#u32}, of {Types::Int32} type) composoed of:
13
13
  # * a 4-bit {#version} field,
14
14
  # * a 8-bit {#traffic_class} field,
15
15
  # * a 20-bit {#flow_label} field,
16
- # * a payload length field ({#length}, {Int16} type}),
17
- # * a next header field ({#next}, {Int8} type),
16
+ # * a payload length field ({#length}, {Types::Int16} type}),
17
+ # * a next header field ({#next}, {Types::Int8} type),
18
18
  # * a hop-limit field ({#hop}, +Int8+ type),
19
19
  # * a source address field ({#src}, {IPv6::Addr} type),
20
20
  # * a destination address field ({#dst}, +IPv6::Addr+ type),
@@ -43,35 +43,44 @@ module PacketGen
43
43
  # ipv6.dst = '2001:1234:5678:abcd::123'
44
44
  # ipv6.body.read 'this is a body'
45
45
  # @author Sylvain Daubert
46
- class IPv6 < Struct.new(:u32, :length, :next, :hop, :src, :dst, :body)
47
- include StructFu
48
- include HeaderMethods
49
- extend HeaderClassMethods
46
+ class IPv6 < Base
50
47
 
51
48
  # IPv6 address, as a group of 8 2-byte words
52
49
  # @author Sylvain Daubert
53
- class Addr < Struct.new(:a1, :a2, :a3, :a4, :a5, :a6, :a7, :a8)
54
- include StructFu
55
-
56
- # @param [Hash] options
57
- # @option options [Integer] :a1
58
- # @option options [Integer] :a2
59
- # @option options [Integer] :a3
60
- # @option options [Integer] :a4
61
- # @option options [Integer] :a5
62
- # @option options [Integer] :a6
63
- # @option options [Integer] :a7
64
- # @option options [Integer] :a8
65
- def initialize(options={})
66
- super Int16.new(options[:a1]),
67
- Int16.new(options[:a2]),
68
- Int16.new(options[:a3]),
69
- Int16.new(options[:a4]),
70
- Int16.new(options[:a5]),
71
- Int16.new(options[:a6]),
72
- Int16.new(options[:a7]),
73
- Int16.new(options[:a8])
74
- end
50
+ class Addr < Base
51
+
52
+ # @!attribute a1
53
+ # 1st 2-byte word of IPv6 address
54
+ # @return [Integer]
55
+ define_field :a1, Types::Int16
56
+ # @!attribute a2
57
+ # 2nd 2-byte word of IPv6 address
58
+ # @return [Integer]
59
+ define_field :a2, Types::Int16
60
+ # @!attribute a3
61
+ # 3rd 2-byte word of IPv6 address
62
+ # @return [Integer]
63
+ define_field :a3, Types::Int16
64
+ # @!attribute a4
65
+ # 4th 2-byte word of IPv6 address
66
+ # @return [Integer]
67
+ define_field :a4, Types::Int16
68
+ # @!attribute a5
69
+ # 5th 2-byte word of IPv6 address
70
+ # @return [Integer]
71
+ define_field :a5, Types::Int16
72
+ # @!attribute a6
73
+ # 6th 2-byte word of IPv6 address
74
+ # @return [Integer]
75
+ define_field :a6, Types::Int16
76
+ # @!attribute a7
77
+ # 7th 2-byte word of IPv6 address
78
+ # @return [Integer]
79
+ define_field :a7, Types::Int16
80
+ # @!attribute a8
81
+ # 8th 2-byte word of IPv6 address
82
+ # @return [Integer]
83
+ define_field :a8, Types::Int16
75
84
 
76
85
  # Read a colon-delimited address
77
86
  # @param [String] str
@@ -92,57 +101,47 @@ module PacketGen
92
101
  self
93
102
  end
94
103
 
95
- # Read a Addr6 from a binary string
96
- # @param [String] str
97
- # @return [self]
98
- def read(str)
99
- force_binary str
100
- self[:a1].read str[0, 2]
101
- self[:a2].read str[2, 2]
102
- self[:a3].read str[4, 2]
103
- self[:a4].read str[6, 2]
104
- self[:a5].read str[8, 2]
105
- self[:a6].read str[10, 2]
106
- self[:a7].read str[12, 2]
107
- self[:a8].read str[14, 2]
108
- self
109
- end
110
-
111
- %i(a1 a2 a3 a4 a5 a6 a7 a8).each do |sym|
112
- class_eval "def #{sym}; self[:#{sym}].to_i; end\n" \
113
- "def #{sym}=(v); self[:#{sym}].read v; end"
114
- end
115
-
116
104
  # Addr6 in human readable form (colon-delimited hex string)
117
105
  # @return [String]
118
106
  def to_human
119
107
  IPAddr.new(to_a.map { |a| a.to_i.to_s(16) }.join(':')).to_s
120
108
  end
121
- end
122
109
 
123
- # @param [Hash] options
124
- # @option options [Integer] :version
125
- # @option options [Integer] :traffic_class
126
- # @option options [Integer] :flow_label
127
- # @option options [Integer] :length payload length
128
- # @option options [Integer] :next
129
- # @option options [Integer] :hop
130
- # @option options [String] :src colon-delimited source address
131
- # @option options [String] :dst colon-delimited destination address
132
- # @option options [String] :body binary string
133
- def initialize(options={})
134
- super Int32.new(0x60000000),
135
- Int16.new(options[:length]),
136
- Int8.new(options[:next]),
137
- Int8.new(options[:hop] || 64),
138
- Addr.new.from_human(options[:src] || '::1'),
139
- Addr.new.from_human(options[:dst] || '::1'),
140
- StructFu::String.new.read(options[:body])
141
- self.version = options[:version] if options[:version]
142
- self.traffic_class = options[:traffic_class] if options[:traffic_class]
143
- self.flow_label = options[:flow_label] if options[:flow_label]
110
+ # Return an array of address 16-bit words
111
+ # @return [Array<Integer>]
112
+ def to_a
113
+ @fields.values
114
+ end
144
115
  end
145
116
 
117
+ # @!attribute u32
118
+ # First 32-bit word of IPv6 header
119
+ # @return [Integer]
120
+ define_field :u32, Types::Int32, default: 0x6000_0000
121
+ # @!attribute length
122
+ # 16-bit word of IPv6 payload length
123
+ # @return [Integer]
124
+ define_field :length, Types::Int16
125
+ # @!attribute next
126
+ # 8-bit IPv6 next payload value
127
+ # @return [Integer]
128
+ define_field :next, Types::Int8
129
+ # @!attribute hop
130
+ # 8-bit IPv6 hop limit
131
+ # @return [Integer]
132
+ define_field :hop, Types::Int8, default: 64
133
+ # @!attribute src
134
+ # IPv6 source address
135
+ # @return [Addr]
136
+ define_field :src, Addr, default: '::1'
137
+ # @!attribute dst
138
+ # IPv6 destination address
139
+ # @return [Addr]
140
+ define_field :dst, Addr, default: '::1'
141
+ # @!attribute body
142
+ # @return [Types::String,Header::Base]
143
+ define_field :body, Types::String
144
+
146
145
  # @!attribute version
147
146
  # @return [Integer] 4-bit version attribute
148
147
  # @!attribute traffic_class
@@ -151,108 +150,18 @@ module PacketGen
151
150
  # @return [Integer] 20-bit flow_label attribute
152
151
  define_bit_fields_on :u32, :version, 4, :traffic_class, 8, :flow_label, 20
153
152
 
154
- # Read a IP header from a string
155
- # @param [String] str binary string
156
- # @return [self]
157
- def read(str)
158
- return self if str.nil?
159
- raise ParseError, 'string too short for IPv6' if str.size < self.sz
160
- force_binary str
161
- first32 = str[0, 4].unpack('N').first
162
- self.version = first32 >> 28
163
- self.traffic_class = (first32 >> 20) & 0xff
164
- self.flow_label = first32 & 0xfffff
165
-
166
- self[:length].read str[4, 2]
167
- self[:next].read str[6, 1]
168
- self[:hop].read str[7, 1]
169
- self[:src].read str[8, 16]
170
- self[:dst].read str[24, 16]
171
- self[:body].read str[40..-1]
172
- self
173
- end
174
-
175
153
  # Compute length and set +len+ field
176
154
  # @return [Integer]
177
155
  def calc_length
178
156
  self.length = body.sz
179
157
  end
180
158
 
181
- # @!attribute length
182
- # 16-bit payload length attribute
183
- # @return [Integer]
184
- def length
185
- self[:length].to_i
186
- end
187
-
188
- # @param [Integer] i
189
- # @return [Integer]
190
- def length=(i)
191
- self[:length].read i
192
- end
193
-
194
- # Getter for next attribute
195
- # @return [Integer]
196
- def next
197
- self[:next].to_i
198
- end
199
-
200
- # Setter for next attribute
201
- # @param [Integer] i
202
- # @return [Integer]
203
- def next=(i)
204
- self[:next].read i
205
- end
206
-
207
- # Getter for hop attribute
208
- # @return [Integer]
209
- def hop
210
- self[:hop].to_i
211
- end
212
-
213
- # Setter for hop attribute
214
- # @param [Integer] i
215
- # @return [Integer]
216
- def hop=(i)
217
- self[:hop].read i
218
- end
219
-
220
- # Getter for src attribute
221
- # @return [String]
222
- def src
223
- self[:src].to_human
224
- end
225
- alias :source :src
226
-
227
- # Setter for src attribute
228
- # @param [String] addr
229
- # @return [Integer]
230
- def src=(addr)
231
- self[:src].from_human addr
232
- end
233
- alias :source= :src=
234
-
235
- # Getter for dst attribute
236
- # @return [String]
237
- def dst
238
- self[:dst].to_human
239
- end
240
- alias :destination :dst
241
-
242
- # Setter for dst attribute
243
- # @param [String] addr
244
- # @return [Integer]
245
- def dst=(addr)
246
- self[:dst].from_human addr
247
- end
248
- alias :destination= :dst=
249
-
250
159
  # Get IPv6 part of pseudo header checksum.
251
160
  # @return [Integer]
252
161
  def pseudo_header_checksum
253
162
  sum = 0
254
- self[:src].each { |word| sum += word.to_i }
255
- self[:dst].each { |word| sum += word.to_i }
163
+ self[:src].to_a.each { |word| sum += word.to_i }
164
+ self[:dst].to_a.each { |word| sum += word.to_i }
256
165
  sum
257
166
  end
258
167