]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/bin/check/named-checkzone.c
MFC r254651:
[FreeBSD/stable/9.git] / contrib / bind9 / bin / check / named-checkzone.c
1 /*
2  * Copyright (C) 2004-2013  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.65 2011/12/22 17:29:22 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/master.h>
43 #include <dns/masterdump.h>
44 #include <dns/name.h>
45 #include <dns/rdataclass.h>
46 #include <dns/rdataset.h>
47 #include <dns/result.h>
48 #include <dns/types.h>
49 #include <dns/zone.h>
50
51 #include "check-tool.h"
52
53 static int quiet = 0;
54 static isc_mem_t *mctx = NULL;
55 static isc_entropy_t *ectx = NULL;
56 dns_zone_t *zone = NULL;
57 dns_zonetype_t zonetype = dns_zone_master;
58 static int dumpzone = 0;
59 static const char *output_filename;
60 static char *prog_name = NULL;
61 static const dns_master_style_t *outputstyle = NULL;
62 static enum { progmode_check, progmode_compile } progmode;
63
64 #define ERRRET(result, function) \
65         do { \
66                 if (result != ISC_R_SUCCESS) { \
67                         if (!quiet) \
68                                 fprintf(stderr, "%s() returned %s\n", \
69                                         function, dns_result_totext(result)); \
70                         return (result); \
71                 } \
72         } while (0)
73
74 ISC_PLATFORM_NORETURN_PRE static void
75 usage(void) ISC_PLATFORM_NORETURN_POST;
76
77 static void
78 usage(void) {
79         fprintf(stderr,
80                 "usage: %s [-djqvD] [-c class] "
81                 "[-f inputformat] [-F outputformat] "
82                 "[-t directory] [-w directory] [-k (ignore|warn|fail)] "
83                 "[-n (ignore|warn|fail)] [-m (ignore|warn|fail)] "
84                 "[-r (ignore|warn|fail)] "
85                 "[-i (full|full-sibling|local|local-sibling|none)] "
86                 "[-M (ignore|warn|fail)] [-S (ignore|warn|fail)] "
87                 "[-W (ignore|warn)] "
88                 "%s zonename filename\n",
89                 prog_name,
90                 progmode == progmode_check ? "[-o filename]" : "-o filename");
91         exit(1);
92 }
93
94 static void
95 destroy(void) {
96         if (zone != NULL)
97                 dns_zone_detach(&zone);
98         dns_name_destroy();
99 }
100
101 /*% main processing routine */
102 int
103 main(int argc, char **argv) {
104         int c;
105         char *origin = NULL;
106         char *filename = NULL;
107         isc_log_t *lctx = NULL;
108         isc_result_t result;
109         char classname_in[] = "IN";
110         char *classname = classname_in;
111         const char *workdir = NULL;
112         const char *inputformatstr = NULL;
113         const char *outputformatstr = NULL;
114         dns_masterformat_t inputformat = dns_masterformat_text;
115         dns_masterformat_t outputformat = dns_masterformat_text;
116         dns_masterrawheader_t header;
117         isc_uint32_t rawversion = 1, serialnum = 0;
118         isc_boolean_t snset = ISC_FALSE;
119         isc_boolean_t logdump = ISC_FALSE;
120         FILE *errout = stdout;
121         char *endp;
122
123         outputstyle = &dns_master_style_full;
124
125         prog_name = strrchr(argv[0], '/');
126         if (prog_name == NULL)
127                 prog_name = strrchr(argv[0], '\\');
128         if (prog_name != NULL)
129                 prog_name++;
130         else
131                 prog_name = argv[0];
132         /*
133          * Libtool doesn't preserve the program name prior to final
134          * installation.  Remove the libtool prefix ("lt-").
135          */
136         if (strncmp(prog_name, "lt-", 3) == 0)
137                 prog_name += 3;
138
139 #define PROGCMP(X) \
140         (strcasecmp(prog_name, X) == 0 || strcasecmp(prog_name, X ".exe") == 0)
141
142         if (PROGCMP("named-checkzone"))
143                 progmode = progmode_check;
144         else if (PROGCMP("named-compilezone"))
145                 progmode = progmode_compile;
146         else
147                 INSIST(0);
148
149         /* Compilation specific defaults */
150         if (progmode == progmode_compile) {
151                 zone_options |= (DNS_ZONEOPT_CHECKNS |
152                                  DNS_ZONEOPT_FATALNS |
153                                  DNS_ZONEOPT_CHECKSPF |
154                                  DNS_ZONEOPT_CHECKDUPRR |
155                                  DNS_ZONEOPT_CHECKNAMES |
156                                  DNS_ZONEOPT_CHECKNAMESFAIL |
157                                  DNS_ZONEOPT_CHECKWILDCARD);
158         } else
159                 zone_options |= (DNS_ZONEOPT_CHECKDUPRR |
160                                  DNS_ZONEOPT_CHECKSPF);
161
162 #define ARGCMP(X) (strcmp(isc_commandline_argument, X) == 0)
163
164         isc_commandline_errprint = ISC_FALSE;
165
166         while ((c = isc_commandline_parse(argc, argv,
167                                "c:df:hi:jk:L:m:n:qr:s:t:o:vw:DF:M:S:T:W:"))
168                != EOF) {
169                 switch (c) {
170                 case 'c':
171                         classname = isc_commandline_argument;
172                         break;
173
174                 case 'd':
175                         debug++;
176                         break;
177
178                 case 'i':
179                         if (ARGCMP("full")) {
180                                 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY |
181                                                 DNS_ZONEOPT_CHECKSIBLING;
182                                 docheckmx = ISC_TRUE;
183                                 docheckns = ISC_TRUE;
184                                 dochecksrv = ISC_TRUE;
185                         } else if (ARGCMP("full-sibling")) {
186                                 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
187                                 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
188                                 docheckmx = ISC_TRUE;
189                                 docheckns = ISC_TRUE;
190                                 dochecksrv = ISC_TRUE;
191                         } else if (ARGCMP("local")) {
192                                 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
193                                 zone_options |= DNS_ZONEOPT_CHECKSIBLING;
194                                 docheckmx = ISC_FALSE;
195                                 docheckns = ISC_FALSE;
196                                 dochecksrv = ISC_FALSE;
197                         } else if (ARGCMP("local-sibling")) {
198                                 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
199                                 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
200                                 docheckmx = ISC_FALSE;
201                                 docheckns = ISC_FALSE;
202                                 dochecksrv = ISC_FALSE;
203                         } else if (ARGCMP("none")) {
204                                 zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
205                                 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
206                                 docheckmx = ISC_FALSE;
207                                 docheckns = ISC_FALSE;
208                                 dochecksrv = ISC_FALSE;
209                         } else {
210                                 fprintf(stderr, "invalid argument to -i: %s\n",
211                                         isc_commandline_argument);
212                                 exit(1);
213                         }
214                         break;
215
216                 case 'f':
217                         inputformatstr = isc_commandline_argument;
218                         break;
219
220                 case 'F':
221                         outputformatstr = isc_commandline_argument;
222                         break;
223
224                 case 'j':
225                         nomerge = ISC_FALSE;
226                         break;
227
228                 case 'k':
229                         if (ARGCMP("warn")) {
230                                 zone_options |= DNS_ZONEOPT_CHECKNAMES;
231                                 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
232                         } else if (ARGCMP("fail")) {
233                                 zone_options |= DNS_ZONEOPT_CHECKNAMES |
234                                                 DNS_ZONEOPT_CHECKNAMESFAIL;
235                         } else if (ARGCMP("ignore")) {
236                                 zone_options &= ~(DNS_ZONEOPT_CHECKNAMES |
237                                                   DNS_ZONEOPT_CHECKNAMESFAIL);
238                         } else {
239                                 fprintf(stderr, "invalid argument to -k: %s\n",
240                                         isc_commandline_argument);
241                                 exit(1);
242                         }
243                         break;
244
245                 case 'L':
246                         snset = ISC_TRUE;
247                         endp = NULL;
248                         serialnum = strtol(isc_commandline_argument, &endp, 0);
249                         if (*endp != '\0') {
250                                 fprintf(stderr, "source serial number "
251                                                 "must be numeric");
252                                 exit(1);
253                         }
254                         break;
255
256                 case 'n':
257                         if (ARGCMP("ignore")) {
258                                 zone_options &= ~(DNS_ZONEOPT_CHECKNS|
259                                                   DNS_ZONEOPT_FATALNS);
260                         } else if (ARGCMP("warn")) {
261                                 zone_options |= DNS_ZONEOPT_CHECKNS;
262                                 zone_options &= ~DNS_ZONEOPT_FATALNS;
263                         } else if (ARGCMP("fail")) {
264                                 zone_options |= DNS_ZONEOPT_CHECKNS|
265                                                 DNS_ZONEOPT_FATALNS;
266                         } else {
267                                 fprintf(stderr, "invalid argument to -n: %s\n",
268                                         isc_commandline_argument);
269                                 exit(1);
270                         }
271                         break;
272
273                 case 'm':
274                         if (ARGCMP("warn")) {
275                                 zone_options |= DNS_ZONEOPT_CHECKMX;
276                                 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
277                         } else if (ARGCMP("fail")) {
278                                 zone_options |= DNS_ZONEOPT_CHECKMX |
279                                                 DNS_ZONEOPT_CHECKMXFAIL;
280                         } else if (ARGCMP("ignore")) {
281                                 zone_options &= ~(DNS_ZONEOPT_CHECKMX |
282                                                   DNS_ZONEOPT_CHECKMXFAIL);
283                         } else {
284                                 fprintf(stderr, "invalid argument to -m: %s\n",
285                                         isc_commandline_argument);
286                                 exit(1);
287                         }
288                         break;
289
290                 case 'o':
291                         output_filename = isc_commandline_argument;
292                         break;
293
294                 case 'q':
295                         quiet++;
296                         break;
297
298                 case 'r':
299                         if (ARGCMP("warn")) {
300                                 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
301                                 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
302                         } else if (ARGCMP("fail")) {
303                                 zone_options |= DNS_ZONEOPT_CHECKDUPRR |
304                                                 DNS_ZONEOPT_CHECKDUPRRFAIL;
305                         } else if (ARGCMP("ignore")) {
306                                 zone_options &= ~(DNS_ZONEOPT_CHECKDUPRR |
307                                                   DNS_ZONEOPT_CHECKDUPRRFAIL);
308                         } else {
309                                 fprintf(stderr, "invalid argument to -r: %s\n",
310                                         isc_commandline_argument);
311                                 exit(1);
312                         }
313                         break;
314
315                 case 's':
316                         if (ARGCMP("full"))
317                                 outputstyle = &dns_master_style_full;
318                         else if (ARGCMP("relative")) {
319                                 outputstyle = &dns_master_style_default;
320                         } else {
321                                 fprintf(stderr,
322                                         "unknown or unsupported style: %s\n",
323                                         isc_commandline_argument);
324                                 exit(1);
325                         }
326                         break;
327
328                 case 't':
329                         result = isc_dir_chroot(isc_commandline_argument);
330                         if (result != ISC_R_SUCCESS) {
331                                 fprintf(stderr, "isc_dir_chroot: %s: %s\n",
332                                         isc_commandline_argument,
333                                         isc_result_totext(result));
334                                 exit(1);
335                         }
336                         break;
337
338                 case 'v':
339                         printf(VERSION "\n");
340                         exit(0);
341
342                 case 'w':
343                         workdir = isc_commandline_argument;
344                         break;
345
346                 case 'D':
347                         dumpzone++;
348                         break;
349
350                 case 'M':
351                         if (ARGCMP("fail")) {
352                                 zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
353                                 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
354                         } else if (ARGCMP("warn")) {
355                                 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
356                                 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
357                         } else if (ARGCMP("ignore")) {
358                                 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
359                                 zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
360                         } else {
361                                 fprintf(stderr, "invalid argument to -M: %s\n",
362                                         isc_commandline_argument);
363                                 exit(1);
364                         }
365                         break;
366
367                 case 'S':
368                         if (ARGCMP("fail")) {
369                                 zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
370                                 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
371                         } else if (ARGCMP("warn")) {
372                                 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
373                                 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
374                         } else if (ARGCMP("ignore")) {
375                                 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
376                                 zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
377                         } else {
378                                 fprintf(stderr, "invalid argument to -S: %s\n",
379                                         isc_commandline_argument);
380                                 exit(1);
381                         }
382                         break;
383
384                 case 'T':
385                         if (ARGCMP("warn")) {
386                                 zone_options |= DNS_ZONEOPT_CHECKSPF;
387                         } else if (ARGCMP("ignore")) {
388                                 zone_options &= ~DNS_ZONEOPT_CHECKSPF;
389                         } else {
390                                 fprintf(stderr, "invalid argument to -T: %s\n",
391                                         isc_commandline_argument);
392                                 exit(1);
393                         }
394                         break;
395
396                 case 'W':
397                         if (ARGCMP("warn"))
398                                 zone_options |= DNS_ZONEOPT_CHECKWILDCARD;
399                         else if (ARGCMP("ignore"))
400                                 zone_options &= ~DNS_ZONEOPT_CHECKWILDCARD;
401                         break;
402
403                 case '?':
404                         if (isc_commandline_option != '?')
405                                 fprintf(stderr, "%s: invalid argument -%c\n",
406                                         prog_name, isc_commandline_option);
407                         /* FALLTHROUGH */
408                 case 'h':
409                         usage();
410
411                 default:
412                         fprintf(stderr, "%s: unhandled option -%c\n",
413                                 prog_name, isc_commandline_option);
414                         exit(1);
415                 }
416         }
417
418         if (workdir != NULL) {
419                 result = isc_dir_chdir(workdir);
420                 if (result != ISC_R_SUCCESS) {
421                         fprintf(stderr, "isc_dir_chdir: %s: %s\n",
422                                 workdir, isc_result_totext(result));
423                         exit(1);
424                 }
425         }
426
427         if (inputformatstr != NULL) {
428                 if (strcasecmp(inputformatstr, "text") == 0)
429                         inputformat = dns_masterformat_text;
430                 else if (strcasecmp(inputformatstr, "raw") == 0)
431                         inputformat = dns_masterformat_raw;
432                 else if (strncasecmp(inputformatstr, "raw=", 4) == 0) {
433                         inputformat = dns_masterformat_raw;
434                         fprintf(stderr,
435                                 "WARNING: input format raw, version ignored\n");
436                 } else {
437                         fprintf(stderr, "unknown file format: %s\n",
438                             inputformatstr);
439                         exit(1);
440                 }
441         }
442
443         if (outputformatstr != NULL) {
444                 if (strcasecmp(outputformatstr, "text") == 0) {
445                         outputformat = dns_masterformat_text;
446                 } else if (strcasecmp(outputformatstr, "raw") == 0) {
447                         outputformat = dns_masterformat_raw;
448                 } else if (strncasecmp(outputformatstr, "raw=", 4) == 0) {
449                         char *end;
450
451                         outputformat = dns_masterformat_raw;
452                         rawversion = strtol(outputformatstr + 4, &end, 10);
453                         if (end == outputformatstr + 4 || *end != '\0' ||
454                             rawversion > 1U) {
455                                 fprintf(stderr,
456                                         "unknown raw format version\n");
457                                 exit(1);
458                         }
459                 } else {
460                         fprintf(stderr, "unknown file format: %s\n",
461                                 outputformatstr);
462                         exit(1);
463                 }
464         }
465
466         if (progmode == progmode_compile) {
467                 dumpzone = 1;   /* always dump */
468                 logdump = !quiet;
469                 if (output_filename == NULL) {
470                         fprintf(stderr,
471                                 "output file required, but not specified\n");
472                         usage();
473                 }
474         }
475
476         if (output_filename != NULL)
477                 dumpzone = 1;
478
479         /*
480          * If we are outputing to stdout then send the informational
481          * output to stderr.
482          */
483         if (dumpzone &&
484             (output_filename == NULL ||
485              strcmp(output_filename, "-") == 0 ||
486              strcmp(output_filename, "/dev/fd/1") == 0 ||
487              strcmp(output_filename, "/dev/stdout") == 0)) {
488                 errout = stderr;
489                 logdump = ISC_FALSE;
490         }
491
492         if (isc_commandline_index + 2 != argc)
493                 usage();
494
495 #ifdef _WIN32
496         InitSockets();
497 #endif
498
499         RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
500         if (!quiet)
501                 RUNTIME_CHECK(setup_logging(mctx, errout, &lctx)
502                               == ISC_R_SUCCESS);
503         RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS);
504         RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE)
505                       == ISC_R_SUCCESS);
506
507         dns_result_register();
508
509         origin = argv[isc_commandline_index++];
510         filename = argv[isc_commandline_index++];
511         result = load_zone(mctx, origin, filename, inputformat, classname,
512                            &zone);
513
514         if (snset) {
515                 dns_master_initrawheader(&header);
516                 header.flags = DNS_MASTERRAW_SOURCESERIALSET;
517                 header.sourceserial = serialnum;
518                 dns_zone_setrawdata(zone, &header);
519         }
520
521         if (result == ISC_R_SUCCESS && dumpzone) {
522                 if (logdump) {
523                         fprintf(errout, "dump zone to %s...", output_filename);
524                         fflush(errout);
525                 }
526                 result = dump_zone(origin, zone, output_filename,
527                                    outputformat, outputstyle, rawversion);
528                 if (logdump)
529                         fprintf(errout, "done\n");
530         }
531
532         if (!quiet && result == ISC_R_SUCCESS)
533                 fprintf(errout, "OK\n");
534         destroy();
535         if (lctx != NULL)
536                 isc_log_destroy(&lctx);
537         isc_hash_destroy();
538         isc_entropy_detach(&ectx);
539         isc_mem_destroy(&mctx);
540 #ifdef _WIN32
541         DestroySockets();
542 #endif
543         return ((result == ISC_R_SUCCESS) ? 0 : 1);
544 }