1 /*
2 * smallapp/unbound-checkconf.c - config file checker for unbound.conf file.
3 *
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
5 *
6 * This software is open source.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 *
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /**
37 * \file
38 *
39 * The config checker checks for syntax and other errors in the unbound.conf
40 * file, and can be used to check for errors before the server is started
41 * or sigHUPped.
42 * Exit status 1 means an error.
43 */
44
45 #include "config.h"
46 #include <ctype.h>
47 #include "util/log.h"
48 #include "util/config_file.h"
49 #include "util/module.h"
50 #include "util/net_help.h"
51 #include "util/regional.h"
52 #include "iterator/iterator.h"
53 #include "iterator/iter_fwd.h"
54 #include "iterator/iter_hints.h"
55 #include "validator/validator.h"
56 #include "services/localzone.h"
57 #include "services/listen_dnsport.h"
58 #include "services/view.h"
59 #include "services/authzone.h"
60 #include "respip/respip.h"
61 #include "sldns/sbuffer.h"
62 #include "sldns/str2wire.h"
63 #ifdef HAVE_GETOPT_H
64 #include <getopt.h>
65 #endif
66 #ifdef HAVE_PWD_H
67 #include <pwd.h>
68 #endif
69 #ifdef HAVE_SYS_STAT_H
70 #include <sys/stat.h>
71 #endif
72 #ifdef HAVE_GLOB_H
73 #include <glob.h>
74 #endif
75 #ifdef WITH_PYTHONMODULE
76 #include "pythonmod/pythonmod.h"
77 #endif
78 #ifdef CLIENT_SUBNET
79 #include "edns-subnet/subnet-whitelist.h"
80 #endif
81
82 /** Give checkconf usage, and exit (1). */
83 static void
usage(void)84 usage(void)
85 {
86 printf("Usage: unbound-checkconf [file]\n");
87 printf(" Checks unbound configuration file for errors.\n");
88 printf("file if omitted %s is used.\n", CONFIGFILE);
89 printf("-o option print value of option to stdout.\n");
90 printf("-f output full pathname with chroot applied, eg. with -o pidfile.\n");
91 printf("-h show this usage help.\n");
92 printf("Version %s\n", PACKAGE_VERSION);
93 printf("BSD licensed, see LICENSE in source package for details.\n");
94 printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
95 exit(1);
96 }
97
98 /**
99 * Print given option to stdout
100 * @param cfg: config
101 * @param opt: option name without trailing :.
102 * This is different from config_set_option.
103 * @param final: if final pathname with chroot applied has to be printed.
104 */
105 static void
print_option(struct config_file * cfg,const char * opt,int final)106 print_option(struct config_file* cfg, const char* opt, int final)
107 {
108 if(strcmp(opt, "pidfile") == 0 && final) {
109 char *p = fname_after_chroot(cfg->pidfile, cfg, 1);
110 if(!p) fatal_exit("out of memory");
111 printf("%s\n", p);
112 free(p);
113 return;
114 }
115 if(strcmp(opt, "auto-trust-anchor-file") == 0 && final) {
116 struct config_strlist* s = cfg->auto_trust_anchor_file_list;
117 for(; s; s=s->next) {
118 char *p = fname_after_chroot(s->str, cfg, 1);
119 if(!p) fatal_exit("out of memory");
120 printf("%s\n", p);
121 free(p);
122 }
123 return;
124 }
125 if(!config_get_option(cfg, opt, config_print_func, stdout))
126 fatal_exit("cannot print option '%s'", opt);
127 }
128
129 /** check if module works with config */
130 static void
check_mod(struct config_file * cfg,struct module_func_block * fb)131 check_mod(struct config_file* cfg, struct module_func_block* fb)
132 {
133 struct module_env env;
134 memset(&env, 0, sizeof(env));
135 env.cfg = cfg;
136 env.scratch = regional_create();
137 env.scratch_buffer = sldns_buffer_new(BUFSIZ);
138 if(!env.scratch || !env.scratch_buffer)
139 fatal_exit("out of memory");
140 if(!edns_known_options_init(&env))
141 fatal_exit("out of memory");
142 if(!(*fb->init)(&env, 0)) {
143 fatal_exit("bad config for %s module", fb->name);
144 }
145 (*fb->deinit)(&env, 0);
146 sldns_buffer_free(env.scratch_buffer);
147 regional_destroy(env.scratch);
148 edns_known_options_delete(&env);
149 }
150
151 /** true if addr is a localhost address, 127.0.0.1 or ::1 (with maybe "@port"
152 * after it) */
153 static int
str_addr_is_localhost(const char * a)154 str_addr_is_localhost(const char* a)
155 {
156 if(strncmp(a, "127.", 4) == 0) return 1;
157 if(strncmp(a, "::1", 3) == 0) return 1;
158 return 0;
159 }
160
161 /** check do-not-query-localhost */
162 static void
donotquerylocalhostcheck(struct config_file * cfg)163 donotquerylocalhostcheck(struct config_file* cfg)
164 {
165 if(cfg->donotquery_localhost) {
166 struct config_stub* p;
167 struct config_strlist* s;
168 for(p=cfg->forwards; p; p=p->next) {
169 for(s=p->addrs; s; s=s->next) {
170 if(str_addr_is_localhost(s->str)) {
171 fprintf(stderr, "unbound-checkconf: warning: forward-addr: '%s' is specified for forward-zone: '%s', but do-not-query-localhost: yes means that the address will not be used for lookups.\n",
172 s->str, p->name);
173 }
174 }
175 }
176 for(p=cfg->stubs; p; p=p->next) {
177 for(s=p->addrs; s; s=s->next) {
178 if(str_addr_is_localhost(s->str)) {
179 fprintf(stderr, "unbound-checkconf: warning: stub-addr: '%s' is specified for stub-zone: '%s', but do-not-query-localhost: yes means that the address will not be used for lookups.\n",
180 s->str, p->name);
181 }
182 }
183 }
184 }
185 }
186
187 /** check localzones */
188 static void
localzonechecks(struct config_file * cfg)189 localzonechecks(struct config_file* cfg)
190 {
191 struct local_zones* zs;
192 if(!(zs = local_zones_create()))
193 fatal_exit("out of memory");
194 if(!local_zones_apply_cfg(zs, cfg))
195 fatal_exit("failed local-zone, local-data configuration");
196 local_zones_delete(zs);
197 }
198
199 /** checks for acl and views */
200 static void
acl_view_tag_checks(struct config_file * cfg,struct views * views)201 acl_view_tag_checks(struct config_file* cfg, struct views* views)
202 {
203 int d;
204 struct sockaddr_storage a;
205 socklen_t alen;
206 struct config_str2list* acl;
207 struct config_str3list* s3;
208 struct config_strbytelist* sb;
209
210 /* acl_view */
211 for(acl=cfg->acl_view; acl; acl = acl->next) {
212 struct view* v;
213 if(!netblockstrtoaddr(acl->str, UNBOUND_DNS_PORT, &a, &alen,
214 &d)) {
215 fatal_exit("cannot parse access-control-view "
216 "address %s %s", acl->str, acl->str2);
217 }
218 v = views_find_view(views, acl->str2, 0);
219 if(!v) {
220 fatal_exit("cannot find view for "
221 "access-control-view: %s %s",
222 acl->str, acl->str2);
223 }
224 lock_rw_unlock(&v->lock);
225 }
226
227 /* acl_tags */
228 for(sb=cfg->acl_tags; sb; sb = sb->next) {
229 if(!netblockstrtoaddr(sb->str, UNBOUND_DNS_PORT, &a, &alen,
230 &d)) {
231 fatal_exit("cannot parse access-control-tags "
232 "address %s", sb->str);
233 }
234 }
235
236 /* acl_tag_actions */
237 for(s3=cfg->acl_tag_actions; s3; s3 = s3->next) {
238 enum localzone_type t;
239 if(!netblockstrtoaddr(s3->str, UNBOUND_DNS_PORT, &a, &alen,
240 &d)) {
241 fatal_exit("cannot parse access-control-tag-actions "
242 "address %s %s %s",
243 s3->str, s3->str2, s3->str3);
244 }
245 if(find_tag_id(cfg, s3->str2) == -1) {
246 fatal_exit("cannot parse tag %s (define-tag it), "
247 "for access-control-tag-actions: %s %s %s",
248 s3->str2, s3->str, s3->str2, s3->str3);
249 }
250 if(!local_zone_str2type(s3->str3, &t)) {
251 fatal_exit("cannot parse access control action type %s"
252 " for access-control-tag-actions: %s %s %s",
253 s3->str3, s3->str, s3->str2, s3->str3);
254 }
255 }
256
257 /* acl_tag_datas */
258 for(s3=cfg->acl_tag_datas; s3; s3 = s3->next) {
259 char buf[65536];
260 uint8_t rr[LDNS_RR_BUF_SIZE];
261 size_t len = sizeof(rr);
262 int res;
263 if(!netblockstrtoaddr(s3->str, UNBOUND_DNS_PORT, &a, &alen,
264 &d)) {
265 fatal_exit("cannot parse access-control-tag-datas address %s %s '%s'",
266 s3->str, s3->str2, s3->str3);
267 }
268 if(find_tag_id(cfg, s3->str2) == -1) {
269 fatal_exit("cannot parse tag %s (define-tag it), "
270 "for access-control-tag-datas: %s %s '%s'",
271 s3->str2, s3->str, s3->str2, s3->str3);
272 }
273 /* '.' is sufficient for validation, and it makes the call to
274 * sldns_wirerr_get_type() simpler below. */
275 snprintf(buf, sizeof(buf), "%s %s", ".", s3->str3);
276 res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600, NULL,
277 0, NULL, 0);
278 if(res != 0) {
279 fatal_exit("cannot parse rr data [char %d] parse error %s, for access-control-tag-datas: %s %s '%s'",
280 (int)LDNS_WIREPARSE_OFFSET(res)-2,
281 sldns_get_errorstr_parse(res),
282 s3->str, s3->str2, s3->str3);
283 }
284 }
285 }
286
287 /** check view and response-ip configuration */
288 static void
view_and_respipchecks(struct config_file * cfg)289 view_and_respipchecks(struct config_file* cfg)
290 {
291 struct views* views = NULL;
292 struct respip_set* respip = NULL;
293 int ignored = 0;
294 if(!(views = views_create()))
295 fatal_exit("Could not create views: out of memory");
296 if(!(respip = respip_set_create()))
297 fatal_exit("Could not create respip set: out of memory");
298 if(!views_apply_cfg(views, cfg))
299 fatal_exit("Could not set up views");
300 if(!respip_global_apply_cfg(respip, cfg))
301 fatal_exit("Could not setup respip set");
302 if(!respip_views_apply_cfg(views, cfg, &ignored))
303 fatal_exit("Could not setup per-view respip sets");
304 acl_view_tag_checks(cfg, views);
305 views_delete(views);
306 respip_set_delete(respip);
307 }
308
309 /** emit warnings for IP in hosts */
310 static void
warn_hosts(const char * typ,struct config_stub * list)311 warn_hosts(const char* typ, struct config_stub* list)
312 {
313 struct sockaddr_storage a;
314 socklen_t alen;
315 struct config_stub* s;
316 struct config_strlist* h;
317 for(s=list; s; s=s->next) {
318 for(h=s->hosts; h; h=h->next) {
319 if(extstrtoaddr(h->str, &a, &alen)) {
320 fprintf(stderr, "unbound-checkconf: warning:"
321 " %s %s: \"%s\" is an IP%s address, "
322 "and when looked up as a host name "
323 "during use may not resolve.\n",
324 s->name, typ, h->str,
325 addr_is_ip6(&a, alen)?"6":"4");
326 }
327 }
328 }
329 }
330
331 /** check interface strings */
332 static void
interfacechecks(struct config_file * cfg)333 interfacechecks(struct config_file* cfg)
334 {
335 int d;
336 struct sockaddr_storage a;
337 socklen_t alen;
338 int i, j, i2, j2;
339 char*** resif = NULL;
340 int* num_resif = NULL;
341
342 if(cfg->num_ifs != 0) {
343 resif = (char***)calloc(cfg->num_ifs, sizeof(char**));
344 if(!resif) fatal_exit("malloc failure");
345 num_resif = (int*)calloc(cfg->num_ifs, sizeof(int));
346 if(!num_resif) fatal_exit("malloc failure");
347 }
348 for(i=0; i<cfg->num_ifs; i++) {
349 /* search for duplicates in IP or ifname arguments */
350 for(i2=0; i2<i; i2++) {
351 if(strcmp(cfg->ifs[i], cfg->ifs[i2]) == 0) {
352 fatal_exit("interface: %s present twice, "
353 "cannot bind same ports twice.",
354 cfg->ifs[i]);
355 }
356 }
357 if(!resolve_interface_names(&cfg->ifs[i], 1, NULL, &resif[i],
358 &num_resif[i])) {
359 fatal_exit("could not resolve interface names, for %s",
360 cfg->ifs[i]);
361 }
362 /* search for duplicates in the returned addresses */
363 for(j=0; j<num_resif[i]; j++) {
364 if(!extstrtoaddr(resif[i][j], &a, &alen)) {
365 if(strcmp(cfg->ifs[i], resif[i][j]) != 0)
366 fatal_exit("cannot parse interface address '%s' from the interface specified as '%s'",
367 resif[i][j], cfg->ifs[i]);
368 else
369 fatal_exit("cannot parse interface specified as '%s'",
370 cfg->ifs[i]);
371 }
372 for(i2=0; i2<i; i2++) {
373 for(j2=0; j2<num_resif[i2]; j2++) {
374 if(strcmp(resif[i][j], resif[i2][j2])
375 == 0) {
376 char info1[1024], info2[1024];
377 if(strcmp(cfg->ifs[i], resif[i][j]) != 0)
378 snprintf(info1, sizeof(info1), "address %s from interface: %s", resif[i][j], cfg->ifs[i]);
379 else snprintf(info1, sizeof(info1), "interface: %s", cfg->ifs[i]);
380 if(strcmp(cfg->ifs[i2], resif[i2][j2]) != 0)
381 snprintf(info2, sizeof(info2), "address %s from interface: %s", resif[i2][j2], cfg->ifs[i2]);
382 else snprintf(info2, sizeof(info2), "interface: %s", cfg->ifs[i2]);
383 fatal_exit("%s present twice, cannot bind the same ports twice. The first entry is %s and the second is %s", resif[i][j], info2, info1);
384 }
385 }
386 }
387 }
388 }
389
390 for(i=0; i<cfg->num_ifs; i++) {
391 config_del_strarray(resif[i], num_resif[i]);
392 }
393 free(resif);
394 free(num_resif);
395
396 for(i=0; i<cfg->num_out_ifs; i++) {
397 if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen) &&
398 !netblockstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen, &d)) {
399 fatal_exit("cannot parse outgoing-interface "
400 "specified as '%s'", cfg->out_ifs[i]);
401 }
402 for(j=0; j<cfg->num_out_ifs; j++) {
403 if(i!=j && strcmp(cfg->out_ifs[i], cfg->out_ifs[j])==0)
404 fatal_exit("outgoing-interface: %s present "
405 "twice, cannot bind same ports twice.",
406 cfg->out_ifs[i]);
407 }
408 }
409 }
410
411 /** check acl ips */
412 static void
aclchecks(struct config_file * cfg)413 aclchecks(struct config_file* cfg)
414 {
415 int d;
416 struct sockaddr_storage a;
417 socklen_t alen;
418 struct config_str2list* acl;
419 for(acl=cfg->acls; acl; acl = acl->next) {
420 if(!netblockstrtoaddr(acl->str, UNBOUND_DNS_PORT, &a, &alen,
421 &d)) {
422 fatal_exit("cannot parse access control address %s %s",
423 acl->str, acl->str2);
424 }
425 }
426 }
427
428 /** check tcp connection limit ips */
429 static void
tcpconnlimitchecks(struct config_file * cfg)430 tcpconnlimitchecks(struct config_file* cfg)
431 {
432 int d;
433 struct sockaddr_storage a;
434 socklen_t alen;
435 struct config_str2list* tcl;
436 for(tcl=cfg->tcp_connection_limits; tcl; tcl = tcl->next) {
437 if(!netblockstrtoaddr(tcl->str, UNBOUND_DNS_PORT, &a, &alen,
438 &d)) {
439 fatal_exit("cannot parse tcp connection limit address %s %s",
440 tcl->str, tcl->str2);
441 }
442 }
443 }
444
445 /** true if fname is a file */
446 static int
is_file(const char * fname)447 is_file(const char* fname)
448 {
449 struct stat buf;
450 if(stat(fname, &buf) < 0) {
451 if(errno==EACCES) {
452 printf("warning: no search permission for one of the directories in path: %s\n", fname);
453 return 1;
454 }
455 perror(fname);
456 return 0;
457 }
458 if(S_ISDIR(buf.st_mode)) {
459 printf("%s is not a file\n", fname);
460 return 0;
461 }
462 return 1;
463 }
464
465 /** true if fname is a directory */
466 static int
is_dir(const char * fname)467 is_dir(const char* fname)
468 {
469 struct stat buf;
470 if(stat(fname, &buf) < 0) {
471 if(errno==EACCES) {
472 printf("warning: no search permission for one of the directories in path: %s\n", fname);
473 return 1;
474 }
475 perror(fname);
476 return 0;
477 }
478 if(!(S_ISDIR(buf.st_mode))) {
479 printf("%s is not a directory\n", fname);
480 return 0;
481 }
482 return 1;
483 }
484
485 /** get base dir of a fname */
486 static char*
basedir(char * fname)487 basedir(char* fname)
488 {
489 char* rev;
490 if(!fname) fatal_exit("out of memory");
491 rev = strrchr(fname, '/');
492 if(!rev) return NULL;
493 if(fname == rev) return NULL;
494 rev[0] = 0;
495 return fname;
496 }
497
498 /** check chroot for a file string */
499 static void
check_chroot_string(const char * desc,char ** ss,const char * chrootdir,struct config_file * cfg)500 check_chroot_string(const char* desc, char** ss,
501 const char* chrootdir, struct config_file* cfg)
502 {
503 char* str = *ss;
504 if(str && str[0]) {
505 *ss = fname_after_chroot(str, cfg, 1);
506 if(!*ss) fatal_exit("out of memory");
507 if(!is_file(*ss)) {
508 if(chrootdir && chrootdir[0])
509 fatal_exit("%s: \"%s\" does not exist in "
510 "chrootdir %s", desc, str, chrootdir);
511 else
512 fatal_exit("%s: \"%s\" does not exist",
513 desc, str);
514 }
515 /* put in a new full path for continued checking */
516 free(str);
517 }
518 }
519
520 /** check file list, every file must be inside the chroot location */
521 static void
check_chroot_filelist(const char * desc,struct config_strlist * list,const char * chrootdir,struct config_file * cfg)522 check_chroot_filelist(const char* desc, struct config_strlist* list,
523 const char* chrootdir, struct config_file* cfg)
524 {
525 struct config_strlist* p;
526 for(p=list; p; p=p->next) {
527 check_chroot_string(desc, &p->str, chrootdir, cfg);
528 }
529 }
530
531 /** check file list, with wildcard processing */
532 static void
check_chroot_filelist_wild(const char * desc,struct config_strlist * list,const char * chrootdir,struct config_file * cfg)533 check_chroot_filelist_wild(const char* desc, struct config_strlist* list,
534 const char* chrootdir, struct config_file* cfg)
535 {
536 struct config_strlist* p;
537 for(p=list; p; p=p->next) {
538 #ifdef HAVE_GLOB
539 if(strchr(p->str, '*') || strchr(p->str, '[') ||
540 strchr(p->str, '?') || strchr(p->str, '{') ||
541 strchr(p->str, '~')) {
542 char* s = p->str;
543 /* adjust whole pattern for chroot and check later */
544 p->str = fname_after_chroot(p->str, cfg, 1);
545 free(s);
546 } else
547 #endif /* HAVE_GLOB */
548 check_chroot_string(desc, &p->str, chrootdir, cfg);
549 }
550 }
551
552 #ifdef CLIENT_SUBNET
553 /** check ECS configuration */
554 static void
ecs_conf_checks(struct config_file * cfg)555 ecs_conf_checks(struct config_file* cfg)
556 {
557 struct ecs_whitelist* whitelist = NULL;
558 if(!(whitelist = ecs_whitelist_create()))
559 fatal_exit("Could not create ednssubnet whitelist: out of memory");
560 if(!ecs_whitelist_apply_cfg(whitelist, cfg))
561 fatal_exit("Could not setup ednssubnet whitelist");
562 ecs_whitelist_delete(whitelist);
563 }
564 #endif /* CLIENT_SUBNET */
565
566 /** check that the modules exist, are compiled in */
567 static void
check_modules_exist(const char * module_conf)568 check_modules_exist(const char* module_conf)
569 {
570 const char** names = module_list_avail();
571 const char* s = module_conf;
572 while(*s) {
573 int i = 0;
574 int is_ok = 0;
575 while(*s && isspace((unsigned char)*s))
576 s++;
577 if(!*s) break;
578 while(names[i]) {
579 if(strncmp(names[i], s, strlen(names[i])) == 0) {
580 is_ok = 1;
581 break;
582 }
583 i++;
584 }
585 if(is_ok == 0) {
586 char n[64];
587 size_t j;
588 n[0]=0;
589 n[sizeof(n)-1]=0;
590 for(j=0; j<sizeof(n)-1; j++) {
591 if(!s[j] || isspace((unsigned char)s[j])) {
592 n[j] = 0;
593 break;
594 }
595 n[j] = s[j];
596 }
597 fatal_exit("module_conf lists module '%s' but that "
598 "module is not available.", n);
599 }
600 s += strlen(names[i]);
601 }
602 }
603
604 /** check configuration for errors */
605 static void
morechecks(struct config_file * cfg)606 morechecks(struct config_file* cfg)
607 {
608 warn_hosts("stub-host", cfg->stubs);
609 warn_hosts("forward-host", cfg->forwards);
610 interfacechecks(cfg);
611 aclchecks(cfg);
612 tcpconnlimitchecks(cfg);
613
614 if(cfg->verbosity < 0)
615 fatal_exit("verbosity value < 0");
616 if(cfg->num_threads <= 0 || cfg->num_threads > 10000)
617 fatal_exit("num_threads value weird");
618 if(!cfg->do_ip4 && !cfg->do_ip6)
619 fatal_exit("ip4 and ip6 are both disabled, pointless");
620 if(!cfg->do_ip4 && cfg->prefer_ip4)
621 fatal_exit("cannot prefer and disable ip4, pointless");
622 if(!cfg->do_ip6 && cfg->prefer_ip6)
623 fatal_exit("cannot prefer and disable ip6, pointless");
624 if(!cfg->do_udp && !cfg->do_tcp)
625 fatal_exit("udp and tcp are both disabled, pointless");
626 if(cfg->edns_buffer_size > cfg->msg_buffer_size)
627 fatal_exit("edns-buffer-size larger than msg-buffer-size, "
628 "answers will not fit in processing buffer");
629 #ifdef UB_ON_WINDOWS
630 w_config_adjust_directory(cfg);
631 #endif
632 if(cfg->chrootdir && cfg->chrootdir[0] &&
633 cfg->chrootdir[strlen(cfg->chrootdir)-1] == '/')
634 fatal_exit("chootdir %s has trailing slash '/' please remove.",
635 cfg->chrootdir);
636 if(cfg->chrootdir && cfg->chrootdir[0] &&
637 !is_dir(cfg->chrootdir)) {
638 fatal_exit("bad chroot directory");
639 }
640 if(cfg->directory && cfg->directory[0]) {
641 char* ad = fname_after_chroot(cfg->directory, cfg, 0);
642 if(!ad) fatal_exit("out of memory");
643 if(!is_dir(ad)) fatal_exit("bad chdir directory");
644 free(ad);
645 }
646 if( (cfg->chrootdir && cfg->chrootdir[0]) ||
647 (cfg->directory && cfg->directory[0])) {
648 if(cfg->pidfile && cfg->pidfile[0]) {
649 char* ad = (cfg->pidfile[0]=='/')?strdup(cfg->pidfile):
650 fname_after_chroot(cfg->pidfile, cfg, 1);
651 char* bd = basedir(ad);
652 if(bd && !is_dir(bd))
653 fatal_exit("pidfile directory does not exist");
654 free(ad);
655 }
656 if(cfg->logfile && cfg->logfile[0]) {
657 char* ad = fname_after_chroot(cfg->logfile, cfg, 1);
658 char* bd = basedir(ad);
659 if(bd && !is_dir(bd))
660 fatal_exit("logfile directory does not exist");
661 free(ad);
662 }
663 }
664
665 check_chroot_filelist("file with root-hints",
666 cfg->root_hints, cfg->chrootdir, cfg);
667 check_chroot_filelist("trust-anchor-file",
668 cfg->trust_anchor_file_list, cfg->chrootdir, cfg);
669 check_chroot_filelist("auto-trust-anchor-file",
670 cfg->auto_trust_anchor_file_list, cfg->chrootdir, cfg);
671 check_chroot_filelist_wild("trusted-keys-file",
672 cfg->trusted_keys_file_list, cfg->chrootdir, cfg);
673 #ifdef USE_IPSECMOD
674 if(cfg->ipsecmod_enabled && strstr(cfg->module_conf, "ipsecmod")) {
675 /* only check hook if enabled */
676 check_chroot_string("ipsecmod-hook", &cfg->ipsecmod_hook,
677 cfg->chrootdir, cfg);
678 }
679 #endif
680 /* remove chroot setting so that modules are not stripping pathnames*/
681 free(cfg->chrootdir);
682 cfg->chrootdir = NULL;
683
684 /* check that the modules listed in module_conf exist */
685 check_modules_exist(cfg->module_conf);
686
687 /* Respip is known to *not* work with dns64. */
688 if(strcmp(cfg->module_conf, "iterator") != 0
689 && strcmp(cfg->module_conf, "validator iterator") != 0
690 && strcmp(cfg->module_conf, "dns64 validator iterator") != 0
691 && strcmp(cfg->module_conf, "dns64 iterator") != 0
692 && strcmp(cfg->module_conf, "respip iterator") != 0
693 && strcmp(cfg->module_conf, "respip validator iterator") != 0
694 #ifdef WITH_PYTHONMODULE
695 && strcmp(cfg->module_conf, "python iterator") != 0
696 && strcmp(cfg->module_conf, "python respip iterator") != 0
697 && strcmp(cfg->module_conf, "python validator iterator") != 0
698 && strcmp(cfg->module_conf, "python respip validator iterator") != 0
699 && strcmp(cfg->module_conf, "validator python iterator") != 0
700 && strcmp(cfg->module_conf, "dns64 python iterator") != 0
701 && strcmp(cfg->module_conf, "dns64 python validator iterator") != 0
702 && strcmp(cfg->module_conf, "dns64 validator python iterator") != 0
703 && strcmp(cfg->module_conf, "python dns64 iterator") != 0
704 && strcmp(cfg->module_conf, "python dns64 validator iterator") != 0
705 #endif
706 #ifdef WITH_DYNLIBMODULE
707 && strcmp(cfg->module_conf, "dynlib iterator") != 0
708 && strcmp(cfg->module_conf, "dynlib dynlib iterator") != 0
709 && strcmp(cfg->module_conf, "dynlib dynlib dynlib iterator") != 0
710 && strcmp(cfg->module_conf, "python dynlib iterator") != 0
711 && strcmp(cfg->module_conf, "python dynlib dynlib iterator") != 0
712 && strcmp(cfg->module_conf, "python dynlib dynlib dynlib iterator") != 0
713 && strcmp(cfg->module_conf, "dynlib respip iterator") != 0
714 && strcmp(cfg->module_conf, "dynlib validator iterator") != 0
715 && strcmp(cfg->module_conf, "dynlib dynlib validator iterator") != 0
716 && strcmp(cfg->module_conf, "dynlib dynlib dynlib validator iterator") != 0
717 && strcmp(cfg->module_conf, "python dynlib validator iterator") != 0
718 && strcmp(cfg->module_conf, "python dynlib dynlib validator iterator") != 0
719 && strcmp(cfg->module_conf, "python dynlib dynlib dynlib validator iterator") != 0
720 && strcmp(cfg->module_conf, "dynlib respip validator iterator") != 0
721 && strcmp(cfg->module_conf, "validator dynlib iterator") != 0
722 && strcmp(cfg->module_conf, "dns64 dynlib iterator") != 0
723 && strcmp(cfg->module_conf, "dns64 dynlib validator iterator") != 0
724 && strcmp(cfg->module_conf, "dns64 validator dynlib iterator") != 0
725 && strcmp(cfg->module_conf, "dynlib dns64 iterator") != 0
726 && strcmp(cfg->module_conf, "dynlib dns64 validator iterator") != 0
727 && strcmp(cfg->module_conf, "dynlib dns64 cachedb iterator") != 0
728 && strcmp(cfg->module_conf, "dynlib dns64 validator cachedb iterator") != 0
729 && strcmp(cfg->module_conf, "dns64 dynlib cachedb iterator") != 0
730 && strcmp(cfg->module_conf, "dns64 dynlib validator cachedb iterator") != 0
731 && strcmp(cfg->module_conf, "dynlib cachedb iterator") != 0
732 && strcmp(cfg->module_conf, "dynlib respip cachedb iterator") != 0
733 && strcmp(cfg->module_conf, "dynlib validator cachedb iterator") != 0
734 && strcmp(cfg->module_conf, "dynlib respip validator cachedb iterator") != 0
735 && strcmp(cfg->module_conf, "cachedb dynlib iterator") != 0
736 && strcmp(cfg->module_conf, "respip cachedb dynlib iterator") != 0
737 && strcmp(cfg->module_conf, "validator cachedb dynlib iterator") != 0
738 && strcmp(cfg->module_conf, "respip validator cachedb dynlib iterator") != 0
739 && strcmp(cfg->module_conf, "validator dynlib cachedb iterator") != 0
740 && strcmp(cfg->module_conf, "respip validator dynlib cachedb iterator") != 0
741 && strcmp(cfg->module_conf, "dynlib subnetcache iterator") != 0
742 && strcmp(cfg->module_conf, "dynlib respip subnetcache iterator") != 0
743 && strcmp(cfg->module_conf, "subnetcache dynlib iterator") != 0
744 && strcmp(cfg->module_conf, "respip subnetcache dynlib iterator") != 0
745 && strcmp(cfg->module_conf, "dynlib subnetcache validator iterator") != 0
746 && strcmp(cfg->module_conf, "dynlib respip subnetcache validator iterator") != 0
747 && strcmp(cfg->module_conf, "subnetcache dynlib validator iterator") != 0
748 && strcmp(cfg->module_conf, "respip subnetcache dynlib validator iterator") != 0
749 && strcmp(cfg->module_conf, "subnetcache validator dynlib iterator") != 0
750 && strcmp(cfg->module_conf, "respip subnetcache validator dynlib iterator") != 0
751 && strcmp(cfg->module_conf, "dynlib ipsecmod iterator") != 0
752 && strcmp(cfg->module_conf, "dynlib ipsecmod respip iterator") != 0
753 && strcmp(cfg->module_conf, "ipsecmod dynlib iterator") != 0
754 && strcmp(cfg->module_conf, "ipsecmod dynlib respip iterator") != 0
755 && strcmp(cfg->module_conf, "ipsecmod validator iterator") != 0
756 && strcmp(cfg->module_conf, "ipsecmod respip validator iterator") != 0
757 && strcmp(cfg->module_conf, "dynlib ipsecmod validator iterator") != 0
758 && strcmp(cfg->module_conf, "dynlib ipsecmod respip validator iterator") != 0
759 && strcmp(cfg->module_conf, "ipsecmod dynlib validator iterator") != 0
760 && strcmp(cfg->module_conf, "ipsecmod dynlib respip validator iterator") != 0
761 && strcmp(cfg->module_conf, "ipsecmod validator dynlib iterator") != 0
762 && strcmp(cfg->module_conf, "ipsecmod respip validator dynlib iterator") != 0
763 #endif
764 #ifdef USE_CACHEDB
765 && strcmp(cfg->module_conf, "validator cachedb iterator") != 0
766 && strcmp(cfg->module_conf, "respip validator cachedb iterator") != 0
767 && strcmp(cfg->module_conf, "cachedb iterator") != 0
768 && strcmp(cfg->module_conf, "respip cachedb iterator") != 0
769 && strcmp(cfg->module_conf, "dns64 validator cachedb iterator") != 0
770 && strcmp(cfg->module_conf, "dns64 cachedb iterator") != 0
771 #endif
772 #if defined(WITH_PYTHONMODULE) && defined(USE_CACHEDB)
773 && strcmp(cfg->module_conf, "python dns64 cachedb iterator") != 0
774 && strcmp(cfg->module_conf, "python dns64 validator cachedb iterator") != 0
775 && strcmp(cfg->module_conf, "dns64 python cachedb iterator") != 0
776 && strcmp(cfg->module_conf, "dns64 python validator cachedb iterator") != 0
777 && strcmp(cfg->module_conf, "python cachedb iterator") != 0
778 && strcmp(cfg->module_conf, "python respip cachedb iterator") != 0
779 && strcmp(cfg->module_conf, "python validator cachedb iterator") != 0
780 && strcmp(cfg->module_conf, "python respip validator cachedb iterator") != 0
781 && strcmp(cfg->module_conf, "cachedb python iterator") != 0
782 && strcmp(cfg->module_conf, "respip cachedb python iterator") != 0
783 && strcmp(cfg->module_conf, "validator cachedb python iterator") != 0
784 && strcmp(cfg->module_conf, "respip validator cachedb python iterator") != 0
785 && strcmp(cfg->module_conf, "validator python cachedb iterator") != 0
786 && strcmp(cfg->module_conf, "respip validator python cachedb iterator") != 0
787 #endif
788 #ifdef CLIENT_SUBNET
789 && strcmp(cfg->module_conf, "subnetcache iterator") != 0
790 && strcmp(cfg->module_conf, "respip subnetcache iterator") != 0
791 && strcmp(cfg->module_conf, "subnetcache validator iterator") != 0
792 && strcmp(cfg->module_conf, "respip subnetcache validator iterator") != 0
793 && strcmp(cfg->module_conf, "dns64 subnetcache iterator") != 0
794 && strcmp(cfg->module_conf, "dns64 subnetcache validator iterator") != 0
795 && strcmp(cfg->module_conf, "dns64 subnetcache respip iterator") != 0
796 && strcmp(cfg->module_conf, "dns64 subnetcache respip validator iterator") != 0
797 #endif
798 #if defined(WITH_PYTHONMODULE) && defined(CLIENT_SUBNET)
799 && strcmp(cfg->module_conf, "python subnetcache iterator") != 0
800 && strcmp(cfg->module_conf, "python respip subnetcache iterator") != 0
801 && strcmp(cfg->module_conf, "subnetcache python iterator") != 0
802 && strcmp(cfg->module_conf, "respip subnetcache python iterator") != 0
803 && strcmp(cfg->module_conf, "python subnetcache validator iterator") != 0
804 && strcmp(cfg->module_conf, "python respip subnetcache validator iterator") != 0
805 && strcmp(cfg->module_conf, "subnetcache python validator iterator") != 0
806 && strcmp(cfg->module_conf, "respip subnetcache python validator iterator") != 0
807 && strcmp(cfg->module_conf, "subnetcache validator python iterator") != 0
808 && strcmp(cfg->module_conf, "respip subnetcache validator python iterator") != 0
809 #endif
810 #ifdef USE_IPSECMOD
811 && strcmp(cfg->module_conf, "ipsecmod iterator") != 0
812 && strcmp(cfg->module_conf, "ipsecmod respip iterator") != 0
813 && strcmp(cfg->module_conf, "ipsecmod validator iterator") != 0
814 && strcmp(cfg->module_conf, "ipsecmod respip validator iterator") != 0
815 #endif
816 #if defined(WITH_PYTHONMODULE) && defined(USE_IPSECMOD)
817 && strcmp(cfg->module_conf, "python ipsecmod iterator") != 0
818 && strcmp(cfg->module_conf, "python ipsecmod respip iterator") != 0
819 && strcmp(cfg->module_conf, "ipsecmod python iterator") != 0
820 && strcmp(cfg->module_conf, "ipsecmod python respip iterator") != 0
821 && strcmp(cfg->module_conf, "ipsecmod validator iterator") != 0
822 && strcmp(cfg->module_conf, "ipsecmod respip validator iterator") != 0
823 && strcmp(cfg->module_conf, "python ipsecmod validator iterator") != 0
824 && strcmp(cfg->module_conf, "python ipsecmod respip validator iterator") != 0
825 && strcmp(cfg->module_conf, "ipsecmod python validator iterator") != 0
826 && strcmp(cfg->module_conf, "ipsecmod python respip validator iterator") != 0
827 && strcmp(cfg->module_conf, "ipsecmod validator python iterator") != 0
828 && strcmp(cfg->module_conf, "ipsecmod respip validator python iterator") != 0
829 #endif
830 #ifdef USE_IPSET
831 && strcmp(cfg->module_conf, "validator ipset iterator") != 0
832 && strcmp(cfg->module_conf, "validator ipset respip iterator") != 0
833 && strcmp(cfg->module_conf, "ipset iterator") != 0
834 && strcmp(cfg->module_conf, "ipset respip iterator") != 0
835 #endif
836 ) {
837 fatal_exit("module conf '%s' is not known to work",
838 cfg->module_conf);
839 }
840
841 #ifdef HAVE_GETPWNAM
842 if(cfg->username && cfg->username[0]) {
843 if(getpwnam(cfg->username) == NULL)
844 fatal_exit("user '%s' does not exist.", cfg->username);
845 # ifdef HAVE_ENDPWENT
846 endpwent();
847 # endif
848 }
849 #endif
850 if(cfg->remote_control_enable && options_remote_is_address(cfg)
851 && cfg->control_use_cert) {
852 check_chroot_string("server-key-file", &cfg->server_key_file,
853 cfg->chrootdir, cfg);
854 check_chroot_string("server-cert-file", &cfg->server_cert_file,
855 cfg->chrootdir, cfg);
856 if(!is_file(cfg->control_key_file))
857 fatal_exit("control-key-file: \"%s\" does not exist",
858 cfg->control_key_file);
859 if(!is_file(cfg->control_cert_file))
860 fatal_exit("control-cert-file: \"%s\" does not exist",
861 cfg->control_cert_file);
862 }
863
864 donotquerylocalhostcheck(cfg);
865 localzonechecks(cfg);
866 view_and_respipchecks(cfg);
867 #ifdef CLIENT_SUBNET
868 ecs_conf_checks(cfg);
869 #endif
870 }
871
872 /** check forwards */
873 static void
check_fwd(struct config_file * cfg)874 check_fwd(struct config_file* cfg)
875 {
876 struct iter_forwards* fwd = forwards_create();
877 if(!fwd || !forwards_apply_cfg(fwd, cfg)) {
878 fatal_exit("Could not set forward zones");
879 }
880 forwards_delete(fwd);
881 }
882
883 /** check hints */
884 static void
check_hints(struct config_file * cfg)885 check_hints(struct config_file* cfg)
886 {
887 struct iter_hints* hints = hints_create();
888 if(!hints || !hints_apply_cfg(hints, cfg)) {
889 fatal_exit("Could not set root or stub hints");
890 }
891 hints_delete(hints);
892 }
893
894 /** check auth zones */
895 static void
check_auth(struct config_file * cfg)896 check_auth(struct config_file* cfg)
897 {
898 int is_rpz = 0;
899 struct auth_zones* az = auth_zones_create();
900 if(!az || !auth_zones_apply_cfg(az, cfg, 0, &is_rpz, NULL, NULL)) {
901 fatal_exit("Could not setup authority zones");
902 }
903 auth_zones_delete(az);
904 }
905
906 /** check config file */
907 static void
checkconf(const char * cfgfile,const char * opt,int final)908 checkconf(const char* cfgfile, const char* opt, int final)
909 {
910 char oldwd[4096];
911 struct config_file* cfg = config_create();
912 if(!cfg)
913 fatal_exit("out of memory");
914 oldwd[0] = 0;
915 if(!getcwd(oldwd, sizeof(oldwd))) {
916 log_err("cannot getcwd: %s", strerror(errno));
917 oldwd[0] = 0;
918 }
919 if(!config_read(cfg, cfgfile, NULL)) {
920 /* config_read prints messages to stderr */
921 config_delete(cfg);
922 exit(1);
923 }
924 if(oldwd[0] && chdir(oldwd) == -1)
925 log_err("cannot chdir(%s): %s", oldwd, strerror(errno));
926 if(opt) {
927 print_option(cfg, opt, final);
928 config_delete(cfg);
929 return;
930 }
931 morechecks(cfg);
932 check_mod(cfg, iter_get_funcblock());
933 check_mod(cfg, val_get_funcblock());
934 #ifdef WITH_PYTHONMODULE
935 if(strstr(cfg->module_conf, "python"))
936 check_mod(cfg, pythonmod_get_funcblock());
937 #endif
938 check_fwd(cfg);
939 check_hints(cfg);
940 check_auth(cfg);
941 printf("unbound-checkconf: no errors in %s\n", cfgfile);
942 config_delete(cfg);
943 }
944
945 /** getopt global, in case header files fail to declare it. */
946 extern int optind;
947 /** getopt global, in case header files fail to declare it. */
948 extern char* optarg;
949
950 /** Main routine for checkconf */
main(int argc,char * argv[])951 int main(int argc, char* argv[])
952 {
953 int c;
954 int final = 0;
955 const char* f;
956 const char* opt = NULL;
957 const char* cfgfile = CONFIGFILE;
958 checklock_start();
959 log_ident_set("unbound-checkconf");
960 log_init(NULL, 0, NULL);
961 #ifdef USE_WINSOCK
962 /* use registry config file in preference to compiletime location */
963 if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile")))
964 cfgfile = CONFIGFILE;
965 #endif /* USE_WINSOCK */
966 /* parse the options */
967 while( (c=getopt(argc, argv, "fho:")) != -1) {
968 switch(c) {
969 case 'f':
970 final = 1;
971 break;
972 case 'o':
973 opt = optarg;
974 break;
975 case '?':
976 case 'h':
977 default:
978 usage();
979 }
980 }
981 argc -= optind;
982 argv += optind;
983 if(argc != 0 && argc != 1)
984 usage();
985 if(argc == 1)
986 f = argv[0];
987 else f = cfgfile;
988 checkconf(f, opt, final);
989 checklock_stop();
990 return 0;
991 }
992