packetfu 1.1.9 → 1.1.10
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/bench/octets.rb +9 -9
- data/examples/100kpackets.rb +12 -12
- data/examples/ackscan.rb +16 -16
- data/examples/arp.rb +35 -35
- data/examples/arphood.rb +36 -36
- data/examples/dissect_thinger.rb +6 -6
- data/examples/new-simple-stats.rb +23 -23
- data/examples/packetfu-shell.rb +25 -25
- data/examples/simple-sniffer.rb +9 -9
- data/examples/simple-stats.rb +23 -23
- data/examples/slammer.rb +3 -3
- data/lib/packetfu.rb +127 -127
- data/lib/packetfu/capture.rb +169 -169
- data/lib/packetfu/config.rb +52 -52
- data/lib/packetfu/inject.rb +56 -56
- data/lib/packetfu/packet.rb +528 -528
- data/lib/packetfu/pcap.rb +579 -579
- data/lib/packetfu/protos/arp.rb +90 -90
- data/lib/packetfu/protos/arp/header.rb +158 -158
- data/lib/packetfu/protos/arp/mixin.rb +36 -36
- data/lib/packetfu/protos/eth.rb +44 -44
- data/lib/packetfu/protos/eth/header.rb +243 -243
- data/lib/packetfu/protos/eth/mixin.rb +3 -3
- data/lib/packetfu/protos/hsrp.rb +69 -69
- data/lib/packetfu/protos/hsrp/header.rb +107 -107
- data/lib/packetfu/protos/hsrp/mixin.rb +29 -29
- data/lib/packetfu/protos/icmp.rb +71 -71
- data/lib/packetfu/protos/icmp/header.rb +82 -82
- data/lib/packetfu/protos/icmp/mixin.rb +14 -14
- data/lib/packetfu/protos/invalid.rb +49 -49
- data/lib/packetfu/protos/ip.rb +69 -69
- data/lib/packetfu/protos/ip/header.rb +291 -291
- data/lib/packetfu/protos/ip/mixin.rb +40 -40
- data/lib/packetfu/protos/ipv6.rb +50 -50
- data/lib/packetfu/protos/ipv6/header.rb +188 -188
- data/lib/packetfu/protos/ipv6/mixin.rb +29 -29
- data/lib/packetfu/protos/tcp.rb +176 -176
- data/lib/packetfu/protos/tcp/ecn.rb +35 -35
- data/lib/packetfu/protos/tcp/flags.rb +74 -74
- data/lib/packetfu/protos/tcp/header.rb +268 -268
- data/lib/packetfu/protos/tcp/hlen.rb +32 -32
- data/lib/packetfu/protos/tcp/mixin.rb +46 -46
- data/lib/packetfu/protos/tcp/option.rb +321 -321
- data/lib/packetfu/protos/tcp/options.rb +95 -95
- data/lib/packetfu/protos/tcp/reserved.rb +35 -35
- data/lib/packetfu/protos/udp.rb +116 -116
- data/lib/packetfu/protos/udp/header.rb +91 -91
- data/lib/packetfu/protos/udp/mixin.rb +3 -3
- data/lib/packetfu/structfu.rb +280 -280
- data/lib/packetfu/utils.rb +226 -217
- data/lib/packetfu/version.rb +41 -41
- data/packetfu.gemspec +2 -1
- data/spec/ethpacket_spec.rb +48 -48
- data/spec/packet_spec.rb +57 -57
- data/spec/packet_subclasses_spec.rb +8 -8
- data/spec/packetfu_spec.rb +59 -59
- data/spec/structfu_spec.rb +268 -268
- data/spec/tcp_spec.rb +75 -75
- data/test/all_tests.rb +13 -13
- data/test/func_lldp.rb +3 -3
- data/test/ptest.rb +2 -2
- data/test/test_arp.rb +116 -116
- data/test/test_capture.rb +45 -45
- data/test/test_eth.rb +68 -68
- data/test/test_hsrp.rb +9 -9
- data/test/test_icmp.rb +52 -52
- data/test/test_inject.rb +18 -18
- data/test/test_invalid.rb +16 -16
- data/test/test_ip.rb +36 -36
- data/test/test_ip6.rb +48 -48
- data/test/test_octets.rb +21 -21
- data/test/test_packet.rb +154 -154
- data/test/test_pcap.rb +170 -170
- data/test/test_structfu.rb +97 -97
- data/test/test_tcp.rb +320 -320
- data/test/test_udp.rb +76 -76
- metadata +4 -3
@@ -1,32 +1,32 @@
|
|
1
1
|
# -*- coding: binary -*-
|
2
2
|
module PacketFu
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
3
|
+
# This Mixin simplifies access to the IPv6Headers. Mix this in with your
|
4
|
+
# packet interface, and it will add methods that essentially delegate to
|
5
|
+
# the 'ipv6_header' method (assuming that it is a IPv6Header object)
|
6
|
+
module IPv6HeaderMixin
|
7
|
+
def ipv6_v=(v); self.ipv6_header.ipv6_v= v; end
|
8
|
+
def ipv6_v; self.ipv6_header.ipv6_v; end
|
9
|
+
def ipv6_class=(v); self.ipv6_header.ipv6_class= v; end
|
10
|
+
def ipv6_class; self.ipv6_header.ipv6_class; end
|
11
|
+
def ipv6_label=(v); self.ipv6_header.ipv6_label= v; end
|
12
|
+
def ipv6_label; self.ipv6_header.ipv6_label; end
|
13
|
+
def ipv6_len=(v); self.ipv6_header.ipv6_len= v; end
|
14
|
+
def ipv6_len; self.ipv6_header.ipv6_len; end
|
15
|
+
def ipv6_next=(v); self.ipv6_header.ipv6_next= v; end
|
16
|
+
def ipv6_next; self.ipv6_header.ipv6_next; end
|
17
|
+
def ipv6_hop=(v); self.ipv6_header.ipv6_hop= v; end
|
18
|
+
def ipv6_hop; self.ipv6_header.ipv6_hop; end
|
19
|
+
def ipv6_src=(v); self.ipv6_header.ipv6_src= v; end
|
20
|
+
def ipv6_src; self.ipv6_header.ipv6_src; end
|
21
|
+
def ipv6_dst=(v); self.ipv6_header.ipv6_dst= v; end
|
22
|
+
def ipv6_dst; self.ipv6_header.ipv6_dst; end
|
23
|
+
def ipv6_calc_len; self.ipv6_header.ipv6_calc_len; end
|
24
|
+
def ipv6_recalc(*v); self.ipv6_header.ipv6_recalc(*v); end
|
25
|
+
def ipv6_saddr; self.ipv6_header.ipv6_saddr; end
|
26
|
+
def ipv6_saddr=(v); self.ipv6_header.ipv6_saddr= v; end
|
27
|
+
def ipv6_daddr; self.ipv6_header.ipv6_daddr; end
|
28
|
+
def ipv6_daddr=(v); self.ipv6_header.ipv6_daddr= v; end
|
29
|
+
def ipv6_src_readable; self.ipv6_header.ipv6_src_readable; end
|
30
|
+
def ipv6_dst_readable; self.ipv6_header.ipv6_dst_readable; end
|
31
|
+
end
|
32
32
|
end
|
data/lib/packetfu/protos/tcp.rb
CHANGED
@@ -9,194 +9,194 @@ require 'packetfu/protos/ip/header'
|
|
9
9
|
require 'packetfu/protos/ip/mixin'
|
10
10
|
|
11
11
|
module PacketFu
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
# TCPPacket is used to construct TCP packets. They contain an EthHeader, an IPHeader, and a TCPHeader.
|
13
|
+
#
|
14
|
+
# == Example
|
15
|
+
#
|
16
16
|
# tcp_pkt = PacketFu::TCPPacket.new
|
17
17
|
# tcp_pkt.tcp_flags.syn=1
|
18
18
|
# tcp_pkt.tcp_dst=80
|
19
19
|
# tcp_pkt.tcp_win=5840
|
20
20
|
# tcp_pkt.tcp_options="mss:1460,sack.ok,ts:#{rand(0xffffffff)};0,nop,ws:7"
|
21
|
-
|
21
|
+
#
|
22
22
|
# tcp_pkt.ip_saddr=[rand(0xff),rand(0xff),rand(0xff),rand(0xff)].join('.')
|
23
23
|
# tcp_pkt.ip_daddr=[rand(0xff),rand(0xff),rand(0xff),rand(0xff)].join('.')
|
24
|
-
|
24
|
+
#
|
25
25
|
# tcp_pkt.recalc
|
26
26
|
# tcp_pkt.to_f('/tmp/tcp.pcap')
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
27
|
+
#
|
28
|
+
# == Parameters
|
29
|
+
# :eth
|
30
|
+
# A pre-generated EthHeader object.
|
31
|
+
# :ip
|
32
|
+
# A pre-generated IPHeader object.
|
33
|
+
# :flavor
|
34
|
+
# TODO: Sets the "flavor" of the TCP packet. This will include TCP options and the initial window
|
35
|
+
# size, per stack. There is a lot of variety here, and it's one of the most useful methods to
|
36
|
+
# remotely fingerprint devices. :flavor will span both ip and tcp for consistency.
|
37
|
+
# :type
|
38
|
+
# TODO: Set up particular types of packets (syn, psh_ack, rst, etc). This can change the initial flavor.
|
39
|
+
# :config
|
40
|
+
# A hash of return address details, often the output of Utils.whoami?
|
41
|
+
class TCPPacket < Packet
|
42
42
|
include ::PacketFu::EthHeaderMixin
|
43
43
|
include ::PacketFu::IPHeaderMixin
|
44
44
|
include ::PacketFu::TCPHeaderMixin
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
46
|
+
attr_accessor :eth_header, :ip_header, :tcp_header
|
47
|
+
|
48
|
+
def self.can_parse?(str)
|
49
|
+
return false unless str.size >= 54
|
50
|
+
return false unless EthPacket.can_parse? str
|
51
|
+
return false unless IPPacket.can_parse? str
|
52
|
+
return false unless str[23,1] == "\x06"
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
|
56
|
+
def read(str=nil, args={})
|
57
|
+
raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
|
58
|
+
@eth_header.read(str)
|
59
|
+
|
60
|
+
# Strip off any extra data, if we are asked to do so.
|
61
|
+
if args[:strip]
|
62
|
+
tcp_body_len = self.ip_len - self.ip_hlen - (self.tcp_hlen * 4)
|
63
|
+
@tcp_header.body.read(@tcp_header.body.to_s[0,tcp_body_len])
|
64
|
+
end
|
65
|
+
super(args)
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def initialize(args={})
|
70
|
+
@eth_header = (args[:eth] || EthHeader.new)
|
71
|
+
@ip_header = (args[:ip] || IPHeader.new)
|
72
|
+
@tcp_header = (args[:tcp] || TCPHeader.new)
|
73
|
+
@tcp_header.flavor = args[:flavor].to_s.downcase
|
74
|
+
|
75
|
+
@ip_header.body = @tcp_header
|
76
|
+
@eth_header.body = @ip_header
|
77
|
+
@headers = [@eth_header, @ip_header, @tcp_header]
|
78
|
+
|
79
|
+
@ip_header.ip_proto=0x06
|
80
|
+
super
|
81
|
+
if args[:flavor]
|
82
|
+
tcp_calc_flavor(@tcp_header.flavor)
|
83
|
+
else
|
84
|
+
tcp_calc_sum
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Sets the correct flavor for TCP Packets. Recognized flavors are:
|
89
|
+
# windows, linux, freebsd
|
90
|
+
def tcp_calc_flavor(str)
|
91
|
+
ts_val = Time.now.to_i + rand(0x4fffffff)
|
92
|
+
ts_sec = rand(0xffffff)
|
93
|
+
case @tcp_header.flavor = str.to_s.downcase
|
94
|
+
when "windows" # WinXP's default syn
|
95
|
+
@tcp_header.tcp_win = 0x4000
|
96
|
+
@tcp_header.tcp_options="MSS:1460,NOP,NOP,SACKOK"
|
97
|
+
@tcp_header.tcp_src = rand(5000 - 1026) + 1026
|
98
|
+
@ip_header.ip_ttl = 64
|
99
|
+
when "linux" # Ubuntu Linux 2.6.24-19-generic default syn
|
100
|
+
@tcp_header.tcp_win = 5840
|
101
|
+
@tcp_header.tcp_options="MSS:1460,SACKOK,TS:#{ts_val};0,NOP,WS:7"
|
102
|
+
@tcp_header.tcp_src = rand(61_000 - 32_000) + 32_000
|
103
|
+
@ip_header.ip_ttl = 64
|
104
|
+
when "freebsd" # Freebsd
|
105
|
+
@tcp_header.tcp_win = 0xffff
|
106
|
+
@tcp_header.tcp_options="MSS:1460,NOP,WS:3,NOP,NOP,TS:#{ts_val};#{ts_sec},SACKOK,EOL,EOL"
|
107
|
+
@ip_header.ip_ttl = 64
|
108
|
+
else
|
109
|
+
@tcp_header.tcp_options="MSS:1460,NOP,NOP,SACKOK"
|
110
|
+
end
|
111
|
+
tcp_calc_sum
|
112
|
+
end
|
113
|
+
|
114
|
+
# tcp_calc_sum() computes the TCP checksum, and is called upon intialization. It usually
|
115
|
+
# should be called just prior to dropping packets to a file or on the wire.
|
116
|
+
#--
|
117
|
+
# This is /not/ delegated down to @tcp_header since we need info
|
118
|
+
# from the IP header, too.
|
119
|
+
#++
|
120
|
+
def tcp_calc_sum
|
121
|
+
checksum = (ip_src.to_i >> 16)
|
122
|
+
checksum += (ip_src.to_i & 0xffff)
|
123
|
+
checksum += (ip_dst.to_i >> 16)
|
124
|
+
checksum += (ip_dst.to_i & 0xffff)
|
125
|
+
checksum += 0x06 # TCP Protocol.
|
126
|
+
checksum += (ip_len.to_i - ((ip_hl.to_i) * 4))
|
127
|
+
checksum += tcp_src
|
128
|
+
checksum += tcp_dst
|
129
|
+
checksum += (tcp_seq.to_i >> 16)
|
130
|
+
checksum += (tcp_seq.to_i & 0xffff)
|
131
|
+
checksum += (tcp_ack.to_i >> 16)
|
132
|
+
checksum += (tcp_ack.to_i & 0xffff)
|
133
|
+
checksum += ((tcp_hlen << 12) +
|
134
|
+
(tcp_reserved << 9) +
|
135
|
+
(tcp_ecn.to_i << 6) +
|
136
|
+
tcp_flags.to_i
|
137
|
+
)
|
138
|
+
checksum += tcp_win
|
139
|
+
checksum += tcp_urg
|
140
|
+
|
141
|
+
chk_tcp_opts = (tcp_opts.to_s.size % 2 == 0 ? tcp_opts.to_s : tcp_opts.to_s + "\x00")
|
142
|
+
chk_tcp_opts.unpack("n*").each {|x| checksum = checksum + x }
|
143
|
+
if (ip_len - ((ip_hl + tcp_hlen) * 4)) >= 0
|
144
|
+
real_tcp_payload = payload[0,( ip_len - ((ip_hl + tcp_hlen) * 4) )] # Can't forget those pesky FCSes!
|
145
|
+
else
|
146
|
+
real_tcp_payload = payload # Something's amiss here so don't bother figuring out where the real payload is.
|
147
|
+
end
|
148
|
+
chk_payload = (real_tcp_payload.size % 2 == 0 ? real_tcp_payload : real_tcp_payload + "\x00") # Null pad if it's odd.
|
149
|
+
chk_payload.unpack("n*").each {|x| checksum = checksum+x }
|
150
|
+
checksum = checksum % 0xffff
|
151
|
+
checksum = 0xffff - checksum
|
152
|
+
checksum == 0 ? 0xffff : checksum
|
153
|
+
@tcp_header.tcp_sum = checksum
|
154
|
+
end
|
155
|
+
|
156
|
+
# Recalculates various fields of the TCP packet.
|
157
|
+
#
|
158
|
+
# ==== Parameters
|
159
|
+
#
|
160
|
+
# :all
|
161
|
+
# Recomputes all calculated fields.
|
162
|
+
# :tcp_sum
|
163
|
+
# Recomputes the TCP checksum.
|
164
|
+
# :tcp_hlen
|
165
|
+
# Recomputes the TCP header length. Useful after options are added.
|
166
|
+
def tcp_recalc(arg=:all)
|
167
|
+
case arg
|
168
|
+
when :tcp_sum
|
169
|
+
tcp_calc_sum
|
170
|
+
when :tcp_hlen
|
171
|
+
@tcp_header.tcp_recalc :tcp_hlen
|
172
|
+
when :all
|
173
|
+
@tcp_header.tcp_recalc :all
|
174
|
+
tcp_calc_sum
|
175
|
+
else
|
176
|
+
raise ArgumentError, "No such field `#{arg}'"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# TCP packets are denoted by a "T ", followed by size,
|
181
|
+
# source and dest information, packet flags, sequence
|
182
|
+
# number, and IPID.
|
183
|
+
def peek_format
|
184
|
+
peek_data = ["T "]
|
185
|
+
peek_data << "%-5d" % self.to_s.size
|
186
|
+
peek_data << "%-21s" % "#{self.ip_saddr}:#{self.tcp_src}"
|
187
|
+
peek_data << "->"
|
188
|
+
peek_data << "%21s" % "#{self.ip_daddr}:#{self.tcp_dst}"
|
189
|
+
flags = ' ['
|
190
|
+
flags << self.tcp_flags_dotmap
|
191
|
+
flags << '] '
|
192
|
+
peek_data << flags
|
193
|
+
peek_data << "S:"
|
194
|
+
peek_data << "%08x" % self.tcp_seq
|
195
|
+
peek_data << "|I:"
|
196
|
+
peek_data << "%04x" % self.ip_id
|
197
|
+
peek_data.join
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
201
|
|
202
202
|
end
|
@@ -1,43 +1,43 @@
|
|
1
1
|
# -*- coding: binary -*-
|
2
2
|
module PacketFu
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
3
|
+
# Implements the Explict Congestion Notification for TCPHeader.
|
4
|
+
#
|
5
|
+
# ==== Header Definition
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# Fixnum (1 bit) :n
|
9
|
+
# Fixnum (1 bit) :c
|
10
|
+
# Fixnum (1 bit) :e
|
11
|
+
class TcpEcn < Struct.new(:n, :c, :e)
|
12
12
|
|
13
|
-
|
13
|
+
include StructFu
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
def initialize(args={})
|
16
|
+
super(args[:n], args[:c], args[:e]) if args
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
# Returns the TcpEcn field as an integer... even though it's going
|
20
|
+
# to be split across a byte boundary.
|
21
|
+
def to_i
|
22
|
+
(n.to_i << 2) + (c.to_i << 1) + e.to_i
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
25
|
+
# Reads a string to populate the object.
|
26
|
+
def read(str)
|
27
|
+
force_binary(str)
|
28
|
+
return self if str.nil? || str.size < 2
|
29
|
+
if 1.respond_to? :ord
|
30
|
+
byte1 = str[0].ord
|
31
|
+
byte2 = str[1].ord
|
32
|
+
else
|
33
|
+
byte1 = str[0]
|
34
|
+
byte2 = str[1]
|
35
|
+
end
|
36
|
+
self[:n] = byte1 & 0b00000001 == 0b00000001 ? 1 : 0
|
37
|
+
self[:c] = byte2 & 0b10000000 == 0b10000000 ? 1 : 0
|
38
|
+
self[:e] = byte2 & 0b01000000 == 0b01000000 ? 1 : 0
|
39
|
+
self
|
40
|
+
end
|
41
41
|
|
42
|
-
|
42
|
+
end
|
43
43
|
end
|