dnsruby 1.55 → 1.56.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/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
|