2008-09-10 15:23:01 +00:00
/*
* daemon / remote . c - remote control for the unbound daemon .
*
* Copyright ( c ) 2008 , NLnet Labs . All rights reserved .
*
* This software is open source .
2023-04-20 15:39:55 +00:00
*
2008-09-10 15:23:01 +00:00
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
2023-04-20 15:39:55 +00:00
*
2008-09-10 15:23:01 +00:00
* Redistributions of source code must retain the above copyright notice ,
* this list of conditions and the following disclaimer .
2023-04-20 15:39:55 +00:00
*
2008-09-10 15:23:01 +00: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 .
2023-04-20 15:39:55 +00:00
*
2008-09-10 15:23:01 +00: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 .
2023-04-20 15:39:55 +00:00
*
2008-09-10 15:23:01 +00:00
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2014-02-07 13:28:39 +00: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 .
2008-09-10 15:23:01 +00:00
*/
/**
* \ file
*
* This file contains the remote control functionality for the daemon .
* The remote control can be performed using either the commandline
2023-04-20 15:39:55 +00:00
* unbound - control tool , or a TLS capable web browser .
2014-10-27 09:54:44 +00:00
* The channel is secured using TLSv1 , and certificates .
2008-09-10 15:23:01 +00:00
* Both the server and the client ( control tool ) have their own keys .
*/
# include "config.h"
2010-03-12 15:17:48 +00:00
# ifdef HAVE_OPENSSL_ERR_H
# include <openssl/err.h>
# endif
2016-09-02 09:59:09 +00:00
# ifdef HAVE_OPENSSL_DH_H
2015-01-06 14:12:59 +00:00
# include <openssl/dh.h>
# endif
2016-09-02 09:59:09 +00:00
# ifdef HAVE_OPENSSL_BN_H
# include <openssl/bn.h>
# endif
2015-01-06 14:12:59 +00:00
2010-03-12 15:17:48 +00:00
# include <ctype.h>
2008-09-10 15:23:01 +00:00
# include "daemon/remote.h"
# include "daemon/worker.h"
2008-09-11 14:14:12 +00:00
# include "daemon/daemon.h"
2008-09-15 14:19:41 +00:00
# include "daemon/stats.h"
2008-09-22 15:20:18 +00:00
# include "daemon/cachedump.h"
2008-09-10 15:23:01 +00:00
# include "util/log.h"
# include "util/config_file.h"
# include "util/net_help.h"
2008-09-16 14:08:38 +00:00
# include "util/module.h"
2008-09-10 15:23:01 +00:00
# include "services/listen_dnsport.h"
2008-09-16 14:08:38 +00:00
# include "services/cache/rrset.h"
2010-10-26 09:08:33 +00:00
# include "services/cache/infra.h"
2008-09-16 14:08:38 +00:00
# include "services/mesh.h"
2008-09-19 14:49:29 +00:00
# include "services/localzone.h"
2018-04-23 14:42:30 +00:00
# include "services/authzone.h"
2019-06-03 13:46:39 +00:00
# include "services/rpz.h"
2008-09-16 14:08:38 +00:00
# include "util/storage/slabhash.h"
# include "util/fptr_wlist.h"
2008-09-19 14:49:29 +00:00
# include "util/data/dname.h"
2008-09-23 14:07:02 +00:00
# include "validator/validator.h"
# include "validator/val_kcache.h"
# include "validator/val_kentry.h"
2012-02-15 14:35:28 +00:00
# include "validator/val_anchor.h"
2009-02-10 15:11:54 +00:00
# include "iterator/iterator.h"
2009-02-13 15:26:37 +00:00
# include "iterator/iter_fwd.h"
2010-02-26 15:40:46 +00:00
# include "iterator/iter_hints.h"
2009-02-13 15:26:37 +00:00
# include "iterator/iter_delegpt.h"
2009-02-10 15:11:54 +00:00
# include "services/outbound_list.h"
# include "services/outside_network.h"
2015-03-26 10:21:38 +00:00
# include "sldns/str2wire.h"
# include "sldns/parseutil.h"
# include "sldns/wire2str.h"
# include "sldns/sbuffer.h"
2023-04-18 13:50:12 +00:00
# include "util/timeval_func.h"
2008-09-10 15:23:01 +00:00
# ifdef HAVE_SYS_TYPES_H
# include <sys / types.h>
# endif
2015-01-06 14:12:59 +00:00
# ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
# endif
2008-09-10 15:23:01 +00:00
# ifdef HAVE_NETDB_H
# include <netdb.h>
# endif
2008-09-16 14:08:38 +00:00
/* just for portability */
# ifdef SQ
# undef SQ
# endif
/** what to put on statistics lines between var and value, ": " or "=" */
# define SQ "="
2018-06-12 07:43:52 +00:00
static int
remote_setup_ctx ( struct daemon_remote * rc , struct config_file * cfg )
2008-09-10 15:23:01 +00:00
{
2008-09-11 14:14:12 +00:00
char * s_cert ;
char * s_key ;
rc - > ctx = SSL_CTX_new ( SSLv23_server_method ( ) ) ;
if ( ! rc - > ctx ) {
log_crypto_err ( " could not SSL_CTX_new " ) ;
2018-06-12 07:43:52 +00:00
return 0 ;
2008-09-11 14:14:12 +00:00
}
2017-06-29 11:45:43 +00:00
if ( ! listen_sslctx_setup ( rc - > ctx ) ) {
2018-06-12 07:43:52 +00:00
return 0 ;
2008-09-11 14:14:12 +00:00
}
2015-01-06 14:12:59 +00:00
2009-06-11 09:43:23 +00:00
s_cert = fname_after_chroot ( cfg - > server_cert_file , cfg , 1 ) ;
s_key = fname_after_chroot ( cfg - > server_key_file , cfg , 1 ) ;
if ( ! s_cert | | ! s_key ) {
log_err ( " out of memory in remote control fname " ) ;
2009-07-06 09:34:47 +00:00
goto setup_error ;
2008-09-11 14:14:12 +00:00
}
verbose ( VERB_ALGO , " setup SSL certificates " ) ;
2015-07-18 12:34:37 +00:00
if ( ! SSL_CTX_use_certificate_chain_file ( rc - > ctx , s_cert ) ) {
2009-02-03 09:55:35 +00:00
log_err ( " Error for server-cert-file: %s " , s_cert ) ;
2015-07-18 12:34:37 +00:00
log_crypto_err ( " Error in SSL_CTX use_certificate_chain_file " ) ;
2009-07-06 09:34:47 +00:00
goto setup_error ;
2009-02-03 09:55:35 +00:00
}
if ( ! SSL_CTX_use_PrivateKey_file ( rc - > ctx , s_key , SSL_FILETYPE_PEM ) ) {
log_err ( " Error for server-key-file: %s " , s_key ) ;
log_crypto_err ( " Error in SSL_CTX use_PrivateKey_file " ) ;
2009-07-06 09:34:47 +00:00
goto setup_error ;
2009-02-03 09:55:35 +00:00
}
if ( ! SSL_CTX_check_private_key ( rc - > ctx ) ) {
log_err ( " Error for server-key-file: %s " , s_key ) ;
log_crypto_err ( " Error in SSL_CTX check_private_key " ) ;
2009-07-06 09:34:47 +00:00
goto setup_error ;
2008-09-11 14:14:12 +00:00
}
2017-06-29 11:45:43 +00:00
listen_sslctx_setup_2 ( rc - > ctx ) ;
2008-09-11 14:14:12 +00:00
if ( ! SSL_CTX_load_verify_locations ( rc - > ctx , s_cert , NULL ) ) {
log_crypto_err ( " Error setting up SSL_CTX verify locations " ) ;
2009-07-06 09:34:47 +00:00
setup_error :
2009-06-11 09:43:23 +00:00
free ( s_cert ) ;
free ( s_key ) ;
2018-06-12 07:43:52 +00:00
return 0 ;
2008-09-11 14:14:12 +00:00
}
SSL_CTX_set_client_CA_list ( rc - > ctx , SSL_load_client_CA_file ( s_cert ) ) ;
SSL_CTX_set_verify ( rc - > ctx , SSL_VERIFY_PEER , NULL ) ;
2009-06-11 09:43:23 +00:00
free ( s_cert ) ;
free ( s_key ) ;
2018-06-12 07:43:52 +00:00
return 1 ;
}
struct daemon_remote *
daemon_remote_create ( struct config_file * cfg )
{
2023-04-20 15:39:55 +00:00
struct daemon_remote * rc = ( struct daemon_remote * ) calloc ( 1 ,
2018-06-12 07:43:52 +00:00
sizeof ( * rc ) ) ;
if ( ! rc ) {
log_err ( " out of memory in daemon_remote_create " ) ;
return NULL ;
}
rc - > max_active = 10 ;
2008-09-11 14:14:12 +00:00
2018-06-12 07:43:52 +00:00
if ( ! cfg - > remote_control_enable ) {
rc - > ctx = NULL ;
return rc ;
}
2018-06-18 09:04:35 +00:00
if ( options_remote_is_address ( cfg ) & & cfg - > control_use_cert ) {
2018-06-12 07:43:52 +00:00
if ( ! remote_setup_ctx ( rc , cfg ) ) {
daemon_remote_delete ( rc ) ;
return NULL ;
}
rc - > use_cert = 1 ;
} else {
2018-06-14 08:14:43 +00:00
struct config_strlist * p ;
2018-06-12 07:43:52 +00:00
rc - > ctx = NULL ;
rc - > use_cert = 0 ;
2018-06-18 09:04:35 +00:00
if ( ! options_remote_is_address ( cfg ) )
for ( p = cfg - > control_ifs . first ; p ; p = p - > next ) {
2018-06-14 08:14:43 +00:00
if ( p - > str & & p - > str [ 0 ] ! = ' / ' )
log_warn ( " control-interface %s is not using TLS, but plain transfer, because first control-interface in config file is a local socket (starts with a /). " , p - > str ) ;
}
2018-06-12 07:43:52 +00:00
}
2008-09-10 15:23:01 +00:00
return rc ;
}
2009-06-11 09:43:23 +00:00
void daemon_remote_clear ( struct daemon_remote * rc )
2008-09-10 15:23:01 +00:00
{
struct rc_state * p , * np ;
if ( ! rc ) return ;
/* but do not close the ports */
listen_list_delete ( rc - > accept_list ) ;
2009-06-11 09:43:23 +00:00
rc - > accept_list = NULL ;
2008-09-10 15:23:01 +00:00
/* do close these sockets */
p = rc - > busy_list ;
while ( p ) {
np = p - > next ;
if ( p - > ssl )
SSL_free ( p - > ssl ) ;
comm_point_delete ( p - > c ) ;
free ( p ) ;
p = np ;
}
2009-06-11 09:43:23 +00:00
rc - > busy_list = NULL ;
rc - > active = 0 ;
rc - > worker = NULL ;
}
void daemon_remote_delete ( struct daemon_remote * rc )
{
if ( ! rc ) return ;
daemon_remote_clear ( rc ) ;
2008-09-11 14:56:46 +00:00
if ( rc - > ctx ) {
SSL_CTX_free ( rc - > ctx ) ;
}
2008-09-10 15:23:01 +00:00
free ( rc ) ;
}
/**
* Add and open a new control port
* @ param ip : ip str
* @ param nr : port nr
* @ param list : list head
* @ param noproto_is_err : if lack of protocol support is an error .
2015-01-06 14:41:04 +00:00
* @ param cfg : config with username for chown of unix - sockets .
2008-09-10 15:23:01 +00:00
* @ return false on failure .
*/
static int
2015-01-06 14:12:59 +00:00
add_open ( const char * ip , int nr , struct listen_port * * list , int noproto_is_err ,
struct config_file * cfg )
2008-09-10 15:23:01 +00:00
{
struct addrinfo hints ;
struct addrinfo * res ;
struct listen_port * n ;
2018-09-11 14:11:50 +00:00
int noproto = 0 ;
2008-09-10 15:23:01 +00:00
int fd , r ;
char port [ 15 ] ;
snprintf ( port , sizeof ( port ) , " %d " , nr ) ;
port [ sizeof ( port ) - 1 ] = 0 ;
memset ( & hints , 0 , sizeof ( hints ) ) ;
2018-09-11 14:11:50 +00:00
log_assert ( ip ) ;
2015-01-06 14:12:59 +00:00
if ( ip [ 0 ] = = ' / ' ) {
/* This looks like a local socket */
2017-01-03 13:43:29 +00:00
fd = create_local_accept_sock ( ip , & noproto , cfg - > use_systemd ) ;
2015-01-06 14:12:59 +00:00
/*
* Change socket ownership and permissions so users other
* than root can access it provided they are in the same
* group as the user we run as .
*/
if ( fd ! = - 1 ) {
2015-01-23 15:23:58 +00:00
# ifdef HAVE_CHOWN
2022-01-07 11:01:28 +00:00
chmod ( ip , ( mode_t ) ( S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP ) ) ;
2015-03-23 20:20:15 +00:00
if ( cfg - > username & & cfg - > username [ 0 ] & &
2016-06-03 07:38:53 +00:00
cfg_uid ! = ( uid_t ) - 1 ) {
if ( chown ( ip , cfg_uid , cfg_gid ) = = - 1 )
2017-07-05 06:59:45 +00:00
verbose ( VERB_QUERY , " cannot chown %u.%u %s: %s " ,
2016-06-03 07:38:53 +00:00
( unsigned ) cfg_uid , ( unsigned ) cfg_gid ,
ip , strerror ( errno ) ) ;
}
2015-01-23 15:23:58 +00:00
# else
( void ) cfg ;
# endif
2008-10-21 13:00:07 +00:00
}
2015-01-06 14:12:59 +00:00
} else {
hints . ai_socktype = SOCK_STREAM ;
hints . ai_flags = AI_PASSIVE | AI_NUMERICHOST ;
if ( ( r = getaddrinfo ( ip , port , & hints , & res ) ) ! = 0 | | ! res ) {
# ifdef USE_WINSOCK
if ( ! noproto_is_err & & r = = EAI_NONAME ) {
/* tried to lookup the address as name */
return 1 ; /* return success, but do nothing */
}
2008-10-21 13:00:07 +00:00
# endif /* USE_WINSOCK */
2015-01-06 14:12:59 +00:00
log_err ( " control interface %s:%s getaddrinfo: %s %s " ,
ip ? ip : " default " , port , gai_strerror ( r ) ,
2008-09-10 15:23:01 +00:00
# ifdef EAI_SYSTEM
2015-01-06 14:12:59 +00:00
r = = EAI_SYSTEM ? ( char * ) strerror ( errno ) : " "
2008-09-10 15:23:01 +00:00
# else
2015-01-06 14:12:59 +00:00
" "
2008-09-10 15:23:01 +00:00
# endif
) ;
2015-01-06 14:12:59 +00:00
return 0 ;
}
/* open fd */
2015-03-19 09:50:35 +00:00
fd = create_tcp_accept_sock ( res , 1 , & noproto , 0 ,
2020-05-07 15:12:26 +00:00
cfg - > ip_transparent , 0 , 0 , cfg - > ip_freebind ,
cfg - > use_systemd , cfg - > ip_dscp ) ;
2015-01-06 14:12:59 +00:00
freeaddrinfo ( res ) ;
2008-09-10 15:23:01 +00:00
}
if ( fd = = - 1 & & noproto ) {
if ( ! noproto_is_err )
return 1 ; /* return success, but do nothing */
log_err ( " cannot open control interface %s %d : "
" protocol not supported " , ip , nr ) ;
return 0 ;
}
if ( fd = = - 1 ) {
log_err ( " cannot open control interface %s %d " , ip , nr ) ;
return 0 ;
}
/* alloc */
n = ( struct listen_port * ) calloc ( 1 , sizeof ( * n ) ) ;
if ( ! n ) {
2020-08-31 06:41:34 +00:00
sock_close ( fd ) ;
2008-09-10 15:23:01 +00:00
log_err ( " out of memory " ) ;
return 0 ;
}
n - > next = * list ;
* list = n ;
n - > fd = fd ;
return 1 ;
}
struct listen_port * daemon_remote_open_ports ( struct config_file * cfg )
{
struct listen_port * l = NULL ;
log_assert ( cfg - > remote_control_enable & & cfg - > control_port ) ;
2018-06-14 08:14:43 +00:00
if ( cfg - > control_ifs . first ) {
2021-02-26 12:54:10 +00:00
char * * rcif = NULL ;
int i , num_rcif = 0 ;
if ( ! resolve_interface_names ( NULL , 0 , cfg - > control_ifs . first ,
& rcif , & num_rcif ) ) {
return NULL ;
}
for ( i = 0 ; i < num_rcif ; i + + ) {
if ( ! add_open ( rcif [ i ] , cfg - > control_port , & l , 1 , cfg ) ) {
2008-09-10 15:23:01 +00:00
listening_ports_free ( l ) ;
2021-02-26 12:54:10 +00:00
config_del_strarray ( rcif , num_rcif ) ;
2008-09-10 15:23:01 +00:00
return NULL ;
}
}
2021-02-26 12:54:10 +00:00
config_del_strarray ( rcif , num_rcif ) ;
2008-09-10 15:23:01 +00:00
} else {
/* defaults */
if ( cfg - > do_ip6 & &
2015-01-06 14:12:59 +00:00
! add_open ( " ::1 " , cfg - > control_port , & l , 0 , cfg ) ) {
2008-09-10 15:23:01 +00:00
listening_ports_free ( l ) ;
return NULL ;
}
if ( cfg - > do_ip4 & &
2015-01-06 14:12:59 +00:00
! add_open ( " 127.0.0.1 " , cfg - > control_port , & l , 1 , cfg ) ) {
2008-09-10 15:23:01 +00:00
listening_ports_free ( l ) ;
return NULL ;
}
}
return l ;
}
/** open accept commpoint */
static int
accept_open ( struct daemon_remote * rc , int fd )
{
struct listen_list * n = ( struct listen_list * ) malloc ( sizeof ( * n ) ) ;
if ( ! n ) {
log_err ( " out of memory " ) ;
return 0 ;
}
n - > next = rc - > accept_list ;
rc - > accept_list = n ;
/* open commpt */
2023-04-20 15:39:55 +00:00
n - > com = comm_point_create_raw ( rc - > worker - > base , fd , 0 ,
2008-09-10 15:23:01 +00:00
& remote_accept_callback , rc ) ;
if ( ! n - > com )
return 0 ;
/* keep this port open, its fd is kept in the rc portlist */
n - > com - > do_not_close = 1 ;
return 1 ;
}
2023-04-20 15:39:55 +00:00
int daemon_remote_open_accept ( struct daemon_remote * rc ,
2009-06-11 09:43:23 +00:00
struct listen_port * ports , struct worker * worker )
2008-09-10 15:23:01 +00:00
{
struct listen_port * p ;
2009-06-11 09:43:23 +00:00
rc - > worker = worker ;
2008-09-10 15:23:01 +00:00
for ( p = ports ; p ; p = p - > next ) {
if ( ! accept_open ( rc , p - > fd ) ) {
log_err ( " could not create accept comm point " ) ;
return 0 ;
}
}
return 1 ;
}
2012-05-08 12:08:55 +00:00
void daemon_remote_stop_accept ( struct daemon_remote * rc )
{
struct listen_list * p ;
for ( p = rc - > accept_list ; p ; p = p - > next ) {
2023-04-20 15:39:55 +00:00
comm_point_stop_listening ( p - > com ) ;
2012-05-08 12:08:55 +00:00
}
}
void daemon_remote_start_accept ( struct daemon_remote * rc )
{
struct listen_list * p ;
for ( p = rc - > accept_list ; p ; p = p - > next ) {
2023-04-20 15:39:55 +00:00
comm_point_start_listening ( p - > com , - 1 , - 1 ) ;
2012-05-08 12:08:55 +00:00
}
}
2023-04-20 15:39:55 +00:00
int remote_accept_callback ( struct comm_point * c , void * arg , int err ,
2008-09-10 15:23:01 +00:00
struct comm_reply * ATTR_UNUSED ( rep ) )
{
struct daemon_remote * rc = ( struct daemon_remote * ) arg ;
struct sockaddr_storage addr ;
socklen_t addrlen ;
int newfd ;
struct rc_state * n ;
if ( err ! = NETEVENT_NOERROR ) {
log_err ( " error %d on remote_accept_callback " , err ) ;
return 0 ;
}
/* perform the accept */
newfd = comm_point_perform_accept ( c , & addr , & addrlen ) ;
if ( newfd = = - 1 )
return 0 ;
/* create new commpoint unless we are servicing already */
if ( rc - > active > = rc - > max_active ) {
log_warn ( " drop incoming remote control: too many connections " ) ;
2009-04-29 15:23:08 +00:00
close_exit :
2020-08-31 06:41:34 +00:00
sock_close ( newfd ) ;
2008-09-10 15:23:01 +00:00
return 0 ;
}
/* setup commpoint to service the remote control command */
n = ( struct rc_state * ) calloc ( 1 , sizeof ( * n ) ) ;
if ( ! n ) {
log_err ( " out of memory " ) ;
2009-04-29 15:23:08 +00:00
goto close_exit ;
2008-09-10 15:23:01 +00:00
}
2018-06-12 07:43:52 +00:00
n - > fd = newfd ;
2008-09-10 15:23:01 +00:00
/* start in reading state */
2023-04-20 15:39:55 +00:00
n - > c = comm_point_create_raw ( rc - > worker - > base , newfd , 0 ,
2008-09-10 15:23:01 +00:00
& remote_control_callback , n ) ;
if ( ! n - > c ) {
log_err ( " out of memory " ) ;
free ( n ) ;
2009-04-29 15:23:08 +00:00
goto close_exit ;
2008-09-10 15:23:01 +00:00
}
log_addr ( VERB_QUERY , " new control connection from " , & addr , addrlen ) ;
2008-09-11 14:14:12 +00:00
n - > c - > do_not_close = 0 ;
comm_point_stop_listening ( n - > c ) ;
comm_point_start_listening ( n - > c , - 1 , REMOTE_CONTROL_TCP_TIMEOUT ) ;
2022-10-03 13:29:47 +00:00
memcpy ( & n - > c - > repinfo . remote_addr , & addr , addrlen ) ;
n - > c - > repinfo . remote_addrlen = addrlen ;
2018-06-12 07:43:52 +00:00
if ( rc - > use_cert ) {
n - > shake_state = rc_hs_read ;
n - > ssl = SSL_new ( rc - > ctx ) ;
if ( ! n - > ssl ) {
log_crypto_err ( " could not SSL_new " ) ;
comm_point_delete ( n - > c ) ;
free ( n ) ;
goto close_exit ;
}
SSL_set_accept_state ( n - > ssl ) ;
2019-11-13 14:16:27 +00:00
( void ) SSL_set_mode ( n - > ssl , ( long ) SSL_MODE_AUTO_RETRY ) ;
2018-06-12 07:43:52 +00:00
if ( ! SSL_set_fd ( n - > ssl , newfd ) ) {
log_crypto_err ( " could not SSL_set_fd " ) ;
SSL_free ( n - > ssl ) ;
comm_point_delete ( n - > c ) ;
free ( n ) ;
goto close_exit ;
}
} else {
n - > ssl = NULL ;
2008-09-11 14:14:12 +00:00
}
2008-09-10 15:23:01 +00:00
n - > rc = rc ;
n - > next = rc - > busy_list ;
rc - > busy_list = n ;
rc - > active + + ;
2008-09-11 14:14:12 +00:00
2023-04-20 15:39:55 +00:00
/* perform the first nonblocking read already, for windows,
2008-09-11 14:14:12 +00:00
* so it can return wouldblock . could be faster too . */
( void ) remote_control_callback ( n - > c , n , NETEVENT_NOERROR , NULL ) ;
2008-09-10 15:23:01 +00:00
return 0 ;
}
/** delete from list */
static void
state_list_remove_elem ( struct rc_state * * list , struct comm_point * c )
{
while ( * list ) {
if ( ( * list ) - > c = = c ) {
* list = ( * list ) - > next ;
return ;
}
list = & ( * list ) - > next ;
}
}
/** decrease active count and remove commpoint from busy list */
static void
clean_point ( struct daemon_remote * rc , struct rc_state * s )
{
state_list_remove_elem ( & rc - > busy_list , s - > c ) ;
rc - > active - - ;
2008-09-11 14:14:12 +00:00
if ( s - > ssl ) {
SSL_shutdown ( s - > ssl ) ;
2008-09-10 15:23:01 +00:00
SSL_free ( s - > ssl ) ;
2008-09-11 14:14:12 +00:00
}
2008-09-10 15:23:01 +00:00
comm_point_delete ( s - > c ) ;
free ( s ) ;
}
2008-09-22 15:20:18 +00:00
int
2018-06-12 07:43:52 +00:00
ssl_print_text ( RES * res , const char * text )
2008-09-15 08:35:45 +00:00
{
int r ;
2023-04-20 15:39:55 +00:00
if ( ! res )
2008-12-03 15:20:56 +00:00
return 0 ;
2018-06-12 07:43:52 +00:00
if ( res - > ssl ) {
ERR_clear_error ( ) ;
if ( ( r = SSL_write ( res - > ssl , text , ( int ) strlen ( text ) ) ) < = 0 ) {
if ( SSL_get_error ( res - > ssl , r ) = = SSL_ERROR_ZERO_RETURN ) {
verbose ( VERB_QUERY , " warning, in SSL_write, peer "
" closed connection " ) ;
return 0 ;
}
log_crypto_err ( " could not SSL_write " ) ;
2008-09-15 08:35:45 +00:00
return 0 ;
}
2018-06-12 07:43:52 +00:00
} else {
size_t at = 0 ;
while ( at < strlen ( text ) ) {
2018-06-19 13:13:35 +00:00
ssize_t r = send ( res - > fd , text + at , strlen ( text ) - at , 0 ) ;
2018-06-12 07:43:52 +00:00
if ( r = = - 1 ) {
if ( errno = = EAGAIN | | errno = = EINTR )
continue ;
2020-08-31 07:12:01 +00:00
log_err ( " could not send: %s " ,
sock_strerror ( errno ) ) ;
2018-06-12 07:43:52 +00:00
return 0 ;
}
at + = r ;
}
2008-09-15 08:35:45 +00:00
}
return 1 ;
}
/** print text over the ssl connection */
static int
2018-06-12 07:43:52 +00:00
ssl_print_vmsg ( RES * ssl , const char * format , va_list args )
2008-09-15 08:35:45 +00:00
{
char msg [ 1024 ] ;
vsnprintf ( msg , sizeof ( msg ) , format , args ) ;
return ssl_print_text ( ssl , msg ) ;
}
/** printf style printing to the ssl connection */
2018-06-12 07:43:52 +00:00
int ssl_printf ( RES * ssl , const char * format , . . . )
2008-09-15 08:35:45 +00:00
{
va_list args ;
int ret ;
va_start ( args , format ) ;
ret = ssl_print_vmsg ( ssl , format , args ) ;
va_end ( args ) ;
return ret ;
}
2008-09-22 15:20:18 +00:00
int
2018-06-12 07:43:52 +00:00
ssl_read_line ( RES * res , char * buf , size_t max )
2008-09-15 08:35:45 +00:00
{
int r ;
size_t len = 0 ;
2018-06-12 07:43:52 +00:00
if ( ! res )
2008-12-03 15:20:56 +00:00
return 0 ;
2008-09-15 08:35:45 +00:00
while ( len < max ) {
2018-06-12 07:43:52 +00:00
if ( res - > ssl ) {
ERR_clear_error ( ) ;
if ( ( r = SSL_read ( res - > ssl , buf + len , 1 ) ) < = 0 ) {
if ( SSL_get_error ( res - > ssl , r ) = = SSL_ERROR_ZERO_RETURN ) {
buf [ len ] = 0 ;
return 1 ;
}
log_crypto_err ( " could not SSL_read " ) ;
return 0 ;
}
} else {
2018-06-12 10:50:51 +00:00
while ( 1 ) {
2018-06-19 13:13:35 +00:00
ssize_t rr = recv ( res - > fd , buf + len , 1 , 0 ) ;
2018-06-12 10:50:51 +00:00
if ( rr < = 0 ) {
if ( rr = = 0 ) {
buf [ len ] = 0 ;
return 1 ;
}
if ( errno = = EINTR | | errno = = EAGAIN )
continue ;
2020-08-31 07:12:01 +00:00
log_err ( " could not recv: %s " ,
sock_strerror ( errno ) ) ;
2018-06-12 10:50:51 +00:00
return 0 ;
2018-06-12 07:43:52 +00:00
}
2018-06-12 10:50:51 +00:00
break ;
2008-09-15 08:35:45 +00:00
}
}
if ( buf [ len ] = = ' \n ' ) {
/* return string without \n */
buf [ len ] = 0 ;
return 1 ;
}
len + + ;
}
buf [ max - 1 ] = 0 ;
log_err ( " control line too long (%d): %s " , ( int ) max , buf ) ;
return 0 ;
}
2008-09-15 14:19:41 +00:00
/** skip whitespace, return new pointer into string */
static char *
skipwhite ( char * str )
{
/* EOS \0 is not a space */
2023-04-20 15:39:55 +00:00
while ( isspace ( ( unsigned char ) * str ) )
2008-09-15 14:19:41 +00:00
str + + ;
return str ;
}
2008-09-15 08:35:45 +00:00
/** send the OK to the control client */
2018-06-12 07:43:52 +00:00
static void send_ok ( RES * ssl )
2008-09-15 08:35:45 +00:00
{
( void ) ssl_printf ( ssl , " ok \n " ) ;
}
/** do the stop command */
static void
2019-11-20 13:37:13 +00:00
do_stop ( RES * ssl , struct worker * worker )
2008-09-15 08:35:45 +00:00
{
2019-11-20 13:37:13 +00:00
worker - > need_to_exit = 1 ;
comm_base_exit ( worker - > base ) ;
2008-09-15 08:35:45 +00:00
send_ok ( ssl ) ;
}
/** do the reload command */
static void
2022-12-14 15:33:28 +00:00
do_reload ( RES * ssl , struct worker * worker , int reuse_cache )
2008-09-15 08:35:45 +00:00
{
2022-12-14 15:33:28 +00:00
worker - > reuse_cache = reuse_cache ;
2019-11-20 13:37:13 +00:00
worker - > need_to_exit = 0 ;
comm_base_exit ( worker - > base ) ;
2008-09-15 08:35:45 +00:00
send_ok ( ssl ) ;
}
2008-09-15 14:19:41 +00:00
/** do the verbosity command */
static void
2018-06-12 07:43:52 +00:00
do_verbosity ( RES * ssl , char * str )
2008-09-15 14:19:41 +00:00
{
int val = atoi ( str ) ;
if ( val = = 0 & & strcmp ( str , " 0 " ) ! = 0 ) {
ssl_printf ( ssl , " error in verbosity number syntax: %s \n " , str ) ;
return ;
}
verbosity = val ;
send_ok ( ssl ) ;
}
/** print stats from statinfo */
static int
2018-06-12 07:43:52 +00:00
print_stats ( RES * ssl , const char * nm , struct ub_stats_info * s )
2008-09-15 14:19:41 +00:00
{
2017-04-13 12:47:29 +00:00
struct timeval sumwait , avg ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " %s.num.queries " SQ " %lu \n " , nm ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . num_queries ) ) return 0 ;
2017-01-05 13:57:12 +00:00
if ( ! ssl_printf ( ssl , " %s.num.queries_ip_ratelimited " SQ " %lu \n " , nm ,
( unsigned long ) s - > svr . num_queries_ip_ratelimited ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " %s.num.cachehits " SQ " %lu \n " , nm ,
( unsigned long ) ( s - > svr . num_queries
2008-09-15 14:19:41 +00:00
- s - > svr . num_queries_missed_cache ) ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " %s.num.cachemiss " SQ " %lu \n " , nm ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . num_queries_missed_cache ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " %s.num.prefetch " SQ " %lu \n " , nm ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . num_queries_prefetch ) ) return 0 ;
2023-04-17 14:02:13 +00:00
if ( ! ssl_printf ( ssl , " %s.num.queries_timed_out " SQ " %lu \n " , nm ,
( unsigned long ) s - > svr . num_queries_timed_out ) ) return 0 ;
2023-04-21 16:23:21 +00:00
if ( ! ssl_printf ( ssl , " %s.query.queue_time_us.max " SQ " %lu \n " , nm ,
( unsigned long ) s - > svr . max_query_time_us ) ) return 0 ;
2020-02-05 13:20:27 +00:00
if ( ! ssl_printf ( ssl , " %s.num.expired " SQ " %lu \n " , nm ,
( unsigned long ) s - > svr . ans_expired ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " %s.num.recursivereplies " SQ " %lu \n " , nm ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > mesh_replies_sent ) ) return 0 ;
2017-04-03 09:03:32 +00:00
# ifdef USE_DNSCRYPT
2017-04-18 09:00:52 +00:00
if ( ! ssl_printf ( ssl , " %s.num.dnscrypt.crypted " SQ " %lu \n " , nm ,
( unsigned long ) s - > svr . num_query_dnscrypt_crypted ) ) return 0 ;
if ( ! ssl_printf ( ssl , " %s.num.dnscrypt.cert " SQ " %lu \n " , nm ,
( unsigned long ) s - > svr . num_query_dnscrypt_cert ) ) return 0 ;
if ( ! ssl_printf ( ssl , " %s.num.dnscrypt.cleartext " SQ " %lu \n " , nm ,
( unsigned long ) s - > svr . num_query_dnscrypt_cleartext ) ) return 0 ;
if ( ! ssl_printf ( ssl , " %s.num.dnscrypt.malformed " SQ " %lu \n " , nm ,
( unsigned long ) s - > svr . num_query_dnscrypt_crypted_malformed ) ) return 0 ;
2017-04-03 09:03:32 +00:00
# endif
2008-09-16 14:08:38 +00:00
if ( ! ssl_printf ( ssl , " %s.requestlist.avg " SQ " %g \n " , nm ,
2010-01-07 16:06:26 +00:00
( s - > svr . num_queries_missed_cache + s - > svr . num_queries_prefetch ) ?
2008-09-15 14:19:41 +00:00
( double ) s - > svr . sum_query_list_size /
2017-04-13 13:11:54 +00:00
( double ) ( s - > svr . num_queries_missed_cache +
2010-01-07 16:06:26 +00:00
s - > svr . num_queries_prefetch ) : 0.0 ) ) return 0 ;
2014-04-10 11:20:41 +00:00
if ( ! ssl_printf ( ssl , " %s.requestlist.max " SQ " %lu \n " , nm ,
( unsigned long ) s - > svr . max_query_list_size ) ) return 0 ;
if ( ! ssl_printf ( ssl , " %s.requestlist.overwritten " SQ " %lu \n " , nm ,
( unsigned long ) s - > mesh_jostled ) ) return 0 ;
if ( ! ssl_printf ( ssl , " %s.requestlist.exceeded " SQ " %lu \n " , nm ,
( unsigned long ) s - > mesh_dropped ) ) return 0 ;
if ( ! ssl_printf ( ssl , " %s.requestlist.current.all " SQ " %lu \n " , nm ,
( unsigned long ) s - > mesh_num_states ) ) return 0 ;
if ( ! ssl_printf ( ssl , " %s.requestlist.current.user " SQ " %lu \n " , nm ,
( unsigned long ) s - > mesh_num_reply_states ) ) return 0 ;
2017-04-13 13:17:51 +00:00
# ifndef S_SPLINT_S
sumwait . tv_sec = s - > mesh_replies_sum_wait_sec ;
sumwait . tv_usec = s - > mesh_replies_sum_wait_usec ;
# endif
2017-04-13 12:47:29 +00:00
timeval_divide ( & avg , & sumwait , s - > mesh_replies_sent ) ;
2014-01-16 16:01:37 +00:00
if ( ! ssl_printf ( ssl , " %s.recursion.time.avg " SQ ARG_LL " d.%6.6d \n " , nm ,
2013-08-22 07:09:57 +00:00
( long long ) avg . tv_sec , ( int ) avg . tv_usec ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " %s.recursion.time.median " SQ " %g \n " , nm ,
2008-09-15 14:19:41 +00:00
s - > mesh_time_median ) ) return 0 ;
2015-03-05 15:23:14 +00:00
if ( ! ssl_printf ( ssl , " %s.tcpusage " SQ " %lu \n " , nm ,
( unsigned long ) s - > svr . tcp_accept_usage ) ) return 0 ;
2008-09-15 14:19:41 +00:00
return 1 ;
}
/** print stats for one thread */
static int
2018-06-12 07:43:52 +00:00
print_thread_stats ( RES * ssl , int i , struct ub_stats_info * s )
2008-09-15 14:19:41 +00:00
{
2017-07-24 09:04:18 +00:00
char nm [ 32 ] ;
2008-09-15 14:19:41 +00:00
snprintf ( nm , sizeof ( nm ) , " thread%d " , i ) ;
nm [ sizeof ( nm ) - 1 ] = 0 ;
return print_stats ( ssl , nm , s ) ;
}
2008-11-11 13:47:25 +00:00
/** print long number */
static int
2018-06-12 07:43:52 +00:00
print_longnum ( RES * ssl , const char * desc , size_t x )
2008-11-11 13:47:25 +00:00
{
if ( x > 1024 * 1024 * 1024 ) {
/* more than a Gb */
size_t front = x / ( size_t ) 1000000 ;
size_t back = x % ( size_t ) 1000000 ;
2023-04-20 15:39:55 +00:00
return ssl_printf ( ssl , " %s%u%6.6u \n " , desc ,
2008-11-11 13:47:25 +00:00
( unsigned ) front , ( unsigned ) back ) ;
} else {
2014-04-10 11:20:41 +00:00
return ssl_printf ( ssl , " %s%lu \n " , desc , ( unsigned long ) x ) ;
2008-11-11 13:47:25 +00:00
}
}
2008-09-16 14:08:38 +00:00
/** print mem stats */
static int
2019-01-22 13:20:06 +00:00
print_mem ( RES * ssl , struct worker * worker , struct daemon * daemon ,
struct ub_stats_info * s )
2008-09-16 14:08:38 +00:00
{
2017-03-07 14:58:51 +00:00
size_t msg , rrset , val , iter , respip ;
2017-04-11 13:10:30 +00:00
# ifdef CLIENT_SUBNET
size_t subnet = 0 ;
# endif /* CLIENT_SUBNET */
2017-05-16 12:39:24 +00:00
# ifdef USE_IPSECMOD
size_t ipsecmod = 0 ;
# endif /* USE_IPSECMOD */
2017-08-31 08:06:17 +00:00
# ifdef USE_DNSCRYPT
size_t dnscrypt_shared_secret = 0 ;
2017-09-18 08:55:08 +00:00
size_t dnscrypt_nonce = 0 ;
2017-08-31 08:06:17 +00:00
# endif /* USE_DNSCRYPT */
2019-10-21 12:20:33 +00:00
# ifdef WITH_DYNLIBMODULE
size_t dynlib = 0 ;
# endif /* WITH_DYNLIBMODULE */
2008-09-16 14:08:38 +00:00
msg = slabhash_get_mem ( daemon - > env - > msg_cache ) ;
rrset = slabhash_get_mem ( & daemon - > env - > rrset_cache - > table ) ;
2017-05-16 14:16:59 +00:00
val = mod_get_mem ( & worker - > env , " validator " ) ;
iter = mod_get_mem ( & worker - > env , " iterator " ) ;
respip = mod_get_mem ( & worker - > env , " respip " ) ;
2017-04-11 13:10:30 +00:00
# ifdef CLIENT_SUBNET
2021-09-03 07:59:15 +00:00
subnet = mod_get_mem ( & worker - > env , " subnetcache " ) ;
2017-04-11 13:10:30 +00:00
# endif /* CLIENT_SUBNET */
2017-05-16 12:39:24 +00:00
# ifdef USE_IPSECMOD
2017-05-16 14:16:59 +00:00
ipsecmod = mod_get_mem ( & worker - > env , " ipsecmod " ) ;
2017-05-16 12:39:24 +00:00
# endif /* USE_IPSECMOD */
2017-08-31 08:06:17 +00:00
# ifdef USE_DNSCRYPT
if ( daemon - > dnscenv ) {
dnscrypt_shared_secret = slabhash_get_mem (
daemon - > dnscenv - > shared_secrets_cache ) ;
2017-09-18 08:55:08 +00:00
dnscrypt_nonce = slabhash_get_mem ( daemon - > dnscenv - > nonces_cache ) ;
2017-08-31 08:06:17 +00:00
}
# endif /* USE_DNSCRYPT */
2019-10-21 12:20:33 +00:00
# ifdef WITH_DYNLIBMODULE
dynlib = mod_get_mem ( & worker - > env , " dynlib " ) ;
# endif /* WITH_DYNLIBMODULE */
2008-09-16 14:08:38 +00:00
2008-11-11 13:47:25 +00:00
if ( ! print_longnum ( ssl , " mem.cache.rrset " SQ , rrset ) )
2008-09-16 14:08:38 +00:00
return 0 ;
2008-11-11 13:47:25 +00:00
if ( ! print_longnum ( ssl , " mem.cache.message " SQ , msg ) )
2008-09-16 14:08:38 +00:00
return 0 ;
2008-11-11 13:47:25 +00:00
if ( ! print_longnum ( ssl , " mem.mod.iterator " SQ , iter ) )
2008-09-16 14:08:38 +00:00
return 0 ;
2008-11-11 13:47:25 +00:00
if ( ! print_longnum ( ssl , " mem.mod.validator " SQ , val ) )
2008-09-16 14:08:38 +00:00
return 0 ;
2017-03-07 14:58:51 +00:00
if ( ! print_longnum ( ssl , " mem.mod.respip " SQ , respip ) )
return 0 ;
2017-04-11 13:10:30 +00:00
# ifdef CLIENT_SUBNET
if ( ! print_longnum ( ssl , " mem.mod.subnet " SQ , subnet ) )
return 0 ;
# endif /* CLIENT_SUBNET */
2017-05-16 12:39:24 +00:00
# ifdef USE_IPSECMOD
if ( ! print_longnum ( ssl , " mem.mod.ipsecmod " SQ , ipsecmod ) )
return 0 ;
# endif /* USE_IPSECMOD */
2017-08-31 08:06:17 +00:00
# ifdef USE_DNSCRYPT
if ( ! print_longnum ( ssl , " mem.cache.dnscrypt_shared_secret " SQ ,
dnscrypt_shared_secret ) )
return 0 ;
2017-09-18 08:55:08 +00:00
if ( ! print_longnum ( ssl , " mem.cache.dnscrypt_nonce " SQ ,
dnscrypt_nonce ) )
return 0 ;
2017-08-31 08:06:17 +00:00
# endif /* USE_DNSCRYPT */
2019-10-21 12:20:33 +00:00
# ifdef WITH_DYNLIBMODULE
if ( ! print_longnum ( ssl , " mem.mod.dynlibmod " SQ , dynlib ) )
return 0 ;
# endif /* WITH_DYNLIBMODULE */
2019-01-22 13:20:06 +00:00
if ( ! print_longnum ( ssl , " mem.streamwait " SQ ,
( size_t ) s - > svr . mem_stream_wait ) )
return 0 ;
2020-05-12 16:12:19 +00:00
if ( ! print_longnum ( ssl , " mem.http.query_buffer " SQ ,
( size_t ) s - > svr . mem_http2_query_buffer ) )
return 0 ;
if ( ! print_longnum ( ssl , " mem.http.response_buffer " SQ ,
( size_t ) s - > svr . mem_http2_response_buffer ) )
return 0 ;
2008-09-16 14:08:38 +00:00
return 1 ;
}
/** print uptime stats */
static int
2018-06-12 07:43:52 +00:00
print_uptime ( RES * ssl , struct worker * worker , int reset )
2008-09-16 14:08:38 +00:00
{
struct timeval now = * worker - > env . now_tv ;
struct timeval up , dt ;
timeval_subtract ( & up , & now , & worker - > daemon - > time_boot ) ;
timeval_subtract ( & dt , & now , & worker - > daemon - > time_last_stat ) ;
2011-02-24 12:16:12 +00:00
if ( reset )
worker - > daemon - > time_last_stat = now ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " time.now " SQ ARG_LL " d.%6.6d \n " ,
2013-08-22 07:09:57 +00:00
( long long ) now . tv_sec , ( unsigned ) now . tv_usec ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " time.up " SQ ARG_LL " d.%6.6d \n " ,
2013-08-22 07:09:57 +00:00
( long long ) up . tv_sec , ( unsigned ) up . tv_usec ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " time.elapsed " SQ ARG_LL " d.%6.6d \n " ,
2013-08-22 07:09:57 +00:00
( long long ) dt . tv_sec , ( unsigned ) dt . tv_usec ) ) return 0 ;
2008-09-16 14:08:38 +00:00
return 1 ;
}
2008-09-18 14:37:20 +00:00
/** print extended histogram */
static int
2018-06-12 07:43:52 +00:00
print_hist ( RES * ssl , struct ub_stats_info * s )
2008-09-18 14:37:20 +00:00
{
struct timehist * hist ;
size_t i ;
hist = timehist_setup ( ) ;
if ( ! hist ) {
log_err ( " out of memory " ) ;
return 0 ;
}
timehist_import ( hist , s - > svr . hist , NUM_BUCKETS_HIST ) ;
for ( i = 0 ; i < hist - > num ; i + + ) {
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl ,
2014-04-10 11:20:41 +00:00
" histogram.%6.6d.%6.6d.to.%6.6d.%6.6d=%lu \n " ,
2008-09-18 14:37:20 +00:00
( int ) hist - > buckets [ i ] . lower . tv_sec ,
( int ) hist - > buckets [ i ] . lower . tv_usec ,
( int ) hist - > buckets [ i ] . upper . tv_sec ,
( int ) hist - > buckets [ i ] . upper . tv_usec ,
2014-04-10 11:20:41 +00:00
( unsigned long ) hist - > buckets [ i ] . count ) ) {
2008-09-18 14:37:20 +00:00
timehist_delete ( hist ) ;
return 0 ;
}
}
timehist_delete ( hist ) ;
return 1 ;
}
2008-09-16 14:08:38 +00:00
/** print extended stats */
static int
2022-12-13 09:04:06 +00:00
print_ext ( RES * ssl , struct ub_stats_info * s , int inhibit_zero )
2008-09-16 14:08:38 +00:00
{
int i ;
2020-02-27 14:08:10 +00:00
char nm [ 32 ] ;
2013-12-03 09:11:16 +00:00
const sldns_rr_descriptor * desc ;
const sldns_lookup_table * lt ;
2008-09-16 14:08:38 +00:00
/* TYPE */
2017-04-13 12:47:29 +00:00
for ( i = 0 ; i < UB_STATS_QTYPE_NUM ; i + + ) {
2008-09-16 14:08:38 +00:00
if ( inhibit_zero & & s - > svr . qtype [ i ] = = 0 )
continue ;
2013-12-03 09:11:16 +00:00
desc = sldns_rr_descript ( ( uint16_t ) i ) ;
2008-09-16 14:08:38 +00:00
if ( desc & & desc - > _name ) {
snprintf ( nm , sizeof ( nm ) , " %s " , desc - > _name ) ;
2008-09-18 08:38:53 +00:00
} else if ( i = = LDNS_RR_TYPE_IXFR ) {
snprintf ( nm , sizeof ( nm ) , " IXFR " ) ;
} else if ( i = = LDNS_RR_TYPE_AXFR ) {
snprintf ( nm , sizeof ( nm ) , " AXFR " ) ;
} else if ( i = = LDNS_RR_TYPE_MAILA ) {
snprintf ( nm , sizeof ( nm ) , " MAILA " ) ;
} else if ( i = = LDNS_RR_TYPE_MAILB ) {
snprintf ( nm , sizeof ( nm ) , " MAILB " ) ;
} else if ( i = = LDNS_RR_TYPE_ANY ) {
snprintf ( nm , sizeof ( nm ) , " ANY " ) ;
2008-09-16 14:08:38 +00:00
} else {
snprintf ( nm , sizeof ( nm ) , " TYPE%d " , i ) ;
}
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.type.%s " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
nm , ( unsigned long ) s - > svr . qtype [ i ] ) ) return 0 ;
2008-09-16 14:08:38 +00:00
}
if ( ! inhibit_zero | | s - > svr . qtype_big ) {
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.type.other " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qtype_big ) ) return 0 ;
2008-09-16 14:08:38 +00:00
}
/* CLASS */
2017-04-13 12:47:29 +00:00
for ( i = 0 ; i < UB_STATS_QCLASS_NUM ; i + + ) {
2008-09-16 14:08:38 +00:00
if ( inhibit_zero & & s - > svr . qclass [ i ] = = 0 )
continue ;
2013-12-03 09:11:16 +00:00
lt = sldns_lookup_by_id ( sldns_rr_classes , i ) ;
2008-09-16 14:08:38 +00:00
if ( lt & & lt - > name ) {
snprintf ( nm , sizeof ( nm ) , " %s " , lt - > name ) ;
} else {
snprintf ( nm , sizeof ( nm ) , " CLASS%d " , i ) ;
}
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.class.%s " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
nm , ( unsigned long ) s - > svr . qclass [ i ] ) ) return 0 ;
2008-09-16 14:08:38 +00:00
}
if ( ! inhibit_zero | | s - > svr . qclass_big ) {
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.class.other " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qclass_big ) ) return 0 ;
2008-09-16 14:08:38 +00:00
}
/* OPCODE */
2017-04-13 12:47:29 +00:00
for ( i = 0 ; i < UB_STATS_OPCODE_NUM ; i + + ) {
2008-09-16 14:08:38 +00:00
if ( inhibit_zero & & s - > svr . qopcode [ i ] = = 0 )
continue ;
2013-12-03 09:11:16 +00:00
lt = sldns_lookup_by_id ( sldns_opcodes , i ) ;
2008-09-16 14:08:38 +00:00
if ( lt & & lt - > name ) {
snprintf ( nm , sizeof ( nm ) , " %s " , lt - > name ) ;
} else {
snprintf ( nm , sizeof ( nm ) , " OPCODE%d " , i ) ;
}
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.opcode.%s " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
nm , ( unsigned long ) s - > svr . qopcode [ i ] ) ) return 0 ;
2008-09-16 14:08:38 +00:00
}
/* transport */
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.tcp " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qtcp ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.tcpout " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qtcp_outgoing ) ) return 0 ;
2022-06-29 08:51:54 +00:00
if ( ! ssl_printf ( ssl , " num.query.udpout " SQ " %lu \n " ,
( unsigned long ) s - > svr . qudp_outgoing ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.tls " SQ " %lu \n " ,
2018-06-28 08:15:47 +00:00
( unsigned long ) s - > svr . qtls ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.tls.resume " SQ " %lu \n " ,
2019-01-23 09:35:52 +00:00
( unsigned long ) s - > svr . qtls_resume ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.ipv6 " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qipv6 ) ) return 0 ;
2020-05-08 10:14:17 +00:00
if ( ! ssl_printf ( ssl , " num.query.https " SQ " %lu \n " ,
( unsigned long ) s - > svr . qhttps ) ) return 0 ;
2008-09-16 14:08:38 +00:00
/* flags */
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.flags.QR " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qbit_QR ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.flags.AA " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qbit_AA ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.flags.TC " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qbit_TC ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.flags.RD " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qbit_RD ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.flags.RA " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qbit_RA ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.flags.Z " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qbit_Z ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.flags.AD " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qbit_AD ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.flags.CD " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qbit_CD ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.edns.present " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qEDNS ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.edns.DO " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . qEDNS_DO ) ) return 0 ;
2008-09-16 14:08:38 +00:00
/* RCODE */
2017-04-13 12:47:29 +00:00
for ( i = 0 ; i < UB_STATS_RCODE_NUM ; i + + ) {
2014-11-12 17:25:59 +00:00
/* Always include RCODEs 0-5 */
if ( inhibit_zero & & i > LDNS_RCODE_REFUSED & & s - > svr . ans_rcode [ i ] = = 0 )
2008-09-16 14:08:38 +00:00
continue ;
2013-12-03 09:11:16 +00:00
lt = sldns_lookup_by_id ( sldns_rcodes , i ) ;
2008-09-16 14:08:38 +00:00
if ( lt & & lt - > name ) {
snprintf ( nm , sizeof ( nm ) , " %s " , lt - > name ) ;
} else {
snprintf ( nm , sizeof ( nm ) , " RCODE%d " , i ) ;
}
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.answer.rcode.%s " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
nm , ( unsigned long ) s - > svr . ans_rcode [ i ] ) ) return 0 ;
2008-09-16 14:08:38 +00:00
}
if ( ! inhibit_zero | | s - > svr . ans_rcode_nodata ) {
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.answer.rcode.nodata " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . ans_rcode_nodata ) ) return 0 ;
2008-09-16 14:08:38 +00:00
}
2017-08-03 12:52:33 +00:00
/* iteration */
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.ratelimited " SQ " %lu \n " ,
2017-08-03 12:52:33 +00:00
( unsigned long ) s - > svr . queries_ratelimited ) ) return 0 ;
2008-09-16 14:08:38 +00:00
/* validation */
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.answer.secure " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . ans_secure ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.answer.bogus " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . ans_bogus ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.rrset.bogus " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . rrset_bogus ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.aggressive.NOERROR " SQ " %lu \n " ,
2018-04-10 11:39:23 +00:00
( unsigned long ) s - > svr . num_neg_cache_noerror ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " num.query.aggressive.NXDOMAIN " SQ " %lu \n " ,
2018-04-10 11:39:23 +00:00
( unsigned long ) s - > svr . num_neg_cache_nxdomain ) ) return 0 ;
2008-09-16 14:08:38 +00:00
/* threat detection */
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " unwanted.queries " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . unwanted_queries ) ) return 0 ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " unwanted.replies " SQ " %lu \n " ,
2014-04-10 11:20:41 +00:00
( unsigned long ) s - > svr . unwanted_replies ) ) return 0 ;
2014-08-01 13:24:46 +00:00
/* cache counts */
if ( ! ssl_printf ( ssl , " msg.cache.count " SQ " %u \n " ,
( unsigned ) s - > svr . msg_cache_count ) ) return 0 ;
if ( ! ssl_printf ( ssl , " rrset.cache.count " SQ " %u \n " ,
( unsigned ) s - > svr . rrset_cache_count ) ) return 0 ;
if ( ! ssl_printf ( ssl , " infra.cache.count " SQ " %u \n " ,
( unsigned ) s - > svr . infra_cache_count ) ) return 0 ;
if ( ! ssl_printf ( ssl , " key.cache.count " SQ " %u \n " ,
( unsigned ) s - > svr . key_cache_count ) ) return 0 ;
2023-01-13 06:33:38 +00:00
/* max collisions */
if ( ! ssl_printf ( ssl , " msg.cache.max_collisions " SQ " %u \n " ,
( unsigned ) s - > svr . msg_cache_max_collisions ) ) return 0 ;
if ( ! ssl_printf ( ssl , " rrset.cache.max_collisions " SQ " %u \n " ,
( unsigned ) s - > svr . rrset_cache_max_collisions ) ) return 0 ;
2019-06-03 13:46:39 +00:00
/* applied RPZ actions */
for ( i = 0 ; i < UB_STATS_RPZ_ACTION_NUM ; i + + ) {
2020-01-30 13:05:56 +00:00
if ( i = = RPZ_NO_OVERRIDE_ACTION )
2019-06-03 13:46:39 +00:00
continue ;
if ( inhibit_zero & & s - > svr . rpz_action [ i ] = = 0 )
continue ;
if ( ! ssl_printf ( ssl , " num.rpz.action.%s " SQ " %lu \n " ,
rpz_action_to_string ( i ) ,
( unsigned long ) s - > svr . rpz_action [ i ] ) ) return 0 ;
}
2017-08-31 08:06:17 +00:00
# ifdef USE_DNSCRYPT
if ( ! ssl_printf ( ssl , " dnscrypt_shared_secret.cache.count " SQ " %u \n " ,
( unsigned ) s - > svr . shared_secret_cache_count ) ) return 0 ;
2017-09-18 08:55:08 +00:00
if ( ! ssl_printf ( ssl , " dnscrypt_nonce.cache.count " SQ " %u \n " ,
( unsigned ) s - > svr . nonce_cache_count ) ) return 0 ;
2017-08-31 08:06:17 +00:00
if ( ! ssl_printf ( ssl , " num.query.dnscrypt.shared_secret.cachemiss " SQ " %lu \n " ,
( unsigned long ) s - > svr . num_query_dnscrypt_secret_missed_cache ) ) return 0 ;
2017-09-18 08:55:08 +00:00
if ( ! ssl_printf ( ssl , " num.query.dnscrypt.replay " SQ " %lu \n " ,
( unsigned long ) s - > svr . num_query_dnscrypt_replay ) ) return 0 ;
2017-08-31 08:06:17 +00:00
# endif /* USE_DNSCRYPT */
2018-04-09 10:15:06 +00:00
if ( ! ssl_printf ( ssl , " num.query.authzone.up " SQ " %lu \n " ,
( unsigned long ) s - > svr . num_query_authzone_up ) ) return 0 ;
if ( ! ssl_printf ( ssl , " num.query.authzone.down " SQ " %lu \n " ,
( unsigned long ) s - > svr . num_query_authzone_down ) ) return 0 ;
2018-08-21 14:14:28 +00:00
# ifdef CLIENT_SUBNET
if ( ! ssl_printf ( ssl , " num.query.subnet " SQ " %lu \n " ,
( unsigned long ) s - > svr . num_query_subnet ) ) return 0 ;
if ( ! ssl_printf ( ssl , " num.query.subnet_cache " SQ " %lu \n " ,
( unsigned long ) s - > svr . num_query_subnet_cache ) ) return 0 ;
# endif /* CLIENT_SUBNET */
2023-05-30 15:49:50 +00:00
# ifdef USE_CACHEDB
if ( ! ssl_printf ( ssl , " num.query.cachedb " SQ " %lu \n " ,
( unsigned long ) s - > svr . num_query_cachedb ) ) return 0 ;
# endif /* USE_CACHEDB */
2008-09-16 14:08:38 +00:00
return 1 ;
}
2008-09-15 14:19:41 +00:00
/** do the stats command */
static void
2019-11-20 13:37:13 +00:00
do_stats ( RES * ssl , struct worker * worker , int reset )
2008-09-15 14:19:41 +00:00
{
2019-11-20 13:37:13 +00:00
struct daemon * daemon = worker - > daemon ;
2017-04-13 12:47:29 +00:00
struct ub_stats_info total ;
struct ub_stats_info s ;
2008-09-15 14:19:41 +00:00
int i ;
2018-09-13 12:20:41 +00:00
memset ( & total , 0 , sizeof ( total ) ) ;
2010-05-18 12:37:04 +00:00
log_assert ( daemon - > num > 0 ) ;
2008-09-15 14:19:41 +00:00
/* gather all thread statistics in one place */
for ( i = 0 ; i < daemon - > num ; i + + ) {
2019-11-20 13:37:13 +00:00
server_stats_obtain ( worker , daemon - > workers [ i ] , & s , reset ) ;
2008-09-15 14:19:41 +00:00
if ( ! print_thread_stats ( ssl , i , & s ) )
return ;
if ( i = = 0 )
total = s ;
else server_stats_add ( & total , & s ) ;
}
/* print the thread statistics */
total . mesh_time_median / = ( double ) daemon - > num ;
2023-04-20 15:39:55 +00:00
if ( ! print_stats ( ssl , " total " , & total ) )
2008-09-16 14:08:38 +00:00
return ;
2019-11-20 13:37:13 +00:00
if ( ! print_uptime ( ssl , worker , reset ) )
2008-09-17 16:45:32 +00:00
return ;
2008-09-16 14:08:38 +00:00
if ( daemon - > cfg - > stat_extended ) {
2019-11-20 13:37:13 +00:00
if ( ! print_mem ( ssl , worker , daemon , & total ) )
2008-09-16 14:08:38 +00:00
return ;
2008-09-18 14:37:20 +00:00
if ( ! print_hist ( ssl , & total ) )
return ;
2022-12-13 09:04:06 +00:00
if ( ! print_ext ( ssl , & total , daemon - > cfg - > stat_inhibit_zero ) )
2008-09-16 14:08:38 +00:00
return ;
}
2008-09-15 14:19:41 +00:00
}
2008-09-19 14:49:29 +00:00
/** parse commandline argument domain name */
static int
2018-06-12 07:43:52 +00:00
parse_arg_name ( RES * ssl , char * str , uint8_t * * res , size_t * len , int * labs )
2008-09-19 14:49:29 +00:00
{
2013-10-31 15:09:26 +00:00
uint8_t nm [ LDNS_MAX_DOMAINLEN + 1 ] ;
size_t nmlen = sizeof ( nm ) ;
int status ;
2008-09-19 14:49:29 +00:00
* res = NULL ;
* len = 0 ;
* labs = 0 ;
2020-03-27 10:27:12 +00:00
if ( str [ 0 ] = = ' \0 ' ) {
ssl_printf ( ssl , " error: this option requires a domain name \n " ) ;
return 0 ;
}
2013-12-03 09:11:16 +00:00
status = sldns_str2wire_dname_buf ( str , nm , & nmlen ) ;
2013-10-31 15:09:26 +00:00
if ( status ! = 0 ) {
ssl_printf ( ssl , " error cannot parse name %s at %d: %s \n " , str ,
LDNS_WIREPARSE_OFFSET ( status ) ,
2013-12-03 09:11:16 +00:00
sldns_get_errorstr_parse ( status ) ) ;
2008-09-19 14:49:29 +00:00
return 0 ;
}
2013-10-31 15:09:26 +00:00
* res = memdup ( nm , nmlen ) ;
2008-09-19 14:49:29 +00:00
if ( ! * res ) {
ssl_printf ( ssl , " error out of memory \n " ) ;
return 0 ;
}
* labs = dname_count_size_labels ( * res , len ) ;
return 1 ;
}
/** find second argument, modifies string */
static int
2018-06-12 07:43:52 +00:00
find_arg2 ( RES * ssl , char * arg , char * * arg2 )
2008-09-19 14:49:29 +00:00
{
char * as = strchr ( arg , ' ' ) ;
char * at = strchr ( arg , ' \t ' ) ;
if ( as & & at ) {
if ( at < as )
as = at ;
as [ 0 ] = 0 ;
* arg2 = skipwhite ( as + 1 ) ;
} else if ( as ) {
as [ 0 ] = 0 ;
* arg2 = skipwhite ( as + 1 ) ;
} else if ( at ) {
at [ 0 ] = 0 ;
* arg2 = skipwhite ( at + 1 ) ;
} else {
ssl_printf ( ssl , " error could not find next argument "
" after %s \n " , arg ) ;
return 0 ;
}
return 1 ;
}
/** Add a new zone */
2016-11-30 11:22:29 +00:00
static int
2018-06-12 07:43:52 +00:00
perform_zone_add ( RES * ssl , struct local_zones * zones , char * arg )
2008-09-19 14:49:29 +00:00
{
uint8_t * nm ;
int nmlabs ;
size_t nmlen ;
char * arg2 ;
enum localzone_type t ;
struct local_zone * z ;
if ( ! find_arg2 ( ssl , arg , & arg2 ) )
2016-11-30 11:22:29 +00:00
return 0 ;
2008-09-19 14:49:29 +00:00
if ( ! parse_arg_name ( ssl , arg , & nm , & nmlen , & nmlabs ) )
2016-11-30 11:22:29 +00:00
return 0 ;
2008-09-19 14:49:29 +00:00
if ( ! local_zone_str2type ( arg2 , & t ) ) {
ssl_printf ( ssl , " error not a zone type. %s \n " , arg2 ) ;
2008-09-23 10:55:36 +00:00
free ( nm ) ;
2016-11-30 11:22:29 +00:00
return 0 ;
2008-09-19 14:49:29 +00:00
}
2016-10-05 09:36:25 +00:00
lock_rw_wrlock ( & zones - > lock ) ;
2023-04-20 15:39:55 +00:00
if ( ( z = local_zones_find ( zones , nm , nmlen ,
2008-09-19 14:49:29 +00:00
nmlabs , LDNS_RR_CLASS_IN ) ) ) {
/* already present in tree */
lock_rw_wrlock ( & z - > lock ) ;
z - > type = t ; /* update type anyway */
lock_rw_unlock ( & z - > lock ) ;
2008-09-23 10:55:36 +00:00
free ( nm ) ;
2016-10-05 09:36:25 +00:00
lock_rw_unlock ( & zones - > lock ) ;
2016-11-30 11:22:29 +00:00
return 1 ;
2008-09-19 14:49:29 +00:00
}
2023-04-20 15:39:55 +00:00
if ( ! local_zones_add_zone ( zones , nm , nmlen ,
2008-09-19 14:49:29 +00:00
nmlabs , LDNS_RR_CLASS_IN , t ) ) {
2016-10-05 09:36:25 +00:00
lock_rw_unlock ( & zones - > lock ) ;
2008-09-19 14:49:29 +00:00
ssl_printf ( ssl , " error out of memory \n " ) ;
2016-11-30 11:22:29 +00:00
return 0 ;
2008-09-19 14:49:29 +00:00
}
2016-10-05 09:36:25 +00:00
lock_rw_unlock ( & zones - > lock ) ;
2016-11-30 11:22:29 +00:00
return 1 ;
}
/** Do the local_zone command */
static void
2018-06-12 07:43:52 +00:00
do_zone_add ( RES * ssl , struct local_zones * zones , char * arg )
2016-11-30 11:22:29 +00:00
{
if ( ! perform_zone_add ( ssl , zones , arg ) )
return ;
2008-09-19 14:49:29 +00:00
send_ok ( ssl ) ;
}
2016-11-30 11:22:29 +00:00
/** Do the local_zones command */
2008-09-19 14:49:29 +00:00
static void
2018-06-12 07:43:52 +00:00
do_zones_add ( RES * ssl , struct local_zones * zones )
2016-11-30 11:22:29 +00:00
{
char buf [ 2048 ] ;
int num = 0 ;
while ( ssl_read_line ( ssl , buf , sizeof ( buf ) ) ) {
if ( buf [ 0 ] = = 0x04 & & buf [ 1 ] = = 0 )
break ; /* end of transmission */
if ( ! perform_zone_add ( ssl , zones , buf ) ) {
if ( ! ssl_printf ( ssl , " error for input line: %s \n " , buf ) )
return ;
}
else
num + + ;
}
( void ) ssl_printf ( ssl , " added %d zones \n " , num ) ;
}
/** Remove a zone */
static int
2018-06-12 07:43:52 +00:00
perform_zone_remove ( RES * ssl , struct local_zones * zones , char * arg )
2008-09-19 14:49:29 +00:00
{
uint8_t * nm ;
int nmlabs ;
size_t nmlen ;
struct local_zone * z ;
if ( ! parse_arg_name ( ssl , arg , & nm , & nmlen , & nmlabs ) )
2016-11-30 11:22:29 +00:00
return 0 ;
2016-10-05 09:36:25 +00:00
lock_rw_wrlock ( & zones - > lock ) ;
2023-04-20 15:39:55 +00:00
if ( ( z = local_zones_find ( zones , nm , nmlen ,
2008-09-19 14:49:29 +00:00
nmlabs , LDNS_RR_CLASS_IN ) ) ) {
/* present in tree */
2016-10-05 09:36:25 +00:00
local_zones_del_zone ( zones , z ) ;
2008-09-19 14:49:29 +00:00
}
2016-10-05 09:36:25 +00:00
lock_rw_unlock ( & zones - > lock ) ;
2008-09-26 13:02:34 +00:00
free ( nm ) ;
2016-11-30 11:22:29 +00:00
return 1 ;
}
/** Do the local_zone_remove command */
static void
2018-06-12 07:43:52 +00:00
do_zone_remove ( RES * ssl , struct local_zones * zones , char * arg )
2016-11-30 11:22:29 +00:00
{
if ( ! perform_zone_remove ( ssl , zones , arg ) )
return ;
2008-09-19 14:49:29 +00:00
send_ok ( ssl ) ;
}
2016-11-30 11:22:29 +00:00
/** Do the local_zones_remove command */
2008-09-19 14:49:29 +00:00
static void
2018-06-12 07:43:52 +00:00
do_zones_remove ( RES * ssl , struct local_zones * zones )
2016-11-30 11:22:29 +00:00
{
char buf [ 2048 ] ;
int num = 0 ;
while ( ssl_read_line ( ssl , buf , sizeof ( buf ) ) ) {
if ( buf [ 0 ] = = 0x04 & & buf [ 1 ] = = 0 )
break ; /* end of transmission */
if ( ! perform_zone_remove ( ssl , zones , buf ) ) {
if ( ! ssl_printf ( ssl , " error for input line: %s \n " , buf ) )
return ;
}
else
num + + ;
}
( void ) ssl_printf ( ssl , " removed %d zones \n " , num ) ;
}
2021-07-16 08:51:27 +00:00
/** check syntax of newly added RR */
static int
check_RR_syntax ( RES * ssl , char * str , int line )
{
uint8_t rr [ LDNS_RR_BUF_SIZE ] ;
size_t len = sizeof ( rr ) , dname_len = 0 ;
int s = sldns_str2wire_rr_buf ( str , rr , & len , & dname_len , 3600 ,
NULL , 0 , NULL , 0 ) ;
if ( s ! = 0 ) {
char linestr [ 32 ] ;
if ( line = = 0 )
linestr [ 0 ] = 0 ;
else snprintf ( linestr , sizeof ( linestr ) , " line %d " , line ) ;
if ( ! ssl_printf ( ssl , " error parsing local-data at %sposition %d '%s': %s \n " ,
linestr , LDNS_WIREPARSE_OFFSET ( s ) , str ,
sldns_get_errorstr_parse ( s ) ) )
return 0 ;
return 0 ;
}
return 1 ;
}
2016-11-30 11:22:29 +00:00
/** Add new RR data */
static int
2021-07-16 08:51:27 +00:00
perform_data_add ( RES * ssl , struct local_zones * zones , char * arg , int line )
2008-09-19 14:49:29 +00:00
{
2021-07-16 08:51:27 +00:00
if ( ! check_RR_syntax ( ssl , arg , line ) ) {
return 0 ;
}
2016-10-05 09:36:25 +00:00
if ( ! local_zones_add_RR ( zones , arg ) ) {
2008-09-19 14:49:29 +00:00
ssl_printf ( ssl , " error in syntax or out of memory, %s \n " , arg ) ;
2016-11-30 11:22:29 +00:00
return 0 ;
2008-09-19 14:49:29 +00:00
}
2016-11-30 11:22:29 +00:00
return 1 ;
}
/** Do the local_data command */
static void
2018-06-12 07:43:52 +00:00
do_data_add ( RES * ssl , struct local_zones * zones , char * arg )
2016-11-30 11:22:29 +00:00
{
2021-07-16 08:51:27 +00:00
if ( ! perform_data_add ( ssl , zones , arg , 0 ) )
2016-11-30 11:22:29 +00:00
return ;
2008-09-19 14:49:29 +00:00
send_ok ( ssl ) ;
}
2016-11-30 11:22:29 +00:00
/** Do the local_datas command */
2008-09-19 14:49:29 +00:00
static void
2018-06-12 07:43:52 +00:00
do_datas_add ( RES * ssl , struct local_zones * zones )
2016-11-30 11:22:29 +00:00
{
char buf [ 2048 ] ;
2021-07-16 08:51:27 +00:00
int num = 0 , line = 0 ;
2016-11-30 11:22:29 +00:00
while ( ssl_read_line ( ssl , buf , sizeof ( buf ) ) ) {
if ( buf [ 0 ] = = 0x04 & & buf [ 1 ] = = 0 )
break ; /* end of transmission */
2021-07-16 08:51:27 +00:00
line + + ;
2021-07-16 08:53:53 +00:00
if ( perform_data_add ( ssl , zones , buf , line ) )
2016-11-30 11:22:29 +00:00
num + + ;
}
( void ) ssl_printf ( ssl , " added %d datas \n " , num ) ;
}
/** Remove RR data */
static int
2018-06-12 07:43:52 +00:00
perform_data_remove ( RES * ssl , struct local_zones * zones , char * arg )
2008-09-19 14:49:29 +00:00
{
uint8_t * nm ;
int nmlabs ;
size_t nmlen ;
if ( ! parse_arg_name ( ssl , arg , & nm , & nmlen , & nmlabs ) )
2016-11-30 11:22:29 +00:00
return 0 ;
2016-10-05 09:36:25 +00:00
local_zones_del_data ( zones , nm ,
2008-09-19 14:49:29 +00:00
nmlen , nmlabs , LDNS_RR_CLASS_IN ) ;
2008-09-23 10:55:36 +00:00
free ( nm ) ;
2016-11-30 11:22:29 +00:00
return 1 ;
}
/** Do the local_data_remove command */
static void
2018-06-12 07:43:52 +00:00
do_data_remove ( RES * ssl , struct local_zones * zones , char * arg )
2016-11-30 11:22:29 +00:00
{
if ( ! perform_data_remove ( ssl , zones , arg ) )
return ;
2008-09-19 14:49:29 +00:00
send_ok ( ssl ) ;
}
2016-11-30 11:22:29 +00:00
/** Do the local_datas_remove command */
static void
2018-06-12 07:43:52 +00:00
do_datas_remove ( RES * ssl , struct local_zones * zones )
2016-11-30 11:22:29 +00:00
{
char buf [ 2048 ] ;
int num = 0 ;
while ( ssl_read_line ( ssl , buf , sizeof ( buf ) ) ) {
if ( buf [ 0 ] = = 0x04 & & buf [ 1 ] = = 0 )
break ; /* end of transmission */
if ( ! perform_data_remove ( ssl , zones , buf ) ) {
if ( ! ssl_printf ( ssl , " error for input line: %s \n " , buf ) )
return ;
}
else
num + + ;
}
( void ) ssl_printf ( ssl , " removed %d datas \n " , num ) ;
}
2016-10-05 09:36:25 +00:00
/** Add a new zone to view */
static void
2018-06-12 07:43:52 +00:00
do_view_zone_add ( RES * ssl , struct worker * worker , char * arg )
2016-10-05 09:36:25 +00:00
{
char * arg2 ;
struct view * v ;
if ( ! find_arg2 ( ssl , arg , & arg2 ) )
return ;
v = views_find_view ( worker - > daemon - > views ,
arg , 1 /* get write lock*/ ) ;
if ( ! v ) {
ssl_printf ( ssl , " no view with name: %s \n " , arg ) ;
return ;
}
2017-03-22 07:19:38 +00:00
if ( ! v - > local_zones ) {
if ( ! ( v - > local_zones = local_zones_create ( ) ) ) {
lock_rw_unlock ( & v - > lock ) ;
ssl_printf ( ssl , " error out of memory \n " ) ;
return ;
}
2017-05-30 13:04:19 +00:00
if ( ! v - > isfirst ) {
/* Global local-zone is not used for this view,
* therefore add defaults to this view - specic
* local - zone . */
struct config_file lz_cfg ;
memset ( & lz_cfg , 0 , sizeof ( lz_cfg ) ) ;
local_zone_enter_defaults ( v - > local_zones , & lz_cfg ) ;
}
2017-03-22 07:19:38 +00:00
}
2016-10-05 09:36:25 +00:00
do_zone_add ( ssl , v - > local_zones , arg2 ) ;
lock_rw_unlock ( & v - > lock ) ;
}
/** Remove a zone from view */
static void
2018-06-12 07:43:52 +00:00
do_view_zone_remove ( RES * ssl , struct worker * worker , char * arg )
2016-10-05 09:36:25 +00:00
{
char * arg2 ;
struct view * v ;
if ( ! find_arg2 ( ssl , arg , & arg2 ) )
return ;
v = views_find_view ( worker - > daemon - > views ,
arg , 1 /* get write lock*/ ) ;
if ( ! v ) {
ssl_printf ( ssl , " no view with name: %s \n " , arg ) ;
return ;
}
2017-03-22 07:19:38 +00:00
if ( ! v - > local_zones ) {
lock_rw_unlock ( & v - > lock ) ;
send_ok ( ssl ) ;
return ;
}
2016-10-05 09:36:25 +00:00
do_zone_remove ( ssl , v - > local_zones , arg2 ) ;
lock_rw_unlock ( & v - > lock ) ;
}
/** Add new RR data to view */
static void
2018-06-12 07:43:52 +00:00
do_view_data_add ( RES * ssl , struct worker * worker , char * arg )
2016-10-05 09:36:25 +00:00
{
char * arg2 ;
struct view * v ;
if ( ! find_arg2 ( ssl , arg , & arg2 ) )
return ;
v = views_find_view ( worker - > daemon - > views ,
arg , 1 /* get write lock*/ ) ;
if ( ! v ) {
ssl_printf ( ssl , " no view with name: %s \n " , arg ) ;
return ;
}
2017-03-22 07:19:38 +00:00
if ( ! v - > local_zones ) {
if ( ! ( v - > local_zones = local_zones_create ( ) ) ) {
lock_rw_unlock ( & v - > lock ) ;
ssl_printf ( ssl , " error out of memory \n " ) ;
return ;
}
}
2016-10-05 09:36:25 +00:00
do_data_add ( ssl , v - > local_zones , arg2 ) ;
lock_rw_unlock ( & v - > lock ) ;
}
2018-11-26 13:37:23 +00:00
/** Add new RR data from stdin to view */
static void
do_view_datas_add ( RES * ssl , struct worker * worker , char * arg )
{
struct view * v ;
v = views_find_view ( worker - > daemon - > views ,
arg , 1 /* get write lock*/ ) ;
if ( ! v ) {
ssl_printf ( ssl , " no view with name: %s \n " , arg ) ;
return ;
}
if ( ! v - > local_zones ) {
if ( ! ( v - > local_zones = local_zones_create ( ) ) ) {
lock_rw_unlock ( & v - > lock ) ;
ssl_printf ( ssl , " error out of memory \n " ) ;
return ;
}
}
do_datas_add ( ssl , v - > local_zones ) ;
lock_rw_unlock ( & v - > lock ) ;
}
2016-10-05 09:36:25 +00:00
/** Remove RR data from view */
static void
2018-06-12 07:43:52 +00:00
do_view_data_remove ( RES * ssl , struct worker * worker , char * arg )
2016-10-05 09:36:25 +00:00
{
char * arg2 ;
struct view * v ;
if ( ! find_arg2 ( ssl , arg , & arg2 ) )
return ;
v = views_find_view ( worker - > daemon - > views ,
arg , 1 /* get write lock*/ ) ;
if ( ! v ) {
ssl_printf ( ssl , " no view with name: %s \n " , arg ) ;
return ;
}
2017-03-22 07:19:38 +00:00
if ( ! v - > local_zones ) {
lock_rw_unlock ( & v - > lock ) ;
send_ok ( ssl ) ;
return ;
}
2016-10-05 09:36:25 +00:00
do_data_remove ( ssl , v - > local_zones , arg2 ) ;
lock_rw_unlock ( & v - > lock ) ;
}
2020-01-29 01:28:00 +00:00
/** Remove RR data from stdin from view */
static void
do_view_datas_remove ( RES * ssl , struct worker * worker , char * arg )
{
struct view * v ;
v = views_find_view ( worker - > daemon - > views ,
arg , 1 /* get write lock*/ ) ;
if ( ! v ) {
ssl_printf ( ssl , " no view with name: %s \n " , arg ) ;
return ;
}
if ( ! v - > local_zones ) {
lock_rw_unlock ( & v - > lock ) ;
ssl_printf ( ssl , " removed 0 datas \n " ) ;
return ;
}
do_datas_remove ( ssl , v - > local_zones ) ;
lock_rw_unlock ( & v - > lock ) ;
}
2008-09-23 10:55:36 +00:00
/** cache lookup of nameservers */
static void
2018-06-12 07:43:52 +00:00
do_lookup ( RES * ssl , struct worker * worker , char * arg )
2008-09-23 10:55:36 +00:00
{
uint8_t * nm ;
int nmlabs ;
size_t nmlen ;
if ( ! parse_arg_name ( ssl , arg , & nm , & nmlen , & nmlabs ) )
return ;
( void ) print_deleg_lookup ( ssl , worker , nm , nmlen , nmlabs ) ;
free ( nm ) ;
}
2009-06-11 09:43:23 +00:00
/** flush something from rrset and msg caches */
static void
do_cache_remove ( struct worker * worker , uint8_t * nm , size_t nmlen ,
uint16_t t , uint16_t c )
{
2017-01-19 10:25:41 +00:00
hashvalue_type h ;
2009-06-11 09:43:23 +00:00
struct query_info k ;
rrset_cache_remove ( worker - > env . rrset_cache , nm , nmlen , t , c , 0 ) ;
2011-05-10 12:34:47 +00:00
if ( t = = LDNS_RR_TYPE_SOA )
rrset_cache_remove ( worker - > env . rrset_cache , nm , nmlen , t , c ,
PACKED_RRSET_SOA_NEG ) ;
2009-06-11 09:43:23 +00:00
k . qname = nm ;
k . qname_len = nmlen ;
k . qtype = t ;
k . qclass = c ;
2016-10-20 15:05:30 +00:00
k . local_alias = NULL ;
2014-11-18 15:15:57 +00:00
h = query_info_hash ( & k , 0 ) ;
2009-06-11 09:43:23 +00:00
slabhash_remove ( worker - > env . msg_cache , h , & k ) ;
2014-11-18 15:15:57 +00:00
if ( t = = LDNS_RR_TYPE_AAAA ) {
/* for AAAA also flush dns64 bit_cd packet */
h = query_info_hash ( & k , BIT_CD ) ;
slabhash_remove ( worker - > env . msg_cache , h , & k ) ;
}
2009-06-11 09:43:23 +00:00
}
2008-09-23 14:07:02 +00:00
/** flush a type */
static void
2018-06-12 07:43:52 +00:00
do_flush_type ( RES * ssl , struct worker * worker , char * arg )
2008-09-23 14:07:02 +00:00
{
uint8_t * nm ;
int nmlabs ;
size_t nmlen ;
char * arg2 ;
uint16_t t ;
if ( ! find_arg2 ( ssl , arg , & arg2 ) )
return ;
if ( ! parse_arg_name ( ssl , arg , & nm , & nmlen , & nmlabs ) )
return ;
2013-12-03 09:11:16 +00:00
t = sldns_get_rr_type_by_name ( arg2 ) ;
2009-06-11 09:43:23 +00:00
do_cache_remove ( worker , nm , nmlen , t , LDNS_RR_CLASS_IN ) ;
2023-04-20 15:39:55 +00:00
2008-09-23 14:07:02 +00:00
free ( nm ) ;
send_ok ( ssl ) ;
}
2009-02-12 10:37:00 +00:00
/** flush statistics */
static void
2018-06-12 07:43:52 +00:00
do_flush_stats ( RES * ssl , struct worker * worker )
2009-02-12 10:37:00 +00:00
{
worker_stats_clear ( worker ) ;
send_ok ( ssl ) ;
}
2011-10-26 15:46:23 +00:00
/**
* Local info for deletion functions
*/
struct del_info {
/** worker */
struct worker * worker ;
/** name to delete */
uint8_t * name ;
/** length */
size_t len ;
/** labels */
int labs ;
/** time to invalidate to */
2013-08-20 12:23:42 +00:00
time_t expired ;
2011-10-26 15:46:23 +00:00
/** number of rrsets removed */
size_t num_rrsets ;
/** number of msgs removed */
size_t num_msgs ;
/** number of key entries removed */
size_t num_keys ;
/** length of addr */
socklen_t addrlen ;
/** socket address for host deletion */
struct sockaddr_storage addr ;
} ;
/** callback to delete hosts in infra cache */
static void
infra_del_host ( struct lruhash_entry * e , void * arg )
{
/* entry is locked */
struct del_info * inf = ( struct del_info * ) arg ;
struct infra_key * k = ( struct infra_key * ) e - > key ;
if ( sockaddr_cmp ( & inf - > addr , inf - > addrlen , & k - > addr , k - > addrlen ) = = 0 ) {
struct infra_data * d = ( struct infra_data * ) e - > data ;
2012-03-02 09:05:36 +00:00
d - > probedelay = 0 ;
2012-03-02 11:57:53 +00:00
d - > timeout_A = 0 ;
d - > timeout_AAAA = 0 ;
d - > timeout_other = 0 ;
2012-03-02 09:05:36 +00:00
rtt_init ( & d - > rtt ) ;
2015-09-25 12:39:10 +00:00
if ( d - > ttl > inf - > expired ) {
2011-10-26 15:46:23 +00:00
d - > ttl = inf - > expired ;
inf - > num_keys + + ;
}
}
}
2010-10-26 09:08:33 +00:00
/** flush infra cache */
static void
2018-06-12 07:43:52 +00:00
do_flush_infra ( RES * ssl , struct worker * worker , char * arg )
2010-10-26 09:08:33 +00:00
{
struct sockaddr_storage addr ;
socklen_t len ;
2011-10-26 15:46:23 +00:00
struct del_info inf ;
2010-10-26 09:08:33 +00:00
if ( strcmp ( arg , " all " ) = = 0 ) {
slabhash_clear ( worker - > env . infra_cache - > hosts ) ;
send_ok ( ssl ) ;
return ;
}
if ( ! ipstrtoaddr ( arg , UNBOUND_DNS_PORT , & addr , & len ) ) {
( void ) ssl_printf ( ssl , " error parsing ip addr: '%s' \n " , arg ) ;
return ;
}
2011-10-26 15:46:23 +00:00
/* delete all entries from cache */
/* what we do is to set them all expired */
inf . worker = worker ;
inf . name = 0 ;
inf . len = 0 ;
inf . labs = 0 ;
inf . expired = * worker - > env . now ;
inf . expired - = 3 ; /* handle 3 seconds skew between threads */
inf . num_rrsets = 0 ;
inf . num_msgs = 0 ;
inf . num_keys = 0 ;
inf . addrlen = len ;
memmove ( & inf . addr , & addr , len ) ;
slabhash_traverse ( worker - > env . infra_cache - > hosts , 1 , & infra_del_host ,
& inf ) ;
2010-10-26 09:08:33 +00:00
send_ok ( ssl ) ;
}
2009-02-12 13:21:19 +00:00
/** flush requestlist */
static void
2018-06-12 07:43:52 +00:00
do_flush_requestlist ( RES * ssl , struct worker * worker )
2009-02-12 13:21:19 +00:00
{
mesh_delete_all ( worker - > env . mesh ) ;
send_ok ( ssl ) ;
}
2008-09-23 14:07:02 +00:00
/** callback to delete rrsets in a zone */
static void
zone_del_rrset ( struct lruhash_entry * e , void * arg )
{
/* entry is locked */
struct del_info * inf = ( struct del_info * ) arg ;
struct ub_packed_rrset_key * k = ( struct ub_packed_rrset_key * ) e - > key ;
if ( dname_subdomain_c ( k - > rk . dname , inf - > name ) ) {
2023-04-20 15:39:55 +00:00
struct packed_rrset_data * d =
2008-09-23 14:07:02 +00:00
( struct packed_rrset_data * ) e - > data ;
2015-09-25 12:39:10 +00:00
if ( d - > ttl > inf - > expired ) {
2010-03-24 14:44:35 +00:00
d - > ttl = inf - > expired ;
inf - > num_rrsets + + ;
}
2008-09-23 14:07:02 +00:00
}
}
2009-04-02 11:56:01 +00:00
/** callback to delete messages in a zone */
static void
zone_del_msg ( struct lruhash_entry * e , void * arg )
{
/* entry is locked */
struct del_info * inf = ( struct del_info * ) arg ;
struct msgreply_entry * k = ( struct msgreply_entry * ) e - > key ;
if ( dname_subdomain_c ( k - > key . qname , inf - > name ) ) {
struct reply_info * d = ( struct reply_info * ) e - > data ;
2015-09-25 12:39:10 +00:00
if ( d - > ttl > inf - > expired ) {
2010-03-24 14:44:35 +00:00
d - > ttl = inf - > expired ;
2018-04-09 07:39:59 +00:00
d - > prefetch_ttl = inf - > expired ;
2018-08-28 14:21:56 +00:00
d - > serve_expired_ttl = inf - > expired ;
2010-03-24 14:44:35 +00:00
inf - > num_msgs + + ;
}
2009-04-02 11:56:01 +00:00
}
}
2008-09-23 14:07:02 +00:00
/** callback to delete keys in zone */
static void
zone_del_kcache ( struct lruhash_entry * e , void * arg )
{
/* entry is locked */
struct del_info * inf = ( struct del_info * ) arg ;
struct key_entry_key * k = ( struct key_entry_key * ) e - > key ;
if ( dname_subdomain_c ( k - > name , inf - > name ) ) {
struct key_entry_data * d = ( struct key_entry_data * ) e - > data ;
2015-09-25 12:39:10 +00:00
if ( d - > ttl > inf - > expired ) {
2010-03-24 14:44:35 +00:00
d - > ttl = inf - > expired ;
inf - > num_keys + + ;
}
2008-09-23 14:07:02 +00:00
}
}
/** remove all rrsets and keys from zone from cache */
static void
2018-06-12 07:43:52 +00:00
do_flush_zone ( RES * ssl , struct worker * worker , char * arg )
2008-09-23 14:07:02 +00:00
{
uint8_t * nm ;
int nmlabs ;
size_t nmlen ;
struct del_info inf ;
if ( ! parse_arg_name ( ssl , arg , & nm , & nmlen , & nmlabs ) )
return ;
/* delete all RRs and key entries from zone */
/* what we do is to set them all expired */
inf . worker = worker ;
inf . name = nm ;
inf . len = nmlen ;
inf . labs = nmlabs ;
inf . expired = * worker - > env . now ;
inf . expired - = 3 ; /* handle 3 seconds skew between threads */
inf . num_rrsets = 0 ;
2009-04-02 11:56:01 +00:00
inf . num_msgs = 0 ;
2008-09-23 14:07:02 +00:00
inf . num_keys = 0 ;
2023-04-20 15:39:55 +00:00
slabhash_traverse ( & worker - > env . rrset_cache - > table , 1 ,
2008-09-23 14:07:02 +00:00
& zone_del_rrset , & inf ) ;
2009-04-02 11:56:01 +00:00
slabhash_traverse ( worker - > env . msg_cache , 1 , & zone_del_msg , & inf ) ;
2008-09-23 14:07:02 +00:00
/* and validator cache */
2009-09-01 14:47:57 +00:00
if ( worker - > env . key_cache ) {
2023-04-20 15:39:55 +00:00
slabhash_traverse ( worker - > env . key_cache - > slab , 1 ,
2009-09-01 14:47:57 +00:00
& zone_del_kcache , & inf ) ;
2008-09-23 14:07:02 +00:00
}
free ( nm ) ;
2014-04-10 11:20:41 +00:00
( void ) ssl_printf ( ssl , " ok removed %lu rrsets, %lu messages "
2023-04-20 15:39:55 +00:00
" and %lu key entries \n " , ( unsigned long ) inf . num_rrsets ,
2014-04-10 11:20:41 +00:00
( unsigned long ) inf . num_msgs , ( unsigned long ) inf . num_keys ) ;
2008-09-23 14:07:02 +00:00
}
2012-07-09 14:33:07 +00:00
/** callback to delete bogus rrsets */
static void
bogus_del_rrset ( struct lruhash_entry * e , void * arg )
{
/* entry is locked */
struct del_info * inf = ( struct del_info * ) arg ;
struct packed_rrset_data * d = ( struct packed_rrset_data * ) e - > data ;
if ( d - > security = = sec_status_bogus ) {
d - > ttl = inf - > expired ;
inf - > num_rrsets + + ;
}
}
/** callback to delete bogus messages */
static void
bogus_del_msg ( struct lruhash_entry * e , void * arg )
{
/* entry is locked */
struct del_info * inf = ( struct del_info * ) arg ;
struct reply_info * d = ( struct reply_info * ) e - > data ;
if ( d - > security = = sec_status_bogus ) {
d - > ttl = inf - > expired ;
inf - > num_msgs + + ;
}
}
/** callback to delete bogus keys */
static void
bogus_del_kcache ( struct lruhash_entry * e , void * arg )
{
/* entry is locked */
struct del_info * inf = ( struct del_info * ) arg ;
struct key_entry_data * d = ( struct key_entry_data * ) e - > data ;
if ( d - > isbad ) {
d - > ttl = inf - > expired ;
inf - > num_keys + + ;
}
}
2014-04-29 08:47:33 +00:00
/** remove all bogus rrsets, msgs and keys from cache */
2012-07-09 14:33:07 +00:00
static void
2018-06-12 07:43:52 +00:00
do_flush_bogus ( RES * ssl , struct worker * worker )
2012-07-09 14:33:07 +00:00
{
struct del_info inf ;
/* what we do is to set them all expired */
inf . worker = worker ;
inf . expired = * worker - > env . now ;
inf . expired - = 3 ; /* handle 3 seconds skew between threads */
inf . num_rrsets = 0 ;
inf . num_msgs = 0 ;
inf . num_keys = 0 ;
2023-04-20 15:39:55 +00:00
slabhash_traverse ( & worker - > env . rrset_cache - > table , 1 ,
2012-07-09 14:33:07 +00:00
& bogus_del_rrset , & inf ) ;
slabhash_traverse ( worker - > env . msg_cache , 1 , & bogus_del_msg , & inf ) ;
/* and validator cache */
if ( worker - > env . key_cache ) {
2023-04-20 15:39:55 +00:00
slabhash_traverse ( worker - > env . key_cache - > slab , 1 ,
2012-07-09 14:33:07 +00:00
& bogus_del_kcache , & inf ) ;
}
2014-04-10 11:20:41 +00:00
( void ) ssl_printf ( ssl , " ok removed %lu rrsets, %lu messages "
2023-04-20 15:39:55 +00:00
" and %lu key entries \n " , ( unsigned long ) inf . num_rrsets ,
2014-04-10 11:20:41 +00:00
( unsigned long ) inf . num_msgs , ( unsigned long ) inf . num_keys ) ;
2012-07-09 14:33:07 +00:00
}
2014-04-29 08:47:33 +00:00
/** callback to delete negative and servfail rrsets */
static void
negative_del_rrset ( struct lruhash_entry * e , void * arg )
{
/* entry is locked */
struct del_info * inf = ( struct del_info * ) arg ;
struct ub_packed_rrset_key * k = ( struct ub_packed_rrset_key * ) e - > key ;
struct packed_rrset_data * d = ( struct packed_rrset_data * ) e - > data ;
/* delete the parentside negative cache rrsets,
2017-09-15 14:29:28 +00:00
* these are nameserver rrsets that failed lookup , rdata empty */
2014-04-29 08:47:33 +00:00
if ( ( k - > rk . flags & PACKED_RRSET_PARENT_SIDE ) & & d - > count = = 1 & &
d - > rrsig_count = = 0 & & d - > rr_len [ 0 ] = = 0 ) {
d - > ttl = inf - > expired ;
inf - > num_rrsets + + ;
}
}
/** callback to delete negative and servfail messages */
static void
negative_del_msg ( struct lruhash_entry * e , void * arg )
{
/* entry is locked */
struct del_info * inf = ( struct del_info * ) arg ;
struct reply_info * d = ( struct reply_info * ) e - > data ;
/* rcode not NOERROR: NXDOMAIN, SERVFAIL, ..: an nxdomain or error
* or NOERROR rcode with ANCOUNT = = 0 : a NODATA answer */
if ( FLAGS_GET_RCODE ( d - > flags ) ! = 0 | | d - > an_numrrsets = = 0 ) {
d - > ttl = inf - > expired ;
inf - > num_msgs + + ;
}
}
/** callback to delete negative key entries */
static void
negative_del_kcache ( struct lruhash_entry * e , void * arg )
{
/* entry is locked */
struct del_info * inf = ( struct del_info * ) arg ;
struct key_entry_data * d = ( struct key_entry_data * ) e - > data ;
/* could be bad because of lookup failure on the DS, DNSKEY, which
* was nxdomain or servfail , and thus a result of negative lookups */
if ( d - > isbad ) {
d - > ttl = inf - > expired ;
inf - > num_keys + + ;
}
}
/** remove all negative(NODATA,NXDOMAIN), and servfail messages from cache */
static void
2018-06-12 07:43:52 +00:00
do_flush_negative ( RES * ssl , struct worker * worker )
2014-04-29 08:47:33 +00:00
{
struct del_info inf ;
/* what we do is to set them all expired */
inf . worker = worker ;
inf . expired = * worker - > env . now ;
inf . expired - = 3 ; /* handle 3 seconds skew between threads */
inf . num_rrsets = 0 ;
inf . num_msgs = 0 ;
inf . num_keys = 0 ;
2023-04-20 15:39:55 +00:00
slabhash_traverse ( & worker - > env . rrset_cache - > table , 1 ,
2014-04-29 08:47:33 +00:00
& negative_del_rrset , & inf ) ;
slabhash_traverse ( worker - > env . msg_cache , 1 , & negative_del_msg , & inf ) ;
/* and validator cache */
if ( worker - > env . key_cache ) {
2023-04-20 15:39:55 +00:00
slabhash_traverse ( worker - > env . key_cache - > slab , 1 ,
2014-04-29 08:47:33 +00:00
& negative_del_kcache , & inf ) ;
}
( void ) ssl_printf ( ssl , " ok removed %lu rrsets, %lu messages "
2023-04-20 15:39:55 +00:00
" and %lu key entries \n " , ( unsigned long ) inf . num_rrsets ,
2014-04-29 08:47:33 +00:00
( unsigned long ) inf . num_msgs , ( unsigned long ) inf . num_keys ) ;
}
2008-09-23 14:07:02 +00:00
/** remove name rrset from cache */
static void
2018-06-12 07:43:52 +00:00
do_flush_name ( RES * ssl , struct worker * w , char * arg )
2008-09-23 14:07:02 +00:00
{
uint8_t * nm ;
int nmlabs ;
size_t nmlen ;
if ( ! parse_arg_name ( ssl , arg , & nm , & nmlen , & nmlabs ) )
return ;
2009-06-11 09:43:23 +00:00
do_cache_remove ( w , nm , nmlen , LDNS_RR_TYPE_A , LDNS_RR_CLASS_IN ) ;
do_cache_remove ( w , nm , nmlen , LDNS_RR_TYPE_AAAA , LDNS_RR_CLASS_IN ) ;
do_cache_remove ( w , nm , nmlen , LDNS_RR_TYPE_NS , LDNS_RR_CLASS_IN ) ;
do_cache_remove ( w , nm , nmlen , LDNS_RR_TYPE_SOA , LDNS_RR_CLASS_IN ) ;
do_cache_remove ( w , nm , nmlen , LDNS_RR_TYPE_CNAME , LDNS_RR_CLASS_IN ) ;
do_cache_remove ( w , nm , nmlen , LDNS_RR_TYPE_DNAME , LDNS_RR_CLASS_IN ) ;
do_cache_remove ( w , nm , nmlen , LDNS_RR_TYPE_MX , LDNS_RR_CLASS_IN ) ;
do_cache_remove ( w , nm , nmlen , LDNS_RR_TYPE_PTR , LDNS_RR_CLASS_IN ) ;
do_cache_remove ( w , nm , nmlen , LDNS_RR_TYPE_SRV , LDNS_RR_CLASS_IN ) ;
do_cache_remove ( w , nm , nmlen , LDNS_RR_TYPE_NAPTR , LDNS_RR_CLASS_IN ) ;
2022-11-30 13:33:16 +00:00
do_cache_remove ( w , nm , nmlen , LDNS_RR_TYPE_SVCB , LDNS_RR_CLASS_IN ) ;
do_cache_remove ( w , nm , nmlen , LDNS_RR_TYPE_HTTPS , LDNS_RR_CLASS_IN ) ;
2023-04-20 15:39:55 +00:00
2008-09-23 14:07:02 +00:00
free ( nm ) ;
send_ok ( ssl ) ;
}
2010-02-26 15:40:46 +00:00
/** printout a delegation point info */
2009-02-12 16:11:53 +00:00
static int
2018-06-12 07:43:52 +00:00
ssl_print_name_dp ( RES * ssl , const char * str , uint8_t * nm , uint16_t dclass ,
2010-02-26 15:40:46 +00:00
struct delegpt * dp )
2009-02-12 16:11:53 +00:00
{
2009-02-13 15:26:37 +00:00
char buf [ 257 ] ;
struct delegpt_ns * ns ;
struct delegpt_addr * a ;
int f = 0 ;
2010-02-26 15:40:46 +00:00
if ( str ) { /* print header for forward, stub */
2013-12-03 09:11:16 +00:00
char * c = sldns_wire2str_class ( dclass ) ;
2010-02-26 15:40:46 +00:00
dname_str ( nm , buf ) ;
2014-05-05 14:47:08 +00:00
if ( ! ssl_printf ( ssl , " %s %s %s " , buf , ( c ? c : " CLASS?? " ) , str ) ) {
2010-02-26 15:40:46 +00:00
free ( c ) ;
return 0 ;
}
free ( c ) ;
}
2009-02-13 15:26:37 +00:00
for ( ns = dp - > nslist ; ns ; ns = ns - > next ) {
dname_str ( ns - > name , buf ) ;
if ( ! ssl_printf ( ssl , " %s%s " , ( f ? " " : " " ) , buf ) )
return 0 ;
f = 1 ;
}
for ( a = dp - > target_list ; a ; a = a - > next_target ) {
addr_to_str ( & a - > addr , a - > addrlen , buf , sizeof ( buf ) ) ;
if ( ! ssl_printf ( ssl , " %s%s " , ( f ? " " : " " ) , buf ) )
return 0 ;
f = 1 ;
}
return ssl_printf ( ssl , " \n " ) ;
}
2010-02-26 15:40:46 +00:00
/** print root forwards */
static int
2018-06-12 07:43:52 +00:00
print_root_fwds ( RES * ssl , struct iter_forwards * fwds , uint8_t * root )
2010-02-26 15:40:46 +00:00
{
struct delegpt * dp ;
dp = forwards_lookup ( fwds , root , LDNS_RR_CLASS_IN ) ;
if ( ! dp )
return ssl_printf ( ssl , " off (using root hints) \ n " ) ;
/* if dp is returned it must be the root */
log_assert ( query_dname_compare ( dp - > name , root ) = = 0 ) ;
return ssl_print_name_dp ( ssl , NULL , root , LDNS_RR_CLASS_IN , dp ) ;
}
2009-02-13 15:26:37 +00:00
/** parse args into delegpt */
static struct delegpt *
2022-02-01 13:44:29 +00:00
parse_delegpt ( RES * ssl , char * args , uint8_t * nm )
2009-02-13 15:26:37 +00:00
{
/* parse args and add in */
char * p = args ;
char * todo ;
2012-02-15 14:35:28 +00:00
struct delegpt * dp = delegpt_create_mlc ( nm ) ;
2009-02-13 15:26:37 +00:00
struct sockaddr_storage addr ;
socklen_t addrlen ;
2018-04-19 12:10:05 +00:00
char * auth_name ;
2012-02-14 15:41:09 +00:00
if ( ! dp ) {
2009-02-13 15:26:37 +00:00
( void ) ssl_printf ( ssl , " error out of memory \n " ) ;
return NULL ;
}
while ( p ) {
todo = p ;
p = strchr ( p , ' ' ) ; /* find next spot, if any */
if ( p ) {
* p + + = 0 ; /* end this spot */
p = skipwhite ( p ) ; /* position at next spot */
}
/* parse address */
2018-04-19 12:10:05 +00:00
if ( ! authextstrtoaddr ( todo , & addr , & addrlen , & auth_name ) ) {
2022-02-01 13:44:29 +00:00
uint8_t * dname = NULL ;
int port ;
dname = authextstrtodname ( todo , & port , & auth_name ) ;
if ( ! dname ) {
2012-02-15 14:35:28 +00:00
( void ) ssl_printf ( ssl , " error cannot parse "
2022-02-01 13:44:29 +00:00
" '%s' \n " , todo ) ;
delegpt_free_mlc ( dp ) ;
return NULL ;
}
# if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
if ( auth_name )
log_err ( " no name verification functionality in "
" ssl library, ignored name for %s " , todo ) ;
# endif
if ( ! delegpt_add_ns_mlc ( dp , dname , 0 , auth_name , port ) ) {
( void ) ssl_printf ( ssl , " error out of memory \n " ) ;
free ( dname ) ;
2012-02-15 14:35:28 +00:00
delegpt_free_mlc ( dp ) ;
return NULL ;
}
} else {
2019-02-07 08:34:28 +00:00
# if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
2018-07-17 12:26:32 +00:00
if ( auth_name )
2022-02-01 13:44:29 +00:00
log_err ( " no name verification functionality in "
2018-07-17 12:30:53 +00:00
" ssl library, ignored name for %s " , todo ) ;
2018-07-17 12:26:32 +00:00
# endif
2012-02-15 14:35:28 +00:00
/* add address */
2018-04-19 12:10:05 +00:00
if ( ! delegpt_add_addr_mlc ( dp , & addr , addrlen , 0 , 0 ,
2022-02-01 13:44:29 +00:00
auth_name , - 1 ) ) {
2012-02-15 14:35:28 +00:00
( void ) ssl_printf ( ssl , " error out of memory \n " ) ;
delegpt_free_mlc ( dp ) ;
return NULL ;
}
2009-02-12 16:11:53 +00:00
}
}
2015-07-09 09:45:08 +00:00
dp - > has_parent_side_NS = 1 ;
2009-02-13 15:26:37 +00:00
return dp ;
}
/** do the status command */
static void
2018-06-12 07:43:52 +00:00
do_forward ( RES * ssl , struct worker * worker , char * args )
2009-02-13 15:26:37 +00:00
{
struct iter_forwards * fwd = worker - > env . fwds ;
uint8_t * root = ( uint8_t * ) " \000 " ;
if ( ! fwd ) {
( void ) ssl_printf ( ssl , " error: structure not allocated \n " ) ;
return ;
}
if ( args = = NULL | | args [ 0 ] = = 0 ) {
( void ) print_root_fwds ( ssl , fwd , root ) ;
return ;
}
/* set root forwards for this thread. since we are in remote control
* the actual mesh is not running , so we can freely edit it . */
/* delete all the existing queries first */
mesh_delete_all ( worker - > env . mesh ) ;
if ( strcmp ( args , " off " ) = = 0 ) {
forwards_delete_zone ( fwd , LDNS_RR_CLASS_IN , root ) ;
} else {
struct delegpt * dp ;
2022-02-01 13:44:29 +00:00
if ( ! ( dp = parse_delegpt ( ssl , args , root ) ) )
2009-02-13 15:26:37 +00:00
return ;
if ( ! forwards_add_zone ( fwd , LDNS_RR_CLASS_IN , dp ) ) {
( void ) ssl_printf ( ssl , " error out of memory \n " ) ;
return ;
}
}
send_ok ( ssl ) ;
2009-02-12 16:11:53 +00:00
}
2012-02-15 14:35:28 +00:00
static int
2018-06-12 07:43:52 +00:00
parse_fs_args ( RES * ssl , char * args , uint8_t * * nm , struct delegpt * * dp ,
2012-02-15 14:35:28 +00:00
int * insecure , int * prime )
{
char * zonename ;
char * rest ;
size_t nmlen ;
int nmlabs ;
/* parse all -x args */
while ( args [ 0 ] = = ' + ' ) {
if ( ! find_arg2 ( ssl , args , & rest ) )
return 0 ;
while ( * ( + + args ) ! = 0 ) {
if ( * args = = ' i ' & & insecure )
* insecure = 1 ;
else if ( * args = = ' p ' & & prime )
* prime = 1 ;
else {
( void ) ssl_printf ( ssl , " error: unknown option %s \n " , args ) ;
return 0 ;
}
}
args = rest ;
}
/* parse name */
if ( dp ) {
if ( ! find_arg2 ( ssl , args , & rest ) )
return 0 ;
zonename = args ;
args = rest ;
} else zonename = args ;
if ( ! parse_arg_name ( ssl , zonename , nm , & nmlen , & nmlabs ) )
return 0 ;
/* parse dp */
if ( dp ) {
2022-02-01 13:44:29 +00:00
if ( ! ( * dp = parse_delegpt ( ssl , args , * nm ) ) ) {
2012-02-15 14:35:28 +00:00
free ( * nm ) ;
return 0 ;
}
}
return 1 ;
}
/** do the forward_add command */
static void
2018-06-12 07:43:52 +00:00
do_forward_add ( RES * ssl , struct worker * worker , char * args )
2012-02-15 14:35:28 +00:00
{
struct iter_forwards * fwd = worker - > env . fwds ;
int insecure = 0 ;
uint8_t * nm = NULL ;
struct delegpt * dp = NULL ;
2012-02-15 15:33:24 +00:00
if ( ! parse_fs_args ( ssl , args , & nm , & dp , & insecure , NULL ) )
2012-02-15 14:35:28 +00:00
return ;
2014-01-16 13:04:34 +00:00
if ( insecure & & worker - > env . anchors ) {
2012-02-15 14:35:28 +00:00
if ( ! anchors_add_insecure ( worker - > env . anchors , LDNS_RR_CLASS_IN ,
nm ) ) {
( void ) ssl_printf ( ssl , " error out of memory \n " ) ;
delegpt_free_mlc ( dp ) ;
free ( nm ) ;
return ;
}
}
if ( ! forwards_add_zone ( fwd , LDNS_RR_CLASS_IN , dp ) ) {
( void ) ssl_printf ( ssl , " error out of memory \n " ) ;
free ( nm ) ;
return ;
}
free ( nm ) ;
send_ok ( ssl ) ;
}
/** do the forward_remove command */
static void
2018-06-12 07:43:52 +00:00
do_forward_remove ( RES * ssl , struct worker * worker , char * args )
2012-02-15 14:35:28 +00:00
{
struct iter_forwards * fwd = worker - > env . fwds ;
int insecure = 0 ;
uint8_t * nm = NULL ;
2012-02-15 15:33:24 +00:00
if ( ! parse_fs_args ( ssl , args , & nm , NULL , & insecure , NULL ) )
2012-02-15 14:35:28 +00:00
return ;
2014-01-16 13:04:34 +00:00
if ( insecure & & worker - > env . anchors )
2012-02-15 14:35:28 +00:00
anchors_delete_insecure ( worker - > env . anchors , LDNS_RR_CLASS_IN ,
nm ) ;
forwards_delete_zone ( fwd , LDNS_RR_CLASS_IN , nm ) ;
free ( nm ) ;
send_ok ( ssl ) ;
}
/** do the stub_add command */
static void
2018-06-12 07:43:52 +00:00
do_stub_add ( RES * ssl , struct worker * worker , char * args )
2012-02-15 14:35:28 +00:00
{
struct iter_forwards * fwd = worker - > env . fwds ;
int insecure = 0 , prime = 0 ;
uint8_t * nm = NULL ;
struct delegpt * dp = NULL ;
2012-02-15 15:33:24 +00:00
if ( ! parse_fs_args ( ssl , args , & nm , & dp , & insecure , & prime ) )
2012-02-15 14:35:28 +00:00
return ;
2014-01-16 13:04:34 +00:00
if ( insecure & & worker - > env . anchors ) {
2012-02-15 14:35:28 +00:00
if ( ! anchors_add_insecure ( worker - > env . anchors , LDNS_RR_CLASS_IN ,
nm ) ) {
( void ) ssl_printf ( ssl , " error out of memory \n " ) ;
delegpt_free_mlc ( dp ) ;
free ( nm ) ;
return ;
}
}
if ( ! forwards_add_stub_hole ( fwd , LDNS_RR_CLASS_IN , nm ) ) {
2014-01-16 13:04:34 +00:00
if ( insecure & & worker - > env . anchors )
anchors_delete_insecure ( worker - > env . anchors ,
LDNS_RR_CLASS_IN , nm ) ;
2012-02-15 14:35:28 +00:00
( void ) ssl_printf ( ssl , " error out of memory \n " ) ;
delegpt_free_mlc ( dp ) ;
free ( nm ) ;
return ;
}
2012-02-16 09:55:50 +00:00
if ( ! hints_add_stub ( worker - > env . hints , LDNS_RR_CLASS_IN , dp , ! prime ) ) {
2012-02-15 14:35:28 +00:00
( void ) ssl_printf ( ssl , " error out of memory \n " ) ;
forwards_delete_stub_hole ( fwd , LDNS_RR_CLASS_IN , nm ) ;
2014-01-16 13:04:34 +00:00
if ( insecure & & worker - > env . anchors )
anchors_delete_insecure ( worker - > env . anchors ,
LDNS_RR_CLASS_IN , nm ) ;
2012-02-15 14:35:28 +00:00
free ( nm ) ;
return ;
}
free ( nm ) ;
send_ok ( ssl ) ;
}
/** do the stub_remove command */
static void
2018-06-12 07:43:52 +00:00
do_stub_remove ( RES * ssl , struct worker * worker , char * args )
2012-02-15 14:35:28 +00:00
{
struct iter_forwards * fwd = worker - > env . fwds ;
int insecure = 0 ;
uint8_t * nm = NULL ;
2012-02-15 15:33:24 +00:00
if ( ! parse_fs_args ( ssl , args , & nm , NULL , & insecure , NULL ) )
2012-02-15 14:35:28 +00:00
return ;
2014-01-16 13:04:34 +00:00
if ( insecure & & worker - > env . anchors )
2012-02-15 14:35:28 +00:00
anchors_delete_insecure ( worker - > env . anchors , LDNS_RR_CLASS_IN ,
nm ) ;
forwards_delete_stub_hole ( fwd , LDNS_RR_CLASS_IN , nm ) ;
2012-02-16 09:55:50 +00:00
hints_delete_stub ( worker - > env . hints , LDNS_RR_CLASS_IN , nm ) ;
2012-02-15 14:35:28 +00:00
free ( nm ) ;
send_ok ( ssl ) ;
}
2013-04-26 14:14:07 +00:00
/** do the insecure_add command */
static void
2018-06-12 07:43:52 +00:00
do_insecure_add ( RES * ssl , struct worker * worker , char * arg )
2013-04-26 14:14:07 +00:00
{
size_t nmlen ;
int nmlabs ;
uint8_t * nm = NULL ;
if ( ! parse_arg_name ( ssl , arg , & nm , & nmlen , & nmlabs ) )
return ;
2014-01-16 13:04:34 +00:00
if ( worker - > env . anchors ) {
if ( ! anchors_add_insecure ( worker - > env . anchors ,
LDNS_RR_CLASS_IN , nm ) ) {
( void ) ssl_printf ( ssl , " error out of memory \n " ) ;
free ( nm ) ;
return ;
}
2013-04-26 14:14:07 +00:00
}
free ( nm ) ;
send_ok ( ssl ) ;
}
/** do the insecure_remove command */
static void
2018-06-12 07:43:52 +00:00
do_insecure_remove ( RES * ssl , struct worker * worker , char * arg )
2013-04-26 14:14:07 +00:00
{
size_t nmlen ;
int nmlabs ;
uint8_t * nm = NULL ;
if ( ! parse_arg_name ( ssl , arg , & nm , & nmlen , & nmlabs ) )
return ;
2014-01-16 13:04:34 +00:00
if ( worker - > env . anchors )
anchors_delete_insecure ( worker - > env . anchors ,
LDNS_RR_CLASS_IN , nm ) ;
2013-04-26 14:14:07 +00:00
free ( nm ) ;
send_ok ( ssl ) ;
}
2015-04-07 13:50:09 +00:00
static void
2018-06-12 07:43:52 +00:00
do_insecure_list ( RES * ssl , struct worker * worker )
2015-04-07 13:50:09 +00:00
{
char buf [ 257 ] ;
struct trust_anchor * a ;
if ( worker - > env . anchors ) {
RBTREE_FOR ( a , struct trust_anchor * , worker - > env . anchors - > tree ) {
if ( a - > numDS = = 0 & & a - > numDNSKEY = = 0 ) {
dname_str ( a - > name , buf ) ;
ssl_printf ( ssl , " %s \n " , buf ) ;
}
}
}
}
2008-12-17 14:03:49 +00:00
/** do the status command */
static void
2018-06-12 07:43:52 +00:00
do_status ( RES * ssl , struct worker * worker )
2008-12-17 14:03:49 +00:00
{
int i ;
time_t uptime ;
if ( ! ssl_printf ( ssl , " version: %s \n " , PACKAGE_VERSION ) )
return ;
if ( ! ssl_printf ( ssl , " verbosity: %d \n " , verbosity ) )
return ;
if ( ! ssl_printf ( ssl , " threads: %d \n " , worker - > daemon - > num ) )
return ;
if ( ! ssl_printf ( ssl , " modules: %d [ " , worker - > daemon - > mods . num ) )
return ;
for ( i = 0 ; i < worker - > daemon - > mods . num ; i + + ) {
if ( ! ssl_printf ( ssl , " %s " , worker - > daemon - > mods . mod [ i ] - > name ) )
return ;
}
if ( ! ssl_printf ( ssl , " ] \n " ) )
return ;
uptime = ( time_t ) time ( NULL ) - ( time_t ) worker - > daemon - > time_boot . tv_sec ;
2014-01-16 16:01:37 +00:00
if ( ! ssl_printf ( ssl , " uptime: " ARG_LL " d seconds \n " , ( long long ) uptime ) )
2008-12-17 14:03:49 +00:00
return ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " options:%s%s%s%s \n " ,
2014-06-26 08:48:51 +00:00
( worker - > daemon - > reuseport ? " reuseport " : " " ) ,
2018-06-18 09:04:35 +00:00
( worker - > daemon - > rc - > accept_list ? " control " : " " ) ,
( worker - > daemon - > rc - > accept_list & & worker - > daemon - > rc - > use_cert ? " (ssl) " : " " ) ,
( worker - > daemon - > rc - > accept_list & & worker - > daemon - > cfg - > control_ifs . first & & worker - > daemon - > cfg - > control_ifs . first - > str & & worker - > daemon - > cfg - > control_ifs . first - > str [ 0 ] = = ' / ' ? " (namedpipe) " : " " )
) )
2014-06-26 08:48:51 +00:00
return ;
2008-12-17 14:03:49 +00:00
if ( ! ssl_printf ( ssl , " unbound (pid %d) is running... \n " ,
( int ) getpid ( ) ) )
return ;
}
2009-02-10 15:11:54 +00:00
/** get age for the mesh state */
static void
2023-04-20 15:39:55 +00:00
get_mesh_age ( struct mesh_state * m , char * buf , size_t len ,
2009-02-10 15:11:54 +00:00
struct module_env * env )
{
if ( m - > reply_list ) {
struct timeval d ;
struct mesh_reply * r = m - > reply_list ;
/* last reply is the oldest */
while ( r & & r - > next )
r = r - > next ;
timeval_subtract ( & d , env - > now_tv , & r - > start_time ) ;
2014-01-16 16:01:37 +00:00
snprintf ( buf , len , ARG_LL " d.%6.6d " ,
( long long ) d . tv_sec , ( int ) d . tv_usec ) ;
2009-02-10 15:11:54 +00:00
} else {
snprintf ( buf , len , " - " ) ;
}
}
/** get status of a mesh state */
static void
2023-04-20 15:39:55 +00:00
get_mesh_status ( struct mesh_area * mesh , struct mesh_state * m ,
2009-02-10 15:11:54 +00:00
char * buf , size_t len )
{
enum module_ext_state s = m - > s . ext_state [ m - > s . curmod ] ;
const char * modname = mesh - > mods . mod [ m - > s . curmod ] - > name ;
size_t l ;
if ( strcmp ( modname , " iterator " ) = = 0 & & s = = module_wait_reply & &
m - > s . minfo [ m - > s . curmod ] ) {
/* break into iterator to find out who its waiting for */
struct iter_qstate * qstate = ( struct iter_qstate * )
m - > s . minfo [ m - > s . curmod ] ;
struct outbound_list * ol = & qstate - > outlist ;
struct outbound_entry * e ;
snprintf ( buf , len , " %s wait for " , modname ) ;
l = strlen ( buf ) ;
buf + = l ; len - = l ;
if ( ol - > first = = NULL )
snprintf ( buf , len , " (empty_list) " ) ;
for ( e = ol - > first ; e ; e = e - > next ) {
snprintf ( buf , len , " " ) ;
l = strlen ( buf ) ;
buf + = l ; len - = l ;
2023-04-20 15:39:55 +00:00
addr_to_str ( & e - > qsent - > addr , e - > qsent - > addrlen ,
2009-02-13 15:26:37 +00:00
buf , len ) ;
2009-02-10 15:11:54 +00:00
l = strlen ( buf ) ;
buf + = l ; len - = l ;
}
} else if ( s = = module_wait_subquery ) {
/* look in subs from mesh state to see what */
char nm [ 257 ] ;
struct mesh_state_ref * sub ;
snprintf ( buf , len , " %s wants " , modname ) ;
l = strlen ( buf ) ;
buf + = l ; len - = l ;
if ( m - > sub_set . count = = 0 )
snprintf ( buf , len , " (empty_list) " ) ;
RBTREE_FOR ( sub , struct mesh_state_ref * , & m - > sub_set ) {
2013-12-03 09:11:16 +00:00
char * t = sldns_wire2str_type ( sub - > s - > s . qinfo . qtype ) ;
char * c = sldns_wire2str_class ( sub - > s - > s . qinfo . qclass ) ;
2009-02-10 15:11:54 +00:00
dname_str ( sub - > s - > s . qinfo . qname , nm ) ;
2013-10-31 15:09:26 +00:00
snprintf ( buf , len , " %s %s %s " , ( t ? t : " TYPE?? " ) ,
( c ? c : " CLASS?? " ) , nm ) ;
2009-02-10 15:11:54 +00:00
l = strlen ( buf ) ;
buf + = l ; len - = l ;
free ( t ) ;
free ( c ) ;
}
} else {
snprintf ( buf , len , " %s is %s " , modname , strextstate ( s ) ) ;
}
}
/** do the dump_requestlist command */
static void
2018-06-12 07:43:52 +00:00
do_dump_requestlist ( RES * ssl , struct worker * worker )
2009-02-10 15:11:54 +00:00
{
struct mesh_area * mesh ;
struct mesh_state * m ;
int num = 0 ;
char buf [ 257 ] ;
char timebuf [ 32 ] ;
char statbuf [ 10240 ] ;
if ( ! ssl_printf ( ssl , " thread #%d \n " , worker - > thread_num ) )
return ;
if ( ! ssl_printf ( ssl , " # type cl name seconds module status \n " ) )
return ;
/* show worker mesh contents */
mesh = worker - > env . mesh ;
if ( ! mesh ) return ;
RBTREE_FOR ( m , struct mesh_state * , & mesh - > all ) {
2013-12-03 09:11:16 +00:00
char * t = sldns_wire2str_type ( m - > s . qinfo . qtype ) ;
char * c = sldns_wire2str_class ( m - > s . qinfo . qclass ) ;
2009-02-10 15:11:54 +00:00
dname_str ( m - > s . qinfo . qname , buf ) ;
get_mesh_age ( m , timebuf , sizeof ( timebuf ) , & worker - > env ) ;
get_mesh_status ( mesh , m , statbuf , sizeof ( statbuf ) ) ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " %3d %4s %2s %s %s %s \n " ,
2013-10-31 15:09:26 +00:00
num , ( t ? t : " TYPE?? " ) , ( c ? c : " CLASS?? " ) , buf , timebuf ,
statbuf ) ) {
2009-02-10 15:11:54 +00:00
free ( t ) ;
free ( c ) ;
return ;
}
num + + ;
free ( t ) ;
free ( c ) ;
}
}
2010-10-26 09:08:33 +00:00
/** structure for argument data for dump infra host */
struct infra_arg {
/** the infra cache */
struct infra_cache * infra ;
/** the SSL connection */
2018-06-12 07:43:52 +00:00
RES * ssl ;
2010-10-26 09:08:33 +00:00
/** the time now */
2013-08-20 12:23:42 +00:00
time_t now ;
2014-07-16 10:07:26 +00:00
/** ssl failure? stop writing and skip the rest. If the tcp
* connection is broken , and writes fail , we then stop writing . */
int ssl_failed ;
2010-10-26 09:08:33 +00:00
} ;
/** callback for every host element in the infra cache */
static void
dump_infra_host ( struct lruhash_entry * e , void * arg )
{
struct infra_arg * a = ( struct infra_arg * ) arg ;
2011-10-26 15:46:23 +00:00
struct infra_key * k = ( struct infra_key * ) e - > key ;
struct infra_data * d = ( struct infra_data * ) e - > data ;
2010-10-26 09:08:33 +00:00
char ip_str [ 1024 ] ;
2011-10-26 15:46:23 +00:00
char name [ 257 ] ;
2017-06-26 12:31:49 +00:00
int port ;
2014-07-16 10:07:26 +00:00
if ( a - > ssl_failed )
return ;
2010-10-26 09:08:33 +00:00
addr_to_str ( & k - > addr , k - > addrlen , ip_str , sizeof ( ip_str ) ) ;
2011-10-26 15:46:23 +00:00
dname_str ( k - > zonename , name ) ;
2017-06-26 12:31:49 +00:00
port = ( int ) ntohs ( ( ( struct sockaddr_in * ) & k - > addr ) - > sin_port ) ;
if ( port ! = UNBOUND_DNS_PORT ) {
snprintf ( ip_str + strlen ( ip_str ) , sizeof ( ip_str ) - strlen ( ip_str ) ,
" @%d " , port ) ;
}
2010-10-26 09:08:33 +00:00
/* skip expired stuff (only backed off) */
if ( d - > ttl < a - > now ) {
2010-10-27 08:09:22 +00:00
if ( d - > rtt . rto > = USEFUL_SERVER_TOP_TIMEOUT ) {
2011-10-26 15:46:23 +00:00
if ( ! ssl_printf ( a - > ssl , " %s %s expired rto %d \n " , ip_str ,
2014-07-16 10:07:26 +00:00
name , d - > rtt . rto ) ) {
a - > ssl_failed = 1 ;
return ;
}
2010-10-27 08:09:22 +00:00
}
2010-10-26 09:08:33 +00:00
return ;
}
2014-04-10 11:20:41 +00:00
if ( ! ssl_printf ( a - > ssl , " %s %s ttl %lu ping %d var %d rtt %d rto %d "
2012-02-10 14:48:09 +00:00
" tA %d tAAAA %d tother %d "
2011-10-26 15:46:23 +00:00
" ednsknown %d edns %d delay %d lame dnssec %d rec %d A %d "
2014-04-10 11:20:41 +00:00
" other %d \n " , ip_str , name , ( unsigned long ) ( d - > ttl - a - > now ) ,
2010-10-26 09:08:33 +00:00
d - > rtt . srtt , d - > rtt . rttvar , rtt_notimeout ( & d - > rtt ) , d - > rtt . rto ,
2012-02-10 14:48:09 +00:00
d - > timeout_A , d - > timeout_AAAA , d - > timeout_other ,
2010-10-26 15:02:08 +00:00
( int ) d - > edns_lame_known , ( int ) d - > edns_version ,
2015-03-26 09:46:06 +00:00
( int ) ( a - > now < d - > probedelay ? ( d - > probedelay - a - > now ) : 0 ) ,
2011-10-26 15:46:23 +00:00
( int ) d - > isdnsseclame , ( int ) d - > rec_lame , ( int ) d - > lame_type_A ,
2014-07-16 10:07:26 +00:00
( int ) d - > lame_other ) ) {
a - > ssl_failed = 1 ;
2010-10-26 09:08:33 +00:00
return ;
2014-07-16 10:07:26 +00:00
}
2010-10-26 09:08:33 +00:00
}
/** do the dump_infra command */
static void
2018-06-12 07:43:52 +00:00
do_dump_infra ( RES * ssl , struct worker * worker )
2010-10-26 09:08:33 +00:00
{
struct infra_arg arg ;
arg . infra = worker - > env . infra_cache ;
arg . ssl = ssl ;
arg . now = * worker - > env . now ;
2014-07-16 10:07:26 +00:00
arg . ssl_failed = 0 ;
2010-10-26 09:08:33 +00:00
slabhash_traverse ( arg . infra - > hosts , 0 , & dump_infra_host , ( void * ) & arg ) ;
}
2010-02-18 16:40:22 +00:00
/** do the log_reopen command */
static void
2018-06-12 07:43:52 +00:00
do_log_reopen ( RES * ssl , struct worker * worker )
2010-02-18 16:40:22 +00:00
{
struct config_file * cfg = worker - > env . cfg ;
send_ok ( ssl ) ;
log_init ( cfg - > logfile , cfg - > use_syslog , cfg - > chrootdir ) ;
}
2018-06-15 13:42:41 +00:00
/** do the auth_zone_reload command */
static void
do_auth_zone_reload ( RES * ssl , struct worker * worker , char * arg )
{
size_t nmlen ;
int nmlabs ;
uint8_t * nm = NULL ;
struct auth_zones * az = worker - > env . auth_zones ;
struct auth_zone * z = NULL ;
2020-10-23 09:44:28 +00:00
struct auth_xfer * xfr = NULL ;
2020-10-23 09:20:08 +00:00
char * reason = NULL ;
2018-06-15 13:42:41 +00:00
if ( ! parse_arg_name ( ssl , arg , & nm , & nmlen , & nmlabs ) )
return ;
if ( az ) {
lock_rw_rdlock ( & az - > lock ) ;
z = auth_zone_find ( az , nm , nmlen , LDNS_RR_CLASS_IN ) ;
if ( z ) {
lock_rw_wrlock ( & z - > lock ) ;
}
2020-10-23 09:44:28 +00:00
xfr = auth_xfer_find ( az , nm , nmlen , LDNS_RR_CLASS_IN ) ;
if ( xfr ) {
lock_basic_lock ( & xfr - > lock ) ;
}
2018-06-15 13:42:41 +00:00
lock_rw_unlock ( & az - > lock ) ;
}
free ( nm ) ;
if ( ! z ) {
2020-10-23 09:44:28 +00:00
if ( xfr ) {
lock_basic_unlock ( & xfr - > lock ) ;
}
2018-06-15 13:42:41 +00:00
( void ) ssl_printf ( ssl , " error no auth-zone %s \n " , arg ) ;
return ;
}
2018-11-22 15:51:09 +00:00
if ( ! auth_zone_read_zonefile ( z , worker - > env . cfg ) ) {
2018-06-15 13:42:41 +00:00
lock_rw_unlock ( & z - > lock ) ;
2020-10-23 09:44:28 +00:00
if ( xfr ) {
lock_basic_unlock ( & xfr - > lock ) ;
}
2018-06-15 13:42:41 +00:00
( void ) ssl_printf ( ssl , " error failed to read %s \n " , arg ) ;
return ;
}
2020-10-23 09:44:28 +00:00
z - > zone_expired = 0 ;
if ( xfr ) {
xfr - > zone_expired = 0 ;
if ( ! xfr_find_soa ( z , xfr ) ) {
if ( z - > data . count = = 0 ) {
lock_rw_unlock ( & z - > lock ) ;
lock_basic_unlock ( & xfr - > lock ) ;
( void ) ssl_printf ( ssl , " zone %s has no contents \n " , arg ) ;
return ;
}
lock_rw_unlock ( & z - > lock ) ;
lock_basic_unlock ( & xfr - > lock ) ;
( void ) ssl_printf ( ssl , " error: no SOA in zone after read %s \n " , arg ) ;
return ;
}
if ( xfr - > have_zone )
xfr - > lease_time = * worker - > env . now ;
lock_basic_unlock ( & xfr - > lock ) ;
}
2020-10-23 09:20:08 +00:00
auth_zone_verify_zonemd ( z , & worker - > env , & worker - > env . mesh - > mods ,
& reason , 0 , 0 ) ;
2020-10-23 09:44:28 +00:00
if ( reason & & z - > zone_expired ) {
2020-10-23 09:47:00 +00:00
lock_rw_unlock ( & z - > lock ) ;
2020-10-23 09:20:08 +00:00
( void ) ssl_printf ( ssl , " error zonemd for %s failed: %s \n " ,
arg , reason ) ;
2020-10-23 09:47:00 +00:00
free ( reason ) ;
return ;
2020-10-23 09:20:08 +00:00
} else if ( reason & & strcmp ( reason , " ZONEMD verification successful " )
= = 0 ) {
( void ) ssl_printf ( ssl , " %s: %s \n " , arg , reason ) ;
}
2018-06-15 13:42:41 +00:00
lock_rw_unlock ( & z - > lock ) ;
2020-10-23 09:47:00 +00:00
free ( reason ) ;
2018-06-15 13:42:41 +00:00
send_ok ( ssl ) ;
}
2018-06-15 15:01:31 +00:00
/** do the auth_zone_transfer command */
static void
do_auth_zone_transfer ( RES * ssl , struct worker * worker , char * arg )
{
size_t nmlen ;
int nmlabs ;
uint8_t * nm = NULL ;
struct auth_zones * az = worker - > env . auth_zones ;
if ( ! parse_arg_name ( ssl , arg , & nm , & nmlen , & nmlabs ) )
return ;
if ( ! az | | ! auth_zones_startprobesequence ( az , & worker - > env , nm , nmlen ,
LDNS_RR_CLASS_IN ) ) {
( void ) ssl_printf ( ssl , " error zone xfr task not found %s \n " , arg ) ;
2020-01-30 13:56:48 +00:00
free ( nm ) ;
2018-06-15 15:01:31 +00:00
return ;
}
2020-01-30 14:45:54 +00:00
free ( nm ) ;
2018-06-15 15:01:31 +00:00
send_ok ( ssl ) ;
}
2023-04-20 15:39:55 +00:00
2010-02-23 13:53:10 +00:00
/** do the set_option command */
static void
2018-06-12 07:43:52 +00:00
do_set_option ( RES * ssl , struct worker * worker , char * arg )
2010-02-23 13:53:10 +00:00
{
char * arg2 ;
if ( ! find_arg2 ( ssl , arg , & arg2 ) )
return ;
if ( ! config_set_option ( worker - > env . cfg , arg , arg2 ) ) {
( void ) ssl_printf ( ssl , " error setting option \n " ) ;
return ;
}
2016-10-25 11:44:03 +00:00
/* effectuate some arguments */
if ( strcmp ( arg , " val-override-date: " ) = = 0 ) {
int m = modstack_find ( & worker - > env . mesh - > mods , " validator " ) ;
struct val_env * val_env = NULL ;
if ( m ! = - 1 ) val_env = ( struct val_env * ) worker - > env . modinfo [ m ] ;
if ( val_env )
val_env - > date_override = worker - > env . cfg - > val_date_override ;
}
2010-02-23 13:53:10 +00:00
send_ok ( ssl ) ;
}
/* routine to printout option values over SSL */
void remote_get_opt_ssl ( char * line , void * arg )
{
2018-06-12 07:43:52 +00:00
RES * ssl = ( RES * ) arg ;
2010-02-23 13:53:10 +00:00
( void ) ssl_printf ( ssl , " %s \n " , line ) ;
}
/** do the get_option command */
static void
2018-06-12 07:43:52 +00:00
do_get_option ( RES * ssl , struct worker * worker , char * arg )
2010-02-23 13:53:10 +00:00
{
int r ;
r = config_get_option ( worker - > env . cfg , arg , remote_get_opt_ssl , ssl ) ;
if ( ! r ) {
( void ) ssl_printf ( ssl , " error unknown option \n " ) ;
return ;
}
}
2010-02-26 15:40:46 +00:00
/** do the list_forwards command */
static void
2018-06-12 07:43:52 +00:00
do_list_forwards ( RES * ssl , struct worker * worker )
2010-02-26 15:40:46 +00:00
{
/* since its a per-worker structure no locks needed */
struct iter_forwards * fwds = worker - > env . fwds ;
struct iter_forward_zone * z ;
2014-04-10 10:54:21 +00:00
struct trust_anchor * a ;
int insecure ;
2010-02-26 15:40:46 +00:00
RBTREE_FOR ( z , struct iter_forward_zone * , fwds - > tree ) {
if ( ! z - > dp ) continue ; /* skip empty marker for stub */
2014-04-10 10:54:21 +00:00
/* see if it is insecure */
insecure = 0 ;
if ( worker - > env . anchors & &
( a = anchor_find ( worker - > env . anchors , z - > name ,
z - > namelabs , z - > namelen , z - > dclass ) ) ) {
if ( ! a - > keylist & & ! a - > numDS & & ! a - > numDNSKEY )
insecure = 1 ;
lock_basic_unlock ( & a - > lock ) ;
}
if ( ! ssl_print_name_dp ( ssl , ( insecure ? " forward +i " : " forward " ) ,
z - > name , z - > dclass , z - > dp ) )
2010-02-26 15:40:46 +00:00
return ;
}
}
/** do the list_stubs command */
static void
2018-06-12 07:43:52 +00:00
do_list_stubs ( RES * ssl , struct worker * worker )
2010-02-26 15:40:46 +00:00
{
struct iter_hints_stub * z ;
2014-04-10 10:54:21 +00:00
struct trust_anchor * a ;
int insecure ;
char str [ 32 ] ;
2012-02-16 09:55:50 +00:00
RBTREE_FOR ( z , struct iter_hints_stub * , & worker - > env . hints - > tree ) {
2014-04-10 10:54:21 +00:00
/* see if it is insecure */
insecure = 0 ;
if ( worker - > env . anchors & &
( a = anchor_find ( worker - > env . anchors , z - > node . name ,
z - > node . labs , z - > node . len , z - > node . dclass ) ) ) {
if ( ! a - > keylist & & ! a - > numDS & & ! a - > numDNSKEY )
insecure = 1 ;
lock_basic_unlock ( & a - > lock ) ;
}
snprintf ( str , sizeof ( str ) , " stub %sprime%s " ,
( z - > noprime ? " no " : " " ) , ( insecure ? " +i " : " " ) ) ;
if ( ! ssl_print_name_dp ( ssl , str , z - > node . name ,
2010-02-26 15:40:46 +00:00
z - > node . dclass , z - > dp ) )
return ;
}
}
2018-04-23 14:42:30 +00:00
/** do the list_auth_zones command */
static void
2018-06-12 07:43:52 +00:00
do_list_auth_zones ( RES * ssl , struct auth_zones * az )
2018-04-23 14:42:30 +00:00
{
struct auth_zone * z ;
char buf [ 257 ] , buf2 [ 256 ] ;
lock_rw_rdlock ( & az - > lock ) ;
RBTREE_FOR ( z , struct auth_zone * , & az - > ztree ) {
lock_rw_rdlock ( & z - > lock ) ;
dname_str ( z - > name , buf ) ;
if ( z - > zone_expired )
snprintf ( buf2 , sizeof ( buf2 ) , " expired " ) ;
else {
uint32_t serial = 0 ;
if ( auth_zone_get_serial ( z , & serial ) )
snprintf ( buf2 , sizeof ( buf2 ) , " serial %u " ,
( unsigned ) serial ) ;
else snprintf ( buf2 , sizeof ( buf2 ) , " no serial " ) ;
}
if ( ! ssl_printf ( ssl , " %s \t %s \n " , buf , buf2 ) ) {
/* failure to print */
lock_rw_unlock ( & z - > lock ) ;
lock_rw_unlock ( & az - > lock ) ;
return ;
}
lock_rw_unlock ( & z - > lock ) ;
}
lock_rw_unlock ( & az - > lock ) ;
}
2010-02-26 16:14:00 +00:00
/** do the list_local_zones command */
static void
2018-06-12 07:43:52 +00:00
do_list_local_zones ( RES * ssl , struct local_zones * zones )
2010-02-26 16:14:00 +00:00
{
struct local_zone * z ;
char buf [ 257 ] ;
2014-01-24 11:21:15 +00:00
lock_rw_rdlock ( & zones - > lock ) ;
2010-02-26 16:14:00 +00:00
RBTREE_FOR ( z , struct local_zone * , & zones - > ztree ) {
lock_rw_rdlock ( & z - > lock ) ;
dname_str ( z - > name , buf ) ;
2023-04-20 15:39:55 +00:00
if ( ! ssl_printf ( ssl , " %s %s \n " , buf ,
2014-07-15 14:42:57 +00:00
local_zone_type2str ( z - > type ) ) ) {
/* failure to print */
lock_rw_unlock ( & z - > lock ) ;
lock_rw_unlock ( & zones - > lock ) ;
return ;
}
2010-02-26 16:14:00 +00:00
lock_rw_unlock ( & z - > lock ) ;
}
2014-01-24 11:21:15 +00:00
lock_rw_unlock ( & zones - > lock ) ;
2010-02-26 16:14:00 +00:00
}
/** do the list_local_data command */
static void
2018-06-12 07:43:52 +00:00
do_list_local_data ( RES * ssl , struct worker * worker , struct local_zones * zones )
2010-02-26 16:14:00 +00:00
{
struct local_zone * z ;
struct local_data * d ;
struct local_rrset * p ;
2013-12-03 09:11:16 +00:00
char * s = ( char * ) sldns_buffer_begin ( worker - > env . scratch_buffer ) ;
size_t slen = sldns_buffer_capacity ( worker - > env . scratch_buffer ) ;
2014-01-24 11:21:15 +00:00
lock_rw_rdlock ( & zones - > lock ) ;
2010-02-26 16:14:00 +00:00
RBTREE_FOR ( z , struct local_zone * , & zones - > ztree ) {
lock_rw_rdlock ( & z - > lock ) ;
RBTREE_FOR ( d , struct local_data * , & z - > data ) {
for ( p = d - > rrsets ; p ; p = p - > next ) {
2013-10-31 15:09:26 +00:00
struct packed_rrset_data * d =
( struct packed_rrset_data * ) p - > rrset - > entry . data ;
size_t i ;
for ( i = 0 ; i < d - > count + d - > rrsig_count ; i + + ) {
if ( ! packed_rr_to_string ( p - > rrset , i ,
0 , s , slen ) ) {
2015-08-24 10:49:28 +00:00
if ( ! ssl_printf ( ssl , " BADRR \n " ) ) {
lock_rw_unlock ( & z - > lock ) ;
lock_rw_unlock ( & zones - > lock ) ;
2013-10-31 15:09:26 +00:00
return ;
2015-08-24 10:49:28 +00:00
}
2013-10-31 15:09:26 +00:00
}
2015-08-24 10:49:28 +00:00
if ( ! ssl_printf ( ssl , " %s \n " , s ) ) {
lock_rw_unlock ( & z - > lock ) ;
lock_rw_unlock ( & zones - > lock ) ;
2013-10-31 15:09:26 +00:00
return ;
2015-08-24 10:49:28 +00:00
}
2013-10-31 15:09:26 +00:00
}
2010-02-26 16:14:00 +00:00
}
}
lock_rw_unlock ( & z - > lock ) ;
}
2014-01-24 11:21:15 +00:00
lock_rw_unlock ( & zones - > lock ) ;
2010-02-26 16:14:00 +00:00
}
2016-10-05 09:36:25 +00:00
/** do the view_list_local_zones command */
static void
2018-06-12 07:43:52 +00:00
do_view_list_local_zones ( RES * ssl , struct worker * worker , char * arg )
2016-10-05 09:36:25 +00:00
{
struct view * v = views_find_view ( worker - > daemon - > views ,
arg , 0 /* get read lock*/ ) ;
if ( ! v ) {
ssl_printf ( ssl , " no view with name: %s \n " , arg ) ;
return ;
}
2017-03-22 07:19:38 +00:00
if ( v - > local_zones ) {
do_list_local_zones ( ssl , v - > local_zones ) ;
}
2016-10-05 09:36:25 +00:00
lock_rw_unlock ( & v - > lock ) ;
}
/** do the view_list_local_data command */
static void
2018-06-12 07:43:52 +00:00
do_view_list_local_data ( RES * ssl , struct worker * worker , char * arg )
2016-10-05 09:36:25 +00:00
{
struct view * v = views_find_view ( worker - > daemon - > views ,
arg , 0 /* get read lock*/ ) ;
if ( ! v ) {
ssl_printf ( ssl , " no view with name: %s \n " , arg ) ;
return ;
}
2017-03-22 07:19:38 +00:00
if ( v - > local_zones ) {
do_list_local_data ( ssl , worker , v - > local_zones ) ;
}
2016-10-05 09:36:25 +00:00
lock_rw_unlock ( & v - > lock ) ;
}
2015-04-10 12:13:59 +00:00
/** struct for user arg ratelimit list */
struct ratelimit_list_arg {
/** the infra cache */
struct infra_cache * infra ;
/** the SSL to print to */
2018-06-12 07:43:52 +00:00
RES * ssl ;
2015-04-10 12:13:59 +00:00
/** all or only ratelimited */
int all ;
/** current time */
time_t now ;
2022-01-29 23:23:22 +00:00
/** if backoff is enabled */
int backoff ;
2015-04-10 12:13:59 +00:00
} ;
2017-01-05 13:57:12 +00:00
# define ip_ratelimit_list_arg ratelimit_list_arg
2015-04-10 12:13:59 +00:00
/** list items in the ratelimit table */
static void
rate_list ( struct lruhash_entry * e , void * arg )
{
struct ratelimit_list_arg * a = ( struct ratelimit_list_arg * ) arg ;
struct rate_key * k = ( struct rate_key * ) e - > key ;
struct rate_data * d = ( struct rate_data * ) e - > data ;
char buf [ 257 ] ;
int lim = infra_find_ratelimit ( a - > infra , k - > name , k - > namelen ) ;
2022-01-29 23:23:22 +00:00
int max = infra_rate_max ( d , a - > now , a - > backoff ) ;
2015-04-10 12:13:59 +00:00
if ( a - > all = = 0 ) {
if ( max < lim )
return ;
}
dname_str ( k - > name , buf ) ;
ssl_printf ( a - > ssl , " %s %d limit %d \n " , buf , max , lim ) ;
}
2017-01-05 13:57:12 +00:00
/** list items in the ip_ratelimit table */
static void
ip_rate_list ( struct lruhash_entry * e , void * arg )
{
char ip [ 128 ] ;
struct ip_ratelimit_list_arg * a = ( struct ip_ratelimit_list_arg * ) arg ;
struct ip_rate_key * k = ( struct ip_rate_key * ) e - > key ;
struct ip_rate_data * d = ( struct ip_rate_data * ) e - > data ;
int lim = infra_ip_ratelimit ;
2022-01-29 23:23:22 +00:00
int max = infra_rate_max ( d , a - > now , a - > backoff ) ;
2017-01-05 13:57:12 +00:00
if ( a - > all = = 0 ) {
if ( max < lim )
return ;
}
addr_to_str ( & k - > addr , k - > addrlen , ip , sizeof ( ip ) ) ;
ssl_printf ( a - > ssl , " %s %d limit %d \n " , ip , max , lim ) ;
}
2015-04-10 12:13:59 +00:00
/** do the ratelimit_list command */
static void
2018-06-12 07:43:52 +00:00
do_ratelimit_list ( RES * ssl , struct worker * worker , char * arg )
2015-04-10 12:13:59 +00:00
{
struct ratelimit_list_arg a ;
a . all = 0 ;
a . infra = worker - > env . infra_cache ;
a . now = * worker - > env . now ;
a . ssl = ssl ;
2022-01-29 23:23:22 +00:00
a . backoff = worker - > env . cfg - > ratelimit_backoff ;
2015-04-10 12:13:59 +00:00
arg = skipwhite ( arg ) ;
if ( strcmp ( arg , " +a " ) = = 0 )
a . all = 1 ;
if ( a . infra - > domain_rates = = NULL | |
( a . all = = 0 & & infra_dp_ratelimit = = 0 ) )
return ;
slabhash_traverse ( a . infra - > domain_rates , 0 , rate_list , & a ) ;
}
2017-01-05 13:57:12 +00:00
/** do the ip_ratelimit_list command */
static void
2018-06-12 07:43:52 +00:00
do_ip_ratelimit_list ( RES * ssl , struct worker * worker , char * arg )
2017-01-05 13:57:12 +00:00
{
struct ip_ratelimit_list_arg a ;
a . all = 0 ;
a . infra = worker - > env . infra_cache ;
a . now = * worker - > env . now ;
a . ssl = ssl ;
2022-01-29 23:23:22 +00:00
a . backoff = worker - > env . cfg - > ip_ratelimit_backoff ;
2017-01-05 13:57:12 +00:00
arg = skipwhite ( arg ) ;
if ( strcmp ( arg , " +a " ) = = 0 )
a . all = 1 ;
if ( a . infra - > client_ip_rates = = NULL | |
( a . all = = 0 & & infra_ip_ratelimit = = 0 ) )
return ;
slabhash_traverse ( a . infra - > client_ip_rates , 0 , ip_rate_list , & a ) ;
}
2020-12-13 19:35:11 +00:00
/** do the rpz_enable/disable command */
static void
do_rpz_enable_disable ( RES * ssl , struct worker * worker , char * arg , int enable ) {
size_t nmlen ;
int nmlabs ;
uint8_t * nm = NULL ;
struct auth_zones * az = worker - > env . auth_zones ;
struct auth_zone * z = NULL ;
if ( ! parse_arg_name ( ssl , arg , & nm , & nmlen , & nmlabs ) )
return ;
if ( az ) {
lock_rw_rdlock ( & az - > lock ) ;
z = auth_zone_find ( az , nm , nmlen , LDNS_RR_CLASS_IN ) ;
if ( z ) {
lock_rw_wrlock ( & z - > lock ) ;
}
lock_rw_unlock ( & az - > lock ) ;
}
free ( nm ) ;
if ( ! z ) {
( void ) ssl_printf ( ssl , " error no auth-zone %s \n " , arg ) ;
return ;
}
if ( ! z - > rpz ) {
( void ) ssl_printf ( ssl , " error auth-zone %s not RPZ \n " , arg ) ;
lock_rw_unlock ( & z - > lock ) ;
return ;
}
if ( enable ) {
rpz_enable ( z - > rpz ) ;
} else {
rpz_disable ( z - > rpz ) ;
}
lock_rw_unlock ( & z - > lock ) ;
send_ok ( ssl ) ;
}
/** do the rpz_enable command */
static void
do_rpz_enable ( RES * ssl , struct worker * worker , char * arg )
{
do_rpz_enable_disable ( ssl , worker , arg , 1 ) ;
}
/** do the rpz_disable command */
static void
do_rpz_disable ( RES * ssl , struct worker * worker , char * arg )
{
do_rpz_enable_disable ( ssl , worker , arg , 0 ) ;
}
2008-12-03 15:20:56 +00:00
/** tell other processes to execute the command */
2010-07-07 13:13:36 +00:00
static void
2018-06-12 07:43:52 +00:00
distribute_cmd ( struct daemon_remote * rc , RES * ssl , char * cmd )
2008-12-03 15:20:56 +00:00
{
int i ;
2023-04-20 15:39:55 +00:00
if ( ! cmd | | ! ssl )
2008-12-03 15:20:56 +00:00
return ;
/* skip i=0 which is me */
for ( i = 1 ; i < rc - > worker - > daemon - > num ; i + + ) {
worker_send_cmd ( rc - > worker - > daemon - > workers [ i ] ,
worker_cmd_remote ) ;
if ( ! tube_write_msg ( rc - > worker - > daemon - > workers [ i ] - > cmd ,
( uint8_t * ) cmd , strlen ( cmd ) + 1 , 0 ) ) {
ssl_printf ( ssl , " error could not distribute cmd \n " ) ;
return ;
}
}
}
2010-08-13 08:14:14 +00:00
/** check for name with end-of-string, space or tab after it */
static int
cmdcmp ( char * p , const char * cmd , size_t len )
{
return strncmp ( p , cmd , len ) = = 0 & & ( p [ len ] = = 0 | | p [ len ] = = ' ' | | p [ len ] = = ' \t ' ) ;
}
2008-09-15 08:35:45 +00:00
/** execute a remote control command */
static void
2023-04-20 15:39:55 +00:00
execute_cmd ( struct daemon_remote * rc , RES * ssl , char * cmd ,
2008-12-03 15:20:56 +00:00
struct worker * worker )
2008-09-15 08:35:45 +00:00
{
2008-09-15 14:19:41 +00:00
char * p = skipwhite ( cmd ) ;
2010-08-13 08:14:14 +00:00
/* compare command */
if ( cmdcmp ( p , " stop " , 4 ) ) {
2019-11-20 13:37:13 +00:00
do_stop ( ssl , worker ) ;
2008-12-03 15:20:56 +00:00
return ;
2022-12-14 15:33:28 +00:00
} else if ( cmdcmp ( p , " reload_keep_cache " , 17 ) ) {
do_reload ( ssl , worker , 1 ) ;
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " reload " , 6 ) ) {
2022-12-14 15:33:28 +00:00
do_reload ( ssl , worker , 0 ) ;
2008-12-03 15:20:56 +00:00
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " stats_noreset " , 13 ) ) {
2019-11-20 13:37:13 +00:00
do_stats ( ssl , worker , 0 ) ;
2009-02-12 11:41:51 +00:00
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " stats " , 5 ) ) {
2019-11-20 13:37:13 +00:00
do_stats ( ssl , worker , 1 ) ;
2008-12-03 15:20:56 +00:00
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " status " , 6 ) ) {
2008-12-17 14:03:49 +00:00
do_status ( ssl , worker ) ;
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " dump_cache " , 10 ) ) {
2008-12-03 15:20:56 +00:00
( void ) dump_cache ( ssl , worker ) ;
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " load_cache " , 10 ) ) {
2008-12-03 15:20:56 +00:00
if ( load_cache ( ssl , worker ) ) send_ok ( ssl ) ;
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " list_forwards " , 13 ) ) {
2010-02-26 15:40:46 +00:00
do_list_forwards ( ssl , worker ) ;
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " list_stubs " , 10 ) ) {
2010-02-26 15:40:46 +00:00
do_list_stubs ( ssl , worker ) ;
return ;
2015-04-07 13:50:09 +00:00
} else if ( cmdcmp ( p , " list_insecure " , 13 ) ) {
do_insecure_list ( ssl , worker ) ;
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " list_local_zones " , 16 ) ) {
2016-10-05 09:36:25 +00:00
do_list_local_zones ( ssl , worker - > daemon - > local_zones ) ;
2010-02-26 16:14:00 +00:00
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " list_local_data " , 15 ) ) {
2016-10-05 09:36:25 +00:00
do_list_local_data ( ssl , worker , worker - > daemon - > local_zones ) ;
return ;
} else if ( cmdcmp ( p , " view_list_local_zones " , 21 ) ) {
do_view_list_local_zones ( ssl , worker , skipwhite ( p + 21 ) ) ;
return ;
} else if ( cmdcmp ( p , " view_list_local_data " , 20 ) ) {
do_view_list_local_data ( ssl , worker , skipwhite ( p + 20 ) ) ;
2010-02-26 16:14:00 +00:00
return ;
2015-04-10 12:13:59 +00:00
} else if ( cmdcmp ( p , " ratelimit_list " , 14 ) ) {
do_ratelimit_list ( ssl , worker , p + 14 ) ;
return ;
2017-01-05 13:57:12 +00:00
} else if ( cmdcmp ( p , " ip_ratelimit_list " , 17 ) ) {
do_ip_ratelimit_list ( ssl , worker , p + 17 ) ;
return ;
2018-04-23 14:42:30 +00:00
} else if ( cmdcmp ( p , " list_auth_zones " , 15 ) ) {
do_list_auth_zones ( ssl , worker - > env . auth_zones ) ;
return ;
2018-06-15 13:42:41 +00:00
} else if ( cmdcmp ( p , " auth_zone_reload " , 16 ) ) {
do_auth_zone_reload ( ssl , worker , skipwhite ( p + 16 ) ) ;
return ;
2018-06-15 15:01:31 +00:00
} else if ( cmdcmp ( p , " auth_zone_transfer " , 18 ) ) {
do_auth_zone_transfer ( ssl , worker , skipwhite ( p + 18 ) ) ;
return ;
2012-02-15 14:35:28 +00:00
} else if ( cmdcmp ( p , " stub_add " , 8 ) ) {
/* must always distribute this cmd */
if ( rc ) distribute_cmd ( rc , ssl , cmd ) ;
do_stub_add ( ssl , worker , skipwhite ( p + 8 ) ) ;
return ;
} else if ( cmdcmp ( p , " stub_remove " , 11 ) ) {
/* must always distribute this cmd */
if ( rc ) distribute_cmd ( rc , ssl , cmd ) ;
do_stub_remove ( ssl , worker , skipwhite ( p + 11 ) ) ;
return ;
} else if ( cmdcmp ( p , " forward_add " , 11 ) ) {
/* must always distribute this cmd */
if ( rc ) distribute_cmd ( rc , ssl , cmd ) ;
do_forward_add ( ssl , worker , skipwhite ( p + 11 ) ) ;
return ;
} else if ( cmdcmp ( p , " forward_remove " , 14 ) ) {
/* must always distribute this cmd */
if ( rc ) distribute_cmd ( rc , ssl , cmd ) ;
do_forward_remove ( ssl , worker , skipwhite ( p + 14 ) ) ;
return ;
2013-04-26 14:14:07 +00:00
} else if ( cmdcmp ( p , " insecure_add " , 12 ) ) {
/* must always distribute this cmd */
if ( rc ) distribute_cmd ( rc , ssl , cmd ) ;
do_insecure_add ( ssl , worker , skipwhite ( p + 12 ) ) ;
return ;
} else if ( cmdcmp ( p , " insecure_remove " , 15 ) ) {
/* must always distribute this cmd */
if ( rc ) distribute_cmd ( rc , ssl , cmd ) ;
do_insecure_remove ( ssl , worker , skipwhite ( p + 15 ) ) ;
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " forward " , 7 ) ) {
2009-02-13 15:26:37 +00:00
/* must always distribute this cmd */
if ( rc ) distribute_cmd ( rc , ssl , cmd ) ;
do_forward ( ssl , worker , skipwhite ( p + 7 ) ) ;
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " flush_stats " , 11 ) ) {
2009-02-12 10:37:00 +00:00
/* must always distribute this cmd */
2009-02-12 13:21:19 +00:00
if ( rc ) distribute_cmd ( rc , ssl , cmd ) ;
2009-02-12 10:37:00 +00:00
do_flush_stats ( ssl , worker ) ;
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " flush_requestlist " , 17 ) ) {
2009-02-12 13:21:19 +00:00
/* must always distribute this cmd */
if ( rc ) distribute_cmd ( rc , ssl , cmd ) ;
do_flush_requestlist ( ssl , worker ) ;
return ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " lookup " , 6 ) ) {
2008-12-03 15:20:56 +00:00
do_lookup ( ssl , worker , skipwhite ( p + 6 ) ) ;
return ;
}
# ifdef THREADS_DISABLED
/* other processes must execute the command as well */
/* commands that should not be distributed, returned above. */
if ( rc ) { /* only if this thread is the master (rc) thread */
/* done before the code below, which may split the string */
distribute_cmd ( rc , ssl , cmd ) ;
}
# endif
2010-08-13 08:14:14 +00:00
if ( cmdcmp ( p , " verbosity " , 9 ) ) {
2008-12-03 15:20:56 +00:00
do_verbosity ( ssl , skipwhite ( p + 9 ) ) ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " local_zone_remove " , 17 ) ) {
2016-10-05 09:36:25 +00:00
do_zone_remove ( ssl , worker - > daemon - > local_zones , skipwhite ( p + 17 ) ) ;
2016-11-30 11:22:29 +00:00
} else if ( cmdcmp ( p , " local_zones_remove " , 18 ) ) {
do_zones_remove ( ssl , worker - > daemon - > local_zones ) ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " local_zone " , 10 ) ) {
2016-10-05 09:36:25 +00:00
do_zone_add ( ssl , worker - > daemon - > local_zones , skipwhite ( p + 10 ) ) ;
2016-11-30 11:22:29 +00:00
} else if ( cmdcmp ( p , " local_zones " , 11 ) ) {
do_zones_add ( ssl , worker - > daemon - > local_zones ) ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " local_data_remove " , 17 ) ) {
2016-10-05 09:36:25 +00:00
do_data_remove ( ssl , worker - > daemon - > local_zones , skipwhite ( p + 17 ) ) ;
2016-11-30 11:22:29 +00:00
} else if ( cmdcmp ( p , " local_datas_remove " , 18 ) ) {
do_datas_remove ( ssl , worker - > daemon - > local_zones ) ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " local_data " , 10 ) ) {
2016-10-05 09:36:25 +00:00
do_data_add ( ssl , worker - > daemon - > local_zones , skipwhite ( p + 10 ) ) ;
2016-11-30 11:22:29 +00:00
} else if ( cmdcmp ( p , " local_datas " , 11 ) ) {
do_datas_add ( ssl , worker - > daemon - > local_zones ) ;
2016-10-05 09:36:25 +00:00
} else if ( cmdcmp ( p , " view_local_zone_remove " , 22 ) ) {
do_view_zone_remove ( ssl , worker , skipwhite ( p + 22 ) ) ;
} else if ( cmdcmp ( p , " view_local_zone " , 15 ) ) {
do_view_zone_add ( ssl , worker , skipwhite ( p + 15 ) ) ;
} else if ( cmdcmp ( p , " view_local_data_remove " , 22 ) ) {
do_view_data_remove ( ssl , worker , skipwhite ( p + 22 ) ) ;
2020-01-29 01:28:00 +00:00
} else if ( cmdcmp ( p , " view_local_datas_remove " , 23 ) ) {
do_view_datas_remove ( ssl , worker , skipwhite ( p + 23 ) ) ;
2016-10-05 09:36:25 +00:00
} else if ( cmdcmp ( p , " view_local_data " , 15 ) ) {
do_view_data_add ( ssl , worker , skipwhite ( p + 15 ) ) ;
2018-11-26 13:37:23 +00:00
} else if ( cmdcmp ( p , " view_local_datas " , 16 ) ) {
do_view_datas_add ( ssl , worker , skipwhite ( p + 16 ) ) ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " flush_zone " , 10 ) ) {
2008-12-03 15:20:56 +00:00
do_flush_zone ( ssl , worker , skipwhite ( p + 10 ) ) ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " flush_type " , 10 ) ) {
2008-12-03 15:20:56 +00:00
do_flush_type ( ssl , worker , skipwhite ( p + 10 ) ) ;
2010-10-26 09:08:33 +00:00
} else if ( cmdcmp ( p , " flush_infra " , 11 ) ) {
do_flush_infra ( ssl , worker , skipwhite ( p + 11 ) ) ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " flush " , 5 ) ) {
2008-12-03 15:20:56 +00:00
do_flush_name ( ssl , worker , skipwhite ( p + 5 ) ) ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " dump_requestlist " , 16 ) ) {
2009-02-10 15:11:54 +00:00
do_dump_requestlist ( ssl , worker ) ;
2010-10-26 09:08:33 +00:00
} else if ( cmdcmp ( p , " dump_infra " , 10 ) ) {
do_dump_infra ( ssl , worker ) ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " log_reopen " , 10 ) ) {
2010-02-18 16:40:22 +00:00
do_log_reopen ( ssl , worker ) ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " set_option " , 10 ) ) {
2010-02-23 13:53:10 +00:00
do_set_option ( ssl , worker , skipwhite ( p + 10 ) ) ;
2010-08-13 08:14:14 +00:00
} else if ( cmdcmp ( p , " get_option " , 10 ) ) {
2010-02-23 13:53:10 +00:00
do_get_option ( ssl , worker , skipwhite ( p + 10 ) ) ;
2012-07-09 14:33:07 +00:00
} else if ( cmdcmp ( p , " flush_bogus " , 11 ) ) {
do_flush_bogus ( ssl , worker ) ;
2014-04-29 08:47:33 +00:00
} else if ( cmdcmp ( p , " flush_negative " , 14 ) ) {
do_flush_negative ( ssl , worker ) ;
2020-12-13 19:35:11 +00:00
} else if ( cmdcmp ( p , " rpz_enable " , 10 ) ) {
do_rpz_enable ( ssl , worker , skipwhite ( p + 10 ) ) ;
} else if ( cmdcmp ( p , " rpz_disable " , 11 ) ) {
do_rpz_disable ( ssl , worker , skipwhite ( p + 11 ) ) ;
2008-09-15 08:35:45 +00:00
} else {
( void ) ssl_printf ( ssl , " error unknown command '%s' \n " , p ) ;
}
}
2023-04-20 15:39:55 +00:00
void
2008-12-03 15:20:56 +00:00
daemon_remote_exec ( struct worker * worker )
{
/* read the cmd string */
uint8_t * msg = NULL ;
2009-01-07 14:30:43 +00:00
uint32_t len = 0 ;
2008-12-03 15:20:56 +00:00
if ( ! tube_read_msg ( worker - > cmd , & msg , & len , 0 ) ) {
log_err ( " daemon_remote_exec: tube_read_msg failed " ) ;
return ;
}
verbose ( VERB_ALGO , " remote exec distributed: %s " , ( char * ) msg ) ;
execute_cmd ( NULL , NULL , ( char * ) msg , worker ) ;
free ( msg ) ;
}
2008-09-11 14:14:12 +00:00
/** handle remote control request */
static void
2018-06-12 07:43:52 +00:00
handle_req ( struct daemon_remote * rc , struct rc_state * s , RES * res )
2008-09-11 14:14:12 +00:00
{
int r ;
2011-06-10 10:11:38 +00:00
char pre [ 10 ] ;
char magic [ 7 ] ;
2008-09-11 14:14:12 +00:00
char buf [ 1024 ] ;
2008-10-21 13:00:07 +00:00
# ifdef USE_WINSOCK
/* makes it possible to set the socket blocking again. */
/* basically removes it from winsock_event ... */
WSAEventSelect ( s - > c - > fd , NULL , 0 ) ;
# endif
2008-09-11 14:14:12 +00:00
fd_set_block ( s - > c - > fd ) ;
2011-06-10 10:11:38 +00:00
/* try to read magic UBCT[version]_space_ string */
2018-06-12 07:43:52 +00:00
if ( res - > ssl ) {
ERR_clear_error ( ) ;
if ( ( r = SSL_read ( res - > ssl , magic , ( int ) sizeof ( magic ) - 1 ) ) < = 0 ) {
if ( SSL_get_error ( res - > ssl , r ) = = SSL_ERROR_ZERO_RETURN )
return ;
log_crypto_err ( " could not SSL_read " ) ;
2008-09-11 14:14:12 +00:00
return ;
2018-06-12 07:43:52 +00:00
}
} else {
2018-06-12 10:50:51 +00:00
while ( 1 ) {
2018-06-19 13:13:35 +00:00
ssize_t rr = recv ( res - > fd , magic , sizeof ( magic ) - 1 , 0 ) ;
2018-06-12 10:50:51 +00:00
if ( rr < = 0 ) {
if ( rr = = 0 ) return ;
if ( errno = = EINTR | | errno = = EAGAIN )
continue ;
2020-08-31 07:12:01 +00:00
log_err ( " could not recv: %s " , sock_strerror ( errno ) ) ;
2018-06-12 10:50:51 +00:00
return ;
}
r = ( int ) rr ;
break ;
2018-06-12 07:43:52 +00:00
}
2008-09-11 14:14:12 +00:00
}
2011-06-10 10:11:38 +00:00
magic [ 6 ] = 0 ;
if ( r ! = 6 | | strncmp ( magic , " UBCT " , 4 ) ! = 0 ) {
2008-09-15 08:35:45 +00:00
verbose ( VERB_QUERY , " control connection has bad magic string " ) ;
2011-06-10 10:11:38 +00:00
/* probably wrong tool connected, ignore it completely */
2008-09-15 08:35:45 +00:00
return ;
}
2008-09-11 14:14:12 +00:00
2008-09-15 08:35:45 +00:00
/* read the command line */
2018-06-12 07:43:52 +00:00
if ( ! ssl_read_line ( res , buf , sizeof ( buf ) ) ) {
2008-09-11 14:14:12 +00:00
return ;
}
2011-06-10 10:11:38 +00:00
snprintf ( pre , sizeof ( pre ) , " UBCT%d " , UNBOUND_CONTROL_VERSION ) ;
if ( strcmp ( magic , pre ) ! = 0 ) {
verbose ( VERB_QUERY , " control connection had bad "
" version %s, cmd: %s " , magic , buf ) ;
2018-06-12 07:43:52 +00:00
ssl_printf ( res , " error version mismatch \n " ) ;
2011-06-10 10:11:38 +00:00
return ;
}
2008-09-15 08:35:45 +00:00
verbose ( VERB_DETAIL , " control cmd: %s " , buf ) ;
/* figure out what to do */
2018-06-12 07:43:52 +00:00
execute_cmd ( rc , res , buf , rc - > worker ) ;
}
/** handle SSL_do_handshake changes to the file descriptor to wait for later */
static int
remote_handshake_later ( struct daemon_remote * rc , struct rc_state * s ,
struct comm_point * c , int r , int r2 )
{
if ( r2 = = SSL_ERROR_WANT_READ ) {
if ( s - > shake_state = = rc_hs_read ) {
/* try again later */
return 0 ;
}
s - > shake_state = rc_hs_read ;
comm_point_listen_for_rw ( c , 1 , 0 ) ;
return 0 ;
} else if ( r2 = = SSL_ERROR_WANT_WRITE ) {
if ( s - > shake_state = = rc_hs_write ) {
/* try again later */
return 0 ;
}
s - > shake_state = rc_hs_write ;
comm_point_listen_for_rw ( c , 0 , 1 ) ;
return 0 ;
} else {
if ( r = = 0 )
log_err ( " remote control connection closed prematurely " ) ;
2019-11-20 13:22:06 +00:00
log_addr ( VERB_OPS , " failed connection from " ,
2022-10-03 13:29:47 +00:00
& s - > c - > repinfo . remote_addr , s - > c - > repinfo . remote_addrlen ) ;
2018-06-12 07:43:52 +00:00
log_crypto_err ( " remote control failed ssl " ) ;
clean_point ( rc , s ) ;
}
2018-06-12 13:02:52 +00:00
return 0 ;
2008-09-11 14:14:12 +00:00
}
2023-04-20 15:39:55 +00:00
int remote_control_callback ( struct comm_point * c , void * arg , int err ,
2008-09-10 15:23:01 +00:00
struct comm_reply * ATTR_UNUSED ( rep ) )
{
2018-06-12 07:43:52 +00:00
RES res ;
2008-09-10 15:23:01 +00:00
struct rc_state * s = ( struct rc_state * ) arg ;
struct daemon_remote * rc = s - > rc ;
2008-09-11 14:14:12 +00:00
int r ;
2008-09-10 15:23:01 +00:00
if ( err ! = NETEVENT_NOERROR ) {
2023-04-20 15:39:55 +00:00
if ( err = = NETEVENT_TIMEOUT )
2008-09-11 14:14:12 +00:00
log_err ( " remote control timed out " ) ;
2008-09-10 15:23:01 +00:00
clean_point ( rc , s ) ;
return 0 ;
}
2018-06-12 07:43:52 +00:00
if ( s - > ssl ) {
/* (continue to) setup the SSL connection */
ERR_clear_error ( ) ;
r = SSL_do_handshake ( s - > ssl ) ;
if ( r ! = 1 ) {
int r2 = SSL_get_error ( s - > ssl , r ) ;
return remote_handshake_later ( rc , s , c , r , r2 ) ;
2008-09-11 14:14:12 +00:00
}
2018-06-12 07:43:52 +00:00
s - > shake_state = rc_none ;
2008-09-11 14:14:12 +00:00
}
2008-09-10 15:23:01 +00:00
/* once handshake has completed, check authentication */
2015-01-06 14:12:59 +00:00
if ( ! rc - > use_cert ) {
verbose ( VERB_ALGO , " unauthenticated remote control connection " ) ;
} else if ( SSL_get_verify_result ( s - > ssl ) = = X509_V_OK ) {
2021-07-30 11:54:43 +00:00
# ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
X509 * x = SSL_get1_peer_certificate ( s - > ssl ) ;
# else
2008-09-11 14:14:12 +00:00
X509 * x = SSL_get_peer_certificate ( s - > ssl ) ;
2021-07-30 11:54:43 +00:00
# endif
2008-09-11 14:14:12 +00:00
if ( ! x ) {
verbose ( VERB_DETAIL , " remote control connection "
" provided no client certificate " ) ;
clean_point ( rc , s ) ;
return 0 ;
}
verbose ( VERB_ALGO , " remote control connection authenticated " ) ;
X509_free ( x ) ;
} else {
verbose ( VERB_DETAIL , " remote control connection failed to "
" authenticate with client certificate " ) ;
clean_point ( rc , s ) ;
return 0 ;
}
2008-09-10 15:23:01 +00:00
/* if OK start to actually handle the request */
2018-06-12 07:43:52 +00:00
res . ssl = s - > ssl ;
res . fd = c - > fd ;
handle_req ( rc , s , & res ) ;
2008-09-10 15:23:01 +00:00
2008-09-11 14:14:12 +00:00
verbose ( VERB_ALGO , " remote control operation completed " ) ;
clean_point ( rc , s ) ;
2008-09-10 15:23:01 +00:00
return 0 ;
}