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