Commit 888bb8bf authored by Mark Andrews's avatar Mark Andrews

1443. [func] Masters lists can now be specified and referenced

                        in zone masters clauses and other masters lists.
developer: marka
reviewer: explorer
parent b312748a
1443. [func] Masters lists can now be specified and referenced
in zone masters clauses and other masters lists.
1442. [func] New fuctions for manipulating port lists:
dns_portlist_create(), dns_portlist_add(),
dns_portlist_remove(), dns_portlist_match(),
......
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: config.c,v 1.38 2003/02/26 02:03:57 marka Exp $ */
/* $Id: config.c,v 1.39 2003/02/26 06:04:02 marka Exp $ */
#include <config.h>
......@@ -333,12 +333,40 @@ ns_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
*addrsp = NULL;
}
static isc_result_t
get_masters_def(cfg_obj_t *cctx, char *name, cfg_obj_t **ret) {
isc_result_t result;
cfg_obj_t *masters = NULL;
cfg_listelt_t *elt;
result = cfg_map_get(cctx, "masters", &masters);
if (result != ISC_R_SUCCESS)
return (result);
for (elt = cfg_list_first(masters);
elt != NULL;
elt = cfg_list_next(elt)) {
cfg_obj_t *list;
const char *listname;
list = cfg_listelt_value(elt);
listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
if (strcasecmp(listname, name) == 0) {
*ret = list;
return (ISC_R_SUCCESS);
}
}
return (ISC_R_NOTFOUND);
}
isc_result_t
ns_config_getipandkeylist(cfg_obj_t *config, cfg_obj_t *list, isc_mem_t *mctx,
isc_sockaddr_t **addrsp, dns_name_t ***keysp,
isc_uint32_t *countp)
{
isc_uint32_t count, i = 0;
isc_uint32_t addrcount = 0, keycount = 0, i = 0;
isc_uint32_t listcount = 0, l = 0, j;
isc_uint32_t stackcount = 0, pushed = 0;
isc_result_t result;
cfg_listelt_t *element;
cfg_obj_t *addrlist;
......@@ -347,12 +375,18 @@ ns_config_getipandkeylist(cfg_obj_t *config, cfg_obj_t *list, isc_mem_t *mctx,
dns_fixedname_t fname;
isc_sockaddr_t *addrs = NULL;
dns_name_t **keys = NULL;
char **lists = NULL;
struct {
cfg_listelt_t *element;
in_port_t port;
} *stack = NULL;
INSIST(addrsp != NULL && *addrsp == NULL);
REQUIRE(addrsp != NULL && *addrsp == NULL);
REQUIRE(keysp != NULL && *keysp == NULL);
REQUIRE(countp != NULL);
newlist:
addrlist = cfg_tuple_get(list, "addresses");
count = ns_config_listcount(addrlist);
portobj = cfg_tuple_get(list, "port");
if (cfg_obj_isuint32(portobj)) {
isc_uint32_t val = cfg_obj_asuint32(portobj);
......@@ -370,35 +404,126 @@ ns_config_getipandkeylist(cfg_obj_t *config, cfg_obj_t *list, isc_mem_t *mctx,
result = ISC_R_NOMEMORY;
addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t));
if (addrs == NULL)
goto cleanup;
keys = isc_mem_get(mctx, count * sizeof(dns_name_t *));
if (keys == NULL)
goto cleanup;
for (element = cfg_list_first(addrlist);
element = cfg_list_first(addrlist);
resume:
for ( ;
element != NULL;
element = cfg_list_next(element), i++)
element = cfg_list_next(element))
{
cfg_obj_t *addr;
cfg_obj_t *key;
char *keystr;
isc_buffer_t b;
INSIST(i < count);
addr = cfg_tuple_get(cfg_listelt_value(element), "sockaddr");
addr = cfg_tuple_get(cfg_listelt_value(element),
"masterselement");
key = cfg_tuple_get(cfg_listelt_value(element), "key");
if (!cfg_obj_issockaddr(addr)) {
char *listname = cfg_obj_asstring(addr);
isc_result_t tresult;
/* Grow lists? */
if (listcount == l) {
void * new;
isc_uint32_t newlen = listcount + 16;
size_t newsize, oldsize;
newsize = newlen * sizeof(*lists);
oldsize = listcount * sizeof(*lists);
new = isc_mem_get(mctx, newsize);
if (new == NULL)
goto cleanup;
if (listcount != 0) {
memcpy(new, lists, oldsize);
isc_mem_put(mctx, lists, oldsize);
}
lists = new;
listcount = newlen;
}
/* Seen? */
for (j = 0; j < l; j++)
if (strcasecmp(lists[j], listname) == 0)
break;
if (j < l)
continue;
tresult = get_masters_def(config, listname, &list);
if (tresult == ISC_R_NOTFOUND) {
cfg_obj_log(addr, ns_g_lctx, ISC_LOG_ERROR,
"masters \"%s\" not found", listname);
result = tresult;
goto cleanup;
}
if (tresult != ISC_R_SUCCESS)
goto cleanup;
lists[l++] = listname;
/* Grow stack? */
if (stackcount == pushed) {
void * new;
isc_uint32_t newlen = stackcount + 16;
size_t newsize, oldsize;
newsize = newlen * sizeof(*stack);
oldsize = stackcount * sizeof(*stack);
new = isc_mem_get(mctx, newsize);
if (new == NULL)
goto cleanup;
if (stackcount != 0) {
memcpy(new, stack, oldsize);
isc_mem_put(mctx, stack, oldsize);
}
stack = new;
stackcount = newlen;
}
/*
* We want to resume processing this list on the
* next element.
*/
stack[pushed].element = cfg_list_next(element);
stack[pushed].port = port;
pushed++;
goto newlist;
}
if (i == addrcount) {
void * new;
isc_uint32_t newlen = addrcount + 16;
size_t newsize, oldsize;
newsize = newlen * sizeof(isc_sockaddr_t);
oldsize = addrcount * sizeof(isc_sockaddr_t);
new = isc_mem_get(mctx, newsize);
if (new == NULL)
goto cleanup;
if (addrcount != 0) {
memcpy(new, addrs, oldsize);
isc_mem_put(mctx, addrs, oldsize);
}
addrs = new;
addrcount = newlen;
newsize = newlen * sizeof(dns_name_t *);
oldsize = keycount * sizeof(dns_name_t *);
new = isc_mem_get(mctx, newsize);
if (new == NULL)
goto cleanup;
if (keycount != 0) {
memcpy(new, keys, newsize);
isc_mem_put(mctx, keys, newsize);
}
keys = new;
keycount = newlen;
}
addrs[i] = *cfg_obj_assockaddr(addr);
if (isc_sockaddr_getport(&addrs[i]) == 0)
isc_sockaddr_setport(&addrs[i], port);
keys[i] = NULL;
if (!cfg_obj_isstring(key))
if (!cfg_obj_isstring(key)) {
i++;
continue;
}
keys[i] = isc_mem_get(mctx, sizeof(dns_name_t));
if (keys[i] == NULL)
goto cleanup;
......@@ -416,20 +541,62 @@ ns_config_getipandkeylist(cfg_obj_t *config, cfg_obj_t *list, isc_mem_t *mctx,
keys[i]);
if (result != ISC_R_SUCCESS)
goto cleanup;
i++;
}
if (pushed != 0) {
pushed--;
element = stack[pushed].element;
port = stack[pushed].port;
goto resume;
}
if (i < addrcount) {
void * new;
size_t newsize, oldsize;
newsize = i * sizeof(isc_sockaddr_t);
oldsize = addrcount * sizeof(isc_sockaddr_t);
if (i != 0) {
new = isc_mem_get(mctx, newsize);
if (new == NULL)
goto cleanup;
memcpy(new, addrs, newsize);
isc_mem_put(mctx, addrs, oldsize);
} else
new = NULL;
addrs = new;
addrcount = i;
newsize = i * sizeof(dns_name_t *);
oldsize = keycount * sizeof(dns_name_t *);
if (i != 0) {
new = isc_mem_get(mctx, newsize);
if (new == NULL)
goto cleanup;
memcpy(new, keys, newsize);
isc_mem_put(mctx, keys, oldsize);
} else
new = NULL;
keys = new;
keycount = i;
}
INSIST(i == count);
if (lists != NULL)
isc_mem_put(mctx, lists, listcount * sizeof(*lists));
if (stack != NULL)
isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
INSIST(keycount == addrcount);
*addrsp = addrs;
*keysp = keys;
*countp = count;
*countp = addrcount;
return (ISC_R_SUCCESS);
cleanup:
if (addrs != NULL)
isc_mem_put(mctx, addrs, count * sizeof(isc_sockaddr_t));
isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t));
if (keys != NULL) {
unsigned int j;
for (j = 0; j <= i; j++) {
if (keys[j] == NULL)
continue;
......@@ -437,8 +604,12 @@ ns_config_getipandkeylist(cfg_obj_t *config, cfg_obj_t *list, isc_mem_t *mctx,
dns_name_free(keys[j], mctx);
isc_mem_put(mctx, keys[j], sizeof(dns_name_t));
}
isc_mem_put(mctx, keys, count * sizeof(dns_name_t *));
isc_mem_put(mctx, keys, keycount * sizeof(dns_name_t *));
}
if (lists != NULL)
isc_mem_put(mctx, lists, listcount * sizeof(*lists));
if (stack != NULL)
isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
return (result);
}
......
......@@ -2,7 +2,7 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.0//EN"
"http://www.oasis-open.org/docbook/xml/4.0/docbookx.dtd">
<!-- File: $Id: Bv9ARM-book.xml,v 1.216 2003/02/26 05:05:14 marka Exp $ -->
<!-- File: $Id: Bv9ARM-book.xml,v 1.217 2003/02/26 06:04:03 marka Exp $ -->
<book>
<title>BIND 9 Administrator Reference Manual</title>
......@@ -2021,6 +2021,11 @@ authentication and authorization using TSIG.</para></entry>
<entry colname = "1"><para><command>logging</command></para></entry>
<entry colname = "2"><para>specifies what the server logs, and where
the log messages are sent.</para></entry>
</row>
<row rowsep = "0">
<entry colname = "1"><para><command>masters</command></para></entry>
<entry colname = "2"><para>defines a named masters list for
inclusion in stub and slave zone masters clauses.</para></entry>
</row>
<row rowsep = "0">
<entry colname = "1"><para><command>options</command></para></entry>
......@@ -2681,6 +2686,17 @@ which are appended to relative names in queries.</para>
number of dots in a relative domain name that should result in an
exact match lookup before search path elements are appended.</para>
</sect2>
<sect2>
<title><command>masters</command> Statement Grammar</title>
<programlisting>
<command>masters</command> <replaceable>name</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> { ( <replaceable>masters_list</replaceable> | <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> <optional>key <replaceable>key</replaceable></optional> ) ; <optional>...</optional> } ;
</programlisting>
</sect2>
<sect2>
<title><command>masters</command> Statement Definition and Usage </title>
<para><command>masters</command> lists allow for a common set of masters
to be easily used by multiple stub and slave zones.
</sect2>
<sect2>
<title><command>options</command> Statement Grammar</title>
......@@ -4407,7 +4423,7 @@ Statement Grammar</title>
<optional> ixfr-base <replaceable>string</replaceable> ; </optional>
<optional> ixfr-tmp-file <replaceable>string</replaceable> ; </optional>
<optional> maintain-ixfr-base <replaceable>yes_or_no</replaceable> ; </optional>
<optional> masters <optional>port <replaceable>ip_port</replaceable></optional> { <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> <optional>key <replaceable>key</replaceable></optional>; <optional>...</optional> } ; </optional>
<optional> masters <optional>port <replaceable>ip_port</replaceable></optional> { ( <replaceable>masters_list</replaceable> | <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> <optional>key <replaceable>key</replaceable></optional> ) ; <optional>...</optional> } ; </optional>
<optional> max-ixfr-log-size <replaceable>number</replaceable> ; </optional>
<optional> max-transfer-idle-in <replaceable>number</replaceable> ; </optional>
<optional> max-transfer-idle-out <replaceable>number</replaceable> ; </optional>
......@@ -4451,6 +4467,7 @@ it.</para></entry>
<entry colname = "2"><para>A slave zone is a replica of a master
zone. The <command>masters</command> list specifies one or more IP addresses
of master servers that the slave contacts to update its copy of the zone.
Masters list elements can also be names of other masters lists.
By default, transfers are made from port 53 on the servers; this can
be changed for all servers by specifying a port number before the
list of IP addresses, or on a per-server basis after the IP address.
......
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: check.c,v 1.34 2003/01/16 03:59:24 marka Exp $ */
/* $Id: check.c,v 1.35 2003/02/26 06:04:03 marka Exp $ */
#include <config.h>
......@@ -282,6 +282,126 @@ check_options(cfg_obj_t *options, isc_log_t *logctx) {
return (result);
}
static isc_result_t
get_masters_def(cfg_obj_t *cctx, char *name, cfg_obj_t **ret) {
isc_result_t result;
cfg_obj_t *masters = NULL;
cfg_listelt_t *elt;
result = cfg_map_get(cctx, "masters", &masters);
if (result != ISC_R_SUCCESS)
return (result);
for (elt = cfg_list_first(masters);
elt != NULL;
elt = cfg_list_next(elt)) {
cfg_obj_t *list;
const char *listname;
list = cfg_listelt_value(elt);
listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
if (strcasecmp(listname, name) == 0) {
*ret = list;
return (ISC_R_SUCCESS);
}
}
return (ISC_R_NOTFOUND);
}
static isc_result_t
validate_masters(cfg_obj_t *obj, cfg_obj_t *config, isc_uint32_t *countp,
isc_log_t *logctx, isc_mem_t *mctx)
{
isc_result_t result = ISC_R_SUCCESS;
isc_result_t tresult;
isc_uint32_t count = 0;
isc_symtab_t *symtab = NULL;
isc_symvalue_t symvalue;
cfg_listelt_t *element;
cfg_listelt_t **stack = NULL;
isc_uint32_t stackcount = 0, pushed = 0;
cfg_obj_t *list;
REQUIRE(countp != NULL);
result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
if (result != ISC_R_SUCCESS)
return (result);
newlist:
list = cfg_tuple_get(obj, "addresses");
element = cfg_list_first(list);
resume:
for ( ;
element != NULL;
element = cfg_list_next(element))
{
char *listname;
cfg_obj_t *addr;
cfg_obj_t *key;
addr = cfg_tuple_get(cfg_listelt_value(element),
"masterselement");
key = cfg_tuple_get(cfg_listelt_value(element), "key");
if (cfg_obj_issockaddr(addr)) {
count++;
continue;
}
if (!cfg_obj_isvoid(key)) {
cfg_obj_log(key, logctx, ISC_LOG_ERROR,
"unexpected token '%s'",
cfg_obj_asstring(key));
if (result == ISC_R_SUCCESS)
result = ISC_R_FAILURE;
}
listname = cfg_obj_asstring(addr);
symvalue.as_pointer = addr;
tresult = isc_symtab_define(symtab, listname, 1, symvalue,
isc_symexists_reject);
if (tresult == ISC_R_EXISTS)
continue;
tresult = get_masters_def(config, listname, &obj);
if (tresult != ISC_R_SUCCESS) {
if (result == ISC_R_SUCCESS)
result = tresult;
cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
"unable to find masters list '%s'",
listname);
continue;
}
/* Grow stack? */
if (stackcount == pushed) {
void * new;
isc_uint32_t newlen = stackcount + 16;
size_t newsize, oldsize;
newsize = newlen * sizeof(*stack);
oldsize = stackcount * sizeof(*stack);
new = isc_mem_get(mctx, newsize);
if (new == NULL)
goto cleanup;
if (stackcount != 0) {
memcpy(new, stack, oldsize);
isc_mem_put(mctx, stack, oldsize);
}
stack = new;
stackcount = newlen;
}
stack[pushed++] = cfg_list_next(element);
goto newlist;
}
if (pushed != 0) {
element = stack[--pushed];
goto resume;
}
cleanup:
if (stack != NULL)
isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
isc_symtab_destroy(&symtab);
*countp = count;
return (result);
}
#define MASTERZONE 1
#define SLAVEZONE 2
#define STUBZONE 4
......@@ -294,7 +414,7 @@ typedef struct {
} optionstable;
static isc_result_t
check_zoneconf(cfg_obj_t *zconfig, isc_symtab_t *symtab,
check_zoneconf(cfg_obj_t *zconfig, cfg_obj_t *config, isc_symtab_t *symtab,
dns_rdataclass_t defclass, isc_log_t *logctx, isc_mem_t *mctx)
{
const char *zname;
......@@ -302,7 +422,6 @@ check_zoneconf(cfg_obj_t *zconfig, isc_symtab_t *symtab,
unsigned int ztype;
cfg_obj_t *zoptions;
cfg_obj_t *obj = NULL;
cfg_obj_t *addrlist = NULL;
isc_symvalue_t symvalue;
isc_result_t result = ISC_R_SUCCESS;
isc_result_t tresult;
......@@ -486,8 +605,12 @@ check_zoneconf(cfg_obj_t *zconfig, isc_symtab_t *symtab,
zname);
result = ISC_R_FAILURE;
} else {
addrlist = cfg_tuple_get(obj, "addresses");
if (cfg_list_first(addrlist) == NULL) {
isc_uint32_t count;
tresult = validate_masters(obj, config, &count,
logctx, mctx);
if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
result = tresult;
if (tresult == ISC_R_SUCCESS && count == 0) {
cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
"zone '%s': empty 'masters' entry",
zname);
......@@ -706,7 +829,8 @@ check_viewconf(cfg_obj_t *config, cfg_obj_t *vconfig, dns_rdataclass_t vclass,
isc_result_t tresult;
cfg_obj_t *zone = cfg_listelt_value(element);
tresult = check_zoneconf(zone, symtab, vclass, logctx, mctx);
tresult = check_zoneconf(zone, config, symtab, vclass,
logctx, mctx);
if (tresult != ISC_R_SUCCESS)
result = ISC_R_FAILURE;
}
......@@ -938,5 +1062,43 @@ bind9_check_namedconf(cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) {
}
}
tresult = cfg_map_get(config, "kal", &acls);
if (tresult == ISC_R_SUCCESS) {
cfg_listelt_t *elt;
cfg_listelt_t *elt2;
const char *aclname;
for (elt = cfg_list_first(acls);
elt != NULL;
elt = cfg_list_next(elt)) {
cfg_obj_t *acl = cfg_listelt_value(elt);
aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
for (elt2 = cfg_list_next(elt);
elt2 != NULL;
elt2 = cfg_list_next(elt2)) {
cfg_obj_t *acl2 = cfg_listelt_value(elt2);
const char *name;
name = cfg_obj_asstring(cfg_tuple_get(acl2,
"name"));
if (strcasecmp(aclname, name) == 0) {
const char *file = cfg_obj_file(acl);
unsigned int line = cfg_obj_line(acl);
if (file == NULL)
file = "<unknown file>";
cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
"attempt to redefine "
"kal '%s' previous "
"definition: %s:%u",
name, file, line);
result = ISC_R_FAILURE;
}
}
}
}
return (result);
}
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: namedconf.c,v 1.17 2003/02/26 05:05:16 marka Exp $ */
/* $Id: namedconf.c,v 1.18 2003/02/26 06:04:03 marka Exp $ */
#include <config.h>
......@@ -69,8 +69,7 @@ doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
static cfg_type_t cfg_type_acl;
static cfg_type_t cfg_type_addrmatchelt;
static cfg_type_t cfg_type_bracketed_aml;
static cfg_type_t cfg_type_bracketed_namesockaddrlist;
static cfg_type_t cfg_type_bracketed_sockaddrkeylist;
static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
static cfg_type_t cfg_type_bracketed_sockaddrlist;
static cfg_type_t cfg_type_controls;
static cfg_type_t cfg_type_controls_sockaddr;
......@@ -81,8 +80,8 @@ static cfg_type_t cfg_type_logfile;
static cfg_type_t cfg_type_logging;
static cfg_type_t cfg_type_logseverity;
static cfg_type_t cfg_type_lwres;
static cfg_type_t cfg_type_masterselement;
static cfg_type_t cfg_type_nameportiplist;
static cfg_type_t cfg_type_namesockaddr;
static cfg_type_t cfg_type_negated;
static cfg_type_t cfg_type_notifytype;
static cfg_type_t cfg_type_optional_class;
......@@ -140,38 +139,48 @@ static cfg_tuplefielddef_t acl_fields[] = {
static cfg_type_t cfg_type_acl = {
"acl", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, acl_fields };
/* masters */
static cfg_tuplefielddef_t masters_fields[] = {
{ "name", &cfg_type_astring, 0 },
{ "port", &cfg_type_optional_port, 0 },
{ "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_masters = {
"masters", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, masters_fields };
/*
* "sockaddrkeylist", a list of socket addresses with optional keys
* and an optional default port, as used in the masters option.
* E.g.,
* "port 1234 { 10.0.0.1 key foo; 1::2 port 69; }"
* "port 1234 { mymasters; 10.0.0.1 key foo; 1::2 port 69; }"
*/
static cfg_tuplefielddef_t sockaddrkey_fields[] = {
{ "sockaddr", &cfg_type_sockaddr, 0 },
static cfg_tuplefielddef_t namesockaddrkey_fields[] = {
{ "masterselement", &cfg_type_masterselement, 0 },
{ "key", &cfg_type_optional_keyref, 0 },
{ NULL, NULL, 0 },
};
static cfg_type_t cfg_type_sockaddrkey = {
"sockaddrkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
sockaddrkey_fields
static cfg_type_t cfg_type_namesockaddrkey = {
"namesockaddrkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
namesockaddrkey_fields
};
static cfg_type_t cfg_type_bracketed_sockaddrkeylist = {
"bracketed_sockaddrkeylist", cfg_parse_bracketed_list,
cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_sockaddrkey
static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = {
"bracketed_namesockaddrkeylist", cfg_parse_bracketed_list,
cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_namesockaddrkey
};