summaryrefslogtreecommitdiffstats
path: root/contrib/bind9/lib/dns/dispatch.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind9/lib/dns/dispatch.c')
-rw-r--r--contrib/bind9/lib/dns/dispatch.c87
1 files changed, 77 insertions, 10 deletions
diff --git a/contrib/bind9/lib/dns/dispatch.c b/contrib/bind9/lib/dns/dispatch.c
index 8534fe1..91ef2c5 100644
--- a/contrib/bind9/lib/dns/dispatch.c
+++ b/contrib/bind9/lib/dns/dispatch.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dispatch.c,v 1.101.2.6.2.10 2004/09/01 04:27:41 marka Exp $ */
+/* $Id: dispatch.c,v 1.101.2.6.2.13 2006/07/19 00:44:04 marka Exp $ */
#include <config.h>
@@ -641,6 +641,50 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
free_buffer(disp, ev->region.base, ev->region.length);
goto unlock;
}
+
+ /*
+ * Now that we have the original dispatch the query was sent
+ * from check that the address and port the response was
+ * sent to make sense.
+ */
+ if (disp != resp->disp) {
+ isc_sockaddr_t a1;
+ isc_sockaddr_t a2;
+
+ /*
+ * Check that the socket types and ports match.
+ */
+ if (disp->socktype != resp->disp->socktype ||
+ isc_sockaddr_getport(&disp->local) !=
+ isc_sockaddr_getport(&resp->disp->local)) {
+ free_buffer(disp, ev->region.base, ev->region.length);
+ goto unlock;
+ }
+
+ /*
+ * If both dispatches are bound to an address then fail as
+ * the addresses can't be equal (enforced by the IP stack).
+ *
+ * Note under Linux a packet can be sent out via IPv4 socket
+ * and the response be received via a IPv6 socket.
+ *
+ * Requests sent out via IPv6 should always come back in
+ * via IPv6.
+ */
+ if (isc_sockaddr_pf(&resp->disp->local) == PF_INET6 &&
+ isc_sockaddr_pf(&disp->local) != PF_INET6) {
+ free_buffer(disp, ev->region.base, ev->region.length);
+ goto unlock;
+ }
+ isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local));
+ isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local));
+ if (!isc_sockaddr_eqaddr(&a1, &resp->disp->local) &&
+ !isc_sockaddr_eqaddr(&a2, &disp->local)) {
+ free_buffer(disp, ev->region.base, ev->region.length);
+ goto unlock;
+ }
+ }
+
queue_response = resp->item_out;
rev = allocate_event(resp->disp);
if (rev == NULL) {
@@ -1687,6 +1731,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,
@@ -1697,7 +1746,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.
@@ -1708,17 +1759,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;
}
@@ -1755,7 +1819,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
*dispp = disp;
- return (ISC_R_SUCCESS);
+ goto cleanheld;
/*
* Error returns.
@@ -1766,7 +1830,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);
}
OpenPOWER on IntegriCloud