- patch for remote control over local sockets, from Dag-Erling

Smorgrav, Ilya Bakulin.  Use control-interface: /path/sock and
  control-use-cert: no.


git-svn-id: file:///svn/unbound/trunk@3304 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2015-01-06 14:12:59 +00:00
parent 0dea293963
commit df73be98bd
20 changed files with 2011 additions and 1740 deletions

View file

@ -353,6 +353,9 @@
/* Define to 1 if `ipi_spec_dst' is a member of `struct in_pktinfo'. */
#undef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST
/* Define to 1 if `sun_len' is a member of `struct sockaddr_un'. */
#undef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
/* Define if you have Swig libraries and header files. */
#undef HAVE_SWIG
@ -383,6 +386,9 @@
/* Define to 1 if you have the <sys/uio.h> header file. */
#undef HAVE_SYS_UIO_H
/* Define to 1 if you have the <sys/un.h> header file. */
#undef HAVE_SYS_UN_H
/* Define to 1 if you have the <sys/wait.h> header file. */
#undef HAVE_SYS_WAIT_H

18
configure vendored
View file

@ -13739,7 +13739,7 @@ CC="$lt_save_CC"
# Checks for header files.
for ac_header in stdarg.h stdbool.h netinet/in.h sys/param.h sys/socket.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h
for ac_header in stdarg.h stdbool.h netinet/in.h sys/param.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
@ -17844,6 +17844,22 @@ $as_echo "no" >&6; }
fi
fi
ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_len" "ac_cv_member_struct_sockaddr_un_sun_len" "
$ac_includes_default
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
"
if test "x$ac_cv_member_struct_sockaddr_un_sun_len" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 1
_ACEOF
fi
ac_fn_c_check_member "$LINENO" "struct in_pktinfo" "ipi_spec_dst" "ac_cv_member_struct_in_pktinfo_ipi_spec_dst" "

View file

@ -269,7 +269,7 @@ AC_CHECK_TOOL(STRIP, strip)
ACX_LIBTOOL_C_ONLY
# Checks for header files.
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h sys/param.h sys/socket.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h sys/param.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h],,, [AC_INCLUDES_DEFAULT])
# check for types.
# Using own tests for int64* because autoconf builtin only give 32bit.
@ -941,6 +941,12 @@ if test $ac_cv_func_daemon = yes; then
])
fi
AC_CHECK_MEMBERS([struct sockaddr_un.sun_len],,,[
AC_INCLUDES_DEFAULT
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
])
AC_CHECK_MEMBERS([struct in_pktinfo.ipi_spec_dst],,,[
AC_INCLUDES_DEFAULT
#if HAVE_SYS_PARAM_H

View file

@ -46,6 +46,10 @@
#ifdef HAVE_OPENSSL_ERR_H
#include <openssl/err.h>
#endif
#ifndef HEADER_DH_H
#include <openssl/dh.h>
#endif
#include <ctype.h>
#include "daemon/remote.h"
#include "daemon/worker.h"
@ -82,6 +86,9 @@
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
@ -131,6 +138,39 @@ timeval_divide(struct timeval* avg, const struct timeval* sum, size_t d)
#endif
}
/*
* The following function was generated using the openssl utility, using
* the command : "openssl dhparam -dsaparam -C 512"
*/
DH *get_dh512()
{
static unsigned char dh512_p[]={
0xC9,0xD7,0x05,0xDA,0x5F,0xAB,0x14,0xE8,0x11,0x56,0x77,0x85,
0xB1,0x24,0x2C,0x95,0x60,0xEA,0xE2,0x10,0x6F,0x0F,0x84,0xEC,
0xF4,0x45,0xE8,0x90,0x7A,0xA7,0x03,0xFF,0x5B,0x88,0x53,0xDE,
0xC4,0xDE,0xBC,0x42,0x78,0x71,0x23,0x7E,0x24,0xA5,0x5E,0x4E,
0xEF,0x6F,0xFF,0x5F,0xAF,0xBE,0x8A,0x77,0x62,0xB4,0x65,0x82,
0x7E,0xC9,0xED,0x2F,
};
static unsigned char dh512_g[]={
0x8D,0x3A,0x52,0xBC,0x8A,0x71,0x94,0x33,0x2F,0xE1,0xE8,0x4C,
0x73,0x47,0x03,0x4E,0x7D,0x40,0xE5,0x84,0xA0,0xB5,0x6D,0x10,
0x6F,0x90,0x43,0x05,0x1A,0xF9,0x0B,0x6A,0xD1,0x2A,0x9C,0x25,
0x0A,0xB9,0xD1,0x14,0xDC,0x35,0x1C,0x48,0x7C,0xC6,0x0C,0x6D,
0x32,0x1D,0xD3,0xC8,0x10,0xA8,0x82,0x14,0xA2,0x1C,0xF4,0x53,
0x23,0x3B,0x1C,0xB9,
};
DH *dh;
if ((dh=DH_new()) == NULL) return(NULL);
dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
if ((dh->p == NULL) || (dh->g == NULL))
{ DH_free(dh); return(NULL); }
dh->length = 160;
return(dh);
}
struct daemon_remote*
daemon_remote_create(struct config_file* cfg)
{
@ -165,6 +205,24 @@ daemon_remote_create(struct config_file* cfg)
daemon_remote_delete(rc);
return NULL;
}
if (cfg->remote_control_use_cert == 0) {
/* No certificates are requested */
if(!SSL_CTX_set_cipher_list(rc->ctx, "aNULL")) {
log_crypto_err("Failed to set aNULL cipher list");
return NULL;
}
/* Since we have no certificates and hence no source of
* DH params, let's generate and set them
*/
if(!SSL_CTX_set_tmp_dh(rc->ctx,get_dh512())) {
log_crypto_err("Wanted to set DH param, but failed");
return NULL;
}
return rc;
}
rc->use_cert = 1;
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) {
@ -244,7 +302,8 @@ void daemon_remote_delete(struct daemon_remote* rc)
* @return false on failure.
*/
static int
add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err)
add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err,
struct config_file* cfg)
{
struct addrinfo hints;
struct addrinfo* res;
@ -255,29 +314,46 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err)
snprintf(port, sizeof(port), "%d", nr);
port[sizeof(port)-1]=0;
memset(&hints, 0, sizeof(hints));
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 */
if(ip[0] == '/') {
/* This looks like a local socket */
fd = create_local_accept_sock(ip, &noproto);
/*
* 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) {
if (cfg->username && cfg->username[0])
chown(ip, cfg->uid, cfg->gid);
chmod(ip, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
}
} 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 */
}
#endif /* USE_WINSOCK */
log_err("control interface %s:%s getaddrinfo: %s %s",
ip?ip:"default", port, gai_strerror(r),
log_err("control interface %s:%s getaddrinfo: %s %s",
ip?ip:"default", port, gai_strerror(r),
#ifdef EAI_SYSTEM
r==EAI_SYSTEM?(char*)strerror(errno):""
r==EAI_SYSTEM?(char*)strerror(errno):""
#else
""
""
#endif
);
return 0;
return 0;
}
/* open fd */
fd = create_tcp_accept_sock(res, 1, &noproto, 0);
freeaddrinfo(res);
}
/* open fd */
fd = create_tcp_accept_sock(res, 1, &noproto, 0);
freeaddrinfo(res);
if(fd == -1 && noproto) {
if(!noproto_is_err)
return 1; /* return success, but do nothing */
@ -314,7 +390,7 @@ struct listen_port* daemon_remote_open_ports(struct config_file* cfg)
if(cfg->control_ifs) {
struct config_strlist* p;
for(p = cfg->control_ifs; p; p = p->next) {
if(!add_open(p->str, cfg->control_port, &l, 1)) {
if(!add_open(p->str, cfg->control_port, &l, 1, cfg)) {
listening_ports_free(l);
return NULL;
}
@ -322,12 +398,12 @@ struct listen_port* daemon_remote_open_ports(struct config_file* cfg)
} else {
/* defaults */
if(cfg->do_ip6 &&
!add_open("::1", cfg->control_port, &l, 0)) {
!add_open("::1", cfg->control_port, &l, 0, cfg)) {
listening_ports_free(l);
return NULL;
}
if(cfg->do_ip4 &&
!add_open("127.0.0.1", cfg->control_port, &l, 1)) {
!add_open("127.0.0.1", cfg->control_port, &l, 1, cfg)) {
listening_ports_free(l);
return NULL;
}
@ -2434,7 +2510,9 @@ int remote_control_callback(struct comm_point* c, void* arg, int err,
s->shake_state = rc_none;
/* once handshake has completed, check authentication */
if(SSL_get_verify_result(s->ssl) == X509_V_OK) {
if (!rc->use_cert) {
verbose(VERB_ALGO, "unauthenticated remote control connection");
} else if(SSL_get_verify_result(s->ssl) == X509_V_OK) {
X509* x = SSL_get_peer_certificate(s->ssl);
if(!x) {
verbose(VERB_DETAIL, "remote control connection "

View file

@ -89,6 +89,8 @@ struct daemon_remote {
struct worker* worker;
/** commpoints for accepting remote control connections */
struct listen_list* accept_list;
/* if certificates are used */
int use_cert;
/** number of active commpoints that are handling remote control */
int active;
/** max active commpoints */

View file

@ -443,18 +443,10 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
{
#ifdef HAVE_GETPWNAM
struct passwd *pwd = NULL;
uid_t uid;
gid_t gid;
/* initialize, but not to 0 (root) */
memset(&uid, 112, sizeof(uid));
memset(&gid, 112, sizeof(gid));
log_assert(cfg);
if(cfg->username && cfg->username[0]) {
if((pwd = getpwnam(cfg->username)) == NULL)
fatal_exit("user '%s' does not exist.", cfg->username);
uid = pwd->pw_uid;
gid = pwd->pw_gid;
/* endpwent below, in case we need pwd for setusercontext */
}
#endif
@ -511,18 +503,11 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
#ifdef HAVE_KILL
if(cfg->pidfile && cfg->pidfile[0]) {
writepid(daemon->pidfile, getpid());
if(!(cfg->chrootdir && cfg->chrootdir[0]) ||
(cfg->chrootdir && cfg->chrootdir[0] &&
strncmp(daemon->pidfile, cfg->chrootdir,
strlen(cfg->chrootdir))==0)) {
/* delete of pidfile could potentially work,
* chown to get permissions */
if(cfg->username && cfg->username[0]) {
if(chown(daemon->pidfile, uid, gid) == -1) {
if(cfg->username && cfg->username[0]) {
if(chown(daemon->pidfile, cfg->uid, cfg->gid) == -1) {
log_err("cannot chown %u.%u %s: %s",
(unsigned)uid, (unsigned)gid,
(unsigned)cfg->uid, (unsigned)cfg->gid,
daemon->pidfile, strerror(errno));
}
}
}
}
@ -537,7 +522,7 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
/* setusercontext does initgroups, setuid, setgid, and
* also resource limits from login config, but we
* still call setresuid, setresgid to be sure to set all uid*/
if(setusercontext(NULL, pwd, uid, (unsigned)
if(setusercontext(NULL, pwd, cfg->uid, (unsigned)
LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0)
log_warn("unable to setusercontext %s: %s",
cfg->username, strerror(errno));
@ -601,27 +586,27 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
#ifdef HAVE_GETPWNAM
if(cfg->username && cfg->username[0]) {
# ifdef HAVE_INITGROUPS
if(initgroups(cfg->username, gid) != 0)
if(initgroups(cfg->username, cfg->gid) != 0)
log_warn("unable to initgroups %s: %s",
cfg->username, strerror(errno));
# endif /* HAVE_INITGROUPS */
endpwent();
#ifdef HAVE_SETRESGID
if(setresgid(gid,gid,gid) != 0)
if(setresgid(cfg->gid,cfg->gid,cfg->gid) != 0)
#elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID)
if(setregid(gid,gid) != 0)
if(setregid(cfg->gid,cfg->gid) != 0)
#else /* use setgid */
if(setgid(gid) != 0)
if(setgid(cfg->gid) != 0)
#endif /* HAVE_SETRESGID */
fatal_exit("unable to set group id of %s: %s",
cfg->username, strerror(errno));
#ifdef HAVE_SETRESUID
if(setresuid(uid,uid,uid) != 0)
if(setresuid(cfg->uid,cfg->uid,cfg->uid) != 0)
#elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID)
if(setreuid(uid,uid) != 0)
if(setreuid(cfg->uid,cfg->uid) != 0)
#else /* use setuid */
if(setuid(uid) != 0)
if(setuid(cfg->uid) != 0)
#endif /* HAVE_SETRESUID */
fatal_exit("unable to set user id of %s: %s",
cfg->username, strerror(errno));

View file

@ -1,5 +1,8 @@
6 January 2015: Wouter
- iana portlist update.
- patch for remote control over local sockets, from Dag-Erling
Smorgrav, Ilya Bakulin. Use control-interface: /path/sock and
control-use-cert: no.
5 January 2015: Wouter
- getauxval test for ppc64 linux compatibility.

View file

@ -965,36 +965,47 @@ to setup SSLv3 / TLSv1 security for the connection. The
section for options. To setup the correct self\-signed certificates use the
\fIunbound\-control\-setup\fR(8) utility.
.TP 5
.B control\-enable: \fI<yes or no>
.B control\-enable: \fI<yes or no>
The option is used to enable remote control, default is "no".
If turned off, the server does not listen for control commands.
.TP 5
.B control\-interface: <ip address>
Give IPv4 or IPv6 addresses to listen on for control commands.
.B control\-interface: \fI<ip address or path>
Give IPv4 or IPv6 addresses or local socket path to listen on for
control commands.
By default localhost (127.0.0.1 and ::1) is listened to.
Use 0.0.0.0 and ::0 to listen to all interfaces.
If you change this and permissions have been dropped, you must restart
the server for the change to take effect.
.TP 5
.B control\-port: <port number>
The port number to listen on for control commands, default is 8953.
If you change this port number, and permissions have been dropped,
a reload is not sufficient to open the port again, you must then restart.
.B control\-port: \fI<port number>
The port number to listen on for IPv4 or IPv6 control interfaces,
default is 8953.
If you change this and permissions have been dropped, you must restart
the server for the change to take effect.
.TP 5
.B server\-key\-file: "<private key file>"
.B control\-use\-cert: \fI<yes or no>
Whether to require certificate authentication of control connections.
The default is "yes".
This should not be changed unless there are other mechanisms in place
to prevent untrusted users from accessing the remote control
interface.
.TP 5
.B server\-key\-file: \fI<private key file>
Path to the server private key, by default unbound_server.key.
This file is generated by the \fIunbound\-control\-setup\fR utility.
This file is used by the unbound server, but not by \fIunbound\-control\fR.
.TP 5
.B server\-cert\-file: "<certificate file.pem>"
.B server\-cert\-file: \fI<certificate file.pem>
Path to the server self signed certificate, by default unbound_server.pem.
This file is generated by the \fIunbound\-control\-setup\fR utility.
This file is used by the unbound server, and also by \fIunbound\-control\fR.
.TP 5
.B control\-key\-file: "<private key file>"
.B control\-key\-file: \fI<private key file>
Path to the control client private key, by default unbound_control.key.
This file is generated by the \fIunbound\-control\-setup\fR utility.
This file is used by \fIunbound\-control\fR.
.TP 5
.B control\-cert\-file: "<certificate file.pem>"
.B control\-cert\-file: \fI<certificate file.pem>
Path to the control client certificate, by default unbound_control.pem.
This certificate has to be signed with the server certificate.
This file is generated by the \fIunbound\-control\-setup\fR utility.

View file

@ -56,6 +56,10 @@
#endif
#include <fcntl.h>
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
/** number of queued TCP connections for listen() */
#define TCP_BACKLOG 256
@ -589,6 +593,61 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
return s;
}
int
create_local_accept_sock(const char *path, int* noproto)
{
#ifdef HAVE_SYS_UN_H
int s;
struct sockaddr_un sun;
#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
/* this member exists on BSDs, not Linux */
sun.sun_len = sizeof(sun);
#endif
sun.sun_family = AF_LOCAL;
/* length is 92-108, 104 on FreeBSD */
strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
if ((s = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) {
log_err("Cannot create local socket %s (%s)",
path, strerror(errno));
return -1;
}
if (unlink(path) && errno != ENOENT) {
/* The socket already exists and cannot be removed */
log_err("Cannot remove old local socket %s (%s)",
path, strerror(errno));
return -1;
}
if (bind(s, (struct sockaddr *)&sun,
sizeof(struct sockaddr_un)) == -1) {
log_err("Cannot bind local socket %s (%s)",
path, strerror(errno));
return -1;
}
if (!fd_set_nonblock(s)) {
log_err("Cannot set non-blocking mode");
return -1;
}
if (listen(s, TCP_BACKLOG) == -1) {
log_err("can't listen: %s", strerror(errno));
return -1;
}
(void)noproto; /*unused*/
return s;
#else
log_err("Local sockets are not supported");
*noproto = 1;
return -1;
#endif
}
/**
* Create socket from getaddrinfo results
*/

View file

@ -207,4 +207,13 @@ int create_udp_sock(int family, int socktype, struct sockaddr* addr,
int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
int* reuseport);
/**
* Create and bind local listening socket
* @param path: path to the socket.
* @param noproto: on error, this is set true if cause is that local sockets
* are not supported.
* @return: the socket. -1 on error.
*/
int create_local_accept_sock(const char* path, int* noproto);
#endif /* LISTEN_DNSPORT_H */

View file

@ -416,7 +416,7 @@ morechecks(struct config_file* cfg, const char* fname)
endpwent();
}
#endif
if(cfg->remote_control_enable) {
if(cfg->remote_control_enable && cfg->remote_control_use_cert) {
check_chroot_string("server-key-file", &cfg->server_key_file,
cfg->chrootdir, cfg);
check_chroot_string("server-cert-file", &cfg->server_cert_file,

View file

@ -59,6 +59,10 @@
#include "util/locks.h"
#include "util/net_help.h"
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
/** Give unbound-control usage, and exit (1). */
static void
usage()
@ -136,32 +140,40 @@ static void ssl_err(const char* s)
static SSL_CTX*
setup_ctx(struct config_file* cfg)
{
char* s_cert, *c_key, *c_cert;
char* s_cert=NULL, *c_key=NULL, *c_cert=NULL;
SSL_CTX* ctx;
s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1);
c_key = fname_after_chroot(cfg->control_key_file, cfg, 1);
c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1);
if(!s_cert || !c_key || !c_cert)
fatal_exit("out of memory");
if(cfg->remote_control_use_cert) {
s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1);
c_key = fname_after_chroot(cfg->control_key_file, cfg, 1);
c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1);
if(!s_cert || !c_key || !c_cert)
fatal_exit("out of memory");
}
ctx = SSL_CTX_new(SSLv23_client_method());
if(!ctx)
ssl_err("could not allocate SSL_CTX pointer");
if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2))
ssl_err("could not set SSL_OP_NO_SSLv2");
if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3))
ssl_err("could not set SSL_OP_NO_SSLv3");
if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) ||
!SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)
|| !SSL_CTX_check_private_key(ctx))
ssl_err("Error setting up SSL_CTX client key and cert");
if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1)
ssl_err("Error setting up SSL_CTX verify, server cert");
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
if(cfg->remote_control_use_cert) {
if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3))
ssl_err("could not set SSL_OP_NO_SSLv3");
if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) ||
!SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)
|| !SSL_CTX_check_private_key(ctx))
ssl_err("Error setting up SSL_CTX client key and cert");
if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1)
ssl_err("Error setting up SSL_CTX verify, server cert");
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
free(s_cert);
free(c_key);
free(c_cert);
free(s_cert);
free(c_key);
free(c_cert);
} else {
/* Use ciphers that don't require authentication */
if(!SSL_CTX_set_cipher_list(ctx, "aNULL"))
ssl_err("Error setting NULL cipher!");
}
return ctx;
}
@ -171,6 +183,7 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd)
{
struct sockaddr_storage addr;
socklen_t addrlen;
int addrfamily = 0;
int fd;
/* use svr or the first config entry */
if(!svr) {
@ -189,12 +202,25 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd)
if(strchr(svr, '@')) {
if(!extstrtoaddr(svr, &addr, &addrlen))
fatal_exit("could not parse IP@port: %s", svr);
#ifdef HAVE_SYS_UN_H
} else if(svr[0] == '/') {
struct sockaddr_un* sun = (struct sockaddr_un *) &addr;
sun->sun_family = AF_LOCAL;
#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
sun->sun_len = sizeof(sun);
#endif
strlcpy(sun->sun_path, svr, sizeof(sun->sun_path));
addrlen = sizeof(struct sockaddr_un);
addrfamily = AF_LOCAL;
#endif
} else {
if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen))
fatal_exit("could not parse IP: %s", svr);
}
fd = socket(addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET,
SOCK_STREAM, 0);
if(addrfamily == 0)
addrfamily = addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET;
fd = socket(addrfamily, SOCK_STREAM, 0);
if(fd == -1) {
#ifndef USE_WINSOCK
fatal_exit("socket: %s", strerror(errno));
@ -223,7 +249,7 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd)
/** setup SSL on the connection */
static SSL*
setup_ssl(SSL_CTX* ctx, int fd)
setup_ssl(SSL_CTX* ctx, int fd, struct config_file* cfg)
{
SSL* ssl;
X509* x;
@ -249,10 +275,13 @@ setup_ssl(SSL_CTX* ctx, int fd)
/* check authenticity of server */
if(SSL_get_verify_result(ssl) != X509_V_OK)
ssl_err("SSL verification failed");
x = SSL_get_peer_certificate(ssl);
if(!x)
ssl_err("Server presented no peer certificate");
X509_free(x);
if(cfg->remote_control_use_cert) {
x = SSL_get_peer_certificate(ssl);
if(!x)
ssl_err("Server presented no peer certificate");
X509_free(x);
}
return ssl;
}
@ -333,7 +362,7 @@ go(const char* cfgfile, char* svr, int quiet, int argc, char* argv[])
/* contact server */
fd = contact_server(svr, cfg, argc>0&&strcmp(argv[0],"status")==0);
ssl = setup_ssl(ctx, fd);
ssl = setup_ssl(ctx, fd, cfg);
/* send command */
ret = go_cmd(ssl, quiet, argc, argv);

View file

@ -60,6 +60,9 @@
#ifdef HAVE_GLOB_H
# include <glob.h>
#endif
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
/** global config during parsing */
struct config_parser_state* cfg_parser = 0;
@ -131,6 +134,8 @@ config_create(void)
goto error_exit;
init_outgoing_availports(cfg->outgoing_avail_ports, 65536);
if(!(cfg->username = strdup(UB_USERNAME))) goto error_exit;
cfg->uid = (uid_t)-1;
cfg->gid = (gid_t)-1;
#ifdef HAVE_CHROOT
if(!(cfg->chrootdir = strdup(CHROOT_DIR))) goto error_exit;
#endif
@ -799,6 +804,17 @@ config_read(struct config_file* cfg, const char* filename, const char* chroot)
errno=EINVAL;
return 0;
}
#ifdef HAVE_GETPWNAM
/* translate username into uid and gid */
if(cfg->username && cfg->username[0]) {
struct passwd *pwd;
if((pwd = getpwnam(cfg->username)) == NULL)
log_err("user '%s' does not exist.", cfg->username);
cfg->uid = pwd->pw_uid;
cfg->gid = pwd->pw_gid;
}
#endif
return 1;
}

View file

@ -192,6 +192,8 @@ struct config_file {
char* chrootdir;
/** username to change to, if not "". */
char* username;
uid_t uid;
gid_t gid;
/** working directory */
char* directory;
/** filename to log to. */
@ -282,6 +284,8 @@ struct config_file {
struct config_strlist* control_ifs;
/** port number for the control port */
int control_port;
/** use certificates for remote control */
int remote_control_use_cert;
/** private key file for server */
char* server_key_file;
/** certificate file for server */

File diff suppressed because it is too large Load diff

View file

@ -315,6 +315,7 @@ remote-control{COLON} { YDVAR(0, VAR_REMOTE_CONTROL) }
control-enable{COLON} { YDVAR(1, VAR_CONTROL_ENABLE) }
control-interface{COLON} { YDVAR(1, VAR_CONTROL_INTERFACE) }
control-port{COLON} { YDVAR(1, VAR_CONTROL_PORT) }
control-use-cert{COLON} { YDVAR(1, VAR_CONTROL_USE_CERT) }
server-key-file{COLON} { YDVAR(1, VAR_SERVER_KEY_FILE) }
server-cert-file{COLON} { YDVAR(1, VAR_SERVER_CERT_FILE) }
control-key-file{COLON} { YDVAR(1, VAR_CONTROL_KEY_FILE) }

File diff suppressed because it is too large Load diff

View file

@ -139,59 +139,60 @@ extern int yydebug;
VAR_SERVER_CERT_FILE = 348,
VAR_CONTROL_KEY_FILE = 349,
VAR_CONTROL_CERT_FILE = 350,
VAR_EXTENDED_STATISTICS = 351,
VAR_LOCAL_DATA_PTR = 352,
VAR_JOSTLE_TIMEOUT = 353,
VAR_STUB_PRIME = 354,
VAR_UNWANTED_REPLY_THRESHOLD = 355,
VAR_LOG_TIME_ASCII = 356,
VAR_DOMAIN_INSECURE = 357,
VAR_PYTHON = 358,
VAR_PYTHON_SCRIPT = 359,
VAR_VAL_SIG_SKEW_MIN = 360,
VAR_VAL_SIG_SKEW_MAX = 361,
VAR_CACHE_MIN_TTL = 362,
VAR_VAL_LOG_LEVEL = 363,
VAR_AUTO_TRUST_ANCHOR_FILE = 364,
VAR_KEEP_MISSING = 365,
VAR_ADD_HOLDDOWN = 366,
VAR_DEL_HOLDDOWN = 367,
VAR_SO_RCVBUF = 368,
VAR_EDNS_BUFFER_SIZE = 369,
VAR_PREFETCH = 370,
VAR_PREFETCH_KEY = 371,
VAR_SO_SNDBUF = 372,
VAR_SO_REUSEPORT = 373,
VAR_HARDEN_BELOW_NXDOMAIN = 374,
VAR_IGNORE_CD_FLAG = 375,
VAR_LOG_QUERIES = 376,
VAR_TCP_UPSTREAM = 377,
VAR_SSL_UPSTREAM = 378,
VAR_SSL_SERVICE_KEY = 379,
VAR_SSL_SERVICE_PEM = 380,
VAR_SSL_PORT = 381,
VAR_FORWARD_FIRST = 382,
VAR_STUB_FIRST = 383,
VAR_MINIMAL_RESPONSES = 384,
VAR_RRSET_ROUNDROBIN = 385,
VAR_MAX_UDP_SIZE = 386,
VAR_DELAY_CLOSE = 387,
VAR_UNBLOCK_LAN_ZONES = 388,
VAR_DNS64_PREFIX = 389,
VAR_DNS64_SYNTHALL = 390,
VAR_DNSTAP = 391,
VAR_DNSTAP_ENABLE = 392,
VAR_DNSTAP_SOCKET_PATH = 393,
VAR_DNSTAP_SEND_IDENTITY = 394,
VAR_DNSTAP_SEND_VERSION = 395,
VAR_DNSTAP_IDENTITY = 396,
VAR_DNSTAP_VERSION = 397,
VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES = 398,
VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES = 399,
VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES = 400,
VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES = 401,
VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES = 402,
VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES = 403
VAR_CONTROL_USE_CERT = 351,
VAR_EXTENDED_STATISTICS = 352,
VAR_LOCAL_DATA_PTR = 353,
VAR_JOSTLE_TIMEOUT = 354,
VAR_STUB_PRIME = 355,
VAR_UNWANTED_REPLY_THRESHOLD = 356,
VAR_LOG_TIME_ASCII = 357,
VAR_DOMAIN_INSECURE = 358,
VAR_PYTHON = 359,
VAR_PYTHON_SCRIPT = 360,
VAR_VAL_SIG_SKEW_MIN = 361,
VAR_VAL_SIG_SKEW_MAX = 362,
VAR_CACHE_MIN_TTL = 363,
VAR_VAL_LOG_LEVEL = 364,
VAR_AUTO_TRUST_ANCHOR_FILE = 365,
VAR_KEEP_MISSING = 366,
VAR_ADD_HOLDDOWN = 367,
VAR_DEL_HOLDDOWN = 368,
VAR_SO_RCVBUF = 369,
VAR_EDNS_BUFFER_SIZE = 370,
VAR_PREFETCH = 371,
VAR_PREFETCH_KEY = 372,
VAR_SO_SNDBUF = 373,
VAR_SO_REUSEPORT = 374,
VAR_HARDEN_BELOW_NXDOMAIN = 375,
VAR_IGNORE_CD_FLAG = 376,
VAR_LOG_QUERIES = 377,
VAR_TCP_UPSTREAM = 378,
VAR_SSL_UPSTREAM = 379,
VAR_SSL_SERVICE_KEY = 380,
VAR_SSL_SERVICE_PEM = 381,
VAR_SSL_PORT = 382,
VAR_FORWARD_FIRST = 383,
VAR_STUB_FIRST = 384,
VAR_MINIMAL_RESPONSES = 385,
VAR_RRSET_ROUNDROBIN = 386,
VAR_MAX_UDP_SIZE = 387,
VAR_DELAY_CLOSE = 388,
VAR_UNBLOCK_LAN_ZONES = 389,
VAR_DNS64_PREFIX = 390,
VAR_DNS64_SYNTHALL = 391,
VAR_DNSTAP = 392,
VAR_DNSTAP_ENABLE = 393,
VAR_DNSTAP_SOCKET_PATH = 394,
VAR_DNSTAP_SEND_IDENTITY = 395,
VAR_DNSTAP_SEND_VERSION = 396,
VAR_DNSTAP_IDENTITY = 397,
VAR_DNSTAP_VERSION = 398,
VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES = 399,
VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES = 400,
VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES = 401,
VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES = 402,
VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES = 403,
VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES = 404
};
#endif
/* Tokens. */
@ -288,59 +289,60 @@ extern int yydebug;
#define VAR_SERVER_CERT_FILE 348
#define VAR_CONTROL_KEY_FILE 349
#define VAR_CONTROL_CERT_FILE 350
#define VAR_EXTENDED_STATISTICS 351
#define VAR_LOCAL_DATA_PTR 352
#define VAR_JOSTLE_TIMEOUT 353
#define VAR_STUB_PRIME 354
#define VAR_UNWANTED_REPLY_THRESHOLD 355
#define VAR_LOG_TIME_ASCII 356
#define VAR_DOMAIN_INSECURE 357
#define VAR_PYTHON 358
#define VAR_PYTHON_SCRIPT 359
#define VAR_VAL_SIG_SKEW_MIN 360
#define VAR_VAL_SIG_SKEW_MAX 361
#define VAR_CACHE_MIN_TTL 362
#define VAR_VAL_LOG_LEVEL 363
#define VAR_AUTO_TRUST_ANCHOR_FILE 364
#define VAR_KEEP_MISSING 365
#define VAR_ADD_HOLDDOWN 366
#define VAR_DEL_HOLDDOWN 367
#define VAR_SO_RCVBUF 368
#define VAR_EDNS_BUFFER_SIZE 369
#define VAR_PREFETCH 370
#define VAR_PREFETCH_KEY 371
#define VAR_SO_SNDBUF 372
#define VAR_SO_REUSEPORT 373
#define VAR_HARDEN_BELOW_NXDOMAIN 374
#define VAR_IGNORE_CD_FLAG 375
#define VAR_LOG_QUERIES 376
#define VAR_TCP_UPSTREAM 377
#define VAR_SSL_UPSTREAM 378
#define VAR_SSL_SERVICE_KEY 379
#define VAR_SSL_SERVICE_PEM 380
#define VAR_SSL_PORT 381
#define VAR_FORWARD_FIRST 382
#define VAR_STUB_FIRST 383
#define VAR_MINIMAL_RESPONSES 384
#define VAR_RRSET_ROUNDROBIN 385
#define VAR_MAX_UDP_SIZE 386
#define VAR_DELAY_CLOSE 387
#define VAR_UNBLOCK_LAN_ZONES 388
#define VAR_DNS64_PREFIX 389
#define VAR_DNS64_SYNTHALL 390
#define VAR_DNSTAP 391
#define VAR_DNSTAP_ENABLE 392
#define VAR_DNSTAP_SOCKET_PATH 393
#define VAR_DNSTAP_SEND_IDENTITY 394
#define VAR_DNSTAP_SEND_VERSION 395
#define VAR_DNSTAP_IDENTITY 396
#define VAR_DNSTAP_VERSION 397
#define VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES 398
#define VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES 399
#define VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES 400
#define VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES 401
#define VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES 402
#define VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES 403
#define VAR_CONTROL_USE_CERT 351
#define VAR_EXTENDED_STATISTICS 352
#define VAR_LOCAL_DATA_PTR 353
#define VAR_JOSTLE_TIMEOUT 354
#define VAR_STUB_PRIME 355
#define VAR_UNWANTED_REPLY_THRESHOLD 356
#define VAR_LOG_TIME_ASCII 357
#define VAR_DOMAIN_INSECURE 358
#define VAR_PYTHON 359
#define VAR_PYTHON_SCRIPT 360
#define VAR_VAL_SIG_SKEW_MIN 361
#define VAR_VAL_SIG_SKEW_MAX 362
#define VAR_CACHE_MIN_TTL 363
#define VAR_VAL_LOG_LEVEL 364
#define VAR_AUTO_TRUST_ANCHOR_FILE 365
#define VAR_KEEP_MISSING 366
#define VAR_ADD_HOLDDOWN 367
#define VAR_DEL_HOLDDOWN 368
#define VAR_SO_RCVBUF 369
#define VAR_EDNS_BUFFER_SIZE 370
#define VAR_PREFETCH 371
#define VAR_PREFETCH_KEY 372
#define VAR_SO_SNDBUF 373
#define VAR_SO_REUSEPORT 374
#define VAR_HARDEN_BELOW_NXDOMAIN 375
#define VAR_IGNORE_CD_FLAG 376
#define VAR_LOG_QUERIES 377
#define VAR_TCP_UPSTREAM 378
#define VAR_SSL_UPSTREAM 379
#define VAR_SSL_SERVICE_KEY 380
#define VAR_SSL_SERVICE_PEM 381
#define VAR_SSL_PORT 382
#define VAR_FORWARD_FIRST 383
#define VAR_STUB_FIRST 384
#define VAR_MINIMAL_RESPONSES 385
#define VAR_RRSET_ROUNDROBIN 386
#define VAR_MAX_UDP_SIZE 387
#define VAR_DELAY_CLOSE 388
#define VAR_UNBLOCK_LAN_ZONES 389
#define VAR_DNS64_PREFIX 390
#define VAR_DNS64_SYNTHALL 391
#define VAR_DNSTAP 392
#define VAR_DNSTAP_ENABLE 393
#define VAR_DNSTAP_SOCKET_PATH 394
#define VAR_DNSTAP_SEND_IDENTITY 395
#define VAR_DNSTAP_SEND_VERSION 396
#define VAR_DNSTAP_IDENTITY 397
#define VAR_DNSTAP_VERSION 398
#define VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES 399
#define VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES 400
#define VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES 401
#define VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES 402
#define VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES 403
#define VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES 404
@ -354,7 +356,7 @@ typedef union YYSTYPE
/* Line 2058 of yacc.c */
#line 358 "util/configparser.h"
#line 360 "util/configparser.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */

View file

@ -95,6 +95,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_PRIVATE_DOMAIN VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE
%token VAR_CONTROL_INTERFACE VAR_CONTROL_PORT VAR_SERVER_KEY_FILE
%token VAR_SERVER_CERT_FILE VAR_CONTROL_KEY_FILE VAR_CONTROL_CERT_FILE
%token VAR_CONTROL_USE_CERT
%token VAR_EXTENDED_STATISTICS VAR_LOCAL_DATA_PTR VAR_JOSTLE_TIMEOUT
%token VAR_STUB_PRIME VAR_UNWANTED_REPLY_THRESHOLD VAR_LOG_TIME_ASCII
%token VAR_DOMAIN_INSECURE VAR_PYTHON VAR_PYTHON_SCRIPT VAR_VAL_SIG_SKEW_MIN
@ -1271,7 +1272,7 @@ contents_rc: contents_rc content_rc
| ;
content_rc: rc_control_enable | rc_control_interface | rc_control_port |
rc_server_key_file | rc_server_cert_file | rc_control_key_file |
rc_control_cert_file
rc_control_cert_file | rc_control_use_cert
;
rc_control_enable: VAR_CONTROL_ENABLE STRING_ARG
{
@ -1299,6 +1300,16 @@ rc_control_interface: VAR_CONTROL_INTERFACE STRING_ARG
yyerror("out of memory");
}
;
rc_control_use_cert: VAR_CONTROL_USE_CERT STRING_ARG
{
OUTYY(("P(control_use_cert:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
else cfg_parser->cfg->remote_control_use_cert =
(strcmp($2, "yes")==0);
free($2);
}
;
rc_server_key_file: VAR_SERVER_KEY_FILE STRING_ARG
{
OUTYY(("P(rc_server_key_file:%s)\n", $2));

View file

@ -156,7 +156,7 @@ log_addr(enum verbosity_value v, const char* str,
case AF_INET6: family="ip6";
sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
break;
case AF_UNIX: family="unix"; break;
case AF_LOCAL: family="local"; break;
default: break;
}
if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
@ -313,7 +313,7 @@ void log_name_addr(enum verbosity_value v, const char* str, uint8_t* zone,
case AF_INET6: family="";
sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
break;
case AF_UNIX: family="unix_family "; break;
case AF_LOCAL: family="local "; break;
default: break;
}
if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {