From a295fbb55cfed38bcf2853c60410cce52ab6cebb Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 5 Jan 2006 03:26:01 +0000 Subject: [PATCH] 1961. [bug] Check the port and address of responses forwarded to dispatch. [RT #15474] --- CHANGES | 3 +++ lib/dns/dispatch.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 563958e06d..020bbbc75c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +1961. [bug] Check the port and address of responses forwarded + to dispatch. [RT #15474] + 1960. [bug] Update code should set NSEC ttls from SOA MINIMUM. [RT #15465] diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 72bf1058a2..e7da8f1bd1 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dispatch.c,v 1.124 2005/07/12 01:00:14 marka Exp $ */ +/* $Id: dispatch.c,v 1.125 2006/01/05 03:26:01 marka Exp $ */ /*! \file */ @@ -643,6 +643,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) {