xref: /freebsd/contrib/unbound/smallapp/unbound-checkconf.c (revision 7a789145f88a6aceacc59029a0cafe7de7aeefea)
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