summaryrefslogtreecommitdiff
path: root/bin/named/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/named/server.c')
-rw-r--r--bin/named/server.c552
1 files changed, 423 insertions, 129 deletions
diff --git a/bin/named/server.c b/bin/named/server.c
index 05c68b992ec4..bc1e76e951e6 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -74,11 +74,13 @@
#include <dns/portlist.h>
#include <dns/rbt.h>
#include <dns/rdataclass.h>
+#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatastruct.h>
#include <dns/resolver.h>
#include <dns/rootns.h>
#include <dns/secalg.h>
+#include <dns/soa.h>
#include <dns/stats.h>
#include <dns/tkey.h>
#include <dns/tsig.h>
@@ -370,6 +372,12 @@ end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
static void
newzone_cfgctx_destroy(void **cfgp);
+static isc_result_t
+putstr(isc_buffer_t *b, const char *str);
+
+isc_result_t
+add_comment(FILE *fp, const char *viewname);
+
/*%
* Configure a single view ACL at '*aclp'. Get its configuration from
* 'vconfig' (for per-view configuration) and maybe from 'config'
@@ -1302,26 +1310,22 @@ on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
return (ISC_FALSE);
}
-static void
-check_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv,
+static isc_result_t
+check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
isc_mem_t *mctx)
{
char **argv = NULL;
unsigned int i;
- isc_result_t result;
+ isc_result_t result = ISC_R_SUCCESS;
- result = dns_zone_getdbtype(*zonep, &argv, mctx);
- if (result != ISC_R_SUCCESS) {
- dns_zone_detach(zonep);
- return;
- }
+ CHECK(dns_zone_getdbtype(zone, &argv, mctx));
/*
* Check that all the arguments match.
*/
for (i = 0; i < dbtypec; i++)
if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
- dns_zone_detach(zonep);
+ CHECK(ISC_R_FAILURE);
break;
}
@@ -1329,8 +1333,11 @@ check_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv,
* Check that there are not extra arguments.
*/
if (i == dbtypec && argv[i] != NULL)
- dns_zone_detach(zonep);
+ result = ISC_R_FAILURE;
+
+ cleanup:
isc_mem_free(mctx, argv);
+ return (result);
}
static isc_result_t
@@ -1623,6 +1630,235 @@ configure_rpz(dns_view_t *view, const cfg_listelt_t *element,
return (ISC_R_SUCCESS);
}
+static isc_result_t
+add_soa(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+ dns_name_t *origin, dns_name_t *contact)
+{
+ dns_dbnode_t *node = NULL;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdatalist_t rdatalist;
+ dns_rdataset_t rdataset;
+ isc_result_t result;
+ unsigned char buf[DNS_SOA_BUFFERSIZE];
+
+ dns_rdataset_init(&rdataset);
+ dns_rdatalist_init(&rdatalist);
+ CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db),
+ 0, 28800, 7200, 604800, 86400, buf, &rdata));
+ rdatalist.type = rdata.type;
+ rdatalist.covers = 0;
+ rdatalist.rdclass = rdata.rdclass;
+ rdatalist.ttl = 86400;
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
+ CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
+ CHECK(dns_db_findnode(db, name, ISC_TRUE, &node));
+ CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
+ cleanup:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+static isc_result_t
+add_ns(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+ dns_name_t *nsname)
+{
+ dns_dbnode_t *node = NULL;
+ dns_rdata_ns_t ns;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdatalist_t rdatalist;
+ dns_rdataset_t rdataset;
+ isc_result_t result;
+ isc_buffer_t b;
+ unsigned char buf[DNS_NAME_MAXWIRE];
+
+ isc_buffer_init(&b, buf, sizeof(buf));
+
+ dns_rdataset_init(&rdataset);
+ dns_rdatalist_init(&rdatalist);
+ ns.common.rdtype = dns_rdatatype_ns;
+ ns.common.rdclass = dns_db_class(db);
+ ns.mctx = NULL;
+ dns_name_init(&ns.name, NULL);
+ dns_name_clone(nsname, &ns.name);
+ CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
+ &ns, &b));
+ rdatalist.type = rdata.type;
+ rdatalist.covers = 0;
+ rdatalist.rdclass = rdata.rdclass;
+ rdatalist.ttl = 86400;
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
+ CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
+ CHECK(dns_db_findnode(db, name, ISC_TRUE, &node));
+ CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
+ cleanup:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+static isc_result_t
+create_empty_zone(dns_zone_t *zone, dns_name_t *name, dns_view_t *view,
+ const cfg_obj_t *zonelist, const char **empty_dbtype,
+ int empty_dbtypec, isc_boolean_t zonestats_on)
+{
+ char namebuf[DNS_NAME_FORMATSIZE];
+ const cfg_listelt_t *element;
+ const cfg_obj_t *obj;
+ const cfg_obj_t *zconfig;
+ const cfg_obj_t *zoptions;
+ const char *rbt_dbtype[4] = { "rbt" };
+ const char *sep = ": view ";
+ const char *str;
+ const char *viewname = view->name;
+ dns_db_t *db = NULL;
+ dns_dbversion_t *version = NULL;
+ dns_fixedname_t cfixed;
+ dns_fixedname_t fixed;
+ dns_fixedname_t nsfixed;
+ dns_name_t *contact;
+ dns_name_t *ns;
+ dns_name_t *zname;
+ dns_zone_t *myzone = NULL;
+ int rbt_dbtypec = 1;
+ isc_result_t result;
+ dns_namereln_t namereln;
+ int order;
+ unsigned int nlabels;
+
+ dns_fixedname_init(&fixed);
+ zname = dns_fixedname_name(&fixed);
+ dns_fixedname_init(&nsfixed);
+ ns = dns_fixedname_name(&nsfixed);
+ dns_fixedname_init(&cfixed);
+ contact = dns_fixedname_name(&cfixed);
+
+ /*
+ * Look for forward "zones" beneath this empty zone and if so
+ * create a custom db for the empty zone.
+ */
+ for (element = cfg_list_first(zonelist);
+ element != NULL;
+ element = cfg_list_next(element)) {
+
+ zconfig = cfg_listelt_value(element);
+ str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
+ CHECK(dns_name_fromstring(zname, str, 0, NULL));
+ namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
+ if (namereln != dns_namereln_subdomain)
+ continue;
+
+ zoptions = cfg_tuple_get(zconfig, "options");
+
+ obj = NULL;
+ (void)cfg_map_get(zoptions, "type", &obj);
+ INSIST(obj != NULL);
+ if (strcasecmp(cfg_obj_asstring(obj), "forward") == 0) {
+ obj = NULL;
+ (void)cfg_map_get(zoptions, "forward", &obj);
+ if (obj == NULL)
+ continue;
+ if (strcasecmp(cfg_obj_asstring(obj), "only") != 0)
+ continue;
+ }
+ if (db == NULL) {
+ CHECK(dns_db_create(view->mctx, "rbt", name,
+ dns_dbtype_zone, view->rdclass,
+ 0, NULL, &db));
+ CHECK(dns_db_newversion(db, &version));
+ if (strcmp(empty_dbtype[2], "@") == 0)
+ dns_name_clone(name, ns);
+ else
+ CHECK(dns_name_fromstring(ns, empty_dbtype[2],
+ 0, NULL));
+ CHECK(dns_name_fromstring(contact, empty_dbtype[3],
+ 0, NULL));
+ CHECK(add_soa(db, version, name, ns, contact));
+ CHECK(add_ns(db, version, name, ns));
+ }
+ CHECK(add_ns(db, version, zname, dns_rootname));
+ }
+
+ /*
+ * Is the existing zone the ok to use?
+ */
+ if (zone != NULL) {
+ unsigned int typec;
+ const char **dbargv;
+
+ if (db != NULL) {
+ typec = rbt_dbtypec;
+ dbargv = rbt_dbtype;
+ } else {
+ typec = empty_dbtypec;
+ dbargv = empty_dbtype;
+ }
+
+ result = check_dbtype(zone, typec, dbargv, view->mctx);
+ if (result != ISC_R_SUCCESS)
+ zone = NULL;
+
+ if (zone != NULL && dns_zone_gettype(zone) != dns_zone_master)
+ zone = NULL;
+ if (zone != NULL && dns_zone_getfile(zone) != NULL)
+ zone = NULL;
+ }
+
+ if (zone == NULL) {
+ CHECK(dns_zone_create(&myzone, view->mctx));
+ zone = myzone;
+ CHECK(dns_zone_setorigin(zone, name));
+ CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
+ if (db == NULL)
+ CHECK(dns_zone_setdbtype(zone, empty_dbtypec,
+ empty_dbtype));
+ dns_zone_setclass(zone, view->rdclass);
+ dns_zone_settype(zone, dns_zone_master);
+ dns_zone_setstats(zone, ns_g_server->zonestats);
+ }
+
+ dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, ISC_FALSE);
+ dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
+ dns_zone_setnotifytype(zone, dns_notifytype_no);
+ dns_zone_setdialup(zone, dns_dialuptype_no);
+ if (view->queryacl)
+ dns_zone_setqueryacl(zone, view->queryacl);
+ else
+ dns_zone_clearqueryacl(zone);
+ if (view->queryonacl)
+ dns_zone_setqueryonacl(zone, view->queryonacl);
+ else
+ dns_zone_clearqueryonacl(zone);
+ dns_zone_clearupdateacl(zone);
+ dns_zone_clearxfracl(zone);
+
+ CHECK(setquerystats(zone, view->mctx, zonestats_on));
+ if (db != NULL) {
+ dns_db_closeversion(db, &version, ISC_TRUE);
+ CHECK(dns_zone_replacedb(zone, db, ISC_FALSE));
+ }
+ dns_zone_setview(zone, view);
+ CHECK(dns_view_addzone(view, zone));
+
+ if (!strcmp(viewname, "_default")) {
+ sep = "";
+ viewname = "";
+ }
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+ ISC_LOG_INFO, "automatic empty zone%s%s: %s",
+ sep, viewname, namebuf);
+
+ cleanup:
+ if (myzone != NULL)
+ dns_zone_detach(&myzone);
+ if (version != NULL)
+ dns_db_closeversion(db, &version, ISC_FALSE);
+ if (db != NULL)
+ dns_db_detach(&db);
+ return (result);
+}
+
/*
* Configure 'view' according to 'vconfig', taking defaults from 'config'
* where values are missing in 'vconfig'.
@@ -1676,7 +1912,6 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
isc_uint32_t max_clients_per_query;
const char *sep = ": view ";
const char *viewname = view->name;
- const char *forview = " for view ";
isc_boolean_t rfc1918;
isc_boolean_t empty_zones_enable;
const cfg_obj_t *disablelist = NULL;
@@ -1722,8 +1957,6 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
if (!strcmp(viewname, "_default")) {
sep = "";
viewname = "";
- forview = "";
- POST(forview);
}
/*
@@ -2980,44 +3213,13 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
if (pview != NULL) {
(void)dns_view_findzone(pview, name, &zone);
dns_view_detach(&pview);
- if (zone != NULL)
- check_dbtype(&zone, empty_dbtypec,
- empty_dbtype, mctx);
- if (zone != NULL) {
- dns_zone_setview(zone, view);
- CHECK(dns_view_addzone(view, zone));
- CHECK(setquerystats(zone, mctx,
- zonestats_on));
- dns_zone_detach(&zone);
- continue;
- }
}
- CHECK(dns_zone_create(&zone, mctx));
- CHECK(dns_zone_setorigin(zone, name));
- dns_zone_setview(zone, view);
- CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr,
- zone));
- dns_zone_setclass(zone, view->rdclass);
- dns_zone_settype(zone, dns_zone_master);
- dns_zone_setstats(zone, ns_g_server->zonestats);
- CHECK(dns_zone_setdbtype(zone, empty_dbtypec,
- empty_dbtype));
- if (view->queryacl != NULL)
- dns_zone_setqueryacl(zone, view->queryacl);
- if (view->queryonacl != NULL)
- dns_zone_setqueryonacl(zone, view->queryonacl);
- dns_zone_setdialup(zone, dns_dialuptype_no);
- dns_zone_setnotifytype(zone, dns_notifytype_no);
- dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS,
- ISC_TRUE);
- CHECK(setquerystats(zone, mctx, zonestats_on));
- CHECK(dns_view_addzone(view, zone));
- isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
- NS_LOGMODULE_SERVER, ISC_LOG_INFO,
- "automatic empty zone%s%s: %s",
- sep, viewname, empty);
- dns_zone_detach(&zone);
+ CHECK(create_empty_zone(zone, name, view, zonelist,
+ empty_dbtype, empty_dbtypec,
+ zonestats_on));
+ if (zone != NULL)
+ dns_zone_detach(&zone);
}
}
@@ -4437,7 +4639,10 @@ load_configuration(const char *filename, ns_server_t *server,
dns_viewlist_t viewlist, builtin_viewlist;
in_port_t listen_port, udpport_low, udpport_high;
int i;
+ int num_zones = 0;
+ isc_boolean_t exclusive = ISC_FALSE;
isc_interval_t interval;
+ isc_logconfig_t *logc = NULL;
isc_portset_t *v4portset = NULL;
isc_portset_t *v6portset = NULL;
isc_resourcevalue_t nfiles;
@@ -4446,12 +4651,10 @@ load_configuration(const char *filename, ns_server_t *server,
isc_uint32_t interface_interval;
isc_uint32_t reserved;
isc_uint32_t udpsize;
- ns_cachelist_t cachelist, tmpcachelist;
- unsigned int maxsocks;
ns_cache_t *nsc;
+ ns_cachelist_t cachelist, tmpcachelist;
struct cfg_context *nzctx;
- int num_zones = 0;
- isc_boolean_t exclusive = ISC_FALSE;
+ unsigned int maxsocks;
ISC_LIST_INIT(viewlist);
ISC_LIST_INIT(builtin_viewlist);
@@ -4739,8 +4942,8 @@ load_configuration(const char *filename, ns_server_t *server,
result = ns_config_get(maps, "tcp-listen-queue", &obj);
INSIST(result == ISC_R_SUCCESS);
ns_g_listen = cfg_obj_asuint32(obj);
- if (ns_g_listen < 3)
- ns_g_listen = 3;
+ if ((ns_g_listen > 0) && (ns_g_listen < 10))
+ ns_g_listen = 10;
/*
* Configure the interface manager according to the "listen-on"
@@ -5112,13 +5315,30 @@ load_configuration(const char *filename, ns_server_t *server,
* unprivileged user, not root.
*/
if (ns_g_logstderr) {
+ const cfg_obj_t *logobj = NULL;
+
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_INFO,
- "ignoring config file logging "
- "statement due to -g option");
+ "not using config file logging "
+ "statement for logging due to "
+ "-g option");
+
+ (void)cfg_map_get(config, "logging", &logobj);
+ if (logobj != NULL) {
+ result = ns_log_configure(NULL, logobj);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(ns_g_lctx,
+ NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_SERVER,
+ ISC_LOG_ERROR,
+ "checking logging configuration "
+ "failed: %s",
+ isc_result_totext(result));
+ goto cleanup;
+ }
+ }
} else {
const cfg_obj_t *logobj = NULL;
- isc_logconfig_t *logc = NULL;
CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
"creating new logging configuration");
@@ -5137,11 +5357,9 @@ load_configuration(const char *filename, ns_server_t *server,
"setting up default 'category default'");
}
- result = isc_logconfig_use(ns_g_lctx, logc);
- if (result != ISC_R_SUCCESS) {
- isc_logconfig_destroy(&logc);
- CHECKM(result, "installing logging configuration");
- }
+ CHECKM(isc_logconfig_use(ns_g_lctx, logc),
+ "installing logging configuration");
+ logc = NULL;
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
@@ -5273,6 +5491,9 @@ load_configuration(const char *filename, ns_server_t *server,
result = ISC_R_SUCCESS;
cleanup:
+ if (logc != NULL)
+ isc_logconfig_destroy(&logc);
+
if (v4portset != NULL)
isc_portset_destroy(ns_g_mctx, &v4portset);
@@ -5971,17 +6192,18 @@ next_token(char **stringp, const char *delim) {
*/
static isc_result_t
zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep,
- const char **zonename)
+ const char **zonename, isc_buffer_t *text)
{
char *input, *ptr;
const char *zonetxt;
char *classtxt;
const char *viewtxt = NULL;
- dns_fixedname_t name;
+ dns_fixedname_t fname;
+ dns_name_t *name;
isc_result_t result;
- isc_buffer_t buf;
dns_view_t *view = NULL;
dns_rdataclass_t rdclass;
+ char problem[DNS_NAME_FORMATSIZE + 500] = "";
REQUIRE(zonep != NULL && *zonep == NULL);
REQUIRE(zonename == NULL || *zonename == NULL);
@@ -6007,38 +6229,40 @@ zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep,
viewtxt = next_token(&input, " \t");
}
- isc_buffer_constinit(&buf, zonetxt, strlen(zonetxt));
- isc_buffer_add(&buf, strlen(zonetxt));
- dns_fixedname_init(&name);
- result = dns_name_fromtext(dns_fixedname_name(&name),
- &buf, dns_rootname, 0, NULL);
- if (result != ISC_R_SUCCESS)
- goto fail1;
+ dns_fixedname_init(&fname);
+ name = dns_fixedname_name(&fname);
+ CHECK(dns_name_fromstring(name, zonetxt, 0, NULL));
if (classtxt != NULL) {
isc_textregion_t r;
r.base = classtxt;
r.length = strlen(classtxt);
- result = dns_rdataclass_fromtext(&rdclass, &r);
- if (result != ISC_R_SUCCESS)
- goto fail1;
+ CHECK(dns_rdataclass_fromtext(&rdclass, &r));
} else
rdclass = dns_rdataclass_in;
if (viewtxt == NULL) {
- result = dns_viewlist_findzone(&server->viewlist,
- dns_fixedname_name(&name),
+ result = dns_viewlist_findzone(&server->viewlist, name,
ISC_TF(classtxt == NULL),
rdclass, zonep);
+ if (result == ISC_R_NOTFOUND)
+ snprintf(problem, sizeof(problem),
+ "no matching zone '%s' in any view",
+ zonetxt);
} else {
result = dns_viewlist_find(&server->viewlist, viewtxt,
rdclass, &view);
- if (result != ISC_R_SUCCESS)
- goto fail1;
+ if (result != ISC_R_SUCCESS) {
+ snprintf(problem, sizeof(problem),
+ "no matching view '%s'", viewtxt);
+ goto report;
+ }
- result = dns_zt_find(view->zonetable, dns_fixedname_name(&name),
- 0, NULL, zonep);
- dns_view_detach(&view);
+ result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
+ if (result != ISC_R_SUCCESS)
+ snprintf(problem, sizeof(problem),
+ "no matching zone '%s' in view '%s'",
+ zonetxt, viewtxt);
}
/* Partial match? */
@@ -6046,7 +6270,20 @@ zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep,
dns_zone_detach(zonep);
if (result == DNS_R_PARTIALMATCH)
result = ISC_R_NOTFOUND;
- fail1:
+ report:
+ if (result != ISC_R_SUCCESS) {
+ isc_result_t tresult;
+
+ tresult = putstr(text, problem);
+ if (tresult == ISC_R_SUCCESS &&
+ isc_buffer_availablelength(text) > 0U)
+ isc_buffer_putuint8(text, 0);
+ }
+
+ cleanup:
+ if (view != NULL)
+ dns_view_detach(&view);
+
return (result);
}
@@ -6054,12 +6291,14 @@ zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep,
* Act on a "retransfer" command from the command channel.
*/
isc_result_t
-ns_server_retransfercommand(ns_server_t *server, char *args) {
+ns_server_retransfercommand(ns_server_t *server, char *args,
+ isc_buffer_t *text)
+{
isc_result_t result;
dns_zone_t *zone = NULL;
dns_zonetype_t type;
- result = zone_from_args(server, args, &zone, NULL);
+ result = zone_from_args(server, args, &zone, NULL, text);
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL)
@@ -6083,7 +6322,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, NULL);
+ result = zone_from_args(server, args, &zone, NULL, text);
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL) {
@@ -6143,7 +6382,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, NULL);
+ result = zone_from_args(server, args, &zone, NULL, text);
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL)
@@ -6168,7 +6407,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, NULL);
+ result = zone_from_args(server, args, &zone, NULL, text);
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL)
@@ -7001,7 +7240,7 @@ ns_server_status(ns_server_t *server, isc_buffer_t *text) {
n = snprintf((char *)isc_buffer_used(text),
isc_buffer_availablelength(text),
- "version: %s%s%s%s\n"
+ "version: %s%s%s%s <id:%s>\n"
#ifdef ISC_PLATFORM_USETHREADS
"CPUs found: %u\n"
"worker threads: %u\n"
@@ -7015,7 +7254,7 @@ ns_server_status(ns_server_t *server, isc_buffer_t *text) {
"recursive clients: %d/%d/%d\n"
"tcp clients: %d/%d\n"
"server is up and running",
- ns_g_version, ob, alt, cb,
+ ns_g_version, ob, alt, cb, ns_g_srcid,
#ifdef ISC_PLATFORM_USETHREADS
ns_g_cpus_detected, ns_g_cpus,
#endif
@@ -7259,7 +7498,7 @@ ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) {
* Act on a "sign" or "loadkeys" command from the command channel.
*/
isc_result_t
-ns_server_rekey(ns_server_t *server, char *args) {
+ns_server_rekey(ns_server_t *server, char *args, isc_buffer_t *text) {
isc_result_t result;
dns_zone_t *zone = NULL;
dns_zonetype_t type;
@@ -7269,7 +7508,7 @@ ns_server_rekey(ns_server_t *server, char *args) {
if (strncasecmp(args, NS_COMMAND_SIGN, strlen(NS_COMMAND_SIGN)) == 0)
fullsign = ISC_TRUE;
- result = zone_from_args(server, args, &zone, NULL);
+ result = zone_from_args(server, args, &zone, NULL, text);
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL)
@@ -7313,7 +7552,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, NULL);
+ result = zone_from_args(server, args, &zone, NULL, text);
if (result != ISC_R_SUCCESS)
return (result);
if (zone == NULL) {
@@ -7433,6 +7672,23 @@ ns_smf_add_message(isc_buffer_t *text) {
#endif /* HAVE_LIBSCF */
/*
+ * Emit a comment at the top of the nzf file containing the viewname
+ * Expects the fp to already be open for writing
+ */
+#define HEADER1 "# New zone file for view: "
+#define HEADER2 "\n# This file contains configuration for zones added by\n" \
+ "# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
+isc_result_t
+add_comment(FILE *fp, const char *viewname) {
+ isc_result_t result;
+ CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
+ CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
+ CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
+ cleanup:
+ return (result);
+}
+
+/*
* Act on an "addzone" command from the command channel.
*/
isc_result_t
@@ -7453,15 +7709,18 @@ ns_server_add_zone(ns_server_t *server, char *args) {
const char *viewname = NULL;
dns_rdataclass_t rdclass;
dns_view_t *view = 0;
- isc_buffer_t buf, *nbuf = NULL;
- dns_name_t dnsname;
+ isc_buffer_t buf;
+ dns_fixedname_t fname;
+ dns_name_t *dnsname;
dns_zone_t *zone = NULL;
FILE *fp = NULL;
struct cfg_context *cfg = NULL;
+ char namebuf[DNS_NAME_FORMATSIZE];
+ off_t offset;
/* Try to parse the argument string */
arglen = strlen(args);
- isc_buffer_init(&argbuf, args, arglen);
+ isc_buffer_init(&argbuf, args, (unsigned int)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,
@@ -7471,10 +7730,10 @@ ns_server_add_zone(ns_server_t *server, char *args) {
zonename = cfg_obj_asstring(cfg_tuple_get(parms, "name"));
isc_buffer_constinit(&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));
+
+ dns_fixedname_init(&fname);
+ dnsname = dns_fixedname_name(&fname);
+ CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, ISC_FALSE, NULL));
/* Make sense of optional class argument */
obj = cfg_tuple_get(parms, "class");
@@ -7503,7 +7762,7 @@ ns_server_add_zone(ns_server_t *server, char *args) {
}
/* Zone shouldn't already exist */
- result = dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone);
+ result = dns_zt_find(view->zonetable, dnsname, 0, NULL, &zone);
if (result == ISC_R_SUCCESS) {
result = ISC_R_EXISTS;
goto cleanup;
@@ -7531,6 +7790,9 @@ ns_server_add_zone(ns_server_t *server, char *args) {
/* Open save file for write configuration */
CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
+ CHECK(isc_stdio_tell(fp, &offset));
+ if (offset == 0)
+ CHECK(add_comment(fp, view->name));
/* Mark view unfrozen so that zone can be added */
result = isc_task_beginexclusive(server->task);
@@ -7544,7 +7806,7 @@ ns_server_add_zone(ns_server_t *server, char *args) {
goto cleanup;
/* Is it there yet? */
- CHECK(dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone));
+ CHECK(dns_zt_find(view->zonetable, dnsname, 0, NULL, &zone));
/*
* Load the zone from the master file. If this fails, we'll
@@ -7572,10 +7834,13 @@ ns_server_add_zone(ns_server_t *server, char *args) {
/* Flag the zone as having been added at runtime */
dns_zone_setadded(zone, ISC_TRUE);
- /* Emit just the zone name from args */
- CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
- CHECK(isc_stdio_write(zonename, strlen(zonename), 1, fp, NULL));
- CHECK(isc_stdio_write(" ", 1, 1, fp, NULL));
+ /* Emit the zone name, quoted and escaped */
+ isc_buffer_init(&buf, namebuf, sizeof(namebuf));
+ CHECK(dns_name_totext(dnsname, ISC_TRUE, &buf));
+ isc_buffer_putuint8(&buf, 0);
+ CHECK(isc_stdio_write("zone \"", 6, 1, fp, NULL));
+ CHECK(isc_stdio_write(namebuf, strlen(namebuf), 1, fp, NULL));
+ CHECK(isc_stdio_write("\" ", 2, 1, fp, NULL));
/* Classname, if not default */
if (classname != NULL && *classname != '\0') {
@@ -7619,8 +7884,6 @@ ns_server_add_zone(ns_server_t *server, char *args) {
dns_zone_detach(&zone);
if (view != NULL)
dns_view_detach(&view);
- if (nbuf != NULL)
- isc_buffer_free(&nbuf);
return (result);
}
@@ -7629,20 +7892,21 @@ ns_server_add_zone(ns_server_t *server, char *args) {
* 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;
- dns_db_t *dbp = NULL;
- const char *filename = NULL;
- char *tmpname = NULL;
- char buf[1024];
- const char *zonename = NULL;
- size_t znamelen = 0;
- FILE *ifp = NULL, *ofp = NULL;
+ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t *text) {
+ isc_result_t result;
+ dns_zone_t *zone = NULL;
+ dns_view_t *view = NULL;
+ dns_db_t *dbp = NULL;
+ const char *filename = NULL;
+ char *tmpname = NULL;
+ char buf[1024];
+ const char *zonename = NULL;
+ size_t znamelen = 0;
+ FILE *ifp = NULL, *ofp = NULL;
+ isc_boolean_t inheader = ISC_TRUE;
/* Parse parameters */
- CHECK(zone_from_args(server, args, &zone, &zonename));
+ CHECK(zone_from_args(server, args, &zone, &zonename, text));
if (zone == NULL) {
result = ISC_R_UNEXPECTEDEND;
@@ -7684,28 +7948,44 @@ ns_server_del_zone(ns_server_t *server, char *args) {
goto cleanup;
}
CHECK(isc_stdio_open(tmpname, "w", &ofp));
+ CHECK(add_comment(ofp, view->name));
/* Look for the entry for that zone */
while (fgets(buf, 1024, ifp)) {
- /* A 'zone' line */
- if (strncasecmp(buf, "zone", 4)) {
+ /* Skip initial comment, if any */
+ if (inheader && *buf == '#')
+ continue;
+ if (*buf != '#')
+ inheader = ISC_FALSE;
+
+ /*
+ * Any other lines not starting with zone, copy
+ * them out and continue.
+ */
+ if (strncasecmp(buf, "zone", 4) != 0) {
fputs(buf, ofp);
continue;
}
p = buf+4;
- /* Locate a name */
+ /* This is a zone; find its name. */
while (*p &&
((*p == '"') || isspace((unsigned char)*p)))
p++;
- /* Is that the zone we're looking for */
- if (strncasecmp(p, zonename, znamelen)) {
+ /*
+ * If it's not the zone we're looking for, copy
+ * it out and continue
+ */
+ if (strncasecmp(p, zonename, znamelen) != 0) {
fputs(buf, ofp);
continue;
}
- /* And nothing else? */
+ /*
+ * But if it is the zone we want, skip over it
+ * so it will be omitted from the new file
+ */
p += znamelen;
if (isspace((unsigned char)*p) ||
*p == '"' || *p == '{') {
@@ -7714,7 +7994,7 @@ ns_server_del_zone(ns_server_t *server, char *args) {
break;
}
- /* Spit it out, keep looking */
+ /* Copy the rest of the buffer out and continue */
fputs(buf, ofp);
}
@@ -7809,3 +8089,17 @@ newzone_cfgctx_destroy(void **cfgp) {
isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
*cfgp = NULL;
}
+
+static isc_result_t
+putstr(isc_buffer_t *b, const char *str) {
+ size_t l = strlen(str);
+
+ /*
+ * Use >= to leave space for NUL termination.
+ */
+ if (l >= isc_buffer_availablelength(b))
+ return (ISC_R_NOSPACE);
+
+ isc_buffer_putmem(b, (const unsigned char *)str, l);
+ return (ISC_R_SUCCESS);
+}