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
@@ -0,0 +1,254 @@
|
|
1
|
+
module PacketGen
|
2
|
+
module Header
|
3
|
+
class TCP
|
4
|
+
|
5
|
+
# Base class to describe a TCP option
|
6
|
+
# @author Sylvain Daubert
|
7
|
+
class Option < Struct.new(:kind, :length, :value)
|
8
|
+
include StructFu
|
9
|
+
|
10
|
+
EOL_KIND = 0
|
11
|
+
NOP_KIND = 1
|
12
|
+
MSS_KIND = 2
|
13
|
+
WS_KIND = 3
|
14
|
+
SACKOK_KIND = 4
|
15
|
+
SACK_KIND = 5
|
16
|
+
ECHO_KIND = 6
|
17
|
+
ECHOREPLY_KIND = 7
|
18
|
+
TS_KIND = 8
|
19
|
+
|
20
|
+
# @param [hash] options
|
21
|
+
# @option options [Integer] :kind
|
22
|
+
# @option options [Integer] :length
|
23
|
+
# @option options [Integer,String] :value
|
24
|
+
def initialize(options={})
|
25
|
+
super Int8.new(options[:kind]),
|
26
|
+
Int8.new(options[:length])
|
27
|
+
|
28
|
+
case options[:value]
|
29
|
+
when Integer
|
30
|
+
klass = case self[:length].to_i
|
31
|
+
when 3; Int8
|
32
|
+
when 4; Int16
|
33
|
+
when 6; Int32
|
34
|
+
else
|
35
|
+
raise ArgumentError, 'impossible length'
|
36
|
+
end
|
37
|
+
self[:value] = klass.new(options[:value])
|
38
|
+
when NilClass
|
39
|
+
self[:value] = StructFu::String.new
|
40
|
+
else
|
41
|
+
self[:value] = StructFu::String.new.read(options[:value])
|
42
|
+
self[:length].read(self[:value].sz + 2) unless options[:length]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Read a TCP option from a string
|
47
|
+
# @param [String] str binary string
|
48
|
+
# @return [self]
|
49
|
+
def read(str)
|
50
|
+
return self if str.nil?
|
51
|
+
force_binary str
|
52
|
+
self[:kind].read str[0, 1]
|
53
|
+
if str[1, 1]
|
54
|
+
self[:length].read str[1, 1]
|
55
|
+
if str[2, 1] && length > 2
|
56
|
+
self[:value].read str[2, length - 2]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
# Getter for kind attribute
|
63
|
+
# @return [Integer]
|
64
|
+
def kind
|
65
|
+
self[:kind].to_i
|
66
|
+
end
|
67
|
+
|
68
|
+
# Setter for kind attribute
|
69
|
+
# @param [Integer] i
|
70
|
+
# @return [Integer]
|
71
|
+
def kind=(i)
|
72
|
+
self[:kind].read i
|
73
|
+
end
|
74
|
+
|
75
|
+
# Getter for length attribute
|
76
|
+
# @return [Integer]
|
77
|
+
def length
|
78
|
+
self[:length].to_i
|
79
|
+
end
|
80
|
+
|
81
|
+
# Setter for length attribute
|
82
|
+
# @param [Integer] i
|
83
|
+
# @return [Integer]
|
84
|
+
def length=(i)
|
85
|
+
self[:length].read i
|
86
|
+
end
|
87
|
+
|
88
|
+
# Say if option has a length
|
89
|
+
# @return [Boolean]
|
90
|
+
def has_length?
|
91
|
+
self[:kind].value && kind >= 2
|
92
|
+
end
|
93
|
+
|
94
|
+
# Getter for value attribute
|
95
|
+
# @return [String, Integer]
|
96
|
+
def value
|
97
|
+
case self[:value]
|
98
|
+
when StructFu::Int
|
99
|
+
self[:value].to_i
|
100
|
+
else
|
101
|
+
self[:value].to_s
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Setter for value attribute
|
106
|
+
# @param [String, Integer] v
|
107
|
+
# @return [String, Integer]
|
108
|
+
def value=(v)
|
109
|
+
self[:value].read v
|
110
|
+
end
|
111
|
+
|
112
|
+
# Get binary string
|
113
|
+
# @return [String]
|
114
|
+
def to_s
|
115
|
+
str = self[:kind].to_s
|
116
|
+
str << self[:length].to_s unless self[:length].value.nil?
|
117
|
+
str << self[:value].to_s if length > 2
|
118
|
+
str
|
119
|
+
end
|
120
|
+
|
121
|
+
# Get option as a human readable string
|
122
|
+
# @return [String]
|
123
|
+
def to_human
|
124
|
+
str = self.class == Option ? "unk-#{kind}" : self.class.to_s.sub(/.*::/, '')
|
125
|
+
if length > 2 and self[:value].to_s.size > 0
|
126
|
+
str << ":#{self[:value].to_s.inspect}"
|
127
|
+
end
|
128
|
+
str
|
129
|
+
end
|
130
|
+
|
131
|
+
# @return [String]
|
132
|
+
def inspect
|
133
|
+
str = "#<#{self.class} kind=#{self[:kind].value.inspect} "
|
134
|
+
str << "length=#{self[:length].value.inspect} " if self[:length].value
|
135
|
+
str << "value=#{self[:value].inspect}>"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# End Of Option TCP option
|
140
|
+
# @author Sylvain Daubert
|
141
|
+
class EOL < Option
|
142
|
+
# @see Option#initialize
|
143
|
+
def initialize(options={})
|
144
|
+
super options.merge!(kind: EOL_KIND)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# No OPeration TCP option
|
149
|
+
# @author Sylvain Daubert
|
150
|
+
class NOP < Option
|
151
|
+
# @see Option#initialize
|
152
|
+
def initialize(options={})
|
153
|
+
super options.merge!(kind: NOP_KIND)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Maximum Segment Size TCP option
|
158
|
+
# @author Sylvain Daubert
|
159
|
+
class MSS < Option
|
160
|
+
# @see Option#initialize
|
161
|
+
def initialize(options={})
|
162
|
+
super options.merge!(kind: MSS_KIND, length: 4)
|
163
|
+
self[:value] = Int16.new(options[:value])
|
164
|
+
end
|
165
|
+
|
166
|
+
# @return [String]
|
167
|
+
def to_human
|
168
|
+
"MSS:#{value}"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Window Size TCP option
|
173
|
+
# @author Sylvain Daubert
|
174
|
+
class WS < Option
|
175
|
+
# @see Option#initialize
|
176
|
+
def initialize(options={})
|
177
|
+
super options.merge!(kind: WS_KIND, length: 3)
|
178
|
+
self[:value] = Int8.new(options[:value])
|
179
|
+
end
|
180
|
+
|
181
|
+
# @return [String]
|
182
|
+
def to_human
|
183
|
+
"WS:#{value}"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Selective Acknowledgment OK TCP option
|
188
|
+
# @author Sylvain Daubert
|
189
|
+
class SACKOK < Option
|
190
|
+
# @see Option#initialize
|
191
|
+
def initialize(options={})
|
192
|
+
super options.merge!(kind: SACKOK_KIND, length: 2)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# Selective Acknowledgment TCP option
|
197
|
+
# @author Sylvain Daubert
|
198
|
+
class SACK < Option
|
199
|
+
# @see Option#initialize
|
200
|
+
def initialize(options={})
|
201
|
+
super options.merge!(kind: SACK_KIND)
|
202
|
+
self[:length].read(2) if self[:value].to_s == ''
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Echo TCP option
|
207
|
+
# @author Sylvain Daubert
|
208
|
+
class ECHO < Option
|
209
|
+
# @see Option#initialize
|
210
|
+
def initialize(options={})
|
211
|
+
super options.merge!(kind: ECHO_KIND, length: 6)
|
212
|
+
self[:value] = Int32.new(options[:value])
|
213
|
+
end
|
214
|
+
|
215
|
+
# @return [String]
|
216
|
+
def to_human
|
217
|
+
"WS:#{value}"
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Echo Reply TCP option
|
222
|
+
# @author Sylvain Daubert
|
223
|
+
class ECHOREPLY < Option
|
224
|
+
# @see Option#initialize
|
225
|
+
def initialize(options={})
|
226
|
+
super options.merge!(kind: ECHOREPLY_KIND, length: 6)
|
227
|
+
self[:value] = Int32.new(options[:value])
|
228
|
+
end
|
229
|
+
|
230
|
+
# @return [String]
|
231
|
+
def to_human
|
232
|
+
"WS:#{value}"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# Timestamp TCP option
|
237
|
+
# @author Sylvain Daubert
|
238
|
+
class TS < Option
|
239
|
+
# @see Option#initialize
|
240
|
+
def initialize(options={})
|
241
|
+
super options.merge!(kind: TS_KIND, length: 10)
|
242
|
+
self[:value] = StructFu::String.new.read(options[:value] || "\0" * 8)
|
243
|
+
end
|
244
|
+
|
245
|
+
# @return [String]
|
246
|
+
def to_human
|
247
|
+
value, echo_reply = self[:value].unpack('NN')
|
248
|
+
"TS:#{value};#{echo_reply}"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module PacketGen
|
2
|
+
module Header
|
3
|
+
class TCP
|
4
|
+
|
5
|
+
# Container for TCP options in {TCP TCP header}.
|
6
|
+
# @author Sylvain Daubert
|
7
|
+
class Options < Array
|
8
|
+
|
9
|
+
# Get {Option} subclasses
|
10
|
+
# @return [Array<Class>]
|
11
|
+
def self.option_classes
|
12
|
+
return @klasses if defined? @klasses
|
13
|
+
@klasses = []
|
14
|
+
Option.constants.each do |cst|
|
15
|
+
next unless cst.to_s.end_with? '_KIND'
|
16
|
+
optname = cst.to_s.sub(/_KIND/, '')
|
17
|
+
@klasses[Option.const_get(cst)] = TCP.const_get(optname)
|
18
|
+
end
|
19
|
+
@klasses
|
20
|
+
end
|
21
|
+
|
22
|
+
# Read TCP header options from a string
|
23
|
+
# @param [String] str binary string
|
24
|
+
# @return [self]
|
25
|
+
def read(str)
|
26
|
+
clear
|
27
|
+
return self if str.nil?
|
28
|
+
PacketGen.force_binary str
|
29
|
+
|
30
|
+
i = 0
|
31
|
+
klasses = self.class.option_classes
|
32
|
+
while i < str.to_s.length
|
33
|
+
kind = str[i, 1].unpack('C').first
|
34
|
+
this_option = if klasses[kind].nil?
|
35
|
+
Option.new
|
36
|
+
else
|
37
|
+
klasses[kind].new
|
38
|
+
end
|
39
|
+
this_option.read str[i, str.size]
|
40
|
+
unless this_option.has_length?
|
41
|
+
this_option.length = nil
|
42
|
+
this_option.value = nil
|
43
|
+
end
|
44
|
+
self << this_option
|
45
|
+
i += this_option.sz
|
46
|
+
end
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
# Add a well-known option
|
51
|
+
# @param [String] opt option name
|
52
|
+
# @param [Object] value
|
53
|
+
# @return [self]
|
54
|
+
# @raise [ArgumentError] unknown option
|
55
|
+
def add(opt, value=nil)
|
56
|
+
raise ArgumentError, "unknown option #{opt}" unless TCP.const_defined?(opt)
|
57
|
+
klass = TCP.const_get(opt)
|
58
|
+
raise ArgumentError "unknown option #{opt}" unless klass < Option
|
59
|
+
option = klass.new(value: value)
|
60
|
+
self << option
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
# Get options binary string
|
65
|
+
# @return [String]
|
66
|
+
def to_s
|
67
|
+
map(&:to_s).join
|
68
|
+
end
|
69
|
+
|
70
|
+
# Get a human readable string
|
71
|
+
# @return [String]
|
72
|
+
def to_human
|
73
|
+
map(&:to_human).join(', ')
|
74
|
+
end
|
75
|
+
|
76
|
+
# Get options size in bytes
|
77
|
+
# @return [Integer]
|
78
|
+
def sz
|
79
|
+
to_s.length
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
require_relative 'option'
|
@@ -0,0 +1,299 @@
|
|
1
|
+
module PacketGen
|
2
|
+
module Header
|
3
|
+
|
4
|
+
# A TCP header consists of:
|
5
|
+
# * a source port ({#sport}, {Int16} type),
|
6
|
+
# * a destination port ({#dport}, +Int16+ type),
|
7
|
+
# * a sequence number ({#seqnum}, {Int32} type),
|
8
|
+
# * an acknownledge number ({#acknum}, +Int32+ type),
|
9
|
+
# * a 16-bit field ({#u16}, +Int16+ type) composed of:
|
10
|
+
# * a 4-bit {#data_offset} value,
|
11
|
+
# * a 3-bit {#reserved} field,
|
12
|
+
# * a 9-bit {#flags} field,
|
13
|
+
# * a {#window} field (+Int16+ type),
|
14
|
+
# * a {#checksum} field (+Int16+ type),
|
15
|
+
# * a urgent pointer ({#urg_pointer}, +Int16+ type),
|
16
|
+
# * an optional {#options} field ({Options} type),
|
17
|
+
# * and a {#body} ({String} type).
|
18
|
+
#
|
19
|
+
# == Create a TCP header
|
20
|
+
# # standalone
|
21
|
+
# tcph = PacketGen::Header::TCP.new
|
22
|
+
# # in a IP packet
|
23
|
+
# pkt = PacketGen.gen('IP').add('TCP')
|
24
|
+
# # access to TCP header
|
25
|
+
# pkt.tcp # => PacketGen::Header::TCP
|
26
|
+
#
|
27
|
+
# == TCP attributes
|
28
|
+
# tcph.sport = 4500
|
29
|
+
# tcph.dport = 80
|
30
|
+
# tcph.seqnum = 43
|
31
|
+
# tcph.acknum = 0x45678925
|
32
|
+
# tcph.wsize = 0x240
|
33
|
+
# tcph.urg_pointer = 0x40
|
34
|
+
# tcph.body.read 'this is a body'
|
35
|
+
#
|
36
|
+
# == Flags
|
37
|
+
# TCP flags may be accesed as a 9-bit integer:
|
38
|
+
# tcph.flags = 0x1002
|
39
|
+
# Each flag may be accessed independently:
|
40
|
+
# tcph.flag_syn? # => Boolean
|
41
|
+
# tcph.flag_rst = true
|
42
|
+
#
|
43
|
+
# == Options
|
44
|
+
# {#options} TCP attribute is a {Options}. {Option} may added to it:
|
45
|
+
# tcph.options << PacketGen::Header::TCP::MSS.new(1250)
|
46
|
+
# Another way is to use {Options#add}:
|
47
|
+
# tcph.options.add 'MSS', 1250
|
48
|
+
# @author Sylvain Daubert
|
49
|
+
class TCP < Struct.new(:sport, :dport, :seqnum, :acknum, :u16,
|
50
|
+
:window, :checksum, :urg_pointer, :options, :body)
|
51
|
+
include StructFu
|
52
|
+
include HeaderMethods
|
53
|
+
extend HeaderClassMethods
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Need to load Options now, as this is used through define_bit_fields_on,
|
59
|
+
# which make a call to TCP.new, which needs Options
|
60
|
+
require_relative 'tcp/options'
|
61
|
+
|
62
|
+
module PacketGen
|
63
|
+
module Header
|
64
|
+
class TCP
|
65
|
+
# IP protocol number for TCP
|
66
|
+
IP_PROTOCOL = 6
|
67
|
+
|
68
|
+
# @param [Hash] options
|
69
|
+
# @option options [Integer] :sport
|
70
|
+
# @option options [Integer] :dport
|
71
|
+
# @option options [Integer] :seqnum
|
72
|
+
# @option options [Integer] :acknum
|
73
|
+
# @option options [Integer] :data_offset
|
74
|
+
# @option options [Integer] :reserved
|
75
|
+
# @option options [Integer] :flags
|
76
|
+
# @option options [Integer] :window
|
77
|
+
# @option options [Integer] :checksum
|
78
|
+
# @option options [Integer] :urg_pointer
|
79
|
+
# @option options [String] :body
|
80
|
+
def initialize(options={})
|
81
|
+
super Int16.new(options[:sport]),
|
82
|
+
Int16.new(options[:dport]),
|
83
|
+
Int32.new(options[:seqnum] || rand(2**32)),
|
84
|
+
Int32.new(options[:acknum]),
|
85
|
+
Int16.new,
|
86
|
+
Int16.new(options[:window] || options[:wsize]),
|
87
|
+
Int16.new(options[:checksum]),
|
88
|
+
Int16.new(options[:urg_pointer]),
|
89
|
+
Options.new,
|
90
|
+
StructFu::String.new.read(options[:body])
|
91
|
+
|
92
|
+
doff = options[:data_offset] || options[:hlen] || 5
|
93
|
+
rsv = options[:reserved] || 0
|
94
|
+
flgs = options[:flags] || 0
|
95
|
+
self.u16.read (((doff << 3) | rsv) << 9) | flgs
|
96
|
+
end
|
97
|
+
|
98
|
+
# @!attribute data_offset
|
99
|
+
# @return [Integer] 4-bit data offsetfrom {#u16}
|
100
|
+
# @!attribute reserved
|
101
|
+
# @return [Integer] 3-bit reserved from {#u16}
|
102
|
+
# @!attribute flags
|
103
|
+
# @return [Integer] 9-bit flags from {#u16}
|
104
|
+
define_bit_fields_on :u16, :data_offset, 4, :reserved, 3, :flags, 9
|
105
|
+
alias :hlen :data_offset
|
106
|
+
alias :hlen= :data_offset=
|
107
|
+
|
108
|
+
# @!attribute flag_ns
|
109
|
+
# @return [Boolean] 1-bit NS flag
|
110
|
+
# @!attribute flag_cwr
|
111
|
+
# @return [Boolean] 1-bit CWR flag
|
112
|
+
# @!attribute flag_ece
|
113
|
+
# @return [Boolean] 1-bit ECE flag
|
114
|
+
# @!attribute flag_urg
|
115
|
+
# @return [Boolean] 1-bit URG flag
|
116
|
+
# @!attribute flag_ack
|
117
|
+
# @return [Boolean] 1-bit ACK flag
|
118
|
+
# @!attribute flag_psh
|
119
|
+
# @return [Boolean] 1-bit PSH flag
|
120
|
+
# @!attribute flag_rst
|
121
|
+
# @return [Boolean] 1-bit RST flag
|
122
|
+
# @!attribute flag_syn
|
123
|
+
# @return [Boolean] 1-bit SYN flag
|
124
|
+
# @!attribute flag_fin
|
125
|
+
# @return [Boolean] 1-bit FIN flag
|
126
|
+
define_bit_fields_on :u16, :_, 7, :flag_ns, :flag_cwr, :flag_ece, :flag_urg,
|
127
|
+
:flag_ack, :flag_psh, :flag_rst, :flag_syn, :flag_fin
|
128
|
+
# Read a TCP header from a string
|
129
|
+
# @param [String] str binary string
|
130
|
+
# @return [self]
|
131
|
+
def read(str)
|
132
|
+
return self if str.nil?
|
133
|
+
raise ParseError, 'string too short for TCP' if str.size < self.sz
|
134
|
+
force_binary str
|
135
|
+
self[:sport].read str[0, 2]
|
136
|
+
self[:dport].read str[2, 2]
|
137
|
+
self[:seqnum].read str[4, 4]
|
138
|
+
self[:acknum].read str[8, 4]
|
139
|
+
self[:u16].read str[12, 2]
|
140
|
+
self[:window].read str[14, 2]
|
141
|
+
self[:checksum].read str[16, 2]
|
142
|
+
self[:urg_pointer].read str[18, 2]
|
143
|
+
self[:options].read str[20, (self.data_offset - 5) * 4] if self.data_offset > 5
|
144
|
+
self[:body].read str[self.data_offset * 4..-1]
|
145
|
+
end
|
146
|
+
|
147
|
+
# Compute checksum and set +checksum+ field
|
148
|
+
# @return [Integer]
|
149
|
+
def calc_checksum
|
150
|
+
sum = ip_header(self).pseudo_header_checksum
|
151
|
+
sum += IP_PROTOCOL
|
152
|
+
sum += self.sz
|
153
|
+
str = self.to_s
|
154
|
+
str << "\x00" if str.length % 2 == 1
|
155
|
+
sum += str.unpack('n*').reduce(:+)
|
156
|
+
|
157
|
+
while sum > 0xffff do
|
158
|
+
sum = (sum & 0xffff) + (sum >> 16)
|
159
|
+
end
|
160
|
+
sum = ~sum & 0xffff
|
161
|
+
self[:checksum].value = (sum == 0) ? 0xffff : sum
|
162
|
+
end
|
163
|
+
|
164
|
+
# Compute header length and set +data_offset+ field
|
165
|
+
# @return [Integer]
|
166
|
+
def calc_length
|
167
|
+
self[:data_offset] = 5 + self[:options].sz / 4
|
168
|
+
end
|
169
|
+
|
170
|
+
# Getter for source port
|
171
|
+
# @return [Integer]
|
172
|
+
def sport
|
173
|
+
self[:sport].to_i
|
174
|
+
end
|
175
|
+
alias :source_port :sport
|
176
|
+
|
177
|
+
# Setter for source port
|
178
|
+
# @param [Integer] port
|
179
|
+
# @return [Integer]
|
180
|
+
def sport=(port)
|
181
|
+
self[:sport].read port
|
182
|
+
end
|
183
|
+
alias :source_port= :sport=
|
184
|
+
|
185
|
+
# Getter for destination port
|
186
|
+
# @return [Integer]
|
187
|
+
def dport
|
188
|
+
self[:dport].to_i
|
189
|
+
end
|
190
|
+
alias :destination_port :dport
|
191
|
+
|
192
|
+
# Setter for destination port
|
193
|
+
# @param [Integer] port
|
194
|
+
# @return [Integer]
|
195
|
+
def dport=(port)
|
196
|
+
self[:dport].read port
|
197
|
+
end
|
198
|
+
alias :destination_port= :dport=
|
199
|
+
|
200
|
+
# Getter for seqnum attribuute
|
201
|
+
# @return [Integer]
|
202
|
+
def seqnum
|
203
|
+
self[:seqnum].to_i
|
204
|
+
end
|
205
|
+
alias :sequence_number :seqnum
|
206
|
+
|
207
|
+
# Setter for seqnum attribuute
|
208
|
+
# @param [Integer] seq
|
209
|
+
# @return [Integer]
|
210
|
+
def seqnum=(seq)
|
211
|
+
self[:seqnum].read seq
|
212
|
+
end
|
213
|
+
alias :sequence_number= :seqnum=
|
214
|
+
|
215
|
+
# Getter for acknum attribuute
|
216
|
+
# @return [Integer]
|
217
|
+
def acknum
|
218
|
+
self[:acknum].to_i
|
219
|
+
end
|
220
|
+
alias :acknowledgment_number :acknum
|
221
|
+
|
222
|
+
# Setter for acknum attribuute
|
223
|
+
# @param [Integer] ack
|
224
|
+
# @return [Integer]
|
225
|
+
def acknum=(ack)
|
226
|
+
self[:acknum].read ack
|
227
|
+
end
|
228
|
+
alias :acknowledgment_number= :acknum=
|
229
|
+
|
230
|
+
alias :hlen :data_offset
|
231
|
+
alias :hlen= :data_offset=
|
232
|
+
|
233
|
+
# Getter for window attribuute
|
234
|
+
# @return [Integer]
|
235
|
+
def window
|
236
|
+
self[:window].to_i
|
237
|
+
end
|
238
|
+
alias :wsize :window
|
239
|
+
|
240
|
+
# Setter for window attribuute
|
241
|
+
# @param [Integer] window
|
242
|
+
# @return [Integer]
|
243
|
+
def window=(window)
|
244
|
+
self[:window].read window
|
245
|
+
end
|
246
|
+
alias :wsize= :window=
|
247
|
+
|
248
|
+
# Getter for checksum attribuute
|
249
|
+
# @return [Integer]
|
250
|
+
def checksum
|
251
|
+
self[:checksum].to_i
|
252
|
+
end
|
253
|
+
|
254
|
+
# Setter for checksum attribuute
|
255
|
+
# @param [Integer] sum
|
256
|
+
# @return [Integer]
|
257
|
+
def checksum=(sum)
|
258
|
+
self[:checksum].read sum
|
259
|
+
end
|
260
|
+
|
261
|
+
# Getter for urg_pointer attribuute
|
262
|
+
# @return [Integer]
|
263
|
+
def urg_pointer
|
264
|
+
self[:urg_pointer].to_i
|
265
|
+
end
|
266
|
+
|
267
|
+
# Setter for urg_pointer attribuute
|
268
|
+
# @param [Integer] urg
|
269
|
+
# @return [Integer]
|
270
|
+
def urg_pointer=(urg)
|
271
|
+
self[:urg_pointer].read urg
|
272
|
+
end
|
273
|
+
|
274
|
+
# @return [String]
|
275
|
+
def inspect
|
276
|
+
str = Inspect.dashed_line(self.class, 2)
|
277
|
+
shift = Inspect.shift_level(2)
|
278
|
+
to_h.each do |attr, value|
|
279
|
+
next if attr == :body
|
280
|
+
str << Inspect.inspect_attribute(attr, value, 2)
|
281
|
+
if attr == :u16
|
282
|
+
doff = Inspect.int_dec_hex(data_offset, 1)
|
283
|
+
str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'data_offset', doff]
|
284
|
+
str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'reserved', reserved]
|
285
|
+
flags = ''
|
286
|
+
%w(ns cwr ece urg ack psh rst syn fin).each do |fl|
|
287
|
+
flags << (send("flag_#{fl}?") ? fl[0].upcase : '.')
|
288
|
+
end
|
289
|
+
str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'flags', flags]
|
290
|
+
end
|
291
|
+
end
|
292
|
+
str
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
IP.bind_header TCP, protocol: TCP::IP_PROTOCOL
|
297
|
+
IPv6.bind_header TCP, next: TCP::IP_PROTOCOL
|
298
|
+
end
|
299
|
+
end
|