diff options
Diffstat (limited to 'external/unbound/contrib/unbound_unixsock.diff')
-rw-r--r-- | external/unbound/contrib/unbound_unixsock.diff | 305 |
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 |