xref: /openbsd/usr.sbin/nsd/nsd-checkzone.c (revision d415bd75)
1 /*
2  * nsd-checkzone.c -- nsd-checkzone(8) checks zones for syntax errors
3  *
4  * Copyright (c) 2013, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 #include "config.h"
11 
12 #include <assert.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <time.h>
17 #include <unistd.h>
18 #include <errno.h>
19 
20 #include "nsd.h"
21 #include "options.h"
22 #include "util.h"
23 #include "zonec.h"
24 #include "ixfr.h"
25 #include "ixfrcreate.h"
26 #include "difffile.h"
27 
28 struct nsd nsd;
29 
30 /*
31  * Print the help text.
32  *
33  */
34 static void
35 usage (void)
36 {
37 	fprintf(stderr, "Usage: nsd-checkzone [-p] <zone name> <zone file>\n");
38 	fprintf(stderr, "\t-p\tprint the zone if the zone is ok\n");
39 	fprintf(stderr, "\t-i <old zone file>\tcreate an IXFR from the differences between the\n\t\told zone file and the new zone file. Writes to \n\t\t<zonefile>.ixfr and renames other <zonefile>.ixfr files to\n\t\t<zonefile>.ixfr.num+1.\n");
40 	fprintf(stderr, "\t-n <ixfr number>\tnumber of IXFR versions to store, at most.\n\t\tdefault %d.\n", (int)IXFR_NUMBER_DEFAULT);
41 	fprintf(stderr, "\t-s <ixfr size>\tsize of IXFR to store, at most. default %d.\n", (int)IXFR_SIZE_DEFAULT);
42 	fprintf(stderr, "Version %s. Report bugs to <%s>.\n",
43 		PACKAGE_VERSION, PACKAGE_BUGREPORT);
44 }
45 
46 static void
47 check_zone(struct nsd* nsd, const char* name, const char* fname, FILE *out,
48 	const char* oldzone, uint32_t ixfr_number, uint64_t ixfr_size)
49 {
50 	const dname_type* dname;
51 	zone_options_type* zo;
52 	zone_type* zone;
53 	unsigned errors;
54 	struct ixfr_create* ixfrcr = NULL;
55 
56 	/* init*/
57 	nsd->db = namedb_open("", nsd->options);
58 	dname = dname_parse(nsd->options->region, name);
59 	if(!dname) {
60 		/* parse failure */
61 		error("cannot parse zone name '%s'", name);
62 	}
63 	zo = zone_options_create(nsd->options->region);
64 	memset(zo, 0, sizeof(*zo));
65 	zo->node.key = dname;
66 	zo->name = name;
67 	zone = namedb_zone_create(nsd->db, dname, zo);
68 
69 	if(oldzone) {
70 		errors = zonec_read(name, oldzone, zone);
71 		if(errors > 0) {
72 			printf("zone %s file %s has %u errors\n", name, oldzone, errors);
73 			exit(1);
74 		}
75 		ixfrcr = ixfr_create_start(zone, fname, ixfr_size, 1);
76 		if(!ixfrcr) {
77 			error("out of memory");
78 		}
79 		delete_zone_rrs(nsd->db, zone);
80 	}
81 
82 	/* read the zone */
83 	errors = zonec_read(name, fname, zone);
84 	if(errors > 0) {
85 		printf("zone %s file %s has %u errors\n", name, fname, errors);
86 		ixfr_create_cancel(ixfrcr);
87 #ifdef MEMCLEAN /* otherwise, the OS collects memory pages */
88 		namedb_close(nsd->db);
89 		region_destroy(nsd->options->region);
90 #endif
91 		exit(1);
92 	}
93 	if(ixfrcr) {
94 		if(!ixfr_create_perform(ixfrcr, zone, 0, nsd, fname,
95 			ixfr_number)) {
96 #ifdef MEMCLEAN /* otherwise, the OS collects memory pages */
97 			namedb_close(nsd->db);
98 			region_destroy(nsd->options->region);
99 			ixfr_create_free(ixfrcr);
100 #endif
101 			error("could not create IXFR");
102 		}
103 		printf("zone %s created IXFR %s.ixfr\n", name, fname);
104 		ixfr_create_free(ixfrcr);
105 	}
106 	if (out) {
107 		print_rrs(out, zone);
108 		printf("; ");
109 	}
110 	printf("zone %s is ok\n", name);
111 	namedb_close(nsd->db);
112 }
113 
114 /* dummy functions to link */
115 int writepid(struct nsd * ATTR_UNUSED(nsd))
116 {
117 	        return 0;
118 }
119 void unlinkpid(const char * ATTR_UNUSED(file))
120 {
121 }
122 void bind8_stats(struct nsd * ATTR_UNUSED(nsd))
123 {
124 }
125 
126 void sig_handler(int ATTR_UNUSED(sig))
127 {
128 }
129 
130 extern char *optarg;
131 extern int optind;
132 
133 int
134 main(int argc, char *argv[])
135 {
136 	/* Scratch variables... */
137 	int c;
138 	int print_zone = 0;
139 	uint32_t ixfr_number = IXFR_NUMBER_DEFAULT;
140 	uint64_t ixfr_size = IXFR_SIZE_DEFAULT;
141 	char* oldzone = NULL;
142 	struct nsd nsd;
143 	memset(&nsd, 0, sizeof(nsd));
144 
145 	log_init("nsd-checkzone");
146 
147 	/* Parse the command line... */
148 	while ((c = getopt(argc, argv, "hi:n:ps:")) != -1) {
149 		switch (c) {
150 		case 'h':
151 			usage();
152 			exit(0);
153 		case 'i':
154 			oldzone = optarg;
155 			break;
156 		case 'n':
157 			ixfr_number = (uint32_t)atoi(optarg);
158 			break;
159 		case 'p':
160 			print_zone = 1;
161 			break;
162 		case 's':
163 			ixfr_size = (uint64_t)atoi(optarg);
164 			break;
165 		case '?':
166 		default:
167 			usage();
168 			exit(1);
169 		}
170 	}
171 	argc -= optind;
172 	argv += optind;
173 
174 	/* Commandline parse error */
175 	if (argc != 2) {
176 		fprintf(stderr, "wrong number of arguments.\n");
177 		usage();
178 		exit(1);
179 	}
180 
181 	nsd.options = nsd_options_create(region_create_custom(xalloc, free,
182 		DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE,
183 		DEFAULT_INITIAL_CLEANUP_SIZE, 1));
184 	if (verbosity == 0)
185 		verbosity = nsd.options->verbosity;
186 
187 	check_zone(&nsd, argv[0], argv[1], print_zone ? stdout : NULL,
188 		oldzone, ixfr_number, ixfr_size);
189 	region_destroy(nsd.options->region);
190 	/* yylex_destroy(); but, not available in all versions of flex */
191 
192 	exit(0);
193 }
194