00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <stdlib.h>
00025
00026 #include <isc/app.h>
00027 #include <isc/commandline.h>
00028 #include <isc/dir.h>
00029 #include <isc/entropy.h>
00030 #include <isc/hash.h>
00031 #include <isc/log.h>
00032 #include <isc/mem.h>
00033 #include <isc/socket.h>
00034 #include <isc/string.h>
00035 #include <isc/task.h>
00036 #include <isc/timer.h>
00037 #include <isc/util.h>
00038
00039 #include <dns/db.h>
00040 #include <dns/fixedname.h>
00041 #include <dns/log.h>
00042 #include <dns/master.h>
00043 #include <dns/masterdump.h>
00044 #include <dns/name.h>
00045 #include <dns/rdataclass.h>
00046 #include <dns/rdataset.h>
00047 #include <dns/result.h>
00048 #include <dns/types.h>
00049 #include <dns/zone.h>
00050
00051 #include "check-tool.h"
00052
00053 static int quiet = 0;
00054 static isc_mem_t *mctx = NULL;
00055 static isc_entropy_t *ectx = NULL;
00056 dns_zone_t *zone = NULL;
00057 dns_zonetype_t zonetype = dns_zone_master;
00058 static int dumpzone = 0;
00059 static const char *output_filename;
00060 static char *prog_name = NULL;
00061 static const dns_master_style_t *outputstyle = NULL;
00062 static enum { progmode_check, progmode_compile } progmode;
00063
00064 #define ERRRET(result, function) \
00065 do { \
00066 if (result != ISC_R_SUCCESS) { \
00067 if (!quiet) \
00068 fprintf(stderr, "%s() returned %s\n", \
00069 function, dns_result_totext(result)); \
00070 return (result); \
00071 } \
00072 } while (0)
00073
00074 ISC_PLATFORM_NORETURN_PRE static void
00075 usage(void) ISC_PLATFORM_NORETURN_POST;
00076
00077 static void
00078 usage(void) {
00079 fprintf(stderr,
00080 "usage: %s [-djqvD] [-c class] "
00081 "[-f inputformat] [-F outputformat] [-J filename] "
00082 "[-t directory] [-w directory] [-k (ignore|warn|fail)] "
00083 "[-n (ignore|warn|fail)] [-m (ignore|warn|fail)] "
00084 "[-r (ignore|warn|fail)] "
00085 "[-i (full|full-sibling|local|local-sibling|none)] "
00086 "[-M (ignore|warn|fail)] [-S (ignore|warn|fail)] "
00087 "[-W (ignore|warn)] "
00088 "%s zonename filename\n",
00089 prog_name,
00090 progmode == progmode_check ? "[-o filename]" : "-o filename");
00091 exit(1);
00092 }
00093
00094 static void
00095 destroy(void) {
00096 if (zone != NULL)
00097 dns_zone_detach(&zone);
00098 dns_name_destroy();
00099 }
00100
00101
00102 int
00103 main(int argc, char **argv) {
00104 int c;
00105 char *origin = NULL;
00106 char *filename = NULL;
00107 isc_log_t *lctx = NULL;
00108 isc_result_t result;
00109 char classname_in[] = "IN";
00110 char *classname = classname_in;
00111 const char *workdir = NULL;
00112 const char *inputformatstr = NULL;
00113 const char *outputformatstr = NULL;
00114 dns_masterformat_t inputformat = dns_masterformat_text;
00115 dns_masterformat_t outputformat = dns_masterformat_text;
00116 dns_masterrawheader_t header;
00117 isc_uint32_t rawversion = 1, serialnum = 0;
00118 dns_ttl_t maxttl = 0;
00119 isc_boolean_t snset = ISC_FALSE;
00120 isc_boolean_t logdump = ISC_FALSE;
00121 FILE *errout = stdout;
00122 char *endp;
00123
00124
00125
00126
00127
00128
00129 outputstyle = &dns_master_style_full;
00130
00131 prog_name = strrchr(argv[0], '/');
00132 if (prog_name == NULL)
00133 prog_name = strrchr(argv[0], '\\');
00134 if (prog_name != NULL)
00135 prog_name++;
00136 else
00137 prog_name = argv[0];
00138
00139
00140
00141
00142 if (strncmp(prog_name, "lt-", 3) == 0)
00143 prog_name += 3;
00144
00145 #define PROGCMP(X) \
00146 (strcasecmp(prog_name, X) == 0 || strcasecmp(prog_name, X ".exe") == 0)
00147
00148 if (PROGCMP("named-checkzone"))
00149 progmode = progmode_check;
00150 else if (PROGCMP("named-compilezone"))
00151 progmode = progmode_compile;
00152 else
00153 INSIST(0);
00154
00155
00156 if (progmode == progmode_compile) {
00157 zone_options |= (DNS_ZONEOPT_CHECKNS |
00158 DNS_ZONEOPT_FATALNS |
00159 DNS_ZONEOPT_CHECKSPF |
00160 DNS_ZONEOPT_CHECKDUPRR |
00161 DNS_ZONEOPT_CHECKNAMES |
00162 DNS_ZONEOPT_CHECKNAMESFAIL |
00163 DNS_ZONEOPT_CHECKWILDCARD);
00164 } else
00165 zone_options |= (DNS_ZONEOPT_CHECKDUPRR |
00166 DNS_ZONEOPT_CHECKSPF);
00167
00168 #define ARGCMP(X) (strcmp(isc_commandline_argument, X) == 0)
00169
00170 isc_commandline_errprint = ISC_FALSE;
00171
00172 while ((c = isc_commandline_parse(argc, argv,
00173 "c:df:hi:jJ:k:L:l:m:n:qr:s:t:o:vw:DF:M:S:T:W:"))
00174 != EOF) {
00175 switch (c) {
00176 case 'c':
00177 classname = isc_commandline_argument;
00178 break;
00179
00180 case 'd':
00181 debug++;
00182 break;
00183
00184 case 'i':
00185 if (ARGCMP("full")) {
00186 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY |
00187 DNS_ZONEOPT_CHECKSIBLING;
00188 docheckmx = ISC_TRUE;
00189 docheckns = ISC_TRUE;
00190 dochecksrv = ISC_TRUE;
00191 } else if (ARGCMP("full-sibling")) {
00192 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
00193 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
00194 docheckmx = ISC_TRUE;
00195 docheckns = ISC_TRUE;
00196 dochecksrv = ISC_TRUE;
00197 } else if (ARGCMP("local")) {
00198 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
00199 zone_options |= DNS_ZONEOPT_CHECKSIBLING;
00200 docheckmx = ISC_FALSE;
00201 docheckns = ISC_FALSE;
00202 dochecksrv = ISC_FALSE;
00203 } else if (ARGCMP("local-sibling")) {
00204 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
00205 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
00206 docheckmx = ISC_FALSE;
00207 docheckns = ISC_FALSE;
00208 dochecksrv = ISC_FALSE;
00209 } else if (ARGCMP("none")) {
00210 zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
00211 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
00212 docheckmx = ISC_FALSE;
00213 docheckns = ISC_FALSE;
00214 dochecksrv = ISC_FALSE;
00215 } else {
00216 fprintf(stderr, "invalid argument to -i: %s\n",
00217 isc_commandline_argument);
00218 exit(1);
00219 }
00220 break;
00221
00222 case 'f':
00223 inputformatstr = isc_commandline_argument;
00224 break;
00225
00226 case 'F':
00227 outputformatstr = isc_commandline_argument;
00228 break;
00229
00230 case 'j':
00231 nomerge = ISC_FALSE;
00232 break;
00233
00234 case 'J':
00235 journal = isc_commandline_argument;
00236 nomerge = ISC_FALSE;
00237 break;
00238
00239 case 'k':
00240 if (ARGCMP("warn")) {
00241 zone_options |= DNS_ZONEOPT_CHECKNAMES;
00242 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
00243 } else if (ARGCMP("fail")) {
00244 zone_options |= DNS_ZONEOPT_CHECKNAMES |
00245 DNS_ZONEOPT_CHECKNAMESFAIL;
00246 } else if (ARGCMP("ignore")) {
00247 zone_options &= ~(DNS_ZONEOPT_CHECKNAMES |
00248 DNS_ZONEOPT_CHECKNAMESFAIL);
00249 } else {
00250 fprintf(stderr, "invalid argument to -k: %s\n",
00251 isc_commandline_argument);
00252 exit(1);
00253 }
00254 break;
00255
00256 case 'L':
00257 snset = ISC_TRUE;
00258 endp = NULL;
00259 serialnum = strtol(isc_commandline_argument, &endp, 0);
00260 if (*endp != '\0') {
00261 fprintf(stderr, "source serial number "
00262 "must be numeric");
00263 exit(1);
00264 }
00265 break;
00266
00267 case 'l':
00268 zone_options2 |= DNS_ZONEOPT2_CHECKTTL;
00269 endp = NULL;
00270 maxttl = strtol(isc_commandline_argument, &endp, 0);
00271 if (*endp != '\0') {
00272 fprintf(stderr, "maximum TTL "
00273 "must be numeric");
00274 exit(1);
00275 }
00276 break;
00277
00278
00279 case 'n':
00280 if (ARGCMP("ignore")) {
00281 zone_options &= ~(DNS_ZONEOPT_CHECKNS|
00282 DNS_ZONEOPT_FATALNS);
00283 } else if (ARGCMP("warn")) {
00284 zone_options |= DNS_ZONEOPT_CHECKNS;
00285 zone_options &= ~DNS_ZONEOPT_FATALNS;
00286 } else if (ARGCMP("fail")) {
00287 zone_options |= DNS_ZONEOPT_CHECKNS|
00288 DNS_ZONEOPT_FATALNS;
00289 } else {
00290 fprintf(stderr, "invalid argument to -n: %s\n",
00291 isc_commandline_argument);
00292 exit(1);
00293 }
00294 break;
00295
00296 case 'm':
00297 if (ARGCMP("warn")) {
00298 zone_options |= DNS_ZONEOPT_CHECKMX;
00299 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
00300 } else if (ARGCMP("fail")) {
00301 zone_options |= DNS_ZONEOPT_CHECKMX |
00302 DNS_ZONEOPT_CHECKMXFAIL;
00303 } else if (ARGCMP("ignore")) {
00304 zone_options &= ~(DNS_ZONEOPT_CHECKMX |
00305 DNS_ZONEOPT_CHECKMXFAIL);
00306 } else {
00307 fprintf(stderr, "invalid argument to -m: %s\n",
00308 isc_commandline_argument);
00309 exit(1);
00310 }
00311 break;
00312
00313 case 'o':
00314 output_filename = isc_commandline_argument;
00315 break;
00316
00317 case 'q':
00318 quiet++;
00319 break;
00320
00321 case 'r':
00322 if (ARGCMP("warn")) {
00323 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
00324 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
00325 } else if (ARGCMP("fail")) {
00326 zone_options |= DNS_ZONEOPT_CHECKDUPRR |
00327 DNS_ZONEOPT_CHECKDUPRRFAIL;
00328 } else if (ARGCMP("ignore")) {
00329 zone_options &= ~(DNS_ZONEOPT_CHECKDUPRR |
00330 DNS_ZONEOPT_CHECKDUPRRFAIL);
00331 } else {
00332 fprintf(stderr, "invalid argument to -r: %s\n",
00333 isc_commandline_argument);
00334 exit(1);
00335 }
00336 break;
00337
00338 case 's':
00339 if (ARGCMP("full"))
00340 outputstyle = &dns_master_style_full;
00341 else if (ARGCMP("relative")) {
00342 outputstyle = &dns_master_style_default;
00343 } else {
00344 fprintf(stderr,
00345 "unknown or unsupported style: %s\n",
00346 isc_commandline_argument);
00347 exit(1);
00348 }
00349 break;
00350
00351 case 't':
00352 result = isc_dir_chroot(isc_commandline_argument);
00353 if (result != ISC_R_SUCCESS) {
00354 fprintf(stderr, "isc_dir_chroot: %s: %s\n",
00355 isc_commandline_argument,
00356 isc_result_totext(result));
00357 exit(1);
00358 }
00359 break;
00360
00361 case 'v':
00362 printf(VERSION "\n");
00363 exit(0);
00364
00365 case 'w':
00366 workdir = isc_commandline_argument;
00367 break;
00368
00369 case 'D':
00370 dumpzone++;
00371 break;
00372
00373 case 'M':
00374 if (ARGCMP("fail")) {
00375 zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
00376 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
00377 } else if (ARGCMP("warn")) {
00378 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
00379 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
00380 } else if (ARGCMP("ignore")) {
00381 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
00382 zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
00383 } else {
00384 fprintf(stderr, "invalid argument to -M: %s\n",
00385 isc_commandline_argument);
00386 exit(1);
00387 }
00388 break;
00389
00390 case 'S':
00391 if (ARGCMP("fail")) {
00392 zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
00393 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
00394 } else if (ARGCMP("warn")) {
00395 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
00396 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
00397 } else if (ARGCMP("ignore")) {
00398 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
00399 zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
00400 } else {
00401 fprintf(stderr, "invalid argument to -S: %s\n",
00402 isc_commandline_argument);
00403 exit(1);
00404 }
00405 break;
00406
00407 case 'T':
00408 if (ARGCMP("warn")) {
00409 zone_options |= DNS_ZONEOPT_CHECKSPF;
00410 } else if (ARGCMP("ignore")) {
00411 zone_options &= ~DNS_ZONEOPT_CHECKSPF;
00412 } else {
00413 fprintf(stderr, "invalid argument to -T: %s\n",
00414 isc_commandline_argument);
00415 exit(1);
00416 }
00417 break;
00418
00419 case 'W':
00420 if (ARGCMP("warn"))
00421 zone_options |= DNS_ZONEOPT_CHECKWILDCARD;
00422 else if (ARGCMP("ignore"))
00423 zone_options &= ~DNS_ZONEOPT_CHECKWILDCARD;
00424 break;
00425
00426 case '?':
00427 if (isc_commandline_option != '?')
00428 fprintf(stderr, "%s: invalid argument -%c\n",
00429 prog_name, isc_commandline_option);
00430
00431 case 'h':
00432 usage();
00433
00434 default:
00435 fprintf(stderr, "%s: unhandled option -%c\n",
00436 prog_name, isc_commandline_option);
00437 exit(1);
00438 }
00439 }
00440
00441 if (workdir != NULL) {
00442 result = isc_dir_chdir(workdir);
00443 if (result != ISC_R_SUCCESS) {
00444 fprintf(stderr, "isc_dir_chdir: %s: %s\n",
00445 workdir, isc_result_totext(result));
00446 exit(1);
00447 }
00448 }
00449
00450 if (inputformatstr != NULL) {
00451 if (strcasecmp(inputformatstr, "text") == 0)
00452 inputformat = dns_masterformat_text;
00453 else if (strcasecmp(inputformatstr, "raw") == 0)
00454 inputformat = dns_masterformat_raw;
00455 else if (strncasecmp(inputformatstr, "raw=", 4) == 0) {
00456 inputformat = dns_masterformat_raw;
00457 fprintf(stderr,
00458 "WARNING: input format raw, version ignored\n");
00459 } else if (strcasecmp(inputformatstr, "map") == 0) {
00460 inputformat = dns_masterformat_map;
00461 } else {
00462 fprintf(stderr, "unknown file format: %s\n",
00463 inputformatstr);
00464 exit(1);
00465 }
00466 }
00467
00468 if (outputformatstr != NULL) {
00469 if (strcasecmp(outputformatstr, "text") == 0) {
00470 outputformat = dns_masterformat_text;
00471 } else if (strcasecmp(outputformatstr, "raw") == 0) {
00472 outputformat = dns_masterformat_raw;
00473 } else if (strncasecmp(outputformatstr, "raw=", 4) == 0) {
00474 char *end;
00475
00476 outputformat = dns_masterformat_raw;
00477 rawversion = strtol(outputformatstr + 4, &end, 10);
00478 if (end == outputformatstr + 4 || *end != '\0' ||
00479 rawversion > 1U) {
00480 fprintf(stderr,
00481 "unknown raw format version\n");
00482 exit(1);
00483 }
00484 } else if (strcasecmp(outputformatstr, "map") == 0) {
00485 outputformat = dns_masterformat_map;
00486 } else {
00487 fprintf(stderr, "unknown file format: %s\n",
00488 outputformatstr);
00489 exit(1);
00490 }
00491 }
00492
00493 if (progmode == progmode_compile) {
00494 dumpzone = 1;
00495 logdump = !quiet;
00496 if (output_filename == NULL) {
00497 fprintf(stderr,
00498 "output file required, but not specified\n");
00499 usage();
00500 }
00501 }
00502
00503 if (output_filename != NULL)
00504 dumpzone = 1;
00505
00506
00507
00508
00509
00510 if (dumpzone &&
00511 (output_filename == NULL ||
00512 strcmp(output_filename, "-") == 0 ||
00513 strcmp(output_filename, "/dev/fd/1") == 0 ||
00514 strcmp(output_filename, "/dev/stdout") == 0)) {
00515 errout = stderr;
00516 logdump = ISC_FALSE;
00517 }
00518
00519 if (isc_commandline_index + 2 != argc)
00520 usage();
00521
00522 #ifdef _WIN32
00523 InitSockets();
00524 #endif
00525
00526 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
00527 if (!quiet)
00528 RUNTIME_CHECK(setup_logging(mctx, errout, &lctx)
00529 == ISC_R_SUCCESS);
00530 RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS);
00531 RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE)
00532 == ISC_R_SUCCESS);
00533
00534 dns_result_register();
00535
00536 origin = argv[isc_commandline_index++];
00537 filename = argv[isc_commandline_index++];
00538 result = load_zone(mctx, origin, filename, inputformat, classname,
00539 maxttl, &zone);
00540
00541 if (snset) {
00542 dns_master_initrawheader(&header);
00543 header.flags = DNS_MASTERRAW_SOURCESERIALSET;
00544 header.sourceserial = serialnum;
00545 dns_zone_setrawdata(zone, &header);
00546 }
00547
00548 if (result == ISC_R_SUCCESS && dumpzone) {
00549 if (logdump) {
00550 fprintf(errout, "dump zone to %s...", output_filename);
00551 fflush(errout);
00552 }
00553 result = dump_zone(origin, zone, output_filename,
00554 outputformat, outputstyle, rawversion);
00555 if (logdump)
00556 fprintf(errout, "done\n");
00557 }
00558
00559 if (!quiet && result == ISC_R_SUCCESS)
00560 fprintf(errout, "OK\n");
00561 destroy();
00562 if (lctx != NULL)
00563 isc_log_destroy(&lctx);
00564 isc_hash_destroy();
00565 isc_entropy_detach(&ectx);
00566 isc_mem_destroy(&mctx);
00567 #ifdef _WIN32
00568 DestroySockets();
00569 #endif
00570 return ((result == ISC_R_SUCCESS) ? 0 : 1);
00571 }