2007-09-26 09:39:49 -04:00
/*
2021-04-13 07:58:53 -04:00
* smallapp / unbound - checkconf . c - config file checker for unbound . conf file .
2007-09-26 09:39:49 -04:00
*
* Copyright ( c ) 2007 , NLnet Labs . All rights reserved .
*
* This software is open source .
2017-05-16 08:39:24 -04:00
*
2007-09-26 09:39:49 -04:00
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
2017-05-16 08:39:24 -04:00
*
2007-09-26 09:39:49 -04:00
* Redistributions of source code must retain the above copyright notice ,
* this list of conditions and the following disclaimer .
2017-05-16 08:39:24 -04:00
*
2007-09-26 09:39:49 -04:00
* Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
2017-05-16 08:39:24 -04:00
*
2007-09-26 09:39:49 -04:00
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission .
2017-05-16 08:39:24 -04:00
*
2007-09-26 09:39:49 -04:00
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2014-02-07 08:28:39 -05:00
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED
* TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR
* PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
2007-09-26 09:39:49 -04:00
*/
/**
* \ file
*
* The config checker checks for syntax and other errors in the unbound . conf
* file , and can be used to check for errors before the server is started
* or sigHUPped .
* Exit status 1 means an error .
*/
# include "config.h"
2018-08-09 04:33:56 -04:00
# include <ctype.h>
2007-09-26 09:39:49 -04:00
# include "util/log.h"
# include "util/config_file.h"
# include "util/module.h"
2007-09-28 10:33:35 -04:00
# include "util/net_help.h"
2007-10-18 16:31:43 -04:00
# include "util/regional.h"
2007-09-26 09:39:49 -04:00
# include "iterator/iterator.h"
2009-03-12 05:36:28 -04:00
# include "iterator/iter_fwd.h"
2012-02-16 04:55:50 -05:00
# include "iterator/iter_hints.h"
2007-09-26 09:39:49 -04:00
# include "validator/validator.h"
2007-11-22 04:30:44 -05:00
# include "services/localzone.h"
2021-11-29 09:13:14 -05:00
# include "services/listen_dnsport.h"
2017-03-07 09:58:51 -05:00
# include "services/view.h"
2017-10-17 11:16:31 -04:00
# include "services/authzone.h"
2017-03-07 09:58:51 -05:00
# include "respip/respip.h"
2015-03-26 06:21:38 -04:00
# include "sldns/sbuffer.h"
2020-07-07 03:00:04 -04:00
# include "sldns/str2wire.h"
2010-03-12 10:17:48 -05:00
# ifdef HAVE_GETOPT_H
# include <getopt.h>
# endif
2008-05-23 10:13:07 -04:00
# ifdef HAVE_PWD_H
2007-09-26 09:39:49 -04:00
# include <pwd.h>
2008-05-23 10:13:07 -04:00
# endif
2008-04-14 10:48:17 -04:00
# ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
# endif
2009-01-07 07:24:34 -05:00
# ifdef HAVE_GLOB_H
# include <glob.h>
# endif
2009-03-25 10:47:47 -04:00
# ifdef WITH_PYTHONMODULE
# include "pythonmod/pythonmod.h"
# endif
2017-08-22 03:43:59 -04:00
# ifdef CLIENT_SUBNET
# include "edns-subnet/subnet-whitelist.h"
# endif
2007-09-26 09:39:49 -04:00
/** Give checkconf usage, and exit (1). */
static void
2016-09-05 03:23:23 -04:00
usage ( void )
2007-09-26 09:39:49 -04:00
{
2007-11-09 08:52:13 -05:00
printf ( " Usage: unbound-checkconf [file] \n " ) ;
2007-09-26 09:39:49 -04:00
printf ( " Checks unbound configuration file for errors. \n " ) ;
2007-11-09 08:52:13 -05:00
printf ( " file if omitted %s is used. \n " , CONFIGFILE ) ;
2009-02-06 10:15:15 -05:00
printf ( " -o option print value of option to stdout. \n " ) ;
2015-01-16 09:31:02 -05:00
printf ( " -f output full pathname with chroot applied, eg. with -o pidfile. \n " ) ;
2024-04-26 08:50:39 -04:00
printf ( " -q quiet (suppress output on success). \n " ) ;
2009-02-06 10:15:15 -05:00
printf ( " -h show this usage help. \n " ) ;
2007-09-26 09:39:49 -04:00
printf ( " Version %s \n " , PACKAGE_VERSION ) ;
printf ( " BSD licensed, see LICENSE in source package for details. \n " ) ;
printf ( " Report bugs to %s \n " , PACKAGE_BUGREPORT ) ;
exit ( 1 ) ;
}
2017-05-16 08:39:24 -04:00
/**
* Print given option to stdout
2009-02-06 10:15:15 -05:00
* @ param cfg : config
2017-05-16 08:39:24 -04:00
* @ param opt : option name without trailing : .
2009-02-06 10:15:15 -05:00
* This is different from config_set_option .
2015-01-16 09:31:02 -05:00
* @ param final : if final pathname with chroot applied has to be printed .
2009-02-06 10:15:15 -05:00
*/
static void
2015-01-16 09:31:02 -05:00
print_option ( struct config_file * cfg , const char * opt , int final )
2009-02-06 10:15:15 -05:00
{
2015-01-16 09:31:02 -05:00
if ( strcmp ( opt , " pidfile " ) = = 0 & & final ) {
2016-11-23 06:21:10 -05:00
char * p = fname_after_chroot ( cfg - > pidfile , cfg , 1 ) ;
if ( ! p ) fatal_exit ( " out of memory " ) ;
printf ( " %s \n " , p ) ;
free ( p ) ;
2015-01-16 09:31:02 -05:00
return ;
}
2018-01-23 09:20:17 -05:00
if ( strcmp ( opt , " auto-trust-anchor-file " ) = = 0 & & final ) {
struct config_strlist * s = cfg - > auto_trust_anchor_file_list ;
for ( ; s ; s = s - > next ) {
char * p = fname_after_chroot ( s - > str , cfg , 1 ) ;
if ( ! p ) fatal_exit ( " out of memory " ) ;
printf ( " %s \n " , p ) ;
free ( p ) ;
}
return ;
}
2010-02-18 11:40:22 -05:00
if ( ! config_get_option ( cfg , opt , config_print_func , stdout ) )
fatal_exit ( " cannot print option '%s' " , opt ) ;
2009-02-06 10:15:15 -05:00
}
2007-09-26 09:39:49 -04:00
/** check if module works with config */
static void
check_mod ( struct config_file * cfg , struct module_func_block * fb )
{
struct module_env env ;
memset ( & env , 0 , sizeof ( env ) ) ;
env . cfg = cfg ;
2007-10-18 16:31:43 -04:00
env . scratch = regional_create ( ) ;
2013-12-03 04:11:16 -05:00
env . scratch_buffer = sldns_buffer_new ( BUFSIZ ) ;
2007-10-18 16:31:43 -04:00
if ( ! env . scratch | | ! env . scratch_buffer )
fatal_exit ( " out of memory " ) ;
2016-12-06 08:42:51 -05:00
if ( ! edns_known_options_init ( & env ) )
fatal_exit ( " out of memory " ) ;
2024-07-01 10:10:07 -04:00
if ( fb - > startup & & ! ( * fb - > startup ) ( & env , 0 ) )
fatal_exit ( " bad config during startup for %s module " , fb - > name ) ;
if ( ! ( * fb - > init ) ( & env , 0 ) )
fatal_exit ( " bad config during init for %s module " , fb - > name ) ;
2007-09-26 09:39:49 -04:00
( * fb - > deinit ) ( & env , 0 ) ;
2024-07-01 10:10:07 -04:00
if ( fb - > destartup )
( * fb - > destartup ) ( & env , 0 ) ;
2013-12-03 04:11:16 -05:00
sldns_buffer_free ( env . scratch_buffer ) ;
2007-10-18 16:31:43 -04:00
regional_destroy ( env . scratch ) ;
2016-12-06 08:42:51 -05:00
edns_known_options_delete ( & env ) ;
2007-09-26 09:39:49 -04:00
}
2019-08-16 06:21:40 -04:00
/** true if addr is a localhost address, 127.0.0.1 or ::1 (with maybe "@port"
* after it ) */
2019-06-25 08:50:49 -04:00
static int
str_addr_is_localhost ( const char * a )
{
if ( strncmp ( a , " 127. " , 4 ) = = 0 ) return 1 ;
if ( strncmp ( a , " ::1 " , 3 ) = = 0 ) return 1 ;
return 0 ;
}
/** check do-not-query-localhost */
static void
donotquerylocalhostcheck ( struct config_file * cfg )
{
if ( cfg - > donotquery_localhost ) {
struct config_stub * p ;
struct config_strlist * s ;
for ( p = cfg - > forwards ; p ; p = p - > next ) {
for ( s = p - > addrs ; s ; s = s - > next ) {
if ( str_addr_is_localhost ( s - > str ) ) {
2019-06-25 09:14:07 -04:00
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 " ,
s - > str , p - > name ) ;
2019-06-25 08:50:49 -04:00
}
}
}
for ( p = cfg - > stubs ; p ; p = p - > next ) {
for ( s = p - > addrs ; s ; s = s - > next ) {
if ( str_addr_is_localhost ( s - > str ) ) {
2019-06-25 09:14:07 -04:00
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 " ,
s - > str , p - > name ) ;
2019-06-25 08:50:49 -04:00
}
}
}
}
}
2008-01-11 06:24:30 -05:00
/** check localzones */
2007-09-26 09:39:49 -04:00
static void
2008-01-11 06:24:30 -05:00
localzonechecks ( struct config_file * cfg )
{
struct local_zones * zs ;
if ( ! ( zs = local_zones_create ( ) ) )
fatal_exit ( " out of memory " ) ;
if ( ! local_zones_apply_cfg ( zs , cfg ) )
fatal_exit ( " failed local-zone, local-data configuration " ) ;
local_zones_delete ( zs ) ;
}
2020-07-07 03:00:04 -04:00
/** checks for acl and views */
static void
2020-07-07 04:18:56 -04:00
acl_view_tag_checks ( struct config_file * cfg , struct views * views )
2020-07-07 03:00:04 -04:00
{
int d ;
struct sockaddr_storage a ;
socklen_t alen ;
struct config_str2list * acl ;
struct config_str3list * s3 ;
struct config_strbytelist * sb ;
/* acl_view */
for ( acl = cfg - > acl_view ; acl ; acl = acl - > next ) {
2020-07-07 04:18:56 -04:00
struct view * v ;
2020-07-07 03:00:04 -04:00
if ( ! netblockstrtoaddr ( acl - > str , UNBOUND_DNS_PORT , & a , & alen ,
& d ) ) {
fatal_exit ( " cannot parse access-control-view "
" address %s %s " , acl - > str , acl - > str2 ) ;
}
v = views_find_view ( views , acl - > str2 , 0 ) ;
if ( ! v ) {
fatal_exit ( " cannot find view for "
" access-control-view: %s %s " ,
acl - > str , acl - > str2 ) ;
}
lock_rw_unlock ( & v - > lock ) ;
}
/* acl_tags */
for ( sb = cfg - > acl_tags ; sb ; sb = sb - > next ) {
if ( ! netblockstrtoaddr ( sb - > str , UNBOUND_DNS_PORT , & a , & alen ,
& d ) ) {
fatal_exit ( " cannot parse access-control-tags "
" address %s " , sb - > str ) ;
}
}
/* acl_tag_actions */
for ( s3 = cfg - > acl_tag_actions ; s3 ; s3 = s3 - > next ) {
enum localzone_type t ;
if ( ! netblockstrtoaddr ( s3 - > str , UNBOUND_DNS_PORT , & a , & alen ,
& d ) ) {
fatal_exit ( " cannot parse access-control-tag-actions "
" address %s %s %s " ,
s3 - > str , s3 - > str2 , s3 - > str3 ) ;
}
if ( find_tag_id ( cfg , s3 - > str2 ) = = - 1 ) {
fatal_exit ( " cannot parse tag %s (define-tag it), "
" for access-control-tag-actions: %s %s %s " ,
s3 - > str2 , s3 - > str , s3 - > str2 , s3 - > str3 ) ;
}
if ( ! local_zone_str2type ( s3 - > str3 , & t ) ) {
fatal_exit ( " cannot parse access control action type %s "
" for access-control-tag-actions: %s %s %s " ,
s3 - > str3 , s3 - > str , s3 - > str2 , s3 - > str3 ) ;
}
}
/* acl_tag_datas */
for ( s3 = cfg - > acl_tag_datas ; s3 ; s3 = s3 - > next ) {
char buf [ 65536 ] ;
uint8_t rr [ LDNS_RR_BUF_SIZE ] ;
size_t len = sizeof ( rr ) ;
int res ;
if ( ! netblockstrtoaddr ( s3 - > str , UNBOUND_DNS_PORT , & a , & alen ,
& d ) ) {
fatal_exit ( " cannot parse access-control-tag-datas address %s %s '%s' " ,
s3 - > str , s3 - > str2 , s3 - > str3 ) ;
}
if ( find_tag_id ( cfg , s3 - > str2 ) = = - 1 ) {
fatal_exit ( " cannot parse tag %s (define-tag it), "
" for access-control-tag-datas: %s %s '%s' " ,
s3 - > str2 , s3 - > str , s3 - > str2 , s3 - > str3 ) ;
}
/* '.' is sufficient for validation, and it makes the call to
* sldns_wirerr_get_type ( ) simpler below . */
snprintf ( buf , sizeof ( buf ) , " %s %s " , " . " , s3 - > str3 ) ;
res = sldns_str2wire_rr_buf ( buf , rr , & len , NULL , 3600 , NULL ,
0 , NULL , 0 ) ;
if ( res ! = 0 ) {
fatal_exit ( " cannot parse rr data [char %d] parse error %s, for access-control-tag-datas: %s %s '%s' " ,
( int ) LDNS_WIREPARSE_OFFSET ( res ) - 2 ,
sldns_get_errorstr_parse ( res ) ,
s3 - > str , s3 - > str2 , s3 - > str3 ) ;
}
}
}
2017-03-07 09:58:51 -05:00
/** check view and response-ip configuration */
static void
view_and_respipchecks ( struct config_file * cfg )
{
struct views * views = NULL ;
struct respip_set * respip = NULL ;
2025-05-20 10:21:02 -04:00
int have_view_respip_cfg = 0 ;
int use_response_ip = 0 ;
2017-03-07 09:58:51 -05:00
if ( ! ( views = views_create ( ) ) )
fatal_exit ( " Could not create views: out of memory " ) ;
if ( ! ( respip = respip_set_create ( ) ) )
fatal_exit ( " Could not create respip set: out of memory " ) ;
if ( ! views_apply_cfg ( views , cfg ) )
fatal_exit ( " Could not set up views " ) ;
2017-04-18 05:00:52 -04:00
if ( ! respip_global_apply_cfg ( respip , cfg ) )
2017-03-07 09:58:51 -05:00
fatal_exit ( " Could not setup respip set " ) ;
2025-05-20 10:21:02 -04:00
if ( ! respip_views_apply_cfg ( views , cfg , & have_view_respip_cfg ) )
2017-03-07 09:58:51 -05:00
fatal_exit ( " Could not setup per-view respip sets " ) ;
2025-05-20 10:21:02 -04:00
use_response_ip = ! respip_set_is_empty ( respip ) | | have_view_respip_cfg ;
if ( use_response_ip & & ! strstr ( cfg - > module_conf , " respip " ) )
fatal_exit ( " response-ip options require respip module " ) ;
2020-07-07 04:18:56 -04:00
acl_view_tag_checks ( cfg , views ) ;
2017-03-07 09:58:51 -05:00
views_delete ( views ) ;
respip_set_delete ( respip ) ;
}
2008-01-11 06:24:30 -05:00
/** emit warnings for IP in hosts */
static void
warn_hosts ( const char * typ , struct config_stub * list )
2007-09-26 09:39:49 -04:00
{
2007-10-19 04:32:36 -04:00
struct sockaddr_storage a ;
socklen_t alen ;
2008-01-11 06:24:30 -05:00
struct config_stub * s ;
struct config_strlist * h ;
for ( s = list ; s ; s = s - > next ) {
for ( h = s - > hosts ; h ; h = h - > next ) {
2021-08-19 10:12:19 -04:00
if ( extstrtoaddr ( h - > str , & a , & alen , UNBOUND_DNS_PORT ) ) {
2008-01-11 06:24:30 -05:00
fprintf ( stderr , " unbound-checkconf: warning: "
" %s %s: \" %s \" is an IP%s address, "
" and when looked up as a host name "
2017-05-16 08:39:24 -04:00
" during use may not resolve. \n " ,
2008-01-11 06:24:30 -05:00
s - > name , typ , h - > str ,
addr_is_ip6 ( & a , alen ) ? " 6 " : " 4 " ) ;
}
}
}
}
/** check interface strings */
static void
interfacechecks ( struct config_file * cfg )
{
2016-07-04 10:51:30 -04:00
int d ;
2008-01-11 06:24:30 -05:00
struct sockaddr_storage a ;
socklen_t alen ;
2021-11-29 08:59:39 -05:00
int i , j , i2 , j2 ;
char * * * resif = NULL ;
2021-11-29 09:26:07 -05:00
int * num_resif = NULL ;
2021-11-29 08:59:39 -05:00
if ( cfg - > num_ifs ! = 0 ) {
resif = ( char * * * ) calloc ( cfg - > num_ifs , sizeof ( char * * ) ) ;
2021-11-29 09:13:14 -05:00
if ( ! resif ) fatal_exit ( " malloc failure " ) ;
2021-11-30 22:31:58 -05:00
num_resif = ( int * ) calloc ( cfg - > num_ifs , sizeof ( int ) ) ;
2021-11-29 09:13:14 -05:00
if ( ! num_resif ) fatal_exit ( " malloc failure " ) ;
2021-11-29 08:59:39 -05:00
}
2007-09-28 10:33:35 -04:00
for ( i = 0 ; i < cfg - > num_ifs ; i + + ) {
2021-11-29 08:59:39 -05:00
/* search for duplicates in IP or ifname arguments */
for ( i2 = 0 ; i2 < i ; i2 + + ) {
if ( strcmp ( cfg - > ifs [ i ] , cfg - > ifs [ i2 ] ) = = 0 ) {
2008-01-11 06:24:30 -05:00
fatal_exit ( " interface: %s present twice, "
" cannot bind same ports twice. " ,
cfg - > ifs [ i ] ) ;
2021-11-29 08:59:39 -05:00
}
}
if ( ! resolve_interface_names ( & cfg - > ifs [ i ] , 1 , NULL , & resif [ i ] ,
& num_resif [ i ] ) ) {
fatal_exit ( " could not resolve interface names, for %s " ,
cfg - > ifs [ i ] ) ;
}
2022-10-03 09:29:47 -04:00
/* check for port combinations that are not supported */
2025-01-21 04:04:30 -05:00
if ( if_is_pp2 ( resif [ i ] [ 0 ] , cfg - > port , cfg - > proxy_protocol_port ) ) {
if ( if_is_dnscrypt ( resif [ i ] [ 0 ] , cfg - > port ,
2022-10-03 09:29:47 -04:00
cfg - > dnscrypt_port ) ) {
fatal_exit ( " PROXYv2 and DNSCrypt combination not "
" supported! " ) ;
2025-01-21 04:04:30 -05:00
} else if ( if_is_https ( resif [ i ] [ 0 ] , cfg - > port ,
2022-10-03 09:29:47 -04:00
cfg - > https_port ) ) {
fatal_exit ( " PROXYv2 and DoH combination not "
" supported! " ) ;
2025-01-21 04:04:30 -05:00
} else if ( if_is_quic ( resif [ i ] [ 0 ] , cfg - > port ,
cfg - > quic_port ) ) {
fatal_exit ( " PROXYv2 and DoQ combination not "
" supported! " ) ;
2022-10-03 09:29:47 -04:00
}
}
2021-11-29 08:59:39 -05:00
/* search for duplicates in the returned addresses */
for ( j = 0 ; j < num_resif [ i ] ; j + + ) {
2022-10-03 09:29:47 -04:00
if ( ! extstrtoaddr ( resif [ i ] [ j ] , & a , & alen , cfg - > port ) ) {
2021-11-29 08:59:39 -05:00
if ( strcmp ( cfg - > ifs [ i ] , resif [ i ] [ j ] ) ! = 0 )
2021-11-29 10:11:32 -05:00
fatal_exit ( " cannot parse interface address '%s' from the interface specified as '%s' " ,
2021-11-29 08:59:39 -05:00
resif [ i ] [ j ] , cfg - > ifs [ i ] ) ;
else
fatal_exit ( " cannot parse interface specified as '%s' " ,
cfg - > ifs [ i ] ) ;
}
for ( i2 = 0 ; i2 < i ; i2 + + ) {
for ( j2 = 0 ; j2 < num_resif [ i2 ] ; j2 + + ) {
if ( strcmp ( resif [ i ] [ j ] , resif [ i2 ] [ j2 ] )
= = 0 ) {
char info1 [ 1024 ] , info2 [ 1024 ] ;
if ( strcmp ( cfg - > ifs [ i ] , resif [ i ] [ j ] ) ! = 0 )
snprintf ( info1 , sizeof ( info1 ) , " address %s from interface: %s " , resif [ i ] [ j ] , cfg - > ifs [ i ] ) ;
else snprintf ( info1 , sizeof ( info1 ) , " interface: %s " , cfg - > ifs [ i ] ) ;
if ( strcmp ( cfg - > ifs [ i2 ] , resif [ i2 ] [ j2 ] ) ! = 0 )
snprintf ( info2 , sizeof ( info2 ) , " address %s from interface: %s " , resif [ i2 ] [ j2 ] , cfg - > ifs [ i2 ] ) ;
else snprintf ( info2 , sizeof ( info2 ) , " interface: %s " , cfg - > ifs [ i2 ] ) ;
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 ) ;
}
}
}
2008-01-11 06:24:30 -05:00
}
2007-09-28 10:33:35 -04:00
}
2021-11-29 08:59:39 -05:00
for ( i = 0 ; i < cfg - > num_ifs ; i + + ) {
config_del_strarray ( resif [ i ] , num_resif [ i ] ) ;
}
free ( resif ) ;
free ( num_resif ) ;
2007-10-19 04:32:36 -04:00
for ( i = 0 ; i < cfg - > num_out_ifs ; i + + ) {
2016-07-04 10:51:30 -04:00
if ( ! ipstrtoaddr ( cfg - > out_ifs [ i ] , UNBOUND_DNS_PORT , & a , & alen ) & &
! netblockstrtoaddr ( cfg - > out_ifs [ i ] , UNBOUND_DNS_PORT , & a , & alen , & d ) ) {
2007-10-19 04:32:36 -04:00
fatal_exit ( " cannot parse outgoing-interface "
" specified as '%s' " , cfg - > out_ifs [ i ] ) ;
}
2008-01-11 06:24:30 -05:00
for ( j = 0 ; j < cfg - > num_out_ifs ; j + + ) {
if ( i ! = j & & strcmp ( cfg - > out_ifs [ i ] , cfg - > out_ifs [ j ] ) = = 0 )
fatal_exit ( " outgoing-interface: %s present "
" twice, cannot bind same ports twice. " ,
cfg - > out_ifs [ i ] ) ;
}
2007-10-19 04:32:36 -04:00
}
2008-01-11 06:24:30 -05:00
}
2022-02-11 04:58:53 -05:00
/** check interface-automatic-ports */
static void
ifautomaticportschecks ( char * ifautomaticports )
{
char * now = ifautomaticports ;
while ( now & & * now ) {
char * after ;
int extraport ;
while ( isspace ( ( unsigned char ) * now ) )
now + + ;
if ( ! * now )
break ;
after = now ;
extraport = ( int ) strtol ( now , & after , 10 ) ;
if ( extraport < 0 | | extraport > 65535 )
fatal_exit ( " interface-automatic-ports: port out of range at position %d in '%s' " , ( int ) ( now - ifautomaticports ) + 1 , ifautomaticports ) ;
if ( extraport = = 0 & & now = = after )
fatal_exit ( " interface-automatic-ports: parse error at position %d in '%s' " , ( int ) ( now - ifautomaticports ) + 1 , ifautomaticports ) ;
now = after ;
}
}
2025-06-16 06:43:31 -04:00
/** check control interface strings */
static void
controlinterfacechecks ( struct config_file * cfg )
{
struct config_strlist * p ;
for ( p = cfg - > control_ifs . first ; p ; p = p - > next ) {
struct sockaddr_storage a ;
socklen_t alen ;
char * * rcif = NULL ;
int i , num_rcif = 0 ;
/* See if it is a local socket, starts with a '/'. */
if ( p - > str & & p - > str [ 0 ] = = ' / ' )
continue ;
if ( ! resolve_interface_names ( & p - > str , 1 , NULL , & rcif ,
& num_rcif ) ) {
fatal_exit ( " could not resolve interface names, for control-interface: %s " ,
p - > str ) ;
}
for ( i = 0 ; i < num_rcif ; i + + ) {
if ( ! extstrtoaddr ( rcif [ i ] , & a , & alen ,
cfg - > control_port ) ) {
if ( strcmp ( p - > str , rcif [ i ] ) ! = 0 )
fatal_exit ( " cannot parse control-interface address '%s' from the control-interface specified as '%s' " ,
rcif [ i ] , p - > str ) ;
else
fatal_exit ( " cannot parse control-interface specified as '%s' " ,
p - > str ) ;
}
}
config_del_strarray ( rcif , num_rcif ) ;
}
}
2008-01-11 06:24:30 -05:00
/** check acl ips */
static void
aclchecks ( struct config_file * cfg )
{
int d ;
struct sockaddr_storage a ;
socklen_t alen ;
struct config_str2list * acl ;
2007-11-19 10:32:55 -05:00
for ( acl = cfg - > acls ; acl ; acl = acl - > next ) {
2017-05-16 08:39:24 -04:00
if ( ! netblockstrtoaddr ( acl - > str , UNBOUND_DNS_PORT , & a , & alen ,
2008-01-11 06:24:30 -05:00
& d ) ) {
2007-11-19 10:32:55 -05:00
fatal_exit ( " cannot parse access control address %s %s " ,
2007-11-20 09:48:33 -05:00
acl - > str , acl - > str2 ) ;
2007-11-19 10:32:55 -05:00
}
}
2008-01-11 06:24:30 -05:00
}
2018-08-07 07:57:42 -04:00
/** check tcp connection limit ips */
static void
tcpconnlimitchecks ( struct config_file * cfg )
{
int d ;
struct sockaddr_storage a ;
socklen_t alen ;
struct config_str2list * tcl ;
for ( tcl = cfg - > tcp_connection_limits ; tcl ; tcl = tcl - > next ) {
if ( ! netblockstrtoaddr ( tcl - > str , UNBOUND_DNS_PORT , & a , & alen ,
& d ) ) {
fatal_exit ( " cannot parse tcp connection limit address %s %s " ,
tcl - > str , tcl - > str2 ) ;
}
}
}
2008-04-14 10:48:17 -04:00
/** true if fname is a file */
static int
2017-05-16 08:39:24 -04:00
is_file ( const char * fname )
2008-04-14 10:48:17 -04:00
{
struct stat buf ;
if ( stat ( fname , & buf ) < 0 ) {
if ( errno = = EACCES ) {
printf ( " warning: no search permission for one of the directories in path: %s \n " , fname ) ;
return 1 ;
}
perror ( fname ) ;
return 0 ;
}
if ( S_ISDIR ( buf . st_mode ) ) {
printf ( " %s is not a file \n " , fname ) ;
return 0 ;
}
return 1 ;
}
/** true if fname is a directory */
static int
2017-05-16 08:39:24 -04:00
is_dir ( const char * fname )
2008-04-14 10:48:17 -04:00
{
struct stat buf ;
if ( stat ( fname , & buf ) < 0 ) {
if ( errno = = EACCES ) {
printf ( " warning: no search permission for one of the directories in path: %s \n " , fname ) ;
return 1 ;
}
perror ( fname ) ;
return 0 ;
}
if ( ! ( S_ISDIR ( buf . st_mode ) ) ) {
printf ( " %s is not a directory \n " , fname ) ;
return 0 ;
}
return 1 ;
}
/** get base dir of a fname */
static char *
2008-08-27 07:29:46 -04:00
basedir ( char * fname )
2008-04-14 10:48:17 -04:00
{
2008-08-27 07:29:46 -04:00
char * rev ;
if ( ! fname ) fatal_exit ( " out of memory " ) ;
rev = strrchr ( fname , ' / ' ) ;
2008-04-14 10:48:17 -04:00
if ( ! rev ) return NULL ;
2008-08-27 07:29:46 -04:00
if ( fname = = rev ) return NULL ;
2008-04-14 10:48:17 -04:00
rev [ 0 ] = 0 ;
2008-08-27 07:29:46 -04:00
return fname ;
2008-04-14 10:48:17 -04:00
}
2008-08-13 10:46:33 -04:00
/** check chroot for a file string */
static void
2008-08-13 11:18:39 -04:00
check_chroot_string ( const char * desc , char * * ss ,
2008-08-13 10:46:33 -04:00
const char * chrootdir , struct config_file * cfg )
{
2008-08-13 11:18:39 -04:00
char * str = * ss ;
if ( str & & str [ 0 ] ) {
2008-08-27 07:29:46 -04:00
* ss = fname_after_chroot ( str , cfg , 1 ) ;
if ( ! * ss ) fatal_exit ( " out of memory " ) ;
if ( ! is_file ( * ss ) ) {
2008-12-09 04:28:39 -05:00
if ( chrootdir & & chrootdir [ 0 ] )
fatal_exit ( " %s: \" %s \" does not exist in "
" chrootdir %s " , desc , str , chrootdir ) ;
else
2017-05-16 08:39:24 -04:00
fatal_exit ( " %s: \" %s \" does not exist " ,
2008-12-09 04:28:39 -05:00
desc , str ) ;
2008-08-13 10:46:33 -04:00
}
/* put in a new full path for continued checking */
2008-08-13 11:18:39 -04:00
free ( str ) ;
2008-08-13 10:46:33 -04:00
}
}
2008-01-30 06:21:20 -05:00
/** check file list, every file must be inside the chroot location */
static void
check_chroot_filelist ( const char * desc , struct config_strlist * list ,
2008-04-14 10:48:17 -04:00
const char * chrootdir , struct config_file * cfg )
2008-01-30 06:21:20 -05:00
{
struct config_strlist * p ;
for ( p = list ; p ; p = p - > next ) {
2008-08-13 10:46:33 -04:00
check_chroot_string ( desc , & p - > str , chrootdir , cfg ) ;
2008-01-30 06:21:20 -05:00
}
}
2009-01-07 09:05:09 -05:00
/** check file list, with wildcard processing */
2009-01-07 07:24:34 -05:00
static void
check_chroot_filelist_wild ( const char * desc , struct config_strlist * list ,
const char * chrootdir , struct config_file * cfg )
{
struct config_strlist * p ;
for ( p = list ; p ; p = p - > next ) {
# ifdef HAVE_GLOB
2017-05-16 08:39:24 -04:00
if ( strchr ( p - > str , ' * ' ) | | strchr ( p - > str , ' [ ' ) | |
strchr ( p - > str , ' ? ' ) | | strchr ( p - > str , ' { ' ) | |
2009-01-07 07:24:34 -05:00
strchr ( p - > str , ' ~ ' ) ) {
char * s = p - > str ;
/* adjust whole pattern for chroot and check later */
p - > str = fname_after_chroot ( p - > str , cfg , 1 ) ;
free ( s ) ;
} else
# endif /* HAVE_GLOB */
check_chroot_string ( desc , & p - > str , chrootdir , cfg ) ;
}
}
2017-08-22 03:43:59 -04:00
# ifdef CLIENT_SUBNET
/** check ECS configuration */
static void
ecs_conf_checks ( struct config_file * cfg )
{
struct ecs_whitelist * whitelist = NULL ;
if ( ! ( whitelist = ecs_whitelist_create ( ) ) )
fatal_exit ( " Could not create ednssubnet whitelist: out of memory " ) ;
if ( ! ecs_whitelist_apply_cfg ( whitelist , cfg ) )
fatal_exit ( " Could not setup ednssubnet whitelist " ) ;
ecs_whitelist_delete ( whitelist ) ;
}
# endif /* CLIENT_SUBNET */
2018-08-09 04:33:56 -04:00
/** check that the modules exist, are compiled in */
static void
check_modules_exist ( const char * module_conf )
{
const char * * names = module_list_avail ( ) ;
const char * s = module_conf ;
while ( * s ) {
int i = 0 ;
int is_ok = 0 ;
while ( * s & & isspace ( ( unsigned char ) * s ) )
s + + ;
2018-08-09 05:07:31 -04:00
if ( ! * s ) break ;
2018-08-09 04:33:56 -04:00
while ( names [ i ] ) {
if ( strncmp ( names [ i ] , s , strlen ( names [ i ] ) ) = = 0 ) {
is_ok = 1 ;
break ;
}
i + + ;
}
if ( is_ok = = 0 ) {
char n [ 64 ] ;
size_t j ;
n [ 0 ] = 0 ;
n [ sizeof ( n ) - 1 ] = 0 ;
2018-08-09 04:46:13 -04:00
for ( j = 0 ; j < sizeof ( n ) - 1 ; j + + ) {
2018-08-09 04:33:56 -04:00
if ( ! s [ j ] | | isspace ( ( unsigned char ) s [ j ] ) ) {
n [ j ] = 0 ;
break ;
}
n [ j ] = s [ j ] ;
}
2025-05-05 08:47:12 -04:00
fatal_exit ( " Unknown value in module-config, module: "
" '%s'. This module is not present (not "
" compiled in); see the list of linked modules "
" with unbound -V " , n ) ;
2018-08-09 04:33:56 -04:00
}
s + = strlen ( names [ i ] ) ;
}
}
2008-01-11 06:24:30 -05:00
/** check configuration for errors */
static void
2018-11-29 07:55:13 -05:00
morechecks ( struct config_file * cfg )
2008-01-11 06:24:30 -05:00
{
warn_hosts ( " stub-host " , cfg - > stubs ) ;
warn_hosts ( " forward-host " , cfg - > forwards ) ;
interfacechecks ( cfg ) ;
2022-02-11 04:58:53 -05:00
ifautomaticportschecks ( cfg - > if_automatic_ports ) ;
2008-01-11 06:24:30 -05:00
aclchecks ( cfg ) ;
2018-08-07 07:57:42 -04:00
tcpconnlimitchecks ( cfg ) ;
2007-09-28 10:33:35 -04:00
2007-09-26 09:39:49 -04:00
if ( cfg - > verbosity < 0 )
fatal_exit ( " verbosity value < 0 " ) ;
2011-08-26 02:50:23 -04:00
if ( cfg - > num_threads < = 0 | | cfg - > num_threads > 10000 )
2007-09-26 09:39:49 -04:00
fatal_exit ( " num_threads value weird " ) ;
if ( ! cfg - > do_ip4 & & ! cfg - > do_ip6 )
fatal_exit ( " ip4 and ip6 are both disabled, pointless " ) ;
2020-02-25 03:55:59 -05:00
if ( ! cfg - > do_ip4 & & cfg - > prefer_ip4 )
fatal_exit ( " cannot prefer and disable ip4, pointless " ) ;
2016-07-04 10:49:49 -04:00
if ( ! cfg - > do_ip6 & & cfg - > prefer_ip6 )
fatal_exit ( " cannot prefer and disable ip6, pointless " ) ;
2007-09-26 09:39:49 -04:00
if ( ! cfg - > do_udp & & ! cfg - > do_tcp )
fatal_exit ( " udp and tcp are both disabled, pointless " ) ;
2009-10-29 06:37:44 -04:00
if ( cfg - > edns_buffer_size > cfg - > msg_buffer_size )
fatal_exit ( " edns-buffer-size larger than msg-buffer-size, "
" answers will not fit in processing buffer " ) ;
2015-12-01 04:12:30 -05:00
# ifdef UB_ON_WINDOWS
w_config_adjust_directory ( cfg ) ;
# endif
2017-05-16 08:39:24 -04:00
if ( cfg - > chrootdir & & cfg - > chrootdir [ 0 ] & &
2008-01-30 06:21:20 -05:00
cfg - > chrootdir [ strlen ( cfg - > chrootdir ) - 1 ] = = ' / ' )
fatal_exit ( " chootdir %s has trailing slash '/' please remove. " ,
cfg - > chrootdir ) ;
2017-05-16 08:39:24 -04:00
if ( cfg - > chrootdir & & cfg - > chrootdir [ 0 ] & &
2008-04-14 10:48:17 -04:00
! is_dir ( cfg - > chrootdir ) ) {
fatal_exit ( " bad chroot directory " ) ;
}
2008-08-27 07:29:46 -04:00
if ( cfg - > directory & & cfg - > directory [ 0 ] ) {
char * ad = fname_after_chroot ( cfg - > directory , cfg , 0 ) ;
if ( ! ad ) fatal_exit ( " out of memory " ) ;
if ( ! is_dir ( ad ) ) fatal_exit ( " bad chdir directory " ) ;
free ( ad ) ;
2008-04-14 10:48:17 -04:00
}
if ( ( cfg - > chrootdir & & cfg - > chrootdir [ 0 ] ) | |
( cfg - > directory & & cfg - > directory [ 0 ] ) ) {
2008-08-27 07:29:46 -04:00
if ( cfg - > pidfile & & cfg - > pidfile [ 0 ] ) {
char * ad = ( cfg - > pidfile [ 0 ] = = ' / ' ) ? strdup ( cfg - > pidfile ) :
fname_after_chroot ( cfg - > pidfile , cfg , 1 ) ;
char * bd = basedir ( ad ) ;
if ( bd & & ! is_dir ( bd ) )
fatal_exit ( " pidfile directory does not exist " ) ;
free ( ad ) ;
2008-04-14 10:48:17 -04:00
}
2008-08-27 07:29:46 -04:00
if ( cfg - > logfile & & cfg - > logfile [ 0 ] ) {
char * ad = fname_after_chroot ( cfg - > logfile , cfg , 1 ) ;
char * bd = basedir ( ad ) ;
if ( bd & & ! is_dir ( bd ) )
fatal_exit ( " logfile directory does not exist " ) ;
free ( ad ) ;
2008-04-14 10:48:17 -04:00
}
}
2017-05-16 08:39:24 -04:00
check_chroot_filelist ( " file with root-hints " ,
2008-04-14 10:48:17 -04:00
cfg - > root_hints , cfg - > chrootdir , cfg ) ;
2017-05-16 08:39:24 -04:00
check_chroot_filelist ( " trust-anchor-file " ,
2008-04-14 10:48:17 -04:00
cfg - > trust_anchor_file_list , cfg - > chrootdir , cfg ) ;
2017-05-16 08:39:24 -04:00
check_chroot_filelist ( " auto-trust-anchor-file " ,
2010-01-12 10:49:30 -05:00
cfg - > auto_trust_anchor_file_list , cfg - > chrootdir , cfg ) ;
2017-05-16 08:39:24 -04:00
check_chroot_filelist_wild ( " trusted-keys-file " ,
2008-04-14 10:48:17 -04:00
cfg - > trusted_keys_file_list , cfg - > chrootdir , cfg ) ;
2023-10-04 09:28:52 -04:00
if ( cfg - > disable_edns_do & & strstr ( cfg - > module_conf , " validator " )
& & ( cfg - > trust_anchor_file_list
| | cfg - > trust_anchor_list
| | cfg - > auto_trust_anchor_file_list
| | cfg - > trusted_keys_file_list ) ) {
char * key = NULL ;
if ( cfg - > auto_trust_anchor_file_list )
key = cfg - > auto_trust_anchor_file_list - > str ;
if ( ! key & & cfg - > trust_anchor_file_list )
key = cfg - > trust_anchor_file_list - > str ;
if ( ! key & & cfg - > trust_anchor_list )
key = cfg - > trust_anchor_list - > str ;
if ( ! key & & cfg - > trusted_keys_file_list )
key = cfg - > trusted_keys_file_list - > str ;
if ( ! key ) key = " " ;
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 ) ;
}
2017-05-16 08:39:24 -04:00
# ifdef USE_IPSECMOD
2017-07-03 03:14:37 -04:00
if ( cfg - > ipsecmod_enabled & & strstr ( cfg - > module_conf , " ipsecmod " ) ) {
/* only check hook if enabled */
check_chroot_string ( " ipsecmod-hook " , & cfg - > ipsecmod_hook ,
cfg - > chrootdir , cfg ) ;
}
2017-05-16 08:39:24 -04:00
# endif
2023-05-01 12:23:13 -04:00
/* remove chroot setting so that modules are not stripping pathnames */
2008-04-14 10:48:17 -04:00
free ( cfg - > chrootdir ) ;
cfg - > chrootdir = NULL ;
2017-03-07 09:58:51 -05:00
2018-08-09 04:33:56 -04:00
/* check that the modules listed in module_conf exist */
check_modules_exist ( cfg - > module_conf ) ;
2017-05-16 08:39:24 -04:00
if ( strcmp ( cfg - > module_conf , " iterator " ) ! = 0
2009-04-02 10:44:57 -04:00
& & strcmp ( cfg - > module_conf , " validator iterator " ) ! = 0
2014-10-10 03:07:58 -04:00
& & strcmp ( cfg - > module_conf , " dns64 validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 iterator " ) ! = 0
2017-03-07 09:58:51 -05:00
& & strcmp ( cfg - > module_conf , " respip iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " respip validator iterator " ) ! = 0
2022-01-05 10:14:47 -05:00
& & strcmp ( cfg - > module_conf , " respip dns64 validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " respip dns64 iterator " ) ! = 0
2009-04-02 10:44:57 -04:00
# ifdef WITH_PYTHONMODULE
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " python iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " python respip iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " python validator iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " python respip validator iterator " ) ! = 0
2009-04-02 10:44:57 -04:00
& & strcmp ( cfg - > module_conf , " validator python iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " dns64 python iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 python validator iterator " ) ! = 0
2014-10-10 03:07:58 -04:00
& & strcmp ( cfg - > module_conf , " dns64 validator python iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " python dns64 iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " python dns64 validator iterator " ) ! = 0
2016-04-14 10:50:18 -04:00
# endif
2020-05-18 04:11:16 -04:00
# ifdef WITH_DYNLIBMODULE
& & strcmp ( cfg - > module_conf , " dynlib iterator " ) ! = 0
2020-05-18 04:16:40 -04:00
& & strcmp ( cfg - > module_conf , " dynlib dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib dynlib dynlib iterator " ) ! = 0
2020-05-18 04:18:28 -04:00
& & strcmp ( cfg - > module_conf , " python dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " python dynlib dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " python dynlib dynlib dynlib iterator " ) ! = 0
2020-05-18 04:11:16 -04:00
& & strcmp ( cfg - > module_conf , " dynlib respip iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib validator iterator " ) ! = 0
2020-05-18 04:16:40 -04:00
& & strcmp ( cfg - > module_conf , " dynlib dynlib validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib dynlib dynlib validator iterator " ) ! = 0
2020-05-18 04:18:28 -04:00
& & strcmp ( cfg - > module_conf , " python dynlib validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " python dynlib dynlib validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " python dynlib dynlib dynlib validator iterator " ) ! = 0
2020-05-18 04:11:16 -04:00
& & strcmp ( cfg - > module_conf , " dynlib respip validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " validator dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 dynlib validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 validator dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib dns64 iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib dns64 validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib dns64 cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib dns64 validator cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 dynlib cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 dynlib validator cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib respip cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib validator cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib respip validator cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " cachedb dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " respip cachedb dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " validator cachedb dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " respip validator cachedb dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " validator dynlib cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " respip validator dynlib cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib subnetcache iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib respip subnetcache iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " subnetcache dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " respip subnetcache dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib subnetcache validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib respip subnetcache validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " subnetcache dynlib validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " respip subnetcache dynlib validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " subnetcache validator dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " respip subnetcache validator dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib ipsecmod iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib ipsecmod respip iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod dynlib respip iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod respip validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib ipsecmod validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dynlib ipsecmod respip validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod dynlib validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod dynlib respip validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod validator dynlib iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod respip validator dynlib iterator " ) ! = 0
# endif
2016-04-14 10:50:18 -04:00
# ifdef USE_CACHEDB
& & strcmp ( cfg - > module_conf , " validator cachedb iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " respip validator cachedb iterator " ) ! = 0
2016-04-14 10:50:18 -04:00
& & strcmp ( cfg - > module_conf , " cachedb iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " respip cachedb iterator " ) ! = 0
2016-04-14 10:50:18 -04:00
& & strcmp ( cfg - > module_conf , " dns64 validator cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 cachedb iterator " ) ! = 0
2025-09-29 10:11:50 -04:00
& & strcmp ( cfg - > module_conf , " respip dns64 validator cachedb iterator " ) ! = 0
2017-03-21 08:08:17 -04:00
# endif
# if defined(WITH_PYTHONMODULE) && defined(USE_CACHEDB)
2016-04-14 10:50:18 -04:00
& & strcmp ( cfg - > module_conf , " python dns64 cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " python dns64 validator cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 python cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 python validator cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " python cachedb iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " python respip cachedb iterator " ) ! = 0
2016-04-14 10:50:18 -04:00
& & strcmp ( cfg - > module_conf , " python validator cachedb iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " python respip validator cachedb iterator " ) ! = 0
2016-04-14 10:50:18 -04:00
& & strcmp ( cfg - > module_conf , " cachedb python iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " respip cachedb python iterator " ) ! = 0
2016-04-14 10:50:18 -04:00
& & strcmp ( cfg - > module_conf , " validator cachedb python iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " respip validator cachedb python iterator " ) ! = 0
2016-04-14 10:50:18 -04:00
& & strcmp ( cfg - > module_conf , " validator python cachedb iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " respip validator python cachedb iterator " ) ! = 0
2017-03-21 08:08:17 -04:00
# endif
2022-01-14 10:30:25 -05:00
# if defined(CLIENT_SUBNET) && defined(USE_CACHEDB)
& & strcmp ( cfg - > module_conf , " respip subnetcache validator cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " subnetcache validator cachedb iterator " ) ! = 0
# endif
2017-03-21 08:08:17 -04:00
# ifdef CLIENT_SUBNET
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " subnetcache iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " respip subnetcache iterator " ) ! = 0
2017-03-21 08:08:17 -04:00
& & strcmp ( cfg - > module_conf , " subnetcache validator iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " respip subnetcache validator iterator " ) ! = 0
2017-09-12 01:43:46 -04:00
& & strcmp ( cfg - > module_conf , " dns64 subnetcache iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 subnetcache validator iterator " ) ! = 0
2020-03-16 04:44:38 -04:00
& & strcmp ( cfg - > module_conf , " dns64 subnetcache respip iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 subnetcache respip validator iterator " ) ! = 0
2017-03-21 08:08:17 -04:00
# endif
# if defined(WITH_PYTHONMODULE) && defined(CLIENT_SUBNET)
& & strcmp ( cfg - > module_conf , " python subnetcache iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " python respip subnetcache iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " subnetcache python iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " respip subnetcache python iterator " ) ! = 0
2017-03-21 08:08:17 -04:00
& & strcmp ( cfg - > module_conf , " python subnetcache validator iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " python respip subnetcache validator iterator " ) ! = 0
2017-03-21 08:08:17 -04:00
& & strcmp ( cfg - > module_conf , " subnetcache python validator iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " respip subnetcache python validator iterator " ) ! = 0
2017-03-21 08:08:17 -04:00
& & strcmp ( cfg - > module_conf , " subnetcache validator python iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " respip subnetcache validator python iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
# endif
# ifdef USE_IPSECMOD
& & strcmp ( cfg - > module_conf , " ipsecmod iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " ipsecmod respip iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " ipsecmod validator iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " ipsecmod respip validator iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
# endif
# if defined(WITH_PYTHONMODULE) && defined(USE_IPSECMOD)
& & strcmp ( cfg - > module_conf , " python ipsecmod iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " python ipsecmod respip iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " ipsecmod python iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " ipsecmod python respip iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " ipsecmod validator iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " ipsecmod respip validator iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " python ipsecmod validator iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " python ipsecmod respip validator iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " ipsecmod python validator iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " ipsecmod python respip validator iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " ipsecmod validator python iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " ipsecmod respip validator python iterator " ) ! = 0
2019-05-02 07:43:30 -04:00
# endif
# ifdef USE_IPSET
& & strcmp ( cfg - > module_conf , " validator ipset iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " validator ipset respip iterator " ) ! = 0
2019-05-02 07:43:30 -04:00
& & strcmp ( cfg - > module_conf , " ipset iterator " ) ! = 0
2020-02-17 07:36:30 -05:00
& & strcmp ( cfg - > module_conf , " ipset respip iterator " ) ! = 0
2009-04-02 10:44:57 -04:00
# endif
) {
2007-11-22 04:30:44 -05:00
fatal_exit ( " module conf '%s' is not known to work " ,
2007-09-26 09:39:49 -04:00
cfg - > module_conf ) ;
}
2008-05-23 10:13:07 -04:00
# ifdef HAVE_GETPWNAM
2007-09-26 09:39:49 -04:00
if ( cfg - > username & & cfg - > username [ 0 ] ) {
2007-12-04 12:54:14 -05:00
if ( getpwnam ( cfg - > username ) = = NULL )
2007-09-26 09:39:49 -04:00
fatal_exit ( " user '%s' does not exist. " , cfg - > username ) ;
2016-06-27 04:00:55 -04:00
# ifdef HAVE_ENDPWENT
2007-09-26 09:39:49 -04:00
endpwent ( ) ;
2016-06-27 04:00:55 -04:00
# endif
2007-09-26 09:39:49 -04:00
}
2008-05-23 10:13:07 -04:00
# endif
2018-06-18 08:15:21 -04:00
if ( cfg - > remote_control_enable & & options_remote_is_address ( cfg )
& & cfg - > control_use_cert ) {
2008-12-09 04:28:39 -05:00
check_chroot_string ( " server-key-file " , & cfg - > server_key_file ,
cfg - > chrootdir , cfg ) ;
check_chroot_string ( " server-cert-file " , & cfg - > server_cert_file ,
cfg - > chrootdir , cfg ) ;
if ( ! is_file ( cfg - > control_key_file ) )
fatal_exit ( " control-key-file: \" %s \" does not exist " ,
cfg - > control_key_file ) ;
if ( ! is_file ( cfg - > control_cert_file ) )
fatal_exit ( " control-cert-file: \" %s \" does not exist " ,
cfg - > control_cert_file ) ;
}
2025-06-16 06:43:31 -04:00
if ( cfg - > remote_control_enable )
controlinterfacechecks ( cfg ) ;
2007-11-22 04:30:44 -05:00
2019-06-25 08:50:49 -04:00
donotquerylocalhostcheck ( cfg ) ;
2008-01-11 06:24:30 -05:00
localzonechecks ( cfg ) ;
2017-03-07 09:58:51 -05:00
view_and_respipchecks ( cfg ) ;
2017-08-22 03:43:59 -04:00
# ifdef CLIENT_SUBNET
ecs_conf_checks ( cfg ) ;
# endif
2007-09-26 09:39:49 -04:00
}
2009-03-12 05:36:28 -04:00
/** check forwards */
static void
check_fwd ( struct config_file * cfg )
{
struct iter_forwards * fwd = forwards_create ( ) ;
if ( ! fwd | | ! forwards_apply_cfg ( fwd , cfg ) ) {
fatal_exit ( " Could not set forward zones " ) ;
}
forwards_delete ( fwd ) ;
}
2012-02-16 04:55:50 -05:00
/** check hints */
static void
check_hints ( struct config_file * cfg )
{
struct iter_hints * hints = hints_create ( ) ;
if ( ! hints | | ! hints_apply_cfg ( hints , cfg ) ) {
2012-02-16 04:58:49 -05:00
fatal_exit ( " Could not set root or stub hints " ) ;
2012-02-16 04:55:50 -05:00
}
hints_delete ( hints ) ;
}
2017-10-17 11:16:31 -04:00
/** check auth zones */
static void
check_auth ( struct config_file * cfg )
{
2019-08-16 06:13:30 -04:00
int is_rpz = 0 ;
2017-10-17 11:16:31 -04:00
struct auth_zones * az = auth_zones_create ( ) ;
2020-10-22 06:10:46 -04:00
if ( ! az | | ! auth_zones_apply_cfg ( az , cfg , 0 , & is_rpz , NULL , NULL ) ) {
2017-10-17 11:16:31 -04:00
fatal_exit ( " Could not setup authority zones " ) ;
}
2025-05-20 10:21:02 -04:00
if ( is_rpz & & ! strstr ( cfg - > module_conf , " respip " ) )
fatal_exit ( " RPZ requires the respip module " ) ;
2017-10-17 11:16:31 -04:00
auth_zones_delete ( az ) ;
}
2007-09-26 09:39:49 -04:00
/** check config file */
static void
2024-04-26 08:50:39 -04:00
checkconf ( const char * cfgfile , const char * opt , int final , int quiet )
2007-09-26 09:39:49 -04:00
{
2016-09-29 03:00:31 -04:00
char oldwd [ 4096 ] ;
2007-09-26 09:39:49 -04:00
struct config_file * cfg = config_create ( ) ;
if ( ! cfg )
fatal_exit ( " out of memory " ) ;
2016-06-13 09:33:51 -04:00
oldwd [ 0 ] = 0 ;
if ( ! getcwd ( oldwd , sizeof ( oldwd ) ) ) {
log_err ( " cannot getcwd: %s " , strerror ( errno ) ) ;
oldwd [ 0 ] = 0 ;
}
2009-01-06 10:47:15 -05:00
if ( ! config_read ( cfg , cfgfile , NULL ) ) {
2007-09-26 09:39:49 -04:00
/* config_read prints messages to stderr */
config_delete ( cfg ) ;
exit ( 1 ) ;
}
2016-06-13 09:33:51 -04:00
if ( oldwd [ 0 ] & & chdir ( oldwd ) = = - 1 )
log_err ( " cannot chdir(%s): %s " , oldwd , strerror ( errno ) ) ;
2014-08-18 03:21:01 -04:00
if ( opt ) {
2015-01-16 09:31:02 -05:00
print_option ( cfg , opt , final ) ;
2014-08-18 03:21:01 -04:00
config_delete ( cfg ) ;
return ;
}
2018-11-29 07:55:13 -05:00
morechecks ( cfg ) ;
2007-09-26 09:39:49 -04:00
check_mod ( cfg , iter_get_funcblock ( ) ) ;
check_mod ( cfg , val_get_funcblock ( ) ) ;
2009-03-25 10:47:47 -04:00
# ifdef WITH_PYTHONMODULE
2009-03-30 08:32:54 -04:00
if ( strstr ( cfg - > module_conf , " python " ) )
check_mod ( cfg , pythonmod_get_funcblock ( ) ) ;
2009-03-25 10:47:47 -04:00
# endif
2009-03-12 05:36:28 -04:00
check_fwd ( cfg ) ;
2012-02-16 04:55:50 -05:00
check_hints ( cfg ) ;
2017-10-17 11:16:31 -04:00
check_auth ( cfg ) ;
2024-04-26 08:50:39 -04:00
if ( ! quiet ) { printf ( " unbound-checkconf: no errors in %s \n " , cfgfile ) ; }
2007-09-26 09:39:49 -04:00
config_delete ( cfg ) ;
}
/** getopt global, in case header files fail to declare it. */
extern int optind ;
/** getopt global, in case header files fail to declare it. */
extern char * optarg ;
/** Main routine for checkconf */
int main ( int argc , char * argv [ ] )
{
int c ;
2015-01-16 09:31:02 -05:00
int final = 0 ;
2024-04-26 08:50:39 -04:00
int quiet = 0 ;
2008-11-04 09:53:50 -05:00
const char * f ;
2009-02-06 10:15:15 -05:00
const char * opt = NULL ;
2012-02-27 08:20:29 -05:00
const char * cfgfile = CONFIGFILE ;
2021-09-10 09:11:30 -04:00
checklock_start ( ) ;
2007-09-26 09:39:49 -04:00
log_ident_set ( " unbound-checkconf " ) ;
2007-10-31 06:56:31 -04:00
log_init ( NULL , 0 , NULL ) ;
2012-02-27 08:20:29 -05:00
# ifdef USE_WINSOCK
/* use registry config file in preference to compiletime location */
if ( ! ( cfgfile = w_lookup_reg_str ( " Software \\ Unbound " , " ConfigFile " ) ) )
cfgfile = CONFIGFILE ;
# endif /* USE_WINSOCK */
2007-09-26 09:39:49 -04:00
/* parse the options */
2024-04-26 08:50:39 -04:00
while ( ( c = getopt ( argc , argv , " fhqo: " ) ) ! = - 1 ) {
2007-09-26 09:39:49 -04:00
switch ( c ) {
2015-01-16 09:31:02 -05:00
case ' f ' :
final = 1 ;
break ;
2009-02-06 10:15:15 -05:00
case ' o ' :
opt = optarg ;
break ;
2024-04-26 08:50:39 -04:00
case ' q ' :
quiet = 1 ;
break ;
2007-09-26 09:39:49 -04:00
case ' ? ' :
case ' h ' :
default :
usage ( ) ;
}
}
argc - = optind ;
argv + = optind ;
2007-11-09 08:52:13 -05:00
if ( argc ! = 0 & & argc ! = 1 )
2007-09-26 09:39:49 -04:00
usage ( ) ;
2007-11-09 08:52:13 -05:00
if ( argc = = 1 )
f = argv [ 0 ] ;
2012-02-27 08:20:29 -05:00
else f = cfgfile ;
2024-04-26 08:50:39 -04:00
checkconf ( f , opt , final , quiet ) ;
2007-10-31 10:46:05 -04:00
checklock_stop ( ) ;
2007-09-26 09:39:49 -04:00
return 0 ;
}