packetgen 0.3.0 → 1.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.
- checksums.yaml +4 -4
- data/lib/packetgen/capture.rb +5 -0
- data/lib/packetgen/header/arp.rb +118 -76
- data/lib/packetgen/header/eth.rb +48 -23
- data/lib/packetgen/header/header_class_methods.rb +75 -1
- data/lib/packetgen/header/header_methods.rb +16 -0
- data/lib/packetgen/header/icmp.rb +39 -16
- data/lib/packetgen/header/icmpv6.rb +28 -5
- data/lib/packetgen/header/ip.rb +140 -58
- data/lib/packetgen/header/ipv6.rb +87 -31
- data/lib/packetgen/header/tcp/option.rb +254 -0
- data/lib/packetgen/header/tcp/options.rb +86 -0
- data/lib/packetgen/header/tcp.rb +299 -0
- data/lib/packetgen/header/udp.rb +45 -19
- data/lib/packetgen/header.rb +6 -0
- data/lib/packetgen/inspect.rb +76 -0
- data/lib/packetgen/packet.rb +12 -51
- data/lib/packetgen/pcapng/block.rb +5 -0
- data/lib/packetgen/pcapng/epb.rb +5 -0
- data/lib/packetgen/pcapng/file.rb +5 -0
- data/lib/packetgen/pcapng/idb.rb +5 -0
- data/lib/packetgen/pcapng/shb.rb +5 -0
- data/lib/packetgen/pcapng/spb.rb +5 -0
- data/lib/packetgen/pcapng/unknown_block.rb +5 -0
- data/lib/packetgen/pcapng.rb +4 -0
- data/lib/packetgen/structfu.rb +5 -3
- data/lib/packetgen/version.rb +6 -1
- data/lib/packetgen.rb +7 -1
- metadata +7 -3
@@ -1,17 +1,40 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
1
6
|
module PacketGen
|
2
7
|
module Header
|
3
8
|
|
4
|
-
# ICMPv6 header
|
9
|
+
# A ICMPv6 header consists of:
|
10
|
+
# * a +type+ field ({Int8} type),
|
11
|
+
# * a +code+ field ({Int8} type),
|
12
|
+
# * a +checksum+ field ({Int16} type),
|
13
|
+
# * and a +body+.
|
14
|
+
#
|
15
|
+
# == Create a ICMPv6 header
|
16
|
+
# # standalone
|
17
|
+
# icmpv6 = PacketGen::Header::ICMPv6.new
|
18
|
+
# # in a packet
|
19
|
+
# pkt = PacketGen.gen('IPv6').add('ICMPv6')
|
20
|
+
# # access to ICMPv6 header
|
21
|
+
# pkt.icmpv6 # => PacketGen::Header::ICMPv6
|
22
|
+
#
|
23
|
+
# == ICMPv6 attributes
|
24
|
+
# icmpv6.code = 0
|
25
|
+
# icmpv6.type = 200
|
26
|
+
# icmpv6.checksum = 0x248a
|
27
|
+
# icmpv6.body.read 'this is a body'
|
5
28
|
# @author Sylvain Daubert
|
6
29
|
class ICMPv6 < ICMP
|
7
30
|
|
8
31
|
# ICMPv6 internet protocol number
|
9
32
|
IP_PROTOCOL = 58
|
10
33
|
|
11
|
-
# Compute checksum and set +
|
34
|
+
# Compute checksum and set +checksum+ field
|
12
35
|
# @return [Integer]
|
13
|
-
def
|
14
|
-
sum = ip_header(self).
|
36
|
+
def calc_checksum
|
37
|
+
sum = ip_header(self).pseudo_header_checksum
|
15
38
|
sum += self.sz
|
16
39
|
sum += IP_PROTOCOL
|
17
40
|
sum +=(type << 8) | code
|
@@ -24,7 +47,7 @@ module PacketGen
|
|
24
47
|
sum = (sum & 0xffff) + (sum >> 16)
|
25
48
|
end
|
26
49
|
sum = ~sum & 0xffff
|
27
|
-
self[:
|
50
|
+
self[:checksum].value = (sum == 0) ? 0xffff : sum
|
28
51
|
end
|
29
52
|
end
|
30
53
|
|
data/lib/packetgen/header/ip.rb
CHANGED
@@ -1,12 +1,65 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
1
5
|
require 'socket'
|
2
6
|
|
3
7
|
module PacketGen
|
4
8
|
module Header
|
5
9
|
|
6
|
-
# IP header
|
10
|
+
# A IP header consists of:
|
11
|
+
# * a first byte ({#u8} of {Int8} type) composed of:
|
12
|
+
# * a 4-bit {#version} field,
|
13
|
+
# * a 4-bit IP header length ({#ihl}) field,
|
14
|
+
# * a total length ({#length}, {Int16} type),
|
15
|
+
# * a ID ({#id}, +Int16+ type),
|
16
|
+
# * a {#frag} worg (+Int16+) composed of:
|
17
|
+
# * 3 1-bit flags ({#flag_rsv}, {#flag_df} and {#flag_mf}),
|
18
|
+
# * a 13-bit {#fragment_offset} field,
|
19
|
+
# * a Time-to-Live ({#ttl}) field (+Int8+),
|
20
|
+
# * a {#protocol} field (+Int8+),
|
21
|
+
# * a {#checksum} field (+Int16+),
|
22
|
+
# * a source IP address ({#src}, {Addr} type),
|
23
|
+
# * a destination IP ddress ({#dst}, +Addr+ type),
|
24
|
+
# * and a {#body} ({String} type).
|
25
|
+
#
|
26
|
+
# == Create a IP header
|
27
|
+
# # standalone
|
28
|
+
# ip = PacketGen::Header::IP.new
|
29
|
+
# # in a packet
|
30
|
+
# pkt = PacketGen.gen('IP')
|
31
|
+
# # access to IP header
|
32
|
+
# pkt.ip # => PacketGen::Header::IP
|
33
|
+
#
|
34
|
+
# == IP attributes
|
35
|
+
# ip.u8 = 0x45
|
36
|
+
# # the same as
|
37
|
+
# ip.version = 4
|
38
|
+
# ip.ihl = 5
|
39
|
+
#
|
40
|
+
# ip.length = 0x43
|
41
|
+
# ip.id = 0x1234
|
42
|
+
#
|
43
|
+
# ip.frag = 0x2031
|
44
|
+
# # the same as:
|
45
|
+
# ip.flag_mf = true
|
46
|
+
# ip.fragment_offset = 0x31
|
47
|
+
#
|
48
|
+
# ip.flag_rsv? # => Boolean
|
49
|
+
# ip.flag_df? # => Boolean
|
50
|
+
# ip.flag_mf? # => Boolean
|
51
|
+
#
|
52
|
+
# ip.ttl = 0x40
|
53
|
+
# ip.protocol = 6
|
54
|
+
# ip.checksum = 0xffff
|
55
|
+
# ip.src = '127.0.0.1'
|
56
|
+
# ip.src # => "127.0.0.1"
|
57
|
+
# ip[:src] # => PacketGen::Header::IP::Addr
|
58
|
+
# ip.dst = '127.0.0.2'
|
59
|
+
# ip.body.read 'this is a body'
|
7
60
|
# @author Sylvain Daubert
|
8
|
-
class IP < Struct.new(:
|
9
|
-
:
|
61
|
+
class IP < Struct.new(:u8, :tos, :length, :id, :frag, :ttl,
|
62
|
+
:protocol, :checksum, :src, :dst, :body)
|
10
63
|
include StructFu
|
11
64
|
include HeaderMethods
|
12
65
|
extend HeaderClassMethods
|
@@ -31,10 +84,10 @@ module PacketGen
|
|
31
84
|
|
32
85
|
end
|
33
86
|
|
34
|
-
#
|
87
|
+
# Read a dotted address
|
35
88
|
# @param [String] str
|
36
89
|
# @return [self]
|
37
|
-
def
|
90
|
+
def from_human(str)
|
38
91
|
return self if str.nil?
|
39
92
|
m = str.match(IPV4_ADDR_REGEX)
|
40
93
|
if m
|
@@ -51,7 +104,7 @@ module PacketGen
|
|
51
104
|
# @return [self]
|
52
105
|
def read(str)
|
53
106
|
return self if str.nil?
|
54
|
-
raise ParseError, 'string too short for
|
107
|
+
raise ParseError, 'string too short for IP::Addr' if str.size < self.sz
|
55
108
|
force_binary str
|
56
109
|
[:a1, :a2, :a3, :a4].each_with_index do |byte, i|
|
57
110
|
self[byte].read str[i, 1]
|
@@ -65,7 +118,7 @@ module PacketGen
|
|
65
118
|
|
66
119
|
# Addr in human readable form (dotted format)
|
67
120
|
# @return [String]
|
68
|
-
def
|
121
|
+
def to_human
|
69
122
|
members.map { |m| "#{self[m].to_i}" }.join('.')
|
70
123
|
end
|
71
124
|
|
@@ -85,63 +138,76 @@ module PacketGen
|
|
85
138
|
# @option options [Integer] :id
|
86
139
|
# @option options [Integer] :frag
|
87
140
|
# @option options [Integer] :ttl
|
88
|
-
# @option options [Integer] :
|
89
|
-
# @option options [Integer] :
|
141
|
+
# @option options [Integer] :protocol
|
142
|
+
# @option options [Integer] :checksum IP header checksum
|
90
143
|
# @option options [String] :src IP source dotted address
|
91
144
|
# @option options [String] :dst IP destination dotted address
|
92
145
|
def initialize(options={})
|
93
|
-
super options[:version] || 4,
|
94
|
-
options[:ihl] || 5,
|
146
|
+
super Int8.new(((options[:version] || 4) << 4) | (options[:ihl] || 5)),
|
95
147
|
Int8.new(options[:tos] || 0),
|
96
148
|
Int16.new(options[:length] || 20),
|
97
149
|
Int16.new(options[:id] || rand(65535)),
|
98
150
|
Int16.new(options[:frag] || 0),
|
99
151
|
Int8.new(options[:ttl] || 64),
|
100
|
-
Int8.new(options[:
|
101
|
-
Int16.new(options[:
|
102
|
-
Addr.new.
|
103
|
-
Addr.new.
|
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'),
|
104
156
|
StructFu::String.new.read(options[:body])
|
105
157
|
end
|
106
158
|
|
159
|
+
# @!attribute version
|
160
|
+
# @return [Integer] 4-bit version attribute
|
161
|
+
# @!attribute ihl
|
162
|
+
# @return [Integer] 4-bit IP header length attribute
|
163
|
+
define_bit_fields_on :u8, :version, 4, :ihl, 4
|
164
|
+
|
165
|
+
# @!attribute flag_rsv
|
166
|
+
# @return [Boolean] reserved bit from flags
|
167
|
+
# @!attribute flag_df
|
168
|
+
# @return [Boolean] Don't Fragment flag
|
169
|
+
# @!attribute flag_mf
|
170
|
+
# @return [Boolena] More Fragment flags
|
171
|
+
# @!attribute fragment_offset
|
172
|
+
# @return [Integer] 13-bit fragment offset
|
173
|
+
define_bit_fields_on :frag, :flag_rsv, :flag_df, :flag_mf, :fragment_offset, 13
|
174
|
+
|
107
175
|
# Read a IP header from a string
|
108
176
|
# @param [String] str binary string
|
109
177
|
# @return [self]
|
110
178
|
def read(str)
|
111
179
|
return self if str.nil?
|
112
|
-
raise ParseError, 'string too short for
|
180
|
+
raise ParseError, 'string too short for IP' if str.size < self.sz
|
113
181
|
force_binary str
|
114
|
-
|
115
|
-
self[:version] = vihl >> 4
|
116
|
-
self[:ihl] = vihl & 0x0f
|
182
|
+
self[:u8].read str[0, 1]
|
117
183
|
self[:tos].read str[1, 1]
|
118
184
|
self[:length].read str[2, 2]
|
119
185
|
self[:id].read str[4, 2]
|
120
186
|
self[:frag].read str[6, 2]
|
121
187
|
self[:ttl].read str[8, 1]
|
122
|
-
self[:
|
123
|
-
self[:
|
188
|
+
self[:protocol].read str[9, 1]
|
189
|
+
self[:checksum].read str[10, 2]
|
124
190
|
self[:src].read str[12, 4]
|
125
191
|
self[:dst].read str[16, 4]
|
126
192
|
self[:body].read str[20..-1]
|
127
193
|
self
|
128
194
|
end
|
129
195
|
|
130
|
-
# Compute checksum and set +
|
196
|
+
# Compute checksum and set +checksum+ field
|
131
197
|
# @return [Integer]
|
132
|
-
def
|
133
|
-
checksum = (self.
|
198
|
+
def calc_checksum
|
199
|
+
checksum = (self[:u8].to_i << 8) | self.tos
|
134
200
|
checksum += self.length
|
135
201
|
checksum += self.id
|
136
202
|
checksum += self.frag
|
137
|
-
checksum += (self.ttl << 8) | self.
|
203
|
+
checksum += (self.ttl << 8) | self.protocol
|
138
204
|
checksum += (self[:src].to_i >> 16)
|
139
205
|
checksum += (self[:src].to_i & 0xffff)
|
140
206
|
checksum += self[:dst].to_i >> 16
|
141
207
|
checksum += self[:dst].to_i & 0xffff
|
142
208
|
checksum = (checksum & 0xffff) + (checksum >> 16)
|
143
209
|
checksum = ~(checksum % 0xffff ) & 0xffff
|
144
|
-
self[:
|
210
|
+
self[:checksum].value = (checksum == 0) ? 0xffff : checksum
|
145
211
|
end
|
146
212
|
|
147
213
|
# Compute length and set +length+ field
|
@@ -215,36 +281,36 @@ module PacketGen
|
|
215
281
|
self[:ttl].value = ttl
|
216
282
|
end
|
217
283
|
|
218
|
-
# Getter for
|
284
|
+
# Getter for protocol attribute
|
219
285
|
# @return [Integer]
|
220
|
-
def
|
221
|
-
self[:
|
286
|
+
def protocol
|
287
|
+
self[:protocol].to_i
|
222
288
|
end
|
223
289
|
|
224
|
-
# Setter for
|
225
|
-
# @param [Integer]
|
290
|
+
# Setter for protocol attribute
|
291
|
+
# @param [Integer] protocol
|
226
292
|
# @return [Integer]
|
227
|
-
def
|
228
|
-
self[:
|
293
|
+
def protocol=(protocol)
|
294
|
+
self[:protocol].value = protocol
|
229
295
|
end
|
230
296
|
|
231
|
-
# Getter for
|
297
|
+
# Getter for checksum attribute
|
232
298
|
# @return [Integer]
|
233
|
-
def
|
234
|
-
self[:
|
299
|
+
def checksum
|
300
|
+
self[:checksum].to_i
|
235
301
|
end
|
236
302
|
|
237
|
-
# Setter for
|
238
|
-
# @param [Integer]
|
303
|
+
# Setter for checksum attribute
|
304
|
+
# @param [Integer] checksum
|
239
305
|
# @return [Integer]
|
240
|
-
def
|
241
|
-
self[:
|
306
|
+
def checksum=(checksum)
|
307
|
+
self[:checksum].value = checksum
|
242
308
|
end
|
243
309
|
|
244
310
|
# Get IP source address
|
245
311
|
# @return [String] dotted address
|
246
312
|
def src
|
247
|
-
self[:src].
|
313
|
+
self[:src].to_human
|
248
314
|
end
|
249
315
|
alias :source :src
|
250
316
|
|
@@ -252,14 +318,14 @@ module PacketGen
|
|
252
318
|
# @param [String] addr dotted IP address
|
253
319
|
# @return [String]
|
254
320
|
def src=(addr)
|
255
|
-
self[:src].
|
321
|
+
self[:src].from_human addr
|
256
322
|
end
|
257
323
|
alias :source= :src=
|
258
324
|
|
259
325
|
# Get IP destination address
|
260
326
|
# @return [String] dotted address
|
261
327
|
def dst
|
262
|
-
self[:dst].
|
328
|
+
self[:dst].to_human
|
263
329
|
end
|
264
330
|
alias :destination :dst
|
265
331
|
|
@@ -267,27 +333,20 @@ module PacketGen
|
|
267
333
|
# @param [String] addr dotted IP address
|
268
334
|
# @return [String]
|
269
335
|
def dst=(addr)
|
270
|
-
self[:dst].
|
336
|
+
self[:dst].from_human addr
|
271
337
|
end
|
272
338
|
alias :destination= :dst=
|
273
339
|
|
274
|
-
# Get
|
275
|
-
# @return [String]
|
276
|
-
def to_s
|
277
|
-
first_byte = [(version << 4) | ihl].pack('C')
|
278
|
-
first_byte << to_a[2..-1].map { |field| field.to_s }.join
|
279
|
-
end
|
280
|
-
|
281
|
-
# Get IP part of pseudo header sum.
|
340
|
+
# Get IP part of pseudo header checksum.
|
282
341
|
# @return [Integer]
|
283
|
-
def
|
284
|
-
|
285
|
-
(
|
342
|
+
def pseudo_header_checksum
|
343
|
+
checksum = self[:src].to_i + self[:dst].to_i
|
344
|
+
(checksum >> 16) + (checksum & 0xffff)
|
286
345
|
end
|
287
346
|
|
288
347
|
# Send IP packet on wire.
|
289
348
|
#
|
290
|
-
# When sending packet at IP level, +
|
349
|
+
# When sending packet at IP level, +checksum+ and +length+ fields are set by
|
291
350
|
# kernel, so bad IP packets cannot be sent this way. To do so, use {Eth#to_w}.
|
292
351
|
# @param [String,nil] iface interface name. Not used
|
293
352
|
# @return [void]
|
@@ -296,9 +355,32 @@ module PacketGen
|
|
296
355
|
sockaddrin = Socket.sockaddr_in(0, dst)
|
297
356
|
sock.send to_s, 0, sockaddrin
|
298
357
|
end
|
358
|
+
|
359
|
+
# @return [String]
|
360
|
+
def inspect
|
361
|
+
str = Inspect.dashed_line(self.class, 2)
|
362
|
+
shift = Inspect.shift_level(2)
|
363
|
+
to_h.each do |attr, value|
|
364
|
+
next if attr == :body
|
365
|
+
str << Inspect.inspect_attribute(attr, value, 2)
|
366
|
+
if attr == :u8
|
367
|
+
str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'version', version]
|
368
|
+
str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'ihl', ihl]
|
369
|
+
elsif attr == :frag
|
370
|
+
flags = flag_rsv? ? %w(RSV) : []
|
371
|
+
flags << 'DF' if flag_df?
|
372
|
+
flags << 'MF' if flag_mf?
|
373
|
+
flags_str = flags.empty? ? 'none' : flags.join(',')
|
374
|
+
str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'flags', flags_str]
|
375
|
+
foff = Inspect.int_dec_hex(fragment_offset, 4)
|
376
|
+
str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'frag_offset', foff]
|
377
|
+
end
|
378
|
+
end
|
379
|
+
str
|
380
|
+
end
|
299
381
|
end
|
300
382
|
|
301
|
-
Eth.bind_header IP,
|
302
|
-
IP.bind_header IP,
|
383
|
+
Eth.bind_header IP, ethertype: 0x800
|
384
|
+
IP.bind_header IP, protocol: 4
|
303
385
|
end
|
304
386
|
end
|
@@ -1,13 +1,49 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
# This file is part of PacketGen
|
3
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
4
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
5
|
+
# This program is published under MIT license.
|
2
6
|
require 'ipaddr'
|
3
7
|
|
4
8
|
module PacketGen
|
5
9
|
module Header
|
6
10
|
|
7
|
-
# IPv6 header
|
11
|
+
# A IPv6 header consists of:
|
12
|
+
# * a first 32-bit word ({#u32}, of {Int32} type) composoed of:
|
13
|
+
# * a 4-bit {#version} field,
|
14
|
+
# * a 8-bit {#traffic_class} field,
|
15
|
+
# * a 20-bit {#flow_label} field,
|
16
|
+
# * a payload length field ({#length}, {Int16} type}),
|
17
|
+
# * a next header field ({#next}, {Int8} type),
|
18
|
+
# * a hop-limit field ({#hop}, +Int8+ type),
|
19
|
+
# * a source address field ({#src}, {IPv6::Addr} type),
|
20
|
+
# * a destination address field ({#dst}, +IPv6::Addr+ type),
|
21
|
+
#
|
22
|
+
# == Create a IPv6 header
|
23
|
+
# # standalone
|
24
|
+
# ipv6 = PacketGen::Header::IPv6.new
|
25
|
+
# # in a packet
|
26
|
+
# pkt = PacketGen.gen('IPv6')
|
27
|
+
# # access to IPv6 header
|
28
|
+
# pkt.ipv6 # => PacketGen::Header::IPv6
|
29
|
+
#
|
30
|
+
# == IPv6 attributes
|
31
|
+
# ipv6.u32 = 0x60280001
|
32
|
+
# # the same as
|
33
|
+
# ipv6.version = 6
|
34
|
+
# ipv6.traffic_class = 2
|
35
|
+
# ipv6.flow_label = 0x80001
|
36
|
+
#
|
37
|
+
# ipv6.length = 0x43
|
38
|
+
# ipv6.hop = 0x40
|
39
|
+
# ipv6.next = 6
|
40
|
+
# ipv6.src = '::1'
|
41
|
+
# ipv6.src # => "::1"
|
42
|
+
# ipv6[:src] # => PacketGen::Header::IPv6::Addr
|
43
|
+
# ipv6.dst = '2001:1234:5678:abcd::123'
|
44
|
+
# ipv6.body.read 'this is a body'
|
8
45
|
# @author Sylvain Daubert
|
9
|
-
class IPv6 < Struct.new(:
|
10
|
-
:next, :hop, :src, :dst, :body)
|
46
|
+
class IPv6 < Struct.new(:u32, :length, :next, :hop, :src, :dst, :body)
|
11
47
|
include StructFu
|
12
48
|
include HeaderMethods
|
13
49
|
extend HeaderClassMethods
|
@@ -37,10 +73,10 @@ module PacketGen
|
|
37
73
|
Int16.new(options[:a8])
|
38
74
|
end
|
39
75
|
|
40
|
-
#
|
76
|
+
# Read a colon-delimited address
|
41
77
|
# @param [String] str
|
42
78
|
# @return [self]
|
43
|
-
def
|
79
|
+
def from_human(str)
|
44
80
|
return self if str.nil?
|
45
81
|
addr = IPAddr.new(str)
|
46
82
|
raise ArgumentError, 'string is not a IPv6 address' unless addr.ipv6?
|
@@ -79,14 +115,14 @@ module PacketGen
|
|
79
115
|
|
80
116
|
# Addr6 in human readable form (colon-delimited hex string)
|
81
117
|
# @return [String]
|
82
|
-
def
|
118
|
+
def to_human
|
83
119
|
IPAddr.new(to_a.map { |a| a.to_i.to_s(16) }.join(':')).to_s
|
84
120
|
end
|
85
121
|
end
|
86
122
|
|
87
123
|
# @param [Hash] options
|
88
124
|
# @option options [Integer] :version
|
89
|
-
# @option options [Integer] :
|
125
|
+
# @option options [Integer] :traffic_class
|
90
126
|
# @option options [Integer] :flow_label
|
91
127
|
# @option options [Integer] :length payload length
|
92
128
|
# @option options [Integer] :next
|
@@ -95,23 +131,32 @@ module PacketGen
|
|
95
131
|
# @option options [String] :dst colon-delimited destination address
|
96
132
|
# @option options [String] :body binary string
|
97
133
|
def initialize(options={})
|
98
|
-
super
|
99
|
-
options[:traffic_class] || 0,
|
100
|
-
options[:flow_label] || 0,
|
134
|
+
super Int32.new(0x60000000),
|
101
135
|
Int16.new(options[:length]),
|
102
136
|
Int8.new(options[:next]),
|
103
137
|
Int8.new(options[:hop] || 64),
|
104
|
-
Addr.new.
|
105
|
-
Addr.new.
|
138
|
+
Addr.new.from_human(options[:src] || '::1'),
|
139
|
+
Addr.new.from_human(options[:dst] || '::1'),
|
106
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]
|
107
144
|
end
|
108
145
|
|
146
|
+
# @!attribute version
|
147
|
+
# @return [Integer] 4-bit version attribute
|
148
|
+
# @!attribute traffic_class
|
149
|
+
# @return [Integer] 8-bit traffic_class attribute
|
150
|
+
# @!attribute flow_label
|
151
|
+
# @return [Integer] 20-bit flow_label attribute
|
152
|
+
define_bit_fields_on :u32, :version, 4, :traffic_class, 8, :flow_label, 20
|
153
|
+
|
109
154
|
# Read a IP header from a string
|
110
155
|
# @param [String] str binary string
|
111
156
|
# @return [self]
|
112
157
|
def read(str)
|
113
158
|
return self if str.nil?
|
114
|
-
raise ParseError, 'string too short for
|
159
|
+
raise ParseError, 'string too short for IPv6' if str.size < self.sz
|
115
160
|
force_binary str
|
116
161
|
first32 = str[0, 4].unpack('N').first
|
117
162
|
self.version = first32 >> 28
|
@@ -133,13 +178,13 @@ module PacketGen
|
|
133
178
|
self.length = body.sz
|
134
179
|
end
|
135
180
|
|
136
|
-
#
|
137
|
-
#
|
181
|
+
# @!attribute length
|
182
|
+
# 16-bit payload length attribute
|
183
|
+
# @return [Integer]
|
138
184
|
def length
|
139
185
|
self[:length].to_i
|
140
186
|
end
|
141
187
|
|
142
|
-
# Setter for length attribute
|
143
188
|
# @param [Integer] i
|
144
189
|
# @return [Integer]
|
145
190
|
def length=(i)
|
@@ -175,7 +220,7 @@ module PacketGen
|
|
175
220
|
# Getter for src attribute
|
176
221
|
# @return [String]
|
177
222
|
def src
|
178
|
-
self[:src].
|
223
|
+
self[:src].to_human
|
179
224
|
end
|
180
225
|
alias :source :src
|
181
226
|
|
@@ -183,14 +228,14 @@ module PacketGen
|
|
183
228
|
# @param [String] addr
|
184
229
|
# @return [Integer]
|
185
230
|
def src=(addr)
|
186
|
-
self[:src].
|
231
|
+
self[:src].from_human addr
|
187
232
|
end
|
188
233
|
alias :source= :src=
|
189
234
|
|
190
235
|
# Getter for dst attribute
|
191
236
|
# @return [String]
|
192
237
|
def dst
|
193
|
-
self[:dst].
|
238
|
+
self[:dst].to_human
|
194
239
|
end
|
195
240
|
alias :destination :dst
|
196
241
|
|
@@ -198,20 +243,13 @@ module PacketGen
|
|
198
243
|
# @param [String] addr
|
199
244
|
# @return [Integer]
|
200
245
|
def dst=(addr)
|
201
|
-
self[:dst].
|
246
|
+
self[:dst].from_human addr
|
202
247
|
end
|
203
248
|
alias :destination= :dst=
|
204
249
|
|
205
|
-
# Get
|
206
|
-
# @return [String]
|
207
|
-
def to_s
|
208
|
-
first32 = (version << 28) | (traffic_class << 20) | flow_label
|
209
|
-
[first32].pack('N') << to_a[3..-1].map { |field| field.to_s }.join
|
210
|
-
end
|
211
|
-
|
212
|
-
# Get IPv6 part of pseudo header sum.
|
250
|
+
# Get IPv6 part of pseudo header checksum.
|
213
251
|
# @return [Integer]
|
214
|
-
def
|
252
|
+
def pseudo_header_checksum
|
215
253
|
sum = 0
|
216
254
|
self[:src].each { |word| sum += word.to_i }
|
217
255
|
self[:dst].each { |word| sum += word.to_i }
|
@@ -247,9 +285,27 @@ module PacketGen
|
|
247
285
|
|
248
286
|
sock.sendmsg body.to_s, 0, sockaddrin, hop_limit, tc, pkt_info
|
249
287
|
end
|
288
|
+
|
289
|
+
# @return [String]
|
290
|
+
def inspect
|
291
|
+
str = Inspect.dashed_line(self.class, 2)
|
292
|
+
to_h.each do |attr, value|
|
293
|
+
next if attr == :body
|
294
|
+
str << Inspect.inspect_attribute(attr, value, 2)
|
295
|
+
if attr == :u32
|
296
|
+
shift = Inspect.shift_level(2)
|
297
|
+
str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'version', version]
|
298
|
+
tclass = Inspect.int_dec_hex(traffic_class, 2)
|
299
|
+
str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'tclass', tclass]
|
300
|
+
fl_value = Inspect.int_dec_hex(flow_label, 5)
|
301
|
+
str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'flow_label', fl_value]
|
302
|
+
end
|
303
|
+
end
|
304
|
+
str
|
305
|
+
end
|
250
306
|
end
|
251
307
|
|
252
|
-
Eth.bind_header IPv6,
|
253
|
-
IP.bind_header IPv6,
|
308
|
+
Eth.bind_header IPv6, ethertype: 0x86DD
|
309
|
+
IP.bind_header IPv6, protocol: 41 # 6to4
|
254
310
|
end
|
255
311
|
end
|