dnsruby 1.55 → 1.56.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +96 -0
- data/Rakefile +30 -29
- data/demo/axfr.rb +93 -93
- data/demo/check_soa.rb +99 -99
- data/demo/check_zone.rb +59 -59
- data/demo/digdlv.rb +43 -43
- data/demo/digroot.rb +34 -34
- data/demo/example_recurse.rb +14 -14
- data/demo/mresolv.rb +30 -30
- data/demo/mx.rb +31 -31
- data/demo/rubydig.rb +37 -37
- data/demo/to_resolve.txt +3088 -3088
- data/demo/trace_dns.rb +46 -46
- data/lib/dnsruby.rb +161 -526
- data/lib/dnsruby/DNS.rb +305 -0
- data/lib/{Dnsruby/Cache.rb → dnsruby/cache.rb} +152 -152
- data/lib/{Dnsruby → dnsruby}/code_mapper.rb +48 -52
- data/lib/dnsruby/code_mappers.rb +295 -0
- data/lib/{Dnsruby/Config.rb → dnsruby/config.rb} +454 -454
- data/lib/{Dnsruby → dnsruby}/dnssec.rb +91 -91
- data/lib/{Dnsruby/Hosts.rb → dnsruby/hosts.rb} +125 -125
- data/lib/{Dnsruby → dnsruby}/ipv4.rb +26 -26
- data/lib/{Dnsruby → dnsruby}/ipv6.rb +42 -42
- data/lib/{Dnsruby → dnsruby}/key_cache.rb +29 -29
- data/lib/dnsruby/message/decoder.rb +164 -0
- data/lib/dnsruby/message/encoder.rb +75 -0
- data/lib/dnsruby/message/header.rb +249 -0
- data/lib/dnsruby/message/message.rb +629 -0
- data/lib/dnsruby/message/question.rb +86 -0
- data/lib/dnsruby/message/section.rb +96 -0
- data/lib/{Dnsruby → dnsruby}/name.rb +141 -141
- data/lib/dnsruby/packet_sender.rb +661 -0
- data/lib/{Dnsruby/Recursor.rb → dnsruby/recursor.rb} +235 -233
- data/lib/dnsruby/resolv.rb +113 -0
- data/lib/dnsruby/resolver.rb +1192 -0
- data/lib/dnsruby/resource/A.rb +56 -0
- data/lib/dnsruby/resource/AAAA.rb +54 -0
- data/lib/{Dnsruby → dnsruby}/resource/AFSDB.rb +68 -68
- data/lib/{Dnsruby → dnsruby}/resource/CERT.rb +105 -105
- data/lib/{Dnsruby → dnsruby}/resource/DHCID.rb +54 -54
- data/lib/dnsruby/resource/DLV.rb +27 -0
- data/lib/{Dnsruby → dnsruby}/resource/DNSKEY.rb +372 -372
- data/lib/{Dnsruby → dnsruby}/resource/DS.rb +255 -255
- data/lib/{Dnsruby → dnsruby}/resource/HINFO.rb +71 -71
- data/lib/{Dnsruby → dnsruby}/resource/HIP.rb +29 -29
- data/lib/{Dnsruby → dnsruby}/resource/IN.rb +30 -30
- data/lib/{Dnsruby → dnsruby}/resource/IPSECKEY.rb +31 -31
- data/lib/{Dnsruby → dnsruby}/resource/ISDN.rb +62 -62
- data/lib/{Dnsruby → dnsruby}/resource/KX.rb +65 -65
- data/lib/{Dnsruby → dnsruby}/resource/LOC.rb +263 -263
- data/lib/{Dnsruby → dnsruby}/resource/MINFO.rb +69 -69
- data/lib/{Dnsruby → dnsruby}/resource/MX.rb +65 -65
- data/lib/{Dnsruby → dnsruby}/resource/NAPTR.rb +98 -98
- data/lib/{Dnsruby → dnsruby}/resource/NSAP.rb +171 -171
- data/lib/dnsruby/resource/NSEC.rb +275 -0
- data/lib/dnsruby/resource/NSEC3.rb +332 -0
- data/lib/dnsruby/resource/NSEC3PARAM.rb +135 -0
- data/lib/dnsruby/resource/OPT.rb +272 -0
- data/lib/{Dnsruby → dnsruby}/resource/PX.rb +70 -70
- data/lib/{Dnsruby → dnsruby}/resource/RP.rb +75 -75
- data/lib/dnsruby/resource/RR.rb +421 -0
- data/lib/dnsruby/resource/RRSIG.rb +275 -0
- data/lib/dnsruby/resource/RRSet.rb +190 -0
- data/lib/{Dnsruby → dnsruby}/resource/RT.rb +67 -67
- data/lib/{Dnsruby → dnsruby}/resource/SOA.rb +94 -94
- data/lib/dnsruby/resource/SPF.rb +29 -0
- data/lib/dnsruby/resource/SRV.rb +112 -0
- data/lib/{Dnsruby → dnsruby}/resource/SSHFP.rb +14 -14
- data/lib/dnsruby/resource/TKEY.rb +163 -0
- data/lib/dnsruby/resource/TSIG.rb +593 -0
- data/lib/{Dnsruby → dnsruby}/resource/TXT.rb +191 -191
- data/lib/dnsruby/resource/X25.rb +55 -0
- data/lib/{Dnsruby → dnsruby}/resource/domain_name.rb +25 -25
- data/lib/{Dnsruby → dnsruby}/resource/generic.rb +80 -80
- data/lib/dnsruby/resource/resource.rb +25 -0
- data/lib/{Dnsruby → dnsruby}/select_thread.rb +148 -148
- data/lib/{Dnsruby/SingleResolver.rb → dnsruby/single_resolver.rb} +60 -60
- data/lib/{Dnsruby → dnsruby}/single_verifier.rb +344 -344
- data/lib/dnsruby/the_log.rb +44 -0
- data/lib/dnsruby/update.rb +278 -0
- data/lib/dnsruby/validator_thread.rb +124 -0
- data/lib/dnsruby/version.rb +3 -0
- data/lib/{Dnsruby → dnsruby}/zone_reader.rb +93 -93
- data/lib/{Dnsruby → dnsruby}/zone_transfer.rb +377 -377
- data/test/spec_helper.rb +16 -0
- data/test/tc_axfr.rb +31 -34
- data/test/tc_cache.rb +32 -32
- data/test/tc_dlv.rb +28 -28
- data/test/tc_dns.rb +73 -76
- data/test/tc_dnskey.rb +31 -32
- data/test/tc_dnsruby.rb +50 -44
- data/test/tc_ds.rb +36 -36
- data/test/tc_escapedchars.rb +252 -255
- data/test/tc_hash.rb +17 -21
- data/test/tc_header.rb +48 -57
- data/test/tc_hip.rb +19 -22
- data/test/tc_ipseckey.rb +18 -21
- data/test/tc_keith.rb +300 -0
- data/test/tc_message.rb +87 -0
- data/test/tc_misc.rb +83 -87
- data/test/tc_name.rb +81 -84
- data/test/tc_naptr.rb +18 -21
- data/test/tc_nsec.rb +55 -55
- data/test/tc_nsec3.rb +23 -24
- data/test/tc_nsec3param.rb +20 -21
- data/test/tc_packet.rb +90 -93
- data/test/tc_packet_unique_push.rb +48 -51
- data/test/tc_question.rb +30 -33
- data/test/tc_queue.rb +16 -17
- data/test/tc_recur.rb +16 -17
- data/test/tc_res_config.rb +38 -41
- data/test/tc_res_env.rb +29 -32
- data/test/tc_res_file.rb +26 -29
- data/test/tc_res_opt.rb +62 -65
- data/test/tc_resolver.rb +287 -242
- data/test/tc_rr-opt.rb +70 -63
- data/test/tc_rr-txt.rb +68 -71
- data/test/tc_rr-unknown.rb +45 -48
- data/test/tc_rr.rb +76 -70
- data/test/tc_rrset.rb +21 -22
- data/test/tc_rrsig.rb +19 -20
- data/test/tc_single_resolver.rb +294 -297
- data/test/tc_soak.rb +199 -202
- data/test/tc_soak_base.rb +29 -34
- data/test/tc_sshfp.rb +20 -23
- data/test/tc_tcp.rb +32 -35
- data/test/tc_tkey.rb +41 -44
- data/test/tc_tsig.rb +81 -84
- data/test/tc_update.rb +108 -111
- data/test/tc_validator.rb +29 -29
- data/test/tc_verifier.rb +81 -82
- data/test/ts_dnsruby.rb +16 -15
- data/test/ts_offline.rb +62 -63
- data/test/ts_online.rb +115 -115
- metadata +155 -90
- data/README +0 -59
- data/lib/Dnsruby/DNS.rb +0 -305
- data/lib/Dnsruby/PacketSender.rb +0 -656
- data/lib/Dnsruby/Resolver.rb +0 -1189
- data/lib/Dnsruby/TheLog.rb +0 -44
- data/lib/Dnsruby/message.rb +0 -1230
- data/lib/Dnsruby/resource/A.rb +0 -56
- data/lib/Dnsruby/resource/AAAA.rb +0 -54
- data/lib/Dnsruby/resource/DLV.rb +0 -27
- data/lib/Dnsruby/resource/NSEC.rb +0 -298
- data/lib/Dnsruby/resource/NSEC3.rb +0 -340
- data/lib/Dnsruby/resource/NSEC3PARAM.rb +0 -135
- data/lib/Dnsruby/resource/OPT.rb +0 -213
- data/lib/Dnsruby/resource/RRSIG.rb +0 -275
- data/lib/Dnsruby/resource/SPF.rb +0 -29
- data/lib/Dnsruby/resource/SRV.rb +0 -112
- data/lib/Dnsruby/resource/TKEY.rb +0 -163
- data/lib/Dnsruby/resource/TSIG.rb +0 -593
- data/lib/Dnsruby/resource/X25.rb +0 -55
- data/lib/Dnsruby/resource/resource.rb +0 -678
- data/lib/Dnsruby/update.rb +0 -278
- data/lib/Dnsruby/validator_thread.rb +0 -124
@@ -1,59 +1,59 @@
|
|
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
|
-
#
|
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
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 express or implied.
|
13
|
-
#See the License for the specific language governing permissions and
|
14
|
-
#limitations under the License.
|
15
|
-
|
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 express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
# ++
|
16
16
|
module Dnsruby
|
17
17
|
|
18
|
-
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
|
27
|
-
#
|
28
|
-
|
29
|
-
#These methods raise an exception or return a response message with rcode==NOERROR
|
30
|
-
#
|
31
|
-
|
32
|
-
|
33
|
-
#
|
34
|
-
|
35
|
-
#These methods use a response queue to return the response and the error to the client.
|
36
|
-
#Support for EventMachine has been deprecated
|
37
|
-
#
|
38
|
-
|
39
|
-
#
|
18
|
+
# == Dnsruby::SingleResolver
|
19
|
+
#
|
20
|
+
# This class has been deprecated.
|
21
|
+
# This implementation exists for legacy clients. New code should use the Dnsruby::Resolver class.
|
22
|
+
# The SingleResolver class targets a single resolver, and controls the sending of a single
|
23
|
+
# packet with a packet timeout. It performs no retries. Only two threads are used - the client
|
24
|
+
# thread and a select thread (which is reused across all queries).
|
25
|
+
#
|
26
|
+
# == Methods
|
27
|
+
#
|
28
|
+
# === Synchronous
|
29
|
+
# These methods raise an exception or return a response message with rcode==NOERROR
|
30
|
+
#
|
31
|
+
# * Dnsruby::SingleResolver#send_message(msg [, use_tcp]))
|
32
|
+
# * Dnsruby::SingleResolver#query(name [, type [, klass]])
|
33
|
+
#
|
34
|
+
# === Asynchronous
|
35
|
+
# These methods use a response queue to return the response and the error to the client.
|
36
|
+
# Support for EventMachine has been deprecated
|
37
|
+
#
|
38
|
+
# * Dnsruby::SingleResolver#send_async(...)
|
39
|
+
#
|
40
40
|
class SingleResolver < Resolver
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
41
|
+
# Can take a hash with the following optional keys :
|
42
|
+
#
|
43
|
+
# * :server
|
44
|
+
# * :port
|
45
|
+
# * :use_tcp
|
46
|
+
# * :no_tcp
|
47
|
+
# * :ignore_truncation
|
48
|
+
# * :src_address
|
49
|
+
# * :src_address6
|
50
|
+
# * :src_port
|
51
|
+
# * :udp_size
|
52
|
+
# * :persistent_tcp
|
53
|
+
# * :persistent_udp
|
54
|
+
# * :tsig
|
55
|
+
# * :packet_timeout
|
56
|
+
# * :recurse
|
57
57
|
def initialize(*args)
|
58
58
|
arg=args[0]
|
59
59
|
@single_res_mutex = Mutex.new
|
@@ -80,7 +80,7 @@ module Dnsruby
|
|
80
80
|
@config = Config.new
|
81
81
|
|
82
82
|
if (arg==nil)
|
83
|
-
#
|
83
|
+
# Get default config
|
84
84
|
@config = Config.new
|
85
85
|
@config.get_ready
|
86
86
|
@server = @config.nameserver[0]
|
@@ -89,13 +89,13 @@ module Dnsruby
|
|
89
89
|
@configured= true
|
90
90
|
@config.nameserver=[arg]
|
91
91
|
@server = @config.nameserver[0]
|
92
|
-
#
|
92
|
+
# @server=arg
|
93
93
|
elsif (arg.kind_of?Name)
|
94
94
|
@config.get_ready
|
95
95
|
@configured= true
|
96
96
|
@config.nameserver=arg
|
97
97
|
@server = @config.nameserver[0]
|
98
|
-
#
|
98
|
+
# @server=arg
|
99
99
|
elsif (arg.kind_of?Hash)
|
100
100
|
arg.keys.each do |attr|
|
101
101
|
if (attr == :server)
|
@@ -122,7 +122,7 @@ module Dnsruby
|
|
122
122
|
|
123
123
|
@single_resolvers = [isr]
|
124
124
|
|
125
|
-
#
|
125
|
+
# ResolverRegister::register_single_resolver(self)
|
126
126
|
end
|
127
127
|
|
128
128
|
def server=(s)
|
@@ -142,13 +142,13 @@ module Dnsruby
|
|
142
142
|
end
|
143
143
|
|
144
144
|
def server
|
145
|
-
#
|
145
|
+
# @single_res_mutex.synchronize {
|
146
146
|
if (!@configured)
|
147
147
|
@config.get_ready
|
148
148
|
add_config_nameservers
|
149
149
|
end
|
150
150
|
return @single_resolvers[0].server
|
151
|
-
#
|
151
|
+
# }
|
152
152
|
end
|
153
153
|
|
154
154
|
def retry_times=(n) # :nodoc:
|
@@ -163,8 +163,8 @@ module Dnsruby
|
|
163
163
|
@query_timeout = t
|
164
164
|
end
|
165
165
|
|
166
|
-
#
|
167
|
-
#
|
166
|
+
# Add the appropriate EDNS OPT RR for the specified packet. This is done
|
167
|
+
# automatically, unless you are using Resolver#send_plain_message
|
168
168
|
def add_opt_rr(m)
|
169
169
|
@single_res_mutex.synchronize {
|
170
170
|
@single_resolvers[0].add_opt_rr(m)
|
@@ -1,18 +1,18 @@
|
|
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
|
-
#
|
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
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 express or implied.
|
13
|
-
#See the License for the specific language governing permissions and
|
14
|
-
#limitations under the License.
|
15
|
-
|
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 express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
# ++
|
16
16
|
|
17
17
|
|
18
18
|
# This class does verification/validation from a single point - signed root,
|
@@ -29,29 +29,29 @@ module Dnsruby
|
|
29
29
|
def initialize(vtype)
|
30
30
|
@verifier_type = vtype
|
31
31
|
@added_dlv_key = false
|
32
|
-
#
|
32
|
+
# The DNSKEY RRs for the signed root (when it exists)
|
33
33
|
@root_anchors = KeyCache.new
|
34
34
|
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
35
|
+
# The set of trust anchors.
|
36
|
+
# If the root is unsigned, then these must be initialised with at least
|
37
|
+
# one trusted key by the client application, if verification is to be performed.
|
38
38
|
@trust_anchors = KeyCache.new
|
39
39
|
|
40
40
|
@dlv_registries = []
|
41
41
|
|
42
|
-
#
|
42
|
+
# The set of keys which are trusted.
|
43
43
|
@trusted_keys = KeyCache.new
|
44
44
|
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
45
|
+
# The set of keys which have been indicated by a DS RRSet which has been
|
46
|
+
# signed by a trusted key. Although we have not yet located these keys, we
|
47
|
+
# have the details (tag and digest) which can identify the keys when we
|
48
|
+
# see them. At that point, they will be added to our trusted keys.
|
49
49
|
@discovered_ds_store = []
|
50
|
-
#
|
51
|
-
#
|
50
|
+
# The configured_ds_store is the set of DS records which have been configured
|
51
|
+
# by the client as trust anchors. Use Dnssec#add_trust_anchor to add these
|
52
52
|
@configured_ds_store = []
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
def set_hints(hints)
|
56
56
|
@@hints = hints
|
57
57
|
end
|
@@ -69,29 +69,29 @@ module Dnsruby
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def get_dlv_resolver # :nodoc:
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
72
|
+
# if (Dnssec.do_validation_with_recursor?)
|
73
|
+
# return Recursor.new
|
74
|
+
# else
|
75
75
|
if (Dnssec.default_resolver)
|
76
76
|
return Dnssec.default_resolver
|
77
77
|
else
|
78
78
|
return Resolver.new
|
79
79
|
end
|
80
|
-
#
|
80
|
+
# end
|
81
81
|
end
|
82
82
|
def add_dlv_key(key)
|
83
|
-
#
|
84
|
-
#
|
83
|
+
# Is this a ZSK or a KSK?
|
84
|
+
# If it is a KSK, then get the ZSK from the zone
|
85
85
|
if (key.sep_key?)
|
86
86
|
get_dlv_key(key)
|
87
87
|
end
|
88
88
|
end
|
89
89
|
def get_dlv_key(ksk) # :nodoc:
|
90
|
-
#
|
90
|
+
# Using the KSK, get the ZSK for the DLV registry
|
91
91
|
if (!@res && (@verifier_type == VerifierType::DLV))
|
92
92
|
@res = get_dlv_resolver
|
93
93
|
end
|
94
|
-
#
|
94
|
+
# print "Sending query : res.dnssec = #{@res.dnssec}"
|
95
95
|
ret = nil
|
96
96
|
begin
|
97
97
|
ret = @res.query_no_validation_or_recursion("dlv.isc.org.", Types.DNSKEY)
|
@@ -99,7 +99,7 @@ module Dnsruby
|
|
99
99
|
raise ResolvError.new("Couldn't get response from Recursor")
|
100
100
|
end
|
101
101
|
rescue ResolvError => e
|
102
|
-
#
|
102
|
+
# print "ERROR - Couldn't find the DLV key\n"
|
103
103
|
TheLog.error("Couldn't find the DLV key\n")
|
104
104
|
return
|
105
105
|
end
|
@@ -107,23 +107,23 @@ module Dnsruby
|
|
107
107
|
begin
|
108
108
|
verify(key_rrset, ksk)
|
109
109
|
add_trusted_key(key_rrset)
|
110
|
-
#
|
110
|
+
# print "Successfully added DLV key\n"
|
111
111
|
TheLog.info("Successfully added DLV key")
|
112
112
|
@added_dlv_key = true
|
113
113
|
rescue VerifyError => e
|
114
|
-
#
|
114
|
+
# print "Error verifying DLV key : #{e}\n"
|
115
115
|
TheLog.error("Error verifying DLV key : #{e}")
|
116
116
|
end
|
117
117
|
end
|
118
118
|
def add_trust_anchor(t)
|
119
119
|
add_trust_anchor_with_expiration(t, Time.utc(2035,"jan",1,20,15,1).to_i)
|
120
120
|
end
|
121
|
-
#
|
121
|
+
# Add the
|
122
122
|
def add_trust_anchor_with_expiration(k, expiration)
|
123
123
|
if (k.type == Types.DNSKEY)
|
124
|
-
#
|
124
|
+
# k.flags = k.flags | RR::IN::DNSKEY::SEP_KEY
|
125
125
|
@trust_anchors.add_key_with_expiration(k, expiration)
|
126
|
-
#
|
126
|
+
# print "Adding trust anchor for #{k.name}\n"
|
127
127
|
TheLog.info("Adding trust anchor for #{k.name}")
|
128
128
|
elsif ((k.type == Types.DS) || ((k.type == Types.DLV) && (@verifier_type == VerifierType::DLV)))
|
129
129
|
@configured_ds_store.push(k)
|
@@ -133,7 +133,7 @@ module Dnsruby
|
|
133
133
|
def remove_trust_anchor(t)
|
134
134
|
@trust_anchors.delete(t)
|
135
135
|
end
|
136
|
-
#
|
136
|
+
# Wipes the cache of trusted keys
|
137
137
|
def clear_trust_anchors
|
138
138
|
@trust_anchors = KeyCache.new
|
139
139
|
end
|
@@ -142,39 +142,39 @@ module Dnsruby
|
|
142
142
|
return @trust_anchors.keys + @configured_ds_store
|
143
143
|
end
|
144
144
|
|
145
|
-
#
|
145
|
+
# Check that the RRSet and RRSIG record are compatible
|
146
146
|
def check_rr_data(rrset, sigrec)#:nodoc: all
|
147
|
-
#Each RR MUST have the same owner name as the RRSIG RR;
|
147
|
+
# Each RR MUST have the same owner name as the RRSIG RR;
|
148
148
|
if (rrset.name.canonical != sigrec.name.canonical)
|
149
149
|
raise VerifyError.new("RRSET should have same owner name as RRSIG for verification (rrsert=#{rrset.name}, sigrec=#{sigrec.name}")
|
150
150
|
end
|
151
151
|
|
152
|
-
#Each RR MUST have the same class as the RRSIG RR;
|
152
|
+
# Each RR MUST have the same class as the RRSIG RR;
|
153
153
|
if (rrset.klass != sigrec.klass)
|
154
154
|
raise VerifyError.new("RRSET should have same DNS class as RRSIG for verification")
|
155
155
|
end
|
156
156
|
|
157
|
-
#Each RR in the RRset MUST have the RR type listed in the
|
158
|
-
#RRSIG RR's Type Covered field;
|
157
|
+
# Each RR in the RRset MUST have the RR type listed in the
|
158
|
+
# RRSIG RR's Type Covered field;
|
159
159
|
if (rrset.type != sigrec.type_covered)
|
160
160
|
raise VerifyError.new("RRSET should have same type as RRSIG for verification")
|
161
161
|
end
|
162
162
|
|
163
|
-
#
|
164
|
-
#
|
165
|
-
#
|
166
|
-
#
|
167
|
-
#
|
163
|
+
# #Each RR in the RRset MUST have the TTL listed in the
|
164
|
+
# #RRSIG Original TTL Field;
|
165
|
+
# if (rrset.ttl != sigrec.original_ttl)
|
166
|
+
# raise VerifyError.new("RRSET should have same ttl as RRSIG original_ttl for verification (should be #{sigrec.original_ttl} but was #{rrset.ttl}")
|
167
|
+
# end
|
168
168
|
|
169
|
-
#
|
169
|
+
# Now check that we are in the validity period for the RRSIG
|
170
170
|
now = Time.now.to_i
|
171
171
|
if ((sigrec.expiration < now) || (sigrec.inception > now))
|
172
172
|
raise VerifyError.new("Signature record not in validity period")
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
176
|
-
#
|
177
|
-
#
|
176
|
+
# Add the specified keys to the trusted key cache.
|
177
|
+
# k can be a KeyCache, or an RRSet of DNSKEYs.
|
178
178
|
def add_trusted_key(k)
|
179
179
|
@trusted_keys.add(k)
|
180
180
|
end
|
@@ -183,7 +183,7 @@ module Dnsruby
|
|
183
183
|
@configured_ds_store.push(ds)
|
184
184
|
end
|
185
185
|
|
186
|
-
#
|
186
|
+
# Wipes the cache of trusted keys
|
187
187
|
def clear_trusted_keys
|
188
188
|
@trusted_keys = KeyCache.new
|
189
189
|
@res = nil
|
@@ -201,15 +201,15 @@ module Dnsruby
|
|
201
201
|
return @trusted_keys.keys + @configured_ds_store + discovered_ds
|
202
202
|
end
|
203
203
|
|
204
|
-
#
|
205
|
-
#
|
204
|
+
# Check that the key fits a signed DS record key details
|
205
|
+
# If so, then add the key to the trusted keys
|
206
206
|
def check_ds(key, ds_rrset)#:nodoc: all
|
207
207
|
expiration = 0
|
208
208
|
found = false
|
209
209
|
ds_rrset.sigs.each { |sig|
|
210
210
|
if ((sig.type_covered == Types.DS) || ((sig.type_covered == Types.DLV)&& (@verifier_type==VerifierType::DLV)))
|
211
211
|
if (sig.inception <= Time.now.to_i)
|
212
|
-
#
|
212
|
+
# Check sig.expiration, sig.algorithm
|
213
213
|
if (sig.expiration > expiration)
|
214
214
|
expiration = sig.expiration
|
215
215
|
end
|
@@ -229,19 +229,19 @@ module Dnsruby
|
|
229
229
|
return found
|
230
230
|
end
|
231
231
|
|
232
|
-
#
|
233
|
-
#
|
234
|
-
#
|
235
|
-
#
|
236
|
-
#
|
237
|
-
#
|
238
|
-
#
|
239
|
-
#
|
240
|
-
#
|
241
|
-
#
|
242
|
-
#
|
243
|
-
#
|
244
|
-
#
|
232
|
+
# Verify the specified message (or RRSet) using the set of trusted keys.
|
233
|
+
# If keys is a DNSKEY, or an Array or RRSet of DNSKEYs, then keys
|
234
|
+
# is added to the set of trusted keys before the message (or RRSet) is
|
235
|
+
# verified.
|
236
|
+
#
|
237
|
+
# If msg is a Dnsruby::Message, then any signed DNSKEY or DS RRSets are
|
238
|
+
# processed first, and any new keys are added to the trusted key set
|
239
|
+
# before the other RRSets are checked.
|
240
|
+
#
|
241
|
+
# msg can be a Dnsruby::Message or Dnsruby::RRSet.
|
242
|
+
# keys may be nil, or a KeyCache or an RRSet of Dnsruby::RR::DNSKEY
|
243
|
+
#
|
244
|
+
# Returns true if the message verifies OK, and false otherwise.
|
245
245
|
def verify(msg, keys = nil)
|
246
246
|
if (msg.kind_of?RRSet)
|
247
247
|
if (msg.type == Types.DNSKEY)
|
@@ -253,13 +253,13 @@ module Dnsruby
|
|
253
253
|
end
|
254
254
|
return verify_rrset(msg, keys)
|
255
255
|
end
|
256
|
-
#
|
257
|
-
#
|
258
|
-
#
|
259
|
-
#
|
256
|
+
# Use the set of trusted keys to check any RRSets we can, ideally
|
257
|
+
# those of other DNSKEY RRSets first. Then, see if we can use any of the
|
258
|
+
# new total set of keys to check the rest of the rrsets.
|
259
|
+
# Return true if we can verify the whole message.
|
260
260
|
|
261
261
|
msg.each_section do |section|
|
262
|
-
#
|
262
|
+
# print "Checking section : #{section}\n"
|
263
263
|
ds_rrsets = section.rrsets(Types.DS)
|
264
264
|
if ((!ds_rrsets || ds_rrsets.length == 0) && (@verifier_type == VerifierType::DLV))
|
265
265
|
ds_rrsets = section.rrsets(Types.DLV)
|
@@ -267,7 +267,7 @@ module Dnsruby
|
|
267
267
|
ds_rrsets.each {|ds_rrset|
|
268
268
|
if ((ds_rrset && ds_rrset.rrs.length > 0) && !verify_ds_rrset(ds_rrset, keys, msg))
|
269
269
|
raise VerifyError.new("Failed to verify DS RRSet")
|
270
|
-
#
|
270
|
+
# return false
|
271
271
|
end
|
272
272
|
}
|
273
273
|
|
@@ -275,24 +275,24 @@ module Dnsruby
|
|
275
275
|
key_rrsets.each {|key_rrset|
|
276
276
|
if ((key_rrset && key_rrset.rrs.length > 0) && !verify_key_rrset(key_rrset, keys))
|
277
277
|
raise VerifyError.new("Failed to verify DNSKEY RRSet")
|
278
|
-
#
|
278
|
+
# return false
|
279
279
|
end
|
280
280
|
}
|
281
281
|
end
|
282
282
|
|
283
283
|
verify_nsecs(msg)
|
284
284
|
|
285
|
-
#
|
285
|
+
# Then, look through all the remaining RRSets, and verify them all (unless not necessary).
|
286
286
|
msg.section_rrsets.each do |section, rrsets|
|
287
287
|
rrsets.each do |rrset|
|
288
|
-
#
|
289
|
-
#
|
288
|
+
# If delegation NS or glue AAAA/A, then don't expect RRSIG.
|
289
|
+
# Otherwise, expect RRSIG and fail verification if RRSIG is not present
|
290
290
|
|
291
291
|
if ((section == "authority") && (rrset.type == Types.NS))
|
292
|
-
#
|
292
|
+
# Check for delegation
|
293
293
|
dsrrset = msg.authority.rrsets('DS')[0]
|
294
294
|
if ((msg.answer.size == 0) && (!dsrrset) && (rrset.type == Types.NS)) # (isDelegation)
|
295
|
-
#
|
295
|
+
# Now check NSEC(3) records for absence of DS and SOA
|
296
296
|
nsec = msg.authority.rrsets('NSEC')[0]
|
297
297
|
if (!nsec || (nsec.length == 0))
|
298
298
|
nsec = msg.authority.rrsets('NSEC3')[0]
|
@@ -303,19 +303,19 @@ module Dnsruby
|
|
303
303
|
end
|
304
304
|
end
|
305
305
|
end
|
306
|
-
#
|
306
|
+
# If NS records delegate the name to the child's nameservers, then they MUST NOT be signed
|
307
307
|
if (rrset.type == Types.NS)
|
308
|
-
#
|
309
|
-
#
|
310
|
-
#
|
311
|
-
#
|
312
|
-
#
|
313
|
-
#
|
314
|
-
#
|
315
|
-
#
|
316
|
-
#
|
317
|
-
#
|
318
|
-
#
|
308
|
+
# all_delegate = true
|
309
|
+
# rrset.rrs.each {|rr|
|
310
|
+
# name = Name.create(rr.nsdname)
|
311
|
+
# name.absolute = true
|
312
|
+
# if (!(name.subdomain_of?(rr.name)))
|
313
|
+
# all_delegate = false
|
314
|
+
# end
|
315
|
+
# }
|
316
|
+
# if (all_delegate && rrset.sigs.length == 0)
|
317
|
+
# next
|
318
|
+
# end
|
319
319
|
if ((rrset.name.canonical == msg.question()[0].qname.canonical) && (rrset.sigs.length == 0))
|
320
320
|
next
|
321
321
|
end
|
@@ -323,8 +323,8 @@ module Dnsruby
|
|
323
323
|
end
|
324
324
|
|
325
325
|
if (section == "additional")
|
326
|
-
#
|
327
|
-
#
|
326
|
+
# check for glue
|
327
|
+
# if the ownername (in the addtional section) of the glue address is the same or longer as the ownername of the NS record, it is glue
|
328
328
|
if (msg.additional.size > 0)
|
329
329
|
arec = msg.additional.rrsets('A')[0]
|
330
330
|
if (!arec || arec.rrs.length == 0)
|
@@ -344,15 +344,15 @@ module Dnsruby
|
|
344
344
|
}
|
345
345
|
end
|
346
346
|
end
|
347
|
-
#
|
347
|
+
# If records are in additional, and no RRSIG, that's Ok - just don't use them!
|
348
348
|
if ((section == "additional") && (rrset.sigs.length == 0))
|
349
|
-
#
|
349
|
+
# @TODO@ Make sure that we don't cache these records!
|
350
350
|
next
|
351
351
|
end
|
352
|
-
#
|
353
|
-
#
|
352
|
+
# else verify RRSet
|
353
|
+
# print "About to verify #{rrset.name}, #{rrset.type}\n"
|
354
354
|
if (!verify_rrset(rrset, keys))
|
355
|
-
#
|
355
|
+
# print "FAILED TO VERIFY RRSET #{rrset.name}, #{rrset.type}\n"
|
356
356
|
TheLog.debug("Failed to verify rrset")
|
357
357
|
return false
|
358
358
|
end
|
@@ -362,59 +362,59 @@ module Dnsruby
|
|
362
362
|
end
|
363
363
|
|
364
364
|
def verify_nsecs(msg) # :nodoc:
|
365
|
-
#
|
366
|
-
#
|
367
|
-
#
|
368
|
-
#
|
369
|
-
#
|
370
|
-
#
|
371
|
-
#
|
372
|
-
#
|
373
|
-
#
|
374
|
-
#
|
375
|
-
#
|
376
|
-
#
|
377
|
-
#
|
378
|
-
#
|
379
|
-
#
|
380
|
-
#
|
381
|
-
#
|
382
|
-
#
|
383
|
-
#
|
384
|
-
#
|
385
|
-
#
|
386
|
-
|
387
|
-
#
|
388
|
-
#
|
389
|
-
#
|
390
|
-
#
|
391
|
-
#
|
365
|
+
# NSEC(3) handling. Get NSEC(3)s in four cases : (RFC 4035, section 3.1.3)
|
366
|
+
# a) No data - <SNAME, SCLASS> matches, but no <SNAME, SCLASS, STYPE) (§3.1.3.1)
|
367
|
+
# - will expect NSEC in Authority (and associated RRSIG)
|
368
|
+
# - NOERROR returned
|
369
|
+
# b) Name error - no RRSets that match <SNAME, SCLASS> either exactly or through wildcard expansion (§3.1.3.2)
|
370
|
+
# - NSEC wil prove i) no exact match for <SNAME, SCLASS>, and ii) no RRSets that could match through wildcard expansion
|
371
|
+
# - this may be proved in one or more NSECs (and associated RRSIGs)
|
372
|
+
# - NXDOMAIN returned - should ensure we verify!
|
373
|
+
# c) Wildcard answer - No <SNAME, SCLASS> direct matches, but matches <SNAME, SCLASS, STYPE> through wildcard expansion (§3.1.3.3)
|
374
|
+
# - Answer section must include wildcard-expanded answer (and associated RRSIGs)
|
375
|
+
# - label count in answer RRSIG indicates wildcard RRSet was expanded (less labels than in owner name)
|
376
|
+
# - Authority section must include NSEC (and RRSIGs) proving that zone does not contain a closer match
|
377
|
+
# - NOERROR returned
|
378
|
+
# d) Wildcard no data - No <SNAME, SCLASS> direct. <SNAME, SCLASS> yes but <SNAME, SCLASS, STYPE> no through wildcard expansion (§3.1.3.4)
|
379
|
+
# - Authority section contains NSECs (and RRSIGs) for :
|
380
|
+
# i) NSEC proving no RRSets matching STYPE at wildcard owner name that matched <SNAME, SCLASS> via wildcard expansion
|
381
|
+
# ii) NSEC proving no RRSets in zone that would have been closer match for <SNAME, SCLASS>
|
382
|
+
# - this may be proved by one or more NSECs (and associated RRSIGs)
|
383
|
+
# - NOERROR returned
|
384
|
+
#
|
385
|
+
# Otherwise no NSECs should be returned.
|
386
|
+
|
387
|
+
# So, check for NSEC records in response, and work out what type of answer we have.
|
388
|
+
# Then, if NSECs are present, make sure that we prove what they said they would.
|
389
|
+
# What if the message *should* have no NSEC records? That can only be known by the validator.
|
390
|
+
# We will assume that the validator has checked the (non)-existence of NSEC records - we should not
|
391
|
+
# get upset if there aren't any. However, if there are, then we should verify that they say the right thing
|
392
392
|
qtype = msg.question()[0].qtype
|
393
393
|
return if (msg.rcode == RCode.NOERROR && ((qtype == Types.ANY) || (qtype == Types.NSEC) || (qtype == Types.NSEC3)))
|
394
394
|
if ((msg.rrsets('NSEC').length > 0) || (msg.rrsets('NSEC3').length > 0))
|
395
395
|
if (msg.rcode == RCode.NXDOMAIN)
|
396
|
-
#
|
397
|
-
#Name error - NSEC wil prove i) no exact match for <SNAME, SCLASS>, and ii) no RRSets that could match through wildcard expansion
|
398
|
-
#
|
396
|
+
# print "Checking NSECs for Name Error\n"
|
397
|
+
# Name error - NSEC wil prove i) no exact match for <SNAME, SCLASS>, and ii) no RRSets that could match through wildcard expansion
|
398
|
+
# - this may be proved in one or more NSECs (and associated RRSIGs)
|
399
399
|
check_name_in_nsecs(msg)
|
400
400
|
return check_no_wildcard_expansion(msg)
|
401
401
|
elsif (msg.rcode == RCode.NOERROR)
|
402
402
|
if (msg.answer.length > 0)
|
403
|
-
#
|
404
|
-
#
|
405
|
-
#
|
406
|
-
#
|
403
|
+
# print "Checking NSECs for wildcard expansion\n"
|
404
|
+
# wildcard expansion answer - check NSECs!
|
405
|
+
# We want to make sure that the NSEC tells us that there is no closer match for this name
|
406
|
+
# @TODO@ We need to make replace the RRSIG name with the wildcard name before we can verify it correctly.
|
407
407
|
check_num_rrsig_labels(msg)
|
408
408
|
return check_name_in_nsecs(msg, msg.question()[0].qtype, true)
|
409
409
|
else
|
410
|
-
#
|
411
|
-
#
|
412
|
-
#
|
410
|
+
# Either no data or wildcard no data - check to see which
|
411
|
+
# Should be able to tell this by checking the number of labels in the NSEC records.
|
412
|
+
# Sort these two last cases out!
|
413
413
|
isWildcardNoData = false
|
414
414
|
[msg.authority.rrsets('NSEC'), msg.authority.rrsets('NSEC3')].each {|nsec_rrsets|
|
415
415
|
nsec_rrsets.each {|nsec_rrset|
|
416
416
|
nsec_rrset.rrs.each {|nsec|
|
417
|
-
#
|
417
|
+
# print "Checking nsec to see if wildcard : #{nsec}\n"
|
418
418
|
if (nsec.name.wild? ||(nsec.name.labels.length < msg.question()[0].qname.labels.length))
|
419
419
|
isWildcardNoData = true
|
420
420
|
end
|
@@ -423,28 +423,28 @@ module Dnsruby
|
|
423
423
|
}
|
424
424
|
|
425
425
|
if (isWildcardNoData)
|
426
|
-
#
|
427
|
-
#
|
428
|
-
#
|
426
|
+
# print "Checking NSECs for wildcard no data\n"
|
427
|
+
# Check NSECs -
|
428
|
+
# i) NSEC proving no RRSets matching STYPE at wildcard owner name that matched <SNAME, SCLASS> via wildcard expansion
|
429
429
|
check_name_not_in_wildcard_nsecs(msg)
|
430
|
-
#
|
430
|
+
# ii) NSEC proving no RRSets in zone that would have been closer match for <SNAME, SCLASS>
|
431
431
|
return check_name_in_and_type_not_in_nsecs(msg)
|
432
432
|
else # (isNoData)
|
433
|
-
#
|
434
|
-
#
|
433
|
+
# print "Checking NSECs for No data\n"
|
434
|
+
# Check NSEC types covered to make sure this type not present.
|
435
435
|
return check_name_in_and_type_not_in_nsecs(msg)
|
436
436
|
end
|
437
437
|
end
|
438
438
|
else
|
439
|
-
#
|
439
|
+
# Anything we should do here?
|
440
440
|
end
|
441
441
|
end
|
442
442
|
|
443
443
|
end
|
444
444
|
|
445
445
|
def check_num_rrsig_labels(msg) # :nodoc:
|
446
|
-
#
|
447
|
-
#
|
446
|
+
# Check that the number of labels in the RRSIG is less than the number
|
447
|
+
# of labels in the answer name
|
448
448
|
answer_rrset = msg.answer.rrset(msg.question()[0].qname, msg.question()[0].qtype)
|
449
449
|
if (answer_rrset.length == 0)
|
450
450
|
raise VerifyError.new("Expected wildcard expanded answer for #{msg.question()[0].qname}")
|
@@ -456,13 +456,13 @@ module Dnsruby
|
|
456
456
|
end
|
457
457
|
|
458
458
|
def check_no_wildcard_expansion(msg) # :nodoc:
|
459
|
-
#
|
459
|
+
# @TODO@ Do this for NSEC3 records!!!
|
460
460
|
proven_no_wildcards = false
|
461
461
|
name = msg.question()[0].qname
|
462
462
|
[msg.authority.rrsets('NSEC'), msg.authority.rrsets('NSEC3')].each {|nsec_rrsets|
|
463
463
|
nsec_rrsets.each {|nsecs|
|
464
464
|
nsecs.rrs.each {|nsec|
|
465
|
-
#
|
465
|
+
# print "Checking NSEC : #{nsec}\n"
|
466
466
|
next if (nsec.name.wild?)
|
467
467
|
if (check_record_proves_no_wildcard(msg, nsec))
|
468
468
|
proven_no_wildcards = true
|
@@ -471,20 +471,20 @@ module Dnsruby
|
|
471
471
|
}
|
472
472
|
}
|
473
473
|
if (!proven_no_wildcards)
|
474
|
-
#
|
474
|
+
# print "No proof that no RRSets could match through wildcard expansion\n"
|
475
475
|
raise VerifyError.new("No proof that no RRSets could match through wildcard expansion")
|
476
476
|
end
|
477
477
|
|
478
478
|
end
|
479
|
-
|
479
|
+
|
480
480
|
def check_record_proves_no_wildcard(msg, nsec) # :nodoc:
|
481
|
-
#
|
482
|
-
#
|
481
|
+
# Check that the NSEC goes from the SOA to a zone canonically after a wildcard
|
482
|
+
# print "Checking wildcard proof for #{nsec.name}\n"
|
483
483
|
soa_rrset = msg.authority.rrset(nsec.name, 'SOA')
|
484
484
|
if (soa_rrset.length > 0)
|
485
|
-
#
|
485
|
+
# print "Found SOA for #{nsec.name}\n"
|
486
486
|
wildcard_name = Name.create("*." + nsec.name.to_s)
|
487
|
-
#
|
487
|
+
# print "Checking #{wildcard_name}\n"
|
488
488
|
if (wildcard_name.canonically_before(nsec.next_domain))
|
489
489
|
return true
|
490
490
|
end
|
@@ -493,16 +493,16 @@ module Dnsruby
|
|
493
493
|
end
|
494
494
|
|
495
495
|
def check_name_in_nsecs(msg, qtype=nil, expected_qtype = false) # :nodoc:
|
496
|
-
#
|
497
|
-
#
|
498
|
-
#
|
496
|
+
# Check these NSECs to make sure that this name cannot be in the zone
|
497
|
+
# and that no RRSets could match through wildcard expansion
|
498
|
+
# @TODO@ Get this right for NSEC3 too!
|
499
499
|
name = msg.question()[0].qname
|
500
500
|
proven_name_in_nsecs = false
|
501
501
|
type_covered_checked = false
|
502
502
|
[msg.authority.rrsets('NSEC'), msg.authority.rrsets('NSEC3')].each {|nsec_rrsets|
|
503
503
|
nsec_rrsets.each {|nsecs|
|
504
504
|
nsecs.rrs.each {|nsec|
|
505
|
-
#
|
505
|
+
# print "Checking NSEC : #{nsec}\n"
|
506
506
|
next if (nsec.name.wild?)
|
507
507
|
if nsec.check_name_in_range(name)
|
508
508
|
proven_name_in_nsecs = true
|
@@ -512,9 +512,9 @@ module Dnsruby
|
|
512
512
|
qtype_present = true
|
513
513
|
end
|
514
514
|
if (qtype_present != expected_qtype)
|
515
|
-
#
|
515
|
+
# print "#{nsec.type} record #{nsec} does #{expected_qtype ? 'not ' : ''} include #{qtype} type\n"
|
516
516
|
raise VerifyError.new("#{nsec.type} record #{nsec} does #{expected_qtype ? 'not ' : ''}include #{qtype} type")
|
517
|
-
#
|
517
|
+
# return false
|
518
518
|
end
|
519
519
|
type_covered_checked = true
|
520
520
|
end
|
@@ -523,11 +523,11 @@ module Dnsruby
|
|
523
523
|
}
|
524
524
|
}
|
525
525
|
if (!proven_name_in_nsecs)
|
526
|
-
#
|
526
|
+
# print "No proof for non-existence for #{name}\n"
|
527
527
|
raise VerifyError.new("No proof for non-existence for #{name}")
|
528
528
|
end
|
529
529
|
if (qtype && !type_covered_checked)
|
530
|
-
#
|
530
|
+
# print "Tyes covered wrong for #{name}\n"
|
531
531
|
raise VerifyError.new("Types covered wrong for #{name}")
|
532
532
|
end
|
533
533
|
end
|
@@ -537,45 +537,45 @@ module Dnsruby
|
|
537
537
|
end
|
538
538
|
|
539
539
|
def check_name_not_in_wildcard_nsecs(msg) # :nodoc:
|
540
|
-
#
|
540
|
+
# @TODO@ Do this for NSEC3 records too!
|
541
541
|
name = msg.question()[0].qname
|
542
542
|
qtype = msg.question()[0].qtype
|
543
543
|
done= false
|
544
544
|
[msg.authority.rrsets('NSEC'), msg.authority.rrsets('NSEC3')].each {|nsec_rrsets|
|
545
545
|
nsec_rrsets.each {|nsecs|
|
546
546
|
nsecs.rrs.each {|nsec|
|
547
|
-
#
|
547
|
+
# print "Checking NSEC : #{nsec}\n"
|
548
548
|
next if !nsec.name.wild?
|
549
|
-
#
|
550
|
-
#
|
551
|
-
#
|
549
|
+
# Check the wildcard expansion
|
550
|
+
# We want to see that the name is in the wildcard range, and that the type
|
551
|
+
# is not in the types for the NSEC
|
552
552
|
if nsec.check_name_in_wildcard_range(name)
|
553
|
-
#
|
553
|
+
# print "Wildcard expansion in #{nsec} includes #{name}\n"
|
554
554
|
raise VerifyError.new("Wildcard expansion in #{nsec} includes #{name}")
|
555
|
-
#
|
555
|
+
# return false
|
556
556
|
end
|
557
557
|
if (nsec.types.include?qtype)
|
558
|
-
#
|
558
|
+
# print "#{qtype} present in wildcard #{nsec}\n"
|
559
559
|
raise VerifyError.new("#{qtype} present in wildcard #{nsec}")
|
560
|
-
#
|
560
|
+
# return false
|
561
561
|
end
|
562
562
|
done = true
|
563
563
|
}
|
564
564
|
}
|
565
565
|
}
|
566
566
|
return if done
|
567
|
-
#
|
567
|
+
# print("Expected wildcard expansion in #{msg}\n")
|
568
568
|
raise VerifyError.new("Expected wildcard expansion in #{msg}")
|
569
|
-
#
|
569
|
+
# return false
|
570
570
|
end
|
571
571
|
|
572
572
|
def verify_ds_rrset(ds_rrset, keys = nil, msg = nil) # :nodoc:
|
573
|
-
#
|
573
|
+
# print "verify_ds_rrset #{ds_rrset}\n"
|
574
574
|
if (ds_rrset && ds_rrset.num_sigs > 0)
|
575
575
|
if (verify_rrset(ds_rrset, keys))
|
576
|
-
#
|
577
|
-
#
|
578
|
-
#
|
576
|
+
# Need to handle DS RRSets (with RRSIGs) not just DS records.
|
577
|
+
# ds_rrset.rrs.each do |ds|
|
578
|
+
# Work out which key this refers to, and add it to the trusted key store
|
579
579
|
found = false
|
580
580
|
if (msg)
|
581
581
|
msg.each_section do |section|
|
@@ -593,16 +593,16 @@ module Dnsruby
|
|
593
593
|
found = true
|
594
594
|
end
|
595
595
|
}
|
596
|
-
#
|
597
|
-
#
|
598
|
-
#
|
599
|
-
#
|
600
|
-
#
|
601
|
-
#
|
596
|
+
# If we couldn't find the trusted key, then we should store the
|
597
|
+
# key tag and digest in a @@discovered_ds_store.
|
598
|
+
# Each time we see a new key (which has been signed) then we should
|
599
|
+
# check if it is sitting on the discovered_ds_store.
|
600
|
+
# If it is, then we should add it to the trusted_keys and remove the
|
601
|
+
# DS from the discovered_ds_store
|
602
602
|
if (!found)
|
603
603
|
@discovered_ds_store.push(ds_rrset)
|
604
604
|
end
|
605
|
-
#
|
605
|
+
# end
|
606
606
|
return true
|
607
607
|
else
|
608
608
|
return false
|
@@ -612,14 +612,14 @@ module Dnsruby
|
|
612
612
|
end
|
613
613
|
|
614
614
|
def verify_key_rrset(key_rrset, keys = nil) # :nodoc:
|
615
|
-
#
|
615
|
+
# print "verify_key_rrset\n"
|
616
616
|
verified = false
|
617
617
|
if (key_rrset && key_rrset.num_sigs > 0)
|
618
618
|
if (verify_rrset(key_rrset, keys))
|
619
|
-
#
|
620
|
-
#
|
621
|
-
#
|
622
|
-
#
|
619
|
+
# key_rrset.rrs.each do |rr|
|
620
|
+
# print "Adding keys : "
|
621
|
+
# key_rrset.rrs.each {|rr| print "#{rr.key_tag}, "}
|
622
|
+
# print "\n"
|
623
623
|
@trusted_keys.add(key_rrset) # rr)
|
624
624
|
verified = true
|
625
625
|
end
|
@@ -629,7 +629,7 @@ module Dnsruby
|
|
629
629
|
end
|
630
630
|
|
631
631
|
def check_ds_stores(key_rrset) # :nodoc:
|
632
|
-
#
|
632
|
+
# See if the keys match any of the to_be_trusted_keys
|
633
633
|
key_rrset.rrs.each do |key|
|
634
634
|
@configured_ds_store.each do |ds|
|
635
635
|
if (ds.check_key(key))
|
@@ -637,8 +637,8 @@ module Dnsruby
|
|
637
637
|
end
|
638
638
|
end
|
639
639
|
@discovered_ds_store.each do |tbtk|
|
640
|
-
#
|
641
|
-
#
|
640
|
+
# Check that the RRSet is still valid!!
|
641
|
+
# Should we get it out of the main cache?
|
642
642
|
if ((tbtk.sigs()[0].expiration < Time.now.to_i))
|
643
643
|
@discovered_ds_store.delete(tbtk)
|
644
644
|
else
|
@@ -650,7 +650,7 @@ module Dnsruby
|
|
650
650
|
}
|
651
651
|
end
|
652
652
|
end
|
653
|
-
#
|
653
|
+
# end
|
654
654
|
end
|
655
655
|
|
656
656
|
end
|
@@ -660,9 +660,9 @@ module Dnsruby
|
|
660
660
|
return keys_to_check
|
661
661
|
end
|
662
662
|
|
663
|
-
#
|
663
|
+
# Find the first matching DNSKEY and RRSIG record in the two sets.
|
664
664
|
def get_matching_key(keys, sigrecs)#:nodoc: all
|
665
|
-
#
|
665
|
+
# There can be multiple signatures in the RRSet - which one should we choose?
|
666
666
|
if ((keys == nil) || (sigrecs == nil))
|
667
667
|
return nil, nil
|
668
668
|
end
|
@@ -690,12 +690,12 @@ module Dnsruby
|
|
690
690
|
return nil, nil
|
691
691
|
end
|
692
692
|
|
693
|
-
#
|
694
|
-
#
|
695
|
-
#
|
696
|
-
#
|
693
|
+
# Verify the signature of an rrset encoded with the specified KeyCache
|
694
|
+
# or RRSet. If no signature is included, false is returned.
|
695
|
+
#
|
696
|
+
# Returns true if the RRSet verified, false otherwise.
|
697
697
|
def verify_rrset(rrset, keys = nil)
|
698
|
-
#
|
698
|
+
# print "Verify_rrset #{rrset.name}, #{rrset.type}\n"
|
699
699
|
# print "ABOUT TO VERIFY WITH #{keys == nil ? '0' : keys.length} keys\n"
|
700
700
|
# if (keys != nil)
|
701
701
|
# if (keys.length > 0)
|
@@ -736,32 +736,32 @@ module Dnsruby
|
|
736
736
|
keyrec, sigrec = get_matching_key(keys, sigrecs)
|
737
737
|
end
|
738
738
|
|
739
|
-
#
|
739
|
+
# return false if !keyrec
|
740
740
|
if (!keyrec)
|
741
|
-
#
|
741
|
+
# print "Couldn't find signing key! #{rrset.name}, #{rrset.type},\n "
|
742
742
|
raise VerifyError.new("Signing key not found")
|
743
743
|
end
|
744
744
|
|
745
|
-
#
|
746
|
-
#3.1.8.1. Signature Calculation
|
745
|
+
# RFC 4034
|
746
|
+
# 3.1.8.1. Signature Calculation
|
747
747
|
|
748
748
|
if (keyrec.sep_key? && !keyrec.zone_key?)
|
749
749
|
Dnsruby.log.error("DNSKEY with SEP flag set and Zone Key flag not set was used to verify RRSIG over RRSET - this is not allowed by RFC4034 section 2.1.1")
|
750
|
-
#
|
750
|
+
# return false
|
751
751
|
raise VerifyError.new("DNSKEY with SEP flag set and Zone Key flag not set")
|
752
752
|
end
|
753
753
|
|
754
754
|
|
755
755
|
# print "VERIFY KEY FOUND - doing verification\n"
|
756
756
|
|
757
|
-
#Any DNS names in the RDATA field of each RR MUST be in
|
758
|
-
#canonical form; and
|
759
|
-
#The RRset MUST be sorted in canonical order.
|
757
|
+
# Any DNS names in the RDATA field of each RR MUST be in
|
758
|
+
# canonical form; and
|
759
|
+
# The RRset MUST be sorted in canonical order.
|
760
760
|
rrset = rrset.sort_canonical
|
761
761
|
|
762
762
|
sig_data = sigrec.sig_data
|
763
763
|
|
764
|
-
#RR(i) = owner | type | class | TTL | RDATA length | RDATA
|
764
|
+
# RR(i) = owner | type | class | TTL | RDATA length | RDATA
|
765
765
|
rrset.each do |rec|
|
766
766
|
old_ttl = rec.ttl
|
767
767
|
rec.ttl = sigrec.original_ttl
|
@@ -775,7 +775,7 @@ module Dnsruby
|
|
775
775
|
sig_data += data
|
776
776
|
end
|
777
777
|
|
778
|
-
#
|
778
|
+
# Now calculate the signature
|
779
779
|
verified = false
|
780
780
|
if [Algorithms.RSASHA1,
|
781
781
|
Algorithms.RSASHA1_NSEC3_SHA1].include?(sigrec.algorithm)
|
@@ -786,9 +786,9 @@ module Dnsruby
|
|
786
786
|
verified = keyrec.public_key.verify(OpenSSL::Digest::SHA512.new, sigrec.signature, sig_data)
|
787
787
|
elsif [Algorithms.DSA,
|
788
788
|
Algorithms.DSA_NSEC3_SHA1].include?(sigrec.algorithm)
|
789
|
-
#
|
790
|
-
#
|
791
|
-
#
|
789
|
+
# we are ignoring T for now
|
790
|
+
# t = sigrec.signature[0]
|
791
|
+
# t = t.getbyte(0) if t.class == String
|
792
792
|
r = RR::get_num(sigrec.signature[1, 20])
|
793
793
|
s = RR::get_num(sigrec.signature[21, 20])
|
794
794
|
r_asn1 = OpenSSL::ASN1::Integer.new(r)
|
@@ -803,39 +803,39 @@ module Dnsruby
|
|
803
803
|
if (!verified)
|
804
804
|
raise VerifyError.new("Signature failed to cryptographically verify")
|
805
805
|
end
|
806
|
-
#
|
806
|
+
# Sort out the TTLs - set it to the minimum valid ttl
|
807
807
|
expiration_diff = (sigrec.expiration.to_i - Time.now.to_i).abs
|
808
808
|
rrset.ttl = ([rrset.ttl, sigrec.ttl, sigrec.original_ttl,
|
809
809
|
expiration_diff].sort)[0]
|
810
|
-
#
|
810
|
+
# print "VERIFIED OK\n"
|
811
811
|
return true
|
812
812
|
end
|
813
813
|
|
814
814
|
def find_closest_dlv_anchor_for(name) # :nodoc:
|
815
|
-
#
|
816
|
-
#
|
815
|
+
# To find the closest anchor, query DLV.isc.org for [a.b.c.d], then [a.b.c], [a.b], etc.
|
816
|
+
# once closest anchor found, simply run follow_chain from that anchor
|
817
|
+
|
818
|
+
# @TODO@ REALLY NEED AGGRESSIVE NEGATIVE CACHING HERE!!
|
819
|
+
# i.e. don't look up zones which we *know* we don't have a DLV anchor for
|
817
820
|
|
818
|
-
# @TODO@ REALLY NEED AGGRESSIVE NEGATIVE CACHING HERE!!
|
819
|
-
# i.e. don't look up zones which we *know* we don't have a DLV anchor for
|
820
|
-
|
821
821
|
n = Name.create(name)
|
822
822
|
root = Name.create(".")
|
823
823
|
while (n != root)
|
824
|
-
#
|
824
|
+
# Try to find name in DLV, and return it if possible
|
825
825
|
dlv_rrset = query_dlv_for(n)
|
826
826
|
if (dlv_rrset)
|
827
827
|
key_rrset = get_zone_key_from_dlv_rrset(dlv_rrset, n)
|
828
828
|
return key_rrset
|
829
829
|
end
|
830
|
-
#
|
830
|
+
# strip the name
|
831
831
|
n = n.strip_label
|
832
832
|
end
|
833
833
|
return false
|
834
834
|
end
|
835
835
|
|
836
836
|
def get_zone_key_from_dlv_rrset(dlv_rrset, name) # :nodoc:
|
837
|
-
#
|
838
|
-
#
|
837
|
+
# We want to return the key for the zone i.e. DS/DNSKEY for .se, NOT DLV for se.dlv.isc.org
|
838
|
+
# So, we have the DLv record. Now use it to add the zone's DNSKEYs to the trusted key set.
|
839
839
|
res = get_nameservers_for(name)
|
840
840
|
if (!res)
|
841
841
|
if (Dnssec.do_validation_with_recursor?)
|
@@ -848,51 +848,51 @@ module Dnsruby
|
|
848
848
|
end
|
849
849
|
end
|
850
850
|
end
|
851
|
-
#
|
852
|
-
#
|
851
|
+
# query = Message.new(name, Types.DNSKEY)
|
852
|
+
# query.do_validation = false
|
853
853
|
ret = nil
|
854
854
|
begin
|
855
|
-
#
|
855
|
+
# ret = res.send_message(query)
|
856
856
|
ret = res.query_no_validation_or_recursion(name, Types.DNSKEY)
|
857
857
|
if (!ret)
|
858
858
|
raise ResolvError.new("Couldn't get DNSKEY from Recursor")
|
859
859
|
end
|
860
860
|
rescue ResolvError => e
|
861
|
-
#
|
861
|
+
# print "Error getting zone key from DLV RR for #{name} : #{e}\n"
|
862
862
|
TheLog.error("Error getting zone key from DLV RR for #{name} : #{e}")
|
863
863
|
return false
|
864
864
|
end
|
865
865
|
key_rrset = ret.answer.rrset(name, Types.DNSKEY)
|
866
866
|
begin
|
867
867
|
verify(key_rrset, dlv_rrset)
|
868
|
-
#
|
868
|
+
# Cache.add(ret)
|
869
869
|
return key_rrset
|
870
870
|
rescue VerifyError => e
|
871
|
-
#
|
871
|
+
# print "Can't move from DLV RR to zone DNSKEY for #{name}, error : #{e}\n"
|
872
872
|
TheLog.debug("Can't move from DLV RR to zone DNSKEY for #{name}, error : #{e}")
|
873
873
|
end
|
874
874
|
return false
|
875
875
|
end
|
876
876
|
|
877
877
|
def query_dlv_for(name) # :nodoc:
|
878
|
-
#
|
878
|
+
# See if there is a record for name in dlv.isc.org
|
879
879
|
if (!@res && (@verifier_type == VerifierType::DLV))
|
880
880
|
@res = get_dlv_resolver
|
881
881
|
end
|
882
882
|
begin
|
883
883
|
name_to_query = name.to_s+".dlv.isc.org"
|
884
|
-
#
|
885
|
-
#
|
886
|
-
#
|
884
|
+
# query = Message.new(name_to_query, Types.DLV)
|
885
|
+
# @res.single_resolvers()[0].prepare_for_dnssec(query)
|
886
|
+
# query.do_validation = false
|
887
887
|
ret = nil
|
888
888
|
begin
|
889
|
-
#
|
889
|
+
# ret = @res.send_message(query)
|
890
890
|
ret = @res.query_no_validation_or_recursion(name_to_query, Types.DLV)
|
891
891
|
if (!ret)
|
892
892
|
raise ResolvError.new("Couldn't get DLV record from Recursor")
|
893
893
|
end
|
894
894
|
rescue ResolvError => e
|
895
|
-
#
|
895
|
+
# print "Error getting DLV record for #{name} : #{e}\n"
|
896
896
|
TheLog.info("Error getting DLV record for #{name} : #{e}")
|
897
897
|
return nil
|
898
898
|
end
|
@@ -900,96 +900,96 @@ module Dnsruby
|
|
900
900
|
if (dlv_rrset.rrs.length > 0)
|
901
901
|
begin
|
902
902
|
verify(dlv_rrset)
|
903
|
-
#
|
903
|
+
# Cache.add(ret)
|
904
904
|
return dlv_rrset
|
905
905
|
rescue VerifyError => e
|
906
|
-
#
|
906
|
+
# print "Error verifying DLV records for #{name}, #{e}\n"
|
907
907
|
TheLog.info("Error verifying DLV records for #{name}, #{e}")
|
908
908
|
end
|
909
909
|
end
|
910
910
|
rescue NXDomain
|
911
|
-
#
|
911
|
+
# print "NXDomain for DLV lookup for #{name}\n"
|
912
912
|
return nil
|
913
913
|
end
|
914
914
|
return nil
|
915
915
|
end
|
916
916
|
|
917
917
|
def find_closest_anchor_for(name) # :nodoc:
|
918
|
-
#
|
919
|
-
#
|
920
|
-
#
|
918
|
+
# Check if we have an anchor for name.
|
919
|
+
# If not, strip off first label and try again
|
920
|
+
# If we get to root, then return false
|
921
921
|
name = "." if name == ""
|
922
922
|
n = Name.create(name)
|
923
923
|
root = Name.create(".")
|
924
924
|
while (true) # n != root)
|
925
|
-
#
|
925
|
+
# Try the trusted keys first, then the DS set
|
926
926
|
(@trust_anchors.keys + @trusted_keys.keys + @configured_ds_store + @discovered_ds_store).each {|key|
|
927
927
|
return key if key.name.canonical == n.canonical
|
928
928
|
}
|
929
929
|
break if (n.to_s == root.to_s)
|
930
|
-
#
|
930
|
+
# strip the name
|
931
931
|
n = n.strip_label
|
932
932
|
end
|
933
933
|
return false
|
934
934
|
end
|
935
935
|
|
936
|
-
#
|
937
|
-
#
|
938
|
-
#
|
939
|
-
#
|
936
|
+
# @TODO@ Handle REVOKED keys! (RFC 5011)
|
937
|
+
# Remember that revoked keys will have a different key_tag than pre-revoked.
|
938
|
+
# So, if we see a revoked key, we should go through our key store for
|
939
|
+
# that authority and remove any keys with the pre-revoked key_tag.
|
940
940
|
|
941
941
|
def follow_chain(anchor, name) # :nodoc:
|
942
|
-
#
|
943
|
-
#
|
944
|
-
#
|
945
|
-
#
|
946
|
-
#
|
947
|
-
#
|
942
|
+
# Follow the chain from the anchor to name, returning the appropriate
|
943
|
+
# key at the end, or false.
|
944
|
+
#
|
945
|
+
# i.e. anchor = se, name = foo.example.se
|
946
|
+
# get anchor for example.se with se anchor
|
947
|
+
# get anchor for foo.example.se with example.se anchor
|
948
948
|
next_key = anchor
|
949
949
|
next_step = anchor.name
|
950
950
|
parent = next_step
|
951
|
-
#
|
951
|
+
# print "Follow chain from #{anchor.name} to #{name}\n"
|
952
952
|
TheLog.debug("Follow chain from #{anchor.name} to #{name}")
|
953
953
|
|
954
|
-
#
|
954
|
+
# res = nil
|
955
955
|
res = Dnssec.default_resolver
|
956
|
-
#
|
956
|
+
# while ((next_step != name) || (next_key.type != Types.DNSKEY))
|
957
957
|
while (true)
|
958
|
-
#
|
958
|
+
# print "In loop for parent=#{parent}, next step = #{next_step}\n"
|
959
959
|
dont_move_on = false
|
960
960
|
if (next_key.type != Types.DNSKEY)
|
961
961
|
dont_move_on = true
|
962
962
|
end
|
963
963
|
next_key, res = get_anchor_for(next_step, parent, next_key, res)
|
964
964
|
if (next_step.canonical.to_s == name.canonical.to_s)
|
965
|
-
#
|
965
|
+
# print "Returning #{next_key.type} for #{next_step}, #{(next_key.type != Types.DNSKEY)}\n"
|
966
966
|
return next_key
|
967
967
|
end
|
968
968
|
return false if (!next_key)
|
969
|
-
#
|
969
|
+
# Add the next label on
|
970
970
|
if (!dont_move_on)
|
971
971
|
parent = next_step
|
972
972
|
next_step = Name.new(name.labels[name.labels.length-1-next_step.labels.length,1] +
|
973
973
|
next_step.labels , name.absolute?)
|
974
|
-
#
|
974
|
+
# print "Next parent = #{parent}, next_step = #{next_step}, next_key.type = #{next_key.type.string}\n"
|
975
975
|
end
|
976
976
|
end
|
977
977
|
|
978
|
-
#
|
978
|
+
# print "Returning #{next_key.type} for #{next_step}, #{(next_key.type != Types.DNSKEY)}\n"
|
979
979
|
|
980
980
|
return next_key
|
981
981
|
end
|
982
982
|
|
983
983
|
def get_anchor_for(child, parent, current_anchor, parent_res = nil) # :nodoc:
|
984
|
-
#
|
984
|
+
# print "Trying to discover anchor for #{child} from #{parent}\n"
|
985
985
|
TheLog.debug("Trying to discover anchor for #{child} from #{parent} using #{current_anchor}, #{parent_res}")
|
986
|
-
#
|
987
|
-
#
|
988
|
-
#
|
989
|
-
#
|
990
|
-
#
|
986
|
+
# We wish to return a DNSKEY which the caller can use to verify name
|
987
|
+
# We are either given a key or a ds record from the parent zone
|
988
|
+
# If given a DNSKEY, then find a DS record signed by that key for the child zone
|
989
|
+
# Use the DS record to find a valid key in the child zone
|
990
|
+
# Return it
|
991
991
|
|
992
|
-
#
|
992
|
+
# Find NS RRSet for parent
|
993
993
|
child_res = nil
|
994
994
|
if (Dnssec.do_validation_with_recursor?)
|
995
995
|
parent_res = get_recursor
|
@@ -998,7 +998,7 @@ module Dnsruby
|
|
998
998
|
begin
|
999
999
|
if (child!=parent)
|
1000
1000
|
if (!parent_res)
|
1001
|
-
#
|
1001
|
+
# print "No res passed - try to get nameservers for #{parent}\n"
|
1002
1002
|
parent_res = get_nameservers_for(parent)
|
1003
1003
|
if (!parent_res)
|
1004
1004
|
if (Dnssec.do_validation_with_recursor?)
|
@@ -1012,10 +1012,10 @@ module Dnsruby
|
|
1012
1012
|
end
|
1013
1013
|
end
|
1014
1014
|
end
|
1015
|
-
#
|
1015
|
+
# Use that Resolver to query for DS record and NS for children
|
1016
1016
|
ds_rrset = current_anchor
|
1017
1017
|
if (current_anchor.type == Types.DNSKEY)
|
1018
|
-
#
|
1018
|
+
# print "Trying to find DS records for #{child} from servers for #{parent}\n"
|
1019
1019
|
TheLog.debug("Trying to find DS records for #{child} from servers for #{parent}")
|
1020
1020
|
ds_ret = nil
|
1021
1021
|
begin
|
@@ -1024,32 +1024,32 @@ module Dnsruby
|
|
1024
1024
|
raise ResolvError.new("Couldn't get DS records from Recursor")
|
1025
1025
|
end
|
1026
1026
|
rescue ResolvError => e
|
1027
|
-
#
|
1027
|
+
# print "Error getting DS record for #{child} : #{e}\n"
|
1028
1028
|
TheLog.error("Error getting DS record for #{child} : #{e}")
|
1029
1029
|
return false, nil
|
1030
1030
|
end
|
1031
1031
|
ds_rrset = ds_ret.answer.rrset(child, Types.DS)
|
1032
1032
|
if (ds_rrset.rrs.length == 0)
|
1033
|
-
#
|
1034
|
-
#
|
1035
|
-
#
|
1033
|
+
# @TODO@ Check NSEC(3) records - still need to verify there are REALLY no ds records!
|
1034
|
+
# print "NO DS RECORDS RETURNED FOR #{parent}\n"
|
1035
|
+
# child_res = parent_res
|
1036
1036
|
else
|
1037
1037
|
begin
|
1038
1038
|
if (verify(ds_rrset, current_anchor) || verify(ds_rrset))
|
1039
|
-
#
|
1039
|
+
# Try to make the resolver from the authority/additional NS RRSets in DS response
|
1040
1040
|
if (!Dnssec.do_validation_with_recursor?)
|
1041
1041
|
child_res = get_nameservers_from_message(child, ds_ret)
|
1042
1042
|
end
|
1043
1043
|
end
|
1044
1044
|
rescue VerifyError => e
|
1045
|
-
#
|
1045
|
+
# print "FAILED TO VERIFY DS RRSET FOR #{child}\n"
|
1046
1046
|
TheLog.info("FAILED TO VERIFY DS RRSET FOR #{child}")
|
1047
1047
|
return false, nil
|
1048
1048
|
end
|
1049
1049
|
end
|
1050
1050
|
end
|
1051
1051
|
end
|
1052
|
-
#
|
1052
|
+
# Make Resolver using all child NSs
|
1053
1053
|
if (!child_res)
|
1054
1054
|
child_res = get_nameservers_for(child, parent_res)
|
1055
1055
|
end
|
@@ -1068,37 +1068,37 @@ module Dnsruby
|
|
1068
1068
|
end
|
1069
1069
|
end
|
1070
1070
|
end
|
1071
|
-
#
|
1072
|
-
#
|
1073
|
-
#
|
1071
|
+
# Query for DNSKEY record, and verify against DS in parent.
|
1072
|
+
# Need to get resolver NOT to verify this message - we verify it afterwards
|
1073
|
+
# print "Trying to find DNSKEY records for #{child} from servers for #{child}\n"
|
1074
1074
|
TheLog.info("Trying to find DNSKEY records for #{child} from servers for #{child}")
|
1075
|
-
#
|
1076
|
-
#
|
1075
|
+
# query = Message.new(child, Types.DNSKEY)
|
1076
|
+
# query.do_validation = false
|
1077
1077
|
key_ret = nil
|
1078
1078
|
begin
|
1079
|
-
#
|
1079
|
+
# key_ret = child_res.send_message(query)
|
1080
1080
|
key_ret = child_res.query_no_validation_or_recursion(child, Types.DNSKEY)
|
1081
1081
|
if (!key_ret)
|
1082
1082
|
raise ResolvError.new("Couldn't get info from Recursor")
|
1083
1083
|
end
|
1084
1084
|
rescue ResolvError => e
|
1085
|
-
#
|
1085
|
+
# print "Error getting DNSKEY for #{child} : #{e}\n"
|
1086
1086
|
TheLog.error("Error getting DNSKEY for #{child} : #{e}")
|
1087
1087
|
return false, nil
|
1088
1088
|
end
|
1089
1089
|
verified = true
|
1090
1090
|
key_rrset = key_ret.answer.rrset(child, Types.DNSKEY)
|
1091
1091
|
if (key_rrset.rrs.length == 0)
|
1092
|
-
#
|
1093
|
-
#
|
1092
|
+
# @TODO@ Still need to check NSEC records to make *sure* no key rrs returned!
|
1093
|
+
# print "NO DNSKEY RECORDS RETURNED FOR #{child}\n"
|
1094
1094
|
TheLog.debug("NO DNSKEY RECORDS RETURNED FOR #{child}")
|
1095
|
-
#
|
1095
|
+
# end
|
1096
1096
|
verified = false
|
1097
1097
|
else
|
1098
|
-
#
|
1098
|
+
# Should check that the matching key's zone flag is set (RFC 4035 section 5.2)
|
1099
1099
|
key_rrset.rrs.each {|k|
|
1100
1100
|
if (!k.zone_key?)
|
1101
|
-
#
|
1101
|
+
# print "Discovered DNSKEY is not a zone key - ignoring\n"
|
1102
1102
|
TheLog.debug("Discovered DNSKEY is not a zone key - ignoring")
|
1103
1103
|
return false, child_res
|
1104
1104
|
end
|
@@ -1113,8 +1113,8 @@ module Dnsruby
|
|
1113
1113
|
end
|
1114
1114
|
end
|
1115
1115
|
end
|
1116
|
-
|
1117
|
-
#
|
1116
|
+
|
1117
|
+
# Try to make the resolver from the authority/additional NS RRSets in DNSKEY response
|
1118
1118
|
new_res = get_nameservers_from_message(child, key_ret) # @TODO@ ?
|
1119
1119
|
if (!new_res)
|
1120
1120
|
new_res = child_res
|
@@ -1123,17 +1123,17 @@ module Dnsruby
|
|
1123
1123
|
TheLog.info("Failed to verify DNSKEY for #{child}")
|
1124
1124
|
return false, nil # new_res
|
1125
1125
|
end
|
1126
|
-
#
|
1126
|
+
# Cache.add(key_ret)
|
1127
1127
|
return key_rrset, new_res
|
1128
1128
|
rescue VerifyError => e
|
1129
|
-
#
|
1129
|
+
# print "Verification error : #{e}\n"
|
1130
1130
|
TheLog.info("Verification error : #{e}\n")
|
1131
1131
|
return false, nil # new_res
|
1132
1132
|
end
|
1133
1133
|
end
|
1134
1134
|
|
1135
1135
|
def get_nameservers_for(name, res = nil) # :nodoc:
|
1136
|
-
#
|
1136
|
+
# @TODO@ !!!
|
1137
1137
|
if (Dnssec.do_validation_with_recursor?)
|
1138
1138
|
return get_recursor
|
1139
1139
|
else
|
@@ -1158,9 +1158,9 @@ module Dnsruby
|
|
1158
1158
|
return nil
|
1159
1159
|
end
|
1160
1160
|
if (ns_rrset.sigs.length > 0)
|
1161
|
-
#
|
1161
|
+
# verify_rrset(ns_rrset) # @TODO@ ??
|
1162
1162
|
end
|
1163
|
-
#
|
1163
|
+
# Cache.add(ns_ret)
|
1164
1164
|
ns_additional = []
|
1165
1165
|
ns_ret.additional.each {|rr| ns_additional.push(rr) if (rr.type == Types.A) }
|
1166
1166
|
nameservers = []
|
@@ -1168,41 +1168,41 @@ module Dnsruby
|
|
1168
1168
|
ns_additional = []
|
1169
1169
|
ns_ret.additional.each {|rr| ns_additional.push(rr) if (rr.type == Types.AAAA) }
|
1170
1170
|
add_nameservers(ns_rrset, ns_additional, nameservers) if (ns_additional.length > 0)
|
1171
|
-
#
|
1171
|
+
# Make Resolver using all NSs
|
1172
1172
|
if (nameservers.length == 0)
|
1173
|
-
#
|
1173
|
+
# print "Can't find nameservers for #{ns_ret.question()[0].qname} from #{ns_rrset.rrs}\n"
|
1174
1174
|
TheLog.info("Can't find nameservers for #{ns_ret.question()[0].qname} from #{ns_rrset.rrs}")
|
1175
1175
|
return nil # @TODO@ Could return a recursor here?
|
1176
|
-
#return Recursor.new
|
1176
|
+
# return Recursor.new
|
1177
1177
|
end
|
1178
1178
|
res = Resolver.new()
|
1179
1179
|
res.nameserver=(nameservers)
|
1180
|
-
#
|
1181
|
-
#
|
1180
|
+
# Set the retry_delay to be (at least) the number of nameservers
|
1181
|
+
# Otherwise, the queries will be sent at a rate of more than one a second!
|
1182
1182
|
res.retry_delay = nameservers.length * 2
|
1183
1183
|
res.dnssec = true
|
1184
1184
|
return res
|
1185
1185
|
end
|
1186
1186
|
|
1187
1187
|
def add_nameservers(ns_rrset, ns_additional, nameservers) # :nodoc:
|
1188
|
-
#
|
1189
|
-
#
|
1188
|
+
# Want to go through all of the ns_rrset NS records,
|
1189
|
+
# print "Checking #{ns_rrset.rrs.length} NS records against #{ns_additional.length} address records\n"
|
1190
1190
|
ns_rrset.rrs.sort_by {rand}.each {|ns_rr|
|
1191
|
-
#
|
1191
|
+
# and see if we can find any of the names in the A/AAAA records in ns_additional
|
1192
1192
|
found_addr = false
|
1193
1193
|
ns_additional.each {|addr_rr|
|
1194
1194
|
if (ns_rr.nsdname.canonical == addr_rr.name.canonical)
|
1195
|
-
#
|
1195
|
+
# print "Found address #{addr_rr.address} for #{ns_rr.nsdname}\n"
|
1196
1196
|
nameservers.push(addr_rr.address.to_s)
|
1197
1197
|
found_addr = true
|
1198
1198
|
break
|
1199
|
-
#
|
1199
|
+
# If we can, then we add the server A/AAAA address to nameservers
|
1200
1200
|
end
|
1201
|
-
#
|
1201
|
+
# If we can't, then we add the server NS name to nameservers
|
1202
1202
|
|
1203
1203
|
}
|
1204
1204
|
if (!found_addr)
|
1205
|
-
#
|
1205
|
+
# print "Couldn't find address - adding #{ns_rr.nsdname}\n"
|
1206
1206
|
nameservers.push(ns_rr.nsdname)
|
1207
1207
|
end
|
1208
1208
|
|
@@ -1210,22 +1210,22 @@ module Dnsruby
|
|
1210
1210
|
end
|
1211
1211
|
|
1212
1212
|
def validate_no_rrsigs(msg) # :nodoc:
|
1213
|
-
#
|
1214
|
-
#
|
1215
|
-
#
|
1213
|
+
# print "Validating unsigned response\n"
|
1214
|
+
# WHAT IF THERE ARE NO RRSIGS IN MSG?
|
1215
|
+
# Then we need to check that we do not expect any RRSIGs
|
1216
1216
|
if (!msg.question()[0] && msg.answer.length == 0)
|
1217
|
-
#
|
1217
|
+
# print "Returning Message insecure OK\n"
|
1218
1218
|
msg.security_level = Message::SecurityLevel.INSECURE
|
1219
1219
|
return true
|
1220
1220
|
end
|
1221
1221
|
qname = msg.question()[0].qname
|
1222
1222
|
closest_anchor = find_closest_anchor_for(qname)
|
1223
|
-
#
|
1223
|
+
# print "Found closest anchor :#{closest_anchor}\n"
|
1224
1224
|
if (closest_anchor)
|
1225
1225
|
actual_anchor = follow_chain(closest_anchor, qname)
|
1226
|
-
#
|
1226
|
+
# print "Actual anchor : #{actual_anchor}\n"
|
1227
1227
|
if (actual_anchor)
|
1228
|
-
#
|
1228
|
+
# print("Anchor exists for #{qname}, but no signatures in #{msg}\n")
|
1229
1229
|
TheLog.error("Anchor exists for #{qname}, but no signatures in #{msg}")
|
1230
1230
|
msg.security_level = Message::SecurityLevel.BOGUS
|
1231
1231
|
return false
|
@@ -1233,15 +1233,15 @@ module Dnsruby
|
|
1233
1233
|
end
|
1234
1234
|
if ((@verifier_type == VerifierType::DLV) &&
|
1235
1235
|
@added_dlv_key)
|
1236
|
-
#
|
1237
|
-
#
|
1236
|
+
# Remember to check DLV registry as well (if appropriate!)
|
1237
|
+
# print "Checking DLV for closest anchor\n"
|
1238
1238
|
dlv_anchor = find_closest_dlv_anchor_for(qname)
|
1239
|
-
#
|
1239
|
+
# print "Found DLV closest anchor :#{dlv_anchor}\n"
|
1240
1240
|
if (dlv_anchor)
|
1241
1241
|
actual_anchor = follow_chain(dlv_anchor, qname)
|
1242
|
-
#
|
1242
|
+
# print "Actual anchor : #{actual_anchor}\n"
|
1243
1243
|
if (actual_anchor)
|
1244
|
-
#
|
1244
|
+
# print("DLV Anchor exists for #{qname}, but no signatures in #{msg}\n")
|
1245
1245
|
TheLog.error("DLV Anchor exists for #{qname}, but no signatures in #{msg}")
|
1246
1246
|
msg.security_level = Message::SecurityLevel.BOGUS
|
1247
1247
|
return false
|
@@ -1249,7 +1249,7 @@ module Dnsruby
|
|
1249
1249
|
|
1250
1250
|
end
|
1251
1251
|
end
|
1252
|
-
#
|
1252
|
+
# print "Returning Message insecure OK\n"
|
1253
1253
|
msg.security_level = Message::SecurityLevel.INSECURE
|
1254
1254
|
return true
|
1255
1255
|
end
|
@@ -1259,14 +1259,14 @@ module Dnsruby
|
|
1259
1259
|
return validate_no_rrsigs(msg)
|
1260
1260
|
end
|
1261
1261
|
|
1262
|
-
#
|
1263
|
-
#
|
1264
|
-
#
|
1265
|
-
#
|
1266
|
-
#
|
1267
|
-
#
|
1268
|
-
#
|
1269
|
-
#
|
1262
|
+
# See if it is a child of any of our trust anchors.
|
1263
|
+
# If it is, then see if we have a trusted key for it
|
1264
|
+
# If we don't, then see if we can get to it from the closest
|
1265
|
+
# trust anchor
|
1266
|
+
# Otherwise, try DLV (if configured)
|
1267
|
+
#
|
1268
|
+
#
|
1269
|
+
# So - find closest existing trust anchor
|
1270
1270
|
error = nil
|
1271
1271
|
msg.security_level = Message::SecurityLevel.INDETERMINATE
|
1272
1272
|
qname = msg.question()[0].qname
|
@@ -1277,28 +1277,28 @@ module Dnsruby
|
|
1277
1277
|
if ((msg.security_level.code < Message::SecurityLevel::SECURE) &&
|
1278
1278
|
(@verifier_type == VerifierType::DLV) &&
|
1279
1279
|
@added_dlv_key)
|
1280
|
-
#
|
1281
|
-
#
|
1280
|
+
# If we can't find anything, and we're set to check DLV, then
|
1281
|
+
# check the DLV registry and work down from there.
|
1282
1282
|
dlv_anchor = find_closest_dlv_anchor_for(qname)
|
1283
1283
|
if (dlv_anchor)
|
1284
|
-
#
|
1284
|
+
# print "Trying to follow DLV anchor from #{dlv_anchor.name} to #{qname}\n"
|
1285
1285
|
TheLog.debug("Trying to follow DLV anchor from #{dlv_anchor.name} to #{qname}")
|
1286
1286
|
error = try_to_follow_from_anchor(dlv_anchor, msg, qname)
|
1287
1287
|
else
|
1288
|
-
#
|
1288
|
+
# print "Couldn't find DLV anchor for #{qname}\n"
|
1289
1289
|
TheLog.debug("Couldn't find DLV anchor for #{qname}")
|
1290
1290
|
end
|
1291
1291
|
end
|
1292
1292
|
if (msg.security_level.code != Message::SecurityLevel::SECURE)
|
1293
1293
|
begin
|
1294
|
-
#
|
1294
|
+
# print "Trying to verify one last time\n"
|
1295
1295
|
|
1296
1296
|
if verify(msg) # Just make sure we haven't picked the keys up anywhere
|
1297
1297
|
msg.security_level = Message::SecurityLevel.SECURE
|
1298
1298
|
return true
|
1299
1299
|
end
|
1300
1300
|
rescue VerifyError => e
|
1301
|
-
#
|
1301
|
+
# print "Verify failed : #{e}\n"
|
1302
1302
|
end
|
1303
1303
|
end
|
1304
1304
|
if (error)
|
@@ -1314,7 +1314,7 @@ module Dnsruby
|
|
1314
1314
|
def try_to_follow_from_anchor(closest_anchor, msg, qname) # :nodoc:
|
1315
1315
|
error = nil
|
1316
1316
|
if (closest_anchor)
|
1317
|
-
#
|
1317
|
+
# Then try to descend to the level we're interested in
|
1318
1318
|
actual_anchor = follow_chain(closest_anchor, qname)
|
1319
1319
|
if (!actual_anchor)
|
1320
1320
|
TheLog.debug("Unable to follow chain from anchor : #{closest_anchor.name}")
|
@@ -1323,7 +1323,7 @@ module Dnsruby
|
|
1323
1323
|
actual_anchor_keys = ""
|
1324
1324
|
actual_anchor.rrs.each {|rr| actual_anchor_keys += ", #{rr.key_tag}"}
|
1325
1325
|
TheLog.debug("Found anchor #{actual_anchor.name}, #{actual_anchor.type} for #{qname} : #{actual_anchor_keys}")
|
1326
|
-
#
|
1326
|
+
# print "Found anchor #{actual_anchor.name}, #{actual_anchor.type} for #{qname} : #{actual_anchor_keys}\n"
|
1327
1327
|
begin
|
1328
1328
|
if (verify(msg, actual_anchor))
|
1329
1329
|
TheLog.debug("Validated #{qname}")
|
@@ -1331,13 +1331,13 @@ module Dnsruby
|
|
1331
1331
|
end
|
1332
1332
|
rescue VerifyError => e
|
1333
1333
|
TheLog.info("BOGUS #{qname}! Error : #{e}")
|
1334
|
-
#
|
1334
|
+
# print "BOGUS #{qname}! Error : #{e}\n"
|
1335
1335
|
msg.security_level = Message::SecurityLevel.BOGUS
|
1336
1336
|
error = e
|
1337
1337
|
end
|
1338
1338
|
end
|
1339
1339
|
else
|
1340
|
-
#
|
1340
|
+
# print "Unable to find an anchor for #{qname}\n"
|
1341
1341
|
msg.security_level = Message::SecurityLevel.INSECURE
|
1342
1342
|
end
|
1343
1343
|
return error
|