named-checkzone.c 10.3 KB
Newer Older
Mark Andrews's avatar
Mark Andrews committed
1
/*
Mark Andrews's avatar
Mark Andrews committed
2
 * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1999-2003  Internet Software Consortium.
Mark Andrews's avatar
Mark Andrews committed
4 5 6 7 8
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
Mark Andrews's avatar
Mark Andrews committed
16 17
 */

18
/* $Id: named-checkzone.c,v 1.39 2005/08/24 23:53:55 marka Exp $ */
19 20

/*! \file */
Mark Andrews's avatar
Mark Andrews committed
21 22 23 24 25 26 27

#include <config.h>

#include <stdlib.h>

#include <isc/app.h>
#include <isc/commandline.h>
28
#include <isc/dir.h>
29 30
#include <isc/entropy.h>
#include <isc/hash.h>
Mark Andrews's avatar
Mark Andrews committed
31 32 33 34 35 36 37 38 39 40 41
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/socket.h>
#include <isc/string.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/util.h>

#include <dns/db.h>
#include <dns/fixedname.h>
#include <dns/log.h>
42
#include <dns/masterdump.h>
43
#include <dns/name.h>
Mark Andrews's avatar
Mark Andrews committed
44 45 46
#include <dns/rdataclass.h>
#include <dns/rdataset.h>
#include <dns/result.h>
47
#include <dns/types.h>
Mark Andrews's avatar
Mark Andrews committed
48 49
#include <dns/zone.h>

Mark Andrews's avatar
cleanup  
Mark Andrews committed
50 51
#include "check-tool.h"

Mark Andrews's avatar
Mark Andrews committed
52 53
static int quiet = 0;
static isc_mem_t *mctx = NULL;
54
static isc_entropy_t *ectx = NULL;
Mark Andrews's avatar
Mark Andrews committed
55 56
dns_zone_t *zone = NULL;
dns_zonetype_t zonetype = dns_zone_master;
57 58
static int dumpzone = 0;
static const char *output_filename;
59 60 61
static char *prog_name = NULL;
static const dns_master_style_t *outputstyle = &dns_master_style_full;
static enum { progmode_check, progmode_compile } progmode;
Mark Andrews's avatar
Mark Andrews committed
62 63 64 65

#define ERRRET(result, function) \
	do { \
		if (result != ISC_R_SUCCESS) { \
Mark Andrews's avatar
Mark Andrews committed
66 67 68
			if (!quiet) \
				fprintf(stderr, "%s() returned %s\n", \
					function, dns_result_totext(result)); \
Mark Andrews's avatar
Mark Andrews committed
69 70 71 72 73
			return (result); \
		} \
	} while (0)

static void
Brian Wellington's avatar
Brian Wellington committed
74
usage(void) {
Mark Andrews's avatar
Mark Andrews committed
75
	fprintf(stderr,
76 77
		"usage: %s [-djqvD] [-c class] [-o output] "
		"[-f inputformat] [-F outputformat] "
78
		"[-t directory] [-w directory] [-k (ignore|warn|fail)] "
79 80
		"[-n (ignore|warn|fail)] [-m (ignore|warn|fail)] "
		"[-i (full|local|none)] [-W (ignore|warn)] "
81
		"zonename filename\n", prog_name);
Mark Andrews's avatar
Mark Andrews committed
82 83 84 85 86
	exit(1);
}

static void
destroy(void) {
Mark Andrews's avatar
Mark Andrews committed
87 88
	if (zone != NULL)
		dns_zone_detach(&zone);
Mark Andrews's avatar
Mark Andrews committed
89 90
}

91
/*% main processing routine */
Mark Andrews's avatar
Mark Andrews committed
92 93 94
int
main(int argc, char **argv) {
	int c;
Mark Andrews's avatar
Mark Andrews committed
95
	char *origin = NULL;
Mark Andrews's avatar
Mark Andrews committed
96 97 98
	char *filename = NULL;
	isc_log_t *lctx = NULL;
	isc_result_t result;
99
	char classname_in[] = "IN";
100
	char *classname = classname_in;
101
	const char *workdir = NULL;
102 103 104 105 106 107 108 109 110 111
	const char *inputformatstr = NULL;
	const char *outputformatstr = NULL;
	dns_masterformat_t inputformat = dns_masterformat_text;
	dns_masterformat_t outputformat = dns_masterformat_text;

	prog_name = strrchr(argv[0], '/');
	if (prog_name != NULL)
		prog_name++;
	else
		prog_name = argv[0];
Mark Andrews's avatar
Mark Andrews committed
112 113 114 115 116 117
	/*
	 * Libtool doesn't preserve the program name prior to final
	 * installation.  Remove the libtool prefix ("lt-").
	 */
	if (strncmp(prog_name, "lt-", 3) == 0)
		prog_name += 3;
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
	if (strcmp(prog_name, "named-checkzone") == 0)
		progmode = progmode_check;
	else if (strcmp(prog_name, "named-compilezone") == 0)
		progmode = progmode_compile;
	else
		INSIST(0);

	/* Compilation specific defaults */
	if (progmode == progmode_compile) {
		zone_options |= (DNS_ZONEOPT_CHECKNS |
				 DNS_ZONEOPT_FATALNS |
				 DNS_ZONEOPT_CHECKNAMES |
				 DNS_ZONEOPT_CHECKNAMESFAIL |
				 DNS_ZONEOPT_CHECKWILDCARD);
	}
Mark Andrews's avatar
Mark Andrews committed
133

134
	while ((c = isc_commandline_parse(argc, argv,
135 136
					  "c:df:i:jk:m:n:qst:o:vw:DF:W:"))
	       != EOF) {
Mark Andrews's avatar
Mark Andrews committed
137 138 139 140
		switch (c) {
		case 'c':
			classname = isc_commandline_argument;
			break;
141

Mark Andrews's avatar
Mark Andrews committed
142 143 144
		case 'd':
			debug++;
			break;
145

146 147
		case 'i':
			if (!strcmp(isc_commandline_argument, "full")) {
148 149 150 151 152 153 154 155 156
				zone_options |= DNS_ZONEOPT_CHECKINTEGRITY |
						DNS_ZONEOPT_CHECKSIBLING;
				docheckmx = ISC_TRUE;
				docheckns = ISC_TRUE;
				dochecksrv = ISC_TRUE;
			} else if (!strcmp(isc_commandline_argument,
					   "full-sibling")) {
				zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
				zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
157 158 159 160 161
				docheckmx = ISC_TRUE;
				docheckns = ISC_TRUE;
				dochecksrv = ISC_TRUE;
			} else if (!strcmp(isc_commandline_argument,
					   "local")) {
162 163 164 165 166 167 168 169 170
				zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
				zone_options |= DNS_ZONEOPT_CHECKSIBLING;
				docheckmx = ISC_FALSE;
				docheckns = ISC_FALSE;
				dochecksrv = ISC_FALSE;
			} else if (!strcmp(isc_commandline_argument,
					   "local-sibling")) {
				zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
				zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
171 172 173 174 175
				docheckmx = ISC_FALSE;
				docheckns = ISC_FALSE;
				dochecksrv = ISC_FALSE;
			} else if (!strcmp(isc_commandline_argument,
					   "none")) {
176 177
				zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
				zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
178 179 180 181 182 183 184 185 186 187
				docheckmx = ISC_FALSE;
				docheckns = ISC_FALSE;
				dochecksrv = ISC_FALSE;
			} else {
				fprintf(stderr, "invalid argument to -i: %s\n",
					isc_commandline_argument);
				exit(1);
			}
			break;

188 189 190 191 192 193 194 195
		case 'f':
			inputformatstr = isc_commandline_argument;
			break;

		case 'F':
			outputformatstr = isc_commandline_argument;
			break;

196
		case 'j':
197 198 199
			nomerge = ISC_FALSE;
			break;

200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
		case 'k':
			if (!strcmp(isc_commandline_argument, "warn")) {
				zone_options |= DNS_ZONEOPT_CHECKNAMES;
				zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
			} else if (!strcmp(isc_commandline_argument,
					   "fail")) {
				zone_options |= DNS_ZONEOPT_CHECKNAMES |
						DNS_ZONEOPT_CHECKNAMESFAIL;
			} else if (!strcmp(isc_commandline_argument,
					   "ignore")) {
				zone_options &= ~(DNS_ZONEOPT_CHECKNAMES |
						  DNS_ZONEOPT_CHECKNAMESFAIL);
			} else {
				fprintf(stderr, "invalid argument to -k: %s\n",
					isc_commandline_argument);
				exit(1);
			}
			break;

219
		case 'n':
220
			if (!strcmp(isc_commandline_argument, "ignore")) {
221 222
				zone_options &= ~(DNS_ZONEOPT_CHECKNS|
						  DNS_ZONEOPT_FATALNS);
223
			} else if (!strcmp(isc_commandline_argument, "warn")) {
224 225
				zone_options |= DNS_ZONEOPT_CHECKNS;
				zone_options &= ~DNS_ZONEOPT_FATALNS;
226
			} else if (!strcmp(isc_commandline_argument, "fail")) {
227 228
				zone_options |= DNS_ZONEOPT_CHECKNS|
					        DNS_ZONEOPT_FATALNS;
229 230 231 232 233
			} else {
				fprintf(stderr, "invalid argument to -n: %s\n",
					isc_commandline_argument);
				exit(1);
			}
234 235
			break;

236
		case 'm':
237
			if (!strcmp(isc_commandline_argument, "warn")) {
238 239
				zone_options |= DNS_ZONEOPT_CHECKMX;
				zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
240
			} else if (!strcmp(isc_commandline_argument,
241
					   "fail")) {
242 243
				zone_options |= DNS_ZONEOPT_CHECKMX |
						DNS_ZONEOPT_CHECKMXFAIL;
244 245
			} else if (!strcmp(isc_commandline_argument,
					   "ignore")) {
246 247 248 249 250 251
				zone_options &= ~(DNS_ZONEOPT_CHECKMX |
						  DNS_ZONEOPT_CHECKMXFAIL);
			} else {
				fprintf(stderr, "invalid argument to -m: %s\n",
					isc_commandline_argument);
				exit(1);
252 253 254
			}
			break;

Mark Andrews's avatar
Mark Andrews committed
255 256 257
		case 'q':
			quiet++;
			break;
258

Mark Andrews's avatar
Mark Andrews committed
259
		case 't':
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
			result = isc_dir_chroot(isc_commandline_argument);
			if (result != ISC_R_SUCCESS) {
				fprintf(stderr, "isc_dir_chroot: %s: %s\n",
					isc_commandline_argument,
					isc_result_totext(result));
				exit(1);
			}
			result = isc_dir_chdir("/");
			if (result != ISC_R_SUCCESS) {
				fprintf(stderr, "isc_dir_chdir: %s\n",
					isc_result_totext(result));
				exit(1);
			}
			break;

275 276 277 278 279 280 281 282 283 284 285 286 287 288
		case 's':
			if (strcmp(isc_commandline_argument, "full") == 0)
				outputstyle = &dns_master_style_full;
			else if (strcmp(isc_commandline_argument,
					"default") == 0) {
				outputstyle = &dns_master_style_default;
			} else {
				fprintf(stderr,
					"unknown or unsupported style: %s\n",
					isc_commandline_argument);
				exit(1);
			}
			break;

289 290 291 292
		case 'o':
			output_filename = isc_commandline_argument;
			break;

293 294 295
		case 'v':
			printf(VERSION "\n");
			exit(0);
296 297 298 299 300

		case 'w':
			workdir = isc_commandline_argument;
			break;

301 302 303 304
		case 'D':
			dumpzone++;
			break;

305 306 307 308 309 310 311
		case 'W':
			if (!strcmp(isc_commandline_argument, "warn"))
				zone_options |= DNS_ZONEOPT_CHECKWILDCARD;
			else if (!strcmp(isc_commandline_argument, "ignore"))
				zone_options &= ~DNS_ZONEOPT_CHECKWILDCARD;
			break;

Mark Andrews's avatar
Mark Andrews committed
312 313 314 315 316
		default:
			usage();
		}
	}

317 318 319 320 321 322 323 324 325
	if (progmode == progmode_compile) {
		dumpzone = 1;	/* always dump */
		if (output_filename == NULL) {
			fprintf(stderr,
				"output file required, but not specified\n");
			usage();
		}
	}

326 327 328 329 330 331 332 333 334
	if (workdir != NULL) {
		result = isc_dir_chdir(workdir);
		if (result != ISC_R_SUCCESS) {
			fprintf(stderr, "isc_dir_chdir: %s: %s\n",
				workdir, isc_result_totext(result));
			exit(1);
		}
	}

335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
	if (inputformatstr != NULL) {
		if (strcasecmp(inputformatstr, "text") == 0)
			inputformat = dns_masterformat_text;
		else if (strcasecmp(inputformatstr, "raw") == 0)
			inputformat = dns_masterformat_raw;
		else {
			fprintf(stderr, "unknown file format: %s\n",
			    inputformatstr);
			exit(1);
		}
	}

	if (outputformatstr != NULL) {
		if (strcasecmp(outputformatstr, "text") == 0)
			outputformat = dns_masterformat_text;
		else if (strcasecmp(outputformatstr, "raw") == 0)
			outputformat = dns_masterformat_raw;
		else {
			fprintf(stderr, "unknown file format: %s\n",
				outputformatstr);
			exit(1);
		}
	}

359
	if (isc_commandline_index + 2 > argc)
Mark Andrews's avatar
Mark Andrews committed
360 361 362
		usage();

	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
363
	if (!quiet)
Mark Andrews's avatar
cleanup  
Mark Andrews committed
364
		RUNTIME_CHECK(setup_logging(mctx, &lctx) == ISC_R_SUCCESS);
365 366 367
	RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS);
	RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE)
		      == ISC_R_SUCCESS);
Mark Andrews's avatar
Mark Andrews committed
368

369 370
	dns_result_register();

371 372
	origin = argv[isc_commandline_index++];
	filename = argv[isc_commandline_index++];
373 374
	result = load_zone(mctx, origin, filename, inputformat, classname,
			   &zone);
375 376

	if (result == ISC_R_SUCCESS && dumpzone) {
377 378 379 380 381 382 383 384
		if (!quiet && progmode == progmode_compile) {
			fprintf(stdout, "dump zone to %s...", output_filename);
			fflush(stdout);
		}
		result = dump_zone(origin, zone, output_filename,
				   outputformat, outputstyle);
		if (!quiet && progmode == progmode_compile)
			fprintf(stdout, "done\n");
385 386
	}

Mark Andrews's avatar
Mark Andrews committed
387
	if (!quiet && result == ISC_R_SUCCESS)
388
		fprintf(stdout, "OK\n");
Mark Andrews's avatar
Mark Andrews committed
389
	destroy();
Mark Andrews's avatar
Mark Andrews committed
390 391
	if (lctx != NULL)
		isc_log_destroy(&lctx);
392 393
	isc_hash_destroy();
	isc_entropy_detach(&ectx);
Mark Andrews's avatar
Mark Andrews committed
394
	isc_mem_destroy(&mctx);
Mark Andrews's avatar
Mark Andrews committed
395
	return ((result == ISC_R_SUCCESS) ? 0 : 1);
Mark Andrews's avatar
Mark Andrews committed
396
}