305 lines
8.9 KiB
Diff
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
|