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