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/as112.h"
48 #include "util/log.h"
49 #include "util/config_file.h"
50 #include "util/module.h"
51 #include "util/net_help.h"
52 #include "util/regional.h"
53 #include "iterator/iterator.h"
54 #include "iterator/iter_fwd.h"
55 #include "iterator/iter_hints.h"
56 #include "validator/validator.h"
57 #include "services/localzone.h"
58 #include "services/listen_dnsport.h"
59 #include "services/view.h"
60 #include "services/authzone.h"
61 #include "respip/respip.h"
62 #include "sldns/sbuffer.h"
63 #include "sldns/str2wire.h"
64 #ifdef HAVE_GETOPT_H
65 #include <getopt.h>
66 #endif
67 #ifdef HAVE_PWD_H
68 #include <pwd.h>
69 #endif
70 #ifdef HAVE_SYS_STAT_H
71 #include <sys/stat.h>
72 #endif
73 #ifdef HAVE_GLOB_H
74 #include <glob.h>
75 #endif
76 #ifdef HAVE_FNMATCH_H
77 #include <fnmatch.h>
78 #endif
79 #ifdef WITH_PYTHONMODULE
80 #include "pythonmod/pythonmod.h"
81 #endif
82 #ifdef CLIENT_SUBNET
83 #include "edns-subnet/subnet-whitelist.h"
84 #endif
85
86 /** Give checkconf usage, and exit (1). */
87 static void
usage(void)88 usage(void)
89 {
90 printf("Usage: local-unbound-checkconf [file]\n");
91 printf(" Checks unbound configuration file for errors.\n");
92 printf("file if omitted %s is used.\n", CONFIGFILE);
93 printf("-o option print value of option to stdout.\n");
94 printf("-f output full pathname with chroot applied, eg. with -o pidfile.\n");
95 printf("-q quiet (suppress output on success).\n");
96 printf("-h show this usage help.\n");
97 printf("Version %s\n", PACKAGE_VERSION);
98 printf("BSD licensed, see LICENSE in source package for details.\n");
99 printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
100 exit(1);
101 }
102
103 /**
104 * Print given option to stdout
105 * @param cfg: config
106 * @param opt: option name without trailing :.
107 * This is different from config_set_option.
108 * @param final: if final pathname with chroot applied has to be printed.
109 */
110 static void
print_option(struct config_file * cfg,const char * opt,int final)111 print_option(struct config_file* cfg, const char* opt, int final)
112 {
113 if(strcmp(opt, "pidfile") == 0 && final) {
114 char *p = fname_after_chroot(cfg->pidfile, cfg, 1);
115 if(!p) fatal_exit("out of memory");
116 printf("%s\n", p);
117 free(p);
118 return;
119 }
120 if(strcmp(opt, "auto-trust-anchor-file") == 0 && final) {
121 struct config_strlist* s = cfg->auto_trust_anchor_file_list;
122 for(; s; s=s->next) {
123 char *p = fname_after_chroot(s->str, cfg, 1);
124 if(!p) fatal_exit("out of memory");
125 printf("%s\n", p);
126 free(p);
127 }
128 return;
129 }
130 if(!config_get_option(cfg, opt, config_print_func, stdout))
131 fatal_exit("cannot print option '%s'", opt);
132 }
133
134 /** check if module works with config */
135 static void
check_mod(struct config_file * cfg,struct module_func_block * fb)136 check_mod(struct config_file* cfg, struct module_func_block* fb)
137 {
138 struct module_env env;
139 memset(&env, 0, sizeof(env));
140 env.cfg = cfg;
141 env.scratch = regional_create();
142 env.scratch_buffer = sldns_buffer_new(BUFSIZ);
143 if(!env.scratch || !env.scratch_buffer)
144 fatal_exit("out of memory");
145 if(!edns_known_options_init(&env))
146 fatal_exit("out of memory");
147 if(fb->startup && !(*fb->startup)(&env, 0))
148 fatal_exit("bad config during startup for %s module", fb->name);
149 if(!(*fb->init)(&env, 0))
150 fatal_exit("bad config during init for %s module", fb->name);
151 (*fb->deinit)(&env, 0);
152 if(fb->destartup)
153 (*fb->destartup)(&env, 0);
154 sldns_buffer_free(env.scratch_buffer);
155 regional_destroy(env.scratch);
156 edns_known_options_delete(&env);
157 }
158
159 /** true if addr is a localhost address, 127.0.0.1 or ::1 (with maybe "@port"
160 * after it) */
161 static int
str_addr_is_localhost(const char * a)162 str_addr_is_localhost(const char* a)
163 {
164 if(strncmp(a, "127.", 4) == 0) return 1;
165 if(strncmp(a, "::1", 3) == 0) return 1;
166 return 0;
167 }
168
169 /** check do-not-query-localhost */
170 static void
donotquerylocalhostcheck(struct config_file * cfg)171 donotquerylocalhostcheck(struct config_file* cfg)
172 {
173 if(cfg->donotquery_localhost) {
174 struct config_stub* p;
175 struct config_strlist* s;
176 for(p=cfg->forwards; 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: 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",
180 s->str, p->name);
181 }
182 }
183 }
184 for(p=cfg->stubs; p; p=p->next) {
185 for(s=p->addrs; s; s=s->next) {
186 if(str_addr_is_localhost(s->str)) {
187 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",
188 s->str, p->name);
189 }
190 }
191 }
192 }
193 }
194
195 static void
nodefaultzonescheck(struct config_file * cfg)196 nodefaultzonescheck(struct config_file* cfg)
197 {
198 struct config_strlist* d;
199 const char** zstr;
200 size_t len;
201
202 #define COMPARE_ZONE_NAME(confname, builtname, len) \
203 (strncasecmp(confname, builtname, (len)) == 0 && \
204 (strlen(confname) == (len) || \
205 (strlen(confname) == (len) + 1 \
206 && confname[(len)] == '.')))
207
208 for(d = cfg->local_zones_nodefault; d; d = d->next) {
209 if(!cfg->unblock_lan_zones) {
210 for(zstr = as112_zones; *zstr; zstr++) {
211 len = strlen(*zstr) - 1; /* trailing '.' */
212 if(COMPARE_ZONE_NAME(d->str, *zstr, len))
213 goto default_continue;
214 }
215 }
216 for(zstr = local_zones_default_special; *zstr; zstr++) {
217 len = strlen(*zstr) - 1; /* trailing '.' */
218 if(COMPARE_ZONE_NAME(d->str, *zstr, len))
219 goto default_continue;
220 }
221 for(zstr = local_zones_default_reverse; *zstr; zstr++) {
222 len = strlen(*zstr) - 1; /* trailing '.' */
223 if(COMPARE_ZONE_NAME(d->str, *zstr, len))
224 goto default_continue;
225 }
226 if(COMPARE_ZONE_NAME(d->str, "localhost.", 10 - 1))
227 goto default_continue;
228 fprintf(stderr, "unbound-checkconf: warning: local-zone: '%s' "
229 "is configured as 'nodefault' but there is no such "
230 "default local-zone. Check the unbound.conf "
231 "documentation for default configured local-zones.\n",
232 d->str);
233 default_continue:
234 ; /* statement to jump to, for older gcc. */
235 }
236 #undef COMPARE_ZONE_NAME
237 }
238
239 /** check localzones */
240 static void
localzonechecks(struct config_file * cfg)241 localzonechecks(struct config_file* cfg)
242 {
243 struct local_zones* zs;
244 nodefaultzonescheck(cfg);
245 if(!(zs = local_zones_create()))
246 fatal_exit("out of memory");
247 if(!local_zones_apply_cfg(zs, cfg))
248 fatal_exit("failed local-zone, local-data configuration");
249 local_zones_delete(zs);
250 }
251
252 /** checks for acl and views */
253 static void
acl_view_tag_checks(struct config_file * cfg,struct views * views)254 acl_view_tag_checks(struct config_file* cfg, struct views* views)
255 {
256 int d;
257 struct sockaddr_storage a;
258 socklen_t alen;
259 struct config_str2list* acl;
260 struct config_str3list* s3;
261 struct config_strbytelist* sb;
262
263 /* acl_view */
264 for(acl=cfg->acl_view; acl; acl = acl->next) {
265 struct view* v;
266 if(!netblockstrtoaddr(acl->str, UNBOUND_DNS_PORT, &a, &alen,
267 &d)) {
268 fatal_exit("cannot parse access-control-view "
269 "address %s %s", acl->str, acl->str2);
270 }
271 v = views_find_view(views, acl->str2, 0);
272 if(!v) {
273 fatal_exit("cannot find view for "
274 "access-control-view: %s %s",
275 acl->str, acl->str2);
276 }
277 lock_rw_unlock(&v->lock);
278 }
279
280 /* acl_tags */
281 for(sb=cfg->acl_tags; sb; sb = sb->next) {
282 if(!netblockstrtoaddr(sb->str, UNBOUND_DNS_PORT, &a, &alen,
283 &d)) {
284 fatal_exit("cannot parse access-control-tags "
285 "address %s", sb->str);
286 }
287 }
288
289 /* acl_tag_actions */
290 for(s3=cfg->acl_tag_actions; s3; s3 = s3->next) {
291 enum localzone_type t;
292 if(!netblockstrtoaddr(s3->str, UNBOUND_DNS_PORT, &a, &alen,
293 &d)) {
294 fatal_exit("cannot parse access-control-tag-actions "
295 "address %s %s %s",
296 s3->str, s3->str2, s3->str3);
297 }
298 if(find_tag_id(cfg, s3->str2) == -1) {
299 fatal_exit("cannot parse tag %s (define-tag it), "
300 "for access-control-tag-actions: %s %s %s",
301 s3->str2, s3->str, s3->str2, s3->str3);
302 }
303 if(!local_zone_str2type(s3->str3, &t)) {
304 fatal_exit("cannot parse access control action type %s"
305 " for access-control-tag-actions: %s %s %s",
306 s3->str3, s3->str, s3->str2, s3->str3);
307 }
308 }
309
310 /* acl_tag_datas */
311 for(s3=cfg->acl_tag_datas; s3; s3 = s3->next) {
312 char buf[65536];
313 uint8_t rr[LDNS_RR_BUF_SIZE];
314 size_t len = sizeof(rr);
315 int res;
316 if(!netblockstrtoaddr(s3->str, UNBOUND_DNS_PORT, &a, &alen,
317 &d)) {
318 fatal_exit("cannot parse access-control-tag-datas address %s %s '%s'",
319 s3->str, s3->str2, s3->str3);
320 }
321 if(find_tag_id(cfg, s3->str2) == -1) {
322 fatal_exit("cannot parse tag %s (define-tag it), "
323 "for access-control-tag-datas: %s %s '%s'",
324 s3->str2, s3->str, s3->str2, s3->str3);
325 }
326 /* '.' is sufficient for validation, and it makes the call to
327 * sldns_wirerr_get_type() simpler below. */
328 snprintf(buf, sizeof(buf), "%s %s", ".", s3->str3);
329 res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600, NULL,
330 0, NULL, 0);
331 if(res != 0) {
332 fatal_exit("cannot parse rr data [char %d] parse error %s, for access-control-tag-datas: %s %s '%s'",
333 (int)LDNS_WIREPARSE_OFFSET(res)-2,
334 sldns_get_errorstr_parse(res),
335 s3->str, s3->str2, s3->str3);
336 }
337 }
338 }
339
340 /** check view and response-ip configuration */
341 static void
view_and_respipchecks(struct config_file * cfg)342 view_and_respipchecks(struct config_file* cfg)
343 {
344 struct views* views = NULL;
345 struct respip_set* respip = NULL;
346 int have_view_respip_cfg = 0;
347 int use_response_ip = 0;
348 if(!(views = views_create()))
349 fatal_exit("Could not create views: out of memory");
350 if(!(respip = respip_set_create()))
351 fatal_exit("Could not create respip set: out of memory");
352 if(!views_apply_cfg(views, cfg))
353 fatal_exit("Could not set up views");
354 if(!respip_global_apply_cfg(respip, cfg))
355 fatal_exit("Could not setup respip set");
356 if(!respip_views_apply_cfg(views, cfg, &have_view_respip_cfg))
357 fatal_exit("Could not setup per-view respip sets");
358 use_response_ip = !respip_set_is_empty(respip) || have_view_respip_cfg;
359 if(use_response_ip && !strstr(cfg->module_conf, "respip"))
360 fatal_exit("response-ip options require respip module");
361 acl_view_tag_checks(cfg, views);
362 views_delete(views);
363 respip_set_delete(respip);
364 }
365
366 /** emit warnings for IP in hosts */
367 static void
warn_hosts(const char * typ,struct config_stub * list)368 warn_hosts(const char* typ, struct config_stub* list)
369 {
370 struct sockaddr_storage a;
371 socklen_t alen;
372 struct config_stub* s;
373 struct config_strlist* h;
374 for(s=list; s; s=s->next) {
375 for(h=s->hosts; h; h=h->next) {
376 if(extstrtoaddr(h->str, &a, &alen, UNBOUND_DNS_PORT)) {
377 fprintf(stderr, "unbound-checkconf: warning:"
378 " %s %s: \"%s\" is an IP%s address, "
379 "and when looked up as a host name "
380 "during use may not resolve.\n",
381 s->name, typ, h->str,
382 addr_is_ip6(&a, alen)?"6":"4");
383 }
384 }
385 }
386 }
387
388 /** check interface strings */
389 static void
interfacechecks(struct config_file * cfg)390 interfacechecks(struct config_file* cfg)
391 {
392 int d;
393 struct sockaddr_storage a;
394 socklen_t alen;
395 int i, j, i2, j2;
396 char*** resif = NULL;
397 int* num_resif = NULL;
398
399 if(cfg->num_ifs != 0) {
400 resif = (char***)calloc(cfg->num_ifs, sizeof(char**));
401 if(!resif) fatal_exit("malloc failure");
402 num_resif = (int*)calloc(cfg->num_ifs, sizeof(int));
403 if(!num_resif) fatal_exit("malloc failure");
404 }
405 for(i=0; i<cfg->num_ifs; i++) {
406 /* search for duplicates in IP or ifname arguments */
407 for(i2=0; i2<i; i2++) {
408 if(strcmp(cfg->ifs[i], cfg->ifs[i2]) == 0) {
409 fatal_exit("interface: %s present twice, "
410 "cannot bind same ports twice.",
411 cfg->ifs[i]);
412 }
413 }
414 if(!resolve_interface_names(&cfg->ifs[i], 1, NULL, &resif[i],
415 &num_resif[i])) {
416 fatal_exit("could not resolve interface names, for %s",
417 cfg->ifs[i]);
418 }
419 /* check for port combinations that are not supported */
420 if(if_is_pp2(resif[i][0], cfg->port, cfg->proxy_protocol_port)) {
421 if(if_is_dnscrypt(resif[i][0], cfg->port,
422 cfg->dnscrypt_port)) {
423 fatal_exit("PROXYv2 and DNSCrypt combination not "
424 "supported!");
425 } else if(if_is_https(resif[i][0], cfg->port,
426 cfg->https_port)) {
427 fatal_exit("PROXYv2 and DoH combination not "
428 "supported!");
429 } else if(if_is_quic(resif[i][0], cfg->port,
430 cfg->quic_port)) {
431 fatal_exit("PROXYv2 and DoQ combination not "
432 "supported!");
433 }
434 }
435 /* search for duplicates in the returned addresses */
436 for(j=0; j<num_resif[i]; j++) {
437 if(!extstrtoaddr(resif[i][j], &a, &alen, cfg->port)) {
438 if(strcmp(cfg->ifs[i], resif[i][j]) != 0)
439 fatal_exit("cannot parse interface address '%s' from the interface specified as '%s'",
440 resif[i][j], cfg->ifs[i]);
441 else
442 fatal_exit("cannot parse interface specified as '%s'",
443 cfg->ifs[i]);
444 }
445 for(i2=0; i2<i; i2++) {
446 for(j2=0; j2<num_resif[i2]; j2++) {
447 if(strcmp(resif[i][j], resif[i2][j2])
448 == 0) {
449 char info1[1024], info2[1024];
450 if(strcmp(cfg->ifs[i], resif[i][j]) != 0)
451 snprintf(info1, sizeof(info1), "address %s from interface: %s", resif[i][j], cfg->ifs[i]);
452 else snprintf(info1, sizeof(info1), "interface: %s", cfg->ifs[i]);
453 if(strcmp(cfg->ifs[i2], resif[i2][j2]) != 0)
454 snprintf(info2, sizeof(info2), "address %s from interface: %s", resif[i2][j2], cfg->ifs[i2]);
455 else snprintf(info2, sizeof(info2), "interface: %s", cfg->ifs[i2]);
456 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);
457 }
458 }
459 }
460 }
461 }
462
463 for(i=0; i<cfg->num_ifs; i++) {
464 config_del_strarray(resif[i], num_resif[i]);
465 }
466 free(resif);
467 free(num_resif);
468
469 for(i=0; i<cfg->num_out_ifs; i++) {
470 if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen) &&
471 !netblockstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen, &d)) {
472 fatal_exit("cannot parse outgoing-interface "
473 "specified as '%s'", cfg->out_ifs[i]);
474 }
475 for(j=0; j<cfg->num_out_ifs; j++) {
476 if(i!=j && strcmp(cfg->out_ifs[i], cfg->out_ifs[j])==0)
477 fatal_exit("outgoing-interface: %s present "
478 "twice, cannot bind same ports twice.",
479 cfg->out_ifs[i]);
480 }
481 }
482 }
483
484 /** check interface-automatic-ports */
485 static void
ifautomaticportschecks(char * ifautomaticports)486 ifautomaticportschecks(char* ifautomaticports)
487 {
488 char* now = ifautomaticports;
489 while(now && *now) {
490 char* after;
491 int extraport;
492 while(isspace((unsigned char)*now))
493 now++;
494 if(!*now)
495 break;
496 after = now;
497 extraport = (int)strtol(now, &after, 10);
498 if(extraport < 0 || extraport > 65535)
499 fatal_exit("interface-automatic-ports: port out of range at position %d in '%s'", (int)(now-ifautomaticports)+1, ifautomaticports);
500 if(extraport == 0 && now == after)
501 fatal_exit("interface-automatic-ports: parse error at position %d in '%s'", (int)(now-ifautomaticports)+1, ifautomaticports);
502 now = after;
503 }
504 }
505
506 /** check control interface strings */
507 static void
controlinterfacechecks(struct config_file * cfg)508 controlinterfacechecks(struct config_file* cfg)
509 {
510 struct config_strlist* p;
511 for(p = cfg->control_ifs.first; p; p = p->next) {
512 struct sockaddr_storage a;
513 socklen_t alen;
514 char** rcif = NULL;
515 int i, num_rcif = 0;
516 /* See if it is a local socket, starts with a '/'. */
517 if(p->str && p->str[0] == '/')
518 continue;
519 if(!resolve_interface_names(&p->str, 1, NULL, &rcif,
520 &num_rcif)) {
521 fatal_exit("could not resolve interface names, for control-interface: %s",
522 p->str);
523 }
524 for(i=0; i<num_rcif; i++) {
525 if(!extstrtoaddr(rcif[i], &a, &alen,
526 cfg->control_port)) {
527 if(strcmp(p->str, rcif[i])!=0)
528 fatal_exit("cannot parse control-interface address '%s' from the control-interface specified as '%s'",
529 rcif[i], p->str);
530 else
531 fatal_exit("cannot parse control-interface specified as '%s'",
532 p->str);
533 }
534 }
535 config_del_strarray(rcif, num_rcif);
536 }
537 }
538
539 /** check acl ips */
540 static void
aclchecks(struct config_file * cfg)541 aclchecks(struct config_file* cfg)
542 {
543 int d;
544 struct sockaddr_storage a;
545 socklen_t alen;
546 struct config_str2list* acl;
547 for(acl=cfg->acls; acl; acl = acl->next) {
548 if(!netblockstrtoaddr(acl->str, UNBOUND_DNS_PORT, &a, &alen,
549 &d)) {
550 fatal_exit("cannot parse access control address %s %s",
551 acl->str, acl->str2);
552 }
553 }
554 }
555
556 /** check tcp connection limit ips */
557 static void
tcpconnlimitchecks(struct config_file * cfg)558 tcpconnlimitchecks(struct config_file* cfg)
559 {
560 int d;
561 struct sockaddr_storage a;
562 socklen_t alen;
563 struct config_str2list* tcl;
564 for(tcl=cfg->tcp_connection_limits; tcl; tcl = tcl->next) {
565 if(!netblockstrtoaddr(tcl->str, UNBOUND_DNS_PORT, &a, &alen,
566 &d)) {
567 fatal_exit("cannot parse tcp connection limit address %s %s",
568 tcl->str, tcl->str2);
569 }
570 }
571 }
572
573 /** true if fname is a file */
574 static int
is_file(const char * fname)575 is_file(const char* fname)
576 {
577 struct stat buf;
578 if(stat(fname, &buf) < 0) {
579 if(errno==EACCES) {
580 printf("warning: no search permission for one of the directories in path: %s\n", fname);
581 return 1;
582 }
583 perror(fname);
584 return 0;
585 }
586 if(S_ISDIR(buf.st_mode)) {
587 printf("%s is not a file\n", fname);
588 return 0;
589 }
590 return 1;
591 }
592
593 /** true if fname is a directory */
594 static int
is_dir(const char * fname)595 is_dir(const char* fname)
596 {
597 struct stat buf;
598 if(stat(fname, &buf) < 0) {
599 if(errno==EACCES) {
600 printf("warning: no search permission for one of the directories in path: %s\n", fname);
601 return 1;
602 }
603 perror(fname);
604 return 0;
605 }
606 if(!(S_ISDIR(buf.st_mode))) {
607 printf("%s is not a directory\n", fname);
608 return 0;
609 }
610 return 1;
611 }
612
613 /** get base dir of a fname */
614 static char*
basedir(char * fname)615 basedir(char* fname)
616 {
617 char* rev;
618 if(!fname) fatal_exit("out of memory");
619 rev = strrchr(fname, '/');
620 if(!rev) return NULL;
621 if(fname == rev) return NULL;
622 rev[0] = 0;
623 return fname;
624 }
625
626 /** check chroot for a file string */
627 static void
check_chroot_string(const char * desc,char ** ss,const char * chrootdir,struct config_file * cfg)628 check_chroot_string(const char* desc, char** ss,
629 const char* chrootdir, struct config_file* cfg)
630 {
631 char* str = *ss;
632 if(str && str[0]) {
633 *ss = fname_after_chroot(str, cfg, 1);
634 if(!*ss) fatal_exit("out of memory");
635 if(!is_file(*ss)) {
636 if(chrootdir && chrootdir[0])
637 fatal_exit("%s: \"%s\" does not exist in "
638 "chrootdir %s", desc, str, chrootdir);
639 else
640 fatal_exit("%s: \"%s\" does not exist",
641 desc, str);
642 }
643 /* put in a new full path for continued checking */
644 free(str);
645 }
646 }
647
648 /** check file list, every file must be inside the chroot location */
649 static void
check_chroot_filelist(const char * desc,struct config_strlist * list,const char * chrootdir,struct config_file * cfg)650 check_chroot_filelist(const char* desc, struct config_strlist* list,
651 const char* chrootdir, struct config_file* cfg)
652 {
653 struct config_strlist* p;
654 for(p=list; p; p=p->next) {
655 check_chroot_string(desc, &p->str, chrootdir, cfg);
656 }
657 }
658
659 /** check file list, with wildcard processing */
660 static void
check_chroot_filelist_wild(const char * desc,struct config_strlist * list,const char * chrootdir,struct config_file * cfg)661 check_chroot_filelist_wild(const char* desc, struct config_strlist* list,
662 const char* chrootdir, struct config_file* cfg)
663 {
664 struct config_strlist* p;
665 for(p=list; p; p=p->next) {
666 #ifdef HAVE_GLOB
667 if(strchr(p->str, '*') || strchr(p->str, '[') ||
668 strchr(p->str, '?') || strchr(p->str, '{') ||
669 strchr(p->str, '~')) {
670 char* s = p->str;
671 /* adjust whole pattern for chroot and check later */
672 p->str = fname_after_chroot(p->str, cfg, 1);
673 free(s);
674 } else
675 #endif /* HAVE_GLOB */
676 check_chroot_string(desc, &p->str, chrootdir, cfg);
677 }
678 }
679
680 #ifdef CLIENT_SUBNET
681 /** check ECS configuration */
682 static void
ecs_conf_checks(struct config_file * cfg)683 ecs_conf_checks(struct config_file* cfg)
684 {
685 struct ecs_whitelist* whitelist = NULL;
686 if(!(whitelist = ecs_whitelist_create()))
687 fatal_exit("Could not create ednssubnet whitelist: out of memory");
688 if(!ecs_whitelist_apply_cfg(whitelist, cfg))
689 fatal_exit("Could not setup ednssubnet whitelist");
690 ecs_whitelist_delete(whitelist);
691 }
692 #endif /* CLIENT_SUBNET */
693
694 /** check that the modules exist, are compiled in */
695 static void
check_modules_exist(const char * module_conf)696 check_modules_exist(const char* module_conf)
697 {
698 const char** names = module_list_avail();
699 const char* s = module_conf;
700 while(*s) {
701 int i = 0;
702 int is_ok = 0;
703 while(*s && isspace((unsigned char)*s))
704 s++;
705 if(!*s) break;
706 while(names[i]) {
707 if(strncmp(names[i], s, strlen(names[i])) == 0) {
708 is_ok = 1;
709 break;
710 }
711 i++;
712 }
713 if(is_ok == 0) {
714 char n[64];
715 size_t j;
716 n[0]=0;
717 n[sizeof(n)-1]=0;
718 for(j=0; j<sizeof(n)-1; j++) {
719 if(!s[j] || isspace((unsigned char)s[j])) {
720 n[j] = 0;
721 break;
722 }
723 n[j] = s[j];
724 }
725 fatal_exit("Unknown value in module-config, module: "
726 "'%s'. This module is not present (not "
727 "compiled in); see the list of linked modules "
728 "with unbound -V", n);
729 }
730 s += strlen(names[i]);
731 }
732 }
733
734 #ifdef USE_IPSECMOD
735 /** Compare filename with string, true if it matches the name. */
736 static int
file_string_matches(char * str,char * fname,struct config_file * cfg)737 file_string_matches(char* str, char* fname, struct config_file* cfg)
738 {
739 char* f;
740 if(!str || str[0] == 0)
741 return 0;
742 /* compare name after chroot and working dir are applied */
743 f = fname_after_chroot(str, cfg, 1);
744 if(!f) fatal_exit("out of memory");
745 if(strcmp(fname, f) == 0) {
746 free(f);
747 return 1;
748 }
749 free(f);
750 return 0;
751 }
752 #endif /* USE_IPSECMOD */
753
754 /** Compare filename with list of files, true if list contains the name. */
755 static int
file_list_contains(struct config_strlist * list,char * fname,struct config_file * cfg)756 file_list_contains(struct config_strlist* list, char* fname,
757 struct config_file* cfg)
758 {
759 struct config_strlist* s;
760 char* f;
761 for(s = list; s; s = s->next) {
762 if(!s->str || s->str[0] == 0)
763 continue; /* skip if no file name */
764 /* compare names after chroot and working dir are applied */
765 f = fname_after_chroot(s->str, cfg, 1);
766 if(!f) fatal_exit("out of memory");
767 if(strcmp(fname, f) == 0) {
768 free(f);
769 return 1;
770 }
771 free(f);
772 }
773 return 0;
774 }
775
776 /** Compare filename with list of files, true if list contains the name,
777 * with glob compare. */
778 static int
file_list_contains_wild(struct config_strlist * list,char * fname,struct config_file * cfg)779 file_list_contains_wild(struct config_strlist* list, char* fname,
780 struct config_file* cfg)
781 {
782 struct config_strlist* s;
783 char* f;
784 for(s = list; s; s = s->next) {
785 if(!s->str || s->str[0] == 0)
786 continue; /* skip if no file name */
787 /* compare names after chroot and working dir are applied */
788 f = fname_after_chroot(s->str, cfg, 1);
789 if(!f) fatal_exit("out of memory");
790 if(strcmp(fname, f) == 0) {
791 free(f);
792 return 1;
793 }
794 #ifdef HAVE_FNMATCH
795 if(fnmatch(f, fname, 0) == 0) {
796 log_err("trusted-keys-file: \"%s\" matches zonefile '%s'",
797 s->str, fname);
798 free(f);
799 return 1;
800 }
801 #endif
802 free(f);
803 }
804 return 0;
805 }
806
807 /** Check if the auth-zone/rpz zonefile: conflicts with other files,
808 * so it would overwrite that file. Refuse it aliasing any read-side bootstrap
809 * file. */
810 static void
check_file_clobber(struct config_file * cfg)811 check_file_clobber(struct config_file* cfg)
812 {
813 struct config_auth* p;
814 char* zfile, *sourceopt = NULL;
815 for(p = cfg->auths; p; p = p->next) {
816 if(!p->name || p->name[0] == 0)
817 continue; /* skip if no name */
818 if(!p->zonefile || p->zonefile[0]==0)
819 continue; /* no zone file */
820 zfile = fname_after_chroot(p->zonefile, cfg, 1);
821 if(!zfile) fatal_exit("out of memory");
822 if(file_list_contains(cfg->auto_trust_anchor_file_list, zfile,
823 cfg))
824 sourceopt = "auto-trust-anchor-file";
825 else if(file_list_contains(cfg->trust_anchor_file_list, zfile,
826 cfg))
827 sourceopt = "trust-anchor-file";
828 else if(file_list_contains_wild(cfg->trusted_keys_file_list,
829 zfile, cfg))
830 sourceopt = "trusted-keys-file";
831 else if(file_list_contains(cfg->root_hints, zfile, cfg))
832 sourceopt = "root-hints";
833 else if(file_list_contains(cfg->tls_session_ticket_keys.first,
834 zfile, cfg))
835 sourceopt = "tls-session-ticket-keys";
836 #ifdef USE_IPSECMOD
837 if(cfg->ipsecmod_enabled &&
838 file_string_matches(cfg->ipsecmod_hook, zfile, cfg))
839 sourceopt = "ipsecmod-hook";
840 #endif
841 if(sourceopt)
842 fatal_exit("auth-zone '%s': zonefile \"%s\" "
843 "is the same path as a %s option. "
844 "The auth-zone transfer would overwrite it.",
845 p->name, p->zonefile, sourceopt);
846 free(zfile);
847 }
848 }
849
850 /** check configuration for errors */
851 static void
morechecks(struct config_file * cfg)852 morechecks(struct config_file* cfg)
853 {
854 warn_hosts("stub-host", cfg->stubs);
855 warn_hosts("forward-host", cfg->forwards);
856 interfacechecks(cfg);
857 ifautomaticportschecks(cfg->if_automatic_ports);
858 aclchecks(cfg);
859 tcpconnlimitchecks(cfg);
860
861 if(cfg->verbosity < 0)
862 fatal_exit("verbosity value < 0");
863 if(cfg->num_threads <= 0 || cfg->num_threads > 10000)
864 fatal_exit("num_threads value weird");
865 if(!cfg->do_ip4 && !cfg->do_ip6)
866 fatal_exit("ip4 and ip6 are both disabled, pointless");
867 if(!cfg->do_ip4 && cfg->prefer_ip4)
868 fatal_exit("cannot prefer and disable ip4, pointless");
869 if(!cfg->do_ip6 && cfg->prefer_ip6)
870 fatal_exit("cannot prefer and disable ip6, pointless");
871 if(!cfg->do_udp && !cfg->do_tcp)
872 fatal_exit("udp and tcp are both disabled, pointless");
873 if(cfg->edns_buffer_size > cfg->msg_buffer_size)
874 fatal_exit("edns-buffer-size larger than msg-buffer-size, "
875 "answers will not fit in processing buffer");
876 #ifdef UB_ON_WINDOWS
877 w_config_adjust_directory(cfg);
878 #endif
879 if(cfg->chrootdir && cfg->chrootdir[0] &&
880 cfg->chrootdir[strlen(cfg->chrootdir)-1] == '/')
881 fatal_exit("chootdir %s has trailing slash '/' please remove.",
882 cfg->chrootdir);
883 if(cfg->chrootdir && cfg->chrootdir[0] &&
884 !is_dir(cfg->chrootdir)) {
885 fatal_exit("bad chroot directory");
886 }
887 if(cfg->directory && cfg->directory[0]) {
888 char* ad = fname_after_chroot(cfg->directory, cfg, 0);
889 if(!ad) fatal_exit("out of memory");
890 if(!is_dir(ad)) fatal_exit("bad chdir directory");
891 free(ad);
892 }
893 if( (cfg->chrootdir && cfg->chrootdir[0]) ||
894 (cfg->directory && cfg->directory[0])) {
895 if(cfg->pidfile && cfg->pidfile[0]) {
896 char* ad = (cfg->pidfile[0]=='/')?strdup(cfg->pidfile):
897 fname_after_chroot(cfg->pidfile, cfg, 1);
898 char* bd = basedir(ad);
899 if(bd && !is_dir(bd))
900 fatal_exit("pidfile directory does not exist");
901 free(ad);
902 }
903 if(cfg->logfile && cfg->logfile[0]) {
904 char* ad = fname_after_chroot(cfg->logfile, cfg, 1);
905 char* bd = basedir(ad);
906 if(bd && !is_dir(bd))
907 fatal_exit("logfile directory does not exist");
908 free(ad);
909 }
910 }
911
912 check_chroot_filelist("file with root-hints",
913 cfg->root_hints, cfg->chrootdir, cfg);
914 check_chroot_filelist("trust-anchor-file",
915 cfg->trust_anchor_file_list, cfg->chrootdir, cfg);
916 check_chroot_filelist("auto-trust-anchor-file",
917 cfg->auto_trust_anchor_file_list, cfg->chrootdir, cfg);
918 check_chroot_filelist_wild("trusted-keys-file",
919 cfg->trusted_keys_file_list, cfg->chrootdir, cfg);
920 if(cfg->disable_edns_do && strstr(cfg->module_conf, "validator")
921 && (cfg->trust_anchor_file_list
922 || cfg->trust_anchor_list
923 || cfg->auto_trust_anchor_file_list
924 || cfg->trusted_keys_file_list)) {
925 char* key = NULL;
926 if(cfg->auto_trust_anchor_file_list)
927 key = cfg->auto_trust_anchor_file_list->str;
928 if(!key && cfg->trust_anchor_file_list)
929 key = cfg->trust_anchor_file_list->str;
930 if(!key && cfg->trust_anchor_list)
931 key = cfg->trust_anchor_list->str;
932 if(!key && cfg->trusted_keys_file_list)
933 key = cfg->trusted_keys_file_list->str;
934 if(!key) key = "";
935 fatal_exit("disable-edns-do does not allow DNSSEC to work, but the validator module uses a trust anchor %s, turn off disable-edns-do or disable validation", key);
936 }
937 #ifdef USE_IPSECMOD
938 if(cfg->ipsecmod_enabled && strstr(cfg->module_conf, "ipsecmod")) {
939 /* only check hook if enabled */
940 check_chroot_string("ipsecmod-hook", &cfg->ipsecmod_hook,
941 cfg->chrootdir, cfg);
942 }
943 #endif
944 check_file_clobber(cfg);
945 /* remove chroot setting so that modules are not stripping pathnames */
946 free(cfg->chrootdir);
947 cfg->chrootdir = NULL;
948
949 /* check that the modules listed in module_conf exist */
950 check_modules_exist(cfg->module_conf);
951
952 if(strcmp(cfg->module_conf, "iterator") != 0
953 && strcmp(cfg->module_conf, "validator iterator") != 0
954 && strcmp(cfg->module_conf, "dns64 validator iterator") != 0
955 && strcmp(cfg->module_conf, "dns64 iterator") != 0
956 && strcmp(cfg->module_conf, "respip iterator") != 0
957 && strcmp(cfg->module_conf, "respip validator iterator") != 0
958 && strcmp(cfg->module_conf, "respip dns64 validator iterator") != 0
959 && strcmp(cfg->module_conf, "respip dns64 iterator") != 0
960 #ifdef WITH_PYTHONMODULE
961 && strcmp(cfg->module_conf, "python iterator") != 0
962 && strcmp(cfg->module_conf, "python respip iterator") != 0
963 && strcmp(cfg->module_conf, "python validator iterator") != 0
964 && strcmp(cfg->module_conf, "python respip validator iterator") != 0
965 && strcmp(cfg->module_conf, "validator python iterator") != 0
966 && strcmp(cfg->module_conf, "dns64 python iterator") != 0
967 && strcmp(cfg->module_conf, "dns64 python validator iterator") != 0
968 && strcmp(cfg->module_conf, "dns64 validator python iterator") != 0
969 && strcmp(cfg->module_conf, "python dns64 iterator") != 0
970 && strcmp(cfg->module_conf, "python dns64 validator iterator") != 0
971 #endif
972 #ifdef WITH_DYNLIBMODULE
973 && strcmp(cfg->module_conf, "dynlib iterator") != 0
974 && strcmp(cfg->module_conf, "dynlib dynlib iterator") != 0
975 && strcmp(cfg->module_conf, "dynlib dynlib dynlib iterator") != 0
976 && strcmp(cfg->module_conf, "python dynlib iterator") != 0
977 && strcmp(cfg->module_conf, "python dynlib dynlib iterator") != 0
978 && strcmp(cfg->module_conf, "python dynlib dynlib dynlib iterator") != 0
979 && strcmp(cfg->module_conf, "dynlib respip iterator") != 0
980 && strcmp(cfg->module_conf, "dynlib validator iterator") != 0
981 && strcmp(cfg->module_conf, "dynlib dynlib validator iterator") != 0
982 && strcmp(cfg->module_conf, "dynlib dynlib dynlib validator iterator") != 0
983 && strcmp(cfg->module_conf, "python dynlib validator iterator") != 0
984 && strcmp(cfg->module_conf, "python dynlib dynlib validator iterator") != 0
985 && strcmp(cfg->module_conf, "python dynlib dynlib dynlib validator iterator") != 0
986 && strcmp(cfg->module_conf, "dynlib respip validator iterator") != 0
987 && strcmp(cfg->module_conf, "validator dynlib iterator") != 0
988 && strcmp(cfg->module_conf, "dns64 dynlib iterator") != 0
989 && strcmp(cfg->module_conf, "dns64 dynlib validator iterator") != 0
990 && strcmp(cfg->module_conf, "dns64 validator dynlib iterator") != 0
991 && strcmp(cfg->module_conf, "dynlib dns64 iterator") != 0
992 && strcmp(cfg->module_conf, "dynlib dns64 validator iterator") != 0
993 && strcmp(cfg->module_conf, "dynlib dns64 cachedb iterator") != 0
994 && strcmp(cfg->module_conf, "dynlib dns64 validator cachedb iterator") != 0
995 && strcmp(cfg->module_conf, "dns64 dynlib cachedb iterator") != 0
996 && strcmp(cfg->module_conf, "dns64 dynlib validator cachedb iterator") != 0
997 && strcmp(cfg->module_conf, "dynlib cachedb iterator") != 0
998 && strcmp(cfg->module_conf, "dynlib respip cachedb iterator") != 0
999 && strcmp(cfg->module_conf, "dynlib validator cachedb iterator") != 0
1000 && strcmp(cfg->module_conf, "dynlib respip validator cachedb iterator") != 0
1001 && strcmp(cfg->module_conf, "cachedb dynlib iterator") != 0
1002 && strcmp(cfg->module_conf, "respip cachedb dynlib iterator") != 0
1003 && strcmp(cfg->module_conf, "validator cachedb dynlib iterator") != 0
1004 && strcmp(cfg->module_conf, "respip validator cachedb dynlib iterator") != 0
1005 && strcmp(cfg->module_conf, "validator dynlib cachedb iterator") != 0
1006 && strcmp(cfg->module_conf, "respip validator dynlib cachedb iterator") != 0
1007 && strcmp(cfg->module_conf, "dynlib subnetcache iterator") != 0
1008 && strcmp(cfg->module_conf, "dynlib respip subnetcache iterator") != 0
1009 && strcmp(cfg->module_conf, "subnetcache dynlib iterator") != 0
1010 && strcmp(cfg->module_conf, "respip subnetcache dynlib iterator") != 0
1011 && strcmp(cfg->module_conf, "dynlib subnetcache validator iterator") != 0
1012 && strcmp(cfg->module_conf, "dynlib respip subnetcache validator iterator") != 0
1013 && strcmp(cfg->module_conf, "subnetcache dynlib validator iterator") != 0
1014 && strcmp(cfg->module_conf, "respip subnetcache dynlib validator iterator") != 0
1015 && strcmp(cfg->module_conf, "subnetcache validator dynlib iterator") != 0
1016 && strcmp(cfg->module_conf, "respip subnetcache validator dynlib iterator") != 0
1017 && strcmp(cfg->module_conf, "dynlib ipsecmod iterator") != 0
1018 && strcmp(cfg->module_conf, "dynlib ipsecmod respip iterator") != 0
1019 && strcmp(cfg->module_conf, "ipsecmod dynlib iterator") != 0
1020 && strcmp(cfg->module_conf, "ipsecmod dynlib respip iterator") != 0
1021 && strcmp(cfg->module_conf, "ipsecmod validator iterator") != 0
1022 && strcmp(cfg->module_conf, "ipsecmod respip validator iterator") != 0
1023 && strcmp(cfg->module_conf, "dynlib ipsecmod validator iterator") != 0
1024 && strcmp(cfg->module_conf, "dynlib ipsecmod respip validator iterator") != 0
1025 && strcmp(cfg->module_conf, "ipsecmod dynlib validator iterator") != 0
1026 && strcmp(cfg->module_conf, "ipsecmod dynlib respip validator iterator") != 0
1027 && strcmp(cfg->module_conf, "ipsecmod validator dynlib iterator") != 0
1028 && strcmp(cfg->module_conf, "ipsecmod respip validator dynlib iterator") != 0
1029 #endif
1030 #ifdef USE_CACHEDB
1031 && strcmp(cfg->module_conf, "validator cachedb iterator") != 0
1032 && strcmp(cfg->module_conf, "respip validator cachedb iterator") != 0
1033 && strcmp(cfg->module_conf, "cachedb iterator") != 0
1034 && strcmp(cfg->module_conf, "respip cachedb iterator") != 0
1035 && strcmp(cfg->module_conf, "dns64 validator cachedb iterator") != 0
1036 && strcmp(cfg->module_conf, "dns64 cachedb iterator") != 0
1037 && strcmp(cfg->module_conf, "respip dns64 validator cachedb iterator") != 0
1038 #endif
1039 #if defined(WITH_PYTHONMODULE) && defined(USE_CACHEDB)
1040 && strcmp(cfg->module_conf, "python dns64 cachedb iterator") != 0
1041 && strcmp(cfg->module_conf, "python dns64 validator cachedb iterator") != 0
1042 && strcmp(cfg->module_conf, "dns64 python cachedb iterator") != 0
1043 && strcmp(cfg->module_conf, "dns64 python validator cachedb iterator") != 0
1044 && strcmp(cfg->module_conf, "python cachedb iterator") != 0
1045 && strcmp(cfg->module_conf, "python respip cachedb iterator") != 0
1046 && strcmp(cfg->module_conf, "python validator cachedb iterator") != 0
1047 && strcmp(cfg->module_conf, "python respip validator cachedb iterator") != 0
1048 && strcmp(cfg->module_conf, "cachedb python iterator") != 0
1049 && strcmp(cfg->module_conf, "respip cachedb python iterator") != 0
1050 && strcmp(cfg->module_conf, "validator cachedb python iterator") != 0
1051 && strcmp(cfg->module_conf, "respip validator cachedb python iterator") != 0
1052 && strcmp(cfg->module_conf, "validator python cachedb iterator") != 0
1053 && strcmp(cfg->module_conf, "respip validator python cachedb iterator") != 0
1054 #endif
1055 #if defined(CLIENT_SUBNET) && defined(USE_CACHEDB)
1056 && strcmp(cfg->module_conf, "respip subnetcache validator cachedb iterator") != 0
1057 && strcmp(cfg->module_conf, "subnetcache validator cachedb iterator") != 0
1058 #endif
1059 #ifdef CLIENT_SUBNET
1060 && strcmp(cfg->module_conf, "subnetcache iterator") != 0
1061 && strcmp(cfg->module_conf, "respip subnetcache iterator") != 0
1062 && strcmp(cfg->module_conf, "subnetcache validator iterator") != 0
1063 && strcmp(cfg->module_conf, "respip subnetcache validator iterator") != 0
1064 && strcmp(cfg->module_conf, "dns64 subnetcache iterator") != 0
1065 && strcmp(cfg->module_conf, "dns64 subnetcache validator iterator") != 0
1066 && strcmp(cfg->module_conf, "dns64 subnetcache respip iterator") != 0
1067 && strcmp(cfg->module_conf, "dns64 subnetcache respip validator iterator") != 0
1068 #endif
1069 #if defined(WITH_PYTHONMODULE) && defined(CLIENT_SUBNET)
1070 && strcmp(cfg->module_conf, "python subnetcache iterator") != 0
1071 && strcmp(cfg->module_conf, "python respip subnetcache iterator") != 0
1072 && strcmp(cfg->module_conf, "subnetcache python iterator") != 0
1073 && strcmp(cfg->module_conf, "respip subnetcache python iterator") != 0
1074 && strcmp(cfg->module_conf, "python subnetcache validator iterator") != 0
1075 && strcmp(cfg->module_conf, "python respip subnetcache validator iterator") != 0
1076 && strcmp(cfg->module_conf, "subnetcache python validator iterator") != 0
1077 && strcmp(cfg->module_conf, "respip subnetcache python validator iterator") != 0
1078 && strcmp(cfg->module_conf, "subnetcache validator python iterator") != 0
1079 && strcmp(cfg->module_conf, "respip subnetcache validator python iterator") != 0
1080 #endif
1081 #ifdef USE_IPSECMOD
1082 && strcmp(cfg->module_conf, "ipsecmod iterator") != 0
1083 && strcmp(cfg->module_conf, "ipsecmod respip iterator") != 0
1084 && strcmp(cfg->module_conf, "ipsecmod validator iterator") != 0
1085 && strcmp(cfg->module_conf, "ipsecmod respip validator iterator") != 0
1086 #endif
1087 #if defined(WITH_PYTHONMODULE) && defined(USE_IPSECMOD)
1088 && strcmp(cfg->module_conf, "python ipsecmod iterator") != 0
1089 && strcmp(cfg->module_conf, "python ipsecmod respip iterator") != 0
1090 && strcmp(cfg->module_conf, "ipsecmod python iterator") != 0
1091 && strcmp(cfg->module_conf, "ipsecmod python respip iterator") != 0
1092 && strcmp(cfg->module_conf, "ipsecmod validator iterator") != 0
1093 && strcmp(cfg->module_conf, "ipsecmod respip validator iterator") != 0
1094 && strcmp(cfg->module_conf, "python ipsecmod validator iterator") != 0
1095 && strcmp(cfg->module_conf, "python ipsecmod respip validator iterator") != 0
1096 && strcmp(cfg->module_conf, "ipsecmod python validator iterator") != 0
1097 && strcmp(cfg->module_conf, "ipsecmod python respip validator iterator") != 0
1098 && strcmp(cfg->module_conf, "ipsecmod validator python iterator") != 0
1099 && strcmp(cfg->module_conf, "ipsecmod respip validator python iterator") != 0
1100 #endif
1101 #ifdef USE_IPSET
1102 && strcmp(cfg->module_conf, "validator ipset iterator") != 0
1103 && strcmp(cfg->module_conf, "validator ipset respip iterator") != 0
1104 && strcmp(cfg->module_conf, "ipset iterator") != 0
1105 && strcmp(cfg->module_conf, "ipset respip iterator") != 0
1106 #endif
1107 ) {
1108 fatal_exit("module conf '%s' is not known to work",
1109 cfg->module_conf);
1110 }
1111
1112 #ifdef HAVE_GETPWNAM
1113 if(cfg->username && cfg->username[0]) {
1114 if(getpwnam(cfg->username) == NULL)
1115 fatal_exit("user '%s' does not exist.", cfg->username);
1116 # ifdef HAVE_ENDPWENT
1117 endpwent();
1118 # endif
1119 }
1120 #endif
1121 if(cfg->remote_control_enable && options_remote_is_address(cfg)
1122 && cfg->control_use_cert) {
1123 check_chroot_string("server-key-file", &cfg->server_key_file,
1124 cfg->chrootdir, cfg);
1125 check_chroot_string("server-cert-file", &cfg->server_cert_file,
1126 cfg->chrootdir, cfg);
1127 if(!is_file(cfg->control_key_file))
1128 fatal_exit("control-key-file: \"%s\" does not exist",
1129 cfg->control_key_file);
1130 if(!is_file(cfg->control_cert_file))
1131 fatal_exit("control-cert-file: \"%s\" does not exist",
1132 cfg->control_cert_file);
1133 }
1134 if(cfg->remote_control_enable)
1135 controlinterfacechecks(cfg);
1136
1137 donotquerylocalhostcheck(cfg);
1138 localzonechecks(cfg);
1139 view_and_respipchecks(cfg);
1140 #ifdef CLIENT_SUBNET
1141 ecs_conf_checks(cfg);
1142 #endif
1143 }
1144
1145 /** check forwards */
1146 static void
check_fwd(struct config_file * cfg)1147 check_fwd(struct config_file* cfg)
1148 {
1149 struct iter_forwards* fwd = forwards_create();
1150 if(!fwd || !forwards_apply_cfg(fwd, cfg)) {
1151 fatal_exit("Could not set forward zones");
1152 }
1153 forwards_delete(fwd);
1154 }
1155
1156 /** check hints */
1157 static void
check_hints(struct config_file * cfg)1158 check_hints(struct config_file* cfg)
1159 {
1160 struct iter_hints* hints = hints_create();
1161 if(!hints || !hints_apply_cfg(hints, cfg)) {
1162 fatal_exit("Could not set root or stub hints");
1163 }
1164 hints_delete(hints);
1165 }
1166
1167 /** check auth zones */
1168 static void
check_auth(struct config_file * cfg)1169 check_auth(struct config_file* cfg)
1170 {
1171 int is_rpz = 0;
1172 struct auth_zones* az = auth_zones_create();
1173 if(!az || !auth_zones_apply_cfg(az, cfg, 0, &is_rpz, NULL, NULL)) {
1174 fatal_exit("Could not setup authority zones");
1175 }
1176 if(is_rpz && !strstr(cfg->module_conf, "respip"))
1177 fatal_exit("RPZ requires the respip module");
1178 auth_zones_delete(az);
1179 }
1180
1181 /** check config file */
1182 static void
checkconf(const char * cfgfile,const char * opt,int final,int quiet)1183 checkconf(const char* cfgfile, const char* opt, int final, int quiet)
1184 {
1185 char oldwd[4096];
1186 struct config_file* cfg = config_create();
1187 if(!cfg)
1188 fatal_exit("out of memory");
1189 oldwd[0] = 0;
1190 if(!getcwd(oldwd, sizeof(oldwd))) {
1191 log_err("cannot getcwd: %s", strerror(errno));
1192 oldwd[0] = 0;
1193 }
1194 if(!config_read(cfg, cfgfile, NULL)) {
1195 /* config_read prints messages to stderr */
1196 config_delete(cfg);
1197 exit(1);
1198 }
1199 if(oldwd[0] && chdir(oldwd) == -1)
1200 log_err("cannot chdir(%s): %s", oldwd, strerror(errno));
1201 if(opt) {
1202 print_option(cfg, opt, final);
1203 config_delete(cfg);
1204 return;
1205 }
1206 morechecks(cfg);
1207 check_mod(cfg, iter_get_funcblock());
1208 check_mod(cfg, val_get_funcblock());
1209 #ifdef WITH_PYTHONMODULE
1210 if(strstr(cfg->module_conf, "python"))
1211 check_mod(cfg, pythonmod_get_funcblock());
1212 #endif
1213 check_fwd(cfg);
1214 check_hints(cfg);
1215 check_auth(cfg);
1216 if(!quiet) { printf("unbound-checkconf: no errors in %s\n", cfgfile); }
1217 config_delete(cfg);
1218 }
1219
1220 /** getopt global, in case header files fail to declare it. */
1221 extern int optind;
1222 /** getopt global, in case header files fail to declare it. */
1223 extern char* optarg;
1224
1225 /** Main routine for checkconf */
main(int argc,char * argv[])1226 int main(int argc, char* argv[])
1227 {
1228 int c;
1229 int final = 0;
1230 int quiet = 0;
1231 const char* f;
1232 const char* opt = NULL;
1233 const char* cfgfile = CONFIGFILE;
1234 checklock_start();
1235 log_ident_set("unbound-checkconf");
1236 log_init(NULL, 0, NULL);
1237 #ifdef USE_WINSOCK
1238 /* use registry config file in preference to compiletime location */
1239 if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile")))
1240 cfgfile = CONFIGFILE;
1241 #endif /* USE_WINSOCK */
1242 /* parse the options */
1243 while( (c=getopt(argc, argv, "fhqo:")) != -1) {
1244 switch(c) {
1245 case 'f':
1246 final = 1;
1247 break;
1248 case 'o':
1249 opt = optarg;
1250 break;
1251 case 'q':
1252 quiet = 1;
1253 break;
1254 case '?':
1255 case 'h':
1256 default:
1257 usage();
1258 }
1259 }
1260 argc -= optind;
1261 argv += optind;
1262 if(argc != 0 && argc != 1)
1263 usage();
1264 if(argc == 1)
1265 f = argv[0];
1266 else f = cfgfile;
1267 checkconf(f, opt, final, quiet);
1268 checklock_stop();
1269 return 0;
1270 }
1271