2 * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2002 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: rootns.c,v 1.32.24.2 2008/02/05 23:46:39 tbox Exp $ */
24 #include <isc/buffer.h>
25 #include <isc/string.h> /* Required for HP/UX (and others?) */
28 #include <dns/callbacks.h>
30 #include <dns/dbiterator.h>
31 #include <dns/fixedname.h>
33 #include <dns/master.h>
34 #include <dns/rdata.h>
35 #include <dns/rdata.h>
36 #include <dns/rdataset.h>
37 #include <dns/rdatasetiter.h>
38 #include <dns/rdatastruct.h>
39 #include <dns/rdatatype.h>
40 #include <dns/result.h>
41 #include <dns/rootns.h>
44 static char root_ns
[] =
46 "; Internet Root Nameservers\n"
49 ". 518400 IN NS A.ROOT-SERVERS.NET.\n"
50 ". 518400 IN NS B.ROOT-SERVERS.NET.\n"
51 ". 518400 IN NS C.ROOT-SERVERS.NET.\n"
52 ". 518400 IN NS D.ROOT-SERVERS.NET.\n"
53 ". 518400 IN NS E.ROOT-SERVERS.NET.\n"
54 ". 518400 IN NS F.ROOT-SERVERS.NET.\n"
55 ". 518400 IN NS G.ROOT-SERVERS.NET.\n"
56 ". 518400 IN NS H.ROOT-SERVERS.NET.\n"
57 ". 518400 IN NS I.ROOT-SERVERS.NET.\n"
58 ". 518400 IN NS J.ROOT-SERVERS.NET.\n"
59 ". 518400 IN NS K.ROOT-SERVERS.NET.\n"
60 ". 518400 IN NS L.ROOT-SERVERS.NET.\n"
61 ". 518400 IN NS M.ROOT-SERVERS.NET.\n"
62 "A.ROOT-SERVERS.NET. 3600000 IN A 198.41.0.4\n"
63 "A.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:503:BA3E::2:30\n"
64 "B.ROOT-SERVERS.NET. 3600000 IN A 192.228.79.201\n"
65 "C.ROOT-SERVERS.NET. 3600000 IN A 192.33.4.12\n"
66 "D.ROOT-SERVERS.NET. 3600000 IN A 128.8.10.90\n"
67 "E.ROOT-SERVERS.NET. 3600000 IN A 192.203.230.10\n"
68 "F.ROOT-SERVERS.NET. 3600000 IN A 192.5.5.241\n"
69 "F.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:500:2F::F\n"
70 "G.ROOT-SERVERS.NET. 3600000 IN A 192.112.36.4\n"
71 "H.ROOT-SERVERS.NET. 3600000 IN A 128.63.2.53\n"
72 "H.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:500:1::803F:235\n"
73 "I.ROOT-SERVERS.NET. 3600000 IN A 192.36.148.17\n"
74 "J.ROOT-SERVERS.NET. 3600000 IN A 192.58.128.30\n"
75 "J.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:503:C27::2:30\n"
76 "K.ROOT-SERVERS.NET. 3600000 IN A 193.0.14.129\n"
77 "K.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:7FD::1\n"
78 "L.ROOT-SERVERS.NET. 3600000 IN A 199.7.83.42\n"
79 "M.ROOT-SERVERS.NET. 3600000 IN A 202.12.27.33\n"
80 "M.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:DC3::35\n";
83 in_rootns(dns_rdataset_t
*rootns
, dns_name_t
*name
) {
85 dns_rdata_t rdata
= DNS_RDATA_INIT
;
88 if (!dns_rdataset_isassociated(rootns
))
89 return (ISC_R_NOTFOUND
);
91 result
= dns_rdataset_first(rootns
);
92 while (result
== ISC_R_SUCCESS
) {
93 dns_rdataset_current(rootns
, &rdata
);
94 result
= dns_rdata_tostruct(&rdata
, &ns
, NULL
);
95 if (result
!= ISC_R_SUCCESS
)
97 if (dns_name_compare(name
, &ns
.name
) == 0)
98 return (ISC_R_SUCCESS
);
99 result
= dns_rdataset_next(rootns
);
101 if (result
== ISC_R_NOMORE
)
102 result
= ISC_R_NOTFOUND
;
107 check_node(dns_rdataset_t
*rootns
, dns_name_t
*name
,
108 dns_rdatasetiter_t
*rdsiter
) {
110 dns_rdataset_t rdataset
;
112 dns_rdataset_init(&rdataset
);
113 result
= dns_rdatasetiter_first(rdsiter
);
114 while (result
== ISC_R_SUCCESS
) {
115 dns_rdatasetiter_current(rdsiter
, &rdataset
);
116 switch (rdataset
.type
) {
117 case dns_rdatatype_a
:
118 case dns_rdatatype_aaaa
:
119 result
= in_rootns(rootns
, name
);
120 if (result
!= ISC_R_SUCCESS
)
123 case dns_rdatatype_ns
:
124 if (dns_name_compare(name
, dns_rootname
) == 0)
128 result
= ISC_R_FAILURE
;
131 dns_rdataset_disassociate(&rdataset
);
132 result
= dns_rdatasetiter_next(rdsiter
);
134 if (result
== ISC_R_NOMORE
)
135 result
= ISC_R_SUCCESS
;
137 if (dns_rdataset_isassociated(&rdataset
))
138 dns_rdataset_disassociate(&rdataset
);
143 check_hints(dns_db_t
*db
) {
145 dns_rdataset_t rootns
;
146 dns_dbiterator_t
*dbiter
= NULL
;
147 dns_dbnode_t
*node
= NULL
;
149 dns_fixedname_t fixname
;
151 dns_rdatasetiter_t
*rdsiter
= NULL
;
153 isc_stdtime_get(&now
);
155 dns_fixedname_init(&fixname
);
156 name
= dns_fixedname_name(&fixname
);
158 dns_rdataset_init(&rootns
);
159 (void)dns_db_find(db
, dns_rootname
, NULL
, dns_rdatatype_ns
, 0,
160 now
, NULL
, name
, &rootns
, NULL
);
161 result
= dns_db_createiterator(db
, ISC_FALSE
, &dbiter
);
162 if (result
!= ISC_R_SUCCESS
)
164 result
= dns_dbiterator_first(dbiter
);
165 while (result
== ISC_R_SUCCESS
) {
166 result
= dns_dbiterator_current(dbiter
, &node
, name
);
167 if (result
!= ISC_R_SUCCESS
)
169 result
= dns_db_allrdatasets(db
, node
, NULL
, now
, &rdsiter
);
170 if (result
!= ISC_R_SUCCESS
)
172 result
= check_node(&rootns
, name
, rdsiter
);
173 if (result
!= ISC_R_SUCCESS
)
175 dns_rdatasetiter_destroy(&rdsiter
);
176 dns_db_detachnode(db
, &node
);
177 result
= dns_dbiterator_next(dbiter
);
179 if (result
== ISC_R_NOMORE
)
180 result
= ISC_R_SUCCESS
;
183 if (dns_rdataset_isassociated(&rootns
))
184 dns_rdataset_disassociate(&rootns
);
186 dns_rdatasetiter_destroy(&rdsiter
);
188 dns_db_detachnode(db
, &node
);
190 dns_dbiterator_destroy(&dbiter
);
195 dns_rootns_create(isc_mem_t
*mctx
, dns_rdataclass_t rdclass
,
196 const char *filename
, dns_db_t
**target
)
198 isc_result_t result
, eresult
;
201 dns_rdatacallbacks_t callbacks
;
204 REQUIRE(target
!= NULL
&& *target
== NULL
);
206 result
= dns_db_create(mctx
, "rbt", dns_rootname
, dns_dbtype_zone
,
207 rdclass
, 0, NULL
, &db
);
208 if (result
!= ISC_R_SUCCESS
)
211 dns_rdatacallbacks_init(&callbacks
);
213 len
= strlen(root_ns
);
214 isc_buffer_init(&source
, root_ns
, len
);
215 isc_buffer_add(&source
, len
);
217 result
= dns_db_beginload(db
, &callbacks
.add
,
218 &callbacks
.add_private
);
219 if (result
!= ISC_R_SUCCESS
)
221 if (filename
!= NULL
) {
223 * Load the hints from the specified filename.
225 result
= dns_master_loadfile(filename
, &db
->origin
,
226 &db
->origin
, db
->rdclass
,
228 &callbacks
, db
->mctx
);
229 } else if (rdclass
== dns_rdataclass_in
) {
231 * Default to using the Internet root servers.
233 result
= dns_master_loadbuffer(&source
, &db
->origin
,
234 &db
->origin
, db
->rdclass
,
236 &callbacks
, db
->mctx
);
238 result
= ISC_R_NOTFOUND
;
239 eresult
= dns_db_endload(db
, &callbacks
.add_private
);
240 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_SEENINCLUDE
)
242 if (result
!= ISC_R_SUCCESS
&& result
!= DNS_R_SEENINCLUDE
)
244 if (check_hints(db
) != ISC_R_SUCCESS
)
245 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
246 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
247 "extra data in root hints '%s'",
248 (filename
!= NULL
) ? filename
: "<BUILT-IN>");
250 return (ISC_R_SUCCESS
);
259 report(dns_view_t
*view
, dns_name_t
*name
, isc_boolean_t missing
,
262 const char *viewname
= "", *sep
= "";
263 char namebuf
[DNS_NAME_FORMATSIZE
];
264 char typebuf
[DNS_RDATATYPE_FORMATSIZE
];
265 char databuf
[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
269 if (strcmp(view
->name
, "_bind") != 0 &&
270 strcmp(view
->name
, "_default") != 0) {
271 viewname
= view
->name
;
275 dns_name_format(name
, namebuf
, sizeof(namebuf
));
276 dns_rdatatype_format(rdata
->type
, typebuf
, sizeof(typebuf
));
277 isc_buffer_init(&buffer
, databuf
, sizeof(databuf
) - 1);
278 result
= dns_rdata_totext(rdata
, NULL
, &buffer
);
279 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
280 databuf
[isc_buffer_usedlength(&buffer
)] = '\0';
283 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
284 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
285 "checkhints%s%s: %s/%s (%s) missing from hints",
286 sep
, viewname
, namebuf
, typebuf
, databuf
);
288 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
289 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
290 "checkhints%s%s: %s/%s (%s) extra record "
291 "in hints", sep
, viewname
, namebuf
, typebuf
,
296 inrrset(dns_rdataset_t
*rrset
, dns_rdata_t
*rdata
) {
298 dns_rdata_t current
= DNS_RDATA_INIT
;
300 result
= dns_rdataset_first(rrset
);
301 while (result
== ISC_R_SUCCESS
) {
302 dns_rdataset_current(rrset
, ¤t
);
303 if (dns_rdata_compare(rdata
, ¤t
) == 0)
305 dns_rdata_reset(¤t
);
306 result
= dns_rdataset_next(rrset
);
312 * Check that the address RRsets match.
314 * Note we don't complain about missing glue records.
318 check_address_records(dns_view_t
*view
, dns_db_t
*hints
, dns_db_t
*db
,
319 dns_name_t
*name
, isc_stdtime_t now
)
321 isc_result_t hresult
, rresult
, result
;
322 dns_rdataset_t hintrrset
, rootrrset
;
323 dns_rdata_t rdata
= DNS_RDATA_INIT
;
324 dns_name_t
*foundname
;
325 dns_fixedname_t fixed
;
327 dns_rdataset_init(&hintrrset
);
328 dns_rdataset_init(&rootrrset
);
329 dns_fixedname_init(&fixed
);
330 foundname
= dns_fixedname_name(&fixed
);
332 hresult
= dns_db_find(hints
, name
, NULL
, dns_rdatatype_a
, 0,
333 now
, NULL
, foundname
, &hintrrset
, NULL
);
334 rresult
= dns_db_find(db
, name
, NULL
, dns_rdatatype_a
,
335 DNS_DBFIND_GLUEOK
, now
, NULL
, foundname
,
337 if (hresult
== ISC_R_SUCCESS
&&
338 (rresult
== ISC_R_SUCCESS
|| rresult
== DNS_R_GLUE
)) {
339 result
= dns_rdataset_first(&rootrrset
);
340 while (result
== ISC_R_SUCCESS
) {
341 dns_rdataset_current(&rootrrset
, &rdata
);
342 if (!inrrset(&hintrrset
, &rdata
))
343 report(view
, name
, ISC_TRUE
, &rdata
);
344 result
= dns_rdataset_next(&rootrrset
);
346 result
= dns_rdataset_first(&hintrrset
);
347 while (result
== ISC_R_SUCCESS
) {
348 dns_rdataset_current(&hintrrset
, &rdata
);
349 if (!inrrset(&rootrrset
, &rdata
))
350 report(view
, name
, ISC_FALSE
, &rdata
);
351 result
= dns_rdataset_next(&hintrrset
);
354 if (hresult
== ISC_R_NOTFOUND
&&
355 (rresult
== ISC_R_SUCCESS
|| rresult
== DNS_R_GLUE
)) {
356 result
= dns_rdataset_first(&rootrrset
);
357 while (result
== ISC_R_SUCCESS
) {
358 dns_rdataset_current(&rootrrset
, &rdata
);
359 report(view
, name
, ISC_TRUE
, &rdata
);
360 result
= dns_rdataset_next(&rootrrset
);
363 if (dns_rdataset_isassociated(&rootrrset
))
364 dns_rdataset_disassociate(&rootrrset
);
365 if (dns_rdataset_isassociated(&hintrrset
))
366 dns_rdataset_disassociate(&hintrrset
);
369 * Check AAAA records.
371 hresult
= dns_db_find(hints
, name
, NULL
, dns_rdatatype_aaaa
, 0,
372 now
, NULL
, foundname
, &hintrrset
, NULL
);
373 rresult
= dns_db_find(db
, name
, NULL
, dns_rdatatype_aaaa
,
374 DNS_DBFIND_GLUEOK
, now
, NULL
, foundname
,
376 if (hresult
== ISC_R_SUCCESS
&&
377 (rresult
== ISC_R_SUCCESS
|| rresult
== DNS_R_GLUE
)) {
378 result
= dns_rdataset_first(&rootrrset
);
379 while (result
== ISC_R_SUCCESS
) {
380 dns_rdataset_current(&rootrrset
, &rdata
);
381 if (!inrrset(&hintrrset
, &rdata
))
382 report(view
, name
, ISC_TRUE
, &rdata
);
383 dns_rdata_reset(&rdata
);
384 result
= dns_rdataset_next(&rootrrset
);
386 result
= dns_rdataset_first(&hintrrset
);
387 while (result
== ISC_R_SUCCESS
) {
388 dns_rdataset_current(&hintrrset
, &rdata
);
389 if (!inrrset(&rootrrset
, &rdata
))
390 report(view
, name
, ISC_FALSE
, &rdata
);
391 dns_rdata_reset(&rdata
);
392 result
= dns_rdataset_next(&hintrrset
);
395 if (hresult
== ISC_R_NOTFOUND
&&
396 (rresult
== ISC_R_SUCCESS
|| rresult
== DNS_R_GLUE
)) {
397 result
= dns_rdataset_first(&rootrrset
);
398 while (result
== ISC_R_SUCCESS
) {
399 dns_rdataset_current(&rootrrset
, &rdata
);
400 report(view
, name
, ISC_TRUE
, &rdata
);
401 dns_rdata_reset(&rdata
);
402 result
= dns_rdataset_next(&rootrrset
);
405 if (dns_rdataset_isassociated(&rootrrset
))
406 dns_rdataset_disassociate(&rootrrset
);
407 if (dns_rdataset_isassociated(&hintrrset
))
408 dns_rdataset_disassociate(&hintrrset
);
412 dns_root_checkhints(dns_view_t
*view
, dns_db_t
*hints
, dns_db_t
*db
) {
414 dns_rdata_t rdata
= DNS_RDATA_INIT
;
416 dns_rdataset_t hintns
, rootns
;
417 const char *viewname
= "", *sep
= "";
420 dns_fixedname_t fixed
;
422 REQUIRE(hints
!= NULL
);
424 REQUIRE(view
!= NULL
);
426 isc_stdtime_get(&now
);
428 if (strcmp(view
->name
, "_bind") != 0 &&
429 strcmp(view
->name
, "_default") != 0) {
430 viewname
= view
->name
;
434 dns_rdataset_init(&hintns
);
435 dns_rdataset_init(&rootns
);
436 dns_fixedname_init(&fixed
);
437 name
= dns_fixedname_name(&fixed
);
439 result
= dns_db_find(hints
, dns_rootname
, NULL
, dns_rdatatype_ns
, 0,
440 now
, NULL
, name
, &hintns
, NULL
);
441 if (result
!= ISC_R_SUCCESS
) {
442 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
443 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
444 "checkhints%s%s: unable to get root NS rrset "
445 "from hints: %s", sep
, viewname
,
446 dns_result_totext(result
));
450 result
= dns_db_find(db
, dns_rootname
, NULL
, dns_rdatatype_ns
, 0,
451 now
, NULL
, name
, &rootns
, NULL
);
452 if (result
!= ISC_R_SUCCESS
) {
453 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
454 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
455 "checkhints%s%s: unable to get root NS rrset "
456 "from cache: %s", sep
, viewname
,
457 dns_result_totext(result
));
462 * Look for missing root NS names.
464 result
= dns_rdataset_first(&rootns
);
465 while (result
== ISC_R_SUCCESS
) {
466 dns_rdataset_current(&rootns
, &rdata
);
467 result
= dns_rdata_tostruct(&rdata
, &ns
, NULL
);
468 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
469 result
= in_rootns(&hintns
, &ns
.name
);
470 if (result
!= ISC_R_SUCCESS
) {
471 char namebuf
[DNS_NAME_FORMATSIZE
];
472 /* missing from hints */
473 dns_name_format(&ns
.name
, namebuf
, sizeof(namebuf
));
474 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
475 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
476 "checkhints%s%s: unable to find root "
477 "NS '%s' in hints", sep
, viewname
,
480 check_address_records(view
, hints
, db
, &ns
.name
, now
);
481 dns_rdata_reset(&rdata
);
482 result
= dns_rdataset_next(&rootns
);
484 if (result
!= ISC_R_NOMORE
) {
489 * Look for extra root NS names.
491 result
= dns_rdataset_first(&hintns
);
492 while (result
== ISC_R_SUCCESS
) {
493 dns_rdataset_current(&hintns
, &rdata
);
494 result
= dns_rdata_tostruct(&rdata
, &ns
, NULL
);
495 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
496 result
= in_rootns(&rootns
, &ns
.name
);
497 if (result
!= ISC_R_SUCCESS
) {
498 char namebuf
[DNS_NAME_FORMATSIZE
];
499 /* extra entry in hints */
500 dns_name_format(&ns
.name
, namebuf
, sizeof(namebuf
));
501 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
502 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
503 "checkhints%s%s: extra NS '%s' in hints",
504 sep
, viewname
, namebuf
);
506 dns_rdata_reset(&rdata
);
507 result
= dns_rdataset_next(&hintns
);
509 if (result
!= ISC_R_NOMORE
) {
514 if (dns_rdataset_isassociated(&rootns
))
515 dns_rdataset_disassociate(&rootns
);
516 if (dns_rdataset_isassociated(&hintns
))
517 dns_rdataset_disassociate(&hintns
);