Ignore machine-check MSRs
[freebsd-src/fkvm-freebsd.git] / contrib / bind9 / bin / check / check-tool.c
blob1f5f1cdc985b1608adfbff152445224539d6a491
1 /*
2 * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-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: check-tool.c,v 1.10.18.18 2007/09/13 05:04:01 each Exp $ */
20 /*! \file */
22 #include <config.h>
24 #include <stdio.h>
26 #include "check-tool.h"
27 #include <isc/util.h>
29 #include <isc/buffer.h>
30 #include <isc/log.h>
31 #include <isc/net.h>
32 #include <isc/netdb.h>
33 #include <isc/region.h>
34 #include <isc/stdio.h>
35 #include <isc/string.h>
36 #include <isc/types.h>
38 #include <dns/fixedname.h>
39 #include <dns/log.h>
40 #include <dns/name.h>
41 #include <dns/rdata.h>
42 #include <dns/rdataclass.h>
43 #include <dns/rdataset.h>
44 #include <dns/types.h>
45 #include <dns/zone.h>
47 #include <isccfg/log.h>
49 #ifdef HAVE_ADDRINFO
50 #ifdef HAVE_GETADDRINFO
51 #ifdef HAVE_GAISTRERROR
52 #define USE_GETADDRINFO
53 #endif
54 #endif
55 #endif
57 #define CHECK(r) \
58 do { \
59 result = (r); \
60 if (result != ISC_R_SUCCESS) \
61 goto cleanup; \
62 } while (0)
64 static const char *dbtype[] = { "rbt" };
66 int debug = 0;
67 isc_boolean_t nomerge = ISC_TRUE;
68 isc_boolean_t docheckmx = ISC_TRUE;
69 isc_boolean_t dochecksrv = ISC_TRUE;
70 isc_boolean_t docheckns = ISC_TRUE;
71 unsigned int zone_options = DNS_ZONEOPT_CHECKNS |
72 DNS_ZONEOPT_CHECKMX |
73 DNS_ZONEOPT_MANYERRORS |
74 DNS_ZONEOPT_CHECKNAMES |
75 DNS_ZONEOPT_CHECKINTEGRITY |
76 DNS_ZONEOPT_CHECKWILDCARD |
77 DNS_ZONEOPT_WARNMXCNAME |
78 DNS_ZONEOPT_WARNSRVCNAME;
81 * This needs to match the list in bin/named/log.c.
83 static isc_logcategory_t categories[] = {
84 { "", 0 },
85 { "client", 0 },
86 { "network", 0 },
87 { "update", 0 },
88 { "queries", 0 },
89 { "unmatched", 0 },
90 { "update-security", 0 },
91 { NULL, 0 }
94 static isc_boolean_t
95 checkns(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner,
96 dns_rdataset_t *a, dns_rdataset_t *aaaa)
98 #ifdef USE_GETADDRINFO
99 dns_rdataset_t *rdataset;
100 dns_rdata_t rdata = DNS_RDATA_INIT;
101 struct addrinfo hints, *ai, *cur;
102 char namebuf[DNS_NAME_FORMATSIZE + 1];
103 char ownerbuf[DNS_NAME_FORMATSIZE];
104 char addrbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
105 isc_boolean_t answer = ISC_TRUE;
106 isc_boolean_t match;
107 const char *type;
108 void *ptr = NULL;
109 int result;
111 REQUIRE(a == NULL || !dns_rdataset_isassociated(a) ||
112 a->type == dns_rdatatype_a);
113 REQUIRE(aaaa == NULL || !dns_rdataset_isassociated(aaaa) ||
114 aaaa->type == dns_rdatatype_aaaa);
115 memset(&hints, 0, sizeof(hints));
116 hints.ai_flags = AI_CANONNAME;
117 hints.ai_family = PF_UNSPEC;
118 hints.ai_socktype = SOCK_STREAM;
119 hints.ai_protocol = IPPROTO_TCP;
121 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
123 * Turn off search.
125 if (dns_name_countlabels(name) > 1U)
126 strcat(namebuf, ".");
127 dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
129 result = getaddrinfo(namebuf, NULL, &hints, &ai);
130 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
131 switch (result) {
132 case 0:
134 * Work around broken getaddrinfo() implementations that
135 * fail to set ai_canonname on first entry.
137 cur = ai;
138 while (cur != NULL && cur->ai_canonname == NULL &&
139 cur->ai_next != NULL)
140 cur = cur->ai_next;
141 if (cur != NULL && cur->ai_canonname != NULL &&
142 strcasecmp(ai->ai_canonname, namebuf) != 0) {
143 dns_zone_log(zone, ISC_LOG_ERROR,
144 "%s/NS '%s' (out of zone) "
145 "is a CNAME (illegal)",
146 ownerbuf, namebuf);
147 /* XXX950 make fatal for 9.5.0 */
148 /* answer = ISC_FALSE; */
150 break;
151 case EAI_NONAME:
152 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
153 case EAI_NODATA:
154 #endif
155 dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' (out of zone) "
156 "has no addresses records (A or AAAA)",
157 ownerbuf, namebuf);
158 /* XXX950 make fatal for 9.5.0 */
159 return (ISC_TRUE);
161 default:
162 dns_zone_log(zone, ISC_LOG_WARNING,
163 "getaddrinfo(%s) failed: %s",
164 namebuf, gai_strerror(result));
165 return (ISC_TRUE);
167 if (a == NULL || aaaa == NULL)
168 return (answer);
170 * Check that all glue records really exist.
172 if (!dns_rdataset_isassociated(a))
173 goto checkaaaa;
174 result = dns_rdataset_first(a);
175 while (result == ISC_R_SUCCESS) {
176 dns_rdataset_current(a, &rdata);
177 match = ISC_FALSE;
178 for (cur = ai; cur != NULL; cur = cur->ai_next) {
179 if (cur->ai_family != AF_INET)
180 continue;
181 ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
182 if (memcmp(ptr, rdata.data, rdata.length) == 0) {
183 match = ISC_TRUE;
184 break;
187 if (!match) {
188 dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
189 "extra GLUE A record (%s)",
190 ownerbuf, namebuf,
191 inet_ntop(AF_INET, rdata.data,
192 addrbuf, sizeof(addrbuf)));
193 /* XXX950 make fatal for 9.5.0 */
194 /* answer = ISC_FALSE; */
196 dns_rdata_reset(&rdata);
197 result = dns_rdataset_next(a);
200 checkaaaa:
201 if (!dns_rdataset_isassociated(aaaa))
202 goto checkmissing;
203 result = dns_rdataset_first(aaaa);
204 while (result == ISC_R_SUCCESS) {
205 dns_rdataset_current(aaaa, &rdata);
206 match = ISC_FALSE;
207 for (cur = ai; cur != NULL; cur = cur->ai_next) {
208 if (cur->ai_family != AF_INET6)
209 continue;
210 ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
211 if (memcmp(ptr, rdata.data, rdata.length) == 0) {
212 match = ISC_TRUE;
213 break;
216 if (!match) {
217 dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
218 "extra GLUE AAAA record (%s)",
219 ownerbuf, namebuf,
220 inet_ntop(AF_INET6, rdata.data,
221 addrbuf, sizeof(addrbuf)));
222 /* XXX950 make fatal for 9.5.0. */
223 /* answer = ISC_FALSE; */
225 dns_rdata_reset(&rdata);
226 result = dns_rdataset_next(aaaa);
229 checkmissing:
231 * Check that all addresses appear in the glue.
233 for (cur = ai; cur != NULL; cur = cur->ai_next) {
234 switch (cur->ai_family) {
235 case AF_INET:
236 rdataset = a;
237 ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
238 type = "A";
239 break;
240 case AF_INET6:
241 rdataset = aaaa;
242 ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
243 type = "AAAA";
244 break;
245 default:
246 continue;
248 match = ISC_FALSE;
249 if (dns_rdataset_isassociated(rdataset))
250 result = dns_rdataset_first(rdataset);
251 else
252 result = ISC_R_FAILURE;
253 while (result == ISC_R_SUCCESS && !match) {
254 dns_rdataset_current(rdataset, &rdata);
255 if (memcmp(ptr, rdata.data, rdata.length) == 0)
256 match = ISC_TRUE;
257 dns_rdata_reset(&rdata);
258 result = dns_rdataset_next(rdataset);
260 if (!match) {
261 dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
262 "missing GLUE %s record (%s)",
263 ownerbuf, namebuf, type,
264 inet_ntop(cur->ai_family, ptr,
265 addrbuf, sizeof(addrbuf)));
266 /* XXX950 make fatal for 9.5.0. */
267 /* answer = ISC_FALSE; */
270 freeaddrinfo(ai);
271 return (answer);
272 #else
273 return (ISC_TRUE);
274 #endif
277 static isc_boolean_t
278 checkmx(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
279 #ifdef USE_GETADDRINFO
280 struct addrinfo hints, *ai, *cur;
281 char namebuf[DNS_NAME_FORMATSIZE + 1];
282 char ownerbuf[DNS_NAME_FORMATSIZE];
283 int result;
284 int level = ISC_LOG_ERROR;
285 isc_boolean_t answer = ISC_TRUE;
287 memset(&hints, 0, sizeof(hints));
288 hints.ai_flags = AI_CANONNAME;
289 hints.ai_family = PF_UNSPEC;
290 hints.ai_socktype = SOCK_STREAM;
291 hints.ai_protocol = IPPROTO_TCP;
293 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
295 * Turn off search.
297 if (dns_name_countlabels(name) > 1U)
298 strcat(namebuf, ".");
299 dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
301 result = getaddrinfo(namebuf, NULL, &hints, &ai);
302 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
303 switch (result) {
304 case 0:
306 * Work around broken getaddrinfo() implementations that
307 * fail to set ai_canonname on first entry.
309 cur = ai;
310 while (cur != NULL && cur->ai_canonname == NULL &&
311 cur->ai_next != NULL)
312 cur = cur->ai_next;
313 if (cur != NULL && cur->ai_canonname != NULL &&
314 strcasecmp(cur->ai_canonname, namebuf) != 0) {
315 if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0)
316 level = ISC_LOG_WARNING;
317 if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) {
318 dns_zone_log(zone, ISC_LOG_WARNING,
319 "%s/MX '%s' (out of zone) "
320 "is a CNAME (illegal)",
321 ownerbuf, namebuf);
322 if (level == ISC_LOG_ERROR)
323 answer = ISC_FALSE;
326 freeaddrinfo(ai);
327 return (answer);
329 case EAI_NONAME:
330 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
331 case EAI_NODATA:
332 #endif
333 dns_zone_log(zone, ISC_LOG_ERROR, "%s/MX '%s' (out of zone) "
334 "has no addresses records (A or AAAA)",
335 ownerbuf, namebuf);
336 /* XXX950 make fatal for 9.5.0. */
337 return (ISC_TRUE);
339 default:
340 dns_zone_log(zone, ISC_LOG_WARNING,
341 "getaddrinfo(%s) failed: %s",
342 namebuf, gai_strerror(result));
343 return (ISC_TRUE);
345 #else
346 return (ISC_TRUE);
347 #endif
350 static isc_boolean_t
351 checksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
352 #ifdef USE_GETADDRINFO
353 struct addrinfo hints, *ai, *cur;
354 char namebuf[DNS_NAME_FORMATSIZE + 1];
355 char ownerbuf[DNS_NAME_FORMATSIZE];
356 int result;
357 int level = ISC_LOG_ERROR;
358 isc_boolean_t answer = ISC_TRUE;
360 memset(&hints, 0, sizeof(hints));
361 hints.ai_flags = AI_CANONNAME;
362 hints.ai_family = PF_UNSPEC;
363 hints.ai_socktype = SOCK_STREAM;
364 hints.ai_protocol = IPPROTO_TCP;
366 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
368 * Turn off search.
370 if (dns_name_countlabels(name) > 1U)
371 strcat(namebuf, ".");
372 dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
374 result = getaddrinfo(namebuf, NULL, &hints, &ai);
375 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
376 switch (result) {
377 case 0:
379 * Work around broken getaddrinfo() implementations that
380 * fail to set ai_canonname on first entry.
382 cur = ai;
383 while (cur != NULL && cur->ai_canonname == NULL &&
384 cur->ai_next != NULL)
385 cur = cur->ai_next;
386 if (cur != NULL && cur->ai_canonname != NULL &&
387 strcasecmp(cur->ai_canonname, namebuf) != 0) {
388 if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0)
389 level = ISC_LOG_WARNING;
390 if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) {
391 dns_zone_log(zone, level,
392 "%s/SRV '%s' (out of zone) "
393 "is a CNAME (illegal)",
394 ownerbuf, namebuf);
395 if (level == ISC_LOG_ERROR)
396 answer = ISC_FALSE;
399 freeaddrinfo(ai);
400 return (answer);
402 case EAI_NONAME:
403 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
404 case EAI_NODATA:
405 #endif
406 dns_zone_log(zone, ISC_LOG_ERROR, "%s/SRV '%s' (out of zone) "
407 "has no addresses records (A or AAAA)",
408 ownerbuf, namebuf);
409 /* XXX950 make fatal for 9.5.0. */
410 return (ISC_TRUE);
412 default:
413 dns_zone_log(zone, ISC_LOG_WARNING,
414 "getaddrinfo(%s) failed: %s",
415 namebuf, gai_strerror(result));
416 return (ISC_TRUE);
418 #else
419 return (ISC_TRUE);
420 #endif
423 isc_result_t
424 setup_logging(isc_mem_t *mctx, isc_log_t **logp) {
425 isc_logdestination_t destination;
426 isc_logconfig_t *logconfig = NULL;
427 isc_log_t *log = NULL;
429 RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS);
430 isc_log_registercategories(log, categories);
431 isc_log_setcontext(log);
432 dns_log_init(log);
433 dns_log_setcontext(log);
434 cfg_log_init(log);
436 destination.file.stream = stdout;
437 destination.file.name = NULL;
438 destination.file.versions = ISC_LOG_ROLLNEVER;
439 destination.file.maximum_size = 0;
440 RUNTIME_CHECK(isc_log_createchannel(logconfig, "stderr",
441 ISC_LOG_TOFILEDESC,
442 ISC_LOG_DYNAMIC,
443 &destination, 0) == ISC_R_SUCCESS);
444 RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr",
445 NULL, NULL) == ISC_R_SUCCESS);
447 *logp = log;
448 return (ISC_R_SUCCESS);
451 /*% load the zone */
452 isc_result_t
453 load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
454 dns_masterformat_t fileformat, const char *classname,
455 dns_zone_t **zonep)
457 isc_result_t result;
458 dns_rdataclass_t rdclass;
459 isc_textregion_t region;
460 isc_buffer_t buffer;
461 dns_fixedname_t fixorigin;
462 dns_name_t *origin;
463 dns_zone_t *zone = NULL;
465 REQUIRE(zonep == NULL || *zonep == NULL);
467 if (debug)
468 fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
469 zonename, filename, classname);
471 CHECK(dns_zone_create(&zone, mctx));
473 dns_zone_settype(zone, dns_zone_master);
475 isc_buffer_init(&buffer, zonename, strlen(zonename));
476 isc_buffer_add(&buffer, strlen(zonename));
477 dns_fixedname_init(&fixorigin);
478 origin = dns_fixedname_name(&fixorigin);
479 CHECK(dns_name_fromtext(origin, &buffer, dns_rootname,
480 ISC_FALSE, NULL));
481 CHECK(dns_zone_setorigin(zone, origin));
482 CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype));
483 CHECK(dns_zone_setfile2(zone, filename, fileformat));
485 DE_CONST(classname, region.base);
486 region.length = strlen(classname);
487 CHECK(dns_rdataclass_fromtext(&rdclass, &region));
489 dns_zone_setclass(zone, rdclass);
490 dns_zone_setoption(zone, zone_options, ISC_TRUE);
491 dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);
492 if (docheckmx)
493 dns_zone_setcheckmx(zone, checkmx);
494 if (docheckns)
495 dns_zone_setcheckns(zone, checkns);
496 if (dochecksrv)
497 dns_zone_setchecksrv(zone, checksrv);
499 CHECK(dns_zone_load(zone));
500 if (zonep != NULL) {
501 *zonep = zone;
502 zone = NULL;
505 cleanup:
506 if (zone != NULL)
507 dns_zone_detach(&zone);
508 return (result);
511 /*% dump the zone */
512 isc_result_t
513 dump_zone(const char *zonename, dns_zone_t *zone, const char *filename,
514 dns_masterformat_t fileformat, const dns_master_style_t *style)
516 isc_result_t result;
517 FILE *output = stdout;
519 if (debug) {
520 if (filename != NULL)
521 fprintf(stderr, "dumping \"%s\" to \"%s\"\n",
522 zonename, filename);
523 else
524 fprintf(stderr, "dumping \"%s\"\n", zonename);
527 if (filename != NULL) {
528 result = isc_stdio_open(filename, "w+", &output);
530 if (result != ISC_R_SUCCESS) {
531 fprintf(stderr, "could not open output "
532 "file \"%s\" for writing\n", filename);
533 return (ISC_R_FAILURE);
537 result = dns_zone_dumptostream2(zone, output, fileformat, style);
539 if (filename != NULL)
540 (void)isc_stdio_close(output);
542 return (result);