From 7076f000ea3487299a9da9318915d042aaba62c5 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Wed, 19 Jul 2006 00:42:13 +0000 Subject: [PATCH] 2048. [bug] It was possible to loop forever when using avoid-v4-udp-ports / avoid-v6-udp-ports when the OS always returned the same local port. [RT #16182] --- CHANGES | 5 +++++ lib/dns/dispatch.c | 41 ++++++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/CHANGES b/CHANGES index 71735c3d84..c8237e56d9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +2048. [bug] It was possible to loop forever when using + avoid-v4-udp-ports / avoid-v6-udp-ports when + the OS always returned the same local port. + [RT #16182] + 2047. [bug] Failed to initialise the interface flags to zero. [RT #16245] diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 91607027ea..2a12d3cb71 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dispatch.c,v 1.126 2006/01/06 00:01:44 marka Exp $ */ +/* $Id: dispatch.c,v 1.127 2006/07/19 00:42:13 marka Exp $ */ /*! \file */ @@ -1735,6 +1735,11 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, /* * mgr should be locked. */ + +#ifndef DNS_DISPATCH_HELD +#define DNS_DISPATCH_HELD 20U +#endif + static isc_result_t dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_taskmgr_t *taskmgr, @@ -1745,7 +1750,9 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, { isc_result_t result; dns_dispatch_t *disp; - isc_socket_t *sock; + isc_socket_t *sock = NULL; + isc_socket_t *held[DNS_DISPATCH_HELD]; + unsigned int i = 0, j = 0; /* * dispatch_allocate() checks mgr for us. @@ -1756,17 +1763,30 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, return (result); /* - * This assumes that the IP stack will *not* quickly reallocate - * the same port. If it does continually reallocate the same port - * then we need a mechanism to hold all the blacklisted sockets - * until we find a usable socket. + * Try to allocate a socket that is not on the blacklist. + * Hold up to DNS_DISPATCH_HELD sockets to prevent the OS + * from returning the same port to us too quickly. */ + memset(held, 0, sizeof(held)); getsocket: result = create_socket(sockmgr, localaddr, &sock); if (result != ISC_R_SUCCESS) goto deallocate_dispatch; if (isc_sockaddr_getport(localaddr) == 0 && blacklisted(mgr, sock)) { - isc_socket_detach(&sock); + if (held[i] != NULL) + isc_socket_detach(&held[i]); + held[i++] = sock; + sock = NULL; + if (i == DNS_DISPATCH_HELD) + i = 0; + if (j++ == 0xffffU) { + mgr_log(mgr, ISC_LOG_ERROR, "avoid-v%s-udp-ports: " + "unable to allocate a non-blacklisted port", + isc_sockaddr_pf(localaddr) == AF_INET ? + "4" : "6"); + result = ISC_R_FAILURE; + goto deallocate_dispatch; + } goto getsocket; } @@ -1803,7 +1823,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, *dispp = disp; - return (ISC_R_SUCCESS); + goto cleanheld; /* * Error returns. @@ -1814,7 +1834,10 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_socket_detach(&disp->socket); deallocate_dispatch: dispatch_free(&disp); - + cleanheld: + for (i = 0; i < DNS_DISPATCH_HELD; i++) + if (held[i] != NULL) + isc_socket_detach(&held[i]); return (result); }