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 Reserved bits for TCPHeader.
|
3
|
+
#
|
4
|
+
# ==== Header Definition
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# Fixnum (1 bit) :r1
|
8
|
+
# Fixnum (1 bit) :r2
|
9
|
+
# Fixnum (1 bit) :r3
|
10
|
+
class TcpReserved < Struct.new(:r1, :r2, :r3)
|
11
|
+
|
12
|
+
include StructFu
|
13
|
+
|
14
|
+
def initialize(args={})
|
15
|
+
super(
|
16
|
+
args[:r1] || 0,
|
17
|
+
args[:r2] || 0,
|
18
|
+
args[:r3] || 0) if args.kind_of? Hash
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the Reserved field as an integer.
|
22
|
+
def to_i
|
23
|
+
(r1.to_i << 2) + (r2.to_i << 1) + r3.to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
# Reads a string to populate the object.
|
27
|
+
def read(str)
|
28
|
+
force_binary(str)
|
29
|
+
return self if str.nil? || str.size.zero?
|
30
|
+
if 1.respond_to? :ord
|
31
|
+
byte = str[0].ord
|
32
|
+
else
|
33
|
+
byte = str[0]
|
34
|
+
end
|
35
|
+
self[:r1] = byte & 0b00000100 == 0b00000100 ? 1 : 0
|
36
|
+
self[:r2] = byte & 0b00000010 == 0b00000010 ? 1 : 0
|
37
|
+
self[:r3] = byte & 0b00000001 == 0b00000001 ? 1 : 0
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
data/lib/packetfu/protos/udp.rb
CHANGED
@@ -1,109 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# UDPHeader is a complete UDP struct, used in UDPPacket. Many Internet-critical protocols
|
4
|
-
# rely on UDP, such as DNS and World of Warcraft.
|
5
|
-
#
|
6
|
-
# For more on UDP packets, see http://www.networksorcery.com/enp/protocol/udp.htm
|
7
|
-
#
|
8
|
-
# ==== Header Definition
|
9
|
-
# Int16 :udp_src
|
10
|
-
# Int16 :udp_dst
|
11
|
-
# Int16 :udp_len Default: calculated
|
12
|
-
# Int16 :udp_sum Default: 0. Often calculated.
|
13
|
-
# String :body
|
14
|
-
class UDPHeader < Struct.new(:udp_src, :udp_dst, :udp_len, :udp_sum, :body)
|
15
|
-
|
16
|
-
include StructFu
|
17
|
-
|
18
|
-
def initialize(args={})
|
19
|
-
super(
|
20
|
-
Int16.new(args[:udp_src]),
|
21
|
-
Int16.new(args[:udp_dst]),
|
22
|
-
Int16.new(args[:udp_len] || udp_calc_len),
|
23
|
-
Int16.new(args[:udp_sum]),
|
24
|
-
StructFu::String.new.read(args[:body])
|
25
|
-
)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Returns the object in string form.
|
29
|
-
def to_s
|
30
|
-
self.to_a.map {|x| x.to_s}.join
|
31
|
-
end
|
32
|
-
|
33
|
-
# Reads a string to populate the object.
|
34
|
-
def read(str)
|
35
|
-
force_binary(str)
|
36
|
-
return self if str.nil?
|
37
|
-
self[:udp_src].read(str[0,2])
|
38
|
-
self[:udp_dst].read(str[2,2])
|
39
|
-
self[:udp_len].read(str[4,2])
|
40
|
-
self[:udp_sum].read(str[6,2])
|
41
|
-
self[:body].read(str[8,str.size])
|
42
|
-
self
|
43
|
-
end
|
44
|
-
|
45
|
-
# Setter for the UDP source port.
|
46
|
-
def udp_src=(i); typecast i; end
|
47
|
-
# Getter for the UDP source port.
|
48
|
-
def udp_src; self[:udp_src].to_i; end
|
49
|
-
# Setter for the UDP destination port.
|
50
|
-
def udp_dst=(i); typecast i; end
|
51
|
-
# Getter for the UDP destination port.
|
52
|
-
def udp_dst; self[:udp_dst].to_i; end
|
53
|
-
# Setter for the length field. Usually should be recalc()'ed instead.
|
54
|
-
def udp_len=(i); typecast i; end
|
55
|
-
# Getter for the length field.
|
56
|
-
def udp_len; self[:udp_len].to_i; end
|
57
|
-
# Setter for the checksum. Usually should be recalc()'ed instad.
|
58
|
-
def udp_sum=(i); typecast i; end
|
59
|
-
# Getter for the checksum.
|
60
|
-
def udp_sum; self[:udp_sum].to_i; end
|
61
|
-
|
62
|
-
# Returns the true length of the UDP packet.
|
63
|
-
def udp_calc_len
|
64
|
-
body.to_s.size + 8
|
65
|
-
end
|
66
|
-
|
67
|
-
# Recalculates calculated fields for UDP.
|
68
|
-
def udp_recalc(args=:all)
|
69
|
-
arg = arg.intern if arg.respond_to? :intern
|
70
|
-
case args
|
71
|
-
when :udp_len
|
72
|
-
self.udp_len = udp_calc_len
|
73
|
-
when :all
|
74
|
-
self.udp_recalc(:udp_len)
|
75
|
-
else
|
76
|
-
raise ArgumentError, "No such field `#{arg}'"
|
77
|
-
end
|
78
|
-
end
|
1
|
+
require 'packetfu/protos/eth/header'
|
2
|
+
require 'packetfu/protos/eth/mixin'
|
79
3
|
|
80
|
-
|
81
|
-
|
82
|
-
self.udp_src
|
83
|
-
end
|
4
|
+
require 'packetfu/protos/ip/header'
|
5
|
+
require 'packetfu/protos/ip/mixin'
|
84
6
|
|
85
|
-
|
86
|
-
|
87
|
-
self.udp_src=(arg)
|
88
|
-
end
|
7
|
+
require 'packetfu/protos/udp/header'
|
8
|
+
require 'packetfu/protos/udp/mixin'
|
89
9
|
|
90
|
-
|
91
|
-
def udp_dport
|
92
|
-
self.udp_dst
|
93
|
-
end
|
94
|
-
|
95
|
-
# Equivalent to udp_dst=
|
96
|
-
def udp_dport=(arg)
|
97
|
-
self.udp_dst=(arg)
|
98
|
-
end
|
99
|
-
|
100
|
-
# Readability aliases
|
101
|
-
|
102
|
-
def udp_sum_readable
|
103
|
-
"0x%04x" % udp_sum
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
10
|
+
module PacketFu
|
107
11
|
|
108
12
|
# UDPPacket is used to construct UDP Packets. They contain an EthHeader, an IPHeader, and a UDPHeader.
|
109
13
|
#
|
@@ -131,6 +35,9 @@ module PacketFu
|
|
131
35
|
# :config
|
132
36
|
# A hash of return address details, often the output of Utils.whoami?
|
133
37
|
class UDPPacket < Packet
|
38
|
+
include ::PacketFu::EthHeaderMixin
|
39
|
+
include ::PacketFu::IPHeaderMixin
|
40
|
+
include ::PacketFu::UDPHeaderMixin
|
134
41
|
|
135
42
|
attr_accessor :eth_header, :ip_header, :udp_header
|
136
43
|
|
@@ -145,15 +52,10 @@ module PacketFu
|
|
145
52
|
def read(str=nil, args={})
|
146
53
|
raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
|
147
54
|
@eth_header.read(str)
|
148
|
-
@ip_header.read(str[14,str.size])
|
149
|
-
@eth_header.body = @ip_header
|
150
55
|
if args[:strip]
|
151
|
-
|
152
|
-
@udp_header.read(
|
153
|
-
else
|
154
|
-
@udp_header.read(str[14+(@ip_header.ip_hlen),str.size])
|
56
|
+
udp_body_len = self.ip_len - self.ip_hlen - 8
|
57
|
+
@udp_header.body.read(@udp_header.body.to_s[0,udp_body_len])
|
155
58
|
end
|
156
|
-
@ip_header.body = @udp_header
|
157
59
|
super(args)
|
158
60
|
self
|
159
61
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module PacketFu
|
2
|
+
|
3
|
+
# UDPHeader is a complete UDP struct, used in UDPPacket. Many Internet-critical protocols
|
4
|
+
# rely on UDP, such as DNS and World of Warcraft.
|
5
|
+
#
|
6
|
+
# For more on UDP packets, see http://www.networksorcery.com/enp/protocol/udp.htm
|
7
|
+
#
|
8
|
+
# ==== Header Definition
|
9
|
+
# Int16 :udp_src
|
10
|
+
# Int16 :udp_dst
|
11
|
+
# Int16 :udp_len Default: calculated
|
12
|
+
# Int16 :udp_sum Default: 0. Often calculated.
|
13
|
+
# String :body
|
14
|
+
class UDPHeader < Struct.new(:udp_src, :udp_dst, :udp_len, :udp_sum, :body)
|
15
|
+
|
16
|
+
include StructFu
|
17
|
+
|
18
|
+
def initialize(args={})
|
19
|
+
super(
|
20
|
+
Int16.new(args[:udp_src]),
|
21
|
+
Int16.new(args[:udp_dst]),
|
22
|
+
Int16.new(args[:udp_len] || udp_calc_len),
|
23
|
+
Int16.new(args[:udp_sum]),
|
24
|
+
StructFu::String.new.read(args[:body])
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the object in string form.
|
29
|
+
def to_s
|
30
|
+
self.to_a.map {|x| x.to_s}.join
|
31
|
+
end
|
32
|
+
|
33
|
+
# Reads a string to populate the object.
|
34
|
+
def read(str)
|
35
|
+
force_binary(str)
|
36
|
+
return self if str.nil?
|
37
|
+
self[:udp_src].read(str[0,2])
|
38
|
+
self[:udp_dst].read(str[2,2])
|
39
|
+
self[:udp_len].read(str[4,2])
|
40
|
+
self[:udp_sum].read(str[6,2])
|
41
|
+
self[:body].read(str[8,str.size])
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
# Setter for the UDP source port.
|
46
|
+
def udp_src=(i); typecast i; end
|
47
|
+
# Getter for the UDP source port.
|
48
|
+
def udp_src; self[:udp_src].to_i; end
|
49
|
+
# Setter for the UDP destination port.
|
50
|
+
def udp_dst=(i); typecast i; end
|
51
|
+
# Getter for the UDP destination port.
|
52
|
+
def udp_dst; self[:udp_dst].to_i; end
|
53
|
+
# Setter for the length field. Usually should be recalc()'ed instead.
|
54
|
+
def udp_len=(i); typecast i; end
|
55
|
+
# Getter for the length field.
|
56
|
+
def udp_len; self[:udp_len].to_i; end
|
57
|
+
# Setter for the checksum. Usually should be recalc()'ed instad.
|
58
|
+
def udp_sum=(i); typecast i; end
|
59
|
+
# Getter for the checksum.
|
60
|
+
def udp_sum; self[:udp_sum].to_i; end
|
61
|
+
|
62
|
+
# Returns the true length of the UDP packet.
|
63
|
+
def udp_calc_len
|
64
|
+
body.to_s.size + 8
|
65
|
+
end
|
66
|
+
|
67
|
+
# Recalculates calculated fields for UDP.
|
68
|
+
def udp_recalc(args=:all)
|
69
|
+
arg = arg.intern if arg.respond_to? :intern
|
70
|
+
case args
|
71
|
+
when :udp_len
|
72
|
+
self.udp_len = udp_calc_len
|
73
|
+
when :all
|
74
|
+
self.udp_recalc(:udp_len)
|
75
|
+
else
|
76
|
+
raise ArgumentError, "No such field `#{arg}'"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Equivalent to udp_src.to_i
|
81
|
+
def udp_sport
|
82
|
+
self.udp_src
|
83
|
+
end
|
84
|
+
|
85
|
+
# Equivalent to udp_src=
|
86
|
+
def udp_sport=(arg)
|
87
|
+
self.udp_src=(arg)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Equivalent to udp_dst
|
91
|
+
def udp_dport
|
92
|
+
self.udp_dst
|
93
|
+
end
|
94
|
+
|
95
|
+
# Equivalent to udp_dst=
|
96
|
+
def udp_dport=(arg)
|
97
|
+
self.udp_dst=(arg)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Readability aliases
|
101
|
+
|
102
|
+
def udp_sum_readable
|
103
|
+
"0x%04x" % udp_sum
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module PacketFu
|
2
|
+
# This Mixin simplifies access to the UDPHeaders. Mix this in with your
|
3
|
+
# packet interface, and it will add methods that essentially delegate to
|
4
|
+
# the 'udp_header' method (assuming that it is a UDPHeader object)
|
5
|
+
module UDPHeaderMixin
|
6
|
+
def udp_src=(v); self.udp_header.udp_src= v; end
|
7
|
+
def udp_src; self.udp_header.udp_src; end
|
8
|
+
def udp_dst=(v); self.udp_header.udp_dst= v; end
|
9
|
+
def udp_dst; self.udp_header.udp_dst; end
|
10
|
+
def udp_len=(v); self.udp_header.udp_len= v; end
|
11
|
+
def udp_len; self.udp_header.udp_len; end
|
12
|
+
def udp_sum=(v); self.udp_header.udp_sum= v; end
|
13
|
+
def udp_sum; self.udp_header.udp_sum; end
|
14
|
+
def udp_calc_len; self.udp_header.udp_calc_len; end
|
15
|
+
def udp_recalc(*v); self.udp_header.udp_recalc(*v); end
|
16
|
+
def udp_sport; self.udp_header.udp_sport; end
|
17
|
+
def udp_sport=(v); self.udp_header.udp_sport= v; end
|
18
|
+
def udp_dport; self.udp_header.udp_dport; end
|
19
|
+
def udp_dport=(v); self.udp_header.udp_dport= v; end
|
20
|
+
def udp_sum_readable; self.udp_header.udp_sum_readable; end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
data/lib/packetfu/utils.rb
CHANGED
@@ -183,30 +183,30 @@ module PacketFu
|
|
183
183
|
ret[:ip6_obj] = IPAddr.new($1)
|
184
184
|
end
|
185
185
|
end # linux
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
186
|
+
when /darwin/i
|
187
|
+
ifconfig_data = %x[ifconfig #{iface}]
|
188
|
+
if ifconfig_data =~ /#{iface}/i
|
189
|
+
ifconfig_data = ifconfig_data.split(/[\s]*\n[\s]*/)
|
190
|
+
else
|
191
|
+
raise ArgumentError, "Cannot ifconfig #{iface}"
|
192
|
+
end
|
193
|
+
real_iface = ifconfig_data.first
|
194
|
+
ret[:iface] = real_iface.split(':')[0]
|
195
|
+
ifconfig_data.each do |s|
|
196
|
+
case s
|
197
|
+
when /ether[\s]([0-9a-fA-F:]{17})/i
|
198
|
+
ret[:eth_saddr] = $1
|
199
|
+
ret[:eth_src] = EthHeader.mac2str(ret[:eth_saddr])
|
200
|
+
when /inet[\s]*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(.*Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+))?/i
|
201
|
+
ret[:ip_saddr] = $1
|
202
|
+
ret[:ip_src] = [IPAddr.new($1).to_i].pack("N")
|
203
|
+
ret[:ip4_obj] = IPAddr.new($1)
|
204
|
+
ret[:ip4_obj] = ret[:ip4_obj].mask($3) if $3
|
205
|
+
when /inet6[\s]*([0-9a-fA-F:\x2f]+)/
|
206
|
+
ret[:ip6_saddr] = $1
|
207
|
+
ret[:ip6_obj] = IPAddr.new($1)
|
208
|
+
end
|
209
|
+
end # darwin
|
210
210
|
end # RUBY_PLATFORM
|
211
211
|
ret
|
212
212
|
end
|
data/lib/packetfu/version.rb
CHANGED
data/packetfu.gemspec
CHANGED
@@ -2,9 +2,9 @@ require 'rake'
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'packetfu'
|
5
|
-
s.version = '1.1.
|
5
|
+
s.version = '1.1.6'
|
6
6
|
s.authors = ['Tod Beardsley']
|
7
|
-
s.email = 'todb@
|
7
|
+
s.email = 'todb@packetfu.com'
|
8
8
|
s.summary = 'PacketFu is a mid-level packet manipulation library.'
|
9
9
|
s.homepage = 'https://github.com/todb/packetfu'
|
10
10
|
s.description = %q{PacketFu is a mid-level packet manipulation library for Ruby. With it, users can read, parse, and write network packets with the level of ease and fun they expect from Ruby. Note that this gem does not automatically require pcaprub, since users may install pcaprub through non-gem means.}
|
data/test/test_ip.rb
CHANGED
@@ -3,25 +3,6 @@ require 'test/unit'
|
|
3
3
|
$:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
|
4
4
|
require 'packetfu'
|
5
5
|
|
6
|
-
class OctetsTest < Test::Unit::TestCase
|
7
|
-
include PacketFu
|
8
|
-
|
9
|
-
def test_octets_read
|
10
|
-
o = Octets.new
|
11
|
-
o.read("\x04\x03\x02\x01")
|
12
|
-
assert_equal("4.3.2.1", o.to_x)
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_octets_read_quad
|
16
|
-
o = Octets.new
|
17
|
-
o.read_quad("1.2.3.4")
|
18
|
-
assert_equal("1.2.3.4", o.to_x)
|
19
|
-
assert_equal("\x01\x02\x03\x04", o.to_s)
|
20
|
-
assert_equal(0x01020304, o.to_i)
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
6
|
class IPTest < Test::Unit::TestCase
|
26
7
|
include PacketFu
|
27
8
|
|
data/test/test_octets.rb
CHANGED
@@ -3,33 +3,30 @@ require 'test/unit'
|
|
3
3
|
$:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
|
4
4
|
require 'packetfu'
|
5
5
|
|
6
|
-
class
|
6
|
+
class OctetsTest < Test::Unit::TestCase
|
7
7
|
include PacketFu
|
8
8
|
|
9
|
-
def
|
10
|
-
|
9
|
+
def test_octets_read
|
10
|
+
o = Octets.new
|
11
|
+
o.read("\x04\x03\x02\x01")
|
12
|
+
assert_equal("4.3.2.1", o.to_x)
|
11
13
|
end
|
12
14
|
|
13
|
-
def
|
14
|
-
|
15
|
+
def test_octets_read_quad
|
16
|
+
o = Octets.new
|
17
|
+
o.read_quad("1.2.3.4")
|
18
|
+
assert_equal("1.2.3.4", o.to_x)
|
19
|
+
assert_equal("\x01\x02\x03\x04", o.to_s)
|
20
|
+
assert_equal(0x01020304, o.to_i)
|
15
21
|
end
|
16
22
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
assert_equal(
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
s = "\x0a\x0a\x0a\x01"
|
25
|
-
@o.read s
|
26
|
-
assert_equal("10.10.10.1", @o.to_x)
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_numerical
|
30
|
-
s = "\x00\x00\x00\x80"
|
31
|
-
@o.read s
|
32
|
-
assert_equal(128, @o.to_i)
|
23
|
+
def test_octets_single_octet
|
24
|
+
o = Octets.new
|
25
|
+
o.read("ABCD")
|
26
|
+
assert_equal(o.o1, 0x41)
|
27
|
+
assert_equal(o.o2, 0x42)
|
28
|
+
assert_equal(o.o3, 0x43)
|
29
|
+
assert_equal(o.o4, 0x44)
|
33
30
|
end
|
34
31
|
|
35
32
|
end
|