* 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>
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;
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);
}
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
"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,
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;
{
isc_interface_t interface;
ns_listenlist_t *ll;
- dns_aclelement_t elt;
- unsigned int prefixlen;
unsigned int family;
result = isc_interfaceiter_current(iter, &interface);
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;
}
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.
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);
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,
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;
/*
* 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
ns_listenlist_attach(value, &mgr->listenon6);
UNLOCK(&mgr->lock);
}
-
* 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>
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.
}
+ /*
+ * 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)