diff --git a/CHANGES b/CHANGES index d0ad3a5f99..f78c19741c 100644 --- a/CHANGES +++ b/CHANGES @@ -34,7 +34,11 @@ 2295. [bug] Silence static overrun error in bin/named/lwaddr.c. [RT #17459] -2294. [placeholder] rt17435 +2294. [func] Allow the experimental statistics channels to have + multiple connections and ACL. + Note: the stats-server and stats-server-v6 options + available in the previous beta releases are replaced + with the generic statistics-channels statment. 2293. [func] Add ACL regression test. [RT #17375] diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in index 48f6865c0a..e6f79e0acd 100644 --- a/bin/named/Makefile.in +++ b/bin/named/Makefile.in @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.96 2007/06/19 06:49:18 marka Exp $ +# $Id: Makefile.in,v 1.97 2008/01/17 00:15:13 jinmei Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -75,7 +75,7 @@ TARGETS = named@EXEEXT@ lwresd@EXEEXT@ OBJS = builtin.@O@ client.@O@ config.@O@ control.@O@ \ controlconf.@O@ interfacemgr.@O@ \ listenlist.@O@ log.@O@ logconf.@O@ main.@O@ notify.@O@ \ - query.@O@ server.@O@ sortlist.@O@ \ + query.@O@ server.@O@ sortlist.@O@ statschannel.@O@ \ tkeyconf.@O@ tsigconf.@O@ update.@O@ xfrout.@O@ \ zoneconf.@O@ \ lwaddr.@O@ lwresd.@O@ lwdclient.@O@ lwderror.@O@ lwdgabn.@O@ \ @@ -89,7 +89,7 @@ GENERATED = bind9.xsl.h SRCS = builtin.c client.c config.c control.c \ controlconf.c interfacemgr.c \ listenlist.c log.c logconf.c main.c notify.c \ - query.c server.c sortlist.c \ + query.c server.c sortlist.c statschannel.c \ tkeyconf.c tsigconf.c update.c xfrout.c \ zoneconf.c \ lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \ diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index 81f548080a..503b59a5f0 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -15,14 +15,13 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.h,v 1.88 2007/12/14 04:01:20 marka Exp $ */ +/* $Id: server.h,v 1.89 2008/01/17 00:15:13 jinmei Exp $ */ #ifndef NAMED_SERVER_H #define NAMED_SERVER_H 1 /*! \file */ -#include #include #include #include @@ -100,10 +99,7 @@ struct ns_server { dns_acache_t *acache; - isc_httpdmgr_t *httpd4; - isc_sockaddr_t httpd_sockaddr4; - isc_httpdmgr_t *httpd6; - isc_sockaddr_t httpd_sockaddr6; + ns_statschannellist_t statschannels; }; #define NS_SERVER_MAGIC ISC_MAGIC('S','V','E','R') diff --git a/bin/named/include/named/statschannel.h b/bin/named/include/named/statschannel.h new file mode 100644 index 0000000000..13c941ae06 --- /dev/null +++ b/bin/named/include/named/statschannel.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: statschannel.h,v 1.2 2008/01/17 00:15:13 jinmei Exp $ */ + +#ifndef NAMED_STATSCHANNEL_H +#define NAMED_STATSCHANNEL_H 1 + +/*! \file + * \brief + * The statistics channels built-in the name server. + */ + +#include + +#include + +#include + +#define NS_STATSCHANNEL_HTTPPORT 80 + +isc_result_t +ns_statschannels_configure(ns_server_t *server, const cfg_obj_t *config, + cfg_aclconfctx_t *aclconfctx); +/*%< + * [Re]configure the statistics channels. + * + * If it is no longer there but was previously configured, destroy + * it here. + * + * If the IP address or port has changed, destroy the old server + * and create a new one. + */ + + +void +ns_statschannels_shutdown(ns_server_t *server); +/*%< + * Initiate shutdown of all the statistics channel listeners. + */ + +#endif /* NAMED_STATSCHANNEL_H */ diff --git a/bin/named/include/named/types.h b/bin/named/include/named/types.h index 84e3971e1e..ba197ca88b 100644 --- a/bin/named/include/named/types.h +++ b/bin/named/include/named/types.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.27 2007/06/19 23:46:59 tbox Exp $ */ +/* $Id: types.h,v 1.28 2008/01/17 00:15:13 jinmei Exp $ */ #ifndef NAMED_TYPES_H #define NAMED_TYPES_H 1 @@ -41,5 +41,6 @@ typedef struct ns_lwsearchctx ns_lwsearchctx_t; typedef struct ns_controls ns_controls_t; typedef struct ns_dispatch ns_dispatch_t; typedef ISC_LIST(ns_dispatch_t) ns_dispatchlist_t; - +typedef struct ns_statschannel ns_statschannel_t; +typedef ISC_LIST(ns_statschannel_t) ns_statschannellist_t; #endif /* NAMED_TYPES_H */ diff --git a/bin/named/server.c b/bin/named/server.c index 2eaf791169..530f77b7a2 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.497 2008/01/09 23:47:00 tbox Exp $ */ +/* $Id: server.c,v 1.498 2008/01/17 00:15:13 jinmei Exp $ */ /*! \file */ @@ -90,6 +90,7 @@ #include #include #include +#include #include #include #include @@ -221,28 +222,6 @@ static const struct { { NULL, ISC_FALSE } }; -#ifdef HAVE_LIBXML2 - -static isc_result_t -server_httpd_create(ns_server_t *server, int pf); - -static isc_result_t -render_index(const char *url, const char *querystring, void *args, - unsigned int *retcode, const char **retmsg, const char **mimetype, - isc_buffer_t *b, isc_httpdfree_t **freecb, - void **freecb_args); - -static isc_result_t -render_xsl(const char *url, const char *querystring, void *args, - unsigned int *retcode, const char **retmsg, const char **mimetype, - isc_buffer_t *b, isc_httpdfree_t **freecb, - void **freecb_args); - -void -server_generatexml(ns_server_t *server, int *buflen, xmlChar **buf); - -#endif /* HAVE_LIBXML2 */ - static void fatal(const char *msg, isc_result_t result); @@ -2989,51 +2968,8 @@ load_configuration(const char *filename, ns_server_t *server, INSIST(result == ISC_R_SUCCESS); server->aclenv.match_mapped = cfg_obj_asboolean(obj); -#ifdef HAVE_LIBXML2 - /* - * [Re]configure the httpd server. - * - * If it is no longer there but was previously configured, destroy - * it here. - * - * If the IP address or port has changed, destroy the old server - * and create a new one. - * - * XXXMLG this will have to change later. Eventually, we will want - * XXXMLG to start it once, and add/remove listener ports as the - * XXXMLG user wants, which will allow more than one. - * XXXMLG We will also want to support some form of ACL. - */ - obj = NULL; - result = ns_config_get(maps, "stats-server", &obj); - - if (result == ISC_R_SUCCESS && obj != NULL) { - if (!isc_sockaddr_equal(cfg_obj_assockaddr(obj), - &server->httpd_sockaddr4)) { - if (server->httpd4 != NULL) - isc_httpdmgr_shutdown(&server->httpd4); - server->httpd_sockaddr4 = *cfg_obj_assockaddr(obj); - CHECKM(server_httpd_create(server, AF_INET), - "stats-server"); - } - } else if (server->httpd4 != NULL) - isc_httpdmgr_shutdown(&server->httpd4); - - obj = NULL; - result = ns_config_get(maps, "stats-server-v6", &obj); - - if (result == ISC_R_SUCCESS && obj != NULL) { - if (!isc_sockaddr_equal(cfg_obj_assockaddr(obj), - &server->httpd_sockaddr6)) { - if (server->httpd6 != NULL) - isc_httpdmgr_shutdown(&server->httpd6); - server->httpd_sockaddr6 = *cfg_obj_assockaddr(obj); - CHECKM(server_httpd_create(server, AF_INET6), - "stats-server-v6"); - } - } else if (server->httpd6 != NULL) - isc_httpdmgr_shutdown(&server->httpd6); -#endif + CHECKM(ns_statschannels_configure(ns_g_server, config, &aclconfctx), + "configuring statistics server(s)"); v4ports = NULL; v6ports = NULL; @@ -3711,13 +3647,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { ISC_LOG_INFO, "shutting down%s", flush ? ": flushing changes" : ""); -#ifdef HAVE_LIBXML2 - if (server->httpd4 != NULL) - isc_httpdmgr_shutdown(&server->httpd4); - if (server->httpd6 != NULL) - isc_httpdmgr_shutdown(&server->httpd6); -#endif - + ns_statschannels_shutdown(server); ns_controls_shutdown(server->controls); end_reserved_dispatches(server, ISC_TRUE); @@ -3758,61 +3688,6 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); } -#ifdef HAVE_LIBXML2 - -static isc_result_t -server_httpd_create(ns_server_t *server, int pf) { - isc_socket_t *sock; - isc_task_t *task; - isc_result_t result; - isc_httpdmgr_t *httpd; - - task = NULL; - result = isc_task_create(ns_g_taskmgr, 0, &task); - INSIST(result == ISC_R_SUCCESS); - isc_task_setname(task, "httpd", NULL); - - sock = NULL; - result = isc_socket_create(ns_g_socketmgr, pf, isc_sockettype_tcp, - &sock); - if (result != ISC_R_SUCCESS) - return (result); - isc_socket_setname(sock, "httpd", NULL); - -#ifndef ISC_ALLOW_MAPPED - isc_socket_ipv6only(sock, ISC_TRUE); -#endif - - if (pf == AF_INET) - result = isc_socket_bind(sock, &server->httpd_sockaddr4); - else - result = isc_socket_bind(sock, &server->httpd_sockaddr6); - if (result != ISC_R_SUCCESS) - goto cleanup; - - httpd = NULL; - result = isc_httpdmgr_create(ns_g_mctx, sock, task, ns_g_timermgr, - &httpd); - if (result != ISC_R_SUCCESS) - goto cleanup; - - isc_httpdmgr_addurl(httpd, "/", render_index, server); - isc_httpdmgr_addurl(httpd, "/bind9.xsl", render_xsl, server); - - if (pf == AF_INET) - server->httpd4 = httpd; - else - server->httpd6 = httpd; - -cleanup: - isc_task_detach(&task); - isc_socket_detach(&sock); - - return (result); -} - -#endif - void ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { isc_result_t result; @@ -3922,13 +3797,7 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { server->dispatchgen = 0; ISC_LIST_INIT(server->dispatches); - /* - * HTTP server configuration. - */ - server->httpd4 = NULL; - isc_sockaddr_any(&server->httpd_sockaddr4); - server->httpd6 = NULL; - isc_sockaddr_any6(&server->httpd_sockaddr6); + ISC_LIST_INIT(server->statschannels); server->magic = NS_SERVER_MAGIC; *serverp = server; @@ -5468,156 +5337,3 @@ ns_smf_add_message(isc_buffer_t *text) { return (ISC_R_SUCCESS); } #endif /* HAVE_LIBSCF */ - -#ifdef HAVE_LIBXML2 - -/* XXXMLG below here sucks. */ - -#define TRY(a) do { result = (a); INSIST(result == ISC_R_SUCCESS); } while(0); -#define TRY0(a) do { xmlrc = (a); INSIST(xmlrc >= 0); } while(0); - -#define NODES 8 -#define SPACES 3 - -void -server_generatexml(ns_server_t *server, int *buflen, xmlChar **buf) -{ - char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"]; - char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"]; - isc_time_t now; - xmlTextWriterPtr writer; - xmlDocPtr doc; - int xmlrc; - dns_view_t *view; - int i; - - isc_time_now(&now); - isc_time_formatISO8601(&ns_g_boottime, boottime, sizeof boottime); - isc_time_formatISO8601(&now, nowstr, sizeof nowstr); - - writer = xmlNewTextWriterDoc(&doc, 0); - TRY0(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL)); - TRY0(xmlTextWriterWritePI(writer, ISC_XMLCHAR "xml-stylesheet", - ISC_XMLCHAR "type=\"text/xsl\" href=\"/bind9.xsl\"")); - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "isc")); - TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version", - ISC_XMLCHAR "1.0")); - - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "bind")); - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics")); - TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version", - ISC_XMLCHAR "1.0")); - - /* - * Start by rendering the views we know of here. For each view we - * know of, call its rendering function. - */ - view = ISC_LIST_HEAD(server->viewlist); - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views")); - while (view != NULL) { - dns_view_xmlrender(view, writer, ISC_XML_RENDERALL); - view = ISC_LIST_NEXT(view, link); - } - TRY0(xmlTextWriterEndElement(writer)); /* views */ - - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "socketmgr")); - isc_socketmgr_renderxml(ns_g_socketmgr, writer); - TRY0(xmlTextWriterEndElement(writer)); /* socketmgr */ - - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr")); - isc_taskmgr_renderxml(ns_g_taskmgr, writer); - TRY0(xmlTextWriterEndElement(writer)); /* taskmgr */ - - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server")); - xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time"); - xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime); - xmlTextWriterEndElement(writer); - xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time"); - xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr); - xmlTextWriterEndElement(writer); - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); - for (i = 0; i < DNS_STATS_NCOUNTERS; i++) { - xmlTextWriterStartElement(writer, - ISC_XMLCHAR dns_statscounter_names[i]); - xmlTextWriterWriteFormatString(writer, - "%" ISC_PRINT_QUADFORMAT "u", - server->querystats[i]); - xmlTextWriterEndElement(writer); - } - xmlTextWriterEndElement(writer); /* counters */ - xmlTextWriterEndElement(writer); /* server */ - - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory")); - isc_mem_renderxml(server->mctx, writer); - TRY0(xmlTextWriterEndElement(writer)); /* memory */ - - TRY0(xmlTextWriterEndElement(writer)); /* statistics */ - TRY0(xmlTextWriterEndElement(writer)); /* bind */ - TRY0(xmlTextWriterEndElement(writer)); /* isc */ - - TRY0(xmlTextWriterEndDocument(writer)); - - xmlFreeTextWriter(writer); - - xmlDocDumpFormatMemoryEnc(doc, buf, buflen, "UTF-8", 1); - xmlFreeDoc(doc); -} - -static void -wrap_xmlfree(isc_buffer_t *buffer, void *arg) -{ - UNUSED(arg); - - xmlFree(isc_buffer_base(buffer)); -} - -static isc_result_t -render_index(const char *url, const char *querystring, void *arg, - unsigned int *retcode, const char **retmsg, const char **mimetype, - isc_buffer_t *b, isc_httpdfree_t **freecb, - void **freecb_args) -{ - unsigned char *msg; - int msglen; - ns_server_t *server = arg; - - UNUSED(url); - UNUSED(querystring); - - server_generatexml(server, &msglen, &msg); - - *retcode = 200; - *retmsg = "OK"; - *mimetype = "text/xml"; - isc_buffer_reinit(b, msg, msglen); - isc_buffer_add(b, msglen); - *freecb = wrap_xmlfree; - *freecb_args = NULL; - - return (ISC_R_SUCCESS); -} - -static isc_result_t -render_xsl(const char *url, const char *querystring, void *args, - unsigned int *retcode, const char **retmsg, const char **mimetype, - isc_buffer_t *b, isc_httpdfree_t **freecb, - void **freecb_args) -{ -#include "bind9.xsl.h" - - UNUSED(url); - UNUSED(querystring); - UNUSED(args); - - *retcode = 200; - *retmsg = "OK"; - *mimetype = "text/xslt+xml"; - isc_buffer_reinit(b, msg, strlen(msg)); - isc_buffer_add(b, strlen(msg)); - *freecb = NULL; - *freecb_args = NULL; - - return (ISC_R_SUCCESS); -} - -#endif /* HAVE_LIBXML2 */ diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c new file mode 100644 index 0000000000..eb2e36b5f8 --- /dev/null +++ b/bin/named/statschannel.c @@ -0,0 +1,533 @@ +/* + * Copyright (C) 2008 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: statschannel.c,v 1.2 2008/01/17 00:15:13 jinmei Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +struct ns_statschannel { + /* Unlocked */ + isc_httpdmgr_t *httpdmgr; + isc_sockaddr_t address; + isc_mem_t *mctx; + + /* + * Locked by channel lock: can be refererenced and modified by both + * the server task and the channel task. + */ + isc_mutex_t lock; + dns_acl_t *acl; + + /* Locked by server task */ + ISC_LINK(struct ns_statschannel) link; +}; + +#ifdef HAVE_LIBXML2 + +/* XXXMLG below here sucks. */ + +#define TRY(a) do { result = (a); INSIST(result == ISC_R_SUCCESS); } while(0); +#define TRY0(a) do { xmlrc = (a); INSIST(xmlrc >= 0); } while(0); + +#define NODES 8 +#define SPACES 3 + +static void +generatexml(ns_server_t *server, int *buflen, xmlChar **buf) { + char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"]; + char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"]; + isc_time_t now; + xmlTextWriterPtr writer; + xmlDocPtr doc; + int xmlrc; + dns_view_t *view; + int i; + + isc_time_now(&now); + isc_time_formatISO8601(&ns_g_boottime, boottime, sizeof boottime); + isc_time_formatISO8601(&now, nowstr, sizeof nowstr); + + writer = xmlNewTextWriterDoc(&doc, 0); + TRY0(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL)); + TRY0(xmlTextWriterWritePI(writer, ISC_XMLCHAR "xml-stylesheet", + ISC_XMLCHAR "type=\"text/xsl\" href=\"/bind9.xsl\"")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "isc")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version", + ISC_XMLCHAR "1.0")); + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "bind")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version", + ISC_XMLCHAR "1.0")); + + /* + * Start by rendering the views we know of here. For each view we + * know of, call its rendering function. + */ + view = ISC_LIST_HEAD(server->viewlist); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views")); + while (view != NULL) { + dns_view_xmlrender(view, writer, ISC_XML_RENDERALL); + view = ISC_LIST_NEXT(view, link); + } + TRY0(xmlTextWriterEndElement(writer)); /* views */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "socketmgr")); + isc_socketmgr_renderxml(ns_g_socketmgr, writer); + TRY0(xmlTextWriterEndElement(writer)); /* socketmgr */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr")); + isc_taskmgr_renderxml(ns_g_taskmgr, writer); + TRY0(xmlTextWriterEndElement(writer)); /* taskmgr */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server")); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime); + xmlTextWriterEndElement(writer); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr); + xmlTextWriterEndElement(writer); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + for (i = 0; i < DNS_STATS_NCOUNTERS; i++) { + xmlTextWriterStartElement(writer, + ISC_XMLCHAR dns_statscounter_names[i]); + xmlTextWriterWriteFormatString(writer, + "%" ISC_PRINT_QUADFORMAT "u", + server->querystats[i]); + xmlTextWriterEndElement(writer); + } + xmlTextWriterEndElement(writer); /* counters */ + xmlTextWriterEndElement(writer); /* server */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory")); + isc_mem_renderxml(server->mctx, writer); + TRY0(xmlTextWriterEndElement(writer)); /* memory */ + + TRY0(xmlTextWriterEndElement(writer)); /* statistics */ + TRY0(xmlTextWriterEndElement(writer)); /* bind */ + TRY0(xmlTextWriterEndElement(writer)); /* isc */ + + TRY0(xmlTextWriterEndDocument(writer)); + + xmlFreeTextWriter(writer); + + xmlDocDumpFormatMemoryEnc(doc, buf, buflen, "UTF-8", 1); + xmlFreeDoc(doc); +} + +static void +wrap_xmlfree(isc_buffer_t *buffer, void *arg) { + UNUSED(arg); + + xmlFree(isc_buffer_base(buffer)); +} + +static isc_result_t +render_index(const char *url, const char *querystring, void *arg, + unsigned int *retcode, const char **retmsg, const char **mimetype, + isc_buffer_t *b, isc_httpdfree_t **freecb, + void **freecb_args) +{ + unsigned char *msg; + int msglen; + ns_server_t *server = arg; + + UNUSED(url); + UNUSED(querystring); + + generatexml(server, &msglen, &msg); + + *retcode = 200; + *retmsg = "OK"; + *mimetype = "text/xml"; + isc_buffer_reinit(b, msg, msglen); + isc_buffer_add(b, msglen); + *freecb = wrap_xmlfree; + *freecb_args = NULL; + + return (ISC_R_SUCCESS); +} + +#endif /* HAVE_LIBXML2 */ + +static isc_result_t +render_xsl(const char *url, const char *querystring, void *args, + unsigned int *retcode, const char **retmsg, const char **mimetype, + isc_buffer_t *b, isc_httpdfree_t **freecb, + void **freecb_args) +{ +#include "bind9.xsl.h" + + UNUSED(url); + UNUSED(querystring); + UNUSED(args); + + *retcode = 200; + *retmsg = "OK"; + *mimetype = "text/xslt+xml"; + isc_buffer_reinit(b, msg, strlen(msg)); + isc_buffer_add(b, strlen(msg)); + *freecb = NULL; + *freecb_args = NULL; + + return (ISC_R_SUCCESS); +} + +static void +shutdown_listener(ns_statschannel_t *listener) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(&listener->address, socktext, sizeof(socktext)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,NS_LOGMODULE_SERVER, + ISC_LOG_NOTICE, "stopping statistics channel on %s", + socktext); + + isc_httpdmgr_shutdown(&listener->httpdmgr); +} + +static isc_boolean_t +client_ok(const isc_sockaddr_t *fromaddr, void *arg) { + ns_statschannel_t *listener = arg; + isc_netaddr_t netaddr; + char socktext[ISC_SOCKADDR_FORMATSIZE]; + int match; + + REQUIRE(listener != NULL); + + isc_netaddr_fromsockaddr(&netaddr, fromaddr); + + LOCK(&listener->lock); + if (dns_acl_match(&netaddr, NULL, listener->acl, &ns_g_server->aclenv, + &match, NULL) == ISC_R_SUCCESS && match > 0) { + UNLOCK(&listener->lock); + return (ISC_TRUE); + } + UNLOCK(&listener->lock); + + isc_sockaddr_format(fromaddr, socktext, sizeof(socktext)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "rejected statistics connection from %s", socktext); + + return (ISC_FALSE); +} + +static void +destroy_listener(void *arg) { + ns_statschannel_t *listener = arg; + + REQUIRE(listener != NULL); + REQUIRE(!ISC_LINK_LINKED(listener, link)); + + /* We don't to have acquire the lock here since it's already unlinked */ + dns_acl_detach(&listener->acl); + + DESTROYLOCK(&listener->lock); + isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener)); +} + +static isc_result_t +add_listener(ns_server_t *server, ns_statschannel_t **listenerp, + const cfg_obj_t *listen_params, const cfg_obj_t *config, + isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, + const char *socktext) +{ + isc_result_t result; + ns_statschannel_t *listener; + isc_task_t *task = NULL; + isc_socket_t *sock = NULL; + const cfg_obj_t *allow; + dns_acl_t *new_acl = NULL; + + listener = isc_mem_get(server->mctx, sizeof(*listener)); + if (listener == NULL) + return (ISC_R_NOMEMORY); + + listener->httpdmgr = NULL; + listener->address = *addr; + listener->acl = NULL; + listener->mctx = NULL; + ISC_LINK_INIT(listener, link); + + result = isc_mutex_init(&listener->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(server->mctx, listener, sizeof(*listener)); + return (ISC_R_FAILURE); + } + + isc_mem_attach(server->mctx, &listener->mctx); + + allow = cfg_tuple_get(listen_params, "allow"); + if (allow != NULL && cfg_obj_islist(allow)) { + result = cfg_acl_fromconfig(allow, config, ns_g_lctx, + aclconfctx, listener->mctx, 0, + &new_acl); + } else + result = dns_acl_any(listener->mctx, &new_acl); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_acl_attach(new_acl, &listener->acl); + dns_acl_detach(&new_acl); + + result = isc_task_create(ns_g_taskmgr, 0, &task); + if (result != ISC_R_SUCCESS) + goto cleanup; + isc_task_setname(task, "statchannel", NULL); + + result = isc_socket_create(ns_g_socketmgr, isc_sockaddr_pf(addr), + isc_sockettype_tcp, &sock); + if (result != ISC_R_SUCCESS) + goto cleanup; + isc_socket_setname(sock, "statchannel", NULL); + +#ifndef ISC_ALLOW_MAPPED + isc_socket_ipv6only(sock, ISC_TRUE); +#endif + + result = isc_socket_bind(sock, addr); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = isc_httpdmgr_create(server->mctx, sock, task, client_ok, + destroy_listener, listener, ns_g_timermgr, + &listener->httpdmgr); + if (result != ISC_R_SUCCESS) + goto cleanup; + +#ifdef HAVE_LIBXML2 + isc_httpdmgr_addurl(listener->httpdmgr, "/", render_index, server); +#endif + isc_httpdmgr_addurl(listener->httpdmgr, "/bind9.xsl", render_xsl, + server); + + *listenerp = listener; + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_NOTICE, + "statistics channel listening on %s", socktext); + +cleanup: + if (result != ISC_R_SUCCESS) { + if (listener->acl != NULL) + dns_acl_detach(&listener->acl); + DESTROYLOCK(&listener->lock); + isc_mem_putanddetach(&listener->mctx, listener, + sizeof(*listener)); + } + if (task != NULL) + isc_task_detach(&task); + if (sock != NULL) + isc_socket_detach(&sock); + + return (result); +} + +static void +update_listener(ns_server_t *server, ns_statschannel_t **listenerp, + const cfg_obj_t *listen_params, const cfg_obj_t *config, + isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, + const char *socktext) +{ + ns_statschannel_t *listener; + const cfg_obj_t *allow = NULL; + dns_acl_t *new_acl = NULL; + isc_result_t result = ISC_R_SUCCESS; + + for (listener = ISC_LIST_HEAD(server->statschannels); + listener != NULL; + listener = ISC_LIST_NEXT(listener, link)) + if (isc_sockaddr_equal(addr, &listener->address)) + break; + + if (listener == NULL) { + *listenerp = NULL; + return; + } + + /* + * Now, keep the old access list unless a new one can be made. + */ + allow = cfg_tuple_get(listen_params, "allow"); + if (allow != NULL) { + result = cfg_acl_fromconfig(allow, config, ns_g_lctx, + aclconfctx, listener->mctx, 0, + &new_acl); + } else + result = dns_acl_any(listener->mctx, &new_acl); + + if (result == ISC_R_SUCCESS) { + LOCK(&listener->lock); + + dns_acl_detach(&listener->acl); + dns_acl_attach(new_acl, &listener->acl); + dns_acl_detach(&new_acl); + + UNLOCK(&listener->lock); + } else { + cfg_obj_log(listen_params, ns_g_lctx, ISC_LOG_WARNING, + "couldn't install new acl for " + "statistics channel %s: %s", + socktext, isc_result_totext(result)); + } + + *listenerp = listener; +} + +isc_result_t +ns_statschannels_configure(ns_server_t *server, const cfg_obj_t *config, + cfg_aclconfctx_t *aclconfctx) +{ + ns_statschannel_t *listener, *listener_next; + ns_statschannellist_t new_listeners; + const cfg_obj_t *statschannellist = NULL; + const cfg_listelt_t *element, *element2; + char socktext[ISC_SOCKADDR_FORMATSIZE]; + + ISC_LIST_INIT(new_listeners); + + /* + * Get the list of named.conf 'statistics-channels' statements. + */ + (void)cfg_map_get(config, "statistics-channels", &statschannellist); + + /* + * Run through the new address/port list, noting sockets that are + * already being listened on and moving them to the new list. + * + * Identifying duplicate addr/port combinations is left to either + * the underlying config code, or to the bind attempt getting an + * address-in-use error. + */ + if (statschannellist != NULL) { +#ifndef HAVE_LIBXML2 + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "statistics-channels specified but not effective " + "due to missing XML library"); +#endif + + for (element = cfg_list_first(statschannellist); + element != NULL; + element = cfg_list_next(element)) { + const cfg_obj_t *statschannel; + const cfg_obj_t *listenercfg = NULL; + + statschannel = cfg_listelt_value(element); + (void)cfg_map_get(statschannel, "inet", + &listenercfg); + if (listenercfg == NULL) + continue; + + for (element2 = cfg_list_first(listenercfg); + element2 != NULL; + element2 = cfg_list_next(element2)) { + const cfg_obj_t *listen_params; + const cfg_obj_t *obj; + isc_sockaddr_t addr; + + listen_params = cfg_listelt_value(element2); + + obj = cfg_tuple_get(listen_params, "address"); + addr = *cfg_obj_assockaddr(obj); + if (isc_sockaddr_getport(&addr) == 0) + isc_sockaddr_setport(&addr, NS_STATSCHANNEL_HTTPPORT); + + isc_sockaddr_format(&addr, socktext, + sizeof(socktext)); + + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, + ISC_LOG_DEBUG(9), + "processing statistics " + "channel %s", + socktext); + + update_listener(server, &listener, + listen_params, config, &addr, + aclconfctx, socktext); + + if (listener != NULL) { + /* + * Remove the listener from the old + * list, so it won't be shut down. + */ + ISC_LIST_UNLINK(server->statschannels, + listener, link); + } else { + /* + * This is a new listener. + */ + isc_result_t r; + + r = add_listener(server, &listener, + listen_params, config, + &addr, aclconfctx, + socktext); + if (r != ISC_R_SUCCESS) { + cfg_obj_log(listen_params, + ns_g_lctx, + ISC_LOG_WARNING, + "couldn't allocate " + "statistics channel" + " %s: %s", + socktext, + isc_result_totext(r)); + } + } + + if (listener != NULL) + ISC_LIST_APPEND(new_listeners, listener, + link); + } + } + } + + for (listener = ISC_LIST_HEAD(server->statschannels); + listener != NULL; + listener = listener_next) { + listener_next = ISC_LIST_NEXT(listener, link); + ISC_LIST_UNLINK(server->statschannels, listener, link); + shutdown_listener(listener); + } + + ISC_LIST_APPENDLIST(server->statschannels, new_listeners, link); + return (ISC_R_SUCCESS); +} + +void +ns_statschannels_shutdown(ns_server_t *server) { + ns_statschannel_t *listener; + + while ((listener = ISC_LIST_HEAD(server->statschannels)) != NULL) { + ISC_LIST_UNLINK(server->statschannels, listener, link); + shutdown_listener(listener); + } +} diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 6d954e3798..d62f1cef00 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + BIND 9 Administrator Reference Manual @@ -3320,6 +3320,17 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. + + + statistics-channels + + + + declares communication channels to get access to + named statistics. + + + server @@ -4569,7 +4580,6 @@ category notify { null; }; disable-empty-zone zone_name ; zero-no-soa-ttl yes_or_no ; zero-no-soa-ttl-cache yes_or_no ; - stats-server address ip_address port ip_port ; }; @@ -6839,33 +6849,6 @@ query-source-v6 address * port *; - - Statistics Server - - - - stats-server - - - Start a HTTP-based statistics server on the given IP address and port. - At this time, no client authentication is performed. - Using the IPv4 wildcard address (0.0.0.0) will cause the stats-server to listen - on all available IP addresses. Listing a single address (10.1.2.3) will listen - only on that address. Please use a caution in enabling this option and limit - connections to it via standard firewall techniques. - - - At this time, the stats-server can only listen on one IP address and port, or on all addresses. - - - This option requires that BIND 9 be compiled with libxml2. - - - - - - - Periodic Task Intervals @@ -7896,6 +7879,74 @@ query-source-v6 address * port *; + + <command>statistics-channels</command> Statement Grammar + +statistics-channels { + [ inet ( ip_addr | * ) [ port ip_port ] [allow { address_match_list } ]; ] + [ inet ...; ] +}; + + + + + <command>statistics-channels</command> Statement Definition and + Usage + + + The statistics-channels statement + declares communication channels to be used by system + administrators to get access to statistics information of + the name server. + + + + This statement intends to be flexible to support multiple + communication protocols in the future, but currently only + HTTP access is supported. + It requires that BIND 9 be compiled with libxml2; + the statistics-channels statement is + still accepted even if it is built without the library, + but any HTTP access will fail with an error. + + + + An inet control channel is a TCP socket + listening at the specified ip_port on the + specified ip_addr, which can be an IPv4 or IPv6 + address. An ip_addr of * (asterisk) is + interpreted as the IPv4 wildcard address; connections will be + accepted on any of the system's IPv4 addresses. + To listen on the IPv6 wildcard address, + use an ip_addr of ::. + + + + If no port is specified, port 80 is used for HTTP channels. + The asterisk "*" cannot be used for + ip_port. + + + + The attempt of opening a statistics channel is + restricted by the optional allow clause. + Connections to the statistics channel are permitted based on the + address_match_list. + If no allow clause is present, + named accepts connection + attempts from any address; since the statistics may + contain sensitive internal information, it is highly + recommended to restrict the source of connection requests + appropriately. + + + + If no statistics-channels statement is present, + named will not open any communication channels. + + + + <command>server</command> Statement Grammar diff --git a/lib/isc/httpd.c b/lib/isc/httpd.c index 36ac12c6e8..c414251940 100644 --- a/lib/isc/httpd.c +++ b/lib/isc/httpd.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: httpd.c,v 1.12 2007/12/02 21:34:20 explorer Exp $ */ +/* $Id: httpd.c,v 1.13 2008/01/17 00:15:14 jinmei Exp $ */ /*! \file */ @@ -32,7 +32,7 @@ * TODO: * * o Put in better checks to make certain things are passed in correctly. - * This includes a magic number for externally-visable structures, + * This includes a magic number for externally-visible structures, * checking for NULL-ness before dereferencing, etc. * o Make the URL processing external functions which will fill-in a buffer * structure we provide, or return an error and we will render a generic @@ -138,6 +138,10 @@ struct isc_httpdmgr { isc_task_t *task; /*%< owning task */ isc_timermgr_t *timermgr; + isc_httpdclientok_t *client_ok; /*%< client validator */ + isc_httpdondestroy_t *ondestroy; /*%< cleanup callback */ + void *cb_arg; /*%< argument for the above */ + unsigned int flags; ISC_LIST(isc_httpd_t) running; /*%< running clients */ @@ -242,7 +246,9 @@ destroy_client(isc_httpd_t **httpdp) isc_result_t isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, - isc_timermgr_t *tmgr, isc_httpdmgr_t **httpdp) + isc_httpdclientok_t *client_ok, + isc_httpdondestroy_t *ondestroy, void *cb_arg, + isc_timermgr_t *tmgr, isc_httpdmgr_t **httpdp) { isc_result_t result; isc_httpdmgr_t *httpd; @@ -269,27 +275,40 @@ isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, httpd->task = NULL; isc_task_attach(task, &httpd->task); httpd->timermgr = tmgr; /* XXXMLG no attach function? */ + httpd->client_ok = client_ok; + httpd->ondestroy = ondestroy; + httpd->cb_arg = cb_arg; ISC_LIST_INIT(httpd->running); ISC_LIST_INIT(httpd->urls); /* XXXMLG ignore errors on isc_socket_listen() */ - (void)isc_socket_listen(sock, SOMAXCONN); + result = isc_socket_listen(sock, SOMAXCONN); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_socket_listen() failed: %s", + isc_result_totext(result)); + goto cleanup; + } + + (void)isc_socket_filter(sock, "httpready"); result = isc_socket_accept(sock, task, isc_httpd_accept, httpd); - if (result != ISC_R_SUCCESS) { - isc_task_detach(&httpd->task); - isc_socket_detach(&httpd->sock); - isc_mem_detach(&httpd->mctx); - isc_mutex_destroy(&httpd->lock); - isc_mem_put(mctx, httpd, sizeof(isc_httpdmgr_t)); - return (result); - } + if (result != ISC_R_SUCCESS) + goto cleanup; httpd->render_404 = render_404; *httpdp = httpd; return (ISC_R_SUCCESS); + + cleanup: + isc_task_detach(&httpd->task); + isc_socket_detach(&httpd->sock); + isc_mem_detach(&httpd->mctx); + isc_mutex_destroy(&httpd->lock); + isc_mem_put(mctx, httpd, sizeof(isc_httpdmgr_t)); + return (result); } static void @@ -338,6 +357,9 @@ httpdmgr_destroy(isc_httpdmgr_t *httpdmgr) UNLOCK(&httpdmgr->lock); isc_mutex_destroy(&httpdmgr->lock); + if (httpdmgr->ondestroy != NULL) + (httpdmgr->ondestroy)(httpdmgr->cb_arg); + mctx = httpdmgr->mctx; isc_mem_putanddetach(&mctx, httpdmgr, sizeof(isc_httpdmgr_t)); @@ -489,6 +511,7 @@ isc_httpd_accept(isc_task_t *task, isc_event_t *ev) isc_httpd_t *httpd; isc_region_t r; isc_socket_newconnev_t *nev = (isc_socket_newconnev_t *)ev; + isc_sockaddr_t peeraddr; ENTER("accept"); @@ -509,10 +532,18 @@ isc_httpd_accept(isc_task_t *task, isc_event_t *ev) goto requeue; } + (void)isc_socket_getpeername(nev->newsocket, &peeraddr); + if (httpdmgr->client_ok != NULL && + !(httpdmgr->client_ok)(&peeraddr, httpdmgr->cb_arg)) { + isc_socket_detach(&nev->newsocket); + goto requeue; + } + httpd = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpd_t)); if (httpd == NULL) { /* XXXMLG log failure */ NOTICE("accept failed to allocate memory, goto requeue"); + isc_socket_detach(&nev->newsocket); goto requeue; } @@ -530,6 +561,7 @@ isc_httpd_accept(isc_task_t *task, isc_event_t *ev) httpd->headerdata = isc_mem_get(httpdmgr->mctx, HTTP_SENDGROW); if (httpd->headerdata == NULL) { isc_mem_put(httpdmgr->mctx, httpd, sizeof(isc_httpd_t)); + isc_socket_detach(&nev->newsocket); goto requeue; } httpd->headerlen = HTTP_SENDGROW; diff --git a/lib/isc/include/isc/httpd.h b/lib/isc/include/isc/httpd.h index 6aab6e8bba..49a548ae10 100644 --- a/lib/isc/include/isc/httpd.h +++ b/lib/isc/include/isc/httpd.h @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: httpd.h,v 1.6 2007/06/19 23:47:18 tbox Exp $ */ +/* $Id: httpd.h,v 1.7 2008/01/17 00:15:14 jinmei Exp $ */ #ifndef ISC_HTTPD_H #define ISC_HTTPD_H 1 @@ -37,7 +37,9 @@ * a http-like header followed by HTTP data. */ isc_result_t -isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *socket, isc_task_t *task, +isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, + isc_httpdclientok_t *client_ok, + isc_httpdondestroy_t *ondestory, void *cb_arg, isc_timermgr_t *tmgr, isc_httpdmgr_t **httpdp); void diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h index f64cd5b6f3..91f70da650 100644 --- a/lib/isc/include/isc/types.h +++ b/lib/isc/include/isc/types.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.43 2007/06/19 23:47:18 tbox Exp $ */ +/* $Id: types.h,v 1.44 2008/01/17 00:15:14 jinmei Exp $ */ #ifndef ISC_TYPES_H #define ISC_TYPES_H 1 @@ -53,8 +53,10 @@ typedef unsigned int isc_eventtype_t; /*%< Event Type */ typedef isc_uint32_t isc_fsaccess_t; /*%< FS Access */ typedef struct isc_hash isc_hash_t; /*%< Hash */ typedef struct isc_httpd isc_httpd_t; /*%< HTTP client */ +typedef void (isc_httpdfree_t)(isc_buffer_t *, void *); /*%< HTTP free function */ typedef struct isc_httpdmgr isc_httpdmgr_t; /*%< HTTP manager */ typedef struct isc_httpdurl isc_httpdurl_t; /*%< HTTP URL */ +typedef void (isc_httpdondestroy_t)(void *); /*%< Callback on destroying httpd */ typedef struct isc_interface isc_interface_t; /*%< Interface */ typedef struct isc_interfaceiter isc_interfaceiter_t; /*%< Interface Iterator */ typedef struct isc_interval isc_interval_t; /*%< Interval */ @@ -90,7 +92,8 @@ typedef struct isc_timermgr isc_timermgr_t; /*%< Timer Manager */ typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *); typedef int (*isc_sockfdwatch_t)(isc_task_t *, isc_socket_t *, void *); -typedef void (isc_httpdfree_t)(isc_buffer_t *, void *); /*%< HTTP free function */ + +/* The following cannot be listed alphabetically due to forward reference */ typedef isc_result_t (isc_httpdaction_t)(const char *url, const char *querystring, void *arg, @@ -100,6 +103,7 @@ typedef isc_result_t (isc_httpdaction_t)(const char *url, isc_buffer_t *body, isc_httpdfree_t **freecb, void **freecb_args); +typedef isc_boolean_t (isc_httpdclientok_t)(const isc_sockaddr_t *, void *); /*% Resource */ typedef enum { diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index bdacf53daf..a18b642cbb 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: namedconf.c,v 1.80 2008/01/02 23:47:02 tbox Exp $ */ +/* $Id: namedconf.c,v 1.81 2008/01/17 00:15:14 jinmei Exp $ */ /*! \file */ @@ -88,9 +88,9 @@ static cfg_type_t cfg_type_masterselement; static cfg_type_t cfg_type_nameportiplist; static cfg_type_t cfg_type_negated; static cfg_type_t cfg_type_notifytype; +static cfg_type_t cfg_type_optional_allow; static cfg_type_t cfg_type_optional_class; static cfg_type_t cfg_type_optional_facility; -static cfg_type_t cfg_type_optional_facility; static cfg_type_t cfg_type_optional_keyref; static cfg_type_t cfg_type_optional_port; static cfg_type_t cfg_type_options; @@ -98,15 +98,13 @@ static cfg_type_t cfg_type_portiplist; static cfg_type_t cfg_type_querysource4; static cfg_type_t cfg_type_querysource6; static cfg_type_t cfg_type_querysource; -static cfg_type_t cfg_type_addrport4; -static cfg_type_t cfg_type_addrport6; -static cfg_type_t cfg_type_addrport; static cfg_type_t cfg_type_server; static cfg_type_t cfg_type_server_key_kludge; static cfg_type_t cfg_type_size; static cfg_type_t cfg_type_sizenodefault; static cfg_type_t cfg_type_sockaddr4wild; static cfg_type_t cfg_type_sockaddr6wild; +static cfg_type_t cfg_type_statschannels; static cfg_type_t cfg_type_view; static cfg_type_t cfg_type_viewopts; static cfg_type_t cfg_type_zone; @@ -588,6 +586,8 @@ namedconf_clauses[] = { { "logging", &cfg_type_logging, 0 }, { "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI }, { "lwres", &cfg_type_lwres, CFG_CLAUSEFLAG_MULTI }, + { "statistics-channels", &cfg_type_statschannels, + CFG_CLAUSEFLAG_MULTI }, { NULL, NULL, 0 } }; @@ -659,8 +659,6 @@ options_clauses[] = { { "use-ixfr", &cfg_type_boolean, 0 }, { "version", &cfg_type_qstringornone, 0 }, { "flush-zones-on-shutdown", &cfg_type_boolean, 0 }, - { "stats-server", &cfg_type_addrport4, 0 }, - { "stats-server-v6", &cfg_type_addrport6, 0 }, { NULL, NULL, 0 } }; @@ -1391,6 +1389,52 @@ static cfg_type_t cfg_type_controls = { "controls", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, &controls_clausesets }; +/*% + * A "statistics-channels" statement is represented as a map with the + * multivalued "inet" clauses. + */ +static void +doc_optional_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) { + const keyword_type_t *kw = type->of; + cfg_print_chars(pctx, "[ ", 2); + cfg_print_chars(pctx, "{ ", 2); + cfg_doc_obj(pctx, kw->type); + cfg_print_chars(pctx, "; ... }", 7); +} + +static cfg_type_t cfg_type_optional_allow = { + "optional_allow", parse_optional_keyvalue, print_keyvalue, + doc_optional_bracketed_list, &cfg_rep_list, &controls_allow_kw +}; + +static cfg_tuplefielddef_t statserver_fields[] = { + { "address", &cfg_type_controls_sockaddr, 0 }, /* reuse controls def */ + { "allow", &cfg_type_optional_allow, 0 }, + { NULL, NULL, 0 } +}; + +static cfg_type_t cfg_type_statschannel = { + "statschannel", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, statserver_fields +}; + +static cfg_clausedef_t +statservers_clauses[] = { + { "inet", &cfg_type_statschannel, CFG_CLAUSEFLAG_MULTI }, + { NULL, NULL, 0 } +}; + +static cfg_clausedef_t * +statservers_clausesets[] = { + statservers_clauses, + NULL +}; + +static cfg_type_t cfg_type_statschannels = { + "statistics-channels", cfg_parse_map, cfg_print_map, cfg_doc_map, + &cfg_rep_map, &statservers_clausesets +}; + /*% * An optional class, as used in view and zone statements. */ @@ -1504,95 +1548,6 @@ static cfg_type_t cfg_type_querysource = { "querysource", NULL, print_querysource, NULL, &cfg_rep_sockaddr, NULL }; -static isc_result_t -parse_addrport(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - cfg_obj_t *obj = NULL; - isc_netaddr_t netaddr; - in_port_t port; - unsigned int have_address = 0; - unsigned int have_port = 0; - const unsigned int *flagp = type->of; - - if ((*flagp & CFG_ADDR_V4OK) != 0) - isc_netaddr_any(&netaddr); - else if ((*flagp & CFG_ADDR_V6OK) != 0) - isc_netaddr_any6(&netaddr); - else - INSIST(0); - - port = 0; - - for (;;) { - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_string) { - if (strcasecmp(TOKEN_STRING(pctx), - "address") == 0) - { - /* read "address" */ - CHECK(cfg_gettoken(pctx, 0)); - CHECK(cfg_parse_rawaddr(pctx, *flagp, - &netaddr)); - have_address++; - } else if (strcasecmp(TOKEN_STRING(pctx), "port") == 0) - { - /* read "port" */ - CHECK(cfg_gettoken(pctx, 0)); - CHECK(cfg_parse_rawport(pctx, - CFG_ADDR_WILDOK, - &port)); - have_port++; - } else if (have_port == 0 && have_address == 0) { - return (cfg_parse_sockaddr(pctx, type, ret)); - } else { - cfg_parser_error(pctx, CFG_LOG_NEAR, - "expected 'address' or 'port'"); - return (ISC_R_UNEXPECTEDTOKEN); - } - } else - break; - } - if (have_address > 1 || have_port > 1 || - have_address + have_port == 0) { - cfg_parser_error(pctx, 0, "expected one address and/or port"); - return (ISC_R_UNEXPECTEDTOKEN); - } - - CHECK(cfg_create_obj(pctx, &cfg_type_addrport, &obj)); - isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); - *ret = obj; - return (ISC_R_SUCCESS); - - cleanup: - cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid query source"); - CLEANUP_OBJ(obj); - return (result); -} - -static void -print_addrport(cfg_printer_t *pctx, const cfg_obj_t *obj) { - isc_netaddr_t na; - isc_netaddr_fromsockaddr(&na, &obj->value.sockaddr); - cfg_print_chars(pctx, "address ", 8); - cfg_print_rawaddr(pctx, &na); - cfg_print_chars(pctx, " port ", 6); - cfg_print_rawuint(pctx, isc_sockaddr_getport(&obj->value.sockaddr)); -} - -static cfg_type_t cfg_type_addrport4 = { - "addrport4", parse_addrport, NULL, cfg_doc_terminal, - NULL, &sockaddr4wild_flags -}; - -static cfg_type_t cfg_type_addrport6 = { - "addrport6", parse_addrport, NULL, cfg_doc_terminal, - NULL, &sockaddr6wild_flags -}; - -static cfg_type_t cfg_type_addrport = { - "addrport", NULL, print_addrport, NULL, &cfg_rep_sockaddr, NULL -}; - /*% addrmatchelt */ static isc_result_t