2007-09-26 09:39:49 -04:00
/*
* checkconf / unbound - checkconf . c - config file checker for unbound . conf file .
*
* 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"
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"
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 " ) ;
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 " ) ;
2007-09-26 09:39:49 -04:00
if ( ! ( * fb - > init ) ( & env , 0 ) ) {
fatal_exit ( " bad config for %s module " , fb - > name ) ;
}
( * fb - > deinit ) ( & 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 ) ;
}
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 ;
int ignored = 0 ;
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 " ) ;
2017-04-18 05:00:52 -04:00
if ( ! respip_views_apply_cfg ( views , cfg , & ignored ) )
2017-03-07 09:58:51 -05:00
fatal_exit ( " Could not setup per-view respip sets " ) ;
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 ) {
if ( extstrtoaddr ( h - > str , & a , & alen ) ) {
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 ;
int i , j ;
2007-09-28 10:33:35 -04:00
for ( i = 0 ; i < cfg - > num_ifs ; i + + ) {
2010-03-22 05:38:06 -04:00
if ( ! extstrtoaddr ( cfg - > ifs [ i ] , & a , & alen ) ) {
2007-09-28 10:33:35 -04:00
fatal_exit ( " cannot parse interface specified as '%s' " ,
cfg - > ifs [ i ] ) ;
}
2008-01-11 06:24:30 -05:00
for ( j = 0 ; j < cfg - > num_ifs ; j + + ) {
if ( i ! = j & & strcmp ( cfg - > ifs [ i ] , cfg - > ifs [ j ] ) = = 0 )
fatal_exit ( " interface: %s present twice, "
" cannot bind same ports twice. " ,
cfg - > ifs [ i ] ) ;
}
2007-09-28 10:33:35 -04:00
}
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
}
/** 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 ] ;
}
fatal_exit ( " module_conf lists module '%s' but that "
" module is not available. " , n ) ;
}
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 ) ;
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 " ) ;
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 ) ;
2017-05-16 08:39:24 -04:00
check_chroot_string ( " dlv-anchor-file " , & cfg - > dlv_anchor_file ,
2008-08-13 10:46:33 -04:00
cfg - > chrootdir , cfg ) ;
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
2008-04-14 10:48:17 -04:00
/* remove chroot setting so that modules are not stripping pathnames*/
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-03-07 09:58:51 -05:00
/* There should be no reason for 'respip' module not to work with
* dns64 , but it ' s not explicitly confirmed , so the combination is
* excluded below . It ' s simply unknown yet for the combination of
* respip and other modules . */
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
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
& & strcmp ( cfg - > module_conf , " python 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
# ifdef USE_CACHEDB
& & strcmp ( cfg - > module_conf , " validator cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 validator cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " dns64 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
& & strcmp ( cfg - > module_conf , " python validator cachedb iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " cachedb python iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " validator cachedb python iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " validator python cachedb iterator " ) ! = 0
2017-03-21 08:08:17 -04:00
# endif
# ifdef CLIENT_SUBNET
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " subnetcache iterator " ) ! = 0
2017-03-21 08:08:17 -04:00
& & strcmp ( cfg - > module_conf , " 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
2017-03-21 08:08:17 -04:00
# endif
# if defined(WITH_PYTHONMODULE) && defined(CLIENT_SUBNET)
& & strcmp ( cfg - > module_conf , " python subnetcache iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
& & strcmp ( cfg - > module_conf , " subnetcache python iterator " ) ! = 0
2017-03-21 08:08:17 -04:00
& & strcmp ( cfg - > module_conf , " python subnetcache validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " subnetcache python validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " subnetcache validator python iterator " ) ! = 0
2017-05-16 08:39:24 -04:00
# endif
# ifdef USE_IPSECMOD
& & strcmp ( cfg - > module_conf , " ipsecmod iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod validator iterator " ) ! = 0
# endif
# if defined(WITH_PYTHONMODULE) && defined(USE_IPSECMOD)
& & strcmp ( cfg - > module_conf , " python ipsecmod iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod python iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " python ipsecmod validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod python validator iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipsecmod validator python iterator " ) ! = 0
2019-05-02 07:43:30 -04:00
# endif
# ifdef USE_IPSET
& & strcmp ( cfg - > module_conf , " validator ipset iterator " ) ! = 0
& & strcmp ( cfg - > module_conf , " ipset 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 ) ;
}
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 ( ) ;
2019-07-16 12:43:16 -04:00
if ( ! az | | ! auth_zones_apply_cfg ( az , cfg , 0 i , & is_rpz ) ) {
2017-10-17 11:16:31 -04:00
fatal_exit ( " Could not setup authority zones " ) ;
}
auth_zones_delete ( az ) ;
}
2007-09-26 09:39:49 -04:00
/** check config file */
static void
2015-01-16 09:31:02 -05:00
checkconf ( const char * cfgfile , const char * opt , int final )
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 ) ;
2014-08-18 03:21:01 -04:00
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 ;
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 ;
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 ) ;
2007-10-31 10:46:05 -04:00
checklock_start ( ) ;
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 */
2015-01-16 09:31:02 -05:00
while ( ( c = getopt ( argc , argv , " fho: " ) ) ! = - 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 ;
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 ;
2015-01-16 09:31:02 -05:00
checkconf ( f , opt , final ) ;
2007-10-31 10:46:05 -04:00
checklock_stop ( ) ;
2007-09-26 09:39:49 -04:00
return 0 ;
}