server.c revision 1c4fb0e31596318b2a712247c7f8bed21412964c
/*
* Copyright (C) 1999, 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 <config.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <isc/assertions.h>
#include <dns/confparser.h>
#include <dns/dispatch.h>
#include <dns/fixedname.h>
#include <dns/resolver.h>
#include <dns/tkeyconf.h>
#include <dns/tsigconf.h>
#include <dns/zoneconf.h>
#include <named/interfacemgr.h>
#include <named/listenlist.h>
/*
* Check an operation for failure. Assumes that the function
* using it has a 'result' variable and a 'cleanup' label.
*/
} while (0)
if (result != ISC_R_SUCCESS) { \
"%s: %s", msg, \
isc_result_totext(result)); \
goto cleanup; \
} \
} while (0) \
if (result != ISC_R_SUCCESS) \
} while (0) \
typedef struct {
} ns_load_t;
static isc_result_t
static isc_result_t
/*
* Configure 'view' according to 'cctx'.
*/
static isc_result_t
{
unsigned int i;
/*
* Configure the view's cache. Try to reuse an existing
* cache if possible, otherwise create a new cache.
* Note that the ADB is not preserved in either case.
*
* XXX Determining when it is safe to reuse a cache is
* tricky. When the view's configuration changes, the cached
* data may become invalid because it reflects our old
* view of the world. As more view attributes become
* configurable, we will have to add code here to check
* whether they have changed in ways that could
* invalidate the cache.
*/
&pview);
goto cleanup;
} else {
}
/*
* XXXRTH Temporary support for loading cache contents.
*/
if (ns_g_cachefile != NULL) {
}
/*
* Resolver.
*
* XXXRTH Hardwired number of tasks.
*/
0, dispatchv4, dispatchv6));
/*
* Set resolver forwarding policy.
*/
/*
* Ugh. Convert between list formats.
*/
for (i = 0; i < forwarders->nextidx; i++) {
goto cleanup;
}
}
/*
* XXXRTH The configuration type 'dns_c_forw_t' should be
* elminated.
*/
forward == dns_c_forw_only);
if (forward == dns_c_forw_only)
}
}
/*
* We have default hints for class IN if we need them.
*/
/*
* Configure the view's TSIG keys.
*/
/*
* Configure the view's peer list.
*/
{
} else {
}
}
}
return (result);
}
/*
* Create the special view that handles queries for
* "version.bind. CH". The version string returned is that
* configured in 'configctx', or a compiled-in default if
* there is no "version" configuration option.
*/
static isc_result_t
char *versiontext;
unsigned char buf[256];
isc_region_t r;
static unsigned char origindata[] = "\007version\004bind";
r.base = origindata;
r.length = sizeof(origindata);
dns_name_fromregion(&origin, &r);
if (versiontext == NULL)
if (len > 255)
&view));
/* Transfer ownership. */
dns_db_detach(&db);
return (result);
}
static isc_result_t
if (result == ISC_R_SUCCESS) {
dns_db_detach(&db);
}
return (result);
}
/*
* Configure or reconfigure a zone. This callback function
* is called after parsing each "zone" statement in named.conf.
*/
static isc_result_t
void *uap)
{
char *viewname;
char *corigin;
/*
* Get the zone origin as a dns_name_t.
*/
/* XXX casting away const */
/*
* Find or create the view in the new view list.
*/
else
viewname = "_default";
goto cleanup;
}
/*
* Master zones must have 'file' set.
*/
"zone '%s': 'file' not specified",
corigin);
goto cleanup;
}
/*
* "hints zones" aren't zones. If we've got one,
* configure it and return.
*/
"zone '%s': 'file' not specified",
corigin);
goto cleanup;
}
} else {
"ignoring non-root hint zone '%s'",
corigin);
}
goto cleanup;
}
/*
* "stub zones" aren't zones either. Eventually we'll
* create a "cache freshener" to keep the stub data in the
* cache.
*/
"stub zone '%s': stub zones are not supported in this release",
corigin);
goto cleanup;
}
/*
* "forward zones" aren't zones either. Eventually we'll
* translate this syntax into the appropriate selective forwarding
* configuration.
*/
"forward zone '%s': forward zones are not supported in this release",
corigin);
goto cleanup;
}
/*
* Check for duplicates in the new zone table.
*/
if (result == ISC_R_SUCCESS) {
/*
* We already have this zone!
*/
goto cleanup;
}
/*
* See if we can reuse an existing zone. This is
* only possible if all of these are true:
* - The zone's view exists
* - A zone with the right name exists in the view
* - The zone is compatible with the config
* options (e.g., an existing master zone cannot
* be reused if the options specify a slave zone)
*/
&pview);
goto cleanup;
goto cleanup;
}
/*
* If we cannot reuse an existing zone, we will have to
* create a new one.
*/
zone));
}
/*
* Configure the zone.
*/
/*
* Add the zone to its view in the new view list.
*/
return (result);
}
/*
* Configure a single server ACL at '*aclp'. Get its configuration by
* calling 'getacl'.
*/
static isc_result_t
{
}
return (result);
}
/*
* Configure a single server quota.
*/
static void
{
}
static isc_result_t
dns_dispatch_t **dispatchp) {
switch (af) {
case AF_INET:
break;
case AF_INET6:
break;
default:
INSIST(0);
}
if (result != ISC_R_SUCCESS)
/*
* If we don't support this address family, we're done!
*/
switch (af) {
case AF_INET:
result = isc_net_probeipv4();
break;
case AF_INET6:
result = isc_net_probeipv6();
break;
default:
INSIST(0);
}
if (result != ISC_R_SUCCESS)
return (ISC_R_SUCCESS);
/*
* The query source is fully wild. No special dispatcher
* work needs to be done.
*/
return (ISC_R_SUCCESS);
}
/*
* If the interface manager has a dispatcher for this address,
* use it.
*/
switch (af) {
case AF_INET:
break;
case AF_INET6:
break;
default:
INSIST(0);
}
dispatchp) !=
/*
* The interface manager doesn't have a matching dispatcher.
*/
if (*server_dispatchp != NULL) {
/*
* We've already got a custom dispatcher. If it is
* compatible with the new configuration, use it.
*/
&sa)) {
return (ISC_R_SUCCESS);
}
/*
* The existing custom dispatcher is not compatible.
* We don't need it anymore.
*/
}
/*
* Create a custom dispatcher.
*/
&socket);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS) {
return (result);
}
/*
* Regardless of whether dns_dispatch_create() succeeded or
* failed, we don't need to keep the reference to the socket.
*/
if (result != ISC_R_SUCCESS)
return (result);
} else {
/*
* We're sharing a UDP dispatcher with the interface manager
* now. Any prior custom dispatcher can be discarded.
*/
if (*server_dispatchp != NULL)
}
return (ISC_R_SUCCESS);
}
/*
* This function is called as soon as the 'options' statement has been
* parsed.
*/
static isc_result_t
/*
* Change directory.
*/
if (result != ISC_R_SUCCESS) {
ISC_LOG_ERROR, "change directory "
"to '%s' failed: %s",
return (result);
}
}
return (ISC_R_SUCCESS);
}
static void
}
/*
* This event callback is invoked to do periodic network
* interface scanning.
*/
static void
}
static isc_result_t
{
char *pidfilename;
ISC_LOG_INFO, "loading configuration from '%s'",
filename);
/*
* Parse the configuration file creating a parse tree. Any
* 'zone' statements are handled immediately by calling
* configure_zone() through 'callbacks'.
*/
&callbacks));
/*
* Configure various server options.
*/
(void) dns_c_ctx_gettransferformat(configctx,
&server->recursionacl));
/*
* Configure the zone manager.
*/
{
}
{
}
/*
* Configure the interface manager according to the "listen-on"
* statement.
*/
{
&listenon);
} else {
/* Not specified, use default. */
&listenon));
}
}
/*
* Rescan the interface list to pick up changes in the
* listen-on option. It's important that we do this before we try
* to configure the query source, since the dispatcher we use might
* be shared with an interface.
*/
/*
* Arrange for further interface scanning to occur periodically
* as specified by the "interface-interval" option.
*/
if (interface_interval == 0) {
} else {
}
AF_INET, &dispatchv4));
AF_INET6, &dispatchv6));
/*
* If we haven't created any views, create a default view for class
* IN. (We're a caching-only server.)
*/
"_default", &view),
"creating default view");
}
/*
* Configure and freeze the views. Their zone tables have
* already been filled in at parsing time, but other stuff
* like the resolvers are still unconfigured.
*/
{
dispatchv4, dispatchv6));
}
/*
* Create (or recreate) the version view.
*/
/*
* Swap our new view list with the production one.
*/
/*
* Load the TKEY information from the configuration.
*/
{
dns_tkey_ctx_t *t = NULL;
"configuring TKEY");
}
/*
* Configure the logging system.
*/
if (ns_g_logstderr) {
"ignoring named.conf logging statement "
"due to -g option");
} else {
"creating new logging configuration");
"configuring logging");
else
"setting up default logging defaults");
if (result != ISC_R_SUCCESS) {
}
}
if (first_time)
/*
* This cleans up either the old production view list
* or our temporary list depending on whether they
* were swapped above or not.
*/
}
if (dispatchv4 != NULL)
if (dispatchv6 != NULL)
return (result);
}
static isc_result_t
/*
* Load zone data from disk.
*/
{
}
/*
* Force zone maintenance. Do this after loading
* so that we know when we need to force AXFR of
* slave zones whose master files are missing.
*/
return (result);
}
static void
"creating client manager");
&server->interfacemgr),
"creating interface manager");
"creating interface timer");
"loading configuration");
"loading zones");
ISC_LOG_INFO, "running");
}
static void
ISC_LOG_INFO, "shutting down");
}
}
void
"initializing server configuration lock");
/* Initialize configuration data with default values. */
/* Initialize server data structures. */
"setting up root hints");
"initializing reload event lock");
sizeof(isc_event_t));
"allocating reload event");
"creating TKEY context");
/*
* Setup the server task, which is responsible for coordinating
* startup and shutdown of the server.
*/
"creating server task");
"isc_task_onshutdown");
"isc_app_onrun");
/*
* Create a timer for periodic interface scanning.
*/
"dns_zonemgr_create");
}
void
}
static void
{
ISC_LOG_CRITICAL, "exiting (due to fatal error)");
exit(1);
}
static void
if (result != DNS_R_SUCCESS) {
"reloading configuration failed: %s",
}
if (result != DNS_R_SUCCESS) {
"reloading zones failed: %s",
}
}
void
}
static isc_result_t
{
if (result != ISC_R_SUCCESS)
return (result);
{
if (result != DNS_R_SUCCESS)
goto cleanup;
}
return (ISC_R_SUCCESS);
return (result);
}
/*
* Create a listen list from the corresponding configuration
* data structure.
*/
static isc_result_t
{
if (result != ISC_R_SUCCESS)
return (result);
if (result != DNS_R_SUCCESS) {
return (result);
}
return (ISC_R_SUCCESS);
}