4 * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: rootns.c,v 1.36 2008/09/24 02:46:22 marka Exp */
26 #include <isc/buffer.h>
27 #include <isc/string.h> /* Required for HP/UX (and others?) */
30 #include <dns/callbacks.h>
32 #include <dns/dbiterator.h>
33 #include <dns/fixedname.h>
35 #include <dns/master.h>
36 #include <dns/rdata.h>
37 #include <dns/rdata.h>
38 #include <dns/rdataset.h>
39 #include <dns/rdatasetiter.h>
40 #include <dns/rdatastruct.h>
41 #include <dns/rdatatype.h>
42 #include <dns/result.h>
43 #include <dns/rootns.h>
46 static char root_ns
[] =
48 "; Internet Root Nameservers\n"
51 ". 518400 IN NS A.ROOT-SERVERS.NET.\n"
52 ". 518400 IN NS B.ROOT-SERVERS.NET.\n"
53 ". 518400 IN NS C.ROOT-SERVERS.NET.\n"
54 ". 518400 IN NS D.ROOT-SERVERS.NET.\n"
55 ". 518400 IN NS E.ROOT-SERVERS.NET.\n"
56 ". 518400 IN NS F.ROOT-SERVERS.NET.\n"
57 ". 518400 IN NS G.ROOT-SERVERS.NET.\n"
58 ". 518400 IN NS H.ROOT-SERVERS.NET.\n"
59 ". 518400 IN NS I.ROOT-SERVERS.NET.\n"
60 ". 518400 IN NS J.ROOT-SERVERS.NET.\n"
61 ". 518400 IN NS K.ROOT-SERVERS.NET.\n"
62 ". 518400 IN NS L.ROOT-SERVERS.NET.\n"
63 ". 518400 IN NS M.ROOT-SERVERS.NET.\n"
64 "A.ROOT-SERVERS.NET. 3600000 IN A 198.41.0.4\n"
65 "A.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:503:BA3E::2:30\n"
66 "B.ROOT-SERVERS.NET. 3600000 IN A 192.228.79.201\n"
67 "C.ROOT-SERVERS.NET. 3600000 IN A 192.33.4.12\n"
68 "D.ROOT-SERVERS.NET. 3600000 IN A 128.8.10.90\n"
69 "E.ROOT-SERVERS.NET. 3600000 IN A 192.203.230.10\n"
70 "F.ROOT-SERVERS.NET. 3600000 IN A 192.5.5.241\n"
71 "F.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:500:2F::F\n"
72 "G.ROOT-SERVERS.NET. 3600000 IN A 192.112.36.4\n"
73 "H.ROOT-SERVERS.NET. 3600000 IN A 128.63.2.53\n"
74 "H.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:500:1::803F:235\n"
75 "I.ROOT-SERVERS.NET. 3600000 IN A 192.36.148.17\n"
76 "J.ROOT-SERVERS.NET. 3600000 IN A 192.58.128.30\n"
77 "J.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:503:C27::2:30\n"
78 "K.ROOT-SERVERS.NET. 3600000 IN A 193.0.14.129\n"
79 "K.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:7FD::1\n"
80 "L.ROOT-SERVERS.NET. 3600000 IN A 199.7.83.42\n"
81 "M.ROOT-SERVERS.NET. 3600000 IN A 202.12.27.33\n"
82 "M.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:DC3::35\n";
85 in_rootns(dns_rdataset_t
*rootns
, dns_name_t
*name
) {
87 dns_rdata_t rdata
= DNS_RDATA_INIT
;
90 if (!dns_rdataset_isassociated(rootns
))
91 return (ISC_R_NOTFOUND
);
93 result
= dns_rdataset_first(rootns
);
94 while (result
== ISC_R_SUCCESS
) {
95 dns_rdataset_current(rootns
, &rdata
);
96 result
= dns_rdata_tostruct(&rdata
, &ns
, NULL
);
97 if (result
!= ISC_R_SUCCESS
)
99 if (dns_name_compare(name
, &ns
.name
) == 0)
100 return (ISC_R_SUCCESS
);
101 result
= dns_rdataset_next(rootns
);
102 dns_rdata_reset(&rdata
);
104 if (result
== ISC_R_NOMORE
)
105 result
= ISC_R_NOTFOUND
;
110 check_node(dns_rdataset_t
*rootns
, dns_name_t
*name
,
111 dns_rdatasetiter_t
*rdsiter
) {
113 dns_rdataset_t rdataset
;
115 dns_rdataset_init(&rdataset
);
116 result
= dns_rdatasetiter_first(rdsiter
);
117 while (result
== ISC_R_SUCCESS
) {
118 dns_rdatasetiter_current(rdsiter
, &rdataset
);
119 switch (rdataset
.type
) {
120 case dns_rdatatype_a
:
121 case dns_rdatatype_aaaa
:
122 result
= in_rootns(rootns
, name
);
123 if (result
!= ISC_R_SUCCESS
)
126 case dns_rdatatype_ns
:
127 if (dns_name_compare(name
, dns_rootname
) == 0)
131 result
= ISC_R_FAILURE
;
134 dns_rdataset_disassociate(&rdataset
);
135 result
= dns_rdatasetiter_next(rdsiter
);
137 if (result
== ISC_R_NOMORE
)
138 result
= ISC_R_SUCCESS
;
140 if (dns_rdataset_isassociated(&rdataset
))
141 dns_rdataset_disassociate(&rdataset
);
146 check_hints(dns_db_t
*db
) {
148 dns_rdataset_t rootns
;
149 dns_dbiterator_t
*dbiter
= NULL
;
150 dns_dbnode_t
*node
= NULL
;
152 dns_fixedname_t fixname
;
154 dns_rdatasetiter_t
*rdsiter
= NULL
;
156 isc_stdtime_get(&now
);
158 dns_fixedname_init(&fixname
);
159 name
= dns_fixedname_name(&fixname
);
161 dns_rdataset_init(&rootns
);
162 (void)dns_db_find(db
, dns_rootname
, NULL
, dns_rdatatype_ns
, 0,
163 now
, NULL
, name
, &rootns
, NULL
);
164 result
= dns_db_createiterator(db
, 0, &dbiter
);
165 if (result
!= ISC_R_SUCCESS
)
167 result
= dns_dbiterator_first(dbiter
);
168 while (result
== ISC_R_SUCCESS
) {
169 result
= dns_dbiterator_current(dbiter
, &node
, name
);
170 if (result
!= ISC_R_SUCCESS
)
172 result
= dns_db_allrdatasets(db
, node
, NULL
, now
, &rdsiter
);
173 if (result
!= ISC_R_SUCCESS
)
175 result
= check_node(&rootns
, name
, rdsiter
);
176 if (result
!= ISC_R_SUCCESS
)
178 dns_rdatasetiter_destroy(&rdsiter
);
179 dns_db_detachnode(db
, &node
);
180 result
= dns_dbiterator_next(dbiter
);
182 if (result
== ISC_R_NOMORE
)
183 result
= ISC_R_SUCCESS
;
186 if (dns_rdataset_isassociated(&rootns
))
187 dns_rdataset_disassociate(&rootns
);
189 dns_rdatasetiter_destroy(&rdsiter
);
191 dns_db_detachnode(db
, &node
);
193 dns_dbiterator_destroy(&dbiter
);
198 dns_rootns_create(isc_mem_t
*mctx
, dns_rdataclass_t rdclass
,
199 const char *filename
, dns_db_t
**target
)
201 isc_result_t result
, eresult
;
204 dns_rdatacallbacks_t callbacks
;
207 REQUIRE(target
!= NULL
&& *target
== NULL
);
209 result
= dns_db_create(mctx
, "rbt", dns_rootname
, dns_dbtype_zone
,
210 rdclass
, 0, NULL
, &db
);
211 if (result
!= ISC_R_SUCCESS
)
214 dns_rdatacallbacks_init(&callbacks
);
216 len
= strlen(root_ns
);
217 isc_buffer_init(&source
, root_ns
, len
);
218 isc_buffer_add(&source
, len
);
220 result
= dns_db_beginload(db
, &callbacks
.add
,
221 &callbacks
.add_private
);
222 if (result
!= ISC_R_SUCCESS
)
224 if (filename
!= NULL
) {
226 * Load the hints from the specified filename.
228 result
= dns_master_loadfile(filename
, &db
->origin
,
229 &db
->origin
, db
->rdclass
,
231 &callbacks
, db
->mctx
);
232 } else if (rdclass
== dns_rdataclass_in
) {
234 * Default to using the Internet root servers.
236 result
= dns_master_loadbuffer(&source
, &db
->origin
,
237 &db
->origin
, db
->rdclass
,
239 &callbacks
, db
->mctx
);
241 result
= ISC_R_NOTFOUND
;
242 eresult
= dns_db_endload(db
, &callbacks
.add_private
);
243 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_SEENINCLUDE
)
245 if (result
!= ISC_R_SUCCESS
&& result
!= DNS_R_SEENINCLUDE
)
247 if (check_hints(db
) != ISC_R_SUCCESS
)
248 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
249 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
250 "extra data in root hints '%s'",
251 (filename
!= NULL
) ? filename
: "<BUILT-IN>");
253 return (ISC_R_SUCCESS
);
262 report(dns_view_t
*view
, dns_name_t
*name
, isc_boolean_t missing
,
265 const char *viewname
= "", *sep
= "";
266 char namebuf
[DNS_NAME_FORMATSIZE
];
267 char typebuf
[DNS_RDATATYPE_FORMATSIZE
];
268 char databuf
[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
272 if (strcmp(view
->name
, "_bind") != 0 &&
273 strcmp(view
->name
, "_default") != 0) {
274 viewname
= view
->name
;
278 dns_name_format(name
, namebuf
, sizeof(namebuf
));
279 dns_rdatatype_format(rdata
->type
, typebuf
, sizeof(typebuf
));
280 isc_buffer_init(&buffer
, databuf
, sizeof(databuf
) - 1);
281 result
= dns_rdata_totext(rdata
, NULL
, &buffer
);
282 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
283 databuf
[isc_buffer_usedlength(&buffer
)] = '\0';
286 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
287 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
288 "checkhints%s%s: %s/%s (%s) missing from hints",
289 sep
, viewname
, namebuf
, typebuf
, databuf
);
291 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
292 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
293 "checkhints%s%s: %s/%s (%s) extra record "
294 "in hints", sep
, viewname
, namebuf
, typebuf
,
299 inrrset(dns_rdataset_t
*rrset
, dns_rdata_t
*rdata
) {
301 dns_rdata_t current
= DNS_RDATA_INIT
;
303 result
= dns_rdataset_first(rrset
);
304 while (result
== ISC_R_SUCCESS
) {
305 dns_rdataset_current(rrset
, ¤t
);
306 if (dns_rdata_compare(rdata
, ¤t
) == 0)
308 dns_rdata_reset(¤t
);
309 result
= dns_rdataset_next(rrset
);
315 * Check that the address RRsets match.
317 * Note we don't complain about missing glue records.
321 check_address_records(dns_view_t
*view
, dns_db_t
*hints
, dns_db_t
*db
,
322 dns_name_t
*name
, isc_stdtime_t now
)
324 isc_result_t hresult
, rresult
, result
;
325 dns_rdataset_t hintrrset
, rootrrset
;
326 dns_rdata_t rdata
= DNS_RDATA_INIT
;
327 dns_name_t
*foundname
;
328 dns_fixedname_t fixed
;
330 dns_rdataset_init(&hintrrset
);
331 dns_rdataset_init(&rootrrset
);
332 dns_fixedname_init(&fixed
);
333 foundname
= dns_fixedname_name(&fixed
);
335 hresult
= dns_db_find(hints
, name
, NULL
, dns_rdatatype_a
, 0,
336 now
, NULL
, foundname
, &hintrrset
, NULL
);
337 rresult
= dns_db_find(db
, name
, NULL
, dns_rdatatype_a
,
338 DNS_DBFIND_GLUEOK
, now
, NULL
, foundname
,
340 if (hresult
== ISC_R_SUCCESS
&&
341 (rresult
== ISC_R_SUCCESS
|| rresult
== DNS_R_GLUE
)) {
342 result
= dns_rdataset_first(&rootrrset
);
343 while (result
== ISC_R_SUCCESS
) {
344 dns_rdata_reset(&rdata
);
345 dns_rdataset_current(&rootrrset
, &rdata
);
346 if (!inrrset(&hintrrset
, &rdata
))
347 report(view
, name
, ISC_TRUE
, &rdata
);
348 result
= dns_rdataset_next(&rootrrset
);
350 result
= dns_rdataset_first(&hintrrset
);
351 while (result
== ISC_R_SUCCESS
) {
352 dns_rdata_reset(&rdata
);
353 dns_rdataset_current(&hintrrset
, &rdata
);
354 if (!inrrset(&rootrrset
, &rdata
))
355 report(view
, name
, ISC_FALSE
, &rdata
);
356 result
= dns_rdataset_next(&hintrrset
);
359 if (hresult
== ISC_R_NOTFOUND
&&
360 (rresult
== ISC_R_SUCCESS
|| rresult
== DNS_R_GLUE
)) {
361 result
= dns_rdataset_first(&rootrrset
);
362 while (result
== ISC_R_SUCCESS
) {
363 dns_rdata_reset(&rdata
);
364 dns_rdataset_current(&rootrrset
, &rdata
);
365 report(view
, name
, ISC_TRUE
, &rdata
);
366 result
= dns_rdataset_next(&rootrrset
);
369 if (dns_rdataset_isassociated(&rootrrset
))
370 dns_rdataset_disassociate(&rootrrset
);
371 if (dns_rdataset_isassociated(&hintrrset
))
372 dns_rdataset_disassociate(&hintrrset
);
375 * Check AAAA records.
377 hresult
= dns_db_find(hints
, name
, NULL
, dns_rdatatype_aaaa
, 0,
378 now
, NULL
, foundname
, &hintrrset
, NULL
);
379 rresult
= dns_db_find(db
, name
, NULL
, dns_rdatatype_aaaa
,
380 DNS_DBFIND_GLUEOK
, now
, NULL
, foundname
,
382 if (hresult
== ISC_R_SUCCESS
&&
383 (rresult
== ISC_R_SUCCESS
|| rresult
== DNS_R_GLUE
)) {
384 result
= dns_rdataset_first(&rootrrset
);
385 while (result
== ISC_R_SUCCESS
) {
386 dns_rdata_reset(&rdata
);
387 dns_rdataset_current(&rootrrset
, &rdata
);
388 if (!inrrset(&hintrrset
, &rdata
))
389 report(view
, name
, ISC_TRUE
, &rdata
);
390 dns_rdata_reset(&rdata
);
391 result
= dns_rdataset_next(&rootrrset
);
393 result
= dns_rdataset_first(&hintrrset
);
394 while (result
== ISC_R_SUCCESS
) {
395 dns_rdata_reset(&rdata
);
396 dns_rdataset_current(&hintrrset
, &rdata
);
397 if (!inrrset(&rootrrset
, &rdata
))
398 report(view
, name
, ISC_FALSE
, &rdata
);
399 dns_rdata_reset(&rdata
);
400 result
= dns_rdataset_next(&hintrrset
);
403 if (hresult
== ISC_R_NOTFOUND
&&
404 (rresult
== ISC_R_SUCCESS
|| rresult
== DNS_R_GLUE
)) {
405 result
= dns_rdataset_first(&rootrrset
);
406 while (result
== ISC_R_SUCCESS
) {
407 dns_rdata_reset(&rdata
);
408 dns_rdataset_current(&rootrrset
, &rdata
);
409 report(view
, name
, ISC_TRUE
, &rdata
);
410 dns_rdata_reset(&rdata
);
411 result
= dns_rdataset_next(&rootrrset
);
414 if (dns_rdataset_isassociated(&rootrrset
))
415 dns_rdataset_disassociate(&rootrrset
);
416 if (dns_rdataset_isassociated(&hintrrset
))
417 dns_rdataset_disassociate(&hintrrset
);
421 dns_root_checkhints(dns_view_t
*view
, dns_db_t
*hints
, dns_db_t
*db
) {
423 dns_rdata_t rdata
= DNS_RDATA_INIT
;
425 dns_rdataset_t hintns
, rootns
;
426 const char *viewname
= "", *sep
= "";
429 dns_fixedname_t fixed
;
431 REQUIRE(hints
!= NULL
);
433 REQUIRE(view
!= NULL
);
435 isc_stdtime_get(&now
);
437 if (strcmp(view
->name
, "_bind") != 0 &&
438 strcmp(view
->name
, "_default") != 0) {
439 viewname
= view
->name
;
443 dns_rdataset_init(&hintns
);
444 dns_rdataset_init(&rootns
);
445 dns_fixedname_init(&fixed
);
446 name
= dns_fixedname_name(&fixed
);
448 result
= dns_db_find(hints
, dns_rootname
, NULL
, dns_rdatatype_ns
, 0,
449 now
, NULL
, name
, &hintns
, NULL
);
450 if (result
!= ISC_R_SUCCESS
) {
451 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
452 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
453 "checkhints%s%s: unable to get root NS rrset "
454 "from hints: %s", sep
, viewname
,
455 dns_result_totext(result
));
459 result
= dns_db_find(db
, dns_rootname
, NULL
, dns_rdatatype_ns
, 0,
460 now
, NULL
, name
, &rootns
, NULL
);
461 if (result
!= ISC_R_SUCCESS
) {
462 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
463 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
464 "checkhints%s%s: unable to get root NS rrset "
465 "from cache: %s", sep
, viewname
,
466 dns_result_totext(result
));
471 * Look for missing root NS names.
473 result
= dns_rdataset_first(&rootns
);
474 while (result
== ISC_R_SUCCESS
) {
475 dns_rdataset_current(&rootns
, &rdata
);
476 result
= dns_rdata_tostruct(&rdata
, &ns
, NULL
);
477 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
478 result
= in_rootns(&hintns
, &ns
.name
);
479 if (result
!= ISC_R_SUCCESS
) {
480 char namebuf
[DNS_NAME_FORMATSIZE
];
481 /* missing from hints */
482 dns_name_format(&ns
.name
, namebuf
, sizeof(namebuf
));
483 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
484 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
485 "checkhints%s%s: unable to find root "
486 "NS '%s' in hints", sep
, viewname
,
489 check_address_records(view
, hints
, db
, &ns
.name
, now
);
490 dns_rdata_reset(&rdata
);
491 result
= dns_rdataset_next(&rootns
);
493 if (result
!= ISC_R_NOMORE
) {
498 * Look for extra root NS names.
500 result
= dns_rdataset_first(&hintns
);
501 while (result
== ISC_R_SUCCESS
) {
502 dns_rdataset_current(&hintns
, &rdata
);
503 result
= dns_rdata_tostruct(&rdata
, &ns
, NULL
);
504 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
505 result
= in_rootns(&rootns
, &ns
.name
);
506 if (result
!= ISC_R_SUCCESS
) {
507 char namebuf
[DNS_NAME_FORMATSIZE
];
508 /* extra entry in hints */
509 dns_name_format(&ns
.name
, namebuf
, sizeof(namebuf
));
510 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
511 DNS_LOGMODULE_HINTS
, ISC_LOG_WARNING
,
512 "checkhints%s%s: extra NS '%s' in hints",
513 sep
, viewname
, namebuf
);
515 dns_rdata_reset(&rdata
);
516 result
= dns_rdataset_next(&hintns
);
518 if (result
!= ISC_R_NOMORE
) {
523 if (dns_rdataset_isassociated(&rootns
))
524 dns_rdataset_disassociate(&rootns
);
525 if (dns_rdataset_isassociated(&hintns
))
526 dns_rdataset_disassociate(&hintns
);