dnsruby 1.57.0 → 1.58.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/.gitignore +1 -2
- data/.travis.yml +1 -1
- data/README.md +2 -2
- data/RELEASE_NOTES.md +16 -0
- data/Rakefile +2 -0
- data/dnsruby.gemspec +2 -0
- data/lib/dnsruby.rb +5 -0
- data/lib/dnsruby/bit_mapping.rb +138 -0
- data/lib/dnsruby/bitmap.rb +108 -0
- data/lib/dnsruby/message/decoder.rb +90 -80
- data/lib/dnsruby/message/message.rb +16 -3
- data/lib/dnsruby/message/section.rb +3 -3
- data/lib/dnsruby/name.rb +2 -2
- data/lib/dnsruby/packet_sender.rb +73 -1
- data/lib/dnsruby/resolv.rb +56 -42
- data/lib/dnsruby/resolver.rb +95 -73
- data/lib/dnsruby/resource/GPOS.rb +9 -3
- data/lib/dnsruby/resource/HIP.rb +1 -1
- data/lib/dnsruby/resource/IN.rb +3 -1
- data/lib/dnsruby/resource/NAPTR.rb +2 -2
- data/lib/dnsruby/resource/NSEC3.rb +2 -2
- data/lib/dnsruby/resource/NXT.rb +302 -0
- data/lib/dnsruby/resource/OPT.rb +2 -2
- data/lib/dnsruby/resource/TXT.rb +2 -2
- data/lib/dnsruby/resource/generic.rb +1 -0
- data/lib/dnsruby/resource/type_bitmap.rb +0 -0
- data/lib/dnsruby/select_thread.rb +174 -83
- data/lib/dnsruby/single_resolver.rb +2 -2
- data/lib/dnsruby/version.rb +1 -1
- data/lib/dnsruby/zone_reader.rb +19 -9
- data/lib/dnsruby/zone_transfer.rb +1 -1
- data/test/spec_helper.rb +9 -1
- data/test/tc_axfr.rb +17 -4
- data/test/tc_gpos.rb +3 -3
- data/test/tc_message.rb +7 -1
- data/test/tc_nxt.rb +192 -0
- data/test/tc_recur.rb +2 -1
- data/test/tc_resolv.rb +73 -0
- data/test/tc_resolver.rb +22 -4
- data/test/tc_rr-opt.rb +9 -8
- data/test/tc_rr.rb +22 -0
- data/test/tc_single_resolver.rb +15 -15
- data/test/tc_soak.rb +154 -65
- data/test/tc_soak_base.rb +15 -15
- data/test/tc_tcp.rb +1 -1
- data/test/tc_tcp_pipelining.rb +203 -0
- data/test/tc_zone_reader.rb +73 -0
- data/test/test_dnsserver.rb +208 -0
- data/test/test_utils.rb +49 -0
- data/test/ts_offline.rb +59 -41
- data/test/ts_online.rb +92 -63
- metadata +40 -3
- data/test/tc_dnsruby.rb +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0542a8574fb4f542e8cdfac4b3efa08335954d76
|
4
|
+
data.tar.gz: 540ef10a9ec536cf6d19cfba946429ac30771c63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 793cd5fa6961776a89b2b1e508fe78573cbf6f52c64dd47b62afe2a4173c4448a9e5291be7a8e95837f862aa48a0b37dd710ba0490872d0db4b780468945df8f
|
7
|
+
data.tar.gz: 604d96ae611adce512eba2a95a93229603d0b85e4f234c3ce4f7d19e78842a8c76aeb70deefd502f2c577d28943e6de1cf6af5e8b5e3e034c4dee5915d8b5ab7
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -16,8 +16,8 @@ queries. It is therefore suitable for high volume DNS applications.
|
|
16
16
|
|
17
17
|
The following is a (non-exhaustive) list of features :
|
18
18
|
|
19
|
-
- Implemented RRs : A, AAAA, AFSDB, ANY, CERT, CNAME, DNAME,
|
20
|
-
HINFO, ISDN, LOC, MB, MG, MINFO, MR, MX, NAPTR, NS, NSAP,
|
19
|
+
- Implemented RRs : A, AAAA, AFSDB, ANY, CERT, CNAME, DNAME, GPOS,
|
20
|
+
HINFO, ISDN, LOC, MB, MG, MINFO, MR, MX, NAPTR, NS, NSAP, NXT,
|
21
21
|
OPT, PTR, PX, RP, RT, SOA, SPF, SRV, TKEY, TSIG, TXT, WKS,
|
22
22
|
X25, DNSKEY, RRSIG, NSEC, NSEC3, NSEC3PARAM, DS, DLV
|
23
23
|
|
data/RELEASE_NOTES.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# Release Notes
|
2
2
|
|
3
|
+
|
4
|
+
## v1.58.0
|
5
|
+
|
6
|
+
* Add TCP pipelining (reusing a single TCP connection for multiple requests).
|
7
|
+
* Enhance zone reading, including reading data from a string.
|
8
|
+
* Add add_answer! method for adding duplicate answers, as needed for an AXFR response.
|
9
|
+
* Add support for GPOS and NXT resource records.
|
10
|
+
* Test cleanup, including removal of use of Nominet servers, soak_test cleanup.
|
11
|
+
* Refactorings: MessageDecoder, Resolv, Resolver (part).
|
12
|
+
* Fix zone reader adding unwanted dot to relative hostnames being converted to absolute.
|
13
|
+
* Fix default access for tsig options in Resolver.
|
14
|
+
* Fix ZoneTransfer not to use deprecated SingleResolver.
|
15
|
+
* Fix Resolver bug in parameter to create_tsig_options.
|
16
|
+
* Fix tests to always use working copy and not gem.
|
17
|
+
|
18
|
+
|
3
19
|
## v1.57.0
|
4
20
|
|
5
21
|
* Add query_raw method as alias for send_plain_message, with option to raise or return error.
|
data/Rakefile
CHANGED
data/dnsruby.gemspec
CHANGED
@@ -33,6 +33,8 @@ DNSSEC NSEC3 support.'
|
|
33
33
|
|
34
34
|
s.add_development_dependency 'rake', '~> 10', '>= 10.3.2'
|
35
35
|
s.add_development_dependency 'minitest', '~> 5.4'
|
36
|
+
s.add_development_dependency 'rubydns', '~> 1.0'
|
37
|
+
s.add_development_dependency 'nio4r', '~> 1.1'
|
36
38
|
|
37
39
|
if RUBY_VERSION >= "1.9.3"
|
38
40
|
s.add_development_dependency 'coveralls', '~> 0.7'
|
data/lib/dnsruby.rb
CHANGED
@@ -27,6 +27,7 @@ require 'dnsruby/update'
|
|
27
27
|
require 'dnsruby/zone_transfer'
|
28
28
|
require 'dnsruby/dnssec'
|
29
29
|
require 'dnsruby/zone_reader'
|
30
|
+
require 'dnsruby/resolv'
|
30
31
|
|
31
32
|
|
32
33
|
# = Dnsruby library
|
@@ -208,6 +209,10 @@ module Dnsruby
|
|
208
209
|
class OtherResolvError < ResolvError
|
209
210
|
end
|
210
211
|
|
212
|
+
# Socket was closed by server before request was processed
|
213
|
+
class SocketEofResolvError < ResolvError
|
214
|
+
end
|
215
|
+
|
211
216
|
# An error occurred processing the TSIG
|
212
217
|
class TsigError < OtherResolvError
|
213
218
|
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# This code is copied from the trick_bag gem (see https://github.com/keithrbennett/trick_bag).
|
2
|
+
# It is copied a) to avoid adding a new dependency and b) because that gem is in
|
3
|
+
# version 0 and is unstable.
|
4
|
+
|
5
|
+
module Dnsruby
|
6
|
+
|
7
|
+
# Provides methods for converting between the various representations
|
8
|
+
# of a bitmap: number, binary encoded string, array, and sparse array.
|
9
|
+
#
|
10
|
+
# Where an array is used to represent bits, the first element (#0) will be the
|
11
|
+
# low (1) bit and the last bit will be the high bit.
|
12
|
+
module BitMapping
|
13
|
+
|
14
|
+
module_function
|
15
|
+
|
16
|
+
# Converts from a binary string to a number, e.g. "\x01\x00" => 256
|
17
|
+
def binary_string_to_number(string)
|
18
|
+
string = string.clone.force_encoding(Encoding::ASCII_8BIT)
|
19
|
+
string.bytes.inject(0) do |number, byte|
|
20
|
+
number * 256 + byte.ord
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# Converts a number to a binary encoded string, e.g. 256 => "\x01\x00"
|
26
|
+
def number_to_binary_string(number, min_length = 0)
|
27
|
+
assert_non_negative(number)
|
28
|
+
binary_string = ''.force_encoding(Encoding::ASCII_8BIT)
|
29
|
+
|
30
|
+
while number > 0
|
31
|
+
byte_value = number & 0xFF
|
32
|
+
binary_string << byte_value
|
33
|
+
number >>= 8
|
34
|
+
end
|
35
|
+
|
36
|
+
binary_string.reverse.rjust(min_length, "\x00")
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Converts a number to an array of place values, e.g. 9 => [8, 0, 0, 1]
|
41
|
+
def number_to_place_value_array(number)
|
42
|
+
assert_non_negative(number)
|
43
|
+
array = []
|
44
|
+
bit_value = 1
|
45
|
+
while number > 0
|
46
|
+
array << ((number & 1 == 1) ? bit_value : 0)
|
47
|
+
number >>= 1
|
48
|
+
bit_value <<= 1
|
49
|
+
end
|
50
|
+
array.reverse
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# Converts from a value array to a number, e.g. [8, 0, 0, 1] => 9
|
55
|
+
def place_value_array_to_number(place_value_array)
|
56
|
+
place_value_array.inject(&:+)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# Converts a number to an array of bit values, e.g. 9 => [1, 0, 0, 1]
|
61
|
+
def number_to_bit_array(number, minimum_binary_places = 0)
|
62
|
+
assert_non_negative(number)
|
63
|
+
array = []
|
64
|
+
while number > 0
|
65
|
+
array << (number & 1)
|
66
|
+
number >>= 1
|
67
|
+
end
|
68
|
+
array.reverse!
|
69
|
+
zero_pad_count = minimum_binary_places - array.size
|
70
|
+
zero_pad_count.times { array.unshift(0) }
|
71
|
+
array
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# Converts an array of bit values, e.g. [1, 0, 0, 1], to a number, e.g. 9
|
76
|
+
def bit_array_to_number(bit_array)
|
77
|
+
return nil if bit_array.empty?
|
78
|
+
multiplier = 1
|
79
|
+
bit_array.reverse.inject(0) do |result, n|
|
80
|
+
result += n * multiplier
|
81
|
+
multiplier *= 2
|
82
|
+
result
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# Converts a number to a sparse array containing bit positions that are set/true/1.
|
88
|
+
# Note that these are bit positions, e.g. 76543210, and not bit column values
|
89
|
+
# such as 128/64/32/16/8/4/2/1.
|
90
|
+
def number_to_set_bit_positions_array(number)
|
91
|
+
assert_non_negative(number)
|
92
|
+
array = []
|
93
|
+
position = 0
|
94
|
+
while number > 0
|
95
|
+
array << position if number & 1 == 1
|
96
|
+
position += 1
|
97
|
+
number >>= 1
|
98
|
+
end
|
99
|
+
array
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# Converts an array of bit position numbers to a numeric value, e.g. [0, 2] => 5
|
104
|
+
def set_bit_position_array_to_number(position_array)
|
105
|
+
return nil if position_array.empty?
|
106
|
+
position_array.inject(0) do |result, n|
|
107
|
+
result += 2 ** n
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
# Converts a binary string to an array of bit values, e.g. "\x0C" => [1, 1, 0, 0]
|
113
|
+
def binary_string_to_bit_array(string, minimum_binary_places = 0)
|
114
|
+
number = binary_string_to_number(string)
|
115
|
+
number_to_bit_array(number, minimum_binary_places)
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
# If number is negative, raises an ArgumentError; else does nothing.
|
120
|
+
def assert_non_negative(number)
|
121
|
+
unless number.is_a?(Integer) && number >= 0
|
122
|
+
raise ArgumentError.new(
|
123
|
+
"Parameter must be a nonnegative Integer (Fixnum, Bignum) " +
|
124
|
+
"but is #{number.inspect} (a #{number.class})")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Reverses a binary string. Note that it is not enough to reverse
|
129
|
+
# the string itself because although the bytes would be reversed,
|
130
|
+
# the bits within each byte would not.
|
131
|
+
def reverse_binary_string_bits(binary_string)
|
132
|
+
binary_place_count = binary_string.size * 8
|
133
|
+
reversed_bit_array = binary_string_to_bit_array(binary_string, binary_place_count).reverse
|
134
|
+
number = bit_array_to_number(reversed_bit_array)
|
135
|
+
number_to_binary_string(number)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# This code is copied from the trick_bag gem (see https://github.com/keithrbennett/trick_bag).
|
2
|
+
# It is copied a) to avoid adding a new dependency and b) because that gem is in
|
3
|
+
# version 0 and is unstable.
|
4
|
+
|
5
|
+
require_relative = ->(*args) do
|
6
|
+
this_file_dir = File.expand_path(File.dirname(__FILE__))
|
7
|
+
args.each { |arg| require(File.join(this_file_dir, arg)) }
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'forwardable'
|
11
|
+
require_relative.('bit_mapping')
|
12
|
+
|
13
|
+
|
14
|
+
module Dnsruby
|
15
|
+
|
16
|
+
# Instances of this class can be created that will hold on to bitmap data and be used
|
17
|
+
# to test bits and convert to other formats.
|
18
|
+
#
|
19
|
+
# Where an array is used to represent bits, the first element (#0) will be the
|
20
|
+
# high bit and the last element will be the low (1's column) bit.
|
21
|
+
class Bitmap
|
22
|
+
|
23
|
+
extend Forwardable
|
24
|
+
|
25
|
+
# This is the internal representation of the bitmap value:
|
26
|
+
attr_reader :number
|
27
|
+
|
28
|
+
# Some instance methods can be delegated to this number:
|
29
|
+
[:&, :|, :^, :hash].each do |method_name|
|
30
|
+
def_delegator :@number, method_name
|
31
|
+
end
|
32
|
+
|
33
|
+
# Set a new value to number, validating first that it is nonnegative.
|
34
|
+
def number=(new_number)
|
35
|
+
self.assert_non_negative(new_number)
|
36
|
+
@number = new_number
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# The constructor is made private because:
|
41
|
+
#
|
42
|
+
# 1) each type of initialization requires its own validation, and it
|
43
|
+
# would be wasteful to do the validation unnecessarily
|
44
|
+
# 2) to enforce that the more descriptively
|
45
|
+
# named class methods should be used to create instances.
|
46
|
+
private_class_method :new
|
47
|
+
|
48
|
+
|
49
|
+
# Class methods to create instances from the various representation types
|
50
|
+
# handled in the BitMapping module's methods.
|
51
|
+
|
52
|
+
# Creates an instance from a nonnegative number.
|
53
|
+
def self.from_number(number)
|
54
|
+
new(number)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Creates an instance from a binary string (e.g. "\x0C").
|
58
|
+
def self.from_binary_string(string)
|
59
|
+
new(BitMapping.binary_string_to_number(string))
|
60
|
+
end
|
61
|
+
|
62
|
+
# Creates an instance from a value array (e.g. [8, 0, 0, 1])
|
63
|
+
def self.from_place_value_array(array)
|
64
|
+
new(BitMapping.place_value_array_to_number(array))
|
65
|
+
end
|
66
|
+
|
67
|
+
# Creates an instance from a bit array (e.g. [1, 0, 0, 1])
|
68
|
+
def self.from_bit_array(array)
|
69
|
+
new(BitMapping.bit_array_to_number(array))
|
70
|
+
end
|
71
|
+
|
72
|
+
# Creates an instance from an array of positions for the bits that are set (e.g. [0, 3])
|
73
|
+
def self.from_set_bit_position_array(array)
|
74
|
+
new(BitMapping.set_bit_position_array_to_number(array))
|
75
|
+
end
|
76
|
+
|
77
|
+
# Instance methods to convert the data to the various representation types:
|
78
|
+
|
79
|
+
# Returns the instance's value as a binary string (e.g. "\x0C")
|
80
|
+
def to_binary_string(min_length = 0)
|
81
|
+
BitMapping.number_to_binary_string(number, min_length)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns the instance's value as an array of bit column values (e.g. [8, 0, 0, 1])
|
85
|
+
def to_place_value_array
|
86
|
+
BitMapping.number_to_place_value_array(number)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns the instance's value as an array of bit column place values (e.g. [8, 0, 0, 1])
|
90
|
+
def to_bit_array
|
91
|
+
BitMapping.number_to_bit_array(number)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns the instance's value as an array of positions for the bits that are set (e.g. [0, 3])
|
95
|
+
def to_set_bit_position_array
|
96
|
+
BitMapping.number_to_set_bit_positions_array(number)
|
97
|
+
end
|
98
|
+
|
99
|
+
def initialize(number)
|
100
|
+
BitMapping.assert_non_negative(number)
|
101
|
+
@number = number
|
102
|
+
end
|
103
|
+
|
104
|
+
def ==(other)
|
105
|
+
other.is_a?(self.class) && other.number == self.number
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -1,6 +1,18 @@
|
|
1
1
|
module Dnsruby
|
2
|
+
|
3
|
+
# This class decodes a binary string containing the raw bytes of the message
|
4
|
+
# as in coming over the wire from a nameserver, and parses it into a
|
5
|
+
# Dnsruby::Message.
|
2
6
|
class MessageDecoder #:nodoc: all
|
3
|
-
|
7
|
+
|
8
|
+
# Keeps a running @index containing the current position (like a cursor)
|
9
|
+
# into the binary string. In general 'get_' methods will position @index
|
10
|
+
# to follow the data they have read.
|
11
|
+
|
12
|
+
attr_reader :data, :index
|
13
|
+
|
14
|
+
# Creates an instance of the decoder, optionally with code block
|
15
|
+
# to be executed with the instance as its parameter.
|
4
16
|
def initialize(data)
|
5
17
|
@data = data
|
6
18
|
@index = 0
|
@@ -8,159 +20,157 @@ class MessageDecoder #:nodoc: all
|
|
8
20
|
yield self if block_given?
|
9
21
|
end
|
10
22
|
|
11
|
-
|
12
|
-
|
23
|
+
# Has bytes remaining in the binary string to be parsed?
|
24
|
+
def has_remaining?
|
25
|
+
@limit > @index
|
26
|
+
end
|
27
|
+
|
28
|
+
# Asserts that the specified position is a valid position in the buffer.
|
29
|
+
# If not, raises a DecodeError. If so, does nothing.
|
30
|
+
def assert_buffer_position_valid(end_position)
|
31
|
+
unless (0..@limit).include?(end_position)
|
32
|
+
raise DecodeError.new("requested position of #{end_position} must be between 0 and buffer size (#{@limit}).")
|
33
|
+
end
|
13
34
|
end
|
14
35
|
|
36
|
+
# Gets the byte value at the specified position
|
37
|
+
def get_byte_at(position)
|
38
|
+
assert_buffer_position_valid(position)
|
39
|
+
return nil if @data[position].nil?
|
40
|
+
@data[position].getbyte(0)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Gets a 16-bit length field from the binary string and yields to the block.
|
44
|
+
# This will be the length of the next item to parse in the binary string.
|
45
|
+
# Returns the object returned from that block.
|
46
|
+
#
|
47
|
+
# When this method returns, @index will point to the byte after the
|
48
|
+
# 16-bit length field.
|
15
49
|
def get_length16
|
16
50
|
len, = self.get_unpack('n')
|
17
51
|
save_limit = @limit
|
18
52
|
@limit = @index + len
|
19
|
-
|
53
|
+
parsed_data = yield(len)
|
20
54
|
if @index < @limit
|
21
55
|
message = "Junk exists; limit = #{@limit}, index = #{@index}"
|
22
56
|
raise DecodeError.new(message)
|
23
|
-
elsif @limit < @index
|
24
|
-
message = "Limit exceeded; limit = #{@limit}, index = #{@index}"
|
25
|
-
raise DecodeError.new(message)
|
26
57
|
end
|
58
|
+
assert_buffer_position_valid(@index)
|
27
59
|
@limit = save_limit
|
28
|
-
|
60
|
+
parsed_data
|
29
61
|
end
|
30
62
|
|
63
|
+
# Returns the specified number of bytes from the binary string.
|
64
|
+
# Length defaults to the remaining (not yet processed) size of the string.
|
31
65
|
def get_bytes(len = @limit - @index)
|
32
|
-
|
66
|
+
bytes = @data[@index, len]
|
33
67
|
@index += len
|
34
|
-
|
68
|
+
bytes
|
35
69
|
end
|
36
70
|
|
71
|
+
# Calls String.unpack to get numbers as specified in the template string.
|
37
72
|
def get_unpack(template)
|
38
73
|
len = 0
|
39
|
-
littlec = ?c
|
40
|
-
bigc = ?C
|
41
|
-
littleh = ?h
|
42
|
-
bigh = ?H
|
43
|
-
littlen = ?n
|
44
|
-
bign = ?N
|
45
|
-
star = ?*
|
46
|
-
|
47
|
-
if (littlec.class != Fixnum)
|
48
|
-
# We're using Ruby 1.9 - convert the codes
|
49
|
-
littlec = littlec.getbyte(0)
|
50
|
-
bigc = bigc.getbyte(0)
|
51
|
-
littleh = littleh.getbyte(0)
|
52
|
-
bigh = bigh.getbyte(0)
|
53
|
-
littlen = littlen.getbyte(0)
|
54
|
-
bign = bign.getbyte(0)
|
55
|
-
star = star.getbyte(0)
|
56
|
-
end
|
57
74
|
|
58
|
-
template.
|
59
|
-
case byte
|
60
|
-
when
|
61
|
-
len += 1
|
62
|
-
when littleh, bigh
|
75
|
+
template.bytes.each do |byte|
|
76
|
+
case byte.chr
|
77
|
+
when 'c', 'C', 'h', 'H'
|
63
78
|
len += 1
|
64
|
-
when
|
79
|
+
when 'n'
|
65
80
|
len += 2
|
66
|
-
when
|
81
|
+
when 'N'
|
67
82
|
len += 4
|
68
|
-
when
|
83
|
+
when '*'
|
69
84
|
len = @limit - @index
|
70
85
|
else
|
71
86
|
raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'")
|
72
87
|
end
|
73
|
-
|
74
|
-
|
75
|
-
|
88
|
+
end
|
89
|
+
|
90
|
+
assert_buffer_position_valid(@index + len)
|
91
|
+
number_array = @data.unpack("@#{@index}#{template}")
|
76
92
|
@index += len
|
77
|
-
|
93
|
+
number_array
|
78
94
|
end
|
79
95
|
|
96
|
+
# Gets a string whose 1-byte length is at @index, and the string starting at @index + 1.
|
80
97
|
def get_string
|
81
|
-
len = @
|
82
|
-
|
83
|
-
|
84
|
-
end
|
85
|
-
raise DecodeError.new("limit exceeded\nlimit = #{@limit}, index = #{@index}, len = #{len}\n") if @limit < @index + 1 + (len ? len : 0)
|
86
|
-
d = @data[@index + 1, len]
|
98
|
+
len = get_byte_at(@index) || 0
|
99
|
+
assert_buffer_position_valid(@index + 1 + len)
|
100
|
+
data_item = @data[@index + 1, len]
|
87
101
|
@index += 1 + len
|
88
|
-
|
102
|
+
data_item
|
89
103
|
end
|
90
104
|
|
105
|
+
# Gets all strings from @index to the end of the binary string.
|
91
106
|
def get_string_list
|
92
107
|
strings = []
|
93
|
-
|
94
|
-
strings << self.get_string
|
95
|
-
end
|
108
|
+
strings << get_string while has_remaining?
|
96
109
|
strings
|
97
110
|
end
|
98
111
|
|
112
|
+
# Gets a Name from the current @index position.
|
99
113
|
def get_name
|
100
|
-
Name.new(
|
114
|
+
Name.new(get_labels)
|
101
115
|
end
|
102
116
|
|
103
|
-
|
104
|
-
|
105
|
-
|
117
|
+
# Returns labels starting at @index.
|
118
|
+
def get_labels(limit = nil)
|
119
|
+
limit = @index if limit.nil? || (@index < limit)
|
120
|
+
labels = []
|
106
121
|
while true
|
107
|
-
temp = @
|
108
|
-
|
109
|
-
temp = temp.getbyte(0)
|
110
|
-
end
|
111
|
-
case temp # @data[@index]
|
122
|
+
temp = get_byte_at(@index)
|
123
|
+
case temp
|
112
124
|
when 0
|
113
125
|
@index += 1
|
114
|
-
return
|
126
|
+
return labels
|
115
127
|
when 192..255
|
116
|
-
idx =
|
128
|
+
idx = get_unpack('n')[0] & 0x3fff
|
117
129
|
if limit <= idx
|
118
130
|
raise DecodeError.new('non-backward name pointer')
|
119
131
|
end
|
120
132
|
save_index = @index
|
121
133
|
@index = idx
|
122
|
-
|
134
|
+
labels += self.get_labels(limit)
|
123
135
|
@index = save_index
|
124
|
-
return
|
136
|
+
return labels
|
125
137
|
else
|
126
|
-
|
138
|
+
labels << self.get_label
|
127
139
|
end
|
128
140
|
end
|
129
|
-
|
141
|
+
labels
|
130
142
|
end
|
131
143
|
|
144
|
+
# Gets a single label.
|
132
145
|
def get_label
|
133
146
|
begin
|
134
|
-
|
135
|
-
label = Name::Label.new(self.get_string)
|
136
|
-
return label
|
137
|
-
# return Name::Label::Str.new(self.get_string)
|
147
|
+
Name::Label.new(get_string)
|
138
148
|
rescue ResolvError => e
|
139
149
|
raise DecodeError.new(e) # Turn it into something more suitable
|
140
150
|
end
|
141
151
|
end
|
142
152
|
|
153
|
+
# Gets a question record.
|
143
154
|
def get_question
|
144
155
|
name = self.get_name
|
145
156
|
type, klass = self.get_unpack('nn')
|
146
|
-
|
147
|
-
q
|
157
|
+
Question.new(name, type, klass)
|
148
158
|
end
|
149
159
|
|
160
|
+
# Gets a resource record.
|
150
161
|
def get_rr
|
151
|
-
name =
|
152
|
-
type, klass, ttl =
|
162
|
+
name = get_name
|
163
|
+
type, klass, ttl = get_unpack('nnN')
|
153
164
|
klass = Classes.new(klass)
|
154
165
|
typeclass = RR.get_class(type, klass)
|
155
166
|
# @TODO@ Trap decode errors here, and somehow mark the record as bad.
|
156
167
|
# Need some way to represent raw data only
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
168
|
+
record = get_length16 { typeclass.decode_rdata(self) }
|
169
|
+
record.name = name
|
170
|
+
record.ttl = ttl
|
171
|
+
record.type = type
|
172
|
+
record.klass = klass
|
173
|
+
record
|
163
174
|
end
|
164
175
|
end
|
165
|
-
|
166
176
|
end
|