mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 14:53:15 -05:00
- Similar to NSD PR#113, implement that interface names can be used,
eg. something like interface: eth0 is resolved at server start and uses the IP addresses for that named interface.
This commit is contained in:
parent
a912786ca9
commit
f6a527c25a
11 changed files with 225 additions and 16 deletions
|
|
@ -272,6 +272,9 @@
|
|||
/* Define to 1 if you have the `getentropy' function. */
|
||||
#undef HAVE_GETENTROPY
|
||||
|
||||
/* Define to 1 if you have the `getifaddrs' function. */
|
||||
#undef HAVE_GETIFADDRS
|
||||
|
||||
/* Define to 1 if you have the <getopt.h> header file. */
|
||||
#undef HAVE_GETOPT_H
|
||||
|
||||
|
|
@ -302,6 +305,9 @@
|
|||
/* If we have htobe64 */
|
||||
#undef HAVE_HTOBE64
|
||||
|
||||
/* Define to 1 if you have the <ifaddrs.h> header file. */
|
||||
#undef HAVE_IFADDRS_H
|
||||
|
||||
/* Define to 1 if you have the `inet_aton' function. */
|
||||
#undef HAVE_INET_ATON
|
||||
|
||||
|
|
@ -371,6 +377,9 @@
|
|||
/* Define to 1 if you have the <nettle/eddsa.h> header file. */
|
||||
#undef HAVE_NETTLE_EDDSA_H
|
||||
|
||||
/* Define to 1 if you have the <net/if.h> header file. */
|
||||
#undef HAVE_NET_IF_H
|
||||
|
||||
/* Use libnss for crypto */
|
||||
#undef HAVE_NSS
|
||||
|
||||
|
|
|
|||
4
configure
vendored
4
configure
vendored
|
|
@ -14726,7 +14726,7 @@ $as_echo "no" >&6; }
|
|||
fi
|
||||
|
||||
# Checks for header files.
|
||||
for ac_header in stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.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 sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h
|
||||
for ac_header in stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.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 sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h net/if.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
|
||||
|
|
@ -20224,7 +20224,7 @@ if test "$ac_res" != no; then :
|
|||
|
||||
fi
|
||||
|
||||
for ac_func in tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4
|
||||
for ac_func in tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs
|
||||
do :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ ACX_LIBTOOL_C_ONLY
|
|||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.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 sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.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 sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h net/if.h],,, [AC_INCLUDES_DEFAULT])
|
||||
|
||||
# Check for Apple header. This uncovers TARGET_OS_IPHONE, TARGET_OS_TV or TARGET_OS_WATCH
|
||||
AC_CHECK_HEADERS([TargetConditionals.h])
|
||||
|
|
@ -1552,7 +1552,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([
|
|||
AC_MSG_RESULT(no))
|
||||
|
||||
AC_SEARCH_LIBS([setusercontext], [util])
|
||||
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4])
|
||||
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs])
|
||||
AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])])
|
||||
AC_CHECK_FUNCS([setresgid],,[AC_CHECK_FUNCS([setregid])])
|
||||
|
||||
|
|
|
|||
|
|
@ -308,6 +308,8 @@ daemon_open_shared_ports(struct daemon* daemon)
|
|||
{
|
||||
log_assert(daemon);
|
||||
if(daemon->cfg->port != daemon->listening_port) {
|
||||
char** resif = NULL;
|
||||
int num_resif = 0;
|
||||
size_t i;
|
||||
struct listen_port* p0;
|
||||
daemon->reuseport = 0;
|
||||
|
|
@ -318,15 +320,18 @@ daemon_open_shared_ports(struct daemon* daemon)
|
|||
free(daemon->ports);
|
||||
daemon->ports = NULL;
|
||||
}
|
||||
if(!resolve_interface_names(daemon->cfg, &resif, &num_resif))
|
||||
return 0;
|
||||
/* see if we want to reuseport */
|
||||
#ifdef SO_REUSEPORT
|
||||
if(daemon->cfg->so_reuseport && daemon->cfg->num_threads > 0)
|
||||
daemon->reuseport = 1;
|
||||
#endif
|
||||
/* try to use reuseport */
|
||||
p0 = listening_ports_open(daemon->cfg, &daemon->reuseport);
|
||||
p0 = listening_ports_open(daemon->cfg, resif, num_resif, &daemon->reuseport);
|
||||
if(!p0) {
|
||||
listening_ports_free(p0);
|
||||
config_del_strarray(resif, num_resif);
|
||||
return 0;
|
||||
}
|
||||
if(daemon->reuseport) {
|
||||
|
|
@ -340,6 +345,7 @@ daemon_open_shared_ports(struct daemon* daemon)
|
|||
if(!(daemon->ports = (struct listen_port**)calloc(
|
||||
daemon->num_ports, sizeof(*daemon->ports)))) {
|
||||
listening_ports_free(p0);
|
||||
config_del_strarray(resif, num_resif);
|
||||
return 0;
|
||||
}
|
||||
daemon->ports[0] = p0;
|
||||
|
|
@ -348,16 +354,19 @@ daemon_open_shared_ports(struct daemon* daemon)
|
|||
for(i=1; i<daemon->num_ports; i++) {
|
||||
if(!(daemon->ports[i]=
|
||||
listening_ports_open(daemon->cfg,
|
||||
resif, num_resif,
|
||||
&daemon->reuseport))
|
||||
|| !daemon->reuseport ) {
|
||||
for(i=0; i<daemon->num_ports; i++)
|
||||
listening_ports_free(daemon->ports[i]);
|
||||
free(daemon->ports);
|
||||
daemon->ports = NULL;
|
||||
config_del_strarray(resif, num_resif);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
config_del_strarray(resif, num_resif);
|
||||
daemon->listening_port = daemon->cfg->port;
|
||||
}
|
||||
if(!daemon->cfg->remote_control_enable && daemon->rc_port) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
27 August 2020: Wouter
|
||||
- Similar to NSD PR#113, implement that interface names can be used,
|
||||
eg. something like interface: eth0 is resolved at server start and
|
||||
uses the IP addresses for that named interface.
|
||||
|
||||
26 August 2020: George
|
||||
- Update documentation in python example code.
|
||||
|
||||
|
|
|
|||
|
|
@ -122,7 +122,8 @@ The port number, default 53, on which the server responds to queries.
|
|||
Interface to use to connect to the network. This interface is listened to
|
||||
for queries from clients, and answers to clients are given from it.
|
||||
Can be given multiple times to work on several interfaces. If none are
|
||||
given the default is to listen to localhost.
|
||||
given the default is to listen to localhost. If an interface name is used
|
||||
instead of an ip address, the list of ip addresses on that interface are used.
|
||||
The interfaces are not changed on a reload (kill \-HUP) but only on restart.
|
||||
A port number can be specified with @port (without spaces between
|
||||
interface and port number), if not specified the default port (from
|
||||
|
|
|
|||
|
|
@ -70,6 +70,13 @@
|
|||
#include <systemd/sd-daemon.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_H
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
/** number of queued TCP connections for listen() */
|
||||
#define TCP_BACKLOG 256
|
||||
|
||||
|
|
@ -1439,8 +1446,163 @@ listen_delete(struct listen_dnsport* front)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_GETIFADDRS
|
||||
static int
|
||||
resolve_ifa_name(struct ifaddrs *ifas, const char *search_ifa, char ***ip_addresses, int *ip_addresses_size)
|
||||
{
|
||||
struct ifaddrs *ifa;
|
||||
int last_ip_addresses_size = *ip_addresses_size;
|
||||
|
||||
for(ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
|
||||
sa_family_t family;
|
||||
const char* atsign;
|
||||
#ifdef INET6 /* | address ip | % | ifa name | @ | port | nul */
|
||||
char addr_buf[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 1 + 16 + 1];
|
||||
#else
|
||||
char addr_buf[INET_ADDRSTRLEN + 1 + 16 + 1];
|
||||
#endif
|
||||
|
||||
if((atsign=strrchr(search_ifa, '@')) != NULL) {
|
||||
if(strlen(ifa->ifa_name) != (size_t)(atsign-search_ifa)
|
||||
|| strncmp(ifa->ifa_name, search_ifa,
|
||||
atsign-search_ifa) != 0)
|
||||
continue;
|
||||
} else {
|
||||
if(strcmp(ifa->ifa_name, search_ifa) != 0)
|
||||
continue;
|
||||
atsign = "";
|
||||
}
|
||||
|
||||
if(ifa->ifa_addr == NULL)
|
||||
continue;
|
||||
|
||||
family = ifa->ifa_addr->sa_family;
|
||||
if(family == AF_INET) {
|
||||
char a4[INET_ADDRSTRLEN + 1];
|
||||
struct sockaddr_in *in4 = (struct sockaddr_in *)
|
||||
ifa->ifa_addr;
|
||||
if(!inet_ntop(family, &in4->sin_addr, a4, sizeof(a4))) {
|
||||
log_err("inet_ntop failed");
|
||||
return 0;
|
||||
}
|
||||
snprintf(addr_buf, sizeof(addr_buf), "%s%s",
|
||||
a4, atsign);
|
||||
}
|
||||
#ifdef INET6
|
||||
else if(family == AF_INET6) {
|
||||
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)
|
||||
ifa->ifa_addr;
|
||||
char a6[INET6_ADDRSTRLEN + 1];
|
||||
char if_index_name[IF_NAMESIZE + 1];
|
||||
if_index_name[0] = 0;
|
||||
if(!inet_ntop(family, &in6->sin6_addr, a6, sizeof(a6))) {
|
||||
log_err("inet_ntop failed");
|
||||
return 0;
|
||||
}
|
||||
if_indextoname(in6->sin6_scope_id,
|
||||
(char *)if_index_name);
|
||||
if (strlen(if_index_name) != 0) {
|
||||
snprintf(addr_buf, sizeof(addr_buf),
|
||||
"%s%%%s%s", a6, if_index_name, atsign);
|
||||
} else {
|
||||
snprintf(addr_buf, sizeof(addr_buf), "%s%s",
|
||||
a6, atsign);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
verbose(4, "interface %s has address %s", search_ifa, addr_buf);
|
||||
|
||||
*ip_addresses = realloc(*ip_addresses, sizeof(char *) * (*ip_addresses_size + 1));
|
||||
if(!*ip_addresses) {
|
||||
log_err("realloc failed: out of memory");
|
||||
return 0;
|
||||
}
|
||||
(*ip_addresses)[*ip_addresses_size] = strdup(addr_buf);
|
||||
if(!(*ip_addresses)[*ip_addresses_size]) {
|
||||
log_err("strdup failed: out of memory");
|
||||
return 0;
|
||||
}
|
||||
(*ip_addresses_size)++;
|
||||
}
|
||||
|
||||
if (*ip_addresses_size == last_ip_addresses_size) {
|
||||
*ip_addresses = realloc(*ip_addresses, sizeof(char *) * (*ip_addresses_size + 1));
|
||||
if(!*ip_addresses) {
|
||||
log_err("realloc failed: out of memory");
|
||||
return 0;
|
||||
}
|
||||
(*ip_addresses)[*ip_addresses_size] = strdup(search_ifa);
|
||||
if(!(*ip_addresses)[*ip_addresses_size]) {
|
||||
log_err("strdup failed: out of memory");
|
||||
return 0;
|
||||
}
|
||||
(*ip_addresses_size)++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif /* HAVE_GETIFADDRS */
|
||||
|
||||
int resolve_interface_names(struct config_file* cfg, char*** resif,
|
||||
int* num_resif)
|
||||
{
|
||||
#ifdef HAVE_GETIFADDRS
|
||||
int i;
|
||||
struct ifaddrs *addrs;
|
||||
if(cfg->num_ifs == 0) {
|
||||
*resif = NULL;
|
||||
*num_resif = 0;
|
||||
return 1;
|
||||
}
|
||||
if(getifaddrs(&addrs) == -1) {
|
||||
log_err("failed to list interfaces: getifaddrs: %s",
|
||||
strerror(errno));
|
||||
freeifaddrs(addrs);
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<cfg->num_ifs; i++) {
|
||||
if(!resolve_ifa_name(addrs, cfg->ifs[i], resif, num_resif)) {
|
||||
freeifaddrs(addrs);
|
||||
config_del_strarray(*resif, *num_resif);
|
||||
*resif = NULL;
|
||||
*num_resif = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
freeifaddrs(addrs);
|
||||
return 1;
|
||||
#else
|
||||
int i;
|
||||
if(cfg->num_ifs == 0) {
|
||||
*resif = NULL;
|
||||
*num_resif = 0;
|
||||
return 1;
|
||||
}
|
||||
*num_resif = cfg->num_ifs;
|
||||
*resif = calloc(*num_resif, sizeof(**resif));
|
||||
if(!*resif) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<*num_resif; i++) {
|
||||
(*resif)[i] = strdup(cfg->ifs[i]);
|
||||
if(!((*resif)[i])) {
|
||||
log_err("out of memory");
|
||||
config_del_strarray(*resif, *num_resif);
|
||||
*resif = NULL;
|
||||
*num_resif = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
#endif /* HAVE_GETIFADDRS */
|
||||
}
|
||||
|
||||
struct listen_port*
|
||||
listening_ports_open(struct config_file* cfg, int* reuseport)
|
||||
listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
|
||||
int* reuseport)
|
||||
{
|
||||
struct listen_port* list = NULL;
|
||||
struct addrinfo hints;
|
||||
|
|
@ -1459,7 +1621,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport)
|
|||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
/* no name lookups on our listening ports */
|
||||
if(cfg->num_ifs > 0)
|
||||
if(num_ifs > 0)
|
||||
hints.ai_flags |= AI_NUMERICHOST;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
#ifndef INET6
|
||||
|
|
@ -1469,7 +1631,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport)
|
|||
return NULL;
|
||||
}
|
||||
/* create ip4 and ip6 ports so that return addresses are nice. */
|
||||
if(do_auto || cfg->num_ifs == 0) {
|
||||
if(do_auto || num_ifs == 0) {
|
||||
if(do_ip6) {
|
||||
hints.ai_family = AF_INET6;
|
||||
if(!ports_create_if(do_auto?"::0":"::1",
|
||||
|
|
@ -1498,12 +1660,12 @@ listening_ports_open(struct config_file* cfg, int* reuseport)
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
} else for(i = 0; i<cfg->num_ifs; i++) {
|
||||
if(str_is_ip6(cfg->ifs[i])) {
|
||||
} else for(i = 0; i<num_ifs; i++) {
|
||||
if(str_is_ip6(ifs[i])) {
|
||||
if(!do_ip6)
|
||||
continue;
|
||||
hints.ai_family = AF_INET6;
|
||||
if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
|
||||
if(!ports_create_if(ifs[i], 0, cfg->do_udp,
|
||||
do_tcp, &hints, portbuf, &list,
|
||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||
cfg->ssl_port, cfg->tls_additional_port,
|
||||
|
|
@ -1517,7 +1679,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport)
|
|||
if(!do_ip4)
|
||||
continue;
|
||||
hints.ai_family = AF_INET;
|
||||
if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
|
||||
if(!ports_create_if(ifs[i], 0, cfg->do_udp,
|
||||
do_tcp, &hints, portbuf, &list,
|
||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||
cfg->ssl_port, cfg->tls_additional_port,
|
||||
|
|
|
|||
|
|
@ -117,19 +117,32 @@ struct listen_port {
|
|||
* interfaces for IP4 and/or IP6, for UDP and/or TCP.
|
||||
* On the given port number. It creates the sockets.
|
||||
* @param cfg: settings on what ports to open.
|
||||
* @param ifs: interfaces to open, array of IP addresses, ip[@port].
|
||||
* @param num_ifs: length of ifs.
|
||||
* @param reuseport: set to true if you want reuseport, or NULL to not have it,
|
||||
* set to false on exit if reuseport failed to apply (because of no
|
||||
* kernel support).
|
||||
* @return: linked list of ports or NULL on error.
|
||||
*/
|
||||
struct listen_port* listening_ports_open(struct config_file* cfg,
|
||||
int* reuseport);
|
||||
char** ifs, int num_ifs, int* reuseport);
|
||||
|
||||
/**
|
||||
* Close and delete the (list of) listening ports.
|
||||
*/
|
||||
void listening_ports_free(struct listen_port* list);
|
||||
|
||||
/**
|
||||
* Resolve interface names in config and store result IP addresses
|
||||
* @param cfg: config
|
||||
* @param resif: string array (malloced array of malloced strings) with
|
||||
* result. NULL if cfg has none.
|
||||
* @param num_resif: length of resif. Zero if cfg has zero num_ifs.
|
||||
* @return 0 on failure.
|
||||
*/
|
||||
int resolve_interface_names(struct config_file* cfg, char*** resif,
|
||||
int* num_resif);
|
||||
|
||||
/**
|
||||
* Create commpoints with for this thread for the shared ports.
|
||||
* @param base: the comm_base that provides event functionality.
|
||||
|
|
|
|||
|
|
@ -1300,7 +1300,14 @@ void outnet_serviced_query_stop(struct serviced_query* sq, void* cb_arg)
|
|||
log_info("double delete of pending serviced query");
|
||||
}
|
||||
|
||||
int resolve_interface_names(struct config_file* ATTR_UNUSED(cfg),
|
||||
char*** ATTR_UNUSED(resif), int* ATTR_UNUSED(num_resif))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg),
|
||||
char** ATTR_UNUSED(ifs), int ATTR_UNUSED(num_ifs),
|
||||
int* ATTR_UNUSED(reuseport))
|
||||
{
|
||||
return calloc(1, 1);
|
||||
|
|
|
|||
|
|
@ -1387,8 +1387,8 @@ config_delviews(struct config_view* p)
|
|||
p = np;
|
||||
}
|
||||
}
|
||||
/** delete string array */
|
||||
static void
|
||||
|
||||
void
|
||||
config_del_strarray(char** array, int num)
|
||||
{
|
||||
int i;
|
||||
|
|
|
|||
|
|
@ -969,6 +969,9 @@ void config_deldblstrlist(struct config_str2list* list);
|
|||
*/
|
||||
void config_deltrplstrlist(struct config_str3list* list);
|
||||
|
||||
/** delete string array */
|
||||
void config_del_strarray(char** array, int num);
|
||||
|
||||
/** delete stringbytelist */
|
||||
void config_del_strbytelist(struct config_strbytelist* list);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue