]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bind9/bin/check/named-checkzone.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / bind9 / bin / check / named-checkzone.c
1 /*
2  * Copyright (C) 2004-2009  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.51.34.4 2009/11/10 20:01:41 each 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
52 static int quiet = 0;
53 static isc_mem_t *mctx = NULL;
54 static isc_entropy_t *ectx = NULL;
55 dns_zone_t *zone = NULL;
56 dns_zonetype_t zonetype = dns_zone_master;
57 static int dumpzone = 0;
58 static const char *output_filename;
59 static char *prog_name = NULL;
60 static const dns_master_style_t *outputstyle = NULL;
61 static 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
73 static void
74 usage(void) {
75         fprintf(stderr,
76                 "usage: %s [-djqvD] [-c class] "
77                 "[-f inputformat] [-F outputformat] "
78                 "[-t directory] [-w directory] [-k (ignore|warn|fail)] "
79                 "[-n (ignore|warn|fail)] [-m (ignore|warn|fail)] "
80                 "[-i (full|full-sibling|local|local-sibling|none)] "
81                 "[-M (ignore|warn|fail)] [-S (ignore|warn|fail)] "
82                 "[-W (ignore|warn)] "
83                 "%s zonename filename\n",
84                 prog_name,
85                 progmode == progmode_check ? "[-o filename]" : "{-o filename}");
86         exit(1);
87 }
88
89 static void
90 destroy(void) {
91         if (zone != NULL)
92                 dns_zone_detach(&zone);
93         dns_name_destroy();
94 }
95
96 /*% main processing routine */
97 int
98 main(int argc, char **argv) {
99         int c;
100         char *origin = NULL;
101         char *filename = NULL;
102         isc_log_t *lctx = NULL;
103         isc_result_t result;
104         char classname_in[] = "IN";
105         char *classname = classname_in;
106         const char *workdir = NULL;
107         const char *inputformatstr = NULL;
108         const char *outputformatstr = NULL;
109         dns_masterformat_t inputformat = dns_masterformat_text;
110         dns_masterformat_t outputformat = dns_masterformat_text;
111         FILE *errout = stdout;
112
113         outputstyle = &dns_master_style_full;
114
115         prog_name = strrchr(argv[0], '/');
116         if (prog_name == NULL)
117                 prog_name = strrchr(argv[0], '\\');
118         if (prog_name != NULL)
119                 prog_name++;
120         else
121                 prog_name = argv[0];
122         /*
123          * Libtool doesn't preserve the program name prior to final
124          * installation.  Remove the libtool prefix ("lt-").
125          */
126         if (strncmp(prog_name, "lt-", 3) == 0)
127                 prog_name += 3;
128
129 #define PROGCMP(X) \
130         (strcasecmp(prog_name, X) == 0 || strcasecmp(prog_name, X ".exe") == 0)
131
132         if (PROGCMP("named-checkzone"))
133                 progmode = progmode_check;
134         else if (PROGCMP("named-compilezone"))
135                 progmode = progmode_compile;
136         else
137                 INSIST(0);
138
139         /* Compilation specific defaults */
140         if (progmode == progmode_compile) {
141                 zone_options |= (DNS_ZONEOPT_CHECKNS |
142                                  DNS_ZONEOPT_FATALNS |
143                                  DNS_ZONEOPT_CHECKNAMES |
144                                  DNS_ZONEOPT_CHECKNAMESFAIL |
145                                  DNS_ZONEOPT_CHECKWILDCARD);
146         }
147
148 #define ARGCMP(X) (strcmp(isc_commandline_argument, X) == 0)
149
150         isc_commandline_errprint = ISC_FALSE;
151
152         while ((c = isc_commandline_parse(argc, argv,
153                                          "c:df:hi:jk:m:n:qs:t:o:vw:DF:M:S:W:"))
154                != EOF) {
155                 switch (c) {
156                 case 'c':
157                         classname = isc_commandline_argument;
158                         break;
159
160                 case 'd':
161                         debug++;
162                         break;
163
164                 case 'i':
165                         if (ARGCMP("full")) {
166                                 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY |
167                                                 DNS_ZONEOPT_CHECKSIBLING;
168                                 docheckmx = ISC_TRUE;
169                                 docheckns = ISC_TRUE;
170                                 dochecksrv = ISC_TRUE;
171                         } else if (ARGCMP("full-sibling")) {
172                                 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
173                                 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
174                                 docheckmx = ISC_TRUE;
175                                 docheckns = ISC_TRUE;
176                                 dochecksrv = ISC_TRUE;
177                         } else if (ARGCMP("local")) {
178                                 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
179                                 zone_options |= DNS_ZONEOPT_CHECKSIBLING;
180                                 docheckmx = ISC_FALSE;
181                                 docheckns = ISC_FALSE;
182                                 dochecksrv = ISC_FALSE;
183                         } else if (ARGCMP("local-sibling")) {
184                                 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
185                                 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
186                                 docheckmx = ISC_FALSE;
187                                 docheckns = ISC_FALSE;
188                                 dochecksrv = ISC_FALSE;
189                         } else if (ARGCMP("none")) {
190                                 zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
191                                 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
192                                 docheckmx = ISC_FALSE;
193                                 docheckns = ISC_FALSE;
194                                 dochecksrv = ISC_FALSE;
195                         } else {
196                                 fprintf(stderr, "invalid argument to -i: %s\n",
197                                         isc_commandline_argument);
198                                 exit(1);
199                         }
200                         break;
201
202                 case 'f':
203                         inputformatstr = isc_commandline_argument;
204                         break;
205
206                 case 'F':
207                         outputformatstr = isc_commandline_argument;
208                         break;
209
210                 case 'j':
211                         nomerge = ISC_FALSE;
212                         break;
213
214                 case 'k':
215                         if (ARGCMP("warn")) {
216                                 zone_options |= DNS_ZONEOPT_CHECKNAMES;
217                                 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
218                         } else if (ARGCMP("fail")) {
219                                 zone_options |= DNS_ZONEOPT_CHECKNAMES |
220                                                 DNS_ZONEOPT_CHECKNAMESFAIL;
221                         } else if (ARGCMP("ignore")) {
222                                 zone_options &= ~(DNS_ZONEOPT_CHECKNAMES |
223                                                   DNS_ZONEOPT_CHECKNAMESFAIL);
224                         } else {
225                                 fprintf(stderr, "invalid argument to -k: %s\n",
226                                         isc_commandline_argument);
227                                 exit(1);
228                         }
229                         break;
230
231                 case 'n':
232                         if (ARGCMP("ignore")) {
233                                 zone_options &= ~(DNS_ZONEOPT_CHECKNS|
234                                                   DNS_ZONEOPT_FATALNS);
235                         } else if (ARGCMP("warn")) {
236                                 zone_options |= DNS_ZONEOPT_CHECKNS;
237                                 zone_options &= ~DNS_ZONEOPT_FATALNS;
238                         } else if (ARGCMP("fail")) {
239                                 zone_options |= DNS_ZONEOPT_CHECKNS|
240                                                 DNS_ZONEOPT_FATALNS;
241                         } else {
242                                 fprintf(stderr, "invalid argument to -n: %s\n",
243                                         isc_commandline_argument);
244                                 exit(1);
245                         }
246                         break;
247
248                 case 'm':
249                         if (ARGCMP("warn")) {
250                                 zone_options |= DNS_ZONEOPT_CHECKMX;
251                                 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
252                         } else if (ARGCMP("fail")) {
253                                 zone_options |= DNS_ZONEOPT_CHECKMX |
254                                                 DNS_ZONEOPT_CHECKMXFAIL;
255                         } else if (ARGCMP("ignore")) {
256                                 zone_options &= ~(DNS_ZONEOPT_CHECKMX |
257                                                   DNS_ZONEOPT_CHECKMXFAIL);
258                         } else {
259                                 fprintf(stderr, "invalid argument to -m: %s\n",
260                                         isc_commandline_argument);
261                                 exit(1);
262                         }
263                         break;
264
265                 case 'q':
266                         quiet++;
267                         break;
268
269                 case 't':
270                         result = isc_dir_chroot(isc_commandline_argument);
271                         if (result != ISC_R_SUCCESS) {
272                                 fprintf(stderr, "isc_dir_chroot: %s: %s\n",
273                                         isc_commandline_argument,
274                                         isc_result_totext(result));
275                                 exit(1);
276                         }
277                         break;
278
279                 case 's':
280                         if (ARGCMP("full"))
281                                 outputstyle = &dns_master_style_full;
282                         else if (ARGCMP("relative")) {
283                                 outputstyle = &dns_master_style_default;
284                         } else {
285                                 fprintf(stderr,
286                                         "unknown or unsupported style: %s\n",
287                                         isc_commandline_argument);
288                                 exit(1);
289                         }
290                         break;
291
292                 case 'o':
293                         output_filename = isc_commandline_argument;
294                         break;
295
296                 case 'v':
297                         printf(VERSION "\n");
298                         exit(0);
299
300                 case 'w':
301                         workdir = isc_commandline_argument;
302                         break;
303
304                 case 'D':
305                         dumpzone++;
306                         break;
307
308                 case 'M':
309                         if (ARGCMP("fail")) {
310                                 zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
311                                 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
312                         } else if (ARGCMP("warn")) {
313                                 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
314                                 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
315                         } else if (ARGCMP("ignore")) {
316                                 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
317                                 zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
318                         } else {
319                                 fprintf(stderr, "invalid argument to -M: %s\n",
320                                         isc_commandline_argument);
321                                 exit(1);
322                         }
323                         break;
324
325                 case 'S':
326                         if (ARGCMP("fail")) {
327                                 zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
328                                 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
329                         } else if (ARGCMP("warn")) {
330                                 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
331                                 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
332                         } else if (ARGCMP("ignore")) {
333                                 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
334                                 zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
335                         } else {
336                                 fprintf(stderr, "invalid argument to -S: %s\n",
337                                         isc_commandline_argument);
338                                 exit(1);
339                         }
340                         break;
341
342                 case 'W':
343                         if (ARGCMP("warn"))
344                                 zone_options |= DNS_ZONEOPT_CHECKWILDCARD;
345                         else if (ARGCMP("ignore"))
346                                 zone_options &= ~DNS_ZONEOPT_CHECKWILDCARD;
347                         break;
348
349                 case '?':
350                         if (isc_commandline_option != '?')
351                                 fprintf(stderr, "%s: invalid argument -%c\n",
352                                         prog_name, isc_commandline_option);
353                 case 'h':
354                         usage();
355
356                 default:
357                         fprintf(stderr, "%s: unhandled option -%c\n",
358                                 prog_name, isc_commandline_option);
359                         exit(1);
360                 }
361         }
362
363         if (workdir != NULL) {
364                 result = isc_dir_chdir(workdir);
365                 if (result != ISC_R_SUCCESS) {
366                         fprintf(stderr, "isc_dir_chdir: %s: %s\n",
367                                 workdir, isc_result_totext(result));
368                         exit(1);
369                 }
370         }
371
372         if (inputformatstr != NULL) {
373                 if (strcasecmp(inputformatstr, "text") == 0)
374                         inputformat = dns_masterformat_text;
375                 else if (strcasecmp(inputformatstr, "raw") == 0)
376                         inputformat = dns_masterformat_raw;
377                 else {
378                         fprintf(stderr, "unknown file format: %s\n",
379                             inputformatstr);
380                         exit(1);
381                 }
382         }
383
384         if (outputformatstr != NULL) {
385                 if (strcasecmp(outputformatstr, "text") == 0)
386                         outputformat = dns_masterformat_text;
387                 else if (strcasecmp(outputformatstr, "raw") == 0)
388                         outputformat = dns_masterformat_raw;
389                 else {
390                         fprintf(stderr, "unknown file format: %s\n",
391                                 outputformatstr);
392                         exit(1);
393                 }
394         }
395
396         if (progmode == progmode_compile) {
397                 dumpzone = 1;   /* always dump */
398                 if (output_filename == NULL) {
399                         fprintf(stderr,
400                                 "output file required, but not specified\n");
401                         usage();
402                 }
403         }
404
405         if (output_filename != NULL)
406                 dumpzone = 1;
407
408         /*
409          * If we are outputing to stdout then send the informational
410          * output to stderr.
411          */
412         if (dumpzone &&
413             (output_filename == NULL ||
414              strcmp(output_filename, "-") == 0 ||
415              strcmp(output_filename, "/dev/fd/1") == 0 ||
416              strcmp(output_filename, "/dev/stdout") == 0))
417                 errout = stderr;
418
419         if (isc_commandline_index + 2 != argc)
420                 usage();
421
422         RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
423         if (!quiet)
424                 RUNTIME_CHECK(setup_logging(mctx, errout, &lctx)
425                               == ISC_R_SUCCESS);
426         RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS);
427         RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE)
428                       == ISC_R_SUCCESS);
429
430         dns_result_register();
431
432         origin = argv[isc_commandline_index++];
433         filename = argv[isc_commandline_index++];
434         result = load_zone(mctx, origin, filename, inputformat, classname,
435                            &zone);
436
437         if (result == ISC_R_SUCCESS && dumpzone) {
438                 if (!quiet && progmode == progmode_compile) {
439                         fprintf(errout, "dump zone to %s...", output_filename);
440                         fflush(errout);
441                 }
442                 result = dump_zone(origin, zone, output_filename,
443                                    outputformat, outputstyle);
444                 if (!quiet && progmode == progmode_compile)
445                         fprintf(errout, "done\n");
446         }
447
448         if (!quiet && result == ISC_R_SUCCESS)
449                 fprintf(errout, "OK\n");
450         destroy();
451         if (lctx != NULL)
452                 isc_log_destroy(&lctx);
453         isc_hash_destroy();
454         isc_entropy_detach(&ectx);
455         isc_mem_destroy(&mctx);
456         return ((result == ISC_R_SUCCESS) ? 0 : 1);
457 }