1/* $NetBSD$ */ 2 3/* 4 * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2003 Internet Software Consortium. 6 * 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. 10 * 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. 18 */ 19 20/* Id: named-checkzone.c,v 1.65 2011/12/22 17:29:22 each Exp */ 21 22/*! \file */ 23 24#include <config.h> 25 26#include <stdlib.h> 27 28#include <isc/app.h> 29#include <isc/commandline.h> 30#include <isc/dir.h> 31#include <isc/entropy.h> 32#include <isc/hash.h> 33#include <isc/log.h> 34#include <isc/mem.h> 35#include <isc/socket.h> 36#include <isc/string.h> 37#include <isc/task.h> 38#include <isc/timer.h> 39#include <isc/util.h> 40 41#include <dns/db.h> 42#include <dns/fixedname.h> 43#include <dns/log.h> 44#include <dns/master.h> 45#include <dns/masterdump.h> 46#include <dns/name.h> 47#include <dns/rdataclass.h> 48#include <dns/rdataset.h> 49#include <dns/result.h> 50#include <dns/types.h> 51#include <dns/zone.h> 52 53#include "check-tool.h" 54 55static int quiet = 0; 56static isc_mem_t *mctx = NULL; 57static isc_entropy_t *ectx = NULL; 58dns_zone_t *zone = NULL; 59dns_zonetype_t zonetype = dns_zone_master; 60static int dumpzone = 0; 61static const char *output_filename; 62static char *prog_name = NULL; 63static const dns_master_style_t *outputstyle = NULL; 64static enum { progmode_check, progmode_compile } progmode; 65 66#define ERRRET(result, function) \ 67 do { \ 68 if (result != ISC_R_SUCCESS) { \ 69 if (!quiet) \ 70 fprintf(stderr, "%s() returned %s\n", \ 71 function, dns_result_totext(result)); \ 72 return (result); \ 73 } \ 74 } while (/*CONSTCOND*/0) 75 76ISC_PLATFORM_NORETURN_PRE static void 77usage(void) ISC_PLATFORM_NORETURN_POST; 78 79static void 80usage(void) { 81 fprintf(stderr, 82 "usage: %s [-djqvD] [-c class] " 83 "[-f inputformat] [-F outputformat] " 84 "[-t directory] [-w directory] [-k (ignore|warn|fail)] " 85 "[-n (ignore|warn|fail)] [-m (ignore|warn|fail)] " 86 "[-r (ignore|warn|fail)] " 87 "[-i (full|full-sibling|local|local-sibling|none)] " 88 "[-M (ignore|warn|fail)] [-S (ignore|warn|fail)] " 89 "[-W (ignore|warn)] " 90 "%s zonename filename\n", 91 prog_name, 92 progmode == progmode_check ? "[-o filename]" : "-o filename"); 93 exit(1); 94} 95 96static void 97destroy(void) { 98 if (zone != NULL) 99 dns_zone_detach(&zone); 100 dns_name_destroy(); 101} 102 103/*% main processing routine */ 104int 105main(int argc, char **argv) { 106 int c; 107 char *origin = NULL; 108 char *filename = NULL; 109 isc_log_t *lctx = NULL; 110 isc_result_t result; 111 char classname_in[] = "IN"; 112 char *classname = classname_in; 113 const char *workdir = NULL; 114 const char *inputformatstr = NULL; 115 const char *outputformatstr = NULL; 116 dns_masterformat_t inputformat = dns_masterformat_text; 117 dns_masterformat_t outputformat = dns_masterformat_text; 118 dns_masterrawheader_t header; 119 isc_uint32_t rawversion = 1, serialnum = 0; 120 isc_boolean_t snset = ISC_FALSE; 121 isc_boolean_t logdump = ISC_FALSE; 122 FILE *errout = stdout; 123 char *endp; 124 125 outputstyle = &dns_master_style_full; 126 127 prog_name = strrchr(argv[0], '/'); 128 if (prog_name == NULL) 129 prog_name = strrchr(argv[0], '\\'); 130 if (prog_name != NULL) 131 prog_name++; 132 else 133 prog_name = argv[0]; 134 /* 135 * Libtool doesn't preserve the program name prior to final 136 * installation. Remove the libtool prefix ("lt-"). 137 */ 138 if (strncmp(prog_name, "lt-", 3) == 0) 139 prog_name += 3; 140 141#define PROGCMP(X) \ 142 (strcasecmp(prog_name, X) == 0 || strcasecmp(prog_name, X ".exe") == 0) 143 144 if (PROGCMP("named-checkzone")) 145 progmode = progmode_check; 146 else if (PROGCMP("named-compilezone")) 147 progmode = progmode_compile; 148 else 149 INSIST(0); 150 151 /* Compilation specific defaults */ 152 if (progmode == progmode_compile) { 153 zone_options |= (DNS_ZONEOPT_CHECKNS | 154 DNS_ZONEOPT_FATALNS | 155 DNS_ZONEOPT_CHECKDUPRR | 156 DNS_ZONEOPT_CHECKNAMES | 157 DNS_ZONEOPT_CHECKNAMESFAIL | 158 DNS_ZONEOPT_CHECKWILDCARD); 159 } else 160 zone_options |= DNS_ZONEOPT_CHECKDUPRR; 161 162#define ARGCMP(X) (strcmp(isc_commandline_argument, X) == 0) 163 164 isc_commandline_errprint = ISC_FALSE; 165 166 while ((c = isc_commandline_parse(argc, argv, 167 "c:df:hi:jk:L:m:n:qr:s:t:o:vw:DF:M:S:W:")) 168 != EOF) { 169 switch (c) { 170 case 'c': 171 classname = isc_commandline_argument; 172 break; 173 174 case 'd': 175 debug++; 176 break; 177 178 case 'i': 179 if (ARGCMP("full")) { 180 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY | 181 DNS_ZONEOPT_CHECKSIBLING; 182 docheckmx = ISC_TRUE; 183 docheckns = ISC_TRUE; 184 dochecksrv = ISC_TRUE; 185 } else if (ARGCMP("full-sibling")) { 186 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; 187 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; 188 docheckmx = ISC_TRUE; 189 docheckns = ISC_TRUE; 190 dochecksrv = ISC_TRUE; 191 } else if (ARGCMP("local")) { 192 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; 193 zone_options |= DNS_ZONEOPT_CHECKSIBLING; 194 docheckmx = ISC_FALSE; 195 docheckns = ISC_FALSE; 196 dochecksrv = ISC_FALSE; 197 } else if (ARGCMP("local-sibling")) { 198 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; 199 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; 200 docheckmx = ISC_FALSE; 201 docheckns = ISC_FALSE; 202 dochecksrv = ISC_FALSE; 203 } else if (ARGCMP("none")) { 204 zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY; 205 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; 206 docheckmx = ISC_FALSE; 207 docheckns = ISC_FALSE; 208 dochecksrv = ISC_FALSE; 209 } else { 210 fprintf(stderr, "invalid argument to -i: %s\n", 211 isc_commandline_argument); 212 exit(1); 213 } 214 break; 215 216 case 'f': 217 inputformatstr = isc_commandline_argument; 218 break; 219 220 case 'F': 221 outputformatstr = isc_commandline_argument; 222 break; 223 224 case 'j': 225 nomerge = ISC_FALSE; 226 break; 227 228 case 'k': 229 if (ARGCMP("warn")) { 230 zone_options |= DNS_ZONEOPT_CHECKNAMES; 231 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL; 232 } else if (ARGCMP("fail")) { 233 zone_options |= DNS_ZONEOPT_CHECKNAMES | 234 DNS_ZONEOPT_CHECKNAMESFAIL; 235 } else if (ARGCMP("ignore")) { 236 zone_options &= ~(DNS_ZONEOPT_CHECKNAMES | 237 DNS_ZONEOPT_CHECKNAMESFAIL); 238 } else { 239 fprintf(stderr, "invalid argument to -k: %s\n", 240 isc_commandline_argument); 241 exit(1); 242 } 243 break; 244 245 case 'L': 246 snset = ISC_TRUE; 247 endp = NULL; 248 serialnum = strtol(isc_commandline_argument, &endp, 0); 249 if (*endp != '\0') { 250 fprintf(stderr, "source serial number " 251 "must be numeric"); 252 exit(1); 253 } 254 break; 255 256 case 'n': 257 if (ARGCMP("ignore")) { 258 zone_options &= ~(DNS_ZONEOPT_CHECKNS| 259 DNS_ZONEOPT_FATALNS); 260 } else if (ARGCMP("warn")) { 261 zone_options |= DNS_ZONEOPT_CHECKNS; 262 zone_options &= ~DNS_ZONEOPT_FATALNS; 263 } else if (ARGCMP("fail")) { 264 zone_options |= DNS_ZONEOPT_CHECKNS| 265 DNS_ZONEOPT_FATALNS; 266 } else { 267 fprintf(stderr, "invalid argument to -n: %s\n", 268 isc_commandline_argument); 269 exit(1); 270 } 271 break; 272 273 case 'm': 274 if (ARGCMP("warn")) { 275 zone_options |= DNS_ZONEOPT_CHECKMX; 276 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; 277 } else if (ARGCMP("fail")) { 278 zone_options |= DNS_ZONEOPT_CHECKMX | 279 DNS_ZONEOPT_CHECKMXFAIL; 280 } else if (ARGCMP("ignore")) { 281 zone_options &= ~(DNS_ZONEOPT_CHECKMX | 282 DNS_ZONEOPT_CHECKMXFAIL); 283 } else { 284 fprintf(stderr, "invalid argument to -m: %s\n", 285 isc_commandline_argument); 286 exit(1); 287 } 288 break; 289 290 case 'o': 291 output_filename = isc_commandline_argument; 292 break; 293 294 case 'q': 295 quiet++; 296 break; 297 298 case 'r': 299 if (ARGCMP("warn")) { 300 zone_options |= DNS_ZONEOPT_CHECKDUPRR; 301 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL; 302 } else if (ARGCMP("fail")) { 303 zone_options |= DNS_ZONEOPT_CHECKDUPRR | 304 DNS_ZONEOPT_CHECKDUPRRFAIL; 305 } else if (ARGCMP("ignore")) { 306 zone_options &= ~(DNS_ZONEOPT_CHECKDUPRR | 307 DNS_ZONEOPT_CHECKDUPRRFAIL); 308 } else { 309 fprintf(stderr, "invalid argument to -r: %s\n", 310 isc_commandline_argument); 311 exit(1); 312 } 313 break; 314 315 case 's': 316 if (ARGCMP("full")) 317 outputstyle = &dns_master_style_full; 318 else if (ARGCMP("relative")) { 319 outputstyle = &dns_master_style_default; 320 } else { 321 fprintf(stderr, 322 "unknown or unsupported style: %s\n", 323 isc_commandline_argument); 324 exit(1); 325 } 326 break; 327 328 case 't': 329 result = isc_dir_chroot(isc_commandline_argument); 330 if (result != ISC_R_SUCCESS) { 331 fprintf(stderr, "isc_dir_chroot: %s: %s\n", 332 isc_commandline_argument, 333 isc_result_totext(result)); 334 exit(1); 335 } 336 break; 337 338 case 'v': 339 printf(VERSION "\n"); 340 exit(0); 341 342 case 'w': 343 workdir = isc_commandline_argument; 344 break; 345 346 case 'D': 347 dumpzone++; 348 break; 349 350 case 'M': 351 if (ARGCMP("fail")) { 352 zone_options &= ~DNS_ZONEOPT_WARNMXCNAME; 353 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; 354 } else if (ARGCMP("warn")) { 355 zone_options |= DNS_ZONEOPT_WARNMXCNAME; 356 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; 357 } else if (ARGCMP("ignore")) { 358 zone_options |= DNS_ZONEOPT_WARNMXCNAME; 359 zone_options |= DNS_ZONEOPT_IGNOREMXCNAME; 360 } else { 361 fprintf(stderr, "invalid argument to -M: %s\n", 362 isc_commandline_argument); 363 exit(1); 364 } 365 break; 366 367 case 'S': 368 if (ARGCMP("fail")) { 369 zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME; 370 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; 371 } else if (ARGCMP("warn")) { 372 zone_options |= DNS_ZONEOPT_WARNSRVCNAME; 373 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; 374 } else if (ARGCMP("ignore")) { 375 zone_options |= DNS_ZONEOPT_WARNSRVCNAME; 376 zone_options |= DNS_ZONEOPT_IGNORESRVCNAME; 377 } else { 378 fprintf(stderr, "invalid argument to -S: %s\n", 379 isc_commandline_argument); 380 exit(1); 381 } 382 break; 383 384 case 'W': 385 if (ARGCMP("warn")) 386 zone_options |= DNS_ZONEOPT_CHECKWILDCARD; 387 else if (ARGCMP("ignore")) 388 zone_options &= ~DNS_ZONEOPT_CHECKWILDCARD; 389 break; 390 391 case '?': 392 if (isc_commandline_option != '?') 393 fprintf(stderr, "%s: invalid argument -%c\n", 394 prog_name, isc_commandline_option); 395 case 'h': 396 usage(); 397 398 default: 399 fprintf(stderr, "%s: unhandled option -%c\n", 400 prog_name, isc_commandline_option); 401 exit(1); 402 } 403 } 404 405 if (workdir != NULL) { 406 result = isc_dir_chdir(workdir); 407 if (result != ISC_R_SUCCESS) { 408 fprintf(stderr, "isc_dir_chdir: %s: %s\n", 409 workdir, isc_result_totext(result)); 410 exit(1); 411 } 412 } 413 414 if (inputformatstr != NULL) { 415 if (strcasecmp(inputformatstr, "text") == 0) 416 inputformat = dns_masterformat_text; 417 else if (strcasecmp(inputformatstr, "raw") == 0) 418 inputformat = dns_masterformat_raw; 419 else if (strncasecmp(inputformatstr, "raw=", 4) == 0) { 420 inputformat = dns_masterformat_raw; 421 fprintf(stderr, 422 "WARNING: input format raw, version ignored\n"); 423 } else { 424 fprintf(stderr, "unknown file format: %s\n", 425 inputformatstr); 426 exit(1); 427 } 428 } 429 430 if (outputformatstr != NULL) { 431 if (strcasecmp(outputformatstr, "text") == 0) { 432 outputformat = dns_masterformat_text; 433 } else if (strcasecmp(outputformatstr, "raw") == 0) { 434 outputformat = dns_masterformat_raw; 435 } else if (strncasecmp(outputformatstr, "raw=", 4) == 0) { 436 char *end; 437 438 outputformat = dns_masterformat_raw; 439 rawversion = strtol(outputformatstr + 4, &end, 10); 440 if (end == outputformatstr + 4 || *end != '\0' || 441 rawversion > 1U) { 442 fprintf(stderr, 443 "unknown raw format version\n"); 444 exit(1); 445 } 446 } else { 447 fprintf(stderr, "unknown file format: %s\n", 448 outputformatstr); 449 exit(1); 450 } 451 } 452 453 if (progmode == progmode_compile) { 454 dumpzone = 1; /* always dump */ 455 logdump = !quiet; 456 if (output_filename == NULL) { 457 fprintf(stderr, 458 "output file required, but not specified\n"); 459 usage(); 460 } 461 } 462 463 if (output_filename != NULL) 464 dumpzone = 1; 465 466 /* 467 * If we are outputing to stdout then send the informational 468 * output to stderr. 469 */ 470 if (dumpzone && 471 (output_filename == NULL || 472 strcmp(output_filename, "-") == 0 || 473 strcmp(output_filename, "/dev/fd/1") == 0 || 474 strcmp(output_filename, "/dev/stdout") == 0)) { 475 errout = stderr; 476 logdump = ISC_FALSE; 477 } 478 479 if (isc_commandline_index + 2 != argc) 480 usage(); 481 482#ifdef _WIN32 483 InitSockets(); 484#endif 485 486 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); 487 if (!quiet) 488 RUNTIME_CHECK(setup_logging(mctx, errout, &lctx) 489 == ISC_R_SUCCESS); 490 RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS); 491 RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE) 492 == ISC_R_SUCCESS); 493 494 dns_result_register(); 495 496 origin = argv[isc_commandline_index++]; 497 filename = argv[isc_commandline_index++]; 498 result = load_zone(mctx, origin, filename, inputformat, classname, 499 &zone); 500 501 if (snset) { 502 dns_master_initrawheader(&header); 503 header.flags = DNS_MASTERRAW_SOURCESERIALSET; 504 header.sourceserial = serialnum; 505 dns_zone_setrawdata(zone, &header); 506 } 507 508 if (result == ISC_R_SUCCESS && dumpzone) { 509 if (logdump) { 510 fprintf(errout, "dump zone to %s...", output_filename); 511 fflush(errout); 512 } 513 result = dump_zone(origin, zone, output_filename, 514 outputformat, outputstyle, rawversion); 515 if (logdump) 516 fprintf(errout, "done\n"); 517 } 518 519 if (!quiet && result == ISC_R_SUCCESS) 520 fprintf(errout, "OK\n"); 521 destroy(); 522 if (lctx != NULL) 523 isc_log_destroy(&lctx); 524 isc_hash_destroy(); 525 isc_entropy_detach(&ectx); 526 isc_mem_destroy(&mctx); 527#ifdef _WIN32 528 DestroySockets(); 529#endif 530 return ((result == ISC_R_SUCCESS) ? 0 : 1); 531} 532