packetfu 1.1.5 → 1.1.6
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.
- data/.document +5 -2
- data/.gitignore +1 -0
- data/LICENSE.txt +1 -1
- data/bench/after-2012-07-28.txt +25 -0
- data/bench/before-2012-07-28.txt +25 -0
- data/bench/benchit.rb +68 -0
- data/bench/calc_delta.rb +17 -0
- data/bench/octets.rb +22 -0
- data/bench/octets_after.txt +8 -0
- data/bench/octets_after_refactor.txt +8 -0
- data/bench/octets_before.txt +8 -0
- data/lib/packetfu.rb +8 -3
- data/lib/packetfu/packet.rb +2 -2
- data/lib/packetfu/pcap.rb +20 -4
- data/lib/packetfu/protos/arp.rb +7 -160
- data/lib/packetfu/protos/arp/header.rb +160 -0
- data/lib/packetfu/protos/arp/mixin.rb +38 -0
- data/lib/packetfu/protos/eth.rb +5 -247
- data/lib/packetfu/protos/eth/header.rb +247 -0
- data/lib/packetfu/protos/eth/mixin.rb +20 -0
- data/lib/packetfu/protos/hsrp.rb +13 -123
- data/lib/packetfu/protos/hsrp/header.rb +120 -0
- data/lib/packetfu/protos/hsrp/mixin.rb +31 -0
- data/lib/packetfu/protos/icmp.rb +10 -97
- data/lib/packetfu/protos/icmp/header.rb +93 -0
- data/lib/packetfu/protos/icmp/mixin.rb +17 -0
- data/lib/packetfu/protos/ip.rb +7 -295
- data/lib/packetfu/protos/ip/header.rb +335 -0
- data/lib/packetfu/protos/ip/mixin.rb +43 -0
- data/lib/packetfu/protos/ipv6.rb +7 -191
- data/lib/packetfu/protos/ipv6/header.rb +190 -0
- data/lib/packetfu/protos/ipv6/mixin.rb +31 -0
- data/lib/packetfu/protos/tcp.rb +13 -939
- data/lib/packetfu/protos/tcp/ecn.rb +42 -0
- data/lib/packetfu/protos/tcp/flags.rb +83 -0
- data/lib/packetfu/protos/tcp/header.rb +307 -0
- data/lib/packetfu/protos/tcp/hlen.rb +40 -0
- data/lib/packetfu/protos/tcp/mixin.rb +48 -0
- data/lib/packetfu/protos/tcp/option.rb +323 -0
- data/lib/packetfu/protos/tcp/options.rb +106 -0
- data/lib/packetfu/protos/tcp/reserved.rb +42 -0
- data/lib/packetfu/protos/udp.rb +12 -110
- data/lib/packetfu/protos/udp/header.rb +107 -0
- data/lib/packetfu/protos/udp/mixin.rb +23 -0
- data/lib/packetfu/utils.rb +24 -24
- data/lib/packetfu/version.rb +1 -1
- data/packetfu.gemspec +2 -2
- data/test/test_ip.rb +0 -19
- data/test/test_octets.rb +18 -21
- data/test/test_tcp.rb +10 -0
- data/test/test_udp.rb +17 -0
- metadata +79 -50
@@ -0,0 +1,42 @@
|
|
1
|
+
module PacketFu
|
2
|
+
# Implements the Explict Congestion Notification for TCPHeader.
|
3
|
+
#
|
4
|
+
# ==== Header Definition
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# Fixnum (1 bit) :n
|
8
|
+
# Fixnum (1 bit) :c
|
9
|
+
# Fixnum (1 bit) :e
|
10
|
+
class TcpEcn < Struct.new(:n, :c, :e)
|
11
|
+
|
12
|
+
include StructFu
|
13
|
+
|
14
|
+
def initialize(args={})
|
15
|
+
super(args[:n], args[:c], args[:e]) if args
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the TcpEcn field as an integer... even though it's going
|
19
|
+
# to be split across a byte boundary.
|
20
|
+
def to_i
|
21
|
+
(n.to_i << 2) + (c.to_i << 1) + e.to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
# Reads a string to populate the object.
|
25
|
+
def read(str)
|
26
|
+
force_binary(str)
|
27
|
+
return self if str.nil? || str.size < 2
|
28
|
+
if 1.respond_to? :ord
|
29
|
+
byte1 = str[0].ord
|
30
|
+
byte2 = str[1].ord
|
31
|
+
else
|
32
|
+
byte1 = str[0]
|
33
|
+
byte2 = str[1]
|
34
|
+
end
|
35
|
+
self[:n] = byte1 & 0b00000001 == 0b00000001 ? 1 : 0
|
36
|
+
self[:c] = byte2 & 0b10000000 == 0b10000000 ? 1 : 0
|
37
|
+
self[:e] = byte2 & 0b01000000 == 0b01000000 ? 1 : 0
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module PacketFu
|
2
|
+
# Implements flags for TCPHeader.
|
3
|
+
#
|
4
|
+
# ==== Header Definition
|
5
|
+
#
|
6
|
+
# Fixnum (1 bit) :urg
|
7
|
+
# Fixnum (1 bit) :ack
|
8
|
+
# Fixnum (1 bit) :psh
|
9
|
+
# Fixnum (1 bit) :rst
|
10
|
+
# Fixnum (1 bit) :syn
|
11
|
+
# Fixnum (1 bit) :fin
|
12
|
+
#
|
13
|
+
# Flags can typically be set by setting them either to 1 or 0, or to true or false.
|
14
|
+
class TcpFlags < Struct.new(:urg, :ack, :psh, :rst, :syn, :fin)
|
15
|
+
|
16
|
+
include StructFu
|
17
|
+
|
18
|
+
def initialize(args={})
|
19
|
+
# This technique attemts to ensure that flags are always 0 (off)
|
20
|
+
# or 1 (on). Statements like nil and false shouldn't be lurking in here.
|
21
|
+
if args.nil? || args.size.zero?
|
22
|
+
super( 0, 0, 0, 0, 0, 0)
|
23
|
+
else
|
24
|
+
super(
|
25
|
+
(args[:urg] ? 1 : 0),
|
26
|
+
(args[:ack] ? 1 : 0),
|
27
|
+
(args[:psh] ? 1 : 0),
|
28
|
+
(args[:rst] ? 1 : 0),
|
29
|
+
(args[:syn] ? 1 : 0),
|
30
|
+
(args[:fin] ? 1 : 0)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the TcpFlags as an integer.
|
36
|
+
# Also not a great candidate for to_s due to the short bitspace.
|
37
|
+
def to_i
|
38
|
+
(urg.to_i << 5) + (ack.to_i << 4) + (psh.to_i << 3) +
|
39
|
+
(rst.to_i << 2) + (syn.to_i << 1) + fin.to_i
|
40
|
+
end
|
41
|
+
|
42
|
+
# Helper to determine if this flag is a 1 or a 0.
|
43
|
+
def zero_or_one(i=0)
|
44
|
+
if i == 0 || i == false || i == nil
|
45
|
+
0
|
46
|
+
else
|
47
|
+
1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Setter for the Urgent flag.
|
52
|
+
def urg=(i); self[:urg] = zero_or_one(i); end
|
53
|
+
# Setter for the Acknowlege flag.
|
54
|
+
def ack=(i); self[:ack] = zero_or_one(i); end
|
55
|
+
# Setter for the Push flag.
|
56
|
+
def psh=(i); self[:psh] = zero_or_one(i); end
|
57
|
+
# Setter for the Reset flag.
|
58
|
+
def rst=(i); self[:rst] = zero_or_one(i); end
|
59
|
+
# Setter for the Synchronize flag.
|
60
|
+
def syn=(i); self[:syn] = zero_or_one(i); end
|
61
|
+
# Setter for the Finish flag.
|
62
|
+
def fin=(i); self[:fin] = zero_or_one(i); end
|
63
|
+
|
64
|
+
# Reads a string to populate the object.
|
65
|
+
def read(str)
|
66
|
+
force_binary(str)
|
67
|
+
return self if str.nil?
|
68
|
+
if 1.respond_to? :ord
|
69
|
+
byte = str[0].ord
|
70
|
+
else
|
71
|
+
byte = str[0]
|
72
|
+
end
|
73
|
+
self[:urg] = byte & 0b00100000 == 0b00100000 ? 1 : 0
|
74
|
+
self[:ack] = byte & 0b00010000 == 0b00010000 ? 1 : 0
|
75
|
+
self[:psh] = byte & 0b00001000 == 0b00001000 ? 1 : 0
|
76
|
+
self[:rst] = byte & 0b00000100 == 0b00000100 ? 1 : 0
|
77
|
+
self[:syn] = byte & 0b00000010 == 0b00000010 ? 1 : 0
|
78
|
+
self[:fin] = byte & 0b00000001 == 0b00000001 ? 1 : 0
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,307 @@
|
|
1
|
+
require 'packetfu/protos/tcp/reserved'
|
2
|
+
require 'packetfu/protos/tcp/hlen'
|
3
|
+
require 'packetfu/protos/tcp/ecn'
|
4
|
+
require 'packetfu/protos/tcp/flags'
|
5
|
+
require 'packetfu/protos/tcp/option'
|
6
|
+
require 'packetfu/protos/tcp/options'
|
7
|
+
|
8
|
+
|
9
|
+
module PacketFu
|
10
|
+
# TCPHeader is a complete TCP struct, used in TCPPacket. Most IP traffic is TCP-based, by
|
11
|
+
# volume.
|
12
|
+
#
|
13
|
+
# For more on TCP packets, see http://www.networksorcery.com/enp/protocol/tcp.htm
|
14
|
+
#
|
15
|
+
# ==== Header Definition
|
16
|
+
#
|
17
|
+
# Int16 :tcp_src Default: random
|
18
|
+
# Int16 :tcp_dst
|
19
|
+
# Int32 :tcp_seq Default: random
|
20
|
+
# Int32 :tcp_ack
|
21
|
+
# TcpHlen :tcp_hlen Default: 5 # Must recalc as options are set.
|
22
|
+
# TcpReserved :tcp_reserved Default: 0
|
23
|
+
# TcpEcn :tcp_ecn
|
24
|
+
# TcpFlags :tcp_flags
|
25
|
+
# Int16 :tcp_win, Default: 0 # WinXP's default syn packet
|
26
|
+
# Int16 :tcp_sum, Default: calculated # Must set this upon generation.
|
27
|
+
# Int16 :tcp_urg
|
28
|
+
# TcpOptions :tcp_opts
|
29
|
+
# String :body
|
30
|
+
#
|
31
|
+
# See also TcpHlen, TcpReserved, TcpEcn, TcpFlags, TcpOpts
|
32
|
+
class TCPHeader < Struct.new(:tcp_src, :tcp_dst,
|
33
|
+
:tcp_seq,
|
34
|
+
:tcp_ack,
|
35
|
+
:tcp_hlen, :tcp_reserved, :tcp_ecn, :tcp_flags, :tcp_win,
|
36
|
+
:tcp_sum, :tcp_urg,
|
37
|
+
:tcp_opts, :body)
|
38
|
+
include StructFu
|
39
|
+
|
40
|
+
def initialize(args={})
|
41
|
+
@random_seq = rand(0xffffffff)
|
42
|
+
@random_src = rand_port
|
43
|
+
super(
|
44
|
+
Int16.new(args[:tcp_src] || tcp_calc_src),
|
45
|
+
Int16.new(args[:tcp_dst]),
|
46
|
+
Int32.new(args[:tcp_seq] || tcp_calc_seq),
|
47
|
+
Int32.new(args[:tcp_ack]),
|
48
|
+
TcpHlen.new(:hlen => (args[:tcp_hlen] || 5)),
|
49
|
+
TcpReserved.new(args[:tcp_reserved] || 0),
|
50
|
+
TcpEcn.new(args[:tcp_ecn]),
|
51
|
+
TcpFlags.new(args[:tcp_flags]),
|
52
|
+
Int16.new(args[:tcp_win] || 0x4000),
|
53
|
+
Int16.new(args[:tcp_sum] || 0),
|
54
|
+
Int16.new(args[:tcp_urg]),
|
55
|
+
TcpOptions.new.read(args[:tcp_opts]),
|
56
|
+
StructFu::String.new.read(args[:body])
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_accessor :flavor
|
61
|
+
|
62
|
+
# Helper function to create the string for Hlen, Reserved, ECN, and Flags.
|
63
|
+
def bits_to_s
|
64
|
+
bytes = []
|
65
|
+
bytes[0] = (self[:tcp_hlen].to_i << 4) +
|
66
|
+
(self[:tcp_reserved].to_i << 1) +
|
67
|
+
self[:tcp_ecn].n.to_i
|
68
|
+
bytes[1] = (self[:tcp_ecn].c.to_i << 7) +
|
69
|
+
(self[:tcp_ecn].e.to_i << 6) +
|
70
|
+
self[:tcp_flags].to_i
|
71
|
+
bytes.pack("CC")
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns the object in string form.
|
75
|
+
def to_s
|
76
|
+
hdr = self.to_a.map do |x|
|
77
|
+
if x.kind_of? TcpHlen
|
78
|
+
bits_to_s
|
79
|
+
elsif x.kind_of? TcpReserved
|
80
|
+
next
|
81
|
+
elsif x.kind_of? TcpEcn
|
82
|
+
next
|
83
|
+
elsif x.kind_of? TcpFlags
|
84
|
+
next
|
85
|
+
else
|
86
|
+
x.to_s
|
87
|
+
end
|
88
|
+
end
|
89
|
+
hdr.flatten.join
|
90
|
+
end
|
91
|
+
|
92
|
+
# Reads a string to populate the object.
|
93
|
+
def read(str)
|
94
|
+
force_binary(str)
|
95
|
+
return self if str.nil?
|
96
|
+
self[:tcp_src].read(str[0,2])
|
97
|
+
self[:tcp_dst].read(str[2,2])
|
98
|
+
self[:tcp_seq].read(str[4,4])
|
99
|
+
self[:tcp_ack].read(str[8,4])
|
100
|
+
self[:tcp_hlen].read(str[12,1])
|
101
|
+
self[:tcp_reserved].read(str[12,1])
|
102
|
+
self[:tcp_ecn].read(str[12,2])
|
103
|
+
self[:tcp_flags].read(str[13,1])
|
104
|
+
self[:tcp_win].read(str[14,2])
|
105
|
+
self[:tcp_sum].read(str[16,2])
|
106
|
+
self[:tcp_urg].read(str[18,2])
|
107
|
+
self[:tcp_opts].read(str[20,((self[:tcp_hlen].to_i * 4) - 20)])
|
108
|
+
self[:body].read(str[(self[:tcp_hlen].to_i * 4),str.size])
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
# Setter for the TCP source port.
|
113
|
+
def tcp_src=(i); typecast i; end
|
114
|
+
# Getter for the TCP source port.
|
115
|
+
def tcp_src; self[:tcp_src].to_i; end
|
116
|
+
# Setter for the TCP destination port.
|
117
|
+
def tcp_dst=(i); typecast i; end
|
118
|
+
# Getter for the TCP destination port.
|
119
|
+
def tcp_dst; self[:tcp_dst].to_i; end
|
120
|
+
# Setter for the TCP sequence number.
|
121
|
+
def tcp_seq=(i); typecast i; end
|
122
|
+
# Getter for the TCP sequence number.
|
123
|
+
def tcp_seq; self[:tcp_seq].to_i; end
|
124
|
+
# Setter for the TCP ackowlegement number.
|
125
|
+
def tcp_ack=(i); typecast i; end
|
126
|
+
# Getter for the TCP ackowlegement number.
|
127
|
+
def tcp_ack; self[:tcp_ack].to_i; end
|
128
|
+
# Setter for the TCP window size number.
|
129
|
+
def tcp_win=(i); typecast i; end
|
130
|
+
# Getter for the TCP window size number.
|
131
|
+
def tcp_win; self[:tcp_win].to_i; end
|
132
|
+
# Setter for the TCP checksum.
|
133
|
+
def tcp_sum=(i); typecast i; end
|
134
|
+
# Getter for the TCP checksum.
|
135
|
+
def tcp_sum; self[:tcp_sum].to_i; end
|
136
|
+
# Setter for the TCP urgent field.
|
137
|
+
def tcp_urg=(i); typecast i; end
|
138
|
+
# Getter for the TCP urgent field.
|
139
|
+
def tcp_urg; self[:tcp_urg].to_i; end
|
140
|
+
|
141
|
+
# Getter for the TCP Header Length value.
|
142
|
+
def tcp_hlen; self[:tcp_hlen].to_i; end
|
143
|
+
# Setter for the TCP Header Length value. Can take
|
144
|
+
# either a string or an integer. Note that if it's
|
145
|
+
# a string, the top four bits are used.
|
146
|
+
def tcp_hlen=(i)
|
147
|
+
case i
|
148
|
+
when PacketFu::TcpHlen
|
149
|
+
self[:tcp_hlen] = i
|
150
|
+
when Numeric
|
151
|
+
self[:tcp_hlen] = TcpHlen.new(:hlen => i.to_i)
|
152
|
+
else
|
153
|
+
self[:tcp_hlen].read(i)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Getter for the TCP Reserved field.
|
158
|
+
def tcp_reserved; self[:tcp_reserved].to_i; end
|
159
|
+
# Setter for the TCP Reserved field.
|
160
|
+
def tcp_reserved=(i)
|
161
|
+
case i
|
162
|
+
when PacketFu::TcpReserved
|
163
|
+
self[:tcp_reserved]=i
|
164
|
+
when Numeric
|
165
|
+
args = {}
|
166
|
+
args[:r1] = (i & 0b100) >> 2
|
167
|
+
args[:r2] = (i & 0b010) >> 1
|
168
|
+
args[:r3] = (i & 0b001)
|
169
|
+
self[:tcp_reserved] = TcpReserved.new(args)
|
170
|
+
else
|
171
|
+
self[:tcp_reserved].read(i)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Getter for the ECN bits.
|
176
|
+
def tcp_ecn; self[:tcp_ecn].to_i; end
|
177
|
+
# Setter for the ECN bits.
|
178
|
+
def tcp_ecn=(i)
|
179
|
+
case i
|
180
|
+
when PacketFu::TcpEcn
|
181
|
+
self[:tcp_ecn]=i
|
182
|
+
when Numeric
|
183
|
+
args = {}
|
184
|
+
args[:n] = (i & 0b100) >> 2
|
185
|
+
args[:c] = (i & 0b010) >> 1
|
186
|
+
args[:e] = (i & 0b001)
|
187
|
+
self[:tcp_ecn] = TcpEcn.new(args)
|
188
|
+
else
|
189
|
+
self[:tcp_ecn].read(i)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Getter for TCP Options.
|
194
|
+
def tcp_opts; self[:tcp_opts].to_s; end
|
195
|
+
# Setter for TCP Options.
|
196
|
+
def tcp_opts=(i)
|
197
|
+
case i
|
198
|
+
when PacketFu::TcpOptions
|
199
|
+
self[:tcp_opts]=i
|
200
|
+
else
|
201
|
+
self[:tcp_opts].read(i)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Resets the sequence number to a new random number.
|
206
|
+
def tcp_calc_seq; @random_seq; end
|
207
|
+
# Resets the source port to a new random number.
|
208
|
+
def tcp_calc_src; @random_src; end
|
209
|
+
|
210
|
+
# Returns the actual length of the TCP options.
|
211
|
+
def tcp_opts_len
|
212
|
+
self[:tcp_opts].to_s.size
|
213
|
+
end
|
214
|
+
|
215
|
+
# Sets and returns the true length of the TCP Header.
|
216
|
+
# TODO: Think about making all the option stuff safer.
|
217
|
+
def tcp_calc_hlen
|
218
|
+
self[:tcp_hlen] = TcpHlen.new(:hlen => ((20 + tcp_opts_len) / 4))
|
219
|
+
end
|
220
|
+
|
221
|
+
# Generates a random high port. This is affected by packet flavor.
|
222
|
+
def rand_port
|
223
|
+
rand(0xffff - 1025) + 1025
|
224
|
+
end
|
225
|
+
|
226
|
+
# Gets a more readable option list.
|
227
|
+
def tcp_options
|
228
|
+
self[:tcp_opts].decode
|
229
|
+
end
|
230
|
+
|
231
|
+
# Gets a more readable flags list
|
232
|
+
def tcp_flags_dotmap
|
233
|
+
dotmap = tcp_flags.members.map do |flag|
|
234
|
+
status = self.tcp_flags.send flag
|
235
|
+
status == 0 ? "." : flag.to_s.upcase[0].chr
|
236
|
+
end
|
237
|
+
dotmap.join
|
238
|
+
end
|
239
|
+
|
240
|
+
# Sets a more readable option list.
|
241
|
+
def tcp_options=(arg)
|
242
|
+
self[:tcp_opts].encode arg
|
243
|
+
end
|
244
|
+
|
245
|
+
# Equivalent to tcp_src.
|
246
|
+
def tcp_sport
|
247
|
+
self.tcp_src.to_i
|
248
|
+
end
|
249
|
+
|
250
|
+
# Equivalent to tcp_src=.
|
251
|
+
def tcp_sport=(arg)
|
252
|
+
self.tcp_src=(arg)
|
253
|
+
end
|
254
|
+
|
255
|
+
# Equivalent to tcp_dst.
|
256
|
+
def tcp_dport
|
257
|
+
self.tcp_dst.to_i
|
258
|
+
end
|
259
|
+
|
260
|
+
# Equivalent to tcp_dst=.
|
261
|
+
def tcp_dport=(arg)
|
262
|
+
self.tcp_dst=(arg)
|
263
|
+
end
|
264
|
+
|
265
|
+
# Recalculates calculated fields for TCP (except checksum which is at the Packet level).
|
266
|
+
def tcp_recalc(arg=:all)
|
267
|
+
case arg
|
268
|
+
when :tcp_hlen
|
269
|
+
tcp_calc_hlen
|
270
|
+
when :tcp_src
|
271
|
+
@random_tcp_src = rand_port
|
272
|
+
when :tcp_sport
|
273
|
+
@random_tcp_src = rand_port
|
274
|
+
when :tcp_seq
|
275
|
+
@random_tcp_seq = rand(0xffffffff)
|
276
|
+
when :all
|
277
|
+
tcp_calc_hlen
|
278
|
+
@random_tcp_src = rand_port
|
279
|
+
@random_tcp_seq = rand(0xffffffff)
|
280
|
+
else
|
281
|
+
raise ArgumentError, "No such field `#{arg}'"
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
# Readability aliases
|
286
|
+
|
287
|
+
alias :tcp_flags_readable :tcp_flags_dotmap
|
288
|
+
|
289
|
+
def tcp_ack_readable
|
290
|
+
"0x%08x" % tcp_ack
|
291
|
+
end
|
292
|
+
|
293
|
+
def tcp_seq_readable
|
294
|
+
"0x%08x" % tcp_seq
|
295
|
+
end
|
296
|
+
|
297
|
+
def tcp_sum_readable
|
298
|
+
"0x%04x" % tcp_sum
|
299
|
+
end
|
300
|
+
|
301
|
+
def tcp_opts_readable
|
302
|
+
tcp_options
|
303
|
+
end
|
304
|
+
|
305
|
+
end
|
306
|
+
|
307
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module PacketFu
|
2
|
+
# Implements the Header Length for TCPHeader.
|
3
|
+
#
|
4
|
+
# ==== Header Definition
|
5
|
+
#
|
6
|
+
# Fixnum (4 bits) :hlen
|
7
|
+
class TcpHlen < Struct.new(:hlen)
|
8
|
+
|
9
|
+
include StructFu
|
10
|
+
|
11
|
+
def initialize(args={})
|
12
|
+
super(args[:hlen])
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the TcpHlen field as an integer. Note these will become the high
|
16
|
+
# bits at the TCP header's offset, even though the lower 4 bits
|
17
|
+
# will be further chopped up.
|
18
|
+
def to_i
|
19
|
+
hlen.to_i & 0b1111
|
20
|
+
end
|
21
|
+
|
22
|
+
# Reads a string to populate the object.
|
23
|
+
def read(str)
|
24
|
+
force_binary(str)
|
25
|
+
return self if str.nil? || str.size.zero?
|
26
|
+
if 1.respond_to? :ord
|
27
|
+
self[:hlen] = (str[0].ord & 0b11110000) >> 4
|
28
|
+
else
|
29
|
+
self[:hlen] = (str[0] & 0b11110000) >> 4
|
30
|
+
end
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the object in string form.
|
35
|
+
def to_s
|
36
|
+
[self.to_i].pack("C")
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|