developer: jinmei

reviewer: marka
1371    [bug]           notify-source-v6, transfer-source-v6 and
                        query-source-v6 with explict addresses and using the
                        same ports as named was listening on could interfere
                        with nameds ability to answer queries sent to those
                        addresses.
This commit is contained in:
Mark Andrews 2002-08-30 02:05:30 +00:00
parent 1b5b46942d
commit 3bdf879a53
4 changed files with 297 additions and 60 deletions

View file

@ -1,3 +1,9 @@
1371 [bug] notify-source-v6, transfer-source-v6 and
query-source-v6 with explict addresses and using the
same ports as named was listening on could interfere
with nameds ability to answer queries sent to those
addresses.
1370. [bug] dig '+[no]recurse' was incorrectly documented.
1369. [bug] Adding an NS record as the lexicographically last

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: interfacemgr.h,v 1.23 2001/08/28 03:58:00 marka Exp $ */
/* $Id: interfacemgr.h,v 1.24 2002/08/30 02:05:30 marka Exp $ */
#ifndef NAMED_INTERFACEMGR_H
#define NAMED_INTERFACEMGR_H 1
@ -120,6 +120,20 @@ ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose);
* in named.conf.
*/
void
ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list,
isc_boolean_t verbose);
/*
* Similar to ns_interfacemgr_scan(), but this function also tries to see the
* need for an explicit listen-on when a list element in 'list' is going to
* override an already-listening a wildcard interface.
*
* This function does not update localhost and localnets ACLs.
*
* This should be called once on server startup, after configuring views and
* zones.
*/
void
ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value);
/*

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: interfacemgr.c,v 1.69 2002/08/17 03:00:49 marka Exp $ */
/* $Id: interfacemgr.c,v 1.70 2002/08/30 02:05:29 marka Exp $ */
#include <config.h>
@ -339,7 +339,8 @@ ns_interface_accepttcp(ns_interface_t *ifp) {
static isc_result_t
ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
const char *name, ns_interface_t **ifpret)
const char *name, ns_interface_t **ifpret,
isc_boolean_t accept_tcp)
{
isc_result_t result;
ns_interface_t *ifp = NULL;
@ -353,15 +354,17 @@ ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
if (result != ISC_R_SUCCESS)
goto cleanup_interface;
result = ns_interface_accepttcp(ifp);
if (result != ISC_R_SUCCESS) {
/*
* XXXRTH We don't currently have a way to easily stop dispatch
* service, so we return currently return ISC_R_SUCCESS (the
* UDP stuff will work even if TCP creation failed). This will
* be fixed later.
*/
result = ISC_R_SUCCESS;
if (accept_tcp == ISC_TRUE) {
result = ns_interface_accepttcp(ifp);
if (result != ISC_R_SUCCESS) {
/*
* XXXRTH We don't currently have a way to easily stop
* dispatch service, so we return currently return
* ISC_R_SUCCESS (the UDP stuff will work even if TCP
* creation failed). This will be fixed later.
*/
result = ISC_R_SUCCESS;
}
}
*ifpret = ifp;
return (ISC_R_SUCCESS);
@ -489,16 +492,65 @@ listenon_is_ip6_any(ns_listenelt_t *elt) {
}
static isc_result_t
do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
isc_result_t result;
dns_aclelement_t elt;
unsigned int family;
unsigned int prefixlen;
family = interface->address.family;
elt.type = dns_aclelementtype_ipprefix;
elt.negative = ISC_FALSE;
elt.u.ip_prefix.address = interface->address;
elt.u.ip_prefix.prefixlen = (family == AF_INET) ? 32 : 128;
result = dns_acl_appendelement(mgr->aclenv.localhost, &elt);
if (result != ISC_R_SUCCESS)
return (result);
result = isc_netaddr_masktoprefixlen(&interface->netmask,
&prefixlen);
/* Non contigious netmasks not allowed by IPv6 arch. */
if (result != ISC_R_SUCCESS && family == AF_INET6)
return (result);
if (result != ISC_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_WARNING,
"omitting IPv4 interface %s from "
"localnets ACL: %s",
interface->name,
isc_result_totext(result));
} else {
elt.u.ip_prefix.prefixlen = prefixlen;
/* XXX suppress duplicates */
result = dns_acl_appendelement(mgr->aclenv.localnets,
&elt);
if (result != ISC_R_SUCCESS)
return (result);
}
return (ISC_R_SUCCESS);
}
static isc_result_t
do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
isc_boolean_t verbose)
{
isc_interfaceiter_t *iter = NULL;
isc_boolean_t scan_ipv4 = ISC_FALSE;
isc_boolean_t scan_ipv6 = ISC_FALSE;
isc_boolean_t adjusting = ISC_FALSE;
isc_result_t result;
isc_netaddr_t zero_address, zero_address6;
ns_listenelt_t *le;
isc_sockaddr_t listen_addr;
ns_interface_t *ifp;
if (ext_listen != NULL)
adjusting = ISC_TRUE;
if (isc_net_probeipv6() == ISC_R_SUCCESS)
scan_ipv6 = ISC_TRUE;
#ifdef WANT_IPV6
@ -539,7 +591,8 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
"interfaces, port %u",
le->port);
result = ns_interface_setup(mgr, &listen_addr,
"<any>", &ifp);
"<any>", &ifp,
ISC_TRUE);
if (result != ISC_R_SUCCESS)
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_ERROR,
@ -557,12 +610,14 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
if (result != ISC_R_SUCCESS)
return (result);
result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
if (result != ISC_R_SUCCESS)
goto cleanup_iter;
result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
if (result != ISC_R_SUCCESS)
goto cleanup_iter;
if (adjusting == ISC_FALSE) {
result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
if (result != ISC_R_SUCCESS)
goto cleanup_iter;
result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
if (result != ISC_R_SUCCESS)
goto cleanup_iter;
}
for (result = isc_interfaceiter_first(iter);
result == ISC_R_SUCCESS;
@ -570,8 +625,6 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
{
isc_interface_t interface;
ns_listenlist_t *ll;
dns_aclelement_t elt;
unsigned int prefixlen;
unsigned int family;
result = isc_interfaceiter_current(iter, &interface);
@ -602,33 +655,8 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
continue;
}
elt.type = dns_aclelementtype_ipprefix;
elt.negative = ISC_FALSE;
elt.u.ip_prefix.address = interface.address;
elt.u.ip_prefix.prefixlen = (family == AF_INET) ? 32 : 128;
result = dns_acl_appendelement(mgr->aclenv.localhost, &elt);
if (result != ISC_R_SUCCESS)
goto ignore_interface;
result = isc_netaddr_masktoprefixlen(&interface.netmask,
&prefixlen);
/* Non contigious netmasks not allowed by IPv6 arch. */
if (result != ISC_R_SUCCESS && family == AF_INET6)
goto ignore_interface;
if (result != ISC_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_WARNING,
"omitting IPv4 interface %s from "
"localnets ACL: %s",
interface.name,
isc_result_totext(result));
} else {
elt.u.ip_prefix.prefixlen = prefixlen;
/* XXX suppress duplicates */
result = dns_acl_appendelement(mgr->aclenv.localnets,
&elt);
if (adjusting == ISC_FALSE) {
result = setup_locals(mgr, &interface);
if (result != ISC_R_SUCCESS)
goto ignore_interface;
}
@ -639,13 +667,10 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
le = ISC_LIST_NEXT(le, link))
{
int match;
isc_boolean_t ipv6_wildcard = ISC_FALSE;
isc_netaddr_t listen_netaddr;
isc_sockaddr_t listen_sockaddr;
/* the case of "any" IPv6 address was already done. */
if (family == AF_INET6 && listenon_is_ip6_any(le))
continue;
/*
* Construct a socket address for this IP/port
* combination.
@ -671,17 +696,58 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
if (match <= 0)
continue;
/*
* The case of "any" IPv6 address will require
* special considerations later, so remember it.
*/
if (family == AF_INET6 && listenon_is_ip6_any(le))
ipv6_wildcard = ISC_TRUE;
/*
* When adjusting interfaces with extra a listening
* list, see if the address matches the extra list.
* If it does, and is also covered by a wildcard
* interface, we need to listen on the address
* explicitly.
*/
if (adjusting == ISC_TRUE) {
ns_listenelt_t *ele;
match = 0;
for (ele = ISC_LIST_HEAD(ext_listen->elts);
ele != NULL;
ele = ISC_LIST_NEXT(ele, link)) {
dns_acl_match(&listen_netaddr, NULL,
ele->acl, NULL,
&match, NULL);
if (match > 0 && ele->port == le->port)
break;
else
match = 0;
}
if (ipv6_wildcard == ISC_TRUE && match == 0)
continue;
}
ifp = find_matching_interface(mgr, &listen_sockaddr);
if (ifp != NULL) {
ifp->generation = mgr->generation;
} else {
char sabuf[ISC_SOCKADDR_FORMATSIZE];
if (adjusting == ISC_FALSE &&
ipv6_wildcard == ISC_TRUE)
continue;
isc_sockaddr_format(&listen_sockaddr,
sabuf, sizeof(sabuf));
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_INFO,
"%s"
"listening on %s interface "
"%s, %s",
(adjusting == ISC_TRUE) ?
"additionally " : "",
(family == AF_INET) ?
"IPv4" : "IPv6",
interface.name, sabuf);
@ -689,7 +755,11 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
result = ns_interface_setup(mgr,
&listen_sockaddr,
interface.name,
&ifp);
&ifp,
(adjusting == ISC_TRUE) ?
ISC_FALSE :
ISC_TRUE);
if (result != ISC_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_ERROR,
@ -725,15 +795,17 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
return (result);
}
void
ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
static void
ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
isc_boolean_t verbose)
{
isc_boolean_t purge = ISC_TRUE;
REQUIRE(NS_INTERFACEMGR_VALID(mgr));
mgr->generation++; /* Increment the generation count. */
if (do_scan(mgr, verbose) != ISC_R_SUCCESS)
if (do_scan(mgr, ext_listen, verbose) != ISC_R_SUCCESS)
purge = ISC_FALSE;
/*
@ -750,9 +822,23 @@ ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
* we're in lwresd-only mode, in which case that is to
* be expected.
*/
if (ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly)
if (ext_listen == NULL &&
ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly) {
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
"not listening on any interfaces");
}
}
void
ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
ns_interfacemgr_scan0(mgr, NULL, verbose);
}
void
ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list,
isc_boolean_t verbose)
{
ns_interfacemgr_scan0(mgr, list, verbose);
}
void
@ -770,4 +856,3 @@ ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
ns_listenlist_attach(value, &mgr->listenon6);
UNLOCK(&mgr->lock);
}

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.c,v 1.382 2002/08/17 00:23:19 marka Exp $ */
/* $Id: server.c,v 1.383 2002/08/30 02:05:29 marka Exp $ */
#include <config.h>
@ -1400,6 +1400,132 @@ scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
server->aclenv.match_mapped = match_mapped;
}
static isc_result_t
add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr) {
ns_listenelt_t *lelt = NULL;
dns_acl_t *src_acl = NULL;
dns_aclelement_t aelt;
isc_result_t result;
isc_sockaddr_t any_sa6;
REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
isc_sockaddr_any6(&any_sa6);
if (!isc_sockaddr_equal(&any_sa6, addr)) {
aelt.type = dns_aclelementtype_ipprefix;
aelt.negative = ISC_FALSE;
aelt.u.ip_prefix.prefixlen = 128;
isc_netaddr_fromin6(&aelt.u.ip_prefix.address,
&addr->type.sin6.sin6_addr);
result = dns_acl_create(mctx, 1, &src_acl);
if (result != ISC_R_SUCCESS)
return (result);
result = dns_acl_appendelement(src_acl, &aelt);
if (result != ISC_R_SUCCESS)
goto clean;
result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr),
src_acl, &lelt);
if (result != ISC_R_SUCCESS)
goto clean;
ISC_LIST_APPEND(list->elts, lelt, link);
}
return (ISC_R_SUCCESS);
clean:
INSIST(lelt == NULL);
if (src_acl != NULL)
dns_acl_detach(&src_acl);
return (result);
}
/*
* Make a list of xxx-source addresses and call ns_interfacemgr_adjust()
* to update the listening interfaces accordingly.
* We currently only consider IPv6, because this only affects IPv6 wildcard
* sockets.
*/
static void
adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
isc_result_t result;
ns_listenlist_t *list = NULL;
dns_view_t *view;
dns_zone_t *zone, *next;
isc_sockaddr_t addr, *addrp;
result = ns_listenlist_create(mctx, &list);
if (result != ISC_R_SUCCESS)
return;
for (view = ISC_LIST_HEAD(server->viewlist);
view != NULL;
view = ISC_LIST_NEXT(view, link)) {
dns_dispatch_t *dispatch6;
dispatch6 = dns_resolver_dispatchv6(view->resolver);
INSIST(dispatch6 != NULL);
result = dns_dispatch_getlocaladdress(dispatch6, &addr);
if (result != ISC_R_SUCCESS)
goto fail;
result = add_listenelt(mctx, list, &addr);
if (result != ISC_R_SUCCESS)
goto fail;
}
zone = NULL;
for (result = dns_zone_first(server->zonemgr, &zone);
result == ISC_R_SUCCESS;
next = NULL, result = dns_zone_next(zone, &next), zone = next) {
dns_view_t *zoneview;
/*
* At this point the zone list may contain a stale zone
* just removed from the configuration. To see the validity,
* check if the corresponding view is in our current view list.
*/
zoneview = dns_zone_getview(zone);
INSIST(zoneview != NULL);
for (view = ISC_LIST_HEAD(server->viewlist);
view != NULL && view != zoneview;
view = ISC_LIST_NEXT(view, link))
;
if (view == NULL)
continue;
addrp = dns_zone_getnotifysrc6(zone);
INSIST(addrp != NULL);
result = add_listenelt(mctx, list, addrp);
if (result != ISC_R_SUCCESS)
goto fail;
addrp = dns_zone_getxfrsource6(zone);
INSIST(addrp != NULL);
result = add_listenelt(mctx, list, addrp);
if (result != ISC_R_SUCCESS)
goto fail;
}
ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE);
clean:
ns_listenlist_detach(&list);
return;
fail:
/*
* Even when we failed the procedure, most of other interfaces
* should work correctly. We therefore just warn it.
*/
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
"could not adjust the listen-on list; "
"some interfaces may not work");
goto clean;
}
/*
* This event callback is invoked to do periodic network
* interface scanning.
@ -2060,6 +2186,12 @@ load_configuration(const char *filename, ns_server_t *server,
}
/*
* Adjust the listening interfaces in accordance with the source
* addresses specified in views and zones.
*/
adjust_interfaces(server, ns_g_mctx);
if (dispatchv4 != NULL)
dns_dispatch_detach(&dispatchv4);
if (dispatchv6 != NULL)