diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in index ef764390a7..0186e0ad0e 100644 --- a/bin/named/Makefile.in +++ b/bin/named/Makefile.in @@ -37,12 +37,14 @@ SUBDIRS = unix TARGETS = named -OBJS = client.@O@ interfacemgr.@O@ log.@O@ main.@O@ notify.@O@ \ +OBJS = client.@O@ interfacemgr.@O@ listenlist.@O@ \ + log.@O@ main.@O@ notify.@O@ \ query.@O@ rootns.@O@ server.@O@ update.@O@ xfrout.@O@ UOBJS = unix/os.@O@ -SRCS = client.c interfacemgr.c log.c main.c notify.c \ +SRCS = client.c interfacemgr.c listenlist.c \ + log.c main.c notify.c \ query.c rootns.c server.c update.c xfrout.c @BIND9_MAKE_RULES@ diff --git a/bin/named/include/named/interfacemgr.h b/bin/named/include/named/interfacemgr.h index e54645bb96..b16776df0b 100644 --- a/bin/named/include/named/interfacemgr.h +++ b/bin/named/include/named/interfacemgr.h @@ -54,6 +54,7 @@ #include +#include #include /*** @@ -113,6 +114,13 @@ ns_interfacemgr_scan(ns_interfacemgr_t *mgr); * in named.conf. */ +void +ns_interfacemgr_setlistenon(ns_interfacemgr_t *mgr, + ns_listenlist_t *value); +/* + * Set the "listen-on" list of 'mgr' to 'value'. + * The previous listen-on list is freed. + */ void ns_interface_attach(ns_interface_t *source, diff --git a/bin/named/include/named/listenlist.h b/bin/named/include/named/listenlist.h new file mode 100644 index 0000000000..928e2743d9 --- /dev/null +++ b/bin/named/include/named/listenlist.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2000 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef NS_LISTENLIST_H +#define NS_LISTENLIST_H 1 + +/***** + ***** Module Info + *****/ + +/* + * "Listen lists", as in the "listen-on" configuration statement. + */ + +/*** + *** Imports + ***/ + +#include +#include +#include +#include + +/*** + *** Types + ***/ + +typedef struct ns_listenelt ns_listenelt_t; +typedef struct ns_listenlist ns_listenlist_t; + +struct ns_listenelt { + isc_mem_t * mctx; + in_port_t port; + dns_acl_t * acl; + ISC_LINK(ns_listenelt_t) link; +}; + +struct ns_listenlist { + isc_mem_t * mctx; + int refcount; + ISC_LIST(ns_listenelt_t) elts; +}; + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +isc_result_t +ns_listenlist_fromconfig(dns_c_lstnlist_t *clist, dns_c_ctx_t *cctx, + dns_aclconfctx_t *actx, + isc_mem_t *mctx, ns_listenlist_t **target); +/* + * Create a listen list from the corresponding configuration + * data structure. + */ + +isc_result_t +ns_listenlist_default(isc_mem_t *mctx, in_port_t port, + ns_listenlist_t **target); +/* + * Create a listen-on list with default contents, matching + * all addresses with port 'port'. + */ + +void +ns_listenlist_attach(ns_listenlist_t *source, ns_listenlist_t **target); + +void +ns_listenlist_detach(ns_listenlist_t **listp); + +ISC_LANG_ENDDECLS + +#endif /* NS_LISTENLIST_H */ + + diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c index 6d5cd47d4e..3863d82b64 100644 --- a/bin/named/interfacemgr.c +++ b/bin/named/interfacemgr.c @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -52,6 +53,7 @@ struct ns_interfacemgr { isc_socketmgr_t * socketmgr; /* Socket manager. */ ns_clientmgr_t * clientmgr; /* Client manager. */ unsigned int generation; /* Current generation no. */ + ns_listenlist_t * listenon; ISC_LIST(ns_interface_t) interfaces; /* List of interfaces. */ }; @@ -74,28 +76,37 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, return (DNS_R_NOMEMORY); result = isc_mutex_init(&mgr->lock); - if (result != ISC_R_SUCCESS) { - isc_mem_put(mctx, mgr, sizeof(*mgr)); - return (result); - } + if (result != ISC_R_SUCCESS) + goto cleanup; mgr->mctx = mctx; mgr->taskmgr = taskmgr; mgr->socketmgr = socketmgr; mgr->clientmgr = clientmgr; mgr->generation = 1; + mgr->listenon = NULL; ISC_LIST_INIT(mgr->interfaces); + result = ns_listenlist_default(mctx, ns_g_port, + &mgr->listenon); + if (result != DNS_R_SUCCESS) + goto cleanup; + mgr->references = 1; mgr->magic = IFMGR_MAGIC; *mgrp = mgr; return (DNS_R_SUCCESS); + + cleanup: + isc_mem_put(mctx, mgr, sizeof(*mgr)); + return (result); } static void ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) { REQUIRE(NS_INTERFACEMGR_VALID(mgr)); + ns_listenlist_detach(&mgr->listenon); isc_mutex_destroy(&mgr->lock); mgr->magic = 0; isc_mem_put(mgr->mctx, mgr, sizeof *mgr); @@ -447,8 +458,8 @@ do_ipv4(ns_interfacemgr_t *mgr) { while (result == ISC_R_SUCCESS) { ns_interface_t *ifp; isc_interface_t interface; - isc_sockaddr_t listen_addr; - + ns_listenelt_t *le; + /* * XXX insert code to match against named.conf * "listen-on" statements here. Also build list of @@ -458,36 +469,60 @@ do_ipv4(ns_interfacemgr_t *mgr) { result = isc_interfaceiter_current(iter, &interface); if (result != ISC_R_SUCCESS) break; - - isc_sockaddr_fromin(&listen_addr, - &interface.address.type.in, - ns_g_port); - ifp = find_matching_interface(mgr, &listen_addr); - if (ifp != NULL) { - ifp->generation = mgr->generation; - } else { + for (le = ISC_LIST_HEAD(mgr->listenon->elts); + le != NULL; + le = ISC_LIST_NEXT(le, link)) + { + int match; + isc_sockaddr_t listen_addr; char buf[128]; const char *addrstr; + /* + * Construct a socket address for this IP/port + * combination. + */ + isc_sockaddr_fromin(&listen_addr, + &interface.address.type.in, + le->port); + + /* + * Construct a human-readable version of same. + */ addrstr = inet_ntop(listen_addr.type.sin.sin_family, &listen_addr.type.sin.sin_addr, buf, sizeof(buf)); if (addrstr == NULL) addrstr = "(bad address)"; - isc_log_write(ns_g_lctx, NS_LOGCATEGORY_NETWORK, - NS_LOGMODULE_INTERFACEMGR, - ISC_LOG_INFO, - "listening on IPv4 interface %s, %s port %u", - interface.name, addrstr, - ntohs(listen_addr.type.sin.sin_port)); - - result = ns_interface_setup(mgr, &listen_addr, &ifp); - if (result != DNS_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "creating IPv4 interface %s " - "failed; interface ignored", - interface.name); + + /* + * See if the address matches the listen-on statement; + * if not, ignore the interface. + */ + result = dns_acl_match(&listen_addr, NULL, + le->acl, &match, NULL); + if (match <= 0) + continue; + + ifp = find_matching_interface(mgr, &listen_addr); + if (ifp != NULL) { + ifp->generation = mgr->generation; + } else { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_NETWORK, + NS_LOGMODULE_INTERFACEMGR, + ISC_LOG_INFO, + "listening on IPv4 interface %s, %s port %u", + interface.name, addrstr, + ntohs(listen_addr.type.sin.sin_port)); + + result = ns_interface_setup(mgr, &listen_addr, &ifp); + if (result != DNS_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "creating IPv4 interface %s " + "failed; interface ignored", + interface.name); + } /* Continue. */ } @@ -566,3 +601,13 @@ ns_interfacemgr_scan(ns_interfacemgr_t *mgr) { */ } } + +void +ns_interfacemgr_setlistenon(ns_interfacemgr_t *mgr, + ns_listenlist_t *value) +{ + LOCK(&mgr->lock); + ns_listenlist_detach(&mgr->listenon); + ns_listenlist_attach(value, &mgr->listenon); + UNLOCK(&mgr->lock); +} diff --git a/bin/named/listenlist.c b/bin/named/listenlist.c new file mode 100644 index 0000000000..e566863f2c --- /dev/null +++ b/bin/named/listenlist.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2000 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include + +#include +#include +#include + +#include + +static void destroy(ns_listenlist_t *list); + +static isc_result_t +ns_listenelt_create(isc_mem_t *mctx, in_port_t port, + dns_acl_t *acl, ns_listenelt_t **target) +{ + ns_listenelt_t *elt = NULL; + REQUIRE(target != NULL && *target == NULL); + elt = isc_mem_get(mctx, sizeof(*elt)); + if (elt == NULL) + return (ISC_R_NOMEMORY); + elt->mctx = mctx; + ISC_LINK_INIT(elt, link); + elt->port = port; + elt->acl = acl; + *target = elt; + return (ISC_R_SUCCESS); +} + +static void +ns_listenelt_destroy(ns_listenelt_t *elt) { + if (elt->acl != NULL) + dns_acl_detach(&elt->acl); + isc_mem_put(elt->mctx, elt, sizeof(*elt)); +} + +static isc_result_t +ns_listenelt_fromconfig(dns_c_lstnon_t *celt, dns_c_ctx_t *cctx, + dns_aclconfctx_t *actx, + isc_mem_t *mctx, ns_listenelt_t **target) +{ + isc_result_t result; + ns_listenelt_t *delt = NULL; + REQUIRE(target != NULL && *target == NULL); + result = ns_listenelt_create(mctx, celt->port, NULL, &delt); + if (result != ISC_R_SUCCESS) + return (result); + + result = dns_acl_fromconfig(celt->iml, cctx, actx, mctx, &delt->acl); + if (result != DNS_R_SUCCESS) { + ns_listenelt_destroy(delt); + return (result); + } + *target = delt; + return (ISC_R_SUCCESS); +} + +static isc_result_t +ns_listenlist_create(isc_mem_t *mctx, ns_listenlist_t **target) { + ns_listenlist_t *list = NULL; + REQUIRE(target != NULL && *target == NULL); + list = isc_mem_get(mctx, sizeof(*list)); + if (list == NULL) + return (ISC_R_NOMEMORY); + list->mctx = mctx; + list->refcount = 1; + ISC_LIST_INIT(list->elts); + *target = list; + return (ISC_R_SUCCESS); +} + +isc_result_t +ns_listenlist_fromconfig(dns_c_lstnlist_t *clist, dns_c_ctx_t *cctx, + dns_aclconfctx_t *actx, + isc_mem_t *mctx, ns_listenlist_t **target) +{ + dns_c_lstnon_t *ce; + isc_result_t result; + ns_listenlist_t *dlist = NULL; + + REQUIRE(target != NULL && *target == NULL); + + result = ns_listenlist_create(mctx, &dlist); + if (result != ISC_R_SUCCESS) + return (result); + + for (ce = ISC_LIST_HEAD(clist->elements); + ce != NULL; + ce = ISC_LIST_NEXT(ce, next)) + { + ns_listenelt_t *delt = NULL; + result = ns_listenelt_fromconfig(ce, cctx, actx, mctx, &delt); + if (result != DNS_R_SUCCESS) + goto cleanup; + ISC_LIST_APPEND(dlist->elts, delt, link); + } + *target = dlist; + return (ISC_R_SUCCESS); + + cleanup: + destroy(dlist); + return (result); +} + +static void +destroy(ns_listenlist_t *list) { + ns_listenelt_t *elt, *next; + for (elt = ISC_LIST_HEAD(list->elts); + elt != NULL; + elt = next) + { + next = ISC_LIST_NEXT(elt, link); + ns_listenelt_destroy(elt); + } + isc_mem_put(list->mctx, list, sizeof(*list)); +} + +void +ns_listenlist_attach(ns_listenlist_t *source, ns_listenlist_t **target) +{ + INSIST(source->refcount > 0); + source->refcount++; + *target = source; +} + +void +ns_listenlist_detach(ns_listenlist_t **listp) +{ + ns_listenlist_t *list = *listp; + INSIST(list->refcount > 0); + list->refcount--; + if (list->refcount == 0) + destroy(list); + *listp = NULL; +} + +isc_result_t +ns_listenlist_default(isc_mem_t *mctx, in_port_t port, + ns_listenlist_t **target) +{ + isc_result_t result; + dns_acl_t *acl = NULL; + ns_listenelt_t *elt = NULL; + ns_listenlist_t *list = NULL; + + REQUIRE(target != NULL && *target == NULL); + result = dns_acl_any(mctx, &acl); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = ns_listenelt_create(mctx, port, acl, &elt); + if (result != ISC_R_SUCCESS) + goto cleanup_acl; + + result = ns_listenlist_create(mctx, &list); + if (result != ISC_R_SUCCESS) + goto cleanup_listenelt; + + ISC_LIST_APPEND(list->elts, elt, link); + + *target = list; + return (ISC_R_SUCCESS); + + cleanup_listenelt: + ns_listenelt_destroy(elt); + cleanup_acl: + dns_acl_detach(&acl); + cleanup: + return (result); +} diff --git a/bin/named/server.c b/bin/named/server.c index cc0002d35c..e74ce3bf5c 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -59,12 +59,13 @@ #include #include -#include #include +#include +#include #include #include #include -#include +#include typedef struct { isc_mem_t * mctx; @@ -459,6 +460,31 @@ load_configuration(const char *filename, ns_server_t *server) { configure_server_acl(configctx, &aclconfctx, ns_g_mctx, dns_c_ctx_gettransferacl, &server->transferacl); + + /* + * Configure the interface manager according to the "listen-on" + * statement. + */ + { + dns_c_lstnlist_t *clistenon = NULL; + ns_listenlist_t *listenon = NULL; + + (void) dns_c_ctx_getlistenlist(configctx, &clistenon); + if (clistenon != NULL) { + result = ns_listenlist_fromconfig(clistenon, + configctx, + &aclconfctx, + ns_g_mctx, &listenon); + } else { + /* Not specified, use default. */ + result = ns_listenlist_default(ns_g_mctx, ns_g_port, + &listenon); + } + RUNTIME_CHECK(result == ISC_R_SUCCESS); + ns_interfacemgr_setlistenon(server->interfacemgr, listenon); + ns_listenlist_detach(&listenon); + } + /* * If we haven't created any views, create a default view for class * IN. (We're a caching-only server.) diff --git a/util/copyrights b/util/copyrights index 466f42f3cd..252374e911 100644 --- a/util/copyrights +++ b/util/copyrights @@ -12,6 +12,7 @@ ./bin/named/include/named/client.h C 1999,2000 ./bin/named/include/named/globals.h C 1999,2000 ./bin/named/include/named/interfacemgr.h C 1999,2000 +./bin/named/include/named/listenlist.h C 2000 ./bin/named/include/named/log.h C 1999,2000 ./bin/named/include/named/main.h C 1999,2000 ./bin/named/include/named/notify.h C 1999,2000 @@ -23,6 +24,7 @@ ./bin/named/include/named/xfrout.h C 1999,2000 ./bin/named/interfacemgr.c C 1999,2000 ./bin/named/log.c C 1999,2000 +./bin/named/listenlist.c C 2000 ./bin/named/main.c C 1999,2000 ./bin/named/named.conf.test X 1999,2000 ./bin/named/notify.c C 1999,2000