danicoin/external/unbound/contrib/unbound_unixsock.diff
2014-10-05 23:44:31 +02:00

305 lines
8.9 KiB
Diff

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