aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/contrib/unbound_unixsock.diff
diff options
context:
space:
mode:
Diffstat (limited to 'external/unbound/contrib/unbound_unixsock.diff')
-rw-r--r--external/unbound/contrib/unbound_unixsock.diff305
1 files changed, 305 insertions, 0 deletions
diff --git a/external/unbound/contrib/unbound_unixsock.diff b/external/unbound/contrib/unbound_unixsock.diff
new file mode 100644
index 000000000..09d05d392
--- /dev/null
+++ b/external/unbound/contrib/unbound_unixsock.diff
@@ -0,0 +1,305 @@
+diff --git a/daemon/remote.c b/daemon/remote.c
+index a2b2204..b6990f3 100644
+--- a/daemon/remote.c
++++ b/daemon/remote.c
+@@ -81,6 +81,11 @@
+ #ifdef HAVE_NETDB_H
+ #include <netdb.h>
+ #endif
++#ifdef HAVE_PWD_H
++#include <pwd.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#endif
+
+ /* just for portability */
+ #ifdef SQ
+@@ -235,7 +240,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;
+@@ -246,29 +252,74 @@ 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 UNIX socket! */
++ fd = create_domain_accept_sock(ip);
++/*
++ * When unbound starts, it first creates a socket and then
++ * drops privs, so the socket is created as root user.
++ * This is fine, but we would like to set _unbound user group
++ * for this socket, and permissions should be 0660 so only
++ * root and _unbound group members can invoke unbound-control.
++ * The username used here is the same as username that unbound
++ * uses for its worker processes.
++ */
++
++/*
++ * Note: this code is an exact copy of code from daemon.c
++ * Normally this should be either wrapped into a function,
++ * or gui/gid values should be retrieved at config parsing time
++ * and then stored in configfile structure.
++ * This requires action from unbound developers!
++*/
++#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();
+ }
++
++ chown(ip, 0, gid);
++ chmod(ip, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
++#endif
++ } 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):""
+ #else
+ ""
+ #endif
+ );
+- return 0;
++ return 0;
++ }
++
++ /* open fd */
++ fd = create_tcp_accept_sock(res, 1, &noproto);
++ freeaddrinfo(res);
+ }
+
+- /* open fd */
+- fd = create_tcp_accept_sock(res, 1, &noproto);
+- freeaddrinfo(res);
+ if(fd == -1 && noproto) {
+ if(!noproto_is_err)
+ return 1; /* return success, but do nothing */
+@@ -305,7 +356,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;
+ }
+@@ -313,12 +364,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;
+ }
+diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c
+index ea7ec3a..4cb04e2 100644
+--- a/services/listen_dnsport.c
++++ b/services/listen_dnsport.c
+@@ -55,6 +55,10 @@
+ #endif
+ #include <fcntl.h>
+
++#ifndef USE_WINSOCK
++#include <sys/un.h>
++#endif
++
+ /** number of queued TCP connections for listen() */
+ #define TCP_BACKLOG 5
+
+@@ -376,6 +380,53 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
+ }
+
+ int
++create_domain_accept_sock(char *path) {
++ int s;
++ struct sockaddr_un unixaddr;
++
++#ifndef USE_WINSOCK
++ unixaddr.sun_len = sizeof(unixaddr);
++ unixaddr.sun_family = AF_UNIX;
++ strlcpy(unixaddr.sun_path, path, 104);
++
++ if((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
++ log_err("Cannot create UNIX 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 UNIX socket %s (%s)",
++ path, strerror(errno));
++ return -1;
++ }
++
++ if(bind(s, (struct sockaddr *) &unixaddr,
++ sizeof(struct sockaddr_un)) == -1) {
++ log_err("Cannot bind UNIX 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;
++ }
++
++ return s;
++#else
++ log_err("UNIX sockets are not supported");
++ return -1;
++#endif
++}
++
++int
+ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto)
+ {
+ int s;
+diff --git a/smallapp/unbound-control.c b/smallapp/unbound-control.c
+index a872f92..10631fd 100644
+--- a/smallapp/unbound-control.c
++++ b/smallapp/unbound-control.c
+@@ -59,6 +59,8 @@
+ #include "util/locks.h"
+ #include "util/net_help.h"
+
++#include <sys/un.h>
++
+ /** Give unbound-control usage, and exit (1). */
+ static void
+ usage()
+@@ -158,6 +160,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) {
+@@ -176,12 +179,21 @@ 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);
++ } else if(svr[0] == '/') {
++ struct sockaddr_un* unixsock = (struct sockaddr_un *) &addr;
++ unixsock->sun_family = AF_UNIX;
++ unixsock->sun_len = sizeof(unixsock);
++ strlcpy(unixsock->sun_path, svr, 104);
++ addrlen = sizeof(struct sockaddr_un);
++ addrfamily = AF_UNIX;
+ } 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 != AF_UNIX)
++ 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));
+diff --git a/util/net_help.c b/util/net_help.c
+index b3136a3..5b5b4a3 100644
+--- a/util/net_help.c
++++ b/util/net_help.c
+@@ -45,6 +45,7 @@
+ #include "util/module.h"
+ #include "util/regional.h"
+ #include <fcntl.h>
++#include <sys/un.h>
+ #include <openssl/ssl.h>
+ #include <openssl/err.h>
+
+@@ -135,7 +136,7 @@ log_addr(enum verbosity_value v, const char* str,
+ {
+ uint16_t port;
+ const char* family = "unknown";
+- char dest[100];
++ char dest[108];
+ int af = (int)((struct sockaddr_in*)addr)->sin_family;
+ void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
+ if(verbosity < v)
+@@ -148,15 +149,23 @@ log_addr(enum verbosity_value v, const char* str,
+ case AF_UNIX: family="unix"; break;
+ default: break;
+ }
+- if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
+- strncpy(dest, "(inet_ntop error)", sizeof(dest));
++
++ if(af != AF_UNIX) {
++ if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
++ strncpy(dest, "(inet_ntop error)", sizeof(dest));
++ }
++ dest[sizeof(dest)-1] = 0;
++ port = ntohs(((struct sockaddr_in*)addr)->sin_port);
++ if(verbosity >= 4)
++ verbose(v, "%s %s %s port %d (len %d)", str, family,
++ dest, (int)port, (int)addrlen);
++ else verbose(v, "%s %s port %d", str, dest, (int)port);
++ } else {
++ struct sockaddr_un* unixsock;
++ unixsock = (struct sockaddr_un *) addr;
++ strlcpy(dest, unixsock->sun_path, sizeof(dest));
++ verbose(v, "%s %s %s", str, family, dest);
+ }
+- dest[sizeof(dest)-1] = 0;
+- port = ntohs(((struct sockaddr_in*)addr)->sin_port);
+- if(verbosity >= 4)
+- verbose(v, "%s %s %s port %d (len %d)", str, family, dest,
+- (int)port, (int)addrlen);
+- else verbose(v, "%s %s port %d", str, dest, (int)port);
+ }
+
+ int