named-checkzone.c revision 216175
1135446Strhodes/* 2216175Sdougb * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18216175Sdougb/* $Id: named-checkzone.c,v 1.51.34.4.10.2 2010/09/07 23:46:26 tbox Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <stdlib.h> 25135446Strhodes 26135446Strhodes#include <isc/app.h> 27135446Strhodes#include <isc/commandline.h> 28135446Strhodes#include <isc/dir.h> 29143731Sdougb#include <isc/entropy.h> 30143731Sdougb#include <isc/hash.h> 31135446Strhodes#include <isc/log.h> 32135446Strhodes#include <isc/mem.h> 33135446Strhodes#include <isc/socket.h> 34135446Strhodes#include <isc/string.h> 35135446Strhodes#include <isc/task.h> 36135446Strhodes#include <isc/timer.h> 37135446Strhodes#include <isc/util.h> 38135446Strhodes 39135446Strhodes#include <dns/db.h> 40135446Strhodes#include <dns/fixedname.h> 41135446Strhodes#include <dns/log.h> 42170222Sdougb#include <dns/masterdump.h> 43170222Sdougb#include <dns/name.h> 44135446Strhodes#include <dns/rdataclass.h> 45135446Strhodes#include <dns/rdataset.h> 46135446Strhodes#include <dns/result.h> 47170222Sdougb#include <dns/types.h> 48135446Strhodes#include <dns/zone.h> 49135446Strhodes 50135446Strhodes#include "check-tool.h" 51135446Strhodes 52135446Strhodesstatic int quiet = 0; 53135446Strhodesstatic isc_mem_t *mctx = NULL; 54143731Sdougbstatic isc_entropy_t *ectx = NULL; 55135446Strhodesdns_zone_t *zone = NULL; 56135446Strhodesdns_zonetype_t zonetype = dns_zone_master; 57135446Strhodesstatic int dumpzone = 0; 58135446Strhodesstatic const char *output_filename; 59170222Sdougbstatic char *prog_name = NULL; 60170222Sdougbstatic const dns_master_style_t *outputstyle = NULL; 61170222Sdougbstatic enum { progmode_check, progmode_compile } progmode; 62135446Strhodes 63135446Strhodes#define ERRRET(result, function) \ 64135446Strhodes do { \ 65135446Strhodes if (result != ISC_R_SUCCESS) { \ 66135446Strhodes if (!quiet) \ 67135446Strhodes fprintf(stderr, "%s() returned %s\n", \ 68135446Strhodes function, dns_result_totext(result)); \ 69135446Strhodes return (result); \ 70135446Strhodes } \ 71135446Strhodes } while (0) 72135446Strhodes 73135446Strhodesstatic void 74135446Strhodesusage(void) { 75135446Strhodes fprintf(stderr, 76204619Sdougb "usage: %s [-djqvD] [-c class] " 77170222Sdougb "[-f inputformat] [-F outputformat] " 78143731Sdougb "[-t directory] [-w directory] [-k (ignore|warn|fail)] " 79170222Sdougb "[-n (ignore|warn|fail)] [-m (ignore|warn|fail)] " 80186462Sdougb "[-i (full|full-sibling|local|local-sibling|none)] " 81186462Sdougb "[-M (ignore|warn|fail)] [-S (ignore|warn|fail)] " 82186462Sdougb "[-W (ignore|warn)] " 83204619Sdougb "%s zonename filename\n", 84204619Sdougb prog_name, 85204619Sdougb progmode == progmode_check ? "[-o filename]" : "{-o filename}"); 86135446Strhodes exit(1); 87135446Strhodes} 88135446Strhodes 89135446Strhodesstatic void 90135446Strhodesdestroy(void) { 91135446Strhodes if (zone != NULL) 92135446Strhodes dns_zone_detach(&zone); 93170222Sdougb dns_name_destroy(); 94135446Strhodes} 95135446Strhodes 96170222Sdougb/*% main processing routine */ 97135446Strhodesint 98135446Strhodesmain(int argc, char **argv) { 99135446Strhodes int c; 100135446Strhodes char *origin = NULL; 101135446Strhodes char *filename = NULL; 102135446Strhodes isc_log_t *lctx = NULL; 103135446Strhodes isc_result_t result; 104135446Strhodes char classname_in[] = "IN"; 105135446Strhodes char *classname = classname_in; 106135446Strhodes const char *workdir = NULL; 107170222Sdougb const char *inputformatstr = NULL; 108170222Sdougb const char *outputformatstr = NULL; 109170222Sdougb dns_masterformat_t inputformat = dns_masterformat_text; 110170222Sdougb dns_masterformat_t outputformat = dns_masterformat_text; 111193149Sdougb FILE *errout = stdout; 112135446Strhodes 113170222Sdougb outputstyle = &dns_master_style_full; 114170222Sdougb 115170222Sdougb prog_name = strrchr(argv[0], '/'); 116174187Sdougb if (prog_name == NULL) 117174187Sdougb prog_name = strrchr(argv[0], '\\'); 118170222Sdougb if (prog_name != NULL) 119170222Sdougb prog_name++; 120170222Sdougb else 121170222Sdougb prog_name = argv[0]; 122170222Sdougb /* 123170222Sdougb * Libtool doesn't preserve the program name prior to final 124170222Sdougb * installation. Remove the libtool prefix ("lt-"). 125170222Sdougb */ 126170222Sdougb if (strncmp(prog_name, "lt-", 3) == 0) 127170222Sdougb prog_name += 3; 128194995Sdougb 129194995Sdougb#define PROGCMP(X) \ 130194995Sdougb (strcasecmp(prog_name, X) == 0 || strcasecmp(prog_name, X ".exe") == 0) 131194995Sdougb 132194995Sdougb if (PROGCMP("named-checkzone")) 133170222Sdougb progmode = progmode_check; 134194995Sdougb else if (PROGCMP("named-compilezone")) 135170222Sdougb progmode = progmode_compile; 136170222Sdougb else 137170222Sdougb INSIST(0); 138170222Sdougb 139170222Sdougb /* Compilation specific defaults */ 140170222Sdougb if (progmode == progmode_compile) { 141170222Sdougb zone_options |= (DNS_ZONEOPT_CHECKNS | 142170222Sdougb DNS_ZONEOPT_FATALNS | 143170222Sdougb DNS_ZONEOPT_CHECKNAMES | 144170222Sdougb DNS_ZONEOPT_CHECKNAMESFAIL | 145170222Sdougb DNS_ZONEOPT_CHECKWILDCARD); 146170222Sdougb } 147170222Sdougb 148170222Sdougb#define ARGCMP(X) (strcmp(isc_commandline_argument, X) == 0) 149170222Sdougb 150193149Sdougb isc_commandline_errprint = ISC_FALSE; 151193149Sdougb 152170222Sdougb while ((c = isc_commandline_parse(argc, argv, 153193149Sdougb "c:df:hi:jk:m:n:qs:t:o:vw:DF:M:S:W:")) 154170222Sdougb != EOF) { 155135446Strhodes switch (c) { 156135446Strhodes case 'c': 157135446Strhodes classname = isc_commandline_argument; 158135446Strhodes break; 159135446Strhodes 160135446Strhodes case 'd': 161135446Strhodes debug++; 162135446Strhodes break; 163135446Strhodes 164170222Sdougb case 'i': 165170222Sdougb if (ARGCMP("full")) { 166170222Sdougb zone_options |= DNS_ZONEOPT_CHECKINTEGRITY | 167170222Sdougb DNS_ZONEOPT_CHECKSIBLING; 168170222Sdougb docheckmx = ISC_TRUE; 169170222Sdougb docheckns = ISC_TRUE; 170170222Sdougb dochecksrv = ISC_TRUE; 171170222Sdougb } else if (ARGCMP("full-sibling")) { 172170222Sdougb zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; 173170222Sdougb zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; 174170222Sdougb docheckmx = ISC_TRUE; 175170222Sdougb docheckns = ISC_TRUE; 176170222Sdougb dochecksrv = ISC_TRUE; 177170222Sdougb } else if (ARGCMP("local")) { 178170222Sdougb zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; 179170222Sdougb zone_options |= DNS_ZONEOPT_CHECKSIBLING; 180170222Sdougb docheckmx = ISC_FALSE; 181170222Sdougb docheckns = ISC_FALSE; 182170222Sdougb dochecksrv = ISC_FALSE; 183170222Sdougb } else if (ARGCMP("local-sibling")) { 184170222Sdougb zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; 185170222Sdougb zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; 186170222Sdougb docheckmx = ISC_FALSE; 187170222Sdougb docheckns = ISC_FALSE; 188170222Sdougb dochecksrv = ISC_FALSE; 189170222Sdougb } else if (ARGCMP("none")) { 190170222Sdougb zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY; 191170222Sdougb zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; 192170222Sdougb docheckmx = ISC_FALSE; 193170222Sdougb docheckns = ISC_FALSE; 194170222Sdougb dochecksrv = ISC_FALSE; 195170222Sdougb } else { 196170222Sdougb fprintf(stderr, "invalid argument to -i: %s\n", 197170222Sdougb isc_commandline_argument); 198170222Sdougb exit(1); 199170222Sdougb } 200170222Sdougb break; 201170222Sdougb 202170222Sdougb case 'f': 203170222Sdougb inputformatstr = isc_commandline_argument; 204170222Sdougb break; 205170222Sdougb 206170222Sdougb case 'F': 207170222Sdougb outputformatstr = isc_commandline_argument; 208170222Sdougb break; 209170222Sdougb 210135446Strhodes case 'j': 211135446Strhodes nomerge = ISC_FALSE; 212135446Strhodes break; 213135446Strhodes 214170222Sdougb case 'k': 215170222Sdougb if (ARGCMP("warn")) { 216170222Sdougb zone_options |= DNS_ZONEOPT_CHECKNAMES; 217170222Sdougb zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL; 218170222Sdougb } else if (ARGCMP("fail")) { 219170222Sdougb zone_options |= DNS_ZONEOPT_CHECKNAMES | 220170222Sdougb DNS_ZONEOPT_CHECKNAMESFAIL; 221170222Sdougb } else if (ARGCMP("ignore")) { 222170222Sdougb zone_options &= ~(DNS_ZONEOPT_CHECKNAMES | 223170222Sdougb DNS_ZONEOPT_CHECKNAMESFAIL); 224170222Sdougb } else { 225170222Sdougb fprintf(stderr, "invalid argument to -k: %s\n", 226170222Sdougb isc_commandline_argument); 227170222Sdougb exit(1); 228170222Sdougb } 229170222Sdougb break; 230170222Sdougb 231135446Strhodes case 'n': 232170222Sdougb if (ARGCMP("ignore")) { 233135446Strhodes zone_options &= ~(DNS_ZONEOPT_CHECKNS| 234135446Strhodes DNS_ZONEOPT_FATALNS); 235170222Sdougb } else if (ARGCMP("warn")) { 236135446Strhodes zone_options |= DNS_ZONEOPT_CHECKNS; 237135446Strhodes zone_options &= ~DNS_ZONEOPT_FATALNS; 238170222Sdougb } else if (ARGCMP("fail")) { 239135446Strhodes zone_options |= DNS_ZONEOPT_CHECKNS| 240186462Sdougb DNS_ZONEOPT_FATALNS; 241170222Sdougb } else { 242170222Sdougb fprintf(stderr, "invalid argument to -n: %s\n", 243170222Sdougb isc_commandline_argument); 244170222Sdougb exit(1); 245170222Sdougb } 246135446Strhodes break; 247135446Strhodes 248170222Sdougb case 'm': 249170222Sdougb if (ARGCMP("warn")) { 250170222Sdougb zone_options |= DNS_ZONEOPT_CHECKMX; 251170222Sdougb zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; 252170222Sdougb } else if (ARGCMP("fail")) { 253170222Sdougb zone_options |= DNS_ZONEOPT_CHECKMX | 254170222Sdougb DNS_ZONEOPT_CHECKMXFAIL; 255170222Sdougb } else if (ARGCMP("ignore")) { 256170222Sdougb zone_options &= ~(DNS_ZONEOPT_CHECKMX | 257170222Sdougb DNS_ZONEOPT_CHECKMXFAIL); 258170222Sdougb } else { 259170222Sdougb fprintf(stderr, "invalid argument to -m: %s\n", 260170222Sdougb isc_commandline_argument); 261170222Sdougb exit(1); 262135446Strhodes } 263135446Strhodes break; 264135446Strhodes 265135446Strhodes case 'q': 266135446Strhodes quiet++; 267135446Strhodes break; 268135446Strhodes 269135446Strhodes case 't': 270135446Strhodes result = isc_dir_chroot(isc_commandline_argument); 271135446Strhodes if (result != ISC_R_SUCCESS) { 272135446Strhodes fprintf(stderr, "isc_dir_chroot: %s: %s\n", 273135446Strhodes isc_commandline_argument, 274135446Strhodes isc_result_totext(result)); 275135446Strhodes exit(1); 276135446Strhodes } 277135446Strhodes break; 278135446Strhodes 279170222Sdougb case 's': 280170222Sdougb if (ARGCMP("full")) 281170222Sdougb outputstyle = &dns_master_style_full; 282170222Sdougb else if (ARGCMP("relative")) { 283170222Sdougb outputstyle = &dns_master_style_default; 284170222Sdougb } else { 285170222Sdougb fprintf(stderr, 286170222Sdougb "unknown or unsupported style: %s\n", 287170222Sdougb isc_commandline_argument); 288170222Sdougb exit(1); 289170222Sdougb } 290170222Sdougb break; 291170222Sdougb 292135446Strhodes case 'o': 293135446Strhodes output_filename = isc_commandline_argument; 294135446Strhodes break; 295135446Strhodes 296135446Strhodes case 'v': 297135446Strhodes printf(VERSION "\n"); 298135446Strhodes exit(0); 299135446Strhodes 300135446Strhodes case 'w': 301135446Strhodes workdir = isc_commandline_argument; 302135446Strhodes break; 303135446Strhodes 304135446Strhodes case 'D': 305135446Strhodes dumpzone++; 306135446Strhodes break; 307135446Strhodes 308170222Sdougb case 'M': 309170222Sdougb if (ARGCMP("fail")) { 310170222Sdougb zone_options &= ~DNS_ZONEOPT_WARNMXCNAME; 311170222Sdougb zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; 312170222Sdougb } else if (ARGCMP("warn")) { 313170222Sdougb zone_options |= DNS_ZONEOPT_WARNMXCNAME; 314170222Sdougb zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; 315170222Sdougb } else if (ARGCMP("ignore")) { 316170222Sdougb zone_options |= DNS_ZONEOPT_WARNMXCNAME; 317170222Sdougb zone_options |= DNS_ZONEOPT_IGNOREMXCNAME; 318170222Sdougb } else { 319170222Sdougb fprintf(stderr, "invalid argument to -M: %s\n", 320170222Sdougb isc_commandline_argument); 321170222Sdougb exit(1); 322170222Sdougb } 323170222Sdougb break; 324170222Sdougb 325170222Sdougb case 'S': 326170222Sdougb if (ARGCMP("fail")) { 327170222Sdougb zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME; 328170222Sdougb zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; 329170222Sdougb } else if (ARGCMP("warn")) { 330170222Sdougb zone_options |= DNS_ZONEOPT_WARNSRVCNAME; 331170222Sdougb zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; 332170222Sdougb } else if (ARGCMP("ignore")) { 333170222Sdougb zone_options |= DNS_ZONEOPT_WARNSRVCNAME; 334170222Sdougb zone_options |= DNS_ZONEOPT_IGNORESRVCNAME; 335170222Sdougb } else { 336170222Sdougb fprintf(stderr, "invalid argument to -S: %s\n", 337170222Sdougb isc_commandline_argument); 338170222Sdougb exit(1); 339170222Sdougb } 340170222Sdougb break; 341170222Sdougb 342170222Sdougb case 'W': 343170222Sdougb if (ARGCMP("warn")) 344170222Sdougb zone_options |= DNS_ZONEOPT_CHECKWILDCARD; 345170222Sdougb else if (ARGCMP("ignore")) 346170222Sdougb zone_options &= ~DNS_ZONEOPT_CHECKWILDCARD; 347170222Sdougb break; 348170222Sdougb 349193149Sdougb case '?': 350193149Sdougb if (isc_commandline_option != '?') 351193149Sdougb fprintf(stderr, "%s: invalid argument -%c\n", 352193149Sdougb prog_name, isc_commandline_option); 353193149Sdougb case 'h': 354135446Strhodes usage(); 355135446Strhodes 356193149Sdougb default: 357193149Sdougb fprintf(stderr, "%s: unhandled option -%c\n", 358193149Sdougb prog_name, isc_commandline_option); 359193149Sdougb exit(1); 360170222Sdougb } 361170222Sdougb } 362170222Sdougb 363135446Strhodes if (workdir != NULL) { 364135446Strhodes result = isc_dir_chdir(workdir); 365135446Strhodes if (result != ISC_R_SUCCESS) { 366135446Strhodes fprintf(stderr, "isc_dir_chdir: %s: %s\n", 367135446Strhodes workdir, isc_result_totext(result)); 368135446Strhodes exit(1); 369135446Strhodes } 370135446Strhodes } 371135446Strhodes 372170222Sdougb if (inputformatstr != NULL) { 373170222Sdougb if (strcasecmp(inputformatstr, "text") == 0) 374170222Sdougb inputformat = dns_masterformat_text; 375170222Sdougb else if (strcasecmp(inputformatstr, "raw") == 0) 376170222Sdougb inputformat = dns_masterformat_raw; 377170222Sdougb else { 378170222Sdougb fprintf(stderr, "unknown file format: %s\n", 379170222Sdougb inputformatstr); 380170222Sdougb exit(1); 381170222Sdougb } 382170222Sdougb } 383170222Sdougb 384170222Sdougb if (outputformatstr != NULL) { 385170222Sdougb if (strcasecmp(outputformatstr, "text") == 0) 386170222Sdougb outputformat = dns_masterformat_text; 387170222Sdougb else if (strcasecmp(outputformatstr, "raw") == 0) 388170222Sdougb outputformat = dns_masterformat_raw; 389170222Sdougb else { 390170222Sdougb fprintf(stderr, "unknown file format: %s\n", 391170222Sdougb outputformatstr); 392170222Sdougb exit(1); 393170222Sdougb } 394170222Sdougb } 395170222Sdougb 396193149Sdougb if (progmode == progmode_compile) { 397193149Sdougb dumpzone = 1; /* always dump */ 398193149Sdougb if (output_filename == NULL) { 399193149Sdougb fprintf(stderr, 400193149Sdougb "output file required, but not specified\n"); 401193149Sdougb usage(); 402193149Sdougb } 403193149Sdougb } 404193149Sdougb 405193149Sdougb if (output_filename != NULL) 406193149Sdougb dumpzone = 1; 407193149Sdougb 408193149Sdougb /* 409193149Sdougb * If we are outputing to stdout then send the informational 410193149Sdougb * output to stderr. 411193149Sdougb */ 412193149Sdougb if (dumpzone && 413193149Sdougb (output_filename == NULL || 414193149Sdougb strcmp(output_filename, "-") == 0 || 415193149Sdougb strcmp(output_filename, "/dev/fd/1") == 0 || 416193149Sdougb strcmp(output_filename, "/dev/stdout") == 0)) 417193149Sdougb errout = stderr; 418193149Sdougb 419193149Sdougb if (isc_commandline_index + 2 != argc) 420135446Strhodes usage(); 421135446Strhodes 422216175Sdougb#ifdef _WIN32 423216175Sdougb InitSockets(); 424216175Sdougb#endif 425216175Sdougb 426135446Strhodes RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); 427170222Sdougb if (!quiet) 428193149Sdougb RUNTIME_CHECK(setup_logging(mctx, errout, &lctx) 429193149Sdougb == ISC_R_SUCCESS); 430143731Sdougb RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS); 431143731Sdougb RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE) 432143731Sdougb == ISC_R_SUCCESS); 433135446Strhodes 434135446Strhodes dns_result_register(); 435135446Strhodes 436135446Strhodes origin = argv[isc_commandline_index++]; 437135446Strhodes filename = argv[isc_commandline_index++]; 438170222Sdougb result = load_zone(mctx, origin, filename, inputformat, classname, 439170222Sdougb &zone); 440135446Strhodes 441135446Strhodes if (result == ISC_R_SUCCESS && dumpzone) { 442170222Sdougb if (!quiet && progmode == progmode_compile) { 443193149Sdougb fprintf(errout, "dump zone to %s...", output_filename); 444193149Sdougb fflush(errout); 445170222Sdougb } 446170222Sdougb result = dump_zone(origin, zone, output_filename, 447170222Sdougb outputformat, outputstyle); 448170222Sdougb if (!quiet && progmode == progmode_compile) 449193149Sdougb fprintf(errout, "done\n"); 450135446Strhodes } 451135446Strhodes 452135446Strhodes if (!quiet && result == ISC_R_SUCCESS) 453193149Sdougb fprintf(errout, "OK\n"); 454135446Strhodes destroy(); 455135446Strhodes if (lctx != NULL) 456135446Strhodes isc_log_destroy(&lctx); 457143731Sdougb isc_hash_destroy(); 458143731Sdougb isc_entropy_detach(&ectx); 459135446Strhodes isc_mem_destroy(&mctx); 460216175Sdougb#ifdef _WIN32 461216175Sdougb DestroySockets(); 462216175Sdougb#endif 463135446Strhodes return ((result == ISC_R_SUCCESS) ? 0 : 1); 464135446Strhodes} 465