+4610. [func] The "new-zones-directory" option specifies the
+ location of NZF or NZD files for storing
+ configuration of zones added by "rndc addzone".
+ Thanks to Petr Menšík. [RT #44853]
+
4609. [cleanup] Rearrange makefiles to enable parallel execution
(i.e. "make -j"). [RT #45078]
/*
* Configure built-in zone for storing managed-key data.
*/
-
static isc_result_t
add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
isc_result_t result;
const cfg_obj_t *maps[4];
const cfg_obj_t *options = NULL, *voptions = NULL;
const cfg_obj_t *nz = NULL;
+ const cfg_obj_t *nzdir = NULL;
+ const char *dir = NULL;
int i = 0;
REQUIRE (config != NULL);
result = ns_config_get(maps, "allow-new-zones", &nz);
if (result == ISC_R_SUCCESS)
allow = cfg_obj_asboolean(nz);
+ result = ns_config_get(maps, "new-zones-directory", &nzdir);
+ if (result == ISC_R_SUCCESS) {
+ dir = cfg_obj_asstring(nzdir);
+ if (dir != NULL) {
+ result = isc_file_isdirectory(dir);
+ }
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
+ NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "invalid new-zones-directory %s: %s",
+ dir, isc_result_totext(result));
+ return (result);
+ }
+
+ dns_view_setnewzonedir(view, dir);
+ }
/*
* A non-empty catalog-zones statement implies allow-new-zones
memset(nzcfg, 0, sizeof(*nzcfg));
- result = dns_view_setnewzones(view, allow, nzcfg,
+ result = dns_view_setnewzones(view, ISC_TRUE, nzcfg,
newzone_cfgctx_destroy);
if (result != ISC_R_SUCCESS) {
isc_mem_free(view->mctx, nzcfg);
char tmp[1024];
isc_result_t result;
- result = isc_file_template("", "nzf-XXXXXXXX", tmp, sizeof(tmp));
+ result = isc_file_template(view->new_zone_file, "nzf-XXXXXXXX",
+ tmp, sizeof(tmp));
if (result == ISC_R_SUCCESS)
result = isc_file_openunique(tmp, &fp);
if (result != ISC_R_SUCCESS)
</para>
<para>
The configuration is saved in a file called
- <filename><replaceable>name</replaceable>.nzf</filename>,
- where <replaceable>name</replaceable> is the
- name of the view, or if it contains characters
- that are incompatible with use as a file name, a
- cryptographic hash generated from the name
- of the view.
+ <filename><replaceable>viewname</replaceable>.nzf</filename>
+ (or, if <command>named</command> is compiled with
+ liblmdb, an LMDB database file called
+ <filename><replaceable>viewname</replaceable>.nzd</filename>).
+ <replaceable>viewname</replaceable> is the
+ name of the view, unless the view name contains characters
+ that are incompatible with use as a file name, in which case
+ a cryptographic hash of the view name is used instead.
When <command>named</command> is
restarted, the file will be loaded into the view
configuration, so that zones that were added
rm -f zonestatus.out*
rm -f ns2/named.conf
rm -f */named.memstats
-rm -f ns1/*.nzf
-rm -f ns1/*.nzf~
+rm -f ns1/*.nzf ns1/*.nzf~
rm -f ns1/*.nzd ns1/*.nzd-lock
-rm -f ns2/*.nzf
-rm -f ns2/*.nzf~
+rm -f ns2/*.nzf ns2/*.nzf~
rm -f ns2/*.nzd ns2/*.nzd-lock
+rm -f ns3/*.nzf ns3/*.nzf~
+rm -f ns3/*.nzd ns3/*.nzd-lock
rm -f ns2/core*
rm -f ns2/inline.db.jbk
rm -f ns2/inline.db.signed
rm -f ns2/inlineslave.bk*
+rm -rf ns2/new-zones
rm -f ns*/named.lock
rm -f ns*/named.run
rm -f ns2/nzf-*
rm -f ns2/redirect.db
rm -f ns2/redirect.bk
rm -f ns3/redirect.db
+
--- /dev/null
+/*
+ * Copyright (C) 2010, 2011, 2016 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+controls { /* empty */ };
+
+include "../../common/controls.conf";
+
+options {
+ port 5300;
+ pid-file "named.pid";
+ listen-on { 10.53.0.2; 10.53.0.4; 10.53.0.5; };
+ listen-on-v6 { none; };
+ recursion no;
+ new-zones-directory "new-zones";
+};
+
+view internal {
+ match-clients { 10.53.0.2; };
+ allow-new-zones no;
+ recursion yes;
+
+ response-policy { zone "policy"; };
+
+ zone "." {
+ type hint;
+ file "../../common/root.hint";
+ };
+
+ zone "policy" {
+ type master;
+ file "normal.db";
+ };
+};
+
+view directory {
+ match-clients { 10.53.0.5; };
+ allow-new-zones yes;
+
+ zone "." {
+ type hint;
+ file "../../common/root.hint";
+ };
+};
+
+view external {
+ match-clients { any; };
+ allow-new-zones yes;
+
+ zone "." {
+ type hint;
+ file "../../common/root.hint";
+ };
+};
+
+# This view is only here to test that configuration context is cleaned
+# up correctly when using multiple named ACLs (regression test for RT #22739)
+acl match { none; };
+acl nobody { none; };
+view extra {
+ match-clients { match; };
+ allow-new-zones yes;
+ allow-transfer { nobody; };
+ allow-query { nobody; };
+ allow-recursion { nobody; };
+};
cp -f ns3/redirect.db.1 ns3/redirect.db
cp -f ns2/named1.conf ns2/named.conf
cp -f ns2/default.nzf.in ns2/3bf305731dd26307.nzf
+mkdir ns2/new-zones
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
+echo "I:adding new zone again to external view ($n)"
+ret=0
+$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 addzone 'added.example in external { type master; file "added.db"; };' 2>&1 | sed 's/^/I:ns2 /'
+$DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.added.example a > dig.out.ns2.int.$n || ret=1
+grep 'status: NOERROR' dig.out.ns2.int.$n > /dev/null || ret=1
+$DIG +norec $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a > dig.out.ns2.ext.$n || ret=1
+grep 'status: NOERROR' dig.out.ns2.ext.$n > /dev/null || ret=1
+grep '^a.added.example' dig.out.ns2.ext.$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:reconfiguring server with multiple views and new-zones-directory"
+rm -f ns2/named.conf
+cp -f ns2/named3.conf ns2/named.conf
+$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reconfig 2>&1 | sed 's/^/I:ns2 /'
+sleep 5
+
+echo "I:checking new zone is still loaded after dir change ($n)"
+ret=0
+$DIG +norec $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a > dig.out.ns2.ext.$n || ret=1
+grep 'status: NOERROR' dig.out.ns2.ext.$n > /dev/null || ret=1
+grep '^a.added.example' dig.out.ns2.ext.$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:deleting newly added zone from external ($n)"
+ret=0
+$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 delzone 'added.example in external' 2>&1 | sed 's/^/I:ns2 /'
+$DIG $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a > dig.out.ns2.$n || ret=1
+grep 'status: REFUSED' dig.out.ns2.$n > /dev/null || ret=1
+grep '^a.added.example' dig.out.ns2.$n > /dev/null && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:adding new zone to directory view ($n)"
+ret=0
+$DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.added.example a > dig.out.ns2.intpre.$n || ret=1
+grep 'status: NOERROR' dig.out.ns2.intpre.$n > /dev/null || ret=1
+$DIG +norec $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a > dig.out.ns2.extpre.$n || ret=1
+grep 'status: REFUSED' dig.out.ns2.extpre.$n > /dev/null || ret=1
+$DIG +norec $DIGOPTS @10.53.0.5 -b 10.53.0.5 a.added.example a > dig.out.ns2.dirpre.$n || ret=1
+grep 'status: REFUSED' dig.out.ns2.dirpre.$n > /dev/null || ret=1
+$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 addzone 'added.example in directory { type master; file "added.db"; };' 2>&1 | sed 's/^/I:ns2 /'
+$DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.added.example a > dig.out.ns2.int.$n || ret=1
+grep 'status: NOERROR' dig.out.ns2.int.$n > /dev/null || ret=1
+$DIG +norec $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a > dig.out.ns2.ext.$n || ret=1
+grep 'status: REFUSED' dig.out.ns2.ext.$n > /dev/null || ret=1
+$DIG +norec $DIGOPTS @10.53.0.5 -b 10.53.0.5 a.added.example a > dig.out.ns2.dir.$n || ret=1
+grep 'status: NOERROR' dig.out.ns2.dir.$n > /dev/null || ret=1
+grep '^a.added.example' dig.out.ns2.dir.$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+if [ -n "$NZD" ]; then
+ echo "I:checking NZD file was created in new-zones-directory ($n)"
+ expect=ns2/new-zones/directory.nzd
+else
+ echo "I:checking NZF file was created in new-zones-directory ($n)"
+ expect=ns2/new-zones/directory.nzf
+fi
+$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 sync 'added.example IN directory' 2>&1 | sed 's/^/I:ns2 /'
+sleep 2
+[ -e "$expect" ] || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:deleting newly added zone from directory ($n)"
+ret=0
+$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 delzone 'added.example in directory' 2>&1 | sed 's/^/I:ns2 /'
+$DIG $DIGOPTS @10.53.0.5 -b 10.53.0.5 a.added.example a > dig.out.ns2.$n || ret=1
+grep 'status: REFUSED' dig.out.ns2.$n > /dev/null || ret=1
+grep '^a.added.example' dig.out.ns2.$n > /dev/null && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
echo "I:ensure the configuration context is cleaned up correctly ($n)"
ret=0
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reconfig > /dev/null 2>&1 || ret=1
[ <command>geoip-directory</command> <replaceable>path_name</replaceable> ; ]
[ <command>key-directory</command> <replaceable>path_name</replaceable> ; ]
[ <command>managed-keys-directory</command> <replaceable>path_name</replaceable> ; ]
+ [ <command>new-zones-directory</command> <replaceable>path_name</replaceable> ; ]
[ <command>named-xfer</command> <replaceable>path_name</replaceable> ; ]
[ <command>tkey-gssapi-keytab</command> <replaceable>path_name</replaceable> ; ]
[ <command>tkey-gssapi-credential</command> <replaceable>principal</replaceable> ; ]
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><command>new-zones-directory</command></term>
+ <listitem>
+ <para>
+ Specifies the directory in which to store the configuration
+ parameters for zones added via <command>rndc addzone</command>.
+ By default, this is the working directory.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><command>named-xfer</command></term>
<listitem>
added at runtime via <command>rndc addzone</command>.
The default is <userinput>no</userinput>.
</para>
+ <para>
+ Newly added zones' configuration parameters
+ are stored so that they can persist after the
+ server is restarted. The configuration information
+ is saved in a file called
+ <filename><replaceable>viewname</replaceable>.nzf</filename>
+ (or, if <command>named</command> is compiled with
+ liblmdb, in an LMDB database file called
+ <filename><replaceable>viewname</replaceable>.nzd</filename>).
+ <replaceable>viewname</replaceable> is the name of the
+ view, unless the view name contains characters that are
+ incompatible with use as a file name, in which case a
+ cryptographic hash of the view name is used instead.
+ </para>
</listitem>
</varlistentry>
<!DOCTYPE book [
<!ENTITY Scaron "Š">
+<!ENTITY scaron "š">
<!ENTITY ccaron "č">
<!ENTITY aacute "á">
+<!ENTITY iacute "í">
<!ENTITY mdash "—">
<!ENTITY ouml "ö">]>
<!--
<section xml:id="relnotes_features"><info><title>New Features</title></info>
<itemizedlist>
+ <listitem>
+ <para>
+ The <command>new-zones-directory</command> option allows
+ <command>named</command> to store configuration parameters
+ for zones added via <command>rndc addzone</command> in a
+ location other than the working directory. Thanks to Petr
+ Menšík of Red Hat for the contribution.
+ [RT #44853]
+ </para>
+ </listitem>
<listitem>
<para>
Many aspects of <command>named</command> have been modified
* XXX: This should be a pointer to an opaque type that
* named implements.
*/
+ char * new_zone_dir;
char * new_zone_file;
- char * new_zone_db;
+ char * new_zone_db;
void * new_zone_dbenv;
void * new_zone_config;
void (*cfg_destroy)(void **);
* \li ISC_R_NOSPACE
*/
+void
+dns_view_setnewzonedir(dns_view_t *view, const char *dir);
+const char *
+dns_view_getnewzonedir(dns_view_t *view);
+/*%<
+ * Set/get the path to the directory in which NZF or NZD files should
+ * be stored. If the path was previously set to a non-NULL value,
+ * the previous value is freed.
+ *
+ * Requires:
+ * \li 'view' is valid.
+ */
+
void
dns_view_restorekeyring(dns_view_t *view);
view->sendcookie = ISC_TRUE;
view->requireservercookie = ISC_FALSE;
view->trust_anchor_telemetry = ISC_TRUE;
+ view->new_zone_dir = NULL;
view->new_zone_file = NULL;
view->new_zone_db = NULL;
view->new_zone_dbenv = NULL;
isc_mem_free(view->mctx, view->new_zone_file);
view->new_zone_file = NULL;
}
+ if (view->new_zone_dir != NULL) {
+ isc_mem_free(view->mctx, view->new_zone_dir);
+ view->new_zone_dir = NULL;
+ }
#ifdef HAVE_LMDB
if (view->new_zone_dbenv != NULL)
mdb_env_close((MDB_env *) view->new_zone_dbenv);
dst_key_free(&key);
}
+/*
+ * Create path to a directory and a filename contructed from viewname.
+ * This is a front-end to isc_file_sanitize(), allowing backward
+ * compatibility to older versions when a file couldn't be expected
+ * to be in the specified directory but might be in the current working
+ * directory instead.
+ *
+ * It first tests for the existence of a file <viewname>.<suffix> in
+ * 'directory'. If the file does not exist, it checks again in the
+ * current working directory. If it does not exist there either,
+ * return the path inside the directory.
+ *
+ * Returns ISC_R_SUCCESS if a path to an existing file is found or
+ * a new path is created; returns ISC_R_NOSPACE if the path won't
+ * fit in 'buflen'.
+ */
+static isc_result_t
+nz_legacy(const char *directory, const char *viewname,
+ const char *suffix, char *buffer, size_t buflen)
+{
+ isc_result_t result;
+ char newbuf[PATH_MAX];
+
+ result = isc_file_sanitize(directory, viewname, suffix,
+ buffer, buflen);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ } else if (directory == NULL || isc_file_exists(buffer)) {
+ return (ISC_R_SUCCESS);
+ } else {
+ /* Save buffer */
+ strlcpy(newbuf, buffer, sizeof(newbuf));
+ }
+
+ /*
+ * It isn't in the specified directory; check CWD.
+ */
+ result = isc_file_sanitize(NULL, viewname, suffix, buffer, buflen);
+ if (result != ISC_R_SUCCESS || isc_file_exists(buffer)) {
+ return (result);
+ }
+
+ /*
+ * File does not exist in either 'directory' or CWD,
+ * so use the path in 'directory'.
+ */
+ strlcpy(buffer, newbuf, buflen);
+ return (ISC_R_SUCCESS);
+}
+
isc_result_t
dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
void (*cfg_destroy)(void **))
view->cfg_destroy = NULL;
}
- if (!allow)
+ if (!allow) {
return (ISC_R_SUCCESS);
+ }
- result = isc_file_sanitize(NULL, view->name, "nzf",
- buffer, sizeof(buffer));
+ result = nz_legacy(view->new_zone_dir, view->name, "nzf",
+ buffer, sizeof(buffer));
if (result != ISC_R_SUCCESS)
goto out;
view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
#ifdef HAVE_LMDB
- result = isc_file_sanitize(NULL, view->name, "nzd",
- buffer, sizeof(buffer));
+ result = nz_legacy(view->new_zone_dir, view->name, "nzd",
+ buffer, sizeof(buffer));
if (result != ISC_R_SUCCESS)
goto out;
view->new_zone_db = isc_mem_strdup(view->mctx, buffer);
return (result);
}
+void
+dns_view_setnewzonedir(dns_view_t *view, const char *dir) {
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ if (view->new_zone_dir != NULL) {
+ isc_mem_free(view->mctx, view->new_zone_dir);
+ view->new_zone_dir = NULL;
+ }
+
+ if (dir == NULL) {
+ return;
+ }
+
+ view->new_zone_dir = isc_mem_strdup(view->mctx, dir);
+}
+
+const char *
+dns_view_getnewzonedir(dns_view_t *view) {
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ return (view->new_zone_dir);
+}
+
isc_result_t
dns_view_searchdlz(dns_view_t *view, const dns_name_t *name,
unsigned int minlabels, dns_clientinfomethods_t *methods,
unlink(F(SHA));
}
+ATF_TC(isc_file_template);
+ATF_TC_HEAD(isc_file_template, tc) {
+ atf_tc_set_md_var(tc, "descr", "file template");
+}
+
+ATF_TC_BODY(isc_file_template, tc) {
+ isc_result_t result;
+ char buf[1024];
+
+ ATF_CHECK(chdir(TESTS) != -1);
+
+ result = isc_file_template("/absolute/path", "file-XXXXXXXX",
+ buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "/absolute/file-XXXXXXXX");
+
+ result = isc_file_template("relative/path", "file-XXXXXXXX",
+ buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "relative/file-XXXXXXXX");
+
+ result = isc_file_template("/trailing/slash/", "file-XXXXXXXX",
+ buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "/trailing/slash/file-XXXXXXXX");
+
+ result = isc_file_template("relative/trailing/slash/", "file-XXXXXXXX",
+ buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "relative/trailing/slash/file-XXXXXXXX");
+
+ result = isc_file_template("/", "file-XXXXXXXX", buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "/file-XXXXXXXX");
+
+ result = isc_file_template("noslash", "file-XXXXXXXX",
+ buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "file-XXXXXXXX");
+
+ result = isc_file_template(NULL, "file-XXXXXXXX", buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "file-XXXXXXXX");
+}
+
/*
* Main
*/
ATF_TP_ADD_TCS(tp) {
ATF_TP_ADD_TC(tp, isc_file_sanitize);
+ ATF_TP_ADD_TC(tp, isc_file_template);
return (atf_no_error());
}
{
const char *s;
- REQUIRE(path != NULL);
REQUIRE(templet != NULL);
REQUIRE(buf != NULL);
+ if (path == NULL)
+ path = "";
+
s = strrchr(templet, '/');
if (s != NULL)
templet = s + 1;
REQUIRE(templet != NULL);
REQUIRE(buf != NULL);
+ if (path == NULL)
+ path = "";
+
s = strrchr(templet, '\\');
if (s != NULL)
templet = s + 1;
{ "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
{ "minimal-any", &cfg_type_boolean, 0 },
{ "minimal-responses", &cfg_type_minimal, 0 },
+ { "new-zones-directory", &cfg_type_qstring, 0 },
{ "nta-recheck", &cfg_type_ttlval, 0 },
{ "nta-lifetime", &cfg_type_ttlval, 0 },
{ "nxdomain-redirect", &cfg_type_astring, 0 },