dnsruby 1.58.0 → 1.59.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +11 -0
- data/RELEASE_NOTES.md +15 -0
- data/Rakefile +2 -1
- data/demo/axfr.rb +84 -85
- data/demo/check_soa.rb +115 -94
- data/demo/check_zone.rb +69 -64
- data/demo/digdlv.rb +22 -24
- data/demo/digroot.rb +23 -19
- data/demo/example_recurse.rb +20 -6
- data/demo/mresolv.rb +26 -14
- data/demo/mx.rb +21 -11
- data/demo/rubydig.rb +34 -25
- data/demo/trace_dns.rb +22 -16
- data/lib/dnsruby/cache.rb +8 -0
- data/lib/dnsruby/config.rb +1 -1
- data/lib/dnsruby/dnssec.rb +6 -2
- data/lib/dnsruby/message/decoder.rb +1 -0
- data/lib/dnsruby/message/question.rb +1 -1
- data/lib/dnsruby/packet_sender.rb +4 -0
- data/lib/dnsruby/recursor.rb +9 -1
- data/lib/dnsruby/resource/OPT.rb +2 -2
- data/lib/dnsruby/resource/RR.rb +4 -4
- data/lib/dnsruby/select_thread.rb +2 -2
- data/lib/dnsruby/single_verifier.rb +24 -4
- data/lib/dnsruby/update.rb +1 -1
- data/lib/dnsruby/validator_thread.rb +2 -1
- data/lib/dnsruby/version.rb +1 -1
- data/test/tc_axfr.rb +1 -1
- data/test/tc_cache.rb +45 -9
- data/test/tc_dns.rb +64 -50
- data/test/tc_message.rb +17 -1
- data/test/tc_res_config.rb +3 -2
- data/test/tc_resolv.rb +1 -1
- data/test/tc_single_resolver.rb +148 -132
- data/test/ts_online.rb +7 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30959b577be6d8f64a67832ec6418fd157ece057
|
4
|
+
data.tar.gz: 94af23844c0a0f1d53b405b0720c9253364ad890
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2237405083ea6ba078a24a172d681b8fde6f770d61fab1617cf4683f576ade793af97edadabe2e76fd649dc0d1eb868eb8bd931021b151ad64b8d0f3c99fc271
|
7
|
+
data.tar.gz: b7f1a0e23ca45cbe15410bd604754c26688ca835edb39dcc340ac4aece8d76c3e67d6ed06a9c2c3488caf2d56c6a5d526fca80f1c6933b43c4e3f0f1ff7a6bce
|
data/LICENSE
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
2
|
+
# you may not use this file except in compliance with the License.
|
3
|
+
# You may obtain a copy of the License at
|
4
|
+
#
|
5
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
6
|
+
#
|
7
|
+
# Unless required by applicable law or agreed to in writing, software
|
8
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
9
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
# See the License for the specific language governing permissions and
|
11
|
+
# limitations under the License.
|
data/RELEASE_NOTES.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# Release Notes
|
2
2
|
|
3
|
+
## v1.59.0
|
4
|
+
|
5
|
+
* Add LICENSE file
|
6
|
+
* Add Cache max_size (gihub issue 64)
|
7
|
+
* Disable caching for SOA lookups in demo check_soa.rb
|
8
|
+
* Fix for invalid nameserver in config
|
9
|
+
* Fix encoding for OPT data (thanks Craig Despeaux)
|
10
|
+
* Various test system fixes
|
11
|
+
* OPT fixes
|
12
|
+
* DNSSEC verification failure handling wrt lack of DS chain
|
13
|
+
* DNSSEC validation policy name constants
|
14
|
+
* Fix for BOGUS DLV chains
|
15
|
+
* demo upgrades
|
16
|
+
* Resolver hints improvements
|
17
|
+
|
3
18
|
|
4
19
|
## v1.58.0
|
5
20
|
|
data/Rakefile
CHANGED
@@ -29,4 +29,5 @@ create_task(:test, 'test/ts_dnsruby.rb')
|
|
29
29
|
create_task(:test_offline, 'test/ts_offline.rb')
|
30
30
|
create_task(:test_online, 'test/ts_online.rb')
|
31
31
|
create_task(:soak, 'test/tc_soak.rb')
|
32
|
-
|
32
|
+
create_task(:message, 'test/tc_message.rb')
|
33
|
+
create_task(:cache, 'test/tc_cache.rb')
|
data/demo/axfr.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
1
3
|
# --
|
2
4
|
# Copyright 2007 Nominet UK
|
3
5
|
#
|
6
|
+
|
4
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
8
|
# you may not use this file except in compliance with the License.
|
6
9
|
# You may obtain a copy of the License at
|
@@ -59,9 +62,16 @@
|
|
59
62
|
# Michael Fuhr <mike@fuhr.org>
|
60
63
|
#
|
61
64
|
|
65
|
+
unless (1..2).include?(ARGV.length)
|
66
|
+
puts "Usage: #{$0} [ -fqs ] [ -D directory ] [ @nameserver ] zone"
|
67
|
+
exit(-1)
|
68
|
+
end
|
69
|
+
|
70
|
+
|
62
71
|
require 'getoptLong'
|
63
72
|
require 'dnsruby'
|
64
73
|
|
74
|
+
|
65
75
|
# ------------------------------------------------------------------------------
|
66
76
|
# Read any command-line options and check syntax.
|
67
77
|
# ------------------------------------------------------------------------------
|
@@ -89,110 +99,99 @@ opts.each do |opt, arg|
|
|
89
99
|
end
|
90
100
|
end
|
91
101
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
# Get the nameserver (if specified) and set up the zone transfer directory
|
97
|
-
# hierarchy.
|
98
|
-
# ------------------------------------------------------------------------------
|
99
|
-
|
100
|
-
nameserver = (ARGV[0] =~ /^@/) ? ARGV.shift : ""
|
101
|
-
nameserver = nameserver.sub(/^@/, "")
|
102
|
-
res = nil
|
103
|
-
if nameserver
|
104
|
-
res = Dnsruby::Resolver.new(nameserver)
|
105
|
-
else
|
106
|
-
res = Dnsruby::Resolver.new
|
107
|
-
end
|
102
|
+
# ------------------------------------------------------------------------------
|
103
|
+
# Get the nameserver (if specified) and set up the zone transfer directory
|
104
|
+
# hierarchy.
|
105
|
+
# ------------------------------------------------------------------------------
|
108
106
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
zonefile = basedir + "/" + zonedir + "/axfr"
|
107
|
+
nameserver = (ARGV[0] =~ /^@/) ? ARGV.shift : ''
|
108
|
+
nameserver = nameserver.sub(/^@/, '')
|
109
|
+
resolver = nameserver ? Dnsruby::Resolver.new(nameserver) : Dnsruby::Resolver.new
|
113
110
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
end
|
111
|
+
zone = ARGV.shift
|
112
|
+
basedir = opt_d || File.join((ENV['HOME'] || ''), '.dns-zones')
|
113
|
+
zonedir = zone.split(/\./).reverse.join("/")
|
114
|
+
zonefile = File.join(basedir, zonedir, 'axfr')
|
119
115
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
end
|
116
|
+
# Don't worry about the 0777 permissions here - the current umask setting
|
117
|
+
# will be applied.
|
118
|
+
# NOTE: mkdir will raise an error on failure so I don't think 'or' works here.
|
119
|
+
unless FileTest.directory?(basedir)
|
120
|
+
Dir.mkdir(basedir, 0777) or raise RuntimeError, "can't mkdir #{basedir}: #{$!}\n"
|
121
|
+
end
|
127
122
|
|
128
|
-
|
129
|
-
|
130
|
-
|
123
|
+
dir = basedir
|
124
|
+
# NOTE: What are we doing here? Could this be replaced by mkdir_p?
|
125
|
+
zonedir.split('/').each do |subdir|
|
126
|
+
dir += '/' + subdir
|
127
|
+
unless FileTest.directory?(dir)
|
128
|
+
Dir.mkdir(dir, 0777) or raise RuntimeError, "can't mkdir #{dir}: #{$!}\n"
|
129
|
+
end
|
130
|
+
end
|
131
131
|
|
132
|
-
|
132
|
+
# ------------------------------------------------------------------------------
|
133
|
+
# Get the zone.
|
134
|
+
# ------------------------------------------------------------------------------
|
133
135
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
136
|
+
if FileTest.exist?(zonefile) && !opt_f
|
137
|
+
zoneref = Marshal.load(File.open(zonefile))
|
138
|
+
if zoneref.nil?
|
139
|
+
raise RuntimeError, "couldn't retrieve zone from #{zonefile}: #{$!}\n"
|
140
|
+
end
|
139
141
|
|
140
|
-
|
141
|
-
|
142
|
-
|
142
|
+
# ----------------------------------------------------------------------
|
143
|
+
# Check the SOA serial number if desired.
|
144
|
+
# ----------------------------------------------------------------------
|
143
145
|
|
144
|
-
|
145
|
-
|
146
|
+
if opt_s
|
147
|
+
serial_file = serial_zone = nil
|
146
148
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
end
|
152
|
-
end
|
153
|
-
if serial_file==nil
|
154
|
-
raise RuntimeError, "no SOA in #{zonefile}\n"
|
149
|
+
zoneref.each do |rr|
|
150
|
+
if (rr.type == 'SOA')
|
151
|
+
serial_file = rr.serial
|
152
|
+
break
|
155
153
|
end
|
154
|
+
end
|
155
|
+
if serial_file.nil?
|
156
|
+
raise RuntimeError, "no SOA in #{zonefile}\n"
|
157
|
+
end
|
156
158
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
159
|
+
soa = resolver.query(zone, 'SOA')
|
160
|
+
if soa.nil?
|
161
|
+
raise RuntimeError, "couldn't get SOA for #{zone}: " + resolver.errorstring + "\n"
|
162
|
+
end
|
161
163
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
end
|
164
|
+
soa.answer.each do |rr|
|
165
|
+
if rr.type == 'SOA'
|
166
|
+
serial_zone = rr.serial
|
167
|
+
break
|
167
168
|
end
|
169
|
+
end
|
168
170
|
|
169
|
-
|
170
|
-
|
171
|
-
end
|
171
|
+
if serial_zone != serial_file
|
172
|
+
opt_f = true
|
172
173
|
end
|
173
|
-
else
|
174
|
-
opt_f = true
|
175
174
|
end
|
175
|
+
else
|
176
|
+
opt_f = true
|
177
|
+
end
|
176
178
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
179
|
+
if opt_f
|
180
|
+
print "nameserver = #{nameserver}, zone=#{zone}"
|
181
|
+
zt = Dnsruby::ZoneTransfer.new
|
182
|
+
zt.server = nameserver if nameserver != ''
|
181
183
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
end
|
186
|
-
Marshal.dump(zoneref, File.open(zonefile, File::CREAT|File::RDWR))
|
184
|
+
zoneref = zt.transfer(zone)
|
185
|
+
if zoneref.nil?
|
186
|
+
raise RuntimeError, "couldn't transfer zone\n"
|
187
187
|
end
|
188
|
+
Marshal.dump(zoneref, File.open(zonefile, File::CREAT | File::RDWR))
|
189
|
+
end
|
188
190
|
|
189
|
-
|
190
|
-
|
191
|
-
|
191
|
+
# ------------------------------------------------------------------------------
|
192
|
+
# Print the records in the zone.
|
193
|
+
# ------------------------------------------------------------------------------
|
192
194
|
|
193
|
-
|
194
|
-
|
195
|
-
print z.to_s + "\n"
|
196
|
-
end
|
197
|
-
end
|
195
|
+
unless opt_q
|
196
|
+
zoneref.each { |z| puts z }
|
198
197
|
end
|
data/demo/check_soa.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
1
3
|
# --
|
2
4
|
# Copyright 2007 Nominet UK
|
3
5
|
#
|
@@ -35,7 +37,7 @@
|
|
35
37
|
# The original Bourne Shell and C versions were printed in
|
36
38
|
# "DNS and BIND" by Paul Albitz & Cricket Liu.
|
37
39
|
#
|
38
|
-
#
|
40
|
+
# The Perl version was written by Michael Fuhr <mike@fuhr.org>.
|
39
41
|
#
|
40
42
|
# = SEE ALSO
|
41
43
|
#
|
@@ -43,116 +45,135 @@
|
|
43
45
|
|
44
46
|
require 'dnsruby'
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
-
# ------------------------------------------------------------------------------
|
48
|
+
NO_DOMAIN_SPECIFIED = -1
|
49
|
+
NO_NAMESERVERS = -2
|
49
50
|
|
50
|
-
if ARGV.length ==1
|
51
|
-
domain = ARGV[0]
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
def fatal_error(message, exit_code)
|
53
|
+
puts message
|
54
|
+
exit(exit_code)
|
55
|
+
end
|
56
56
|
|
57
|
-
res = Dnsruby::Resolver.new
|
58
57
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
begin
|
63
|
-
ns_req = res.query(domain, "NS")
|
64
|
-
rescue Exception => e
|
65
|
-
print "Error : #{e}"
|
66
|
-
return
|
67
|
-
end
|
68
|
-
if (ns_req.header.ancount == 0)
|
69
|
-
print "No nameservers found for #{domain}\n"
|
70
|
-
return
|
71
|
-
end
|
58
|
+
def usage
|
59
|
+
fatal_error("Usage: #{$0} domain", NO_DOMAIN_SPECIFIED)
|
60
|
+
end
|
72
61
|
|
73
|
-
# Send out non-recursive queries
|
74
|
-
res.recurse=(0)
|
75
62
|
|
63
|
+
def create_resolver
|
64
|
+
resolver = Dnsruby::Resolver.new
|
65
|
+
resolver.retry_times = 2
|
66
|
+
resolver.recurse = 0 # Send out non-recursive queries
|
67
|
+
# disable caching otherwise SOA is cached from first nameserver queried
|
68
|
+
resolver.do_caching = false
|
69
|
+
resolver
|
70
|
+
end
|
76
71
|
|
77
|
-
# ------------------------------------------------------------------------------
|
78
|
-
# Check the SOA record on each nameserver.
|
79
|
-
# ------------------------------------------------------------------------------
|
80
72
|
|
81
|
-
|
73
|
+
def get_ns_response(resolver, domain)
|
74
|
+
ns_response = resolver.query(domain, 'NS')
|
75
|
+
if ns_response.header.ancount == 0
|
76
|
+
fatal_error("No nameservers found for #{domain}.", NO_NAMESERVERS)
|
77
|
+
end
|
78
|
+
ns_response
|
79
|
+
end
|
82
80
|
|
83
|
-
# ----------------------------------------------------------------------
|
84
|
-
# Set the resolver to query this nameserver.
|
85
|
-
# ----------------------------------------------------------------------
|
86
|
-
ns = nsrr.domainname
|
87
81
|
|
82
|
+
# Finds all the nameserver domains for the domain.
|
83
|
+
def get_ns_domains(resolver, domain)
|
84
|
+
ns_response = get_ns_response(resolver, domain)
|
85
|
+
ns_answers = ns_response.answer.select { |r| r.type == 'NS'}
|
86
|
+
ns_answers.map(&:domainname)
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def process_ns_domain(resolver, domain, ns_domain)
|
91
|
+
|
92
|
+
a_response = begin
|
88
93
|
# In order to lookup the IP(s) of the nameserver, we need a Resolver
|
89
94
|
# object that is set to our local, recursive nameserver. So we create
|
90
95
|
# a new object just to do that.
|
96
|
+
local_resolver = Dnsruby::Resolver.new
|
91
97
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
98
|
+
local_resolver.query(ns_domain, 'A')
|
99
|
+
rescue Exception => e
|
100
|
+
puts "Cannot find address for #{ns_domain}: #{e}"
|
101
|
+
return
|
102
|
+
end
|
103
|
+
|
104
|
+
a_answers = a_response.answer.select {|r| r.type == 'A'}
|
105
|
+
a_answers.each do |a_answer|
|
106
|
+
|
107
|
+
# ----------------------------------------------------------------------
|
108
|
+
# Ask this IP.
|
109
|
+
# ----------------------------------------------------------------------
|
110
|
+
ip_address = a_answer.address
|
111
|
+
resolver.nameserver = ip_address.to_s
|
112
|
+
print "#{ns_domain} (#{ip_address}): "
|
113
|
+
|
114
|
+
# ----------------------------------------------------------------------
|
115
|
+
# Get the SOA record.
|
116
|
+
# ----------------------------------------------------------------------
|
117
|
+
soa_response = begin
|
118
|
+
resolver.query(domain, 'SOA', 'IN')
|
96
119
|
rescue Exception => e
|
97
|
-
|
98
|
-
|
120
|
+
puts "Error : #{e}"
|
121
|
+
return
|
122
|
+
end
|
123
|
+
|
124
|
+
# ----------------------------------------------------------------------
|
125
|
+
# Is this nameserver authoritative for the domain?
|
126
|
+
# ----------------------------------------------------------------------
|
127
|
+
|
128
|
+
unless soa_response.header.aa
|
129
|
+
print "isn't authoritative for #{domain}\n"
|
130
|
+
return
|
131
|
+
end
|
132
|
+
|
133
|
+
# ----------------------------------------------------------------------
|
134
|
+
# We should have received exactly one answer.
|
135
|
+
# ----------------------------------------------------------------------
|
136
|
+
|
137
|
+
unless soa_response.header.ancount == 1
|
138
|
+
puts "expected 1 answer, got #{soa_response.header.ancount}."
|
139
|
+
return
|
99
140
|
end
|
100
141
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
print "#{ns} (#{ip}): "
|
110
|
-
|
111
|
-
# ----------------------------------------------------------------------
|
112
|
-
# Get the SOA record.
|
113
|
-
# ----------------------------------------------------------------------
|
114
|
-
soa_req=nil
|
115
|
-
begin
|
116
|
-
soa_req = res.query(domain, 'SOA', 'IN')
|
117
|
-
rescue Exception => e
|
118
|
-
print "Error : #{e}\n"
|
119
|
-
next
|
120
|
-
end
|
121
|
-
|
122
|
-
# ----------------------------------------------------------------------
|
123
|
-
# Is this nameserver authoritative for the domain?
|
124
|
-
# ----------------------------------------------------------------------
|
125
|
-
|
126
|
-
unless (soa_req.header.aa)
|
127
|
-
print "isn't authoritative for #{domain}\n"
|
128
|
-
next
|
129
|
-
end
|
130
|
-
|
131
|
-
# ----------------------------------------------------------------------
|
132
|
-
# We should have received exactly one answer.
|
133
|
-
# ----------------------------------------------------------------------
|
134
|
-
|
135
|
-
unless (soa_req.header.ancount == 1)
|
136
|
-
print "expected 1 answer, got ", soa_req.header.ancount, "\n"
|
137
|
-
next
|
138
|
-
end
|
139
|
-
|
140
|
-
# ----------------------------------------------------------------------
|
141
|
-
# Did we receive an SOA record?
|
142
|
-
# ----------------------------------------------------------------------
|
143
|
-
|
144
|
-
unless ((soa_req.answer)[0].type == "SOA")
|
145
|
-
print "expected SOA, got ", (soa_req.answer)[0].type, "\n"
|
146
|
-
next
|
147
|
-
end
|
148
|
-
|
149
|
-
# ----------------------------------------------------------------------
|
150
|
-
# Print the serial number.
|
151
|
-
# ----------------------------------------------------------------------
|
152
|
-
|
153
|
-
print "has serial number ", (soa_req.answer)[0].serial, "\n"
|
142
|
+
# ----------------------------------------------------------------------
|
143
|
+
# Did we receive an SOA record?
|
144
|
+
# ----------------------------------------------------------------------
|
145
|
+
|
146
|
+
answer_type = soa_response.answer[0].type
|
147
|
+
unless answer_type == 'SOA'
|
148
|
+
puts "expected SOA, got #{answer_type}"
|
149
|
+
return
|
154
150
|
end
|
151
|
+
|
152
|
+
# ----------------------------------------------------------------------
|
153
|
+
# Print the serial number.
|
154
|
+
# ----------------------------------------------------------------------
|
155
|
+
|
156
|
+
puts "has serial number #{soa_response.answer[0].serial}"
|
155
157
|
end
|
156
|
-
else
|
157
|
-
print "Usage: #{$0} domain\n"
|
158
158
|
end
|
159
|
+
|
160
|
+
|
161
|
+
def main
|
162
|
+
|
163
|
+
# Get domain from command line, printing usage and exiting if none provided:
|
164
|
+
domain = ARGV.fetch(0) { usage }
|
165
|
+
|
166
|
+
resolver = create_resolver
|
167
|
+
|
168
|
+
ns_domains = get_ns_domains(resolver, domain)
|
169
|
+
|
170
|
+
# ------------------------------------------------------------------------------
|
171
|
+
# Check the SOA record on each nameserver.
|
172
|
+
# ------------------------------------------------------------------------------
|
173
|
+
ns_domains.each do |ns_domain_name|
|
174
|
+
process_ns_domain(resolver, domain, ns_domain_name)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
main
|