1b7579f77SDag-Erling Smørgrav /* 2b7579f77SDag-Erling Smørgrav * checkconf/unbound-checkconf.c - config file checker for unbound.conf file. 3b7579f77SDag-Erling Smørgrav * 4b7579f77SDag-Erling Smørgrav * Copyright (c) 2007, NLnet Labs. All rights reserved. 5b7579f77SDag-Erling Smørgrav * 6b7579f77SDag-Erling Smørgrav * This software is open source. 7b7579f77SDag-Erling Smørgrav * 8b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10b7579f77SDag-Erling Smørgrav * are met: 11b7579f77SDag-Erling Smørgrav * 12b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14b7579f77SDag-Erling Smørgrav * 15b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18b7579f77SDag-Erling Smørgrav * 19b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21b7579f77SDag-Erling Smørgrav * specific prior written permission. 22b7579f77SDag-Erling Smørgrav * 23b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2417d15b25SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2517d15b25SDag-Erling Smørgrav * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2617d15b25SDag-Erling Smørgrav * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2717d15b25SDag-Erling Smørgrav * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2817d15b25SDag-Erling Smørgrav * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 2917d15b25SDag-Erling Smørgrav * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 3017d15b25SDag-Erling Smørgrav * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 3117d15b25SDag-Erling Smørgrav * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 3217d15b25SDag-Erling Smørgrav * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3317d15b25SDag-Erling Smørgrav * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34b7579f77SDag-Erling Smørgrav */ 35b7579f77SDag-Erling Smørgrav 36b7579f77SDag-Erling Smørgrav /** 37b7579f77SDag-Erling Smørgrav * \file 38b7579f77SDag-Erling Smørgrav * 39b7579f77SDag-Erling Smørgrav * The config checker checks for syntax and other errors in the unbound.conf 40b7579f77SDag-Erling Smørgrav * file, and can be used to check for errors before the server is started 41b7579f77SDag-Erling Smørgrav * or sigHUPped. 42b7579f77SDag-Erling Smørgrav * Exit status 1 means an error. 43b7579f77SDag-Erling Smørgrav */ 44b7579f77SDag-Erling Smørgrav 45b7579f77SDag-Erling Smørgrav #include "config.h" 464c75e3aaSDag-Erling Smørgrav #include <ctype.h> 47b7579f77SDag-Erling Smørgrav #include "util/log.h" 48b7579f77SDag-Erling Smørgrav #include "util/config_file.h" 49b7579f77SDag-Erling Smørgrav #include "util/module.h" 50b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 51b7579f77SDag-Erling Smørgrav #include "util/regional.h" 52b7579f77SDag-Erling Smørgrav #include "iterator/iterator.h" 53b7579f77SDag-Erling Smørgrav #include "iterator/iter_fwd.h" 54b7579f77SDag-Erling Smørgrav #include "iterator/iter_hints.h" 55b7579f77SDag-Erling Smørgrav #include "validator/validator.h" 56b7579f77SDag-Erling Smørgrav #include "services/localzone.h" 5765b390aaSDag-Erling Smørgrav #include "services/view.h" 5857bddd21SDag-Erling Smørgrav #include "services/authzone.h" 5965b390aaSDag-Erling Smørgrav #include "respip/respip.h" 6009a3aaf3SDag-Erling Smørgrav #include "sldns/sbuffer.h" 61b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETOPT_H 62b7579f77SDag-Erling Smørgrav #include <getopt.h> 63b7579f77SDag-Erling Smørgrav #endif 64b7579f77SDag-Erling Smørgrav #ifdef HAVE_PWD_H 65b7579f77SDag-Erling Smørgrav #include <pwd.h> 66b7579f77SDag-Erling Smørgrav #endif 67b7579f77SDag-Erling Smørgrav #ifdef HAVE_SYS_STAT_H 68b7579f77SDag-Erling Smørgrav #include <sys/stat.h> 69b7579f77SDag-Erling Smørgrav #endif 70b7579f77SDag-Erling Smørgrav #ifdef HAVE_GLOB_H 71b7579f77SDag-Erling Smørgrav #include <glob.h> 72b7579f77SDag-Erling Smørgrav #endif 73b7579f77SDag-Erling Smørgrav #ifdef WITH_PYTHONMODULE 74b7579f77SDag-Erling Smørgrav #include "pythonmod/pythonmod.h" 75b7579f77SDag-Erling Smørgrav #endif 76971980c3SDag-Erling Smørgrav #ifdef CLIENT_SUBNET 77971980c3SDag-Erling Smørgrav #include "edns-subnet/subnet-whitelist.h" 78971980c3SDag-Erling Smørgrav #endif 79b7579f77SDag-Erling Smørgrav 80b7579f77SDag-Erling Smørgrav /** Give checkconf usage, and exit (1). */ 81b7579f77SDag-Erling Smørgrav static void 82b5663de9SDag-Erling Smørgrav usage(void) 83b7579f77SDag-Erling Smørgrav { 84b70d78d6SDag-Erling Smørgrav printf("Usage: local-unbound-checkconf [file]\n"); 85b7579f77SDag-Erling Smørgrav printf(" Checks unbound configuration file for errors.\n"); 86b7579f77SDag-Erling Smørgrav printf("file if omitted %s is used.\n", CONFIGFILE); 87b7579f77SDag-Erling Smørgrav printf("-o option print value of option to stdout.\n"); 886480faa8SDag-Erling Smørgrav printf("-f output full pathname with chroot applied, eg. with -o pidfile.\n"); 89b7579f77SDag-Erling Smørgrav printf("-h show this usage help.\n"); 90b7579f77SDag-Erling Smørgrav printf("Version %s\n", PACKAGE_VERSION); 91b7579f77SDag-Erling Smørgrav printf("BSD licensed, see LICENSE in source package for details.\n"); 92b7579f77SDag-Erling Smørgrav printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 93b7579f77SDag-Erling Smørgrav exit(1); 94b7579f77SDag-Erling Smørgrav } 95b7579f77SDag-Erling Smørgrav 96b7579f77SDag-Erling Smørgrav /** 97b7579f77SDag-Erling Smørgrav * Print given option to stdout 98b7579f77SDag-Erling Smørgrav * @param cfg: config 99b7579f77SDag-Erling Smørgrav * @param opt: option name without trailing :. 100b7579f77SDag-Erling Smørgrav * This is different from config_set_option. 1016480faa8SDag-Erling Smørgrav * @param final: if final pathname with chroot applied has to be printed. 102b7579f77SDag-Erling Smørgrav */ 103b7579f77SDag-Erling Smørgrav static void 1046480faa8SDag-Erling Smørgrav print_option(struct config_file* cfg, const char* opt, int final) 105b7579f77SDag-Erling Smørgrav { 1066480faa8SDag-Erling Smørgrav if(strcmp(opt, "pidfile") == 0 && final) { 107bc892140SDag-Erling Smørgrav char *p = fname_after_chroot(cfg->pidfile, cfg, 1); 108bc892140SDag-Erling Smørgrav if(!p) fatal_exit("out of memory"); 109bc892140SDag-Erling Smørgrav printf("%s\n", p); 110bc892140SDag-Erling Smørgrav free(p); 1116480faa8SDag-Erling Smørgrav return; 1126480faa8SDag-Erling Smørgrav } 11357bddd21SDag-Erling Smørgrav if(strcmp(opt, "auto-trust-anchor-file") == 0 && final) { 11457bddd21SDag-Erling Smørgrav struct config_strlist* s = cfg->auto_trust_anchor_file_list; 11557bddd21SDag-Erling Smørgrav for(; s; s=s->next) { 11657bddd21SDag-Erling Smørgrav char *p = fname_after_chroot(s->str, cfg, 1); 11757bddd21SDag-Erling Smørgrav if(!p) fatal_exit("out of memory"); 11857bddd21SDag-Erling Smørgrav printf("%s\n", p); 11957bddd21SDag-Erling Smørgrav free(p); 12057bddd21SDag-Erling Smørgrav } 12157bddd21SDag-Erling Smørgrav return; 12257bddd21SDag-Erling Smørgrav } 123b7579f77SDag-Erling Smørgrav if(!config_get_option(cfg, opt, config_print_func, stdout)) 124b7579f77SDag-Erling Smørgrav fatal_exit("cannot print option '%s'", opt); 125b7579f77SDag-Erling Smørgrav } 126b7579f77SDag-Erling Smørgrav 127b7579f77SDag-Erling Smørgrav /** check if module works with config */ 128b7579f77SDag-Erling Smørgrav static void 129b7579f77SDag-Erling Smørgrav check_mod(struct config_file* cfg, struct module_func_block* fb) 130b7579f77SDag-Erling Smørgrav { 131b7579f77SDag-Erling Smørgrav struct module_env env; 132b7579f77SDag-Erling Smørgrav memset(&env, 0, sizeof(env)); 133b7579f77SDag-Erling Smørgrav env.cfg = cfg; 134b7579f77SDag-Erling Smørgrav env.scratch = regional_create(); 13517d15b25SDag-Erling Smørgrav env.scratch_buffer = sldns_buffer_new(BUFSIZ); 136b7579f77SDag-Erling Smørgrav if(!env.scratch || !env.scratch_buffer) 137b7579f77SDag-Erling Smørgrav fatal_exit("out of memory"); 138bc892140SDag-Erling Smørgrav if(!edns_known_options_init(&env)) 139bc892140SDag-Erling Smørgrav fatal_exit("out of memory"); 140b7579f77SDag-Erling Smørgrav if(!(*fb->init)(&env, 0)) { 141b7579f77SDag-Erling Smørgrav fatal_exit("bad config for %s module", fb->name); 142b7579f77SDag-Erling Smørgrav } 143b7579f77SDag-Erling Smørgrav (*fb->deinit)(&env, 0); 14417d15b25SDag-Erling Smørgrav sldns_buffer_free(env.scratch_buffer); 145b7579f77SDag-Erling Smørgrav regional_destroy(env.scratch); 146bc892140SDag-Erling Smørgrav edns_known_options_delete(&env); 147b7579f77SDag-Erling Smørgrav } 148b7579f77SDag-Erling Smørgrav 1490eefd307SCy Schubert /** true if addr is a localhost address, 127.0.0.1 or ::1 (with maybe "@port" 1500eefd307SCy Schubert * after it) */ 1510eefd307SCy Schubert static int 1520eefd307SCy Schubert str_addr_is_localhost(const char* a) 1530eefd307SCy Schubert { 1540eefd307SCy Schubert if(strncmp(a, "127.", 4) == 0) return 1; 1550eefd307SCy Schubert if(strncmp(a, "::1", 3) == 0) return 1; 1560eefd307SCy Schubert return 0; 1570eefd307SCy Schubert } 1580eefd307SCy Schubert 1590eefd307SCy Schubert /** check do-not-query-localhost */ 1600eefd307SCy Schubert static void 1610eefd307SCy Schubert donotquerylocalhostcheck(struct config_file* cfg) 1620eefd307SCy Schubert { 1630eefd307SCy Schubert if(cfg->donotquery_localhost) { 1640eefd307SCy Schubert struct config_stub* p; 1650eefd307SCy Schubert struct config_strlist* s; 1660eefd307SCy Schubert for(p=cfg->forwards; p; p=p->next) { 1670eefd307SCy Schubert for(s=p->addrs; s; s=s->next) { 1680eefd307SCy Schubert if(str_addr_is_localhost(s->str)) { 1690eefd307SCy Schubert 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", 1700eefd307SCy Schubert s->str, p->name); 1710eefd307SCy Schubert } 1720eefd307SCy Schubert } 1730eefd307SCy Schubert } 1740eefd307SCy Schubert for(p=cfg->stubs; p; p=p->next) { 1750eefd307SCy Schubert for(s=p->addrs; s; s=s->next) { 1760eefd307SCy Schubert if(str_addr_is_localhost(s->str)) { 1770eefd307SCy Schubert 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", 1780eefd307SCy Schubert s->str, p->name); 1790eefd307SCy Schubert } 1800eefd307SCy Schubert } 1810eefd307SCy Schubert } 1820eefd307SCy Schubert } 1830eefd307SCy Schubert } 1840eefd307SCy Schubert 185b7579f77SDag-Erling Smørgrav /** check localzones */ 186b7579f77SDag-Erling Smørgrav static void 187b7579f77SDag-Erling Smørgrav localzonechecks(struct config_file* cfg) 188b7579f77SDag-Erling Smørgrav { 189b7579f77SDag-Erling Smørgrav struct local_zones* zs; 190b7579f77SDag-Erling Smørgrav if(!(zs = local_zones_create())) 191b7579f77SDag-Erling Smørgrav fatal_exit("out of memory"); 192b7579f77SDag-Erling Smørgrav if(!local_zones_apply_cfg(zs, cfg)) 193b7579f77SDag-Erling Smørgrav fatal_exit("failed local-zone, local-data configuration"); 194b7579f77SDag-Erling Smørgrav local_zones_delete(zs); 195b7579f77SDag-Erling Smørgrav } 196b7579f77SDag-Erling Smørgrav 19765b390aaSDag-Erling Smørgrav /** check view and response-ip configuration */ 19865b390aaSDag-Erling Smørgrav static void 19965b390aaSDag-Erling Smørgrav view_and_respipchecks(struct config_file* cfg) 20065b390aaSDag-Erling Smørgrav { 20165b390aaSDag-Erling Smørgrav struct views* views = NULL; 20265b390aaSDag-Erling Smørgrav struct respip_set* respip = NULL; 20365b390aaSDag-Erling Smørgrav int ignored = 0; 20465b390aaSDag-Erling Smørgrav if(!(views = views_create())) 20565b390aaSDag-Erling Smørgrav fatal_exit("Could not create views: out of memory"); 20665b390aaSDag-Erling Smørgrav if(!(respip = respip_set_create())) 20765b390aaSDag-Erling Smørgrav fatal_exit("Could not create respip set: out of memory"); 20865b390aaSDag-Erling Smørgrav if(!views_apply_cfg(views, cfg)) 20965b390aaSDag-Erling Smørgrav fatal_exit("Could not set up views"); 21065b390aaSDag-Erling Smørgrav if(!respip_global_apply_cfg(respip, cfg)) 21165b390aaSDag-Erling Smørgrav fatal_exit("Could not setup respip set"); 21265b390aaSDag-Erling Smørgrav if(!respip_views_apply_cfg(views, cfg, &ignored)) 21365b390aaSDag-Erling Smørgrav fatal_exit("Could not setup per-view respip sets"); 21465b390aaSDag-Erling Smørgrav views_delete(views); 21565b390aaSDag-Erling Smørgrav respip_set_delete(respip); 21665b390aaSDag-Erling Smørgrav } 21765b390aaSDag-Erling Smørgrav 218b7579f77SDag-Erling Smørgrav /** emit warnings for IP in hosts */ 219b7579f77SDag-Erling Smørgrav static void 220b7579f77SDag-Erling Smørgrav warn_hosts(const char* typ, struct config_stub* list) 221b7579f77SDag-Erling Smørgrav { 222b7579f77SDag-Erling Smørgrav struct sockaddr_storage a; 223b7579f77SDag-Erling Smørgrav socklen_t alen; 224b7579f77SDag-Erling Smørgrav struct config_stub* s; 225b7579f77SDag-Erling Smørgrav struct config_strlist* h; 226b7579f77SDag-Erling Smørgrav for(s=list; s; s=s->next) { 227b7579f77SDag-Erling Smørgrav for(h=s->hosts; h; h=h->next) { 228b7579f77SDag-Erling Smørgrav if(extstrtoaddr(h->str, &a, &alen)) { 229b7579f77SDag-Erling Smørgrav fprintf(stderr, "unbound-checkconf: warning:" 230b7579f77SDag-Erling Smørgrav " %s %s: \"%s\" is an IP%s address, " 231b7579f77SDag-Erling Smørgrav "and when looked up as a host name " 232b7579f77SDag-Erling Smørgrav "during use may not resolve.\n", 233b7579f77SDag-Erling Smørgrav s->name, typ, h->str, 234b7579f77SDag-Erling Smørgrav addr_is_ip6(&a, alen)?"6":"4"); 235b7579f77SDag-Erling Smørgrav } 236b7579f77SDag-Erling Smørgrav } 237b7579f77SDag-Erling Smørgrav } 238b7579f77SDag-Erling Smørgrav } 239b7579f77SDag-Erling Smørgrav 240b7579f77SDag-Erling Smørgrav /** check interface strings */ 241b7579f77SDag-Erling Smørgrav static void 242b7579f77SDag-Erling Smørgrav interfacechecks(struct config_file* cfg) 243b7579f77SDag-Erling Smørgrav { 244b5663de9SDag-Erling Smørgrav int d; 245b7579f77SDag-Erling Smørgrav struct sockaddr_storage a; 246b7579f77SDag-Erling Smørgrav socklen_t alen; 247b7579f77SDag-Erling Smørgrav int i, j; 248b7579f77SDag-Erling Smørgrav for(i=0; i<cfg->num_ifs; i++) { 249b7579f77SDag-Erling Smørgrav if(!extstrtoaddr(cfg->ifs[i], &a, &alen)) { 250b7579f77SDag-Erling Smørgrav fatal_exit("cannot parse interface specified as '%s'", 251b7579f77SDag-Erling Smørgrav cfg->ifs[i]); 252b7579f77SDag-Erling Smørgrav } 253b7579f77SDag-Erling Smørgrav for(j=0; j<cfg->num_ifs; j++) { 254b7579f77SDag-Erling Smørgrav if(i!=j && strcmp(cfg->ifs[i], cfg->ifs[j])==0) 255b7579f77SDag-Erling Smørgrav fatal_exit("interface: %s present twice, " 256b7579f77SDag-Erling Smørgrav "cannot bind same ports twice.", 257b7579f77SDag-Erling Smørgrav cfg->ifs[i]); 258b7579f77SDag-Erling Smørgrav } 259b7579f77SDag-Erling Smørgrav } 260b7579f77SDag-Erling Smørgrav for(i=0; i<cfg->num_out_ifs; i++) { 261b5663de9SDag-Erling Smørgrav if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen) && 262b5663de9SDag-Erling Smørgrav !netblockstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen, &d)) { 263b7579f77SDag-Erling Smørgrav fatal_exit("cannot parse outgoing-interface " 264b7579f77SDag-Erling Smørgrav "specified as '%s'", cfg->out_ifs[i]); 265b7579f77SDag-Erling Smørgrav } 266b7579f77SDag-Erling Smørgrav for(j=0; j<cfg->num_out_ifs; j++) { 267b7579f77SDag-Erling Smørgrav if(i!=j && strcmp(cfg->out_ifs[i], cfg->out_ifs[j])==0) 268b7579f77SDag-Erling Smørgrav fatal_exit("outgoing-interface: %s present " 269b7579f77SDag-Erling Smørgrav "twice, cannot bind same ports twice.", 270b7579f77SDag-Erling Smørgrav cfg->out_ifs[i]); 271b7579f77SDag-Erling Smørgrav } 272b7579f77SDag-Erling Smørgrav } 273b7579f77SDag-Erling Smørgrav } 274b7579f77SDag-Erling Smørgrav 275b7579f77SDag-Erling Smørgrav /** check acl ips */ 276b7579f77SDag-Erling Smørgrav static void 277b7579f77SDag-Erling Smørgrav aclchecks(struct config_file* cfg) 278b7579f77SDag-Erling Smørgrav { 279b7579f77SDag-Erling Smørgrav int d; 280b7579f77SDag-Erling Smørgrav struct sockaddr_storage a; 281b7579f77SDag-Erling Smørgrav socklen_t alen; 282b7579f77SDag-Erling Smørgrav struct config_str2list* acl; 283b7579f77SDag-Erling Smørgrav for(acl=cfg->acls; acl; acl = acl->next) { 284b7579f77SDag-Erling Smørgrav if(!netblockstrtoaddr(acl->str, UNBOUND_DNS_PORT, &a, &alen, 285b7579f77SDag-Erling Smørgrav &d)) { 286b7579f77SDag-Erling Smørgrav fatal_exit("cannot parse access control address %s %s", 287b7579f77SDag-Erling Smørgrav acl->str, acl->str2); 288b7579f77SDag-Erling Smørgrav } 289b7579f77SDag-Erling Smørgrav } 290b7579f77SDag-Erling Smørgrav } 291b7579f77SDag-Erling Smørgrav 2924c75e3aaSDag-Erling Smørgrav /** check tcp connection limit ips */ 2934c75e3aaSDag-Erling Smørgrav static void 2944c75e3aaSDag-Erling Smørgrav tcpconnlimitchecks(struct config_file* cfg) 2954c75e3aaSDag-Erling Smørgrav { 2964c75e3aaSDag-Erling Smørgrav int d; 2974c75e3aaSDag-Erling Smørgrav struct sockaddr_storage a; 2984c75e3aaSDag-Erling Smørgrav socklen_t alen; 2994c75e3aaSDag-Erling Smørgrav struct config_str2list* tcl; 3004c75e3aaSDag-Erling Smørgrav for(tcl=cfg->tcp_connection_limits; tcl; tcl = tcl->next) { 3014c75e3aaSDag-Erling Smørgrav if(!netblockstrtoaddr(tcl->str, UNBOUND_DNS_PORT, &a, &alen, 3024c75e3aaSDag-Erling Smørgrav &d)) { 3034c75e3aaSDag-Erling Smørgrav fatal_exit("cannot parse tcp connection limit address %s %s", 3044c75e3aaSDag-Erling Smørgrav tcl->str, tcl->str2); 3054c75e3aaSDag-Erling Smørgrav } 3064c75e3aaSDag-Erling Smørgrav } 3074c75e3aaSDag-Erling Smørgrav } 3084c75e3aaSDag-Erling Smørgrav 309b7579f77SDag-Erling Smørgrav /** true if fname is a file */ 310b7579f77SDag-Erling Smørgrav static int 311b7579f77SDag-Erling Smørgrav is_file(const char* fname) 312b7579f77SDag-Erling Smørgrav { 313b7579f77SDag-Erling Smørgrav struct stat buf; 314b7579f77SDag-Erling Smørgrav if(stat(fname, &buf) < 0) { 315b7579f77SDag-Erling Smørgrav if(errno==EACCES) { 316b7579f77SDag-Erling Smørgrav printf("warning: no search permission for one of the directories in path: %s\n", fname); 317b7579f77SDag-Erling Smørgrav return 1; 318b7579f77SDag-Erling Smørgrav } 319b7579f77SDag-Erling Smørgrav perror(fname); 320b7579f77SDag-Erling Smørgrav return 0; 321b7579f77SDag-Erling Smørgrav } 322b7579f77SDag-Erling Smørgrav if(S_ISDIR(buf.st_mode)) { 323b7579f77SDag-Erling Smørgrav printf("%s is not a file\n", fname); 324b7579f77SDag-Erling Smørgrav return 0; 325b7579f77SDag-Erling Smørgrav } 326b7579f77SDag-Erling Smørgrav return 1; 327b7579f77SDag-Erling Smørgrav } 328b7579f77SDag-Erling Smørgrav 329b7579f77SDag-Erling Smørgrav /** true if fname is a directory */ 330b7579f77SDag-Erling Smørgrav static int 331b7579f77SDag-Erling Smørgrav is_dir(const char* fname) 332b7579f77SDag-Erling Smørgrav { 333b7579f77SDag-Erling Smørgrav struct stat buf; 334b7579f77SDag-Erling Smørgrav if(stat(fname, &buf) < 0) { 335b7579f77SDag-Erling Smørgrav if(errno==EACCES) { 336b7579f77SDag-Erling Smørgrav printf("warning: no search permission for one of the directories in path: %s\n", fname); 337b7579f77SDag-Erling Smørgrav return 1; 338b7579f77SDag-Erling Smørgrav } 339b7579f77SDag-Erling Smørgrav perror(fname); 340b7579f77SDag-Erling Smørgrav return 0; 341b7579f77SDag-Erling Smørgrav } 342b7579f77SDag-Erling Smørgrav if(!(S_ISDIR(buf.st_mode))) { 343b7579f77SDag-Erling Smørgrav printf("%s is not a directory\n", fname); 344b7579f77SDag-Erling Smørgrav return 0; 345b7579f77SDag-Erling Smørgrav } 346b7579f77SDag-Erling Smørgrav return 1; 347b7579f77SDag-Erling Smørgrav } 348b7579f77SDag-Erling Smørgrav 349b7579f77SDag-Erling Smørgrav /** get base dir of a fname */ 350b7579f77SDag-Erling Smørgrav static char* 351b7579f77SDag-Erling Smørgrav basedir(char* fname) 352b7579f77SDag-Erling Smørgrav { 353b7579f77SDag-Erling Smørgrav char* rev; 354b7579f77SDag-Erling Smørgrav if(!fname) fatal_exit("out of memory"); 355b7579f77SDag-Erling Smørgrav rev = strrchr(fname, '/'); 356b7579f77SDag-Erling Smørgrav if(!rev) return NULL; 357b7579f77SDag-Erling Smørgrav if(fname == rev) return NULL; 358b7579f77SDag-Erling Smørgrav rev[0] = 0; 359b7579f77SDag-Erling Smørgrav return fname; 360b7579f77SDag-Erling Smørgrav } 361b7579f77SDag-Erling Smørgrav 362b7579f77SDag-Erling Smørgrav /** check chroot for a file string */ 363b7579f77SDag-Erling Smørgrav static void 364b7579f77SDag-Erling Smørgrav check_chroot_string(const char* desc, char** ss, 365b7579f77SDag-Erling Smørgrav const char* chrootdir, struct config_file* cfg) 366b7579f77SDag-Erling Smørgrav { 367b7579f77SDag-Erling Smørgrav char* str = *ss; 368b7579f77SDag-Erling Smørgrav if(str && str[0]) { 369b7579f77SDag-Erling Smørgrav *ss = fname_after_chroot(str, cfg, 1); 370b7579f77SDag-Erling Smørgrav if(!*ss) fatal_exit("out of memory"); 371b7579f77SDag-Erling Smørgrav if(!is_file(*ss)) { 372b7579f77SDag-Erling Smørgrav if(chrootdir && chrootdir[0]) 373b7579f77SDag-Erling Smørgrav fatal_exit("%s: \"%s\" does not exist in " 374b7579f77SDag-Erling Smørgrav "chrootdir %s", desc, str, chrootdir); 375b7579f77SDag-Erling Smørgrav else 376b7579f77SDag-Erling Smørgrav fatal_exit("%s: \"%s\" does not exist", 377b7579f77SDag-Erling Smørgrav desc, str); 378b7579f77SDag-Erling Smørgrav } 379b7579f77SDag-Erling Smørgrav /* put in a new full path for continued checking */ 380b7579f77SDag-Erling Smørgrav free(str); 381b7579f77SDag-Erling Smørgrav } 382b7579f77SDag-Erling Smørgrav } 383b7579f77SDag-Erling Smørgrav 384b7579f77SDag-Erling Smørgrav /** check file list, every file must be inside the chroot location */ 385b7579f77SDag-Erling Smørgrav static void 386b7579f77SDag-Erling Smørgrav check_chroot_filelist(const char* desc, struct config_strlist* list, 387b7579f77SDag-Erling Smørgrav const char* chrootdir, struct config_file* cfg) 388b7579f77SDag-Erling Smørgrav { 389b7579f77SDag-Erling Smørgrav struct config_strlist* p; 390b7579f77SDag-Erling Smørgrav for(p=list; p; p=p->next) { 391b7579f77SDag-Erling Smørgrav check_chroot_string(desc, &p->str, chrootdir, cfg); 392b7579f77SDag-Erling Smørgrav } 393b7579f77SDag-Erling Smørgrav } 394b7579f77SDag-Erling Smørgrav 395b7579f77SDag-Erling Smørgrav /** check file list, with wildcard processing */ 396b7579f77SDag-Erling Smørgrav static void 397b7579f77SDag-Erling Smørgrav check_chroot_filelist_wild(const char* desc, struct config_strlist* list, 398b7579f77SDag-Erling Smørgrav const char* chrootdir, struct config_file* cfg) 399b7579f77SDag-Erling Smørgrav { 400b7579f77SDag-Erling Smørgrav struct config_strlist* p; 401b7579f77SDag-Erling Smørgrav for(p=list; p; p=p->next) { 402b7579f77SDag-Erling Smørgrav #ifdef HAVE_GLOB 403b7579f77SDag-Erling Smørgrav if(strchr(p->str, '*') || strchr(p->str, '[') || 404b7579f77SDag-Erling Smørgrav strchr(p->str, '?') || strchr(p->str, '{') || 405b7579f77SDag-Erling Smørgrav strchr(p->str, '~')) { 406b7579f77SDag-Erling Smørgrav char* s = p->str; 407b7579f77SDag-Erling Smørgrav /* adjust whole pattern for chroot and check later */ 408b7579f77SDag-Erling Smørgrav p->str = fname_after_chroot(p->str, cfg, 1); 409b7579f77SDag-Erling Smørgrav free(s); 410b7579f77SDag-Erling Smørgrav } else 411b7579f77SDag-Erling Smørgrav #endif /* HAVE_GLOB */ 412b7579f77SDag-Erling Smørgrav check_chroot_string(desc, &p->str, chrootdir, cfg); 413b7579f77SDag-Erling Smørgrav } 414b7579f77SDag-Erling Smørgrav } 415b7579f77SDag-Erling Smørgrav 416971980c3SDag-Erling Smørgrav #ifdef CLIENT_SUBNET 417971980c3SDag-Erling Smørgrav /** check ECS configuration */ 418971980c3SDag-Erling Smørgrav static void 419971980c3SDag-Erling Smørgrav ecs_conf_checks(struct config_file* cfg) 420971980c3SDag-Erling Smørgrav { 421971980c3SDag-Erling Smørgrav struct ecs_whitelist* whitelist = NULL; 422971980c3SDag-Erling Smørgrav if(!(whitelist = ecs_whitelist_create())) 423971980c3SDag-Erling Smørgrav fatal_exit("Could not create ednssubnet whitelist: out of memory"); 424971980c3SDag-Erling Smørgrav if(!ecs_whitelist_apply_cfg(whitelist, cfg)) 425971980c3SDag-Erling Smørgrav fatal_exit("Could not setup ednssubnet whitelist"); 426971980c3SDag-Erling Smørgrav ecs_whitelist_delete(whitelist); 427971980c3SDag-Erling Smørgrav } 428971980c3SDag-Erling Smørgrav #endif /* CLIENT_SUBNET */ 429971980c3SDag-Erling Smørgrav 4304c75e3aaSDag-Erling Smørgrav /** check that the modules exist, are compiled in */ 4314c75e3aaSDag-Erling Smørgrav static void 4324c75e3aaSDag-Erling Smørgrav check_modules_exist(const char* module_conf) 4334c75e3aaSDag-Erling Smørgrav { 4344c75e3aaSDag-Erling Smørgrav const char** names = module_list_avail(); 4354c75e3aaSDag-Erling Smørgrav const char* s = module_conf; 4364c75e3aaSDag-Erling Smørgrav while(*s) { 4374c75e3aaSDag-Erling Smørgrav int i = 0; 4384c75e3aaSDag-Erling Smørgrav int is_ok = 0; 4394c75e3aaSDag-Erling Smørgrav while(*s && isspace((unsigned char)*s)) 4404c75e3aaSDag-Erling Smørgrav s++; 4414c75e3aaSDag-Erling Smørgrav if(!*s) break; 4424c75e3aaSDag-Erling Smørgrav while(names[i]) { 4434c75e3aaSDag-Erling Smørgrav if(strncmp(names[i], s, strlen(names[i])) == 0) { 4444c75e3aaSDag-Erling Smørgrav is_ok = 1; 4454c75e3aaSDag-Erling Smørgrav break; 4464c75e3aaSDag-Erling Smørgrav } 4474c75e3aaSDag-Erling Smørgrav i++; 4484c75e3aaSDag-Erling Smørgrav } 4494c75e3aaSDag-Erling Smørgrav if(is_ok == 0) { 4504c75e3aaSDag-Erling Smørgrav char n[64]; 4514c75e3aaSDag-Erling Smørgrav size_t j; 4524c75e3aaSDag-Erling Smørgrav n[0]=0; 4534c75e3aaSDag-Erling Smørgrav n[sizeof(n)-1]=0; 4544c75e3aaSDag-Erling Smørgrav for(j=0; j<sizeof(n)-1; j++) { 4554c75e3aaSDag-Erling Smørgrav if(!s[j] || isspace((unsigned char)s[j])) { 4564c75e3aaSDag-Erling Smørgrav n[j] = 0; 4574c75e3aaSDag-Erling Smørgrav break; 4584c75e3aaSDag-Erling Smørgrav } 4594c75e3aaSDag-Erling Smørgrav n[j] = s[j]; 4604c75e3aaSDag-Erling Smørgrav } 4614c75e3aaSDag-Erling Smørgrav fatal_exit("module_conf lists module '%s' but that " 4624c75e3aaSDag-Erling Smørgrav "module is not available.", n); 4634c75e3aaSDag-Erling Smørgrav } 4644c75e3aaSDag-Erling Smørgrav s += strlen(names[i]); 4654c75e3aaSDag-Erling Smørgrav } 4664c75e3aaSDag-Erling Smørgrav } 4674c75e3aaSDag-Erling Smørgrav 468b7579f77SDag-Erling Smørgrav /** check configuration for errors */ 469b7579f77SDag-Erling Smørgrav static void 470e86b9096SDag-Erling Smørgrav morechecks(struct config_file* cfg) 471b7579f77SDag-Erling Smørgrav { 472b7579f77SDag-Erling Smørgrav warn_hosts("stub-host", cfg->stubs); 473b7579f77SDag-Erling Smørgrav warn_hosts("forward-host", cfg->forwards); 474b7579f77SDag-Erling Smørgrav interfacechecks(cfg); 475b7579f77SDag-Erling Smørgrav aclchecks(cfg); 4764c75e3aaSDag-Erling Smørgrav tcpconnlimitchecks(cfg); 477b7579f77SDag-Erling Smørgrav 478b7579f77SDag-Erling Smørgrav if(cfg->verbosity < 0) 479b7579f77SDag-Erling Smørgrav fatal_exit("verbosity value < 0"); 480b7579f77SDag-Erling Smørgrav if(cfg->num_threads <= 0 || cfg->num_threads > 10000) 481b7579f77SDag-Erling Smørgrav fatal_exit("num_threads value weird"); 482b7579f77SDag-Erling Smørgrav if(!cfg->do_ip4 && !cfg->do_ip6) 483b7579f77SDag-Erling Smørgrav fatal_exit("ip4 and ip6 are both disabled, pointless"); 484b5663de9SDag-Erling Smørgrav if(!cfg->do_ip6 && cfg->prefer_ip6) 485b5663de9SDag-Erling Smørgrav fatal_exit("cannot prefer and disable ip6, pointless"); 486b7579f77SDag-Erling Smørgrav if(!cfg->do_udp && !cfg->do_tcp) 487b7579f77SDag-Erling Smørgrav fatal_exit("udp and tcp are both disabled, pointless"); 488b7579f77SDag-Erling Smørgrav if(cfg->edns_buffer_size > cfg->msg_buffer_size) 489b7579f77SDag-Erling Smørgrav fatal_exit("edns-buffer-size larger than msg-buffer-size, " 490b7579f77SDag-Erling Smørgrav "answers will not fit in processing buffer"); 49105ab2901SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 49205ab2901SDag-Erling Smørgrav w_config_adjust_directory(cfg); 49305ab2901SDag-Erling Smørgrav #endif 494b7579f77SDag-Erling Smørgrav if(cfg->chrootdir && cfg->chrootdir[0] && 495b7579f77SDag-Erling Smørgrav cfg->chrootdir[strlen(cfg->chrootdir)-1] == '/') 496b7579f77SDag-Erling Smørgrav fatal_exit("chootdir %s has trailing slash '/' please remove.", 497b7579f77SDag-Erling Smørgrav cfg->chrootdir); 498b7579f77SDag-Erling Smørgrav if(cfg->chrootdir && cfg->chrootdir[0] && 499b7579f77SDag-Erling Smørgrav !is_dir(cfg->chrootdir)) { 500b7579f77SDag-Erling Smørgrav fatal_exit("bad chroot directory"); 501b7579f77SDag-Erling Smørgrav } 502b7579f77SDag-Erling Smørgrav if(cfg->directory && cfg->directory[0]) { 503b7579f77SDag-Erling Smørgrav char* ad = fname_after_chroot(cfg->directory, cfg, 0); 504b7579f77SDag-Erling Smørgrav if(!ad) fatal_exit("out of memory"); 505b7579f77SDag-Erling Smørgrav if(!is_dir(ad)) fatal_exit("bad chdir directory"); 506b7579f77SDag-Erling Smørgrav free(ad); 507b7579f77SDag-Erling Smørgrav } 508b7579f77SDag-Erling Smørgrav if( (cfg->chrootdir && cfg->chrootdir[0]) || 509b7579f77SDag-Erling Smørgrav (cfg->directory && cfg->directory[0])) { 510b7579f77SDag-Erling Smørgrav if(cfg->pidfile && cfg->pidfile[0]) { 511b7579f77SDag-Erling Smørgrav char* ad = (cfg->pidfile[0]=='/')?strdup(cfg->pidfile): 512b7579f77SDag-Erling Smørgrav fname_after_chroot(cfg->pidfile, cfg, 1); 513b7579f77SDag-Erling Smørgrav char* bd = basedir(ad); 514b7579f77SDag-Erling Smørgrav if(bd && !is_dir(bd)) 515b7579f77SDag-Erling Smørgrav fatal_exit("pidfile directory does not exist"); 516b7579f77SDag-Erling Smørgrav free(ad); 517b7579f77SDag-Erling Smørgrav } 518b7579f77SDag-Erling Smørgrav if(cfg->logfile && cfg->logfile[0]) { 519b7579f77SDag-Erling Smørgrav char* ad = fname_after_chroot(cfg->logfile, cfg, 1); 520b7579f77SDag-Erling Smørgrav char* bd = basedir(ad); 521b7579f77SDag-Erling Smørgrav if(bd && !is_dir(bd)) 522b7579f77SDag-Erling Smørgrav fatal_exit("logfile directory does not exist"); 523b7579f77SDag-Erling Smørgrav free(ad); 524b7579f77SDag-Erling Smørgrav } 525b7579f77SDag-Erling Smørgrav } 526b7579f77SDag-Erling Smørgrav 527b7579f77SDag-Erling Smørgrav check_chroot_filelist("file with root-hints", 528b7579f77SDag-Erling Smørgrav cfg->root_hints, cfg->chrootdir, cfg); 529b7579f77SDag-Erling Smørgrav check_chroot_filelist("trust-anchor-file", 530b7579f77SDag-Erling Smørgrav cfg->trust_anchor_file_list, cfg->chrootdir, cfg); 531b7579f77SDag-Erling Smørgrav check_chroot_filelist("auto-trust-anchor-file", 532b7579f77SDag-Erling Smørgrav cfg->auto_trust_anchor_file_list, cfg->chrootdir, cfg); 533b7579f77SDag-Erling Smørgrav check_chroot_filelist_wild("trusted-keys-file", 534b7579f77SDag-Erling Smørgrav cfg->trusted_keys_file_list, cfg->chrootdir, cfg); 535b7579f77SDag-Erling Smørgrav check_chroot_string("dlv-anchor-file", &cfg->dlv_anchor_file, 536b7579f77SDag-Erling Smørgrav cfg->chrootdir, cfg); 537c7f4d7adSDag-Erling Smørgrav #ifdef USE_IPSECMOD 538971980c3SDag-Erling Smørgrav if(cfg->ipsecmod_enabled && strstr(cfg->module_conf, "ipsecmod")) { 539971980c3SDag-Erling Smørgrav /* only check hook if enabled */ 540971980c3SDag-Erling Smørgrav check_chroot_string("ipsecmod-hook", &cfg->ipsecmod_hook, 541971980c3SDag-Erling Smørgrav cfg->chrootdir, cfg); 542971980c3SDag-Erling Smørgrav } 543c7f4d7adSDag-Erling Smørgrav #endif 544b7579f77SDag-Erling Smørgrav /* remove chroot setting so that modules are not stripping pathnames*/ 545b7579f77SDag-Erling Smørgrav free(cfg->chrootdir); 546b7579f77SDag-Erling Smørgrav cfg->chrootdir = NULL; 547b7579f77SDag-Erling Smørgrav 5484c75e3aaSDag-Erling Smørgrav /* check that the modules listed in module_conf exist */ 5494c75e3aaSDag-Erling Smørgrav check_modules_exist(cfg->module_conf); 5504c75e3aaSDag-Erling Smørgrav 551*091e9e46SCy Schubert /* Respip is known to *not* work with dns64. */ 552b7579f77SDag-Erling Smørgrav if(strcmp(cfg->module_conf, "iterator") != 0 553b7579f77SDag-Erling Smørgrav && strcmp(cfg->module_conf, "validator iterator") != 0 554ff825849SDag-Erling Smørgrav && strcmp(cfg->module_conf, "dns64 validator iterator") != 0 555ff825849SDag-Erling Smørgrav && strcmp(cfg->module_conf, "dns64 iterator") != 0 55665b390aaSDag-Erling Smørgrav && strcmp(cfg->module_conf, "respip iterator") != 0 55765b390aaSDag-Erling Smørgrav && strcmp(cfg->module_conf, "respip validator iterator") != 0 558b7579f77SDag-Erling Smørgrav #ifdef WITH_PYTHONMODULE 559b7579f77SDag-Erling Smørgrav && strcmp(cfg->module_conf, "python iterator") != 0 560*091e9e46SCy Schubert && strcmp(cfg->module_conf, "python respip iterator") != 0 561b7579f77SDag-Erling Smørgrav && strcmp(cfg->module_conf, "python validator iterator") != 0 562*091e9e46SCy Schubert && strcmp(cfg->module_conf, "python respip validator iterator") != 0 563b7579f77SDag-Erling Smørgrav && strcmp(cfg->module_conf, "validator python iterator") != 0 564ff825849SDag-Erling Smørgrav && strcmp(cfg->module_conf, "dns64 python iterator") != 0 565ff825849SDag-Erling Smørgrav && strcmp(cfg->module_conf, "dns64 python validator iterator") != 0 566ff825849SDag-Erling Smørgrav && strcmp(cfg->module_conf, "dns64 validator python iterator") != 0 567ff825849SDag-Erling Smørgrav && strcmp(cfg->module_conf, "python dns64 iterator") != 0 568ff825849SDag-Erling Smørgrav && strcmp(cfg->module_conf, "python dns64 validator iterator") != 0 569b7579f77SDag-Erling Smørgrav #endif 570e2d15004SDag-Erling Smørgrav #ifdef USE_CACHEDB 571e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "validator cachedb iterator") != 0 572*091e9e46SCy Schubert && strcmp(cfg->module_conf, "respip validator cachedb iterator") != 0 573e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "cachedb iterator") != 0 574*091e9e46SCy Schubert && strcmp(cfg->module_conf, "respip cachedb iterator") != 0 575e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "dns64 validator cachedb iterator") != 0 576e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "dns64 cachedb iterator") != 0 57765b390aaSDag-Erling Smørgrav #endif 57865b390aaSDag-Erling Smørgrav #if defined(WITH_PYTHONMODULE) && defined(USE_CACHEDB) 579e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "python dns64 cachedb iterator") != 0 580e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "python dns64 validator cachedb iterator") != 0 581e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "dns64 python cachedb iterator") != 0 582e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "dns64 python validator cachedb iterator") != 0 583e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "python cachedb iterator") != 0 584*091e9e46SCy Schubert && strcmp(cfg->module_conf, "python respip cachedb iterator") != 0 585e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "python validator cachedb iterator") != 0 586*091e9e46SCy Schubert && strcmp(cfg->module_conf, "python respip validator cachedb iterator") != 0 587e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "cachedb python iterator") != 0 588*091e9e46SCy Schubert && strcmp(cfg->module_conf, "respip cachedb python iterator") != 0 589e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "validator cachedb python iterator") != 0 590*091e9e46SCy Schubert && strcmp(cfg->module_conf, "respip validator cachedb python iterator") != 0 591e2d15004SDag-Erling Smørgrav && strcmp(cfg->module_conf, "validator python cachedb iterator") != 0 592*091e9e46SCy Schubert && strcmp(cfg->module_conf, "respip validator python cachedb iterator") != 0 593e2d15004SDag-Erling Smørgrav #endif 59465b390aaSDag-Erling Smørgrav #ifdef CLIENT_SUBNET 59565b390aaSDag-Erling Smørgrav && strcmp(cfg->module_conf, "subnetcache iterator") != 0 596*091e9e46SCy Schubert && strcmp(cfg->module_conf, "respip subnetcache iterator") != 0 59765b390aaSDag-Erling Smørgrav && strcmp(cfg->module_conf, "subnetcache validator iterator") != 0 598*091e9e46SCy Schubert && strcmp(cfg->module_conf, "respip subnetcache validator iterator") != 0 599971980c3SDag-Erling Smørgrav && strcmp(cfg->module_conf, "dns64 subnetcache iterator") != 0 600971980c3SDag-Erling Smørgrav && strcmp(cfg->module_conf, "dns64 subnetcache validator iterator") != 0 60165b390aaSDag-Erling Smørgrav #endif 60265b390aaSDag-Erling Smørgrav #if defined(WITH_PYTHONMODULE) && defined(CLIENT_SUBNET) 60365b390aaSDag-Erling Smørgrav && strcmp(cfg->module_conf, "python subnetcache iterator") != 0 604*091e9e46SCy Schubert && strcmp(cfg->module_conf, "python respip subnetcache iterator") != 0 60565b390aaSDag-Erling Smørgrav && strcmp(cfg->module_conf, "subnetcache python iterator") != 0 606*091e9e46SCy Schubert && strcmp(cfg->module_conf, "respip subnetcache python iterator") != 0 60765b390aaSDag-Erling Smørgrav && strcmp(cfg->module_conf, "python subnetcache validator iterator") != 0 608*091e9e46SCy Schubert && strcmp(cfg->module_conf, "python respip subnetcache validator iterator") != 0 60965b390aaSDag-Erling Smørgrav && strcmp(cfg->module_conf, "subnetcache python validator iterator") != 0 610*091e9e46SCy Schubert && strcmp(cfg->module_conf, "respip subnetcache python validator iterator") != 0 61165b390aaSDag-Erling Smørgrav && strcmp(cfg->module_conf, "subnetcache validator python iterator") != 0 612*091e9e46SCy Schubert && strcmp(cfg->module_conf, "respip subnetcache validator python iterator") != 0 61365b390aaSDag-Erling Smørgrav #endif 614c7f4d7adSDag-Erling Smørgrav #ifdef USE_IPSECMOD 615c7f4d7adSDag-Erling Smørgrav && strcmp(cfg->module_conf, "ipsecmod iterator") != 0 616*091e9e46SCy Schubert && strcmp(cfg->module_conf, "ipsecmod respip iterator") != 0 617c7f4d7adSDag-Erling Smørgrav && strcmp(cfg->module_conf, "ipsecmod validator iterator") != 0 618*091e9e46SCy Schubert && strcmp(cfg->module_conf, "ipsecmod respip validator iterator") != 0 619c7f4d7adSDag-Erling Smørgrav #endif 620c7f4d7adSDag-Erling Smørgrav #if defined(WITH_PYTHONMODULE) && defined(USE_IPSECMOD) 621c7f4d7adSDag-Erling Smørgrav && strcmp(cfg->module_conf, "python ipsecmod iterator") != 0 622*091e9e46SCy Schubert && strcmp(cfg->module_conf, "python ipsecmod respip iterator") != 0 623c7f4d7adSDag-Erling Smørgrav && strcmp(cfg->module_conf, "ipsecmod python iterator") != 0 624*091e9e46SCy Schubert && strcmp(cfg->module_conf, "ipsecmod python respip iterator") != 0 625c7f4d7adSDag-Erling Smørgrav && strcmp(cfg->module_conf, "ipsecmod validator iterator") != 0 626*091e9e46SCy Schubert && strcmp(cfg->module_conf, "ipsecmod respip validator iterator") != 0 627c7f4d7adSDag-Erling Smørgrav && strcmp(cfg->module_conf, "python ipsecmod validator iterator") != 0 628*091e9e46SCy Schubert && strcmp(cfg->module_conf, "python ipsecmod respip validator iterator") != 0 629c7f4d7adSDag-Erling Smørgrav && strcmp(cfg->module_conf, "ipsecmod python validator iterator") != 0 630*091e9e46SCy Schubert && strcmp(cfg->module_conf, "ipsecmod python respip validator iterator") != 0 631c7f4d7adSDag-Erling Smørgrav && strcmp(cfg->module_conf, "ipsecmod validator python iterator") != 0 632*091e9e46SCy Schubert && strcmp(cfg->module_conf, "ipsecmod respip validator python iterator") != 0 633c7f4d7adSDag-Erling Smørgrav #endif 6340eefd307SCy Schubert #ifdef USE_IPSET 6350eefd307SCy Schubert && strcmp(cfg->module_conf, "validator ipset iterator") != 0 636*091e9e46SCy Schubert && strcmp(cfg->module_conf, "validator ipset respip iterator") != 0 6370eefd307SCy Schubert && strcmp(cfg->module_conf, "ipset iterator") != 0 638*091e9e46SCy Schubert && strcmp(cfg->module_conf, "ipset respip iterator") != 0 6390eefd307SCy Schubert #endif 640b7579f77SDag-Erling Smørgrav ) { 641b7579f77SDag-Erling Smørgrav fatal_exit("module conf '%s' is not known to work", 642b7579f77SDag-Erling Smørgrav cfg->module_conf); 643b7579f77SDag-Erling Smørgrav } 644b7579f77SDag-Erling Smørgrav 645b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 646b7579f77SDag-Erling Smørgrav if(cfg->username && cfg->username[0]) { 647b7579f77SDag-Erling Smørgrav if(getpwnam(cfg->username) == NULL) 648b7579f77SDag-Erling Smørgrav fatal_exit("user '%s' does not exist.", cfg->username); 649b5663de9SDag-Erling Smørgrav # ifdef HAVE_ENDPWENT 650b7579f77SDag-Erling Smørgrav endpwent(); 651b5663de9SDag-Erling Smørgrav # endif 652b7579f77SDag-Erling Smørgrav } 653b7579f77SDag-Erling Smørgrav #endif 6547da0adf7SDag-Erling Smørgrav if(cfg->remote_control_enable && options_remote_is_address(cfg) 6557da0adf7SDag-Erling Smørgrav && cfg->control_use_cert) { 656b7579f77SDag-Erling Smørgrav check_chroot_string("server-key-file", &cfg->server_key_file, 657b7579f77SDag-Erling Smørgrav cfg->chrootdir, cfg); 658b7579f77SDag-Erling Smørgrav check_chroot_string("server-cert-file", &cfg->server_cert_file, 659b7579f77SDag-Erling Smørgrav cfg->chrootdir, cfg); 660b7579f77SDag-Erling Smørgrav if(!is_file(cfg->control_key_file)) 661b7579f77SDag-Erling Smørgrav fatal_exit("control-key-file: \"%s\" does not exist", 662b7579f77SDag-Erling Smørgrav cfg->control_key_file); 663b7579f77SDag-Erling Smørgrav if(!is_file(cfg->control_cert_file)) 664b7579f77SDag-Erling Smørgrav fatal_exit("control-cert-file: \"%s\" does not exist", 665b7579f77SDag-Erling Smørgrav cfg->control_cert_file); 666b7579f77SDag-Erling Smørgrav } 667b7579f77SDag-Erling Smørgrav 6680eefd307SCy Schubert donotquerylocalhostcheck(cfg); 669b7579f77SDag-Erling Smørgrav localzonechecks(cfg); 67065b390aaSDag-Erling Smørgrav view_and_respipchecks(cfg); 671971980c3SDag-Erling Smørgrav #ifdef CLIENT_SUBNET 672971980c3SDag-Erling Smørgrav ecs_conf_checks(cfg); 673971980c3SDag-Erling Smørgrav #endif 674b7579f77SDag-Erling Smørgrav } 675b7579f77SDag-Erling Smørgrav 676b7579f77SDag-Erling Smørgrav /** check forwards */ 677b7579f77SDag-Erling Smørgrav static void 678b7579f77SDag-Erling Smørgrav check_fwd(struct config_file* cfg) 679b7579f77SDag-Erling Smørgrav { 680b7579f77SDag-Erling Smørgrav struct iter_forwards* fwd = forwards_create(); 681b7579f77SDag-Erling Smørgrav if(!fwd || !forwards_apply_cfg(fwd, cfg)) { 682b7579f77SDag-Erling Smørgrav fatal_exit("Could not set forward zones"); 683b7579f77SDag-Erling Smørgrav } 684b7579f77SDag-Erling Smørgrav forwards_delete(fwd); 685b7579f77SDag-Erling Smørgrav } 686b7579f77SDag-Erling Smørgrav 687b7579f77SDag-Erling Smørgrav /** check hints */ 688b7579f77SDag-Erling Smørgrav static void 689b7579f77SDag-Erling Smørgrav check_hints(struct config_file* cfg) 690b7579f77SDag-Erling Smørgrav { 691b7579f77SDag-Erling Smørgrav struct iter_hints* hints = hints_create(); 692b7579f77SDag-Erling Smørgrav if(!hints || !hints_apply_cfg(hints, cfg)) { 693b7579f77SDag-Erling Smørgrav fatal_exit("Could not set root or stub hints"); 694b7579f77SDag-Erling Smørgrav } 695b7579f77SDag-Erling Smørgrav hints_delete(hints); 696b7579f77SDag-Erling Smørgrav } 697b7579f77SDag-Erling Smørgrav 69857bddd21SDag-Erling Smørgrav /** check auth zones */ 69957bddd21SDag-Erling Smørgrav static void 70057bddd21SDag-Erling Smørgrav check_auth(struct config_file* cfg) 70157bddd21SDag-Erling Smørgrav { 702*091e9e46SCy Schubert int is_rpz = 0; 70357bddd21SDag-Erling Smørgrav struct auth_zones* az = auth_zones_create(); 704*091e9e46SCy Schubert if(!az || !auth_zones_apply_cfg(az, cfg, 0i, &is_rpz)) { 70557bddd21SDag-Erling Smørgrav fatal_exit("Could not setup authority zones"); 70657bddd21SDag-Erling Smørgrav } 70757bddd21SDag-Erling Smørgrav auth_zones_delete(az); 70857bddd21SDag-Erling Smørgrav } 70957bddd21SDag-Erling Smørgrav 710b7579f77SDag-Erling Smørgrav /** check config file */ 711b7579f77SDag-Erling Smørgrav static void 7126480faa8SDag-Erling Smørgrav checkconf(const char* cfgfile, const char* opt, int final) 713b7579f77SDag-Erling Smørgrav { 714bc892140SDag-Erling Smørgrav char oldwd[4096]; 715b7579f77SDag-Erling Smørgrav struct config_file* cfg = config_create(); 716b7579f77SDag-Erling Smørgrav if(!cfg) 717b7579f77SDag-Erling Smørgrav fatal_exit("out of memory"); 718b5663de9SDag-Erling Smørgrav oldwd[0] = 0; 719b5663de9SDag-Erling Smørgrav if(!getcwd(oldwd, sizeof(oldwd))) { 720b5663de9SDag-Erling Smørgrav log_err("cannot getcwd: %s", strerror(errno)); 721b5663de9SDag-Erling Smørgrav oldwd[0] = 0; 722b5663de9SDag-Erling Smørgrav } 723b7579f77SDag-Erling Smørgrav if(!config_read(cfg, cfgfile, NULL)) { 724b7579f77SDag-Erling Smørgrav /* config_read prints messages to stderr */ 725b7579f77SDag-Erling Smørgrav config_delete(cfg); 726b7579f77SDag-Erling Smørgrav exit(1); 727b7579f77SDag-Erling Smørgrav } 728b5663de9SDag-Erling Smørgrav if(oldwd[0] && chdir(oldwd) == -1) 729b5663de9SDag-Erling Smørgrav log_err("cannot chdir(%s): %s", oldwd, strerror(errno)); 730ff825849SDag-Erling Smørgrav if(opt) { 7316480faa8SDag-Erling Smørgrav print_option(cfg, opt, final); 732ff825849SDag-Erling Smørgrav config_delete(cfg); 733ff825849SDag-Erling Smørgrav return; 734ff825849SDag-Erling Smørgrav } 735e86b9096SDag-Erling Smørgrav morechecks(cfg); 736b7579f77SDag-Erling Smørgrav check_mod(cfg, iter_get_funcblock()); 737b7579f77SDag-Erling Smørgrav check_mod(cfg, val_get_funcblock()); 738b7579f77SDag-Erling Smørgrav #ifdef WITH_PYTHONMODULE 739b7579f77SDag-Erling Smørgrav if(strstr(cfg->module_conf, "python")) 740b7579f77SDag-Erling Smørgrav check_mod(cfg, pythonmod_get_funcblock()); 741b7579f77SDag-Erling Smørgrav #endif 742b7579f77SDag-Erling Smørgrav check_fwd(cfg); 743b7579f77SDag-Erling Smørgrav check_hints(cfg); 74457bddd21SDag-Erling Smørgrav check_auth(cfg); 745ff825849SDag-Erling Smørgrav printf("unbound-checkconf: no errors in %s\n", cfgfile); 746b7579f77SDag-Erling Smørgrav config_delete(cfg); 747b7579f77SDag-Erling Smørgrav } 748b7579f77SDag-Erling Smørgrav 749b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 750b7579f77SDag-Erling Smørgrav extern int optind; 751b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 752b7579f77SDag-Erling Smørgrav extern char* optarg; 753b7579f77SDag-Erling Smørgrav 754b7579f77SDag-Erling Smørgrav /** Main routine for checkconf */ 755b7579f77SDag-Erling Smørgrav int main(int argc, char* argv[]) 756b7579f77SDag-Erling Smørgrav { 757b7579f77SDag-Erling Smørgrav int c; 7586480faa8SDag-Erling Smørgrav int final = 0; 759b7579f77SDag-Erling Smørgrav const char* f; 760b7579f77SDag-Erling Smørgrav const char* opt = NULL; 761b7579f77SDag-Erling Smørgrav const char* cfgfile = CONFIGFILE; 762b7579f77SDag-Erling Smørgrav log_ident_set("unbound-checkconf"); 763b7579f77SDag-Erling Smørgrav log_init(NULL, 0, NULL); 764b7579f77SDag-Erling Smørgrav checklock_start(); 765b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 766b7579f77SDag-Erling Smørgrav /* use registry config file in preference to compiletime location */ 767b7579f77SDag-Erling Smørgrav if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile"))) 768b7579f77SDag-Erling Smørgrav cfgfile = CONFIGFILE; 769b7579f77SDag-Erling Smørgrav #endif /* USE_WINSOCK */ 770b7579f77SDag-Erling Smørgrav /* parse the options */ 7716480faa8SDag-Erling Smørgrav while( (c=getopt(argc, argv, "fho:")) != -1) { 772b7579f77SDag-Erling Smørgrav switch(c) { 7736480faa8SDag-Erling Smørgrav case 'f': 7746480faa8SDag-Erling Smørgrav final = 1; 7756480faa8SDag-Erling Smørgrav break; 776b7579f77SDag-Erling Smørgrav case 'o': 777b7579f77SDag-Erling Smørgrav opt = optarg; 778b7579f77SDag-Erling Smørgrav break; 779b7579f77SDag-Erling Smørgrav case '?': 780b7579f77SDag-Erling Smørgrav case 'h': 781b7579f77SDag-Erling Smørgrav default: 782b7579f77SDag-Erling Smørgrav usage(); 783b7579f77SDag-Erling Smørgrav } 784b7579f77SDag-Erling Smørgrav } 785b7579f77SDag-Erling Smørgrav argc -= optind; 786b7579f77SDag-Erling Smørgrav argv += optind; 787b7579f77SDag-Erling Smørgrav if(argc != 0 && argc != 1) 788b7579f77SDag-Erling Smørgrav usage(); 789b7579f77SDag-Erling Smørgrav if(argc == 1) 790b7579f77SDag-Erling Smørgrav f = argv[0]; 791b7579f77SDag-Erling Smørgrav else f = cfgfile; 7926480faa8SDag-Erling Smørgrav checkconf(f, opt, final); 793b7579f77SDag-Erling Smørgrav checklock_stop(); 794b7579f77SDag-Erling Smørgrav return 0; 795b7579f77SDag-Erling Smørgrav } 796