2930. [experimental] New "rndc addzone" and "rndc delzone" commads

allow dynamic addition and deletion of zones.
			To enable this feature, specify a "new-zone-file"
			option at the view or options level in named.conf.
			Zone configuration information for the new zones
			will be written into that file.  To make the new
			zones persist after a restart, "include" the file
			into named.conf in the appropriate view.  (Note:
			This feature is not yet documented, and its syntax
			is expected to change.) [RT #19447]
This commit is contained in:
Evan Hunt 2010-07-11 00:12:57 +00:00
parent 773896a200
commit 86dcc40058
13 changed files with 734 additions and 36 deletions

11
CHANGES
View file

@ -1,3 +1,14 @@
2930. [experimental] New "rndc addzone" and "rndc delzone" commads
allow dynamic addition and deletion of zones.
To enable this feature, specify a "new-zone-file"
option at the view or options level in named.conf.
Zone configuration information for the new zones
will be written into that file. To make the new
zones persist after a restart, "include" the file
into named.conf in the appropriate view. (Note:
This feature is not yet documented, and its syntax
is expected to change.) [RT #19447]
2929. [bug] Improved handling of GSS security contexts:
- added LRU expiration for generated TSIGs
- added the ability to use a non-default realm

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: control.c,v 1.38 2010/06/25 23:46:51 tbox Exp $ */
/* $Id: control.c,v 1.39 2010/07/11 00:12:57 each Exp $ */
/*! \file */
@ -191,6 +191,10 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) {
result = ns_server_validation(ns_g_server, command);
} else if (command_compare(command, NS_COMMAND_SIGN)) {
result = ns_server_sign(ns_g_server, command);
} else if (command_compare(command, NS_COMMAND_ADDZONE)) {
result = ns_server_add_zone(ns_g_server, command);
} else if (command_compare(command, NS_COMMAND_DELZONE)) {
result = ns_server_del_zone(ns_g_server, command);
} else {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: control.h,v 1.29 2010/06/25 23:46:51 tbox Exp $ */
/* $Id: control.h,v 1.30 2010/07/11 00:12:57 each Exp $ */
#ifndef NAMED_CONTROL_H
#define NAMED_CONTROL_H 1
@ -59,6 +59,8 @@
#define NS_COMMAND_NOTIFY "notify"
#define NS_COMMAND_VALIDATION "validation"
#define NS_COMMAND_SIGN "sign"
#define NS_COMMAND_ADDZONE "addzone"
#define NS_COMMAND_DELZONE "delzone"
isc_result_t
ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp);

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.h,v 1.107 2010/06/25 03:24:05 marka Exp $ */
/* $Id: server.h,v 1.108 2010/07/11 00:12:57 each Exp $ */
#ifndef NAMED_SERVER_H
#define NAMED_SERVER_H 1
@ -319,4 +319,16 @@ ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr);
isc_result_t
ns_server_validation(ns_server_t *server, char *args);
/*%
* Add a zone to a running process
*/
isc_result_t
ns_server_add_zone(ns_server_t *server, char *args);
/*%
* Deletes a zone from a running process
*/
isc_result_t
ns_server_del_zone(ns_server_t *server, char *args);
#endif /* NAMED_SERVER_H */

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.c,v 1.571 2010/06/25 23:46:51 tbox Exp $ */
/* $Id: server.c,v 1.572 2010/07/11 00:12:57 each Exp $ */
/*! \file */
@ -24,6 +24,9 @@
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <isc/app.h>
#include <isc/base64.h>
@ -291,6 +294,15 @@ add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
static void
end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
/*
* Stores config for building zones after the fact
*/
static cfg_obj_t *nzf_config = NULL;
static cfg_parser_t *nzf_parser = NULL;
static const char *nzf_file = NULL;
static const cfg_obj_t *nzf_option = NULL;
static cfg_aclconfctx_t nzf_actx;
/*%
* Configure a single view ACL at '*aclp'. Get its configuration from
* 'vconfig' (for per-view configuration) and maybe from 'config'
@ -3999,6 +4011,17 @@ load_configuration(const char *filename, ns_server_t *server,
}
}
/* Are we preserving config for adding zones dynamically? */
obj = NULL;
result = cfg_map_get(options, "new-zone-file", &obj);
if (obj && nzf_option == NULL) {
nzf_file = cfg_obj_asstring(obj);
if (nzf_file && *nzf_file) {
/* Remember this configuration */
nzf_option = config;
}
}
/*
* Rescan the interface list to pick up changes in the
* listen-on option. It's important that we do this before we try
@ -4094,6 +4117,20 @@ load_configuration(const char *filename, ns_server_t *server,
CHECK(configure_view(view, config, vconfig,
&cachelist, bindkeys,
ns_g_mctx, &aclconfctx, ISC_TRUE));
if (vconfig != NULL) {
/*
* Are we preserving config for dynamically added
* zones?
*/
const cfg_obj_t *voptions;
voptions = cfg_tuple_get(vconfig, "options");
obj = NULL;
result = cfg_map_get(voptions, "new-zone-file", &obj);
if (obj && nzf_option == NULL)
nzf_option = config;
}
dns_view_freeze(view);
dns_view_detach(&view);
}
@ -4415,7 +4452,16 @@ load_configuration(const char *filename, ns_server_t *server,
if (v6portset != NULL)
isc_portset_destroy(ns_g_mctx, &v6portset);
cfg_aclconfctx_destroy(&aclconfctx);
/* Preserve config, we'll need it when adding zones */
if (nzf_option != NULL) {
nzf_parser = conf_parser;
conf_parser = NULL;
nzf_config = config;
config = NULL;
memcpy(&nzf_actx, &aclconfctx, sizeof(cfg_aclconfctx_t));
} else {
cfg_aclconfctx_destroy(&aclconfctx);
}
if (conf_parser != NULL) {
if (config != NULL)
@ -4623,6 +4669,12 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
cfg_obj_destroy(ns_g_parser, &ns_g_config);
cfg_parser_destroy(&ns_g_parser);
if (nzf_config) {
cfg_aclconfctx_destroy(&nzf_actx);
cfg_obj_destroy(nzf_parser, &nzf_config);
cfg_parser_destroy(&nzf_parser);
}
for (view = ISC_LIST_HEAD(server->viewlist);
view != NULL;
view = view_next) {
@ -5096,7 +5148,9 @@ next_token(char **stringp, const char *delim) {
* set '*zonep' to NULL.
*/
static isc_result_t
zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) {
zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep,
const char **zonename)
{
char *input, *ptr;
const char *zonetxt;
char *classtxt;
@ -5120,6 +5174,8 @@ zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) {
zonetxt = next_token(&input, " \t");
if (zonetxt == NULL)
return (ISC_R_SUCCESS);
if (zonename)
*zonename = zonetxt;
/* Look for the optional class name. */
classtxt = next_token(&input, " \t");
@ -5180,7 +5236,7 @@ ns_server_retransfercommand(ns_server_t *server, char *args) {
dns_zone_t *zone = NULL;
dns_zonetype_t type;
result = zone_from_args(server, args, &zone);
result = zone_from_args(server, args, &zone, NULL);
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL)
@ -5204,7 +5260,7 @@ ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
dns_zonetype_t type;
const char *msg = NULL;
result = zone_from_args(server, args, &zone);
result = zone_from_args(server, args, &zone, NULL);
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL) {
@ -5264,7 +5320,7 @@ ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) {
dns_zone_t *zone = NULL;
const unsigned char msg[] = "zone notify queued";
result = zone_from_args(server, args, &zone);
result = zone_from_args(server, args, &zone, NULL);
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL)
@ -5289,7 +5345,7 @@ ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
const unsigned char msg2[] = "not a slave or stub zone";
dns_zonetype_t type;
result = zone_from_args(server, args, &zone);
result = zone_from_args(server, args, &zone, NULL);
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL)
@ -6385,7 +6441,7 @@ ns_server_sign(ns_server_t *server, char *args) {
dns_zonetype_t type;
isc_uint16_t keyopts;
result = zone_from_args(server, args, &zone);
result = zone_from_args(server, args, &zone, NULL);
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL)
@ -6425,7 +6481,7 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
isc_boolean_t frozen;
const char *msg = NULL;
result = zone_from_args(server, args, &zone);
result = zone_from_args(server, args, &zone, NULL);
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL) {
@ -6543,3 +6599,503 @@ ns_smf_add_message(isc_buffer_t *text) {
return (ISC_R_SUCCESS);
}
#endif /* HAVE_LIBSCF */
/*
* Act on an "addzone" command from the command channel.
*/
isc_result_t
ns_server_add_zone(ns_server_t *server, char *args) {
isc_result_t result;
isc_buffer_t argbuf;
size_t arglen, len;
cfg_parser_t *parser = NULL;
cfg_obj_t *config = NULL;
const cfg_obj_t *vconfig = NULL;
const cfg_obj_t *views = NULL;
const cfg_listelt_t *element;
const cfg_obj_t *parms = NULL;
const cfg_obj_t *obj = NULL;
const char *zonename;
const char *classname = NULL;
const char *argp;
const char *viewname = NULL;
dns_rdataclass_t rdclass;
dns_view_t *view = 0;
isc_buffer_t buf, *nbuf = NULL;
dns_name_t dnsname;
const char *filename = 0;
const char *filepart = NULL;
char fnamebuf[512];
struct stat sb;
dns_zone_t *zone = NULL;
FILE *fp = NULL;
/* Are we accepting new zones? */
if (nzf_option == NULL)
return (ISC_R_FAILURE);
/* Try to parse the argument string */
arglen = strlen(args);
isc_buffer_init(&argbuf, args, arglen);
isc_buffer_add(&argbuf, strlen(args));
CHECK(cfg_parser_create(server->mctx, ns_g_lctx, &parser));
CHECK(cfg_parse_buffer(parser, &argbuf, &cfg_type_addzoneconf,
&config));
CHECK(cfg_map_get(config, "addzone", &parms));
zonename = cfg_obj_asstring(cfg_tuple_get(parms, "name"));
isc_buffer_init(&buf, zonename, strlen(zonename));
isc_buffer_add(&buf, strlen(zonename));
dns_name_init(&dnsname, NULL);
isc_buffer_allocate(server->mctx, &nbuf, 256);
dns_name_setbuffer(&dnsname, nbuf);
CHECK(dns_name_fromtext(&dnsname, &buf, dns_rootname, ISC_FALSE, NULL));
/*
* If new-zone-file indicates a directory rather than a file,
* then "filepart" is the filename in the directory in which to
* write the zone configuration text.
*/
obj = cfg_tuple_get(parms, "filepart");
if (obj && cfg_obj_isstring(obj))
filepart = cfg_obj_asstring(obj);
if (filepart != NULL && *filepart != '\0') {
/* No hidden fles or full paths */
if (*filepart == '.' ||
#ifdef WIN32
*filepart == '\\' ||
#endif
*filepart == '/')
{
result = ISC_R_INVALIDFILE;
goto cleanup;
}
/* No crawling up the directory tree */
if (strstr(filepart, "..") != NULL) {
result = ISC_R_INVALIDFILE;
goto cleanup;
}
}
/* Make sense of optional class argument */
obj = cfg_tuple_get(parms, "class");
CHECK(ns_config_getclass(obj, dns_rdataclass_in, &rdclass));
if (rdclass != dns_rdataclass_in && obj)
classname = cfg_obj_asstring(obj);
/* Make sense of optional view argument */
obj = cfg_tuple_get(parms, "view");
if (obj && cfg_obj_isstring(obj))
viewname = cfg_obj_asstring(obj);
if (viewname == NULL || *viewname == '\0')
viewname = "_default";
CHECK(dns_viewlist_find(&server->viewlist, viewname, rdclass, &view));
/* Zone shouldn't already exist */
result = dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone);
if (result == ISC_R_SUCCESS) {
result = ISC_R_EXISTS;
goto cleanup;
} else if (result == DNS_R_PARTIALMATCH) {
/* Create our sub-zone anyway */
dns_zone_detach(&zone);
zone = NULL;
}
else if (result != ISC_R_NOTFOUND)
goto cleanup;
/* Find configuration for this view */
(void)cfg_map_get(nzf_config, "view", &views);
for (element = cfg_list_first(views);
element != NULL;
element = cfg_list_next(element))
{
const char *vname;
vconfig = cfg_listelt_value(element);
vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
if (vname && !strcasecmp(vname, viewname)) {
/* What is save file for this view? */
if (vconfig != NULL) {
const cfg_obj_t *voptions;
voptions = cfg_tuple_get(vconfig, "options");
if (voptions) {
obj = NULL;
result = cfg_map_get(voptions,
"new-zone-file",
&obj);
if (result == ISC_R_SUCCESS)
filename =
cfg_obj_asstring(obj);
}
}
break;
}
vconfig = NULL;
}
/* Can we add and remove zones in this view? */
if (filename == NULL || *filename == '\0')
filename = nzf_file;
if (filename == NULL || *filename == '\0') {
/* No adding zones in this view */
result = ISC_R_FAILURE;
goto cleanup;
}
/* Possibly contruct a full path */
if (filepart != NULL && *filepart != '\0') {
snprintf(fnamebuf, 512, "%s/%s", filename, filepart);
filename = fnamebuf;
}
/* Path must be an existing file */
if (stat(filename, &sb) < 0) {
result = ISC_R_FILENOTFOUND;
goto cleanup;
}
if (!S_ISREG(sb.st_mode)) {
result = ISC_R_FILENOTFOUND;
goto cleanup;
}
/* Mark zone unfrozen so that zone can be added. */
dns_view_thaw(view);
result = configure_zone(nzf_option, parms, vconfig,
server->mctx, view, &nzf_actx);
dns_view_freeze(view);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
/* Is it there yet? */
CHECK(dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone));
/*
* Load the zone from the master file. If this fails, we'll
* need to undo the configuration we've done already.
*/
result = dns_zone_loadnew(zone);
if (result != ISC_R_SUCCESS) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_INFO,
"addzone failed; reverting.");
/* If the zone loaded partially, unload it */
dns_db_t *dbp = NULL;
if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
dns_db_detach(&dbp);
dns_zone_unload(zone);
}
/* Remove the zone from the zone table */
dns_zt_unmount(view->zonetable, zone);
goto cleanup;
}
/* Write zone configuration out to our save file */
CHECK(isc_stdio_open(filename, "a", &fp));
/* Emit just the zone name from args */
CHECK(isc_stdio_write("zone ", 5, 1, fp, &len));
CHECK(isc_stdio_write(zonename, strlen(zonename), 1, fp, &len));
CHECK(isc_stdio_write(" ", 1, 1, fp, &len));
/* Classname, if not default */
if (classname != NULL && *classname != '\0') {
CHECK(isc_stdio_write(classname, strlen(classname), 1, fp,
&len));
CHECK(isc_stdio_write(" ", 1, 1, fp, &len));
}
/* Find beginning of option block from args */
for (argp = args; *argp; argp++, arglen--) {
if (*argp == '{') { /* Assume matching '}' */
/* Add that to our file */
CHECK(isc_stdio_write(argp, arglen, 1, fp, &len));
/* Make sure we end with a LF */
if (argp[arglen-1] != '\n') {
CHECK(isc_stdio_write("\n", 1, 1, fp, &len));
}
break;
}
}
CHECK(isc_stdio_close(fp));
fp = NULL;
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_INFO,
"zone %s added to view %s via addzone",
zonename, viewname);
result = ISC_R_SUCCESS;
cleanup:
if (fp != NULL)
isc_stdio_close(fp);
if (parser != NULL) {
if (config != NULL)
cfg_obj_destroy(parser, &config);
cfg_parser_destroy(&parser);
}
if (zone != NULL)
dns_zone_detach(&zone);
if (view != NULL)
dns_view_detach(&view);
if (nbuf != NULL)
isc_buffer_free(&nbuf);
return (result);
}
/*
* Pull an optional quoted filepart out of an arglist, shuffling memory
* so we can hand it off to zone_from_args() later
*/
static char *
extract_optional_qstring(char **args) {
char *p = *args;
char *str, *d;
char quote;
/* Skip past the command name */
while (isspace(*p))
p++;
while (*p && !isspace(*p))
p++;
/* Look for an open quote */
while (isspace(*p))
p++;
if (*p != '\'' && *p != '"')
return (NULL);
/* Move that string to the front of the buf */
quote = *p++;
str = d = *args;
while (*p && *p != quote)
*d++ = *p++;
if (!*p)
return (NULL); /* No matching close quote */
/* End that string */
*d++ = 0;
*args = d;
/* A bogus command name to placate zone_from_args() */
*d++ = 'X';
/* Cover over any remainder with spaces */
while (d <= p)
*d++ = ' ';
return (str);
}
/*
* Act on a "delzone" command from the command channel.
*/
isc_result_t
ns_server_del_zone(ns_server_t *server, char *args) {
isc_result_t result;
dns_zone_t *zone = NULL;
dns_view_t *view = NULL;
const cfg_obj_t *views = NULL;
const cfg_obj_t *obj = NULL;
const cfg_obj_t *vconfig = NULL;
dns_db_t *dbp = NULL;
const char *filename = NULL;
char *filepart = NULL;
char fnamebuf[512];
char *tmpname = NULL;
const cfg_listelt_t *element;
char buf[1024];
const char *zonename = NULL;
size_t znamelen = 0;
FILE *ifp = NULL, *ofp = NULL;
/* Only accept removes if we're accepting adds */
if (nzf_option == NULL)
return (ISC_R_FAILURE);
/* Possibly a filename in quotes */
filepart = extract_optional_qstring(&args);
if (filepart != NULL && *filepart != '\0') {
/* No hidden fles or full paths */
if (*filepart == '.' ||
#ifdef WIN32
*filepart == '\\' ||
#endif
*filepart == '/')
{
result = ISC_R_INVALIDFILE;
goto cleanup;
}
/* No crawling up the directory tree */
if (strstr(filepart, "..") != NULL) {
result = ISC_R_INVALIDFILE;
goto cleanup;
}
}
/* Make sense of rest of params */
CHECK(zone_from_args(server, args, &zone, &zonename));
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL) {
result = ISC_R_UNEXPECTEDEND;
goto cleanup;
}
if (zonename != NULL && *zonename != '\0')
znamelen = strlen(zonename);
/* Dig out configuration for this zone */
view = dns_zone_getview(zone);
(void)cfg_map_get(nzf_config, "view", &views);
for (element = cfg_list_first(views);
element != NULL;
element = cfg_list_next(element))
{
const char *vname;
vconfig = cfg_listelt_value(element);
vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
if (vname != NULL && !strcasecmp(vname, view->name)) {
/* What is save file for this view? */
if (vconfig != NULL) {
const cfg_obj_t *voptions;
voptions = cfg_tuple_get(vconfig, "options");
if (voptions != NULL) {
obj = NULL;
result = cfg_map_get(voptions,
"new-zone-file",
&obj);
if (result == ISC_R_SUCCESS)
filename =
cfg_obj_asstring(obj);
}
}
break;
}
vconfig = NULL;
}
/* Can we add and remove zones in this view? */
if (filename == NULL || *filename == '\0')
filename = nzf_file;
if (filename == NULL || *filename == '\0') {
/* No adding zones in this view */
result = ISC_R_FAILURE;
goto cleanup;
}
/* Possibly contruct a full path */
if (filepart != NULL && *filepart != '\0') {
snprintf(fnamebuf, 512, "%s/%s", filename, filepart);
filename = fnamebuf;
}
/* Rewrite zone list */
result = isc_stdio_open(filename, "r", &ifp);
if (ifp != NULL && result == ISC_R_SUCCESS) {
char *found = NULL, *p;
size_t n;
/* Create a temporary file */
CHECK(isc_string_printf(buf, 1023, "%s.%d", filename,
getpid()));
if (!(tmpname = isc_mem_strdup(server->mctx, buf))) {
result = ISC_R_NOMEMORY;
goto cleanup;
}
CHECK(isc_stdio_open(tmpname, "w", &ofp));
/* Look for the entry for that zone */
while (fgets(buf, 1024, ifp)) {
/* A 'zone' line */
if (strncasecmp(buf, "zone", 4)) {
fputs(buf, ofp);
continue;
}
p = buf+4;
/* Locate a name */
while (*p && ((*p == '"') || isspace(*p)))
p++;
/* Is that the zone we're looking for */
if (strncasecmp(p, zonename, znamelen)) {
fputs(buf, ofp);
continue;
}
/* And nothing else? */
p += znamelen;
if (isspace(*p) || *p == '"' || *p == '{') {
/* This must be the entry */
found = p;
break;
}
/* Spit it out, keep looking */
fputs(buf, ofp);
}
/* Skip over an option block (matching # of braces) */
if (found) {
int obrace = 0, cbrace = 0;
while (1) {
while (*p) {
if (*p == '{') obrace++;
if (*p == '}') cbrace++;
p++;
}
if (obrace && (obrace == cbrace))
break;
if (!fgets(buf, 1024, ifp))
break;
p = buf;
}
}
/* Just spool the remainder of the file out */
while ((n = fread(buf, 1, 1024, ifp)) > 0)
fwrite(buf, 1, n, ofp);
/* Move temporary into place */
CHECK(isc_file_rename(tmpname, filename));
}
/* Stop answering for this zone */
if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
dns_db_detach(&dbp);
dns_zone_unload(zone);
}
CHECK(dns_zt_unmount(view->zonetable, zone));
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_INFO,
"zone %s removed via delzone", zonename);
result = ISC_R_SUCCESS;
cleanup:
if (ifp != NULL)
isc_stdio_close(ifp);
if (ofp != NULL) {
isc_stdio_close(ofp);
isc_file_remove(tmpname);
}
if (tmpname != NULL)
isc_mem_free(server->mctx, tmpname);
if (zone != NULL)
dns_zone_detach(&zone);
return (result);
}

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zoneconf.c,v 1.161 2009/12/04 21:09:32 marka Exp $ */
/* $Id: zoneconf.c,v 1.162 2010/07/11 00:12:57 each Exp $ */
/*% */
@ -558,6 +558,28 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
if (result == ISC_R_SUCCESS)
filename = cfg_obj_asstring(obj);
/*
* Unless we're using some alternative database, a master zone
* will be needing a master file.
*/
if (ztype == dns_zone_master && cpval == default_dbtype) {
if (filename == NULL) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
"zone '%s': 'file' not specified",
zname);
return (ISC_R_FAILURE);
}
if (!isc_file_exists(filename)) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
"zone '%s': master file not found",
zname);
return (ISC_R_NOTFOUND);
}
}
masterformat = dns_masterformat_text;
obj = NULL;
result= ns_config_get(maps, "masterfile-format", &obj);

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rndc.c,v 1.129 2010/06/25 23:46:51 tbox Exp $ */
/* $Id: rndc.c,v 1.130 2010/07/11 00:12:57 each Exp $ */
/*! \file */
@ -143,6 +143,10 @@ command is one of the following:\n\
validation newstate [view]\n\
Enable / disable DNSSEC validation.\n\
*restart Restart the server.\n\
addzone [\"file\"] zone [class [view]] { zone-options }\n\
Add zone to given view. Requires new-zone-file option.\n\
delzone [\"file\"] zone [class [view]]\n\
Removes zone from given view. Requires new-zone-file option.\n\
\n\
* == not yet implemented\n\
Version: %s\n",

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: resolver.h,v 1.66 2010/02/25 05:08:01 tbox Exp $ */
/* $Id: resolver.h,v 1.67 2010/07/11 00:12:57 each Exp $ */
#ifndef DNS_RESOLVER_H
#define DNS_RESOLVER_H 1
@ -180,7 +180,7 @@ dns_resolver_freeze(dns_resolver_t *res);
*
* Requires:
*
*\li 'res' is a valid, unfrozen resolver.
*\li 'res' is a valid resolver.
*
* Ensures:
*

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: view.h,v 1.124 2010/06/22 03:58:38 marka Exp $ */
/* $Id: view.h,v 1.125 2010/07/11 00:12:57 each Exp $ */
#ifndef DNS_VIEW_H
#define DNS_VIEW_H 1
@ -416,7 +416,7 @@ dns_view_addzone(dns_view_t *view, dns_zone_t *zone);
void
dns_view_freeze(dns_view_t *view);
/*%<
* Freeze view.
* Freeze view. No changes can be made to view configuration while frozen.
*
* Requires:
*
@ -427,6 +427,21 @@ dns_view_freeze(dns_view_t *view);
*\li 'view' is frozen.
*/
void
dns_view_thaw(dns_view_t *view);
/*%<
* Thaw view. This allows zones to be added or removed at runtime. This is
* NOT thread-safe; the caller MUST have run isc_task_exclusive() prior to
* thawing the view.
*
* Requires:
*
*\li 'view' is a valid, frozen view.
*
* Ensures:
*
*\li 'view' is no longer frozen.
*/
isc_result_t
dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: resolver.c,v 1.424 2010/07/04 00:48:57 marka Exp $ */
/* $Id: resolver.c,v 1.425 2010/07/11 00:12:57 each Exp $ */
/*! \file */
@ -7684,13 +7684,11 @@ dns_resolver_prime(dns_resolver_t *res) {
void
dns_resolver_freeze(dns_resolver_t *res) {
/*
* Freeze resolver.
*/
REQUIRE(VALID_RESOLVER(res));
REQUIRE(!res->frozen);
res->frozen = ISC_TRUE;
}

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: view.c,v 1.165 2010/06/22 03:58:38 marka Exp $ */
/* $Id: view.c,v 1.166 2010/07/11 00:12:57 each Exp $ */
/*! \file */
@ -709,7 +709,27 @@ dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
view->dstport = dstport;
}
void
dns_view_freeze(dns_view_t *view) {
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(!view->frozen);
if (view->resolver != NULL) {
INSIST(view->cachedb != NULL);
dns_resolver_freeze(view->resolver);
}
view->frozen = ISC_TRUE;
}
#ifdef BIND9
void
dns_view_thaw(dns_view_t *view) {
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(view->frozen);
view->frozen = ISC_FALSE;
}
isc_result_t
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
isc_result_t result;
@ -723,18 +743,6 @@ dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
}
#endif
void
dns_view_freeze(dns_view_t *view) {
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(!view->frozen);
if (view->resolver != NULL) {
INSIST(view->cachedb != NULL);
dns_resolver_freeze(view->resolver);
}
view->frozen = ISC_TRUE;
}
#ifdef BIND9
isc_result_t
dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: namedconf.h,v 1.15 2009/07/31 23:43:23 each Exp $ */
/* $Id: namedconf.h,v 1.16 2010/07/11 00:12:57 each Exp $ */
#ifndef ISCCFG_NAMEDCONF_H
#define ISCCFG_NAMEDCONF_H 1
@ -36,6 +36,9 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_namedconf;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_bindkeys;
/*%< A bind.keys file. */
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_addzoneconf;
/*%< A single zone passed via the addzone rndc command. */
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_rndcconf;
/*%< A complete rndc.conf file. */

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: namedconf.c,v 1.119 2010/06/25 03:24:05 marka Exp $ */
/* $Id: namedconf.c,v 1.120 2010/07/11 00:12:57 each Exp $ */
/*! \file */
@ -101,6 +101,7 @@ 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_qstring;
static cfg_type_t cfg_type_optional_facility;
static cfg_type_t cfg_type_optional_keyref;
static cfg_type_t cfg_type_optional_port;
@ -888,6 +889,7 @@ options_clauses[] = {
{ "use-ixfr", &cfg_type_boolean, 0 },
{ "version", &cfg_type_qstringornone, 0 },
{ "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
{ "new-zone-file", &cfg_type_qstringornone, 0 },
{ NULL, NULL, 0 }
};
@ -1057,6 +1059,7 @@ view_clauses[] = {
{ "transfer-format", &cfg_type_transferformat, 0 },
{ "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
{ "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
{ "new-zone-file", &cfg_type_qstringornone, 0 },
#ifdef ALLOW_FILTER_AAAA_ON_V4
{ "filter-aaaa", &cfg_type_bracketed_aml, 0 },
{ "filter-aaaa-on-v4", &cfg_type_v4_aaaa, 0 },
@ -1396,6 +1399,42 @@ static cfg_type_t cfg_type_logging = {
"logging", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, logging_clausesets };
/*%
* For parsing an 'addzone' statement
*/
/*%
* A zone statement.
*/
static cfg_tuplefielddef_t addzone_fields[] = {
{ "filepart", &cfg_type_optional_qstring, 0 },
{ "name", &cfg_type_astring, 0 },
{ "class", &cfg_type_optional_class, 0 },
{ "view", &cfg_type_optional_class, 0 },
{ "options", &cfg_type_zoneopts, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_addzone = {
"addzone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, addzone_fields };
static cfg_clausedef_t
addzoneconf_clauses[] = {
{ "addzone", &cfg_type_addzone, 0 },
{ NULL, NULL, 0 }
};
static cfg_clausedef_t *
addzoneconf_clausesets[] = {
addzoneconf_clauses,
NULL
};
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_addzoneconf = {
"addzoneconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
&cfg_rep_map, addzoneconf_clausesets
};
static isc_result_t
parse_unitstring(char *str, isc_resourcevalue_t *valuep) {
char *endp;
@ -1798,6 +1837,30 @@ static cfg_type_t cfg_type_optional_class = {
NULL, NULL
};
/*%
* An optional string, distinguished by being in quotes
*/
static isc_result_t
parse_optional_qstr(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
isc_result_t result;
UNUSED(type);
CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
if (pctx->token.type == isc_tokentype_qstring)
CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, ret));
else
CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
cleanup:
return (result);
}
static cfg_type_t cfg_type_optional_qstring = {
"optional_quoted_string", parse_optional_qstr, NULL, cfg_doc_terminal,
NULL, NULL
};
static isc_result_t
parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
isc_result_t result;