From: Florian Obser Date: Fri, 10 Jan 2020 12:55:55 +0000 (+0100) Subject: Allow the kernel to provide random source ports. X-Git-Tag: release-1.11.0~93^2~2^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5aaa5e253deac0f6ea0d45305668b20031f4610e;p=thirdparty%2Funbound.git Allow the kernel to provide random source ports. On some operating systems, for example OpenBSD since some decades, the kernel binds to a random source port if asked for any port (port number 0). There is no need to replicate this functionality in userland. --- diff --git a/config.h.in b/config.h.in index 78d47fedc..4f419604c 100644 --- a/config.h.in +++ b/config.h.in @@ -805,6 +805,10 @@ /* Define to 1 to use ipset support */ #undef USE_IPSET +/* Define to 1 to disable explict UDP source port randomisation and rely on the + kernel to provide random source ports */ +#undef DISABLE_EXPLICIT_PORT_RANDOMISATION + /* Define if you want to use internal select based events */ #undef USE_MINI_EVENT diff --git a/configure b/configure index bdec1f002..744defe21 100755 --- a/configure +++ b/configure @@ -890,6 +890,7 @@ enable_cachedb enable_ipsecmod enable_ipset with_libmnl +enable_explicit_port_randomisation with_libunbound_only ' ac_precious_vars='build_alias @@ -1579,6 +1580,9 @@ Optional Features: --enable-ipsecmod Enable ipsecmod module that facilitates opportunistic IPsec --enable-ipset enable ipset module + --disable-explicit-port-randomisation + disable explicit source port randomisation and rely + on the kernel to provide random source ports Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -21443,6 +21447,21 @@ $as_echo "found in $dir" >&6; } # nothing ;; esac +# Check whether --enable-explicit-port-randomisation was given. +if test "${enable_explicit_port_randomisation+set}" = set; then : + enableval=$enable_explicit_port_randomisation; +fi + +case "$enable_explicit_port_randomisation" in + no) + +$as_echo "#define DISABLE_EXPLICIT_PORT_RANDOMISATION 1" >>confdefs.h + + ;; + yes|*) + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ${MAKE:-make} supports $< with implicit rule in scope" >&5 $as_echo_n "checking if ${MAKE:-make} supports $< with implicit rule in scope... " >&6; } diff --git a/configure.ac b/configure.ac index 3e00c999c..d58c825d0 100644 --- a/configure.ac +++ b/configure.ac @@ -1778,6 +1778,15 @@ case "$enable_ipset" in # nothing ;; esac +AC_ARG_ENABLE(explicit-port-randomisation, AC_HELP_STRING([--disable-explicit-port-randomisation], [disable explicit source port randomisation and rely on the kernel to provide random source ports])) +case "$enable_explicit_port_randomisation" in + no) + AC_DEFINE([DISABLE_EXPLICIT_PORT_RANDOMISATION], [1], [Define this to enable kernel based UDP source port randomization.]) + ;; + yes|*) + ;; +esac + AC_MSG_CHECKING([if ${MAKE:-make} supports $< with implicit rule in scope]) # on openBSD, the implicit rule make $< work. diff --git a/services/outside_network.c b/services/outside_network.c index d3ebe04f6..1e83bf3a1 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -514,7 +514,9 @@ portcomm_loweruse(struct outside_network* outnet, struct port_comm* pc) comm_point_close(pc->cp); pif = pc->pif; log_assert(pif->inuse > 0); +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION pif->avail_ports[pif->avail_total - pif->inuse] = pc->number; +#endif pif->inuse--; pif->out[pc->index] = pif->out[pif->inuse]; pif->out[pc->index]->index = pc->index; @@ -727,10 +729,12 @@ create_pending_tcp(struct outside_network* outnet, size_t bufsize) static int setup_if(struct port_if* pif, const char* addrstr, int* avail, int numavail, size_t numfd) { +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION pif->avail_total = numavail; pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int)); if(!pif->avail_ports) return 0; +#endif if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) && !netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen, &pif->pfxlen)) @@ -957,7 +961,9 @@ outside_network_delete(struct outside_network* outnet) comm_point_delete(pc->cp); free(pc); } +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION free(outnet->ip4_ifs[i].avail_ports); +#endif free(outnet->ip4_ifs[i].out); } free(outnet->ip4_ifs); @@ -971,7 +977,9 @@ outside_network_delete(struct outside_network* outnet) comm_point_delete(pc->cp); free(pc); } +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION free(outnet->ip6_ifs[i].avail_ports); +#endif free(outnet->ip6_ifs[i].out); } free(outnet->ip6_ifs); @@ -1135,6 +1143,7 @@ select_ifport(struct outside_network* outnet, struct pending* pend, while(1) { my_if = ub_random_max(outnet->rnd, num_if); pif = &ifs[my_if]; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION my_port = ub_random_max(outnet->rnd, pif->avail_total); if(my_port < pif->inuse) { /* port already open */ @@ -1146,6 +1155,9 @@ select_ifport(struct outside_network* outnet, struct pending* pend, /* try to open new port, if fails, loop to try again */ log_assert(pif->inuse < pif->maxout); portno = pif->avail_ports[my_port - pif->inuse]; +#else + my_port = portno = 0; +#endif fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen, portno, &inuse, outnet->rnd); if(fd == -1 && !inuse) { @@ -1169,8 +1181,10 @@ select_ifport(struct outside_network* outnet, struct pending* pend, /* grab port in interface */ pif->out[pif->inuse] = pend->pc; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION pif->avail_ports[my_port - pif->inuse] = pif->avail_ports[pif->avail_total-pif->inuse-1]; +#endif pif->inuse++; break; } @@ -2227,6 +2241,7 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr, } addr = &pif->addr; addrlen = pif->addrlen; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION pnum = ub_random_max(outnet->rnd, pif->avail_total); if(pnum < pif->inuse) { /* port already open */ @@ -2235,7 +2250,9 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr, /* unused ports in start part of array */ port = pif->avail_ports[pnum - pif->inuse]; } - +#else + pnum = port = 0; +#endif if(addr_is_ip6(to_addr, to_addrlen)) { struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr; sa.sin6_port = (in_port_t)htons((uint16_t)port); @@ -2459,7 +2476,10 @@ if_get_mem(struct port_if* pif) { size_t s; int i; - s = sizeof(*pif) + sizeof(int)*pif->avail_total + + s = sizeof(*pif) + +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + sizeof(int)*pif->avail_total + +#endif sizeof(struct port_comm*)*pif->maxout; for(i=0; iinuse; i++) s += sizeof(*pif->out[i]) + diff --git a/services/outside_network.h b/services/outside_network.h index 3456a3da3..f12b2e5be 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -172,11 +172,13 @@ struct port_if { * if 0, no randomisation. */ int pfxlen; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION /** the available ports array. These are unused. * Only the first total-inuse part is filled. */ int* avail_ports; /** the total number of available ports (size of the array) */ int avail_total; +#endif /** array of the commpoints currently in use. * allocated for max number of fds, first part in use. */