packetgen 0.3.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|