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