Commit 186e7f37 authored by Mark Andrews's avatar Mark Andrews

2122. [func] Experimental http server and statistics support

                        for named via xml.
parent de468b9d
2122. [func] Experimental http server and statistics support
for named via xml.
2121. [func] Add a 10 slot dead masters cache (LRU) with a 600
second timeout. [RT #16553]
......
......@@ -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.87 2005/09/05 00:10:51 marka Exp $
# $Id: Makefile.in,v 1.88 2006/12/21 06:02:29 marka Exp $
srcdir = @srcdir@
VPATH = @srcdir@
......@@ -84,6 +84,8 @@ OBJS = builtin.@O@ client.@O@ config.@O@ control.@O@ \
UOBJS = unix/os.@O@
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 \
......@@ -128,7 +130,12 @@ docclean manclean maintainer-clean::
rm -f ${MANOBJS}
clean distclean maintainer-clean::
rm -f ${TARGETS} ${OBJS}
rm -f ${TARGETS} ${OBJS} ${GENERATED}
bind9.xsl.h: bind9.xsl convertxsl.pl
perl convertxsl.pl < ${srcdir}/bind9.xsl > bind9.xsl.h
server.o:: bind9.xsl.h
installdirs:
$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir}
......
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:template match="isc/bind/statistics">
<html>
<head>
<style type="text/css">
body {
font-family: sans-serif;
background-color: #ffffff;
color: #000000;
}
table {
border-collapse: collapse;
}
tr.rowh {
text-align: center;
border: 1px solid #000000;
background-color: #8080ff;
color: #ffffff;
}
tr.row {
text-align: right;
border: 1px solid #000000;
background-color: teal;
color: #ffffff;
}
tr.lrow {
text-align: left;
border: 1px solid #000000;
background-color: teal;
color: #ffffff;
}
.header {
background-color: teal;
color: #ffffff;
padding: 4px;
}
.content {
background-color: #ffffff;
color: #000000;
padding: 4px;
}
.item {
padding: 4px;
align: right;
}
.value {
padding: 4px;
font-weight: bold;
}
</style>
<title>BIND 9 Statistics</title>
</head>
<body>
<div class="header">Bind 9 Configuration and Statistics</div>
<br/>
<table>
<tr class="rowh"><th colspan="2">Times</th></tr>
<tr class="lrow">
<td>boot-time</td>
<td><xsl:value-of select="server/boot-time"/></td>
</tr>
<tr class="lrow">
<td>current-time</td>
<td><xsl:value-of select="server/current-time"/></td>
</tr>
</table>
<br/>
<table>
<tr class="rowh"><th colspan="2">Server statistics</th></tr>
<xsl:for-each select="server/counters/*">
<tr class="lrow">
<td><xsl:value-of select="name()"/></td>
<td><xsl:value-of select="."/></td>
</tr>
</xsl:for-each>
</table>
<br />
<xsl:for-each select="views/view">
<table>
<tr class="rowh">
<th colspan="4">Zones for View <xsl:value-of select="name" /></th>
</tr>
<tr class="rowh">
<th>Name</th>
<th>Class</th>
<th>Serial</th>
</tr>
<xsl:for-each select="zones/zone">
<tr class="lrow">
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="rdataclass"/></td>
<td><xsl:value-of select="serial"/></td>
</tr>
</xsl:for-each>
</table>
<br />
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
#!/usr/bin/env perl
use strict;
use warnings;
print 'char msg[] = "';
my $lines = '';
while (<>) {
chomp;
$lines .= $_;
}
$lines =~ s/[\ \t]+/ /g;
$lines =~ s/\>\ \</\>\</g;
$lines =~ s/\"/\\\"/g;
print $lines;
print '\\n";', "\n";
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: globals.h,v 1.68 2006/03/02 00:37:23 marka Exp $ */
/* $Id: globals.h,v 1.69 2006/12/21 06:02:30 marka Exp $ */
#ifndef NAMED_GLOBALS_H
#define NAMED_GLOBALS_H 1
......@@ -25,6 +25,7 @@
#include <isc/rwlock.h>
#include <isc/log.h>
#include <isc/net.h>
#include <isc/mib.h>
#include <isccfg/cfg.h>
......@@ -48,6 +49,7 @@ EXTERN isc_taskmgr_t * ns_g_taskmgr INIT(NULL);
EXTERN dns_dispatchmgr_t * ns_g_dispatchmgr INIT(NULL);
EXTERN isc_entropy_t * ns_g_entropy INIT(NULL);
EXTERN isc_entropy_t * ns_g_fallbackentropy INIT(NULL);
EXTERN isc_mib_t * ns_g_mib INIT(NULL);
/*
* XXXRTH We're going to want multiple timer managers eventually. One
......@@ -113,6 +115,7 @@ EXTERN const char * lwresd_g_defaultpidfile INIT(NS_LOCALSTATEDIR
EXTERN const char * ns_g_username INIT(NULL);
EXTERN int ns_g_listen INIT(3);
EXTERN isc_time_t ns_g_boottime;
#undef EXTERN
#undef INIT
......
......@@ -15,21 +15,23 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.h,v 1.84 2006/12/04 01:52:45 marka Exp $ */
/* $Id: server.h,v 1.85 2006/12/21 06:02:30 marka Exp $ */
#ifndef NAMED_SERVER_H
#define NAMED_SERVER_H 1
/*! \file */
#include <isc/httpd.h>
#include <isc/log.h>
#include <isc/sockaddr.h>
#include <isc/magic.h>
#include <isc/types.h>
#include <isc/quota.h>
#include <isc/sockaddr.h>
#include <isc/types.h>
#include <isc/xml.h>
#include <dns/types.h>
#include <dns/acl.h>
#include <dns/types.h>
#include <named/types.h>
......@@ -97,6 +99,9 @@ struct ns_server {
ns_dispatchlist_t dispatches;
dns_acache_t *acache;
isc_httpdmgr_t *httpd;
isc_sockaddr_t httpd_sockaddr;
};
#define NS_SERVER_MAGIC ISC_MAGIC('S','V','E','R')
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: types.h,v 1.23 2005/04/29 00:22:33 marka Exp $ */
/* $Id: types.h,v 1.24 2006/12/21 06:02:30 marka Exp $ */
#ifndef NAMED_TYPES_H
#define NAMED_TYPES_H 1
......@@ -28,6 +28,8 @@ typedef struct ns_client ns_client_t;
typedef struct ns_clientmgr ns_clientmgr_t;
typedef struct ns_query ns_query_t;
typedef struct ns_server ns_server_t;
typedef struct ns_xmld ns_xmld_t;
typedef struct ns_xmldmgr ns_xmldmgr_t;
typedef struct ns_interface ns_interface_t;
typedef struct ns_interfacemgr ns_interfacemgr_t;
typedef struct ns_lwresd ns_lwresd_t;
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: main.c,v 1.153 2006/11/10 18:44:46 marka Exp $ */
/* $Id: main.c,v 1.154 2006/12/21 06:02:29 marka Exp $ */
/*! \file */
......@@ -670,6 +670,14 @@ setup(void) {
ns_g_conffile = absolute_conffile;
}
/*
* Record the server's startup time.
*/
result = isc_time_now(&ns_g_boottime);
if (result != ISC_R_SUCCESS)
ns_main_earlyfatal("isc_time_now() failed: %s",
isc_result_totext(result));
result = create_managers();
if (result != ISC_R_SUCCESS)
ns_main_earlyfatal("create_managers() failed: %s",
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.c,v 1.469 2006/12/07 05:05:09 marka Exp $ */
/* $Id: server.c,v 1.470 2006/12/21 06:02:29 marka Exp $ */
/*! \file */
......@@ -29,6 +29,7 @@
#include <isc/entropy.h>
#include <isc/file.h>
#include <isc/hash.h>
#include <isc/httpd.h>
#include <isc/lex.h>
#include <isc/parseint.h>
#include <isc/print.h>
......@@ -38,6 +39,7 @@
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/util.h>
#include <isc/xml.h>
#include <isccfg/namedconf.h>
......@@ -217,6 +219,31 @@ static const struct {
{ NULL, ISC_FALSE }
};
#ifdef HAVE_LIBXML2
void
server_httpd_create(ns_server_t *server);
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
tree_walk(xmlTextWriterPtr writer, isc_mib_t *mib, isc_mibnode_t *node);
void
server_generatexml(ns_server_t *server, unsigned int *buflen, xmlChar **buf);
#endif /* HAVE_LIBXML2 */
static void
fatal(const char *msg, isc_result_t result);
......@@ -2783,6 +2810,39 @@ 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 IPv6 and 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_sockaddr)) {
if (server->httpd != NULL)
isc_httpdmgr_shutdown(&server->httpd);
server->httpd_sockaddr = *cfg_obj_assockaddr(obj);
server_httpd_create(server);
}
} else {
if (server->httpd != NULL)
isc_httpdmgr_shutdown(&server->httpd);
}
#endif
v4ports = NULL;
v6ports = NULL;
(void)ns_config_get(maps, "avoid-v4-udp-ports", &v4ports);
......@@ -3450,6 +3510,11 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
ISC_LOG_INFO, "shutting down%s",
flush ? ": flushing changes" : "");
#ifdef HAVE_LIBXML2
if (server->httpd != NULL)
isc_httpdmgr_shutdown(&server->httpd);
#endif
ns_controls_shutdown(server->controls);
end_reserved_dispatches(server, ISC_TRUE);
......@@ -3490,6 +3555,41 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
}
#ifdef HAVE_LIBXML2
void
server_httpd_create(ns_server_t *server)
{
isc_socket_t *sock;
isc_task_t *task;
isc_result_t result;
task = NULL;
result = isc_task_create(ns_g_taskmgr, 0, &task);
INSIST(result == ISC_R_SUCCESS);
sock = NULL;
result = isc_socket_create(ns_g_socketmgr, PF_INET,
isc_sockettype_tcp, &sock);
INSIST(result == ISC_R_SUCCESS);
result = isc_socket_bind(sock, &server->httpd_sockaddr);
INSIST(result == ISC_R_SUCCESS);
server->httpd = NULL;
result = isc_httpdmgr_create(ns_g_mctx, sock, task, ns_g_timermgr,
&server->httpd);
INSIST(result == ISC_R_SUCCESS);
isc_httpdmgr_addurl(server->httpd, "/", render_index, server);
isc_httpdmgr_addurl(server->httpd, "/bind9.xsl", render_xsl, server);
isc_task_detach(&task);
isc_socket_detach(&sock);
}
#endif
void
ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
isc_result_t result;
......@@ -3599,6 +3699,11 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
server->dispatchgen = 0;
ISC_LIST_INIT(server->dispatches);
/*
* HTTP server configuration.
*/
server->httpd = NULL;
server->magic = NS_SERVER_MAGIC;
*serverp = server;
}
......@@ -3786,6 +3891,7 @@ reload(ns_server_t *server) {
"reloading zones failed: %s",
isc_result_totext(result));
}
cleanup:
return (result);
}
......@@ -3802,6 +3908,7 @@ reconfig(ns_server_t *server) {
"loading new zones failed: %s",
isc_result_totext(result));
}
cleanup: ;
}
......@@ -5044,3 +5151,196 @@ 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
tree_walk(xmlTextWriterPtr writer, isc_mib_t *mib, isc_mibnode_t *node)
{
char buf[128];
int xmlrc;
while (node != NULL) {
if (node->type == ISC_MIBNODETYPE_NODE)
if (!isc_mibnode_haschildren(node))
goto nextnode;
TRY0(xmlTextWriterStartElement(writer,
ISC_XMLCHAR node->name));
switch (node->type) {
case ISC_MIBNODETYPE_NODE:
tree_walk(writer, mib, isc_mib_firstnode(mib, node));
break;
case ISC_MIBNODETYPE_UINT32:
sprintf(buf, "%u", *(unsigned int *)(node->data));
TRY0(xmlTextWriterWriteString(writer,
ISC_XMLCHAR buf));
break;
case ISC_MIBNODETYPE_INT32:
sprintf(buf, "%d", *(int *)(node->data));
TRY0(xmlTextWriterWriteString(writer,
ISC_XMLCHAR buf));
break;
case ISC_MIBNODETYPE_UINT64:
sprintf(buf, "%qu",
*(unsigned long long *)(node->data));
TRY0(xmlTextWriterWriteString(writer,
ISC_XMLCHAR buf));
break;
case ISC_MIBNODETYPE_INT64:
sprintf(buf, "%qd", *(long long *)(node->data));
TRY0(xmlTextWriterWriteString(writer,
ISC_XMLCHAR buf));
break;
case ISC_MIBNODETYPE_STRING:
sprintf(buf, "%s", *(char **)(node->data));
TRY0(xmlTextWriterWriteString(writer,
ISC_XMLCHAR buf));
break;
}
TRY0(xmlTextWriterEndElement(writer));
nextnode:
node = isc_mib_nextnode(mib, node);
}
}
void
server_generatexml(ns_server_t *server, unsigned 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 "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(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;
unsigned 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 */
......@@ -16,7 +16,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: config.h.in,v 1.83 2006/12/04 01:54:53 marka Exp $ */
/* $Id: config.h.in,v 1.86 2006/12/22 01:46:18 marka Exp $ */
/*! \file */
......@@ -199,6 +199,9 @@ int sigwait(const unsigned int *set, int *sig);
/* Define to 1 if you have the `thr' library (-lthr). */
#undef HAVE_LIBTHR
/* Define if libxml2 was found */
#undef HAVE_LIBXML2
/* Define to 1 if you have the <linux/capability.h> header file. */
#undef HAVE_LINUX_CAPABILITY_H
......
......@@ -14,7 +14,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
# $Id: configure,v 1.409 2006/12/04 04:27:29 marka Exp $
# $Id: configure,v 1.410 2006/12/21 06:03:37 marka Exp $
#
# Portions Copyright (C) 1996-2001 Nominum, Inc.
#
......@@ -29,7 +29,7 @@
# 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.
# From configure.in Revision: 1.421 .
# From configure.in Revision: 1.422 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59.
#