dnsruby 1.56.0 → 1.57.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/.coveralls.yml +2 -0
- data/.gitignore +24 -0
- data/.travis.yml +15 -0
- data/Gemfile +3 -0
- data/README.md +9 -12
- data/RELEASE_NOTES.md +100 -0
- data/SIGNED_UPDATES +22 -0
- data/dnsruby.gemspec +41 -0
- data/lib/dnsruby/code_mapper.rb +1 -1
- data/lib/dnsruby/message/decoder.rb +4 -2
- data/lib/dnsruby/resolver.rb +24 -0
- data/lib/dnsruby/resource/GPOS.rb +187 -0
- data/lib/dnsruby/resource/RR.rb +1 -2
- data/lib/dnsruby/resource/generic.rb +1 -0
- data/lib/dnsruby/version.rb +1 -1
- data/lib/dnsruby/zone_reader.rb +1 -2
- data/test/spec_helper.rb +1 -0
- data/test/tc_gpos.rb +124 -0
- data/test/tc_hs.rb +25 -0
- data/test/tc_nsec3.rb +0 -5
- data/test/tc_resolver.rb +74 -1
- data/test/tc_rr-opt.rb +32 -0
- data/test/tc_rr.rb +9 -0
- data/test/ts_offline.rb +1 -0
- data/test/ts_online.rb +1 -0
- metadata +44 -4
- data/test/tc_keith.rb +0 -300
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6d192a2471584058955bbdd453c5384567f8133
|
4
|
+
data.tar.gz: bc95f3527bfbab7ccc9f2861c3725dc86e5d9e6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 408fd7d3242777cea4965ad97f8bf9f1c21677d604b0e6a68a5221f2fb6d9f2389a116936fb754f42f8bed8d4901f3ed87fab0fa67627af2d5fed8ac0426a190
|
7
|
+
data.tar.gz: 18b2bcfa91dc712faef28725394dcf3f89d154e4e0669b666d5bb3e553f29ed38f2d3bf2cca9b2dc5cd6d86c46059535dd0e2343af7ae0999cb3e9c263257e09
|
data/.coveralls.yml
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
.idea/
|
12
|
+
lib/bundler/man
|
13
|
+
pkg
|
14
|
+
rdoc
|
15
|
+
spec/reports
|
16
|
+
test/tmp
|
17
|
+
test/version_tmp
|
18
|
+
tmp
|
19
|
+
*.bundle
|
20
|
+
*.so
|
21
|
+
*.o
|
22
|
+
*.a
|
23
|
+
mkmf.log
|
24
|
+
/nbproject/private/
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
CHANGED
@@ -5,8 +5,7 @@ Dnsruby
|
|
5
5
|
=======
|
6
6
|
|
7
7
|
Dnsruby is a pure Ruby DNS client library which implements a
|
8
|
-
stub resolver. It aims to comply with all DNS RFCs
|
9
|
-
DNSSEC NSEC3 support.
|
8
|
+
stub resolver. It aims to comply with all DNS RFCs.
|
10
9
|
|
11
10
|
Dnsruby presents an enhanced API for DNS. It is based on Ruby's core
|
12
11
|
resolv.rb Resolv API, but has been much extended to provide a
|
@@ -36,7 +35,7 @@ Dependencies
|
|
36
35
|
Dnsruby can run with no dependencies. However, if you wish to
|
37
36
|
use TSIG or DNSSEC then the OpenSSL library must be available.
|
38
37
|
This is a part of the Ruby standard library, but appears not to
|
39
|
-
be present on all Ruby platforms. If it is not available, then
|
38
|
+
be present on all Ruby platforms. If it is not available, then
|
40
39
|
the test code will not run the tests which require it. Code which
|
41
40
|
attempts to use the library (if it is not present) will raise an
|
42
41
|
exception.
|
@@ -73,11 +72,6 @@ at runtime:
|
|
73
72
|
bundle exec rake test
|
74
73
|
```
|
75
74
|
|
76
|
-
Nominet operates a test server which the Dnsruby test code queries.
|
77
|
-
If this server is not available then some of the online tests will
|
78
|
-
not be run.
|
79
|
-
|
80
|
-
|
81
75
|
Usage Help
|
82
76
|
----------
|
83
77
|
|
@@ -88,9 +82,12 @@ in understanding how to use Dnsruby:
|
|
88
82
|
* http://blog.nominet.org.uk/tech/2009/05/21/examples-of-using-dnsruby-with-dnssec/
|
89
83
|
|
90
84
|
|
91
|
-
Contact
|
85
|
+
Contact/Links
|
92
86
|
-------
|
93
87
|
|
94
|
-
|
95
|
-
|
96
|
-
|
88
|
+
| Link Type | Link/Text |
|
89
|
+
|-----|-----
|
90
|
+
| Author Email | alex@caerkettontech.com |
|
91
|
+
| Github | https://github.com/alexdalitz/dnsruby |
|
92
|
+
| Google Group | https://groups.google.com/forum/#!forum/dnsruby |
|
93
|
+
| Rubygems | http://rubygems.org/gems/dnsruby/ |
|
data/RELEASE_NOTES.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# Release Notes
|
2
|
+
|
3
|
+
## v1.57.0
|
4
|
+
|
5
|
+
* Add query_raw method as alias for send_plain_message, with option to raise or return error.
|
6
|
+
* Fixed a bug in RR hash calculation where TTL should have been ignored but wasn't.
|
7
|
+
* Add support for (obsolete) GPOS resource record type.
|
8
|
+
* Tweak Travis CI configuration.
|
9
|
+
* Fix zone reader for case where a line contains whitespace preceding a comment.
|
10
|
+
* Add post install message.
|
11
|
+
* Improve README.
|
12
|
+
* Moved content of NEWS to RELEASE_NOTES.md.
|
13
|
+
* Use git ls-files now to determine files for inclusion in gem.
|
14
|
+
|
15
|
+
|
16
|
+
## v1.56.0
|
17
|
+
|
18
|
+
* Drop support for Ruby 1.8, using lambda -> and hash 'key: value' notations.
|
19
|
+
* First release since the move from Rubyforge to Github (https://github.com/alexdalitz/dnsruby).
|
20
|
+
* Add EDNS client subnet support.
|
21
|
+
* Relocate CodeMapper subclasses, Resolv, RR, and RRSet classes.
|
22
|
+
* Add Travis CI and coveralls integration.
|
23
|
+
* Improve Google IPV6 support.
|
24
|
+
* Convert some file names to snake case.
|
25
|
+
* Remove trailing whitespace from lines, and ensure that comments have space between '#' and text.
|
26
|
+
* Restore test success when running under JRuby.
|
27
|
+
* Disabled attempt to connect to Nominet servers, which are no longer available.
|
28
|
+
* Convert from test/unit to minitest/autorun to support Ruby 2.1+.
|
29
|
+
* Remove setup.rb.
|
30
|
+
* Other minor refactoring and improvements to production code, test code, and documentation.
|
31
|
+
|
32
|
+
|
33
|
+
## v1.53
|
34
|
+
|
35
|
+
* Validation routine fixes
|
36
|
+
* Ruby 1.9 fixes
|
37
|
+
* Recursor fixes
|
38
|
+
* IPv4 Regex fixes
|
39
|
+
* Fixes for A/PTR lookups with IP-like domain name
|
40
|
+
* TXT and SSHFP processing fixes
|
41
|
+
* Default retry parameters in Resolver more sensible
|
42
|
+
|
43
|
+
|
44
|
+
## v1.48
|
45
|
+
|
46
|
+
* Fixed deadlock/performance issue seen on some platforms
|
47
|
+
* DNSSEC validation now disabled by default
|
48
|
+
* Signed root DS record can be added to validator
|
49
|
+
* ITAR support removed
|
50
|
+
* multi-line DS/RRSIG reading bug fixed (thanks Marco Davids!)
|
51
|
+
* DS algorithms of more than one digit can now be read from string
|
52
|
+
* LOC records now parsed correctly
|
53
|
+
* HINFO records now parsed correctly
|
54
|
+
|
55
|
+
|
56
|
+
## v1.42
|
57
|
+
|
58
|
+
* Complicated TXT and NAPTR records now handled correctly
|
59
|
+
* ZoneReader now handles odd escape characters correctly
|
60
|
+
* Warns when immediate timeout occurs because no nameservers are configured
|
61
|
+
* Easy hmac-sha1/256 options to Resolver#tsig=
|
62
|
+
* ZoneReader fixed for "IN CNAME @" notations
|
63
|
+
* ZoneReader supports wildcards
|
64
|
+
* Dnsruby.version method added - currently returns 1.42
|
65
|
+
|
66
|
+
|
67
|
+
## v1.41
|
68
|
+
|
69
|
+
* RFC3597 unknown classes (e.g. CLASS32) now handled correctly
|
70
|
+
in RRSIGs
|
71
|
+
* Resolver#do_caching flag added for Resolver-level caching
|
72
|
+
* DNSKEY#key_tag now cached - only recalculated when key data
|
73
|
+
changes
|
74
|
+
* Bugfix where Resolver would not time queries out if no
|
75
|
+
nameservers were configured
|
76
|
+
* Recursor now performs A and AAAA queries in parallel
|
77
|
+
* Fix for zero length salt
|
78
|
+
* Fixing priming for signed root
|
79
|
+
* Fixes for DLV verification
|
80
|
+
* Other minor fixes
|
81
|
+
|
82
|
+
|
83
|
+
## v1.40
|
84
|
+
|
85
|
+
* Zone file reading support added (Dnsruby::ZoneReader)
|
86
|
+
* Name and Label speed-ups
|
87
|
+
* CodeMapper speed-ups
|
88
|
+
* DHCID RR added
|
89
|
+
* LOC presentation format parsing fixed
|
90
|
+
* KX RR added
|
91
|
+
* Quotations now allowed in text representation for ISDN, X25 and HINFO
|
92
|
+
* AFSDB from_string fixes
|
93
|
+
* Fixing CERT types and from_string
|
94
|
+
* CERT now allows algorithm 0
|
95
|
+
* Fix for DS record comparison
|
96
|
+
* HIP RR added
|
97
|
+
* Minor bug fixes
|
98
|
+
* IPSECKEY RR added
|
99
|
+
* Clients can now manipulate Name::Labels
|
100
|
+
|
data/SIGNED_UPDATES
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Signed updates with Dnsruby
|
2
|
+
===========================
|
3
|
+
|
4
|
+
In order to use TSIG records to automatically perform TSIG signing/verification of messages :
|
5
|
+
|
6
|
+
res = Dnsruby::Resolver.new("ns0.validation-test-servers.nominet.org.uk")
|
7
|
+
|
8
|
+
# Now configure the resolver with the TSIG key for signing/verifying
|
9
|
+
KEY_NAME="rubytsig"
|
10
|
+
KEY = "8n6gugn4aJ7MazyNlMccGKH1WxD2B3UvN/O/RA6iBupO2/03u9CTa3Ewz3gBWTSBCH3crY4Kk+tigNdeJBAvrw=="
|
11
|
+
res.tsig=KEY_NAME, KEY
|
12
|
+
|
13
|
+
|
14
|
+
# Now try sending/receiving some update messages
|
15
|
+
update = Dnsruby::Update.new("validation-test-servers.nominet.org.uk")
|
16
|
+
update_name = generate_update_name
|
17
|
+
update.absent(update_name)
|
18
|
+
update.add(update_name, 'TXT', 100, "test signed update")
|
19
|
+
|
20
|
+
# Resolver will automatically sign message and verify response
|
21
|
+
response = res.send_message(update)
|
22
|
+
assert(response.verified?) # Check that the response has been verified
|
data/dnsruby.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'dnsruby/version'
|
4
|
+
|
5
|
+
SPEC = Gem::Specification.new do |s|
|
6
|
+
s.name = "dnsruby"
|
7
|
+
s.version = Dnsruby::VERSION
|
8
|
+
s.authors = ["Alex Dalitz"]
|
9
|
+
s.email = 'alex@caerkettontech.com'
|
10
|
+
s.homepage = "https://github.com/alexdalitz/dnsruby"
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
s.summary = "Ruby DNS(SEC) implementation"
|
13
|
+
s.description = \
|
14
|
+
'Dnsruby is a pure Ruby DNS client library which implements a
|
15
|
+
stub resolver. It aims to comply with all DNS RFCs, including
|
16
|
+
DNSSEC NSEC3 support.'
|
17
|
+
s.license = "Apache License, Version 2.0"
|
18
|
+
s.files = `git ls-files -z`.split("\x0")
|
19
|
+
|
20
|
+
s.post_install_message = \
|
21
|
+
"Installing dnsruby...
|
22
|
+
For issues and source code: https://github.com/alexdalitz/dnsruby
|
23
|
+
For general discussion (please tell us how you use dnsruby): https://groups.google.com/forum/#!forum/dnsruby"
|
24
|
+
|
25
|
+
s.test_file = "test/ts_offline.rb"
|
26
|
+
s.has_rdoc = true
|
27
|
+
s.extra_rdoc_files = ["DNSSEC", "EXAMPLES", "README.md", "EVENTMACHINE"]
|
28
|
+
|
29
|
+
unless /java/ === RUBY_PLATFORM
|
30
|
+
s.add_development_dependency 'pry', '~> 0.10'
|
31
|
+
s.add_development_dependency 'pry-byebug', '~> 2.0' if RUBY_VERSION >= '2'
|
32
|
+
end
|
33
|
+
|
34
|
+
s.add_development_dependency 'rake', '~> 10', '>= 10.3.2'
|
35
|
+
s.add_development_dependency 'minitest', '~> 5.4'
|
36
|
+
|
37
|
+
if RUBY_VERSION >= "1.9.3"
|
38
|
+
s.add_development_dependency 'coveralls', '~> 0.7'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
data/lib/dnsruby/code_mapper.rb
CHANGED
@@ -114,7 +114,7 @@ module Dnsruby
|
|
114
114
|
@code = arg.code
|
115
115
|
@string = array.values[@code]
|
116
116
|
else
|
117
|
-
raise ArgumentError.new("Unknown argument #{arg} for #{self.class}")
|
117
|
+
raise ArgumentError.new("Unknown argument of type #{arg.class}: #{arg} for #{self.class}")
|
118
118
|
end
|
119
119
|
end
|
120
120
|
|
@@ -18,9 +18,11 @@ class MessageDecoder #:nodoc: all
|
|
18
18
|
@limit = @index + len
|
19
19
|
d = yield(len)
|
20
20
|
if @index < @limit
|
21
|
-
|
21
|
+
message = "Junk exists; limit = #{@limit}, index = #{@index}"
|
22
|
+
raise DecodeError.new(message)
|
22
23
|
elsif @limit < @index
|
23
|
-
|
24
|
+
message = "Limit exceeded; limit = #{@limit}, index = #{@index}"
|
25
|
+
raise DecodeError.new(message)
|
24
26
|
end
|
25
27
|
@limit = save_limit
|
26
28
|
d
|
data/lib/dnsruby/resolver.rb
CHANGED
@@ -264,6 +264,30 @@ module Dnsruby
|
|
264
264
|
[response, error]
|
265
265
|
end
|
266
266
|
|
267
|
+
# Sends a message with send_plain_message.
|
268
|
+
# Effectively a wrapper around send_plain_message, but adds
|
269
|
+
# the ability to configure whether an error will be raised
|
270
|
+
# or returned if it occurs.
|
271
|
+
#
|
272
|
+
# @param message the message to send to the DNS server
|
273
|
+
# @param error_strategy :return to return [response, error] (default),
|
274
|
+
# :raise to return response only, or raise an error if one occurs
|
275
|
+
def query_raw(message, error_strategy = :return)
|
276
|
+
|
277
|
+
unless [:return, :raise].include?(error_strategy)
|
278
|
+
raise ArgumentError.new('error_strategy should be one of [:return, :raise].')
|
279
|
+
end
|
280
|
+
|
281
|
+
response, error = send_plain_message(message)
|
282
|
+
|
283
|
+
if error_strategy == :return
|
284
|
+
[response, error]
|
285
|
+
else
|
286
|
+
raise error if error
|
287
|
+
response
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
267
291
|
# This method takes a Message (supplied by the client), and sends it to
|
268
292
|
# the configured nameservers. No changes are made to the Message before it
|
269
293
|
# is sent (TSIG signatures will be applied if configured on the Resolver).
|
@@ -0,0 +1,187 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
module Dnsruby
|
4
|
+
class RR
|
5
|
+
# Class for Geographic Position (GPOS) resource records.
|
6
|
+
#
|
7
|
+
# RFC 1712 (https://www.ietf.org/rfc/rfc1712.txt)
|
8
|
+
class GPOS < RR
|
9
|
+
|
10
|
+
TypeValue = Types::GPOS
|
11
|
+
ClassValue = Classes::IN
|
12
|
+
ClassHash[[TypeValue, ClassValue]] = self #:nodoc: all
|
13
|
+
|
14
|
+
attr_accessor :longitude, :latitude, :altitude # NOTE: these are strings, not numbers
|
15
|
+
|
16
|
+
REQUIRED_KEYS = [:longitude, :latitude, :altitude]
|
17
|
+
|
18
|
+
|
19
|
+
# As with all resource record subclasses of RR, this class cannot be
|
20
|
+
# directly instantiated, but instead must be instantiated via use of
|
21
|
+
# one of the RR class methods. These GPOS class methods are wrappers
|
22
|
+
# around those RR methods, so that there is an interface on the GPOS
|
23
|
+
# class for creating GPOS instances.
|
24
|
+
|
25
|
+
# Create an instance from a hash of parameters, e.g.:
|
26
|
+
# {
|
27
|
+
# name: 'techhumans.com',
|
28
|
+
# type: Types::GPOS,
|
29
|
+
# ttl: 1234,
|
30
|
+
# longitude: '10.0',
|
31
|
+
# latitude: '20.0',
|
32
|
+
# altitude: '30.0',
|
33
|
+
# }
|
34
|
+
def self.from_hash(gpos_params_hash)
|
35
|
+
RR.new_from_hash(gpos_params_hash)
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# Create an instance from a string containing parameters, e.g.:
|
40
|
+
# 'a.dnsruby.com. 10800 IN GPOS 10.0 20.0 30.0'
|
41
|
+
def self.from_string(gpos_params_string)
|
42
|
+
RR.new_from_string(gpos_params_string)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# Create an instance from an ordered parameter list, e.g.:
|
47
|
+
# EXAMPLE_GPOS_DATA = begin
|
48
|
+
# rdata = RR::GPOS.build_rdata(EXAMPLE_LONGITUDE, EXAMPLE_LATITUDE, EXAMPLE_ALTITUDE)
|
49
|
+
# [EXAMPLE_HOSTNAME, Types::GPOS, Classes::IN, EXAMPLE_TTL, rdata.length, rdata, 0]
|
50
|
+
# end
|
51
|
+
# self.from_data(*EXAMPLE_GPOS_DATA)
|
52
|
+
def self.from_data(*gpos_params_data)
|
53
|
+
RR.new_from_data(*gpos_params_data)
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def from_data(array)
|
58
|
+
unless array.size == 3
|
59
|
+
raise "Array size for creating GPOS record must be 3 (long, lat, alt). Array was:\n#{array.inspect}"
|
60
|
+
end
|
61
|
+
|
62
|
+
from_hash({
|
63
|
+
longitude: array[0],
|
64
|
+
latitude: array[1],
|
65
|
+
altitude: array[2]
|
66
|
+
})
|
67
|
+
end
|
68
|
+
|
69
|
+
def from_hash(init_data)
|
70
|
+
self.class.validate_floats(init_data)
|
71
|
+
@longitude = init_data[:longitude].to_s
|
72
|
+
@latitude = init_data[:latitude].to_s
|
73
|
+
@altitude = init_data[:altitude].to_s
|
74
|
+
self.rdata = build_rdata
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
def from_string(string)
|
79
|
+
# Convert commas to spaces, then split by spaces:
|
80
|
+
from_data(string.gsub(',', ' ').split(' '))
|
81
|
+
end
|
82
|
+
|
83
|
+
# From the RFC:
|
84
|
+
# GPOS has the following format:
|
85
|
+
# <owner> <ttl> <class> GPOS <longitude> <latitude> <altitude>
|
86
|
+
#
|
87
|
+
# We handle the rdata, the RR superclass does the rest.
|
88
|
+
def rdata_to_string
|
89
|
+
[longitude, latitude, altitude].join(' ')
|
90
|
+
end
|
91
|
+
|
92
|
+
def encode_rdata(msg, _canonical)
|
93
|
+
msg.put_bytes(build_rdata)
|
94
|
+
end
|
95
|
+
|
96
|
+
def build_rdata
|
97
|
+
self.class.build_rdata(longitude, latitude, altitude)
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.build_rdata(longitude, latitude, altitude)
|
101
|
+
binary_string = ''.force_encoding('ASCII-8BIT')
|
102
|
+
|
103
|
+
binary_string << longitude.length.chr
|
104
|
+
binary_string << longitude
|
105
|
+
binary_string << latitude.length.chr
|
106
|
+
binary_string << latitude
|
107
|
+
binary_string << altitude.length.chr
|
108
|
+
binary_string << altitude
|
109
|
+
binary_string
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.decode_rdata(message)
|
113
|
+
rdata_s = message.get_bytes.clone
|
114
|
+
|
115
|
+
index = 0
|
116
|
+
|
117
|
+
long_len = rdata_s[index].ord; index += 1
|
118
|
+
longitude = rdata_s[index, long_len]; index += long_len
|
119
|
+
|
120
|
+
lat_len = rdata_s[index].ord; index += 1
|
121
|
+
latitude = rdata_s[index, lat_len]; index += lat_len
|
122
|
+
|
123
|
+
alt_len = rdata_s[index].ord; index += 1
|
124
|
+
altitude = rdata_s[index, alt_len]; index += alt_len
|
125
|
+
|
126
|
+
validate_latitude(latitude)
|
127
|
+
validate_longitude(longitude)
|
128
|
+
|
129
|
+
new([longitude, latitude, altitude].join(' ')) # e.g. "10.0 20.0 30.0"
|
130
|
+
end
|
131
|
+
|
132
|
+
# 'name' is used in the RR superclass, but 'owner' is the term referred to
|
133
|
+
# in the RFC, so we'll make owner an alias for name.
|
134
|
+
def owner
|
135
|
+
name
|
136
|
+
end
|
137
|
+
|
138
|
+
# 'name' is used in the RR superclass, but 'owner' is the term referred to
|
139
|
+
# in the RFC, so we'll make owner an alias for name.
|
140
|
+
def owner=(owner_string)
|
141
|
+
self.name = owner_string
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.valid_float?(object)
|
145
|
+
begin
|
146
|
+
Float(object)
|
147
|
+
true
|
148
|
+
rescue
|
149
|
+
false
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.validate_float_in_range(label, object, bound)
|
154
|
+
number = Float(object)
|
155
|
+
valid_range = (-Float(bound)..Float(bound))
|
156
|
+
unless valid_range.include?(number)
|
157
|
+
raise "Value of #{label} (#{number}) was not in the range #{valid_range}."
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.validate_longitude(value)
|
162
|
+
validate_float_in_range('longitude', value, 180)
|
163
|
+
end
|
164
|
+
|
165
|
+
def self.validate_latitude(value)
|
166
|
+
validate_float_in_range('latitude', value, 90)
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.validate_floats(init_data)
|
170
|
+
bad_float_keys = REQUIRED_KEYS.reject { |key| valid_float?(init_data[key]) }
|
171
|
+
unless bad_float_keys.empty?
|
172
|
+
message = "The following key value pair(s) do not have valid floats or float strings:\n"
|
173
|
+
bad_float_keys.each do |key|
|
174
|
+
message << "%:-12.12s => %s\n" % [init_data[key]]
|
175
|
+
end
|
176
|
+
raise message
|
177
|
+
end
|
178
|
+
|
179
|
+
validate_longitude(init_data[:longitude])
|
180
|
+
validate_latitude(init_data[:latitude])
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
|
data/lib/dnsruby/resource/RR.rb
CHANGED
@@ -320,7 +320,6 @@ class RR
|
|
320
320
|
end
|
321
321
|
|
322
322
|
def ==(other)
|
323
|
-
|
324
323
|
return false unless self.class == other.class
|
325
324
|
|
326
325
|
ivars_to_compare = ->(object) do
|
@@ -351,7 +350,7 @@ class RR
|
|
351
350
|
end
|
352
351
|
|
353
352
|
def hash # :nodoc:
|
354
|
-
vars = self.instance_variables - [
|
353
|
+
vars = (self.instance_variables - [:@ttl]).sort
|
355
354
|
vars.inject(0) do |hash_value, var_name|
|
356
355
|
hash_value ^ self.instance_variable_get(var_name).hash
|
357
356
|
end
|
data/lib/dnsruby/version.rb
CHANGED
data/lib/dnsruby/zone_reader.rb
CHANGED
@@ -69,12 +69,11 @@ module Dnsruby
|
|
69
69
|
# Returns a string representing the normalised line.
|
70
70
|
def process_line(line, do_prefix_hack = false)
|
71
71
|
return nil if (line[0,1] == ";")
|
72
|
+
line = strip_comments(line)
|
72
73
|
return nil if (line.strip.length == 0)
|
73
74
|
return nil if (!line || (line.length == 0))
|
74
75
|
@in_quoted_section = false if !@continued_line
|
75
76
|
|
76
|
-
line = strip_comments(line)
|
77
|
-
|
78
77
|
if (line.index("$ORIGIN") == 0)
|
79
78
|
@origin = line.split()[1].strip # $ORIGIN <domain-name> [<comment>]
|
80
79
|
# print "Setting $ORIGIN to #{@origin}\n"
|
data/test/spec_helper.rb
CHANGED
data/test/tc_gpos.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
require_relative '../lib/dnsruby/resource/GPOS.rb'
|
4
|
+
|
5
|
+
include Dnsruby
|
6
|
+
|
7
|
+
# Tests GPOS resource record. See bottom of file for sample zone file.
|
8
|
+
class TestGPOS < Minitest::Test
|
9
|
+
|
10
|
+
EXAMPLE_LONGITUDE = '10.0'
|
11
|
+
EXAMPLE_LATITUDE = '20.0'
|
12
|
+
EXAMPLE_ALTITUDE = '30.0'
|
13
|
+
EXAMPLE_HOSTNAME = 'a.dnsruby.com.'
|
14
|
+
EXAMPLE_TTL = 3 * 60 * 60 # 10,800 seconds, or 3 hours
|
15
|
+
|
16
|
+
EXAMPLE_GPOS_STRING = 'a.dnsruby.com. 10800 IN GPOS 10.0 20.0 30.0'
|
17
|
+
|
18
|
+
EXAMPLE_GPOS_HASH = {
|
19
|
+
name: EXAMPLE_HOSTNAME,
|
20
|
+
type: Types::GPOS,
|
21
|
+
ttl: EXAMPLE_TTL,
|
22
|
+
longitude: EXAMPLE_LONGITUDE,
|
23
|
+
latitude: EXAMPLE_LATITUDE,
|
24
|
+
altitude: EXAMPLE_ALTITUDE,
|
25
|
+
}
|
26
|
+
|
27
|
+
EXAMPLE_GPOS_DATA = begin
|
28
|
+
rdata = RR::GPOS.build_rdata(EXAMPLE_LONGITUDE, EXAMPLE_LATITUDE, EXAMPLE_ALTITUDE)
|
29
|
+
[EXAMPLE_HOSTNAME, Types::GPOS, Classes::IN, EXAMPLE_TTL, rdata.length, rdata, 0]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns a GPOS record returned by a BIND server configured with the zone file
|
33
|
+
# shown at the bottom of this file. I (keithrbennett) was unable to find a GPOS
|
34
|
+
# record on the public Internet to use for live testing.
|
35
|
+
def gpos_from_response
|
36
|
+
# query = Message.new(EXAMPLE_HOSTNAME, 'GPOS')
|
37
|
+
# query_binary = "E0\u0000\u0000\u0000\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0001a\adnsruby\u0003com\u0000\u0000\e\u0000\u0001"
|
38
|
+
# response, _error = Resolver.new('127.0.0.1').query_raw(query)
|
39
|
+
|
40
|
+
response_binary = "E0\x84\x80\x00\x01\x00\x01\x00\x01\x00\x01\x01a\adnsruby\x03com\x00\x00\e\x00\x01\xC0\f\x00\e\x00\x01\x00\x00*0\x00\x0F\x0410.0\x0420.0\x0430.0\xC0\x0E\x00\x02\x00\x01\x00\x00*0\x00\x06\x03ns1\xC0\x0E\xC0F\x00\x01\x00\x01\x00\x00*0\x00\x04\x7F\x00\x00\x01"
|
41
|
+
response = Message.decode(response_binary)
|
42
|
+
|
43
|
+
# response_binary = "\xE7\x01\x85\x90\x00\x01\x00\x01\x00\x01\x00\x01\x01g\adnsruby\x03com" +
|
44
|
+
# "\x00\x00\e\x00\x01\xC0\f\x00\e\x00\x01\x00\t:\x80\x00\x0F\x0420.0\x0430.0\x0410.0" +
|
45
|
+
# "\xC0\x0E\x00\x02\x00\x01\x00\t:\x80\x00\x05\x02ns\xC0\x0E\xC0F\x00\x01\x00\x01\x00" +
|
46
|
+
# "\t:\x80\x00\x04\xC0\xA8\x01\n"; nil
|
47
|
+
#
|
48
|
+
# response = Message.decode(response_binary)
|
49
|
+
|
50
|
+
response.answer[0]
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def test_answer
|
55
|
+
answer = gpos_from_response
|
56
|
+
assert answer.is_a?(RR::GPOS), "Expected RR::GPOS but got a #{answer.class}: #{answer}"
|
57
|
+
assert_equal(EXAMPLE_LONGITUDE, answer.longitude)
|
58
|
+
assert_equal(EXAMPLE_LATITUDE, answer.latitude)
|
59
|
+
assert_equal(EXAMPLE_ALTITUDE, answer.altitude)
|
60
|
+
assert_equal(EXAMPLE_TTL, answer.ttl)
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# should be: <owner> <ttl> <class> GPOS <longitude> <latitude> <altitude>
|
65
|
+
def test_to_s
|
66
|
+
actual = gpos_from_response.to_s.split
|
67
|
+
expected = %w(a.dnsruby.com. 10800 IN GPOS 10.0 20.0 30.0)
|
68
|
+
assert_equal(expected, actual)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_creation_approaches
|
72
|
+
|
73
|
+
ans_from_data = RR::GPOS.from_data(*EXAMPLE_GPOS_DATA)
|
74
|
+
ans_from_string = RR::GPOS.from_string(EXAMPLE_GPOS_STRING)
|
75
|
+
ans_from_hash = RR::GPOS.from_hash(EXAMPLE_GPOS_HASH)
|
76
|
+
|
77
|
+
fails_to_populate_rdata = []
|
78
|
+
fails_to_populate_rdata << 'data' if ans_from_data.rdata.nil?
|
79
|
+
fails_to_populate_rdata << 'string' if ans_from_string.rdata.nil?
|
80
|
+
fails_to_populate_rdata << 'hash' if ans_from_hash.rdata.nil?
|
81
|
+
|
82
|
+
assert_equal([], fails_to_populate_rdata,
|
83
|
+
"Populate modes failing to populate rdata: #{fails_to_populate_rdata.join(', ')}")
|
84
|
+
|
85
|
+
assert_equal(ans_from_data.rdata, ans_from_hash.rdata)
|
86
|
+
assert_equal(ans_from_data.rdata, ans_from_string.rdata)
|
87
|
+
|
88
|
+
assert_equal(ans_from_data, ans_from_hash)
|
89
|
+
assert_equal(ans_from_data, ans_from_string)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_decode_encode
|
93
|
+
response_binary = "E0\x84\x80\x00\x01\x00\x01\x00\x01\x00\x01\x01a\adnsruby\x03com\x00\x00\e\x00\x01\xC0\f\x00\e\x00\x01\x00\x00*0\x00\x0F\x0410.0\x0420.0\x0430.0\xC0\x0E\x00\x02\x00\x01\x00\x00*0\x00\x06\x03ns1\xC0\x0E\xC0F\x00\x01\x00\x01\x00\x00*0\x00\x04\x7F\x00\x00\x01"
|
94
|
+
message_object = Message.decode(response_binary)
|
95
|
+
reconstructed_binary = message_object.encode
|
96
|
+
assert_equal response_binary.force_encoding('ASCII-8BIT'), reconstructed_binary
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# Sample zone file for setting up BIND to serve GPOS records:
|
102
|
+
=begin
|
103
|
+
$TTL 3h
|
104
|
+
|
105
|
+
@ IN SOA dnsruby.com. foo.dnsruby.com. (
|
106
|
+
1 ; serial
|
107
|
+
3H ; refresh after 3 hours
|
108
|
+
1H ; retry after 1 hour
|
109
|
+
1W ; expire after 1 week
|
110
|
+
1H) ; negative caching TTL of 1 hour
|
111
|
+
|
112
|
+
dnsruby.com. IN NS ns1
|
113
|
+
|
114
|
+
; Addresses for canonical names
|
115
|
+
|
116
|
+
ns1.dnsruby.com. IN A 127.0.0.1
|
117
|
+
|
118
|
+
a.dnsruby.com. IN A 2.4.6.8
|
119
|
+
IN GPOS 10.0 20.0 30.0
|
120
|
+
|
121
|
+
b.dnsruby.com. IN A 2.4.6.9
|
122
|
+
IN GPOS 40 50 60
|
123
|
+
|
124
|
+
=end
|
data/test/tc_hs.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
include Dnsruby
|
4
|
+
|
5
|
+
class TestDNS < Minitest::Test
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Dnsruby::Config.reset
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
# Illustrates that when a message whose class is 'HS' is sent to
|
13
|
+
# a DNS server that does not support the HS class, using send_plain_message,
|
14
|
+
# the response returns with an rcode of NOTIMP and a Dnsruby::NotImp error.
|
15
|
+
def test_hs_class_returns_notimp_code_and_error
|
16
|
+
resolver_host = 'a.gtld-servers.net'
|
17
|
+
resolver = Resolver.new(resolver_host)
|
18
|
+
message = Message.new('test.com', 'A', 'HS')
|
19
|
+
response, error = resolver.send_plain_message(message)
|
20
|
+
|
21
|
+
assert_equal(RCode::NOTIMP, response.rcode)
|
22
|
+
assert_equal(Dnsruby::NotImp, error.class)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/test/tc_nsec3.rb
CHANGED
@@ -134,9 +134,4 @@ class Nsec3Test < Minitest::Test
|
|
134
134
|
rr = RR.create("929p027vb26s89h6fv5j7hmsis4tcr1p.tjeb.nl. 3600 IN NSEC3 1 0 5 beef 9rs4nbe7128ap5i6v196ge2iag5b7rcq A AAAA RRSIG
|
135
135
|
")
|
136
136
|
end
|
137
|
-
|
138
|
-
def test_rfc_examples
|
139
|
-
print "IMPLEMENT NSEC3 validation!\n"
|
140
|
-
return
|
141
|
-
end
|
142
137
|
end
|
data/test/tc_resolver.rb
CHANGED
@@ -285,4 +285,77 @@ class TestResolver < Minitest::Test
|
|
285
285
|
def test_eventtype_api
|
286
286
|
# @TODO@ TEST THE Resolver::EventType interface!
|
287
287
|
end
|
288
|
-
end
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
# Tests to see that query_raw handles send_plain_message's return values correctly.
|
292
|
+
class TestRawQuery < Minitest::Test
|
293
|
+
|
294
|
+
class CustomError < RuntimeError; end
|
295
|
+
|
296
|
+
# Returns a new resolver whose send_plain_message method always returns
|
297
|
+
# nil for the response, and a RuntimeError for the error.
|
298
|
+
def resolver_returning_error
|
299
|
+
resolver = Resolver.new
|
300
|
+
def resolver.send_plain_message(_message)
|
301
|
+
[nil, CustomError.new]
|
302
|
+
end
|
303
|
+
resolver
|
304
|
+
end
|
305
|
+
|
306
|
+
# Returns a new resolver whose send_plain_message is overridden to return
|
307
|
+
# :response_from_send_plain_message instead of a real Dnsruby::Message,
|
308
|
+
# for easy comparison in the tests.
|
309
|
+
def resolver_returning_response
|
310
|
+
resolver = Resolver.new
|
311
|
+
def resolver.send_plain_message(_message)
|
312
|
+
[:response_from_send_plain_message, nil]
|
313
|
+
end
|
314
|
+
resolver
|
315
|
+
end
|
316
|
+
|
317
|
+
# Test that when a strategy other than :raise or :return is passed,
|
318
|
+
# an ArgumentError is raised.
|
319
|
+
def test_bad_strategy
|
320
|
+
assert_raises(ArgumentError) do
|
321
|
+
resolver_returning_error.query_raw(Message.new, :invalid_strategy)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
# Test that when send_plain_message returns an error,
|
326
|
+
# and the error strategy is :raise, query_raw raises an error.
|
327
|
+
def test_raise_error
|
328
|
+
assert_raises(CustomError) do
|
329
|
+
resolver_returning_error.query_raw(Message.new, :raise)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
# Tests that if you don't specify an error strategy, an error will be
|
334
|
+
# returned rather than raised (i.e. strategy defaults to :return).
|
335
|
+
def test_return_error_is_default
|
336
|
+
_response, error = resolver_returning_error.query_raw(Message.new)
|
337
|
+
assert error.is_a?(CustomError)
|
338
|
+
end
|
339
|
+
|
340
|
+
# Tests that when no error is returned, no error is raised.
|
341
|
+
def test_raise_no_error
|
342
|
+
response, _error = resolver_returning_response.query_raw(Message.new, :raise)
|
343
|
+
assert_equal :response_from_send_plain_message, response
|
344
|
+
end
|
345
|
+
|
346
|
+
# Test that when send_plain_message returns an error, and the error strategy
|
347
|
+
# is set to :return, then an error is returned.
|
348
|
+
def test_return_error
|
349
|
+
_response, error = resolver_returning_error.query_raw(Message.new, :return)
|
350
|
+
assert error.is_a?(CustomError)
|
351
|
+
end
|
352
|
+
|
353
|
+
# Test that when send_plain_message returns a valid and response
|
354
|
+
# and nil error, the same are returned by query_raw.
|
355
|
+
def test_return_no_error
|
356
|
+
response, error = resolver_returning_response.query_raw(Message.new, :return)
|
357
|
+
assert_nil error
|
358
|
+
assert_equal :response_from_send_plain_message, response
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
data/test/tc_rr-opt.rb
CHANGED
@@ -20,6 +20,38 @@ require 'socket'
|
|
20
20
|
|
21
21
|
include Dnsruby
|
22
22
|
class TestRrOpt < Minitest::Test
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
# This test illustrates that when an OPT record specifying a maximum
|
27
|
+
# UDP size is added to a query, the server will respect that setting
|
28
|
+
# and limit the response's size to <= that maximum.
|
29
|
+
# This works only with send_plain_message, not send_message, query, etc.
|
30
|
+
def test_plain_respects_bufsize
|
31
|
+
|
32
|
+
resolver = Resolver.new('a.gtld-servers.net')
|
33
|
+
|
34
|
+
run_test = ->(bufsize) do
|
35
|
+
|
36
|
+
create_test_query = ->(bufsize) do
|
37
|
+
message = Message.new('com', Types.ANY, Classes.IN)
|
38
|
+
message.add_additional(RR::OPT.new(bufsize))
|
39
|
+
message
|
40
|
+
end
|
41
|
+
|
42
|
+
query = create_test_query.(bufsize)
|
43
|
+
response, _error = resolver.send_plain_message(query)
|
44
|
+
# puts "\nBufsize is #{bufsize}, binary message size is #{response.encode.size}"
|
45
|
+
assert_equal(true, response.header.tc)
|
46
|
+
assert(response.encode.size <= bufsize)
|
47
|
+
end
|
48
|
+
|
49
|
+
run_test.(512)
|
50
|
+
run_test.(612)
|
51
|
+
run_test.(4096)
|
52
|
+
end
|
53
|
+
|
54
|
+
|
23
55
|
def test_rropt
|
24
56
|
size=2048;
|
25
57
|
ednsflags=0x9e22;
|
data/test/tc_rr.rb
CHANGED
@@ -319,4 +319,13 @@ class TestRR < Minitest::Test
|
|
319
319
|
# We should be here because the method should not have been found.
|
320
320
|
end
|
321
321
|
end
|
322
|
+
|
323
|
+
# TTL should be ignored when calculating the hash of an RR.
|
324
|
+
def test_hash_ignores_ttl
|
325
|
+
a1 = RR.new_from_string 'techhumans.com. 1111 IN A 69.89.31.97'
|
326
|
+
a2 = RR.new_from_string 'techhumans.com. 1111 IN A 69.89.31.97'
|
327
|
+
a3 = RR.new_from_string 'techhumans.com. 2222 IN A 69.89.31.97'
|
328
|
+
assert_equal a1.hash, a2.hash
|
329
|
+
assert_equal a1.hash, a3.hash
|
330
|
+
end
|
322
331
|
end
|
data/test/ts_offline.rb
CHANGED
data/test/ts_online.rb
CHANGED
@@ -40,6 +40,7 @@ if (online)
|
|
40
40
|
print "It may just be that some UDP packets got lost the first time...\n"
|
41
41
|
require_relative "tc_resolver.rb"
|
42
42
|
require_relative "tc_dnsruby.rb"
|
43
|
+
require_relative "tc_hs.rb"
|
43
44
|
# require_relative "tc_inet6.rb"
|
44
45
|
# require_relative "tc_recurse.rb"
|
45
46
|
require_relative "tc_tcp.rb"
|
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dnsruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.57.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Dalitz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pry
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry-byebug
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
13
41
|
- !ruby/object:Gem::Dependency
|
14
42
|
name: rake
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -71,11 +99,17 @@ extra_rdoc_files:
|
|
71
99
|
- README.md
|
72
100
|
- EVENTMACHINE
|
73
101
|
files:
|
102
|
+
- ".coveralls.yml"
|
103
|
+
- ".gitignore"
|
104
|
+
- ".travis.yml"
|
74
105
|
- DNSSEC
|
75
106
|
- EVENTMACHINE
|
76
107
|
- EXAMPLES
|
108
|
+
- Gemfile
|
77
109
|
- README.md
|
110
|
+
- RELEASE_NOTES.md
|
78
111
|
- Rakefile
|
112
|
+
- SIGNED_UPDATES
|
79
113
|
- demo/axfr.rb
|
80
114
|
- demo/check_soa.rb
|
81
115
|
- demo/check_zone.rb
|
@@ -87,6 +121,7 @@ files:
|
|
87
121
|
- demo/rubydig.rb
|
88
122
|
- demo/to_resolve.txt
|
89
123
|
- demo/trace_dns.rb
|
124
|
+
- dnsruby.gemspec
|
90
125
|
- lib/dnsruby.rb
|
91
126
|
- lib/dnsruby/DNS.rb
|
92
127
|
- lib/dnsruby/cache.rb
|
@@ -117,6 +152,7 @@ files:
|
|
117
152
|
- lib/dnsruby/resource/DLV.rb
|
118
153
|
- lib/dnsruby/resource/DNSKEY.rb
|
119
154
|
- lib/dnsruby/resource/DS.rb
|
155
|
+
- lib/dnsruby/resource/GPOS.rb
|
120
156
|
- lib/dnsruby/resource/HINFO.rb
|
121
157
|
- lib/dnsruby/resource/HIP.rb
|
122
158
|
- lib/dnsruby/resource/IN.rb
|
@@ -169,11 +205,12 @@ files:
|
|
169
205
|
- test/tc_dnsruby.rb
|
170
206
|
- test/tc_ds.rb
|
171
207
|
- test/tc_escapedchars.rb
|
208
|
+
- test/tc_gpos.rb
|
172
209
|
- test/tc_hash.rb
|
173
210
|
- test/tc_header.rb
|
174
211
|
- test/tc_hip.rb
|
212
|
+
- test/tc_hs.rb
|
175
213
|
- test/tc_ipseckey.rb
|
176
|
-
- test/tc_keith.rb
|
177
214
|
- test/tc_message.rb
|
178
215
|
- test/tc_misc.rb
|
179
216
|
- test/tc_name.rb
|
@@ -214,7 +251,10 @@ homepage: https://github.com/alexdalitz/dnsruby
|
|
214
251
|
licenses:
|
215
252
|
- Apache License, Version 2.0
|
216
253
|
metadata: {}
|
217
|
-
post_install_message:
|
254
|
+
post_install_message: |-
|
255
|
+
Installing dnsruby...
|
256
|
+
For issues and source code: https://github.com/alexdalitz/dnsruby
|
257
|
+
For general discussion (please tell us how you use dnsruby): https://groups.google.com/forum/#!forum/dnsruby
|
218
258
|
rdoc_options: []
|
219
259
|
require_paths:
|
220
260
|
- lib
|
data/test/tc_keith.rb
DELETED
@@ -1,300 +0,0 @@
|
|
1
|
-
# --
|
2
|
-
# Copyright 2007 Nominet UK
|
3
|
-
#
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
-
# you may not use this file except in compliance with the License.
|
6
|
-
# You may obtain a copy of the License at
|
7
|
-
#
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
-
#
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either tmexpress or implied.
|
13
|
-
# See the License for the specific language governing permissions and
|
14
|
-
# limitations under the License.
|
15
|
-
# ++
|
16
|
-
require_relative 'spec_helper'
|
17
|
-
|
18
|
-
require 'socket'
|
19
|
-
|
20
|
-
include Dnsruby
|
21
|
-
# @TODO@ We also need a test server so we can control behaviour of server to test
|
22
|
-
# different aspects of retry strategy.
|
23
|
-
# Of course, with Ruby's limit of 256 open sockets per process, we'd need to run
|
24
|
-
# the server in a different Ruby process.
|
25
|
-
|
26
|
-
class TestResolver < Minitest::Test
|
27
|
-
|
28
|
-
include Dnsruby
|
29
|
-
|
30
|
-
Thread::abort_on_exception = true
|
31
|
-
|
32
|
-
GOOD_DOMAIN_NAME = 'example.com'
|
33
|
-
BAD_DOMAIN_NAME = 'dnsruby-test-of-bad-domain-name.blah'
|
34
|
-
|
35
|
-
PORT = 42138
|
36
|
-
@@port = PORT
|
37
|
-
|
38
|
-
def setup
|
39
|
-
Dnsruby::Config.reset
|
40
|
-
end
|
41
|
-
|
42
|
-
def assert_valid_response(response)
|
43
|
-
assert(response.kind_of?(Message), "Expected response to be a message but was a #{response.class}")
|
44
|
-
end
|
45
|
-
|
46
|
-
def assert_nil_response(response)
|
47
|
-
assert(response.nil?, "Expected no response but got a #{response.class}:\n#{response}")
|
48
|
-
end
|
49
|
-
|
50
|
-
def assert_error_is_exception(error, error_class = Exception)
|
51
|
-
assert(error.is_a?(error_class), "Expected error to be an #{error_class}, but was a #{error.class}:\n#{error}")
|
52
|
-
end
|
53
|
-
|
54
|
-
def assert_nil_error(error)
|
55
|
-
assert(error.nil?, "Expected no error but got a #{error.class}:\n#{error}")
|
56
|
-
end
|
57
|
-
|
58
|
-
def test_send_message
|
59
|
-
response = Resolver.new.send_message(Message.new("example.com", Types.A))
|
60
|
-
assert_valid_response(response)
|
61
|
-
end
|
62
|
-
|
63
|
-
def test_send_message_bang_noerror
|
64
|
-
response, error = Resolver.new.send_message!(Message.new(GOOD_DOMAIN_NAME, Types.A))
|
65
|
-
assert_nil_error(error)
|
66
|
-
assert_valid_response(response)
|
67
|
-
end
|
68
|
-
|
69
|
-
def test_send_message_bang_error
|
70
|
-
message = Message.new(BAD_DOMAIN_NAME, Types.A)
|
71
|
-
response, error = Resolver.new.send_message!(message)
|
72
|
-
assert_nil_response(response)
|
73
|
-
assert_error_is_exception(error)
|
74
|
-
end
|
75
|
-
|
76
|
-
def test_send_plain_message
|
77
|
-
resolver = Resolver.new
|
78
|
-
response, error = resolver.send_plain_message(Message.new("cnn.com"))
|
79
|
-
assert_nil_error(error)
|
80
|
-
assert_valid_response(response)
|
81
|
-
|
82
|
-
m = Message.new(BAD_DOMAIN_NAME)
|
83
|
-
m.header.rd = true
|
84
|
-
response, error = resolver.send_plain_message(m)
|
85
|
-
assert_valid_response(response)
|
86
|
-
assert_error_is_exception(error, NXDomain)
|
87
|
-
end
|
88
|
-
|
89
|
-
def test_query
|
90
|
-
response = Resolver.new.query("example.com")
|
91
|
-
assert_valid_response(response)
|
92
|
-
end
|
93
|
-
|
94
|
-
def test_query_bang_noerror
|
95
|
-
response, error = Resolver.new.query!(GOOD_DOMAIN_NAME)
|
96
|
-
assert_nil_error(error)
|
97
|
-
assert_valid_response(response)
|
98
|
-
end
|
99
|
-
|
100
|
-
def test_query_bang_error
|
101
|
-
response, error = Resolver.new.query!(BAD_DOMAIN_NAME)
|
102
|
-
assert_nil_response(response)
|
103
|
-
assert_error_is_exception(error)
|
104
|
-
end
|
105
|
-
|
106
|
-
def test_query_async
|
107
|
-
q = Queue.new
|
108
|
-
Resolver.new.send_async(Message.new("example.com", Types.A),q,q)
|
109
|
-
id, response, error = q.pop
|
110
|
-
assert_equal(id, q, "Id wrong!")
|
111
|
-
assert_valid_response(response)
|
112
|
-
assert_nil_error(error)
|
113
|
-
end
|
114
|
-
|
115
|
-
def test_query_one_duff_server_one_good
|
116
|
-
res = Resolver.new({:nameserver => ["8.8.8.8", "8.8.8.7"]})
|
117
|
-
res.retry_delay=1
|
118
|
-
q = Queue.new
|
119
|
-
res.send_async(Message.new("example.com", Types.A),q,q)
|
120
|
-
id, response, error = q.pop
|
121
|
-
assert_equal(id, q, "Id wrong!")
|
122
|
-
assert_valid_response(response)
|
123
|
-
assert_nil_error(error)
|
124
|
-
end
|
125
|
-
|
126
|
-
# @TODO@ Implement!! But then, why would anyone want to do this?
|
127
|
-
# def test_many_threaded_clients
|
128
|
-
# assert(false, "IMPLEMENT!")
|
129
|
-
# end
|
130
|
-
|
131
|
-
def test_reverse_lookup
|
132
|
-
m = Message.new("8.8.8.8", Types.PTR)
|
133
|
-
r = Resolver.new
|
134
|
-
q=Queue.new
|
135
|
-
r.send_async(m,q,q)
|
136
|
-
id,ret, error=q.pop
|
137
|
-
assert(ret.kind_of?(Message))
|
138
|
-
no_pointer=true
|
139
|
-
ret.each_answer do |answer|
|
140
|
-
if (answer.type==Types.PTR)
|
141
|
-
no_pointer=false
|
142
|
-
assert(answer.domainname.to_s=~/google-public-dns/)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
assert(!no_pointer)
|
146
|
-
end
|
147
|
-
|
148
|
-
# def test_bad_host
|
149
|
-
# res = Resolver.new({:nameserver => "localhost"})
|
150
|
-
# res.retry_times=1
|
151
|
-
# res.retry_delay=0
|
152
|
-
# res.query_timeout = 1
|
153
|
-
# q = Queue.new
|
154
|
-
# res.send_async(Message.new("example.com", Types.A), q, q)
|
155
|
-
# id, m, err = q.pop
|
156
|
-
# assert(id==q)
|
157
|
-
# assert(m == nil)
|
158
|
-
# assert(err.kind_of?(OtherResolvError) || err.kind_of?(IOError), "OtherResolvError or IOError expected : got #{err.class}")
|
159
|
-
# end
|
160
|
-
#
|
161
|
-
def test_nxdomain
|
162
|
-
resolver = Resolver.new
|
163
|
-
q = Queue.new
|
164
|
-
resolver .send_async(Message.new(BAD_DOMAIN_NAME, Types.A), q, 1)
|
165
|
-
id, m, error = q.pop
|
166
|
-
assert(id==1, "Id should have been 1 but was #{id}")
|
167
|
-
assert(m.rcode == RCode.NXDOMAIN, "Expected NXDOMAIN but got #{m.rcode} instead.")
|
168
|
-
assert_error_is_exception(error, NXDomain)
|
169
|
-
end
|
170
|
-
|
171
|
-
def test_timeouts
|
172
|
-
# test timeout behaviour for different retry, retrans, total timeout etc.
|
173
|
-
# Problem here is that many sockets will be created for queries which time out.
|
174
|
-
# Run a query which will not respond, and check that the timeout works
|
175
|
-
if (!RUBY_PLATFORM=~/darwin/)
|
176
|
-
start=stop=0
|
177
|
-
retry_times = 3
|
178
|
-
retry_delay=1
|
179
|
-
packet_timeout=2
|
180
|
-
# Work out what time should be, then time it to check
|
181
|
-
expected = ((2**(retry_times-1))*retry_delay) + packet_timeout
|
182
|
-
begin
|
183
|
-
res = Resolver.new({:nameserver => "10.0.1.128"})
|
184
|
-
# res = Resolver.new({:nameserver => "213.248.199.17"})
|
185
|
-
res.packet_timeout=packet_timeout
|
186
|
-
res.retry_times=retry_times
|
187
|
-
res.retry_delay=retry_delay
|
188
|
-
start=Time.now
|
189
|
-
m = res.send_message(Message.new("a.t.dnsruby.validation-test-servers.nominet.org.uk", Types.A))
|
190
|
-
fail
|
191
|
-
rescue ResolvTimeout
|
192
|
-
stop=Time.now
|
193
|
-
time = stop-start
|
194
|
-
assert(time <= expected *1.3 && time >= expected *0.9, "Wrong time take, expected #{expected}, took #{time}")
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
def test_packet_timeout
|
200
|
-
res = Resolver.new({:nameserver => []})
|
201
|
-
# res = Resolver.new({:nameserver => "10.0.1.128"})
|
202
|
-
start=stop=0
|
203
|
-
retry_times = retry_delay = packet_timeout= 10
|
204
|
-
query_timeout=2
|
205
|
-
begin
|
206
|
-
res.packet_timeout=packet_timeout
|
207
|
-
res.retry_times=retry_times
|
208
|
-
res.retry_delay=retry_delay
|
209
|
-
res.query_timeout=query_timeout
|
210
|
-
# Work out what time should be, then time it to check
|
211
|
-
expected = query_timeout
|
212
|
-
start=Time.now
|
213
|
-
m = res.send_message(Message.new("a.t.dnsruby.validation-test-servers.nominet.org.uk", Types.A))
|
214
|
-
fail
|
215
|
-
rescue ResolvTimeout
|
216
|
-
stop=Time.now
|
217
|
-
time = stop-start
|
218
|
-
assert(time <= expected *1.3 && time >= expected *0.9, "Wrong time take, expected #{expected}, took #{time}")
|
219
|
-
end #
|
220
|
-
end
|
221
|
-
|
222
|
-
def test_queue_packet_timeout
|
223
|
-
# if (!RUBY_PLATFORM=~/darwin/)
|
224
|
-
res = Resolver.new({:nameserver => "10.0.1.128"})
|
225
|
-
# bad = SingleResolver.new("localhost")
|
226
|
-
res.add_server("localhost")
|
227
|
-
expected = 2
|
228
|
-
res.query_timeout=expected
|
229
|
-
q = Queue.new
|
230
|
-
start = Time.now
|
231
|
-
m = res.send_async(Message.new("a.t.dnsruby.validation-test-servers.nominet.org.uk", Types.A), q, q)
|
232
|
-
id,ret,err = q.pop
|
233
|
-
stop = Time.now
|
234
|
-
assert(id=q)
|
235
|
-
assert(ret==nil)
|
236
|
-
assert(err.class == ResolvTimeout, "#{err.class}, #{err}")
|
237
|
-
time = stop-start
|
238
|
-
assert(time <= expected *1.3 && time >= expected *0.9, "Wrong time take, expected #{expected}, took #{time}")
|
239
|
-
# end
|
240
|
-
end
|
241
|
-
|
242
|
-
def test_illegal_src_port
|
243
|
-
# Also test all singleresolver ports ok
|
244
|
-
# Try to set src_port to an illegal value - make sure error raised, and port OK
|
245
|
-
res = Resolver.new
|
246
|
-
res.port = 56789
|
247
|
-
tests = [53, 387, 1265, 3210, 48619]
|
248
|
-
tests.each do |bad_port|
|
249
|
-
begin
|
250
|
-
res.src_port = bad_port
|
251
|
-
fail("bad port #{bad_port}")
|
252
|
-
rescue
|
253
|
-
end
|
254
|
-
end
|
255
|
-
assert(res.single_resolvers[0].src_port = 56789)
|
256
|
-
end
|
257
|
-
|
258
|
-
def test_add_src_port
|
259
|
-
# Try setting and adding port ranges, and invalid ports, and 0.
|
260
|
-
# Also test all singleresolver ports ok
|
261
|
-
res = Resolver.new
|
262
|
-
res.src_port = [56789,56790, 56793]
|
263
|
-
assert(res.src_port == [56789,56790, 56793])
|
264
|
-
res.src_port = 56889..56891
|
265
|
-
assert(res.src_port == [56889,56890,56891])
|
266
|
-
res.add_src_port(60000..60002)
|
267
|
-
assert(res.src_port == [56889,56890,56891,60000,60001,60002])
|
268
|
-
res.add_src_port([60004,60005])
|
269
|
-
assert(res.src_port == [56889,56890,56891,60000,60001,60002,60004,60005])
|
270
|
-
res.add_src_port(60006)
|
271
|
-
assert(res.src_port == [56889,56890,56891,60000,60001,60002,60004,60005,60006])
|
272
|
-
# Now test invalid src_ports
|
273
|
-
tests = [0, 53, [60007, 53], [60008, 0], 55..100]
|
274
|
-
tests.each do |x|
|
275
|
-
begin
|
276
|
-
res.add_src_port(x)
|
277
|
-
fail()
|
278
|
-
rescue
|
279
|
-
end
|
280
|
-
end
|
281
|
-
assert(res.src_port == [56889,56890,56891,60000,60001,60002,60004,60005,60006])
|
282
|
-
assert(res.single_resolvers[0].src_port == [56889,56890,56891,60000,60001,60002,60004,60005,60006])
|
283
|
-
end
|
284
|
-
|
285
|
-
def test_eventtype_api
|
286
|
-
# @TODO@ TEST THE Resolver::EventType interface!
|
287
|
-
end
|
288
|
-
|
289
|
-
def test_rd_not_overwritten
|
290
|
-
message = Message.new(GOOD_DOMAIN_NAME)
|
291
|
-
message.header.rd = false
|
292
|
-
assert(! message.header.rd)
|
293
|
-
resolver = Resolver.new
|
294
|
-
raise "Header rd flag was overwritten to true in #{__FILE__}:#{__LINE__}" if message.header.rd
|
295
|
-
_response = resolver.send_message(message)
|
296
|
-
puts "Header rd: #{message.header.rd}"
|
297
|
-
raise "Header rd flag was overwritten to true in #{__FILE__}:#{__LINE__}" if message.header.rd
|
298
|
-
assert(! message.header.rd, "Header rd flag was overwritten to true")
|
299
|
-
end
|
300
|
-
end
|