2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-22 01:59:26 +00:00

4376. [experimental] Added support for Catalog Zones, a new method for

provisioning secondary servers in which a list of
                        zones to be served is stored in a DNS zone and can
                        be propagated to slaves via AXFR/IXFR. [RT #41581]

4375.   [func]          Add support for automatic reallocation of isc_buffer
                        to isc_buffer_put* functions. [RT #42394]
This commit is contained in:
Witold Krecicki 2016-05-26 21:23:19 +02:00
parent bfe9697f92
commit 7a00d69909
56 changed files with 4721 additions and 162 deletions

3
.gitignore vendored
View File

@ -55,3 +55,6 @@ unit/atf-src/test-programs/sh_helpers
# ccc-analyzer store its results in .plist directories
*.plist/
*~
.project
.cproject
.settings

View File

@ -1,3 +1,11 @@
4376. [experimental] Added support for Catalog Zones, a new method for
provisioning secondary servers in which a list of
zones to be served is stored in a DNS zone and can
be propagated to slaves via AXFR/IXFR. [RT #41581]
4375. [func] Add support for automatic reallocation of isc_buffer
to isc_buffer_put* functions. [RT #42394]
4374. [bug] Use SAVE/RESTORE macros in query.c to reduce the
probability of reference counting errors as seen
in 4365. [RT #42405]

View File

@ -576,9 +576,7 @@ get_masters_def(const cfg_obj_t *cctx, const char *name,
isc_result_t
ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list,
isc_mem_t *mctx, isc_sockaddr_t **addrsp,
isc_dscp_t **dscpsp, dns_name_t ***keysp,
isc_uint32_t *countp)
isc_mem_t *mctx, dns_ipkeylist_t *ipkl)
{
isc_uint32_t addrcount = 0, dscpcount = 0, keycount = 0, i = 0;
isc_uint32_t listcount = 0, l = 0, j;
@ -601,10 +599,10 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list,
isc_dscp_t dscp;
} *stack = NULL;
REQUIRE(addrsp != NULL && *addrsp == NULL);
REQUIRE(dscpsp != NULL && *dscpsp == NULL);
REQUIRE(keysp != NULL && *keysp == NULL);
REQUIRE(countp != NULL);
REQUIRE(ipkl != NULL);
REQUIRE(ipkl->addrs == NULL);
REQUIRE(ipkl->keys == NULL);
REQUIRE(ipkl->dscps == NULL);
/*
* Get system defaults.
@ -857,10 +855,10 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list,
INSIST(keycount == addrcount);
*addrsp = addrs;
*dscpsp = dscps;
*keysp = keys;
*countp = addrcount;
ipkl->addrs = addrs;
ipkl->dscps = dscps;
ipkl->keys = keys;
ipkl->count = addrcount;
return (ISC_R_SUCCESS);
@ -886,37 +884,6 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list,
return (result);
}
void
ns_config_putipandkeylist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
isc_dscp_t **dscpsp, dns_name_t ***keysp,
isc_uint32_t count)
{
unsigned int i;
dns_name_t **keys;
REQUIRE(addrsp != NULL && *addrsp != NULL);
REQUIRE(dscpsp == NULL || *dscpsp != NULL);
REQUIRE(keysp != NULL && *keysp != NULL);
keys = *keysp;
isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t));
if (dscpsp != NULL)
isc_mem_put(mctx, *dscpsp, count * sizeof(isc_dscp_t));
for (i = 0; i < count; i++) {
if (keys[i] == NULL)
continue;
if (dns_name_dynamic(keys[i]))
dns_name_free(keys[i], mctx);
isc_mem_put(mctx, keys[i], sizeof(dns_name_t));
}
isc_mem_put(mctx, *keysp, count * sizeof(dns_name_t *));
*addrsp = NULL;
if (dscpsp != NULL)
*dscpsp = NULL;
*keysp = NULL;
}
isc_result_t
ns_config_getport(const cfg_obj_t *config, in_port_t *portp) {
const cfg_obj_t *maps[3];

View File

@ -31,11 +31,11 @@ isc_result_t
ns_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf);
isc_result_t
ns_config_get(cfg_obj_t const * const *maps, const char* name,
ns_config_get(cfg_obj_t const * const *maps, const char *name,
const cfg_obj_t **obj);
isc_result_t
ns_checknames_get(const cfg_obj_t **maps, const char* name,
ns_checknames_get(const cfg_obj_t **maps, const char *name,
const cfg_obj_t **obj);
int
@ -64,14 +64,7 @@ ns_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
isc_result_t
ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list,
isc_mem_t *mctx, isc_sockaddr_t **addrsp,
isc_dscp_t **dscpp, dns_name_t ***keys,
isc_uint32_t *countp);
void
ns_config_putipandkeylist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
isc_dscp_t **dscpsp, dns_name_t ***keys,
isc_uint32_t count);
isc_mem_t *mctx, dns_ipkeylist_t *ipkl);
isc_result_t
ns_config_getport(const cfg_obj_t *config, in_port_t *portp);

View File

@ -283,6 +283,16 @@ options {
check-mx-cname ( fail | warn | ignore );
check-srv-cname ( fail | warn | ignore );
cache-file <replaceable>quoted_string</replaceable>; // test option
catalog-zones {
zone <replaceable>quoted_string</replaceable>
<optional> default-masters
<optional>port <replaceable>ip_port</replaceable></optional>
<optional>dscp <replaceable>ip_dscp</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>in-memory <replaceable>yes_or_no</replaceable></optional>
<optional>min-update-interval <replaceable>interval</replaceable></optional>
; ... };
;
suppress-initial-notify <replaceable>boolean</replaceable>; // not yet implemented
preferred-glue <replaceable>string</replaceable>;
dual-stack-servers <optional> port <replaceable>integer</replaceable> </optional> {

View File

@ -65,11 +65,13 @@
#include <dns/adb.h>
#include <dns/badcache.h>
#include <dns/cache.h>
#include <dns/catz.h>
#include <dns/db.h>
#include <dns/dispatch.h>
#include <dns/dlz.h>
#include <dns/dns64.h>
#include <dns/dyndb.h>
#include <dns/events.h>
#include <dns/forward.h>
#include <dns/journal.h>
#include <dns/keytable.h>
@ -275,6 +277,19 @@ typedef struct {
isc_refcount_t refs;
} ns_zoneload_t;
typedef struct {
ns_server_t *server;
} catz_cb_data_t;
typedef struct catz_chgzone_event {
ISC_EVENT_COMMON(struct catz_chgzone_event);
dns_catz_entry_t *entry;
dns_catz_zone_t *origin;
dns_view_t *view;
catz_cb_data_t *cbd;
isc_boolean_t mod;
} catz_chgzone_event_t;
/*
* These zones should not leak onto the Internet.
*/
@ -1990,12 +2005,439 @@ configure_rpz(dns_view_t *view, const cfg_obj_t *rpz_obj,
"updated RPZ policy: version %d",
view->rpzs->rpz_ver);
}
if (pview != NULL)
dns_view_detach(&pview);
return (ISC_R_SUCCESS);
}
static void
catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
catz_chgzone_event_t *ev = (catz_chgzone_event_t *) event0;
isc_result_t result;
isc_buffer_t namebuf;
isc_buffer_t *confbuf;
char nameb[DNS_NAME_FORMATSIZE];
const cfg_obj_t *zlist = NULL;
cfg_obj_t *zoneconf = NULL;
cfg_obj_t *zoneobj = NULL;
ns_cfgctx_t *cfg;
dns_zone_t *zone = NULL;
cfg = (ns_cfgctx_t *) ev->view->new_zone_config;
if (cfg == NULL) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
"catz: allow-new-zones statement missing from "
"config; cannot add zone from the catalog");
goto cleanup;
}
isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
dns_name_totext(dns_catz_entry_getname(ev->entry), ISC_TRUE, &namebuf);
isc_buffer_putuint8(&namebuf, 0);
/* Zone shouldn't already exist */
result = dns_zt_find(ev->view->zonetable,
dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
if (result == ISC_R_SUCCESS) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
"catz: zone \"%s\" already exists", nameb);
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) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
"catz: error \"%s\" while trying to "
"add zone \"%s\"",
isc_result_totext(result), nameb);
goto cleanup;
}
/* Create a config for new zone */
confbuf = NULL;
dns_catz_generate_zonecfg(ev->origin, ev->entry, &confbuf);
cfg_parser_reset(cfg->add_parser);
result = cfg_parse_buffer2(cfg->add_parser, confbuf, "catz",
&cfg_type_addzoneconf, &zoneconf);
isc_buffer_free(&confbuf);
if (result != ISC_R_SUCCESS) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
"catz: error \"%s\" while trying to generate "
"config for zone \"%s\"",
isc_result_totext(result), nameb);
goto cleanup;
}
CHECK(cfg_map_get(zoneconf, "zone", &zlist));
if (!cfg_obj_islist(zlist))
CHECK(ISC_R_FAILURE);
/* For now we only support adding one zone at a time */
zoneobj = cfg_listelt_value(cfg_list_first(zlist));
/* Mark view unfrozen so that zone can be added */
result = isc_task_beginexclusive(task);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
dns_view_thaw(ev->view);
result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
ev->cbd->server->mctx, ev->view, NULL,
cfg->actx, ISC_TRUE, ISC_FALSE, ev->mod);
dns_view_freeze(ev->view);
isc_task_endexclusive(task);
if (result != ISC_R_SUCCESS) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
"catz: failed to configure zone \"%s\" - %d",
nameb, result);
goto cleanup;
}
/* Is it there yet? */
CHECK(dns_zt_find(ev->view->zonetable,
dns_catz_entry_getname(ev->entry), 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) {
dns_db_t *dbp = NULL;
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
"catz: dns_zone_loadnew() failed "
"with %s; reverting.",
isc_result_totext(result));
/* If the zone loaded partially, unload it */
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(ev->view->zonetable, zone);
goto cleanup;
}
/* Flag the zone as having been added at runtime */
dns_zone_setadded(zone, ISC_TRUE);
cleanup:
if (zone != NULL)
dns_zone_detach(&zone);
if (zoneconf != NULL)
cfg_obj_destroy(cfg->add_parser, &zoneconf);
dns_catz_entry_detach(ev->origin, &ev->entry);
dns_catz_zone_detach(&ev->origin);
dns_view_detach(&ev->view);
isc_event_free(ISC_EVENT_PTR(&ev));
}
static void
catz_delzone_taskaction(isc_task_t *task, isc_event_t *event0) {
catz_chgzone_event_t *ev = (catz_chgzone_event_t *) event0;
isc_result_t result;
dns_zone_t *zone = NULL;
dns_db_t *dbp = NULL;
char cname[DNS_NAME_FORMATSIZE];
const char * file;
result = isc_task_beginexclusive(task);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
dns_name_format(dns_catz_entry_getname(ev->entry), cname,
DNS_NAME_FORMATSIZE);
result = dns_zt_find(ev->view->zonetable,
dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
if (result != ISC_R_SUCCESS) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
"catz: catz_delzone_taskaction: "
"zone '%s' not found", cname);
goto cleanup;
}
/* TODO make other flag for CZ zones */
/* TODO2 make sure that we delete only 'own' zones */
if (!dns_zone_getadded(zone)) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
"catz: catz_delzone_taskaction: "
"zone '%s' is not a dynamically added zone",
cname);
goto cleanup;
}
/* 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(ev->view->zonetable, zone));
file = dns_zone_getfile(zone);
isc_file_remove(file);
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
"catz: catz_delzone_taskaction: "
"zone '%s' deleted", cname);
cleanup:
isc_task_endexclusive(task);
if (zone != NULL)
dns_zone_detach(&zone);
dns_catz_entry_detach(ev->origin, &ev->entry);
dns_catz_zone_detach(&ev->origin);
dns_view_detach(&ev->view);
isc_event_free(ISC_EVENT_PTR(&ev));
}
static isc_result_t
catz_create_chg_task(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata,
isc_eventtype_t type)
{
catz_chgzone_event_t *event;
isc_task_t *task;
isc_result_t result;
isc_taskaction_t action;
switch (type) {
case DNS_EVENT_CATZADDZONE:
case DNS_EVENT_CATZMODZONE:
action = catz_addmodzone_taskaction;
break;
case DNS_EVENT_CATZDELZONE:
action = catz_delzone_taskaction;
break;
default:
REQUIRE(0);
}
event = (catz_chgzone_event_t *) isc_event_allocate(view->mctx, origin,
type, action, NULL,
sizeof(*event));
if (event == NULL)
return (ISC_R_NOMEMORY);
event->cbd = (catz_cb_data_t *) udata;
event->entry = NULL;
event->origin = NULL;
event->view = NULL;
event->mod = ISC_TF(type == DNS_EVENT_CATZMODZONE);
dns_catz_entry_attach(entry, &event->entry);
dns_catz_zone_attach(origin, &event->origin);
dns_view_attach(view, &event->view);
task = NULL;
result = isc_taskmgr_excltask(taskmgr, &task);
REQUIRE(result == ISC_R_SUCCESS);
isc_task_send(task, ISC_EVENT_PTR(&event));
isc_task_detach(&task);
return (ISC_R_SUCCESS);
}
static isc_result_t
catz_addzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata)
{
return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
DNS_EVENT_CATZADDZONE));
}
static isc_result_t
catz_delzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata)
{
return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
DNS_EVENT_CATZDELZONE));
}
static isc_result_t
catz_modzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata)
{
return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
DNS_EVENT_CATZMODZONE));
}
static isc_result_t
configure_catz_zone(dns_view_t *view, const cfg_obj_t *config,
const cfg_listelt_t *element)
{
const cfg_obj_t *catz_obj, *obj;
dns_catz_zone_t *zone = NULL;
const char *str;
isc_result_t result;
dns_name_t origin;
dns_catz_options_t *opts;
dns_view_t *pview = NULL;
dns_name_init(&origin, NULL);
catz_obj = cfg_listelt_value(element);
str = cfg_obj_asstring(cfg_tuple_get(catz_obj, "zone name"));
result = dns_name_fromstring(&origin, str, DNS_NAME_DOWNCASE,
view->mctx);
if (result == ISC_R_SUCCESS && dns_name_equal(&origin, dns_rootname))
result = DNS_R_EMPTYLABEL;
if (result != ISC_R_SUCCESS) {
cfg_obj_log(catz_obj, ns_g_lctx, DNS_CATZ_ERROR_LEVEL,
"catz: invalid zone name '%s'", str);
goto cleanup;
}
result = dns_catz_add_zone(view->catzs, &origin, &zone);
if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
cfg_obj_log(catz_obj, ns_g_lctx, DNS_CATZ_ERROR_LEVEL,
"catz: unable to create catalog zone '%s', "
"error %s",
str, isc_result_totext(result));
goto cleanup;
}
if (result == ISC_R_EXISTS) {
isc_ht_iter_t *it = NULL;
result = dns_viewlist_find(&ns_g_server->viewlist,
view->name,
view->rdclass, &pview);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
/*
* xxxwpk todo: reconfigure the zone!!!!
*/
cfg_obj_log(catz_obj, ns_g_lctx, DNS_CATZ_ERROR_LEVEL,
"catz: catalog zone '%s' will not be reconfigured",
str);
/*
* We have to walk through all the member zones and attach
* them to current view
*/
result = dns_catz_get_iterator(zone, &it);
if (result != ISC_R_SUCCESS) {
cfg_obj_log(catz_obj, ns_g_lctx, DNS_CATZ_ERROR_LEVEL,
"catz: unable to create iterator");
goto cleanup;
}
for (result = isc_ht_iter_first(it);
result == ISC_R_SUCCESS;
result = isc_ht_iter_next(it))
{
dns_name_t *name = NULL;
dns_zone_t *dnszone = NULL;
dns_catz_entry_t *entry = NULL;
isc_result_t tresult;
isc_ht_iter_current(it, (void **) &entry);
name = dns_catz_entry_getname(entry);
tresult = dns_view_findzone(pview, name, &dnszone);
RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
dns_zone_setview(dnszone, view);
if (view->acache != NULL)
dns_zone_setacache(dnszone, view->acache);
dns_view_addzone(view, dnszone);
}
isc_ht_iter_destroy(&it);
result = ISC_R_SUCCESS;
}
dns_catz_zone_resetdefoptions(zone);
opts = dns_catz_zone_getdefoptions(zone);
obj = cfg_tuple_get(catz_obj, "default-masters");
if (obj != NULL)
result = ns_config_getipandkeylist(config, obj,
view->mctx, &opts->masters);
obj = cfg_tuple_get(catz_obj, "in-memory");
if (obj != NULL && cfg_obj_isboolean(obj))
opts->in_memory = cfg_obj_asboolean(obj);
obj = cfg_tuple_get(catz_obj, "min-update-interval");
if (obj != NULL && cfg_obj_isuint32(obj))
opts->min_update_interval = cfg_obj_asuint32(obj);
cleanup:
if (pview != NULL)
dns_view_detach(&pview);
dns_name_free(&origin, view->mctx);
return (result);
}
static catz_cb_data_t ns_catz_cbdata;
static dns_catz_zonemodmethods_t ns_catz_zonemodmethods = {
catz_addzone,
catz_modzone,
catz_delzone,
&ns_catz_cbdata
};
static isc_result_t
configure_catz(dns_view_t *view, const cfg_obj_t *config,
const cfg_obj_t *catz_obj)
{
const cfg_listelt_t *zone_element;
const dns_catz_zones_t *old = NULL;
dns_view_t *pview = NULL;
isc_result_t result;
/* xxxwpk TODO do it cleaner, once, somewhere */
ns_catz_cbdata.server = ns_g_server;
zone_element = cfg_list_first(cfg_tuple_get(catz_obj, "zone list"));
if (zone_element == NULL)
return (ISC_R_SUCCESS);
CHECK(dns_catz_new_zones(&view->catzs, &ns_catz_zonemodmethods,
view->mctx, ns_g_taskmgr, ns_g_timermgr));
result = dns_viewlist_find(&ns_g_server->viewlist, view->name,
view->rdclass, &pview);
if (result == ISC_R_SUCCESS)
old = pview->catzs;
if (old != NULL) {
dns_catz_catzs_detach(&view->catzs);
dns_catz_catzs_attach(pview->catzs, &view->catzs);
dns_catz_prereconfig(view->catzs);
}
while (zone_element != NULL) {
CHECK(configure_catz_zone(view, config, zone_element));
zone_element = cfg_list_next(zone_element);
}
if (old != NULL)
dns_catz_postreconfig(view->catzs);
result = ISC_R_SUCCESS;
cleanup:
if (pview != NULL)
dns_view_detach(&pview);
return (result);
}
#define CHECK_RRL(cond, pat, val1, val2) \
do { \
if (!(cond)) { \
@ -2693,6 +3135,12 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
CHECK(configure_rpz(view, obj, &old_rpz_ok));
}
obj = NULL;
if (view->rdclass == dns_rdataclass_in && need_hints &&
ns_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS) {
CHECK(configure_catz(view, config, obj));
}
/*
* Configure the zones.
*/
@ -4574,6 +5022,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
dns_rdataclass_t zclass;
const char *ztypestr;
dns_rpz_num_t rpz_num;
isc_boolean_t zone_is_catz = ISC_FALSE;
options = NULL;
(void)cfg_map_get(config, "options", &options);
@ -4801,6 +5250,10 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
break;
}
if (view->catzs != NULL &&
dns_catz_get_zone(view->catzs, origin) != NULL)
zone_is_catz = ISC_TRUE;
/*
* See if we can reuse an existing zone. This is
* only possible if all of these are true:
@ -4850,7 +5303,6 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
dns_zone_setstats(zone, ns_g_server->zonestats);
}
if (rpz_num != DNS_RPZ_INVALID_NUM) {
result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
if (result != ISC_R_SUCCESS) {
@ -4864,6 +5316,9 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
}
}
if (zone_is_catz)
dns_zone_catz_enable(zone, view->catzs);
/*
* If the zone contains a 'forwarders' statement, configure
* selective forwarding.
@ -4919,7 +5374,19 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
* Add the zone to its view in the new view list.
*/
if (!modify)
CHECK(dns_view_addzone(view, zone));
CHECK(dns_view_addzone(view, zone));
if (zone_is_catz) {
/*
* force catz reload if the zone is loaded;
* if it's not it'll get reloaded on zone load
*/
dns_db_t *db = NULL;
tresult = dns_zone_getdb(zone, &db);
if (tresult == ISC_R_SUCCESS)
dns_catz_dbupdate_callback(db, view->catzs);
}
/*
* Ensure that zone keys are reloaded on reconfig
@ -5684,6 +6151,20 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
if (result == ISC_R_SUCCESS)
allow = cfg_obj_asboolean(nz);
/*
* A non-empty catalog-zones statement implies allow-new-zones
*/
if (!allow) {
const cfg_obj_t *cz = NULL;
result = ns_config_get(maps, "catalog-zones", &cz);
if (result == ISC_R_SUCCESS) {
const cfg_listelt_t *e =
cfg_list_first(cfg_tuple_get(cz, "zone list"));
if (e != NULL)
allow = ISC_TRUE;
}
}
if (!allow) {
dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
return (ISC_R_SUCCESS);

View File

@ -27,6 +27,7 @@
#include <dns/acl.h>
#include <dns/db.h>
#include <dns/ipkeylist.h>
#include <dns/fixedname.h>
#include <dns/log.h>
#include <dns/name.h>
@ -805,9 +806,6 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
const char *filename = NULL;
const char *dupcheck;
dns_notifytype_t notifytype = dns_notifytype_yes;
isc_sockaddr_t *addrs;
isc_dscp_t *dscps;
dns_name_t **keynames;
isc_uint32_t count;
unsigned int dbargc;
char **dbargv;
@ -1149,23 +1147,19 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
(notifytype == dns_notifytype_masteronly &&
ztype == dns_zone_master)))
{
isc_uint32_t addrcount;
addrs = NULL;
keynames = NULL;
dscps = NULL;
dns_ipkeylist_t ipkl;
ipkl.count = 0;
ipkl.addrs = NULL;
ipkl.dscps = NULL;
ipkl.keys = NULL;
RETERR(ns_config_getipandkeylist(config, obj, mctx,
&addrs, &dscps,
&keynames,
&addrcount));
result = dns_zone_setalsonotifydscpkeys(zone, addrs,
dscps, keynames,
addrcount);
if (addrcount != 0)
ns_config_putipandkeylist(mctx, &addrs, &dscps,
&keynames, addrcount);
else
INSIST(addrs == NULL && dscps == NULL &&
keynames == NULL);
&ipkl));
result = dns_zone_setalsonotifydscpkeys(zone,
ipkl.addrs,
ipkl.dscps,
ipkl.keys,
ipkl.count);
dns_ipkeylist_clear(mctx, &ipkl);
RETERR(result);
} else
RETERR(dns_zone_setalsonotify(zone, NULL, 0));
@ -1628,19 +1622,19 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
obj = NULL;
(void)cfg_map_get(zoptions, "masters", &obj);
if (obj != NULL) {
addrs = NULL;
dscps = NULL;
keynames = NULL;
dns_ipkeylist_t ipkl;
ipkl.count = 0;
ipkl.addrs = NULL;
ipkl.dscps = NULL;
ipkl.keys = NULL;
RETERR(ns_config_getipandkeylist(config, obj, mctx,
&addrs, &dscps,
&keynames, &count));
result = dns_zone_setmasterswithkeys(mayberaw, addrs,
keynames, count);
if (count != 0)
ns_config_putipandkeylist(mctx, &addrs, &dscps,
&keynames, count);
else
INSIST(addrs == NULL && keynames == NULL);
&ipkl));
result = dns_zone_setmasterswithkeys(mayberaw,
ipkl.addrs,
ipkl.keys,
ipkl.count);
dns_ipkeylist_clear(mctx, &ipkl);
RETERR(result);
} else
result = dns_zone_setmasters(mayberaw, NULL, 0);
RETERR(result);

View File

@ -0,0 +1,23 @@
# Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
rm -f dig.out.*
rm -f nsupdate.out.*
rm -f ns*/named.memstats
rm -f ns*/named.run
rm -f ns*/named.lock
rm -f ns{1,2}/*dom*example.db
rm -f ns{1,2}/catalog.example.db
rm -f ns*/*.jnl
rm -f ns*/*.nzf

View File

@ -0,0 +1,3 @@
@ 3600 SOA . . 1 86400 3600 86400 3600
@ 3600 IN NS invalid.
version IN TXT "1"

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2011, 2013, 2016 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
include "../../common/rndc.key";
controls {
inet 10.53.0.1 port 9953 allow { any; } keys { rndc_key; };
};
options {
query-source address 10.53.0.1;
notify-source 10.53.0.1;
transfer-source 10.53.0.1;
port 5300;
allow-new-zones yes;
pid-file "named.pid";
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
notify no;
recursion no;
};
zone "catalog.example" {
type master;
file "catalog.example.db";
allow-transfer { any; };
allow-update { any; };
also-notify { 10.53.0.2; };
notify explicit;
};

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2011, 2013, 2016 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
include "../../common/rndc.key";
controls {
inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
};
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
transfer-source 10.53.0.2;
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
notify no;
recursion no;
serial-query-rate 100;
catalog-zones {
zone "catalog.example" default-masters { 10.53.0.1; };
};
};
zone "catalog.example" {
type slave;
file "catalog.example.db";
masters { 10.53.0.1; };
};

View File

@ -0,0 +1,2 @@
@ 3600 IN SOA . . 1 3600 3600 3600 3600
@ IN NS invalid.

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2011, 2013, 2016 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
include "../../common/rndc.key";
controls {
inet 10.53.0.3 port 9953 allow { any; } keys { rndc_key; };
};
options {
query-source address 10.53.0.3;
notify-source 10.53.0.3;
transfer-source 10.53.0.3;
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
notify no;
recursion no;
};
zone "dom4.example" {
type master;
file "dom4.example.db";
allow-transfer { any; };
allow-update { any; };
notify explicit;
};

View File

@ -0,0 +1,22 @@
#!/bin/sh
#
# Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
$SHELL clean.sh
cat ns1/catalog.example.db.in > ns1/catalog.example.db

View File

@ -0,0 +1,305 @@
#!/bin/sh -x
#
# Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
status=0
n=0
n=`expr $n + 1`
echo "I:checking that dom1.example is not served by master ($n)"
ret=0
$DIG soa dom1.example @10.53.0.1 -p 5300 > dig.out.test$n
grep "status: REFUSED" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:Adding a domain dom1.example to master via RNDC ($n)"
ret=0
echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns1/dom1.example.db
echo "@ IN NS invalid." >> ns1/dom1.example.db
$RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 addzone dom1.example '{type master; file "dom1.example.db";};' || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking that dom1.example is now served by master ($n)"
ret=0
$DIG soa dom1.example @10.53.0.1 -p 5300 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
cur=`awk 'BEGIN {l=0} /^/ {l++} END { print l }' ns2/named.run`
n=`expr $n + 1`
echo "I:Adding domain dom1.example to catalog zone ($n)"
ret=0
$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
server 10.53.0.1 5300
update add e721433b6160b450260d4f54b3ec8bab30cb3b83.zones.catalog.example 3600 IN PTR dom1.example.
send
END
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:waiting for slave to sync up ($n)"
ret=1
try=0
while test $try -lt 45
do
sleep 1
sed -n "$cur,"'$p' < ns2/named.run | grep "catz: adding zone 'dom1.example' from catalog 'catalog.example'" > /dev/null && {
ret=0
break
}
try=`expr $try + 1`
done
try=0
while test $try -lt 45
do
sleep 1
sed -n "$cur,"'$p' < ns2/named.run | grep "transfer of 'dom1.example/IN' from 10.53.0.1#5300: Transfer status: success" > /dev/null && {
ret=0
break
}
try=`expr $try + 1`
done
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking that dom1.example is served by slave ($n)"
ret=0
$DIG soa dom1.example @10.53.0.2 -p 5300 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:Removing domain dom1.example from catalog zone ($n)"
ret=0
$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
server 10.53.0.1 5300
update delete e721433b6160b450260d4f54b3ec8bab30cb3b83.zones.catalog.example
send
END
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:waiting for slave to sync up ($n)"
ret=1
try=0
while test $try -lt 45
do
sleep 1
sed -n "$cur,"'$p' < ns2/named.run | grep "catz: deleting zone 'dom1.example' from catalog 'catalog.example'" > /dev/null && {
ret=0
break
}
try=`expr $try + 1`
done
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking that dom1.example is not served by slave ($n)"
ret=0
$DIG soa dom1.example @10.53.0.2 -p 5300 > dig.out.test$n
grep "status: REFUSED" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:Adding a domain dom2.example to master via RNDC ($n)"
ret=0
echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns1/dom2.example.db
echo "@ IN NS invalid." >> ns1/dom2.example.db
$RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 addzone dom2.example '{type master; file "dom2.example.db";};' || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:Adding domains dom2.example, dom3.example and some trash to catalog zone ($n)"
ret=0
$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
server 10.53.0.1 5300
update add 636722929740e507aaf27c502812fc395d30fb17.zones.catalog.example 3600 IN PTR dom2.example.
update add b901f492f3ebf6c1e5b597e51766f02f0479eb03.zones.catalog.example 3600 IN PTR dom3.example.
update add e721433b6160b450260d4f54b3ec8bab30cb3b83.zones.catalog.example 3600 IN NS foo.bar.
update add trash.catalog.example 3600 IN A 1.2.3.4
update add trash2.foo.catalog.example 3600 IN A 1.2.3.4
update add trash3.zones.catalog.example 3600 IN NS a.dom2.example.
send
END
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking that dom3.example is not served by master ($n)"
ret=0
$DIG soa dom3.example @10.53.0.1 -p 5300 > dig.out.test$n
grep "status: REFUSED" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:Adding a domain dom3.example to master via RNDC ($n)"
ret=0
echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns1/dom3.example.db
echo "@ IN NS invalid." >> ns1/dom3.example.db
$RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 addzone dom3.example '{type master; file "dom3.example.db"; also-notify { 10.53.0.2; }; };' || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking that dom3.example is served by master ($n)"
ret=0
$DIG soa dom2.example @10.53.0.1 -p 5300 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:waiting for slave to sync up ($n)"
ret=1
try=0
while test $try -lt 45
do
sleep 1
sed -n "$cur,"'$p' < ns2/named.run | grep "catz: adding zone 'dom3.example' from catalog 'catalog.example'" > /dev/null && {
ret=0
break
}
try=`expr $try + 1`
done
try=0
while test $try -lt 45
do
sleep 1
sed -n "$cur,"'$p' < ns2/named.run | grep "transfer of 'dom3.example/IN' from 10.53.0.1#5300: Transfer status: success" > /dev/null && {
ret=0
break
}
try=`expr $try + 1`
done
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking that dom3.example is served by slave ($n)"
ret=0
$DIG soa dom3.example @10.53.0.2 -p 5300 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:Adding dom4.example with 'masters' defined and a random label ($n)"
ret=0
$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
server 10.53.0.1 5300
update add somerandomlabel.zones.catalog.example 3600 IN PTR dom4.example.
update add masters.somerandomlabel.zones.catalog.example 3600 IN A 10.53.0.3
send
END
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:waiting for slave to sync up ($n)"
ret=1
try=0
while test $try -lt 45
do
sleep 1
sed -n "$cur,"'$p' < ns2/named.run | grep "catz: adding zone 'dom4.example' from catalog 'catalog.example'" > /dev/null && {
ret=0
break
}
try=`expr $try + 1`
done
try=0
while test $try -lt 45
do
sleep 1
sed -n "$cur,"'$p' < ns2/named.run | grep "transfer of 'dom4.example/IN' from 10.53.0.3#5300: Transfer status: success" > /dev/null && {
ret=0
break
}
try=`expr $try + 1`
done
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking that dom4.example is served by slave ($n)"
ret=0
$DIG soa dom4.example @10.53.0.2 -p 5300 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:Removing domain dom2.example from catalog zone ($n)"
ret=0
$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
server 10.53.0.1 5300
update delete 636722929740e507aaf27c502812fc395d30fb17.zones.catalog.example
send
END
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:waiting for slave to sync up ($n)"
ret=1
try=0
while test $try -lt 45
do
sleep 1
sed -n "$cur,"'$p' < ns2/named.run | grep "catz: deleting zone 'dom2.example' from catalog 'catalog.example'" > /dev/null && {
ret=0
break
}
try=`expr $try + 1`
done
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking that dom2.example is not served by slave ($n)"
ret=0
$DIG soa dom2.example @10.53.0.2 -p 5300 > dig.out.test$n
grep "status: REFUSED" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking that dom3.example is still served by slave ($n)"
ret=0
$DIG soa dom3.example @10.53.0.2 -p 5300 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
echo "I:exit status: $status"
exit $status

View File

@ -68,7 +68,7 @@ RANDFILE=$TOP/bin/tests/system/random.data
# load on the machine to make it unusable to other users.
# v6synth
SUBDIRS="acl additional allow_query addzone autosign builtin
cacheclean case checkconf @CHECKDS@ checknames checkzone
cacheclean case catz checkconf @CHECKDS@ checknames checkzone
cookie @COVERAGE@ database digdelv dlv dlvauto dlz dlzexternal
dname dns64 dnssec dsdigest dscp @DNSTAP@ dyndb ecdsa ednscompliance
emptyzones fetchlimit filter-aaaa formerr forward geoip glue gost

View File

@ -2373,6 +2373,8 @@ options {
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="dyndb.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="catz.xml"/>
<section xml:id="ipv6"><info><title>IPv6 Support in <acronym>BIND</acronym> 9</title></info>
<para>
<acronym>BIND</acronym> 9 fully supports all currently
@ -4674,6 +4676,16 @@ badresp:1,adberr:0,findfail:0,valfail:0]
<optional> qname-wait-recurse <replaceable>yes_or_no</replaceable> </optional>
<optional> automatic-interface-scan <replaceable>yes_or_no</replaceable> </optional>
; </optional>
<optional> catalog-zones {
zone <replaceable>quoted_string</replaceable>
<optional> default-masters
<optional>port <replaceable>ip_port</replaceable></optional>
<optional>dscp <replaceable>ip_dscp</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>in-memory <replaceable>yes_or_no</replaceable></optional>
<optional>min-update-interval <replaceable>interval</replaceable></optional>
; <optional>...</optional> };
; </optional>
<optional>v6-bias <replaceable>number</replaceable> ; </optional>
};
</programlisting>

Binary file not shown.

229
doc/arm/catz.xml Normal file
View File

@ -0,0 +1,229 @@
<!--
- Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
-->
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="catz-info"><info><title>Catalog Zones</title></info>
<para>
A "catalog zone" is a special DNS zone that contains a list of
other zones to be served, along with their configuration parameters.
Zones listed in a catalog zone are called "member zones".
When a catalog zone is loaded or transferred to a slave server
which supports this functionality, the slave server will create
the member zones automatically. When the catalog zone is updated
is updated (for example, to add or delete member zones, or change
their configuration aprameters) those changes are immediately put
into effect. Because the catalog zone is a normal DNS zone, these
configuration changes can be propagated using the standard AXFR/IXFR
zone transfer mechanism.
</para>
<para>
Catalog zones' format and behavior are specified as an internet draft
for interoperability among DNS implementations. As of this release, the
latest revision of the DNS catalog zones draft can be found here:
https://datatracker.ietf.org/doc/draft-muks-dnsop-dns-catalog-zones/
</para>
<section><info><title>Principle of Operation</title></info>
<para>
Normally, if a zone is to be served by a slave server, the
<filename>named.conf</filename> file on the server must list the
zone, or the zone must be added using <command>rndc addzone</command>.
In environments with a large number of slave servers and/or where
the zones being served are changing frequently, the overhead involved
in maintaining consistent zone configuration on all the slave
servers can be significant.
</para>
<para>
A catalog zone is a way to ease this administrative burden. It is a
DNS zone that lists member zones that should be served by slave servers.
When a slave server receives an update to the catalog zone, it adds,
removes, or reconfigures member zones based on the data received.
</para>
<para>
To use a catalog zone, it must first be set up as a normal zone on
the master and the on slave servers that will be configured to use
it. It must also be added to a <option>catalog-zones</option> list
in the <option>options</option> or <option>view</option> statement
in <filename>named.conf</filename>. (This is comparable to the way
a policy zone is configured as a normal zone and also listed in
a <option>response-policy</option> statement.)
</para>
<para>
To use the catalog zone feature to serve a new member zone:
<itemizedlist>
<listitem>
<para>
Set up the the member zone to be served on the master as normal.
This could be done by editing <filename>named.conf</filename>,
or by running <command>rndc addzone</command>.
</para>
</listitem>
<listitem>
<para>
Add an entry to the catalog zone for the new member zone.
This could be done by editing the catalog zone's master file
and running <command>rndc reload</command>, or by updating
the zone using <command>nsupdate</command>.
</para>
</listitem>
</itemizedlist>
The change to the catalog zone will be propagated from the master to all
slaves using the normal AXFR/IXFR mechanism. When the slave receives the
update to the catalog zone, it will detect the entry for the new member
zone, create an instance of of that zone on the slave server, and point
that instance to the <option>masters</option> specified in the catalog
zone data. The newly created member zone is a normal slave zone, so
BIND will immediately initiate a transfer of zone contents from the
master. Once complete, the slave will start serving the member zone.
</para>
<para>
Removing a member zone from a slave server requires nothing more than
deleting the member zone's entry in the catalog zone. The change to the
catalog cone is propagated to the slave server using the normal AXFR/IXFR
transfer mechanism. The slave server, on processing the update, will
notice that the member zone has been removed. It will stop serving the
zone and remove it froms its list of configured zones. (Removing the
member zone from the master server has to be done in the normal way,
by editing the configuration file or running
<command>rndc delzone</command>.)
</para>
</section>
<section><info><title>Configuring Catalog Zones</title></info>
<para>
Catalog zones are configured with a <command>catalog-zones</command>
statement in the <literal>options</literal> or <literal>view</literal>
section of <filename>named.conf</filename>. For example,
</para>
<screen>
catalog-zones {
zone "catalog.example" default-masters { 10.53.0.1; } in-memory true min-update-interval 10;
};
</screen>
<para>
This statement specifies that the zone
<literal>catalog.example</literal> is a catalog zone. This zone must be
properly configured in the same view. In most configurations, it would
be a slave zone.
</para>
<para>
The <option>default-masters</option> option defines the default masters
for member zones listed in a catalog zone. This can be overriden by
options within a catalog zone. If no such options are included, then
member zones will transfer their contents from the servers listed in
this option.
</para>
<para>
The <option>in-memory</option> option, if set to <literal>yes</literal>,
causes member zones to be stored only in memory. This is functionally
equivalent to configuring a slave zone without a <option>file</option>.
option. The default is <literal>no</literal>; member zones' content
will be stored locally in a file whose name is automatically generated
from the view name, catalog zone name, and member zone name.
</para>
<para>
The <option>min-update-interval</option> option sets the minimum
interval between processing of updates to catalog zones, in seconds.
If an update to a catalog zone (for example, via IXFR) happens less
than <option>min-update-interval</option> seconds after the most
recent update, then the changes will not be carried out until this
interval has elapsed. The default is <literal>5</literal> seconds.
</para>
<para>
Catalog zones are defined on a per-view basis. Configuring a non-empty
<option>catalog-zones</option> statement in a view will automatically
turn on <option>allow-new-zones</option> for that view. (Note: this
means <command>rndc addzone</command> and <command>rndc delzone</command>
will also work in any view that supports catalog zones.)
</para>
</section>
<section><info><title>Catalog Zone format</title></info>
<para>
A catalog zone is a regular DNS zone; therefore, it has to have a
single <literal>SOA</literal> and at least one <literal>NS</literal>
record.
</para>
<para>
A record stating the version of the catalog zone format is
also required. If the version number listed is not supported by
the server, then a catalog zone may not be used by that server.
</para>
<screen>
catalog.example. IN SOA . . 2016022901 900 600 86400 1
catalog.example. IN NS nsexample.
version.catalog.example. IN TXT "1"
</screen>
<para>
Note that this record must have the domain name
version.<replaceable>catalog-zone-name</replaceable>. This illustrates
how the meaning of data stored in a catalog zone is indicated by the
the domain name label immediately before the catalog zone domain.
</para>
<para>
Catalog zones can contain a set of global options that are applied to
all member zones, overriding the settings for the catalog zone
in the configuration file. Currently only the "masters" option
is supported:
<!-- TODO masters IN MX (with TSIG), allow-query, allow-tranfer -->
</para>
<screen>
masters.catalog.example IN A 192.0.2.1
masters.catalog.example IN AAAA 2001:db8::1
</screen>
<para>
(Note that if more than one server is defined, the order in which
they are used is undefined. The above example could correspond to
a zone configured with
<option>masters { 192.0.2.1; 2001:db8::1; };</option>
or with
<option>masters { 2001:db8::1; 192.0.2.1; };</option>.
There is currently no way to force a particular ordering.)
</para>
<para>
A member zone is added by including a <literal>PTR</literal>
resource record in the <literal>zones</literal> sub-domain of the
catalog zone. The record label is a <literal>SHA-1</literal> hash
of the member zone name in wire format. The target of the PTR
record is the member zone name. For example, to add the member
zone <literal>domain.example</literal>:
</para>
<screen>
5960775ba382e7a4e09263fc06e7c00569b6a05c.zones.catalog.example IN PTR domain.example.
</screen>
<para>
The hash is necessary to identify options for a specific member
zone. The member zone-specific options are defined the same way as
global options, but in the member zone subdomain:
</para>
<screen>
masters.5960775ba382e7a4e09263fc06e7c00569b6a05c.zones.catalog.example IN A 192.0.2.2
masters.5960775ba382e7a4e09263fc06e7c00569b6a05c.zones.catalog.example IN AAAA 2001:db8::2
</screen>
<para>
As would be expected, options defined for a specific zone override
the global options defined in the catalog zone. These in turn override
the global options defined in the <literal>catalog-zones</literal>
statement in the configuration file.
</para>
<para>
(Note that none of the global records an option will be inherited if
any records are defined for that option for the specific zone. For
example, if the zone had a <literal>masters</literal> record of type
A but not AAAA, then it would <emphasis>not</emphasis> inherit the
type AAAA record from the global option.)
</para>
</section>
</section>

View File

@ -54,6 +54,35 @@
<section xml:id="relnotes_features"><info><title>New Features</title></info>
<itemizedlist>
<listitem>
<para>
A new method of provisioning secondary servers called
"Catalog Zones" has been added. This is an implementation of
<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://datatracker.ietf.org/doc/draft-muks-dnsop-dns-catalog-zones/">
draft-muks-dnsop-dns-catalog-zones/
</link>.
</para>
<para>
A catalog zone is a regular DNS zone which contains a list
of "member zones", along with the configuration options for
each of those zones. When a server is configured to use a
catalog zone, all the zones listed in the catalog zone are
added to the local server as slave zones. When the catalog
zone is updated (e.g., by adding or removing zones, or
changing configuration options for existing zones) those
changes will be put into effect. Since the catalog zone is
itself a DNS zone, this means configuration changes can be
propagated to slaves using the standard AXFR/IXFR update
mechanism.
</para>
<para>
This feature should be considered experimental. It currently
supports only basic features; more advanced features such as
ACLs and TSIG keys are not yet supported. Example catalog
zone configurations can be found in the Chapter 9 of the
BIND Administrator Reference Manual.
</para>
</listitem>
<listitem>
<para>
Added rndc python module.

View File

@ -65,11 +65,11 @@ DNSTAPOBJS = dnstap.@O@ dnstap.pb-c.@O@
# Alphabetically
DNSOBJS = acache.@O@ acl.@O@ adb.@O@ badcache.@O@ byaddr.@O@ \
cache.@O@ callbacks.@O@ clientinfo.@O@ compress.@O@ \
cache.@O@ callbacks.@O@ catz.@O@ clientinfo.@O@ compress.@O@ \
db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \
dlz.@O@ dns64.@O@ dnssec.@O@ ds.@O@ dyndb.@O@ forward.@O@ \
iptable.@O@ journal.@O@ keydata.@O@ keytable.@O@ \
lib.@O@ log.@O@ lookup.@O@ \
ipkeylist.@O@ iptable.@O@ journal.@O@ keydata.@O@ \
keytable.@O@ lib.@O@ log.@O@ lookup.@O@ \
master.@O@ masterdump.@O@ message.@O@ \
name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ nta.@O@ \
order.@O@ peer.@O@ portlist.@O@ private.@O@ \
@ -108,8 +108,8 @@ DNSSRCS = acache.c acl.c adb.c badcache. byaddr.c \
cache.c callbacks.c clientinfo.c compress.c \
db.c dbiterator.c dbtable.c diff.c dispatch.c \
dlz.c dns64.c dnssec.c ds.c dyndb.c forward.c \
iptable.c journal.c keydata.c keytable.c lib.c log.c \
lookup.c master.c masterdump.c message.c \
ipkeylist.c iptable.c journal.c keydata.c keytable.c lib.c \
log.c lookup.c master.c masterdump.c message.c \
name.c ncache.c nsec.c nsec3.c nta.c \
order.c peer.c portlist.c \
rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c rdatalist.c \

View File

@ -583,7 +583,7 @@ initialize_action(void) {
}
/*
* Called via isc_radix_walk() to find IP table nodes that are
* Called via isc_radix_process() to find IP table nodes that are
* insecure.
*/
static void

1474
lib/dns/catz.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -15,8 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id$ */
/*! \file */
/***
@ -307,6 +305,8 @@ dns_db_beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
isc_result_t
dns_db_endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
dns_dbonupdatelistener_t *listener;
/*
* Finish loading 'db'.
*/
@ -315,6 +315,11 @@ dns_db_endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
REQUIRE(DNS_CALLBACK_VALID(callbacks));
REQUIRE(callbacks->add_private != NULL);
for (listener = ISC_LIST_HEAD(db->update_listeners);
listener != NULL;
listener = ISC_LIST_NEXT(listener, link))
listener->onupdate(db, listener->onupdate_arg);
return ((db->methods->endload)(db, callbacks));
}
@ -330,7 +335,8 @@ dns_db_load2(dns_db_t *db, const char *filename, dns_masterformat_t format) {
isc_result_t
dns_db_load3(dns_db_t *db, const char *filename, dns_masterformat_t format,
unsigned int options) {
unsigned int options)
{
isc_result_t result, eresult;
dns_rdatacallbacks_t callbacks;
@ -445,6 +451,7 @@ void
dns_db_closeversion(dns_db_t *db, dns_dbversion_t **versionp,
isc_boolean_t commit)
{
dns_dbonupdatelistener_t *listener;
/*
* Close version '*versionp'.
@ -456,6 +463,13 @@ dns_db_closeversion(dns_db_t *db, dns_dbversion_t **versionp,
(db->methods->closeversion)(db, versionp, commit);
if (commit == ISC_TRUE) {
for (listener = ISC_LIST_HEAD(db->update_listeners);
listener != NULL;
listener = ISC_LIST_NEXT(listener, link))
listener->onupdate(db, listener->onupdate_arg);
}
ENSURE(*versionp == NULL);
}
@ -1043,3 +1057,55 @@ dns_db_rpz_ready(dns_db_t *db) {
return (ISC_R_SUCCESS);
return ((db->methods->rpz_ready)(db));
}
/**
* Attach a notify-on-update function the database
*/
isc_result_t
dns_db_updatenotify_register(dns_db_t *db,
dns_dbupdate_callback_t fn,
void *fn_arg)
{
dns_dbonupdatelistener_t *listener;
REQUIRE(db != NULL);
REQUIRE(fn != NULL);
listener = isc_mem_get(db->mctx, sizeof(dns_dbonupdatelistener_t));
if (listener == NULL)
return (ISC_R_NOMEMORY);
listener->onupdate = fn;
listener->onupdate_arg = fn_arg;
ISC_LINK_INIT(listener, link);
ISC_LIST_APPEND(db->update_listeners, listener, link);
return (ISC_R_SUCCESS);
}
isc_result_t
dns_db_updatenotify_unregister(dns_db_t *db,
dns_dbupdate_callback_t fn,
void *fn_arg)
{
dns_dbonupdatelistener_t *listener;
REQUIRE(db != NULL);
for (listener = ISC_LIST_HEAD(db->update_listeners);
listener != NULL;
listener = ISC_LIST_NEXT(listener, link))
{
if ((listener->onupdate == fn) &&
(listener->onupdate_arg == fn_arg))
{
ISC_LIST_UNLINK(db->update_listeners, listener, link);
isc_mem_put(db->mctx, listener,
sizeof(dns_dbonupdatelistener_t));
return (ISC_R_SUCCESS);
}
}
return (ISC_R_NOTFOUND);
}

465
lib/dns/include/dns/catz.h Normal file
View File

@ -0,0 +1,465 @@
/*
* Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef DNS_CATZ_H
#define DNS_CATZ_H 1
#include <isc/ht.h>
#include <isc/lang.h>
#include <isc/refcount.h>
#include <isc/rwlock.h>
#include <isc/time.h>
#include <isc/timer.h>
#include <dns/db.h>
#include <dns/fixedname.h>
#include <dns/ipkeylist.h>
#include <dns/rdata.h>
#include <dns/types.h>
ISC_LANG_BEGINDECLS
#define DNS_CATZ_ERROR_LEVEL ISC_LOG_WARNING
#define DNS_CATZ_INFO_LEVEL ISC_LOG_INFO
#define DNS_CATZ_DEBUG_LEVEL1 ISC_LOG_DEBUG(1)
#define DNS_CATZ_DEBUG_LEVEL2 ISC_LOG_DEBUG(2)
#define DNS_CATZ_DEBUG_LEVEL3 ISC_LOG_DEBUG(3)
#define DNS_CATZ_DEBUG_QUIET (DNS_CATZ_DEBUG_LEVEL3+1)
/*
* Catalog Zones functions and structures.
*/
/*
* Options for a member zone in a catalog
*/
struct dns_catz_entry_options {
/*
* Options that can be overriden in catalog zone
*/
/* masters definition */
dns_ipkeylist_t masters;
/*
* Options that are only set in named.conf
*/
/* zone should not be stored on disk (no 'file' statement in def */
isc_boolean_t in_memory;
/*
* Minimal interval between catalog zone updates, if a new version
* of catalog zone is received before this time the update will be
* postponed. This is a global option for the whole catalog zone.
*/
isc_uint32_t min_update_interval;
};
void
dns_catz_options_init(dns_catz_options_t *options);
/*%<
* Initialize 'options' to NULL values.
*
* Requires:
* \li options to be non NULL
*/
void
dns_catz_options_free(dns_catz_options_t *options, isc_mem_t *mctx);
/*%<
* Free 'options' contents into 'mctx'. ('options' itself is not freed.)
*
* Requires:
* \li options to be non NULL
* \li mctx to be a valid memory context
*/
isc_result_t
dns_catz_options_copy(isc_mem_t *mctx, const dns_catz_options_t *opts,
dns_catz_options_t *nopts);
/*%<
* Duplicate 'opts' into 'nopts', allocating space from 'mctx'
*
* Requires:
* \li 'mctx' to be a valid memory context
* \li 'options' to be non NULL and valid options
* \li 'nopts' to be non NULL
*/
isc_result_t
dns_catz_options_setdefault(isc_mem_t *mctx, const dns_catz_options_t *defaults,
dns_catz_options_t *opts);
/*%<
* Replace empty values in 'opts' with values from 'defaults'
*
* Requires:
* \li mctx to be a valid memory context
* \li defaults to be non NULL and valid options
* \li opts to be non NULL
*/
dns_name_t *
dns_catz_entry_getname(dns_catz_entry_t *entry);
/*%<
* Get domain name for 'entry'
*
* Requires:
* \li entry to be non NULL
*
* Returns:
* \li domain name for entry
*/
isc_result_t
dns_catz_entry_new(isc_mem_t *mctx, const dns_name_t *domain,
dns_catz_entry_t **nentryp);
/*%<
* Allocate a new catz_entry on 'mctx', with the name 'domain'
*
* Requires:
* \li mctx to be a valid memory context
* \li domain to be valid dns_name or NULL
* \li nentryp to be non NULL, *nentryp to be NULL
*
* Returns:
* \li ISC_R_SUCCESS on success
* \li ISC_R_NOMEMORY on allocation failure
*/
isc_result_t
dns_catz_entry_copy(dns_catz_zone_t *zone, const dns_catz_entry_t *entry,
dns_catz_entry_t **nentryp);
/*%<
* Allocate a new catz_entry and deep copy 'entry' into 'nentryp'.
*
* Requires:
* \li mctx to be a valid memory context
* \li entry to be non NULL
* \li nentryp to be non NULL, *nentryp to be NULL
*
* Returns:
* \li ISC_R_SUCCESS on success
* \li ISC_R_NOMEMORY on allocation failure
*/
void
dns_catz_entry_attach(dns_catz_entry_t *entry, dns_catz_entry_t **entryp);
/*%<
* Attach an entry
*
* Requires:
* \li entry is not NULL
* \li entryp is not NULL, *entryp is NULL
*/
void
dns_catz_entry_detach(dns_catz_zone_t *zone, dns_catz_entry_t **entryp);
/*%<
* Detach an entry, free if no further references
*
* Requires:
* \li zone is not NULL
* \li entryp is not NULL, *entryp is not NULL
*/
isc_result_t
dns_catz_entry_validate(const dns_catz_entry_t *entry);
/*%<
* Validate whether entry is correct.
* (NOT YET IMPLEMENTED: always returns true)
*/
isc_boolean_t
dns_catz_entry_cmp(const dns_catz_entry_t *ea, const dns_catz_entry_t *eb);
/*%<
* Deep compare two entries
*
* Requires:
* \li ea is not NULL
* \li eb is not NULL
*
* Returns:
* \li ISC_TRUE if entries are the same
* \li ISC_FALSE if the entries differ
*/
void
dns_catz_zone_attach(dns_catz_zone_t *zone, dns_catz_zone_t **zonep);
/*%<
* Attach a catzone
*
* Requires:
* \li zone is not NULL
* \li zonep is not NULL, *zonep is NULL
*/
void
dns_catz_zone_detach(dns_catz_zone_t** zonep);
/*%<
* Detach a zone, free if no further references
*
* Requires:
* \li zonep is not NULL, *zonep is not NULL
*/
isc_result_t
dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep,
const dns_name_t *name);
/*%<
* Allocate a new catz zone on catzs mctx
*
* Requires:
* \li catzs is not NULL
* \li zonep is not NULL, *zonep is NULL
* \li name is not NULL
*
*/
dns_name_t *
dns_catz_zone_getname(dns_catz_zone_t *zone);
/*%<
* Get catalog zone name
*
* Requires:
* \li zone is not NULL
*/
dns_catz_options_t *
dns_catz_zone_getdefoptions(dns_catz_zone_t *zone);
/*%<
* Get default member zone options for catalog zone 'zone'
*
* Requires:
* \li zone is not NULL
*/
void
dns_catz_zone_resetdefoptions(dns_catz_zone_t *zone);
/*%<
* Reset the default member zone options for catalog zone 'zone' to
* the default values.
*
* Requires:
* \li zone is not NULL
*/
isc_result_t
dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone);
/*%<
* Merge 'newzone' into 'target', calling addzone/delzone/modzone
* (from zone->catzs->zmm) for appropriate member zones.
*
* Requires:
* \li orig is not NULL
* \li newzone is not NULL, *newzone is not NULL
*
*/
isc_result_t
dns_catz_update_process(dns_catz_zones_t *catzs, dns_catz_zone_t *zone,
dns_name_t *src_name, dns_rdataset_t *rdataset);
/*%<
* Process a single rdataset from a catalog zone 'zone' update, src_name is the
* record name.
*
* Requires:
* \li catzs is not NULL
* \li zone is not NULL
* \li src_name is not NULL
* \li rdataset is valid
*/
isc_result_t
dns_catz_generate_masterfilename(dns_catz_zone_t *zone, dns_catz_entry_t *entry,
isc_buffer_t **buffer);
/*%<
* Generate master file name and put it into *buffer (might be reallocated).
* The general format of the file name is:
* __catz__catalog.zone.name__member_zone_name.db
* But if it's too long it's shortened to:
* __catz__unique_hash_generated_from_the_above.db
*
* Requires:
* \li zone is not NULL
* \li entry is not NULL
* \li buffer is not NULL and *buffer is not NULL
*/
isc_result_t
dns_catz_generate_zonecfg(dns_catz_zone_t *zone, dns_catz_entry_t *entry,
isc_buffer_t **buf);
/*%<
* Generate a zone config entry (in text form) from dns_catz_entry and puts
* it into *buf. buf might be reallocated.
*
* Requires:
* \li zone is not NULL
* \li entry is not NULL
* \li buf is not NULL
* \li *buf is NULL
*
*/
/* Methods provided by named to dynamically modify the member zones */
/* xxxwpk TODO config! */
struct dns_catz_zonemodmethods {
isc_result_t (*addzone)(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata);
isc_result_t (*modzone)(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata);
isc_result_t (*delzone)(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
dns_view_t *view, isc_taskmgr_t *task, void *udata);
void * udata;
};
isc_result_t
dns_catz_new_zones(dns_catz_zones_t **catzsp, dns_catz_zonemodmethods_t *zmm,
isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_timermgr_t *timermgr);
/*%<
* Allocate a new catz_zones object, a collection storing all catalog zones
* for a view.
*
* Requires:
* \li catzsp is not NULL, *catzsp is NULL
* \li zmm is not NULL
*
*/
isc_result_t
dns_catz_add_zone(dns_catz_zones_t *catzs, const dns_name_t *name,
dns_catz_zone_t **catzp);
/*%<
* Allocate a new catz named 'name' and put it in 'catzs' collection.
*
* Requires:
* \li catzs is not NULL
* \li name is not NULL
* \li zonep is not NULL, *zonep is NULL
*
*/
dns_catz_zone_t *
dns_catz_get_zone(dns_catz_zones_t *catzs, const dns_name_t *name);
/*%<
* Returns a zone named 'name' from collection 'catzs'
*
* Requires:
* \li catzs is not NULL
* \li name is not NULL
*/
void
dns_catz_catzs_attach(dns_catz_zones_t *catzs, dns_catz_zones_t **catzsp);
/*%<
* Attach 'catzs' to 'catzsp'
*
* Requires:
* \li catzs is not NULL
* \li catzsp is not NULL, *catzsp is NULL
*/
void
dns_catz_catzs_detach(dns_catz_zones_t **catzsp);
/*%<
* Detach 'catzsp', free if no further references
*
* Requires:
* \li catzsp is not NULL, *catzsp is not NULL
*/
void
dns_catz_catzs_set_view(dns_catz_zones_t *catzs, dns_view_t *view);
/*%<
* Set a view for catzs
*
* Requires:
* \li catzs is not NULL
* \li catzs->view is NULL or catzs->view == view
*/
isc_result_t
dns_catz_dbupdate_callback(dns_db_t *db, void *fn_arg);
/*%<
* Callback for update of catalog zone database.
* If there was no catalog zone update recently it launches an
* update_taskaction immediately.
* If there was an update recently it schedules update_taskaction for some time
* in the future.
* If there is an update scheduled it replaces old db version with a new one.
*
* Requires:
* \li db is a valid database
* \li fn_arg is not NULL (casted to dns_catz_zones_t*)
*/
void
dns_catz_update_taskaction(isc_task_t *task, isc_event_t *event);
/*%<
* Task that launches dns_catz_update_from_db
*
* Requires:
* \li event is not NULL
*/
void
dns_catz_update_from_db(dns_db_t *db, dns_catz_zones_t *catzs);
/*%<
* Process an updated database for a catalog zone.
* It creates a new catz, iterates over database to fill it with content, and
* then merges new catz into old catz.
*
* Requires:
* \li db is a valid DB
* \li catzs is not NULL
*
*/
void
dns_catz_prereconfig(dns_catz_zones_t *catzs);
/*%<
* Called before reconfig, clears 'active' flag on all the zones in set
*
* Requires:
* \li catzs is not NULL
*
*/
void
dns_catz_postreconfig(dns_catz_zones_t *catzs);
/*%<
* Called after reconfig, walks through all zones in set, removes those
* inactive and force reload of those with changed configuration.
*
* Requires:
* \li catzs is not NULL
*/
isc_result_t
dns_catz_get_iterator(dns_catz_zone_t *catz, isc_ht_iter_t **itp);
/*%<
* Get the hashtable iterator on catalog zone members, point '*itp' to it.
*
* Returns:
* \li #ISC_R_SUCCESS -- success
* \li Any other value -- failure
*/
ISC_LANG_ENDDECLS
#endif /* DNS_CATZ_H_ */

View File

@ -203,6 +203,9 @@ typedef isc_result_t
unsigned int argc, char *argv[], void *driverarg,
dns_db_t **dbp);
typedef isc_result_t
(*dns_dbupdate_callback_t)(dns_db_t *db, void *fn_arg);
#define DNS_DB_MAGIC ISC_MAGIC('D','N','S','D')
#define DNS_DB_VALID(db) ISC_MAGIC_VALID(db, DNS_DB_MAGIC)
@ -216,19 +219,26 @@ typedef isc_result_t
* invariants.
*/
struct dns_db {
unsigned int magic;
unsigned int impmagic;
dns_dbmethods_t * methods;
isc_uint16_t attributes;
dns_rdataclass_t rdclass;
dns_name_t origin;
isc_ondestroy_t ondest;
isc_mem_t * mctx;
unsigned int magic;
unsigned int impmagic;
dns_dbmethods_t * methods;
isc_uint16_t attributes;
dns_rdataclass_t rdclass;
dns_name_t origin;
isc_ondestroy_t ondest;
isc_mem_t * mctx;
ISC_LIST(dns_dbonupdatelistener_t) update_listeners;
};
#define DNS_DBATTR_CACHE 0x01
#define DNS_DBATTR_STUB 0x02
struct dns_dbonupdatelistener {
dns_dbupdate_callback_t onupdate;
void * onupdate_arg;
ISC_LINK(dns_dbonupdatelistener_t) link;
};
/*@{*/
/*%
* Options that can be specified for dns_db_find().
@ -1624,6 +1634,35 @@ dns_db_rpz_ready(dns_db_t *db);
* Finish loading a response policy zone.
*/
isc_result_t
dns_db_updatenotify_register(dns_db_t *db,
dns_dbupdate_callback_t fn,
void *fn_arg);
/*%<
* Register a notify-on-update callback function to a database.
*
* Requires:
*
* \li 'db' is a valid database
* \li 'db' does not have an update callback registered
* \li 'fn' is not NULL
*
*/
isc_result_t
dns_db_updatenotify_unregister(dns_db_t *db,
dns_dbupdate_callback_t fn,
void *fn_arg);
/*%<
* Unregister a notify-on-update callback.
*
* Requires:
*
* \li 'db' is a valid database
* \li 'db' has update callback registered
*
*/
ISC_LANG_ENDDECLS
#endif /* DNS_DB_H */

View File

@ -80,6 +80,10 @@
#define DNS_EVENT_KEYDONE (ISC_EVENTCLASS_DNS + 50)
#define DNS_EVENT_SETNSEC3PARAM (ISC_EVENTCLASS_DNS + 51)
#define DNS_EVENT_SETSERIAL (ISC_EVENTCLASS_DNS + 52)
#define DNS_EVENT_CATZUPDATED (ISC_EVENTCLASS_DNS + 53)
#define DNS_EVENT_CATZADDZONE (ISC_EVENTCLASS_DNS + 54)
#define DNS_EVENT_CATZMODZONE (ISC_EVENTCLASS_DNS + 55)
#define DNS_EVENT_CATZDELZONE (ISC_EVENTCLASS_DNS + 56)
#define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0)
#define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535)

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef DNS_IPKEYLIST_H
#define DNS_IPKEYLIST_H 1
#include <isc/types.h>
#include <dns/types.h>
/*%
* A structure holding a list of addresses, dscps and keys. Used to
* store masters for a slave zone, created by parsing config options.
*/
struct dns_ipkeylist {
isc_sockaddr_t *addrs;
isc_dscp_t *dscps;
dns_name_t **keys;
isc_uint32_t count;
};
void
dns_ipkeylist_clear(isc_mem_t *mctx, dns_ipkeylist_t *ipkl);
/*%<
* Free `ipkl` contents using `mctx`.
*
* After this call, `ipkl` is a freshly cleared structure with all
* pointers set to `NULL` and count set to 0.
*
* Requires:
*\li 'mctx' to be a valid memory context.
*\li 'ipkl' to be non NULL and have its members `addrs` and `keys`
* allocated. 'dscps' might be NULL.
*/
void
dns_ipkeylist_copy(isc_mem_t *mctx, const dns_ipkeylist_t *src,
dns_ipkeylist_t *dst);
/*%<
* Deep copy `src` into empty `dst`, allocating `dst`'s contents.
*
* Requires:
*\li 'mctx' to be a valid memory context.
*\li 'src' to be non NULL
*\li 'dst' to be non NULL and point to an empty \ref dns_ipkeylist_t
* with all pointers set to `NULL` and count set to 0.
*/
#endif

View File

@ -391,7 +391,7 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep);
*/
isc_result_t
dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
dns_rbt_findname(dns_rbt_t *rbt, const dns_name_t *name, unsigned int options,
dns_name_t *foundname, void **data);
/*%<
* Get the data pointer associated with 'name'.
@ -430,7 +430,7 @@ dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
*/
isc_result_t
dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
dns_rbt_findnode(dns_rbt_t *rbt, const dns_name_t *name, dns_name_t *foundname,
dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
unsigned int options, dns_rbtfindcallback_t callback,
void *callback_arg);

View File

@ -45,6 +45,12 @@ typedef struct dns_adbfind dns_adbfind_t;
typedef ISC_LIST(dns_adbfind_t) dns_adbfindlist_t;
typedef struct dns_badcache dns_badcache_t;
typedef struct dns_byaddr dns_byaddr_t;
typedef struct dns_catz_zonemodmethods dns_catz_zonemodmethods_t;
typedef struct dns_catz_entry_options dns_catz_options_t;
typedef struct dns_catz_entry dns_catz_entry_t;
typedef struct dns_catz_zone dns_catz_zone_t;
typedef struct dns_catz_changed dns_catz_changed_t;
typedef struct dns_catz_zones dns_catz_zones_t;
typedef struct dns_client dns_client_t;
typedef void dns_clientrestrans_t;
typedef void dns_clientreqtrans_t;
@ -57,6 +63,7 @@ typedef struct dns_dbimplementation dns_dbimplementation_t;
typedef struct dns_dbiterator dns_dbiterator_t;
typedef void dns_dbload_t;
typedef void dns_dbnode_t;
typedef struct dns_dbonupdatelistener dns_dbonupdatelistener_t;
typedef struct dns_dbtable dns_dbtable_t;
typedef void dns_dbversion_t;
typedef struct dns_dlzimplementation dns_dlzimplementation_t;
@ -146,6 +153,7 @@ typedef struct dns_zone dns_zone_t;
typedef ISC_LIST(dns_zone_t) dns_zonelist_t;
typedef struct dns_zonemgr dns_zonemgr_t;
typedef struct dns_zt dns_zt_t;
typedef struct dns_ipkeylist dns_ipkeylist_t;
/*
* If we are not using GSSAPI, define the types we use as opaque types here.

View File

@ -70,6 +70,7 @@
#include <isc/stdtime.h>
#include <dns/acl.h>
#include <dns/catz.h>
#include <dns/clientinfo.h>
#include <dns/dnstap.h>
#include <dns/fixedname.h>
@ -178,6 +179,7 @@ struct dns_view {
dns_dns64list_t dns64;
unsigned int dns64cnt;
dns_rpz_zones_t *rpzs;
dns_catz_zones_t *catzs;
dns_dlzdblist_t dlz_searched;
dns_dlzdblist_t dlz_unsearched;
isc_uint32_t fail_ttl;

View File

@ -15,8 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id$ */
#ifndef DNS_ZONE_H
#define DNS_ZONE_H 1
@ -32,6 +30,7 @@
#include <isc/lang.h>
#include <isc/rwlock.h>
#include <dns/catz.h>
#include <dns/master.h>
#include <dns/masterdump.h>
#include <dns/rdatastruct.h>
@ -2393,6 +2392,30 @@ dns_zone_rpz_enable_db(dns_zone_t *zone, dns_db_t *db);
dns_rpz_num_t
dns_zone_get_rpz_num(dns_zone_t *zone);
void
dns_zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs);
/*%<
* Enable zone as catalog zone.
*
* Requires:
*
* \li 'zone' is a valid zone object
* \li 'catzs' is not NULL
* \li prior to calling, zone->catzs is NULL or is equal to 'catzs'
*/
void
dns_zone_catz_enable_db(dns_zone_t *zone, dns_db_t *db);
/*%<
* If 'zone' is a catalog zone, then set up a notify-on-update trigger
* in its database. (If not a catalog zone, this function has no effect.)
*
* Requires:
*
* \li 'zone' is a valid zone object
* \li 'db' is not NULL
*/
void
dns_zone_setstatlevel(dns_zone_t *zone, dns_zonestat_level_t level);

View File

@ -90,7 +90,7 @@ dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone);
*/
isc_result_t
dns_zt_find(dns_zt_t *zt, dns_name_t *name, unsigned int options,
dns_zt_find(dns_zt_t *zt, const dns_name_t *name, unsigned int options,
dns_name_t *foundname, dns_zone_t **zone);
/*%<
* Find the best match for 'name' in 'zt'. If foundname is non NULL

92
lib/dns/ipkeylist.c Normal file
View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <isc/mem.h>
#include <isc/sockaddr.h>
#include <isc/util.h>
#include <dns/ipkeylist.h>
#include <dns/name.h>
void
dns_ipkeylist_clear(isc_mem_t *mctx, dns_ipkeylist_t *ipkl) {
isc_uint32_t i;
REQUIRE(ipkl != NULL);
REQUIRE(ipkl->addrs != NULL);
REQUIRE(ipkl->keys != NULL);
if (ipkl->count == 0)
return;
isc_mem_put(mctx, ipkl->addrs, ipkl->count * sizeof(isc_sockaddr_t));
if (ipkl->dscps != NULL)
isc_mem_put(mctx, ipkl->dscps,
ipkl->count * sizeof(isc_dscp_t));
for (i = 0; i < ipkl->count; i++) {
if (ipkl->keys[i] == NULL)
continue;
if (dns_name_dynamic(ipkl->keys[i]))
dns_name_free(ipkl->keys[i], mctx);
isc_mem_put(mctx, ipkl->keys[i], sizeof(dns_name_t));
}
isc_mem_put(mctx, ipkl->keys, ipkl->count * sizeof(dns_name_t *));
ipkl->count = 0;
ipkl->addrs = NULL;
ipkl->dscps = NULL;
ipkl->keys = NULL;
}
void
dns_ipkeylist_copy(isc_mem_t *mctx, const dns_ipkeylist_t *src,
dns_ipkeylist_t *dst)
{
isc_uint32_t i;
REQUIRE(dst != NULL);
REQUIRE(dst->count == 0 &&
dst->addrs == NULL && dst->keys == NULL && dst->dscps == NULL);
if (src->count == 0)
return;
dst->count = src->count;
dst->addrs = isc_mem_get(mctx,
src->count * sizeof(isc_sockaddr_t));
memmove(dst->addrs, src->addrs,
src->count * sizeof(isc_sockaddr_t));
if (src->dscps != NULL) {
dst->dscps = isc_mem_get(mctx,
src->count * sizeof(isc_dscp_t));
memmove(dst->dscps, src->dscps,
src->count * sizeof(isc_dscp_t));
}
if (src->keys != NULL) {
dst->keys = isc_mem_get(mctx, src->count * sizeof(dns_name_t *));
for (i = 0; i < src->count; i++) {
if (src->keys[i] != NULL) {
dst->keys[i] = isc_mem_get(mctx,
sizeof(dns_name_t));
dns_name_dup(src->keys[i], mctx, dst->keys[i]);
} else {
dst->keys[i] = NULL;
}
}
}
}

View File

@ -1566,9 +1566,13 @@ dns_name_totext2(const dns_name_t *name, unsigned int options,
if (nlen != 0 && trem == 0)
return (ISC_R_NOSPACE);
if (!saw_root || omit_final_dot)
if (!saw_root || omit_final_dot) {
trem++;
tdata--;
}
if (trem > 0) {
*tdata = 0;
}
isc_buffer_add(target, tlen - trem);
#ifdef ISC_PLATFORM_USETHREADS

View File

@ -1457,7 +1457,7 @@ dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data) {
* Find the node for "name" in the tree of trees.
*/
isc_result_t
dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
dns_rbt_findnode(dns_rbt_t *rbt, const dns_name_t *name, dns_name_t *foundname,
dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
unsigned int options, dns_rbtfindcallback_t callback,
void *callback_arg)
@ -1988,7 +1988,7 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
* Get the data pointer associated with 'name'.
*/
isc_result_t
dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
dns_rbt_findname(dns_rbt_t *rbt, const dns_name_t *name, unsigned int options,
dns_name_t *foundname, void **data) {
dns_rbtnode_t *node = NULL;
isc_result_t result;

View File

@ -1159,6 +1159,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {
char buf[DNS_NAME_FORMATSIZE];
dns_rbt_t **treep;
isc_time_t start;
dns_dbonupdatelistener_t *listener, *listener_next;
if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in)
overmem((dns_db_t *)rbtdb, (isc_boolean_t)-1);
@ -1317,6 +1318,16 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {
isc_file_munmap(rbtdb->mmap_location,
(size_t) rbtdb->mmap_size);
for (listener = ISC_LIST_HEAD(rbtdb->common.update_listeners);
listener != NULL;
listener = listener_next)
{
listener_next = ISC_LIST_NEXT(listener, link);
ISC_LIST_UNLINK(rbtdb->common.update_listeners, listener, link);
isc_mem_put(rbtdb->common.mctx, listener,
sizeof(dns_dbonupdatelistener_t));
}
isc_mem_putanddetach(&rbtdb->common.mctx, rbtdb, sizeof(*rbtdb));
isc_ondestroy_notify(&ondest, rbtdb);
}
@ -8166,6 +8177,8 @@ dns_rbtdb_create
rbtdb->common.rdclass = rdclass;
rbtdb->common.mctx = NULL;
ISC_LIST_INIT(rbtdb->common.update_listeners);
result = RBTDB_INITLOCK(&rbtdb->lock);
if (result != ISC_R_SUCCESS)
goto cleanup_rbtdb;

View File

@ -229,6 +229,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->v6_aaaa = dns_aaaa_ok;
view->aaaa_acl = NULL;
view->rpzs = NULL;
view->catzs = NULL;
dns_fixedname_init(&view->dlv_fixed);
view->managed_keys = NULL;
view->redirect = NULL;
@ -379,6 +380,8 @@ destroy(dns_view_t *view) {
dns_rrl_view_destroy(view);
if (view->rpzs != NULL)
dns_rpz_detach_rpzs(&view->rpzs);
if (view->catzs != NULL)
dns_catz_catzs_detach(&view->catzs);
for (dlzdb = ISC_LIST_HEAD(view->dlz_searched);
dlzdb != NULL;
dlzdb = ISC_LIST_HEAD(view->dlz_searched)) {
@ -578,6 +581,9 @@ view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
if (view->flush)
dns_zone_flush(rdzone);
}
if (view->catzs != NULL) {
dns_catz_catzs_detach(&view->catzs);
}
done = all_done(view);
UNLOCK(&view->lock);

View File

@ -109,6 +109,28 @@ dns_cache_setcachesize
dns_cache_setcleaninginterval
dns_cache_setfilename
dns_cache_updatestats
dns_catz_catzs_attach
dns_catz_catzs_detach
dns_catz_catzs_set_view
dns_catz_dbupdate_callback
dns_catz_entry_attach
dns_catz_entry_cmp
dns_catz_entry_detach
dns_catz_entry_getname
dns_catz_entry_validate
dns_catz_get_iterator
dns_catz_get_zone
dns_catz_options_clear
dns_catz_options_init
dns_catz_postreconfig
dns_catz_prereconfig
dns_catz_update_from_db
dns_catz_update_taskaction
dns_catz_zone_attach
dns_catz_zone_detach
dns_catz_zone_getdefoptions
dns_catz_zone_getname
dns_catz_zones_merge
dns_cert_fromtext
dns_cert_totext
dns_client_addtrustedkey
@ -209,6 +231,8 @@ dns_db_settask
dns_db_subtractrdataset
dns_db_transfernode
dns_db_unregister
dns_db_updatenotify_register
dns_db_updatenotify_unregister
dns_dbiterator_current
dns_dbiterator_destroy
dns_dbiterator_first

View File

@ -30,6 +30,7 @@
#include <isc/util.h>
#include <dns/callbacks.h>
#include <dns/catz.h>
#include <dns/db.h>
#include <dns/diff.h>
#include <dns/events.h>
@ -279,8 +280,10 @@ axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp) {
xfr->rdclass,
0, NULL, /* XXX guess */
dbp);
if (result == ISC_R_SUCCESS)
if (result == ISC_R_SUCCESS) {
dns_zone_rpz_enable_db(xfr->zone, *dbp);
dns_zone_catz_enable_db(xfr->zone, *dbp);
}
return (result);
}

View File

@ -43,6 +43,7 @@
#include <dns/acl.h>
#include <dns/adb.h>
#include <dns/callbacks.h>
#include <dns/catz.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
#include <dns/dlz.h>
@ -380,6 +381,11 @@ struct dns_zone {
dns_rpz_zones_t *rpzs;
dns_rpz_num_t rpz_num;
/*%
* catalog zone data
*/
dns_catz_zones_t *catzs;
/*%
* Serial number update method.
*/
@ -1036,6 +1042,9 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->automatic = ISC_FALSE;
zone->rpzs = NULL;
zone->rpz_num = DNS_RPZ_INVALID_NUM;
zone->catzs = NULL;
ISC_LIST_INIT(zone->forwards);
zone->raw = NULL;
zone->secure = NULL;
@ -1170,6 +1179,9 @@ zone_free(dns_zone_t *zone) {
dns_rpz_detach_rpzs(&zone->rpzs);
zone->rpz_num = DNS_RPZ_INVALID_NUM;
}
if (zone->catzs != NULL) {
dns_catz_catzs_detach(&zone->catzs);
}
zone_freedbargs(zone);
RUNTIME_CHECK(dns_zone_setmasterswithkeys(zone, NULL, NULL, 0)
== ISC_R_SUCCESS);
@ -1748,6 +1760,34 @@ dns_zone_rpz_enable_db(dns_zone_t *zone, dns_db_t *db) {
}
}
void
dns_zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(catzs != NULL);
LOCK_ZONE(zone);
INSIST(zone->catzs == NULL || zone->catzs == catzs);
dns_catz_catzs_set_view(catzs, zone->view);
if (zone->catzs == NULL)
dns_catz_catzs_attach(catzs, &zone->catzs);
UNLOCK_ZONE(zone);
}
/*
* If a zone is a catalog zone, attach it to update notification in database.
*/
void
dns_zone_catz_enable_db(dns_zone_t *zone, dns_db_t *db) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(db != NULL);
if (zone->catzs != NULL) {
dns_db_updatenotify_register(db, dns_catz_dbupdate_callback,
zone->catzs);
}
}
static isc_boolean_t
zone_touched(dns_zone_t *zone) {
isc_result_t result;
@ -2344,6 +2384,7 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
unsigned int options;
dns_zone_rpz_enable_db(zone, db);
dns_zone_catz_enable_db(zone, db);
options = get_master_options(zone);
if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS))
options |= DNS_MASTER_MANYERRORS;

View File

@ -155,7 +155,7 @@ dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) {
}
isc_result_t
dns_zt_find(dns_zt_t *zt, dns_name_t *name, unsigned int options,
dns_zt_find(dns_zt_t *zt, const dns_name_t *name, unsigned int options,
dns_name_t *foundname, dns_zone_t **zonep)
{
isc_result_t result;

View File

@ -57,8 +57,8 @@ OBJS = @ISC_EXTRA_OBJS@ @ISC_PK11_O@ @ISC_PK11_RESULT_O@ \
aes.@O@ assertions.@O@ backtrace.@O@ base32.@O@ base64.@O@ \
bind9.@O@ buffer.@O@ bufferlist.@O@ \
commandline.@O@ counter.@O@ crc64.@O@ error.@O@ event.@O@ \
hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \
httpd.@O@ inet_aton.@O@ iterated_hash.@O@ \
hash.@O@ ht.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ \
hmacsha.@O@ httpd.@O@ inet_aton.@O@ iterated_hash.@O@ \
lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
md5.@O@ mem.@O@ mutexblock.@O@ \
netaddr.@O@ netscope.@O@ pool.@O@ ondestroy.@O@ \
@ -77,8 +77,8 @@ CHACHASRCS = chacha_private.h
SRCS = @ISC_EXTRA_SRCS@ @ISC_PK11_C@ @ISC_PK11_RESULT_C@ \
aes.c assertions.c backtrace.c base32.c base64.c bind9.c \
buffer.c bufferlist.c commandline.c counter.c crc64.c \
error.c event.c heap.c hex.c hmacmd5.c hmacsha.c \
httpd.c inet_aton.c iterated_hash.c \
error.c event.c hash.c ht.c heap.c hex.c hmacmd5.c \
hmacsha.c httpd.c inet_aton.c iterated_hash.c \
lex.c lfsr.c lib.c log.c \
md5.c mem.c mutexblock.c \
netaddr.c netscope.c pool.c ondestroy.c \

View File

@ -60,6 +60,7 @@ isc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length) {
*/
REQUIRE(b->length <= length);
REQUIRE(base != NULL);
REQUIRE(b->autore = ISC_FALSE);
(void)memmove(base, b->base, b->length);
b->base = base;
@ -79,6 +80,13 @@ isc__buffer_invalidate(isc_buffer_t *b) {
ISC__BUFFER_INVALIDATE(b);
}
void
isc_buffer_setautorealloc(isc_buffer_t *b, isc_boolean_t enable) {
REQUIRE(ISC_BUFFER_VALID(b));
REQUIRE(b->mctx != NULL);
b->autore = enable;
}
void
isc__buffer_region(isc_buffer_t *b, isc_region_t *r) {
/*
@ -279,8 +287,13 @@ isc_buffer_getuint8(isc_buffer_t *b) {
void
isc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val) {
isc_result_t result;
REQUIRE(ISC_BUFFER_VALID(b));
REQUIRE(b->used + 1 <= b->length);
if (b->autore) {
result = isc_buffer_reserve(&b, 1);
REQUIRE(result == ISC_R_SUCCESS);
}
REQUIRE(isc_buffer_availablelength(b) >= 1);
ISC__BUFFER_PUTUINT8(b, val);
}
@ -308,16 +321,26 @@ isc_buffer_getuint16(isc_buffer_t *b) {
void
isc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val) {
isc_result_t result;
REQUIRE(ISC_BUFFER_VALID(b));
REQUIRE(b->used + 2 <= b->length);
if (b->autore) {
result = isc_buffer_reserve(&b, 2);
REQUIRE(result == ISC_R_SUCCESS);
}
REQUIRE(isc_buffer_availablelength(b) >= 2);
ISC__BUFFER_PUTUINT16(b, val);
}
void
isc__buffer_putuint24(isc_buffer_t *b, isc_uint32_t val) {
isc_result_t result;
REQUIRE(ISC_BUFFER_VALID(b));
REQUIRE(b->used + 3 <= b->length);
if (b->autore) {
result = isc_buffer_reserve(&b, 3);
REQUIRE(result == ISC_R_SUCCESS);
}
REQUIRE(isc_buffer_availablelength(b) >= 3);
ISC__BUFFER_PUTUINT24(b, val);
}
@ -347,8 +370,13 @@ isc_buffer_getuint32(isc_buffer_t *b) {
void
isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val) {
isc_result_t result;
REQUIRE(ISC_BUFFER_VALID(b));
REQUIRE(b->used + 4 <= b->length);
if (b->autore == ISC_TRUE) {
result = isc_buffer_reserve(&b, 4);
REQUIRE(result == ISC_R_SUCCESS);
}
REQUIRE(isc_buffer_availablelength(b) >= 4);
ISC__BUFFER_PUTUINT32(b, val);
}
@ -380,11 +408,16 @@ isc_buffer_getuint48(isc_buffer_t *b) {
void
isc__buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) {
isc_result_t result;
isc_uint16_t valhi;
isc_uint32_t vallo;
REQUIRE(ISC_BUFFER_VALID(b));
REQUIRE(b->used + 6 <= b->length);
if (b->autore == ISC_TRUE) {
result = isc_buffer_reserve(&b, 6);
REQUIRE(result == ISC_R_SUCCESS);
}
REQUIRE(isc_buffer_availablelength(b) >= 6);
valhi = (isc_uint16_t)(val >> 32);
vallo = (isc_uint32_t)(val & 0xFFFFFFFF);
@ -396,8 +429,13 @@ void
isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
unsigned int length)
{
isc_result_t result;
REQUIRE(ISC_BUFFER_VALID(b));
REQUIRE(b->used + length <= b->length);
if (b->autore == ISC_TRUE) {
result = isc_buffer_reserve(&b, length);
REQUIRE(result == ISC_R_SUCCESS);
}
REQUIRE(isc_buffer_availablelength(b) >= length);
ISC__BUFFER_PUTMEM(b, base, length);
}
@ -406,6 +444,7 @@ void
isc__buffer_putstr(isc_buffer_t *b, const char *source) {
unsigned int l;
unsigned char *cp;
isc_result_t result;
REQUIRE(ISC_BUFFER_VALID(b));
REQUIRE(source != NULL);
@ -414,8 +453,11 @@ isc__buffer_putstr(isc_buffer_t *b, const char *source) {
* Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once.
*/
l = strlen(source);
REQUIRE(l <= isc_buffer_availablelength(b));
if (b->autore == ISC_TRUE) {
result = isc_buffer_reserve(&b, l);
REQUIRE(result == ISC_R_SUCCESS);
}
REQUIRE(isc_buffer_availablelength(b) >= l);
cp = isc_buffer_used(b);
memmove(cp, source, l);
@ -448,16 +490,21 @@ isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
unsigned int length)
{
isc_buffer_t *dbuf;
unsigned char * bdata;
REQUIRE(dynbuffer != NULL);
REQUIRE(*dynbuffer == NULL);
dbuf = isc_mem_get(mctx, length + sizeof(isc_buffer_t));
dbuf = isc_mem_get(mctx, sizeof(isc_buffer_t));
if (dbuf == NULL)
return (ISC_R_NOMEMORY);
isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t),
length);
bdata = isc_mem_get(mctx, length);
if (bdata == NULL) {
isc_mem_put(mctx, dbuf, sizeof(isc_buffer_t));
return (ISC_R_NOMEMORY);
}
isc_buffer_init(dbuf, bdata, length);
dbuf->mctx = mctx;
ENSURE(ISC_BUFFER_VALID(dbuf));
@ -469,7 +516,7 @@ isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
isc_result_t
isc_buffer_reallocate(isc_buffer_t **dynbuffer, unsigned int length) {
isc_buffer_t *dbuf;
unsigned char *bdata;
REQUIRE(dynbuffer != NULL);
REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
@ -483,18 +530,16 @@ isc_buffer_reallocate(isc_buffer_t **dynbuffer, unsigned int length) {
* it doesn't remap pages, but does ordinary copy. So is
* isc_mem_reallocate(), which has additional issues.
*/
dbuf = isc_mem_get((*dynbuffer)->mctx, length + sizeof(isc_buffer_t));
if (dbuf == NULL)
bdata = isc_mem_get((*dynbuffer)->mctx, length);
if (bdata == NULL)
return (ISC_R_NOMEMORY);
memmove(dbuf, *dynbuffer, (*dynbuffer)->length + sizeof(isc_buffer_t));
isc_mem_put(dbuf->mctx, *dynbuffer,
(*dynbuffer)->length + sizeof(isc_buffer_t));
memmove(bdata, (*dynbuffer)->base, (*dynbuffer)->length);
isc_mem_put((*dynbuffer)->mctx, (*dynbuffer)->base,
(*dynbuffer)->length);
dbuf->base = ((unsigned char *)dbuf) + sizeof(isc_buffer_t);
dbuf->length = length;
*dynbuffer = dbuf;
(*dynbuffer)->base = bdata;
(*dynbuffer)->length = length;
return (ISC_R_SUCCESS);
}
@ -530,7 +575,6 @@ isc_buffer_reserve(isc_buffer_t **dynbuffer, unsigned int size) {
void
isc_buffer_free(isc_buffer_t **dynbuffer) {
unsigned int real_length;
isc_buffer_t *dbuf;
isc_mem_t *mctx;
@ -540,11 +584,10 @@ isc_buffer_free(isc_buffer_t **dynbuffer) {
dbuf = *dynbuffer;
*dynbuffer = NULL; /* destroy external reference */
real_length = dbuf->length + sizeof(isc_buffer_t);
mctx = dbuf->mctx;
dbuf->mctx = NULL;
isc_buffer_invalidate(dbuf);
isc_mem_put(mctx, dbuf, real_length);
isc_mem_put(mctx, dbuf->base, dbuf->length);
isc_buffer_invalidate(dbuf);
isc_mem_put(mctx, dbuf, sizeof(isc_buffer_t));
}

339
lib/isc/ht.c Normal file
View File

@ -0,0 +1,339 @@
/*
* Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include <isc/hash.h>
#include <isc/ht.h>
#include <isc/types.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/result.h>
#include <isc/util.h>
typedef struct isc_ht_node isc_ht_node_t;
#define ISC_HT_MAGIC ISC_MAGIC('H', 'T', 'a', 'b')
#define ISC_HT_VALID(ht) ISC_MAGIC_VALID(ht, ISC_HT_MAGIC)
struct isc_ht_node {
void *value;
isc_ht_node_t *next;
size_t keysize;
unsigned char key[];
};
struct isc_ht {
unsigned int magic;
isc_mem_t *mctx;
size_t size;
size_t mask;
unsigned int count;
isc_ht_node_t **table;
};
struct isc_ht_iter {
isc_ht_t *ht;
isc_uint32_t i;
isc_ht_node_t *cur;
};
isc_result_t
isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, isc_uint8_t bits) {
isc_ht_t *ht = NULL;
isc_uint32_t i;
REQUIRE(htp != NULL && *htp == NULL);
REQUIRE(mctx != NULL);
REQUIRE(bits >= 1 && bits <= (sizeof(size_t)*8 - 1));
ht = isc_mem_get(mctx, sizeof(struct isc_ht));
if (ht == NULL) {
return (ISC_R_NOMEMORY);
}
ht->mctx = NULL;
isc_mem_attach(mctx, &ht->mctx);
ht->size = (1<<bits);
ht->mask = (1<<bits)-1;
ht->count = 0;
ht->table = isc_mem_get(ht->mctx, ht->size * sizeof(isc_ht_node_t*));
if (ht->table == NULL) {
isc_mem_putanddetach(&ht->mctx, ht, sizeof(struct isc_ht));
return (ISC_R_NOMEMORY);
}
for (i = 0; i < ht->size; i++) {
ht->table[i] = NULL;
}
ht->magic = ISC_HT_MAGIC;
*htp = ht;
return (ISC_R_SUCCESS);
}
void
isc_ht_destroy(isc_ht_t **htp) {
isc_ht_t *ht;
isc_uint32_t i;
REQUIRE(htp != NULL);
ht = *htp;
REQUIRE(ISC_HT_VALID(ht));
ht->magic = 0;
for (i = 0; i < ht->size; i++) {
isc_ht_node_t *node = ht->table[i];
while (node != NULL) {
isc_ht_node_t *next = node->next;
ht->count--;
isc_mem_put(ht->mctx, node,
sizeof(isc_ht_node_t) + node->keysize);
node = next;
}
}
INSIST(ht->count == 0);
isc_mem_put(ht->mctx, ht->table, ht->size * sizeof(isc_ht_node_t*));
isc_mem_putanddetach(&ht->mctx, ht, sizeof(struct isc_ht));
*htp = NULL;
}
isc_result_t
isc_ht_add(isc_ht_t *ht, const unsigned char *key,
isc_uint32_t keysize, void *value)
{
isc_ht_node_t *node;
isc_uint32_t hash;
REQUIRE(ISC_HT_VALID(ht));
REQUIRE(key != NULL && keysize > 0);
hash = isc_hash_function(key, keysize, ISC_TRUE, NULL);
node = ht->table[hash & ht->mask];
while (node != NULL) {
if (keysize == node->keysize &&
memcmp(key, node->key, keysize) == 0)
{
return (ISC_R_EXISTS);
}
node = node->next;
}
node = isc_mem_get(ht->mctx, sizeof(isc_ht_node_t) + keysize);
if (node == NULL) {
return (ISC_R_NOMEMORY);
}
memmove(node->key, key, keysize);
node->keysize = keysize;
node->next = ht->table[hash & ht->mask];
node->value = value;
ht->count++;
ht->table[hash & ht->mask] = node;
return (ISC_R_SUCCESS);
}
isc_result_t
isc_ht_find(const isc_ht_t *ht, const unsigned char *key,
isc_uint32_t keysize, void **valuep)
{
isc_ht_node_t *node;
isc_uint32_t hash;
REQUIRE(ISC_HT_VALID(ht));
REQUIRE(key != NULL && keysize > 0);
REQUIRE(valuep != NULL);
hash = isc_hash_function(key, keysize, ISC_TRUE, NULL);
node = ht->table[hash & ht->mask];
while (node != NULL) {
if (keysize == node->keysize &&
memcmp(key, node->key, keysize) == 0)
{
*valuep = node->value;
return (ISC_R_SUCCESS);
}
node = node->next;
}
return (ISC_R_NOTFOUND);
}
isc_result_t
isc_ht_delete(isc_ht_t *ht, const unsigned char *key, isc_uint32_t keysize) {
isc_ht_node_t *node, *prev;
isc_uint32_t hash;
REQUIRE(ISC_HT_VALID(ht));
REQUIRE(key != NULL && keysize > 0);
prev = NULL;
hash = isc_hash_function(key, keysize, ISC_TRUE, NULL);
node = ht->table[hash & ht->mask];
while (node != NULL) {
if (keysize == node->keysize &&
memcmp(key, node->key, keysize) == 0)
{
if (prev == NULL) {
ht->table[hash & ht->mask] = node->next;
} else {
prev->next = node->next;
}
isc_mem_put(ht->mctx, node,
sizeof(isc_ht_node_t) + node->keysize);
ht->count--;
return (ISC_R_SUCCESS);
}
prev = node;
node = node->next;
}
return (ISC_R_NOTFOUND);
}
isc_result_t
isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) {
isc_ht_iter_t *it;
REQUIRE(ISC_HT_VALID(ht));
REQUIRE(itp != NULL && *itp == NULL);
if (ht->count == 0)
return (ISC_R_NOMORE);
it = isc_mem_get(ht->mctx, sizeof(isc_ht_iter_t));
if (it == NULL)
return (ISC_R_NOMEMORY);
it->ht = ht;
it->i = 0;
it->cur = NULL;
*itp = it;
return (ISC_R_SUCCESS);
}
void
isc_ht_iter_destroy(isc_ht_iter_t **itp) {
isc_ht_iter_t *it;
isc_ht_t *ht;
REQUIRE(itp != NULL && *itp != NULL);
it = *itp;
ht = it->ht;
isc_mem_put(ht->mctx, it, sizeof(isc_ht_iter_t));
*itp = NULL;
}
isc_result_t
isc_ht_iter_first(isc_ht_iter_t *it) {
REQUIRE(it != NULL);
it->i = 0;
while (it->i < it->ht->size && it->ht->table[it->i] == NULL)
it->i++;
if(it->i == it->ht->size)
return (ISC_R_NOMORE);
it->cur = it->ht->table[it->i];
return (ISC_R_SUCCESS);
}
isc_result_t
isc_ht_iter_next(isc_ht_iter_t *it) {
REQUIRE(it != NULL);
REQUIRE(it->cur != NULL);
it->cur = it->cur->next;
if (it->cur == NULL) {
while (it->i < it->ht->size && it->ht->table[it->i] == NULL)
it->i++;
if (it->i < it->ht->size)
return (ISC_R_NOMORE);
it->cur = it->ht->table[it->i];
}
return (ISC_R_SUCCESS);
}
void
isc_ht_iter_current(isc_ht_iter_t *it, void **valuep) {
REQUIRE(it != NULL);
REQUIRE(it->cur != NULL);
*valuep = it->cur->value;
}
unsigned int
isc_ht_count(isc_ht_t *ht) {
REQUIRE(ISC_HT_VALID(ht));
return(ht->count);
}
isc_result_t
isc_ht_walk(isc_ht_t *ht, isc_ht_walkfn walkfn, void *udata) {
isc_uint32_t i;
isc_result_t res;
REQUIRE(ISC_HT_VALID(ht));
for (i = 0; i < ht->size; i++) {
isc_ht_node_t *cur = ht->table[i];
isc_ht_node_t *prev = NULL;
while (cur != NULL) {
if (walkfn == NULL) {
continue;
}
res = walkfn(udata, cur->key, cur->keysize, cur->value);
if (res != ISC_R_SUCCESS && res != ISC_R_EXISTS) {
return (res);
}
if (res == ISC_R_EXISTS) { /* remove this node */
isc_ht_node_t *tmp = cur;
cur = cur->next;
if (prev == NULL) {
ht->table[i] = cur;
} else {
prev->next = cur;
}
isc_mem_put(ht->mctx, tmp,
sizeof(isc_ht_node_t) + tmp->keysize);
ht->count--;
} else {
prev = cur;
cur = cur->next;
}
}
}
return (ISC_R_SUCCESS);
}

View File

@ -184,6 +184,8 @@ struct isc_buffer {
ISC_LINK(isc_buffer_t) link;
/*! private internal elements */
isc_mem_t *mctx;
/* automatically realloc buffer at put* */
isc_boolean_t autore;
};
/***
@ -316,6 +318,16 @@ isc__buffer_invalidate(isc_buffer_t *b);
* calling isc_buffer_init() on it will cause an assertion failure.
*/
void
isc_buffer_setautorealloc(isc_buffer_t *b, isc_boolean_t enable);
/*!<
* \brief Enable or disable autoreallocation on 'b'.
*
* Requires:
*\li 'b' is a valid dynamic buffer (b->mctx != NULL).
*
*/
void
isc__buffer_region(isc_buffer_t *b, isc_region_t *r);
/*!<
@ -530,7 +542,8 @@ isc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val);
* Requires:
*\li 'b' is a valid buffer.
*
*\li The length of the unused region of 'b' is at least 1.
*\li The length of the unused region of 'b' is at least 1
* or the buffer has autoreallocation enabled.
*
* Ensures:
*\li The used pointer in 'b' is advanced by 1.
@ -546,7 +559,8 @@ isc_buffer_getuint16(isc_buffer_t *b);
*
*\li 'b' is a valid buffer.
*
*\li The length of the available region of 'b' is at least 2.
*\li The length of the available region of 'b' is at least 2
* or the buffer has autoreallocation enabled.
*
* Ensures:
*
@ -566,7 +580,8 @@ isc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val);
* Requires:
*\li 'b' is a valid buffer.
*
*\li The length of the unused region of 'b' is at least 2.
*\li The length of the unused region of 'b' is at least 2
* or the buffer has autoreallocation enabled.
*
* Ensures:
*\li The used pointer in 'b' is advanced by 2.
@ -602,7 +617,8 @@ isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val);
* Requires:
*\li 'b' is a valid buffer.
*
*\li The length of the unused region of 'b' is at least 4.
*\li The length of the unused region of 'b' is at least 4
* or the buffer has autoreallocation enabled.
*
* Ensures:
*\li The used pointer in 'b' is advanced by 4.
@ -638,7 +654,8 @@ isc__buffer_putuint48(isc_buffer_t *b, isc_uint64_t val);
* Requires:
*\li 'b' is a valid buffer.
*
*\li The length of the unused region of 'b' is at least 6.
*\li The length of the unused region of 'b' is at least 6
* or the buffer has autoreallocation enabled.
*
* Ensures:
*\li The used pointer in 'b' is advanced by 6.
@ -653,7 +670,8 @@ isc__buffer_putuint24(isc_buffer_t *b, isc_uint32_t val);
* Requires:
*\li 'b' is a valid buffer.
*
* The length of the unused region of 'b' is at least 3.
* The length of the unused region of 'b' is at least 3
* or the buffer has autoreallocation enabled.
*
* Ensures:
*\li The used pointer in 'b' is advanced by 3.
@ -666,7 +684,8 @@ isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
* \brief Copy 'length' bytes of memory at 'base' into 'b'.
*
* Requires:
*\li 'b' is a valid buffer.
*\li 'b' is a valid buffer, and it has at least 'length'
* or the buffer has autoreallocation enabled.
*
*\li 'base' points to 'length' bytes of valid memory.
*
@ -682,7 +701,7 @@ isc__buffer_putstr(isc_buffer_t *b, const char *source);
*
*\li 'source' to be a valid NULL terminated string.
*
*\li strlen(source) <= isc_buffer_available(b)
*\li strlen(source) <= isc_buffer_available(b) || b->mctx != NULL
*/
isc_result_t
@ -738,6 +757,7 @@ ISC_LANG_ENDDECLS
(_b)->mctx = NULL; \
ISC_LINK_INIT(_b, link); \
(_b)->magic = ISC_BUFFER_MAGIC; \
(_b)->autore = ISC_FALSE; \
} while (0)
#define ISC__BUFFER_INITNULL(_b) ISC__BUFFER_INIT(_b, NULL, 0)

View File

@ -19,6 +19,7 @@
#define ISC_HASH_H 1
#include <isc/types.h>
#include <isc/util.h>
/*****
***** Module Info
@ -105,7 +106,8 @@ isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit);
*/
void
isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp);
isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp)
ISC_DEPRECATED;
/*!<
* \brief Attach to a hash object.
*
@ -113,7 +115,8 @@ isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp);
*/
void
isc_hash_ctxdetach(isc_hash_t **hctxp);
isc_hash_ctxdetach(isc_hash_t **hctxp)
ISC_DEPRECATED;
/*!<
* \brief Detach from a hash object.
*
@ -158,10 +161,12 @@ isc_hash_init(void);
/*@{*/
unsigned int
isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key,
unsigned int keylen, isc_boolean_t case_sensitive);
unsigned int keylen, isc_boolean_t case_sensitive)
ISC_DEPRECATED;
unsigned int
isc_hash_calc(const unsigned char *key, unsigned int keylen,
isc_boolean_t case_sensitive);
isc_boolean_t case_sensitive)
ISC_DEPRECATED;
/*!<
* \brief Calculate a hash value.
*
@ -183,7 +188,8 @@ isc_hash_calc(const unsigned char *key, unsigned int keylen,
/*@}*/
void
isc__hash_setvec(const isc_uint16_t *vec);
isc__hash_setvec(const isc_uint16_t *vec)
ISC_DEPRECATED;
/*!<
* \brief Set the contents of the random vector used in hashing.

167
lib/isc/include/isc/ht.h Normal file
View File

@ -0,0 +1,167 @@
/*
* Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* ! \file */
#ifndef ISC_HT_H
#define ISC_HT_H 1
#include <string.h>
#include <isc/types.h>
#include <isc/result.h>
typedef struct isc_ht isc_ht_t;
typedef struct isc_ht_iter isc_ht_iter_t;
/*%
* Initialize hashtable at *htp, using memory context and size of (1<<bits)
*
* Requires:
*\li htp is not NULL
*\li *htp is NULL
*\li mctx is a valid memory context
*\li bits >=1 && bits <=32
*
* Returns:
*\li #ISC_R_NOMEMORY -- not enough memory to create pool
*\li #ISC_R_SUCCESS -- all is well.
*/
isc_result_t
isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, isc_uint8_t bits);
/*%
* Destroy hashtable, freeing everything
*
* Requires:
* \li *htp is valid hashtable
*/
void
isc_ht_destroy(isc_ht_t **htp);
/*%
* Add a node to hashtable, pointed by binary key 'key' of size 'keysize';
* set its value to 'value'
*
* Requires:
*\li ht is a valid hashtable
*
* Returns:
*\li #ISC_R_NOMEMORY -- not enough memory to create pool
*\li #ISC_R_EXISTS -- node of the same key already exists
*\li #ISC_R_SUCCESS -- all is well.
*/
isc_result_t
isc_ht_add(isc_ht_t *ht, const unsigned char *key, isc_uint32_t keysize,
void *value);
/*%
* Find a node matching 'key'/'keysize' in hashtable 'ht';
* if found, set 'value' to its value
*
* Requires:
* \li 'ht' is a valid hashtable
*
* Returns:
* \li #ISC_R_SUCCESS -- success
* \li #ISC_R_NOTFOUND -- key not found
*/
isc_result_t
isc_ht_find(const isc_ht_t *ht, const unsigned char *key,
isc_uint32_t keysize, void **valuep);
/*%
* Delete node from hashtable
* Requires:
*\li ht is a valid hashtable
*
* Returns:
*\li #ISC_R_NOTFOUND -- key not found
*\li #ISC_R_SUCCESS -- all is well
*/
isc_result_t
isc_ht_delete(isc_ht_t *ht, const unsigned char *key, isc_uint32_t keysize);
typedef isc_result_t (*isc_ht_walkfn)(void *udata, const unsigned char *key,
isc_uint32_t keysize, void *data);
/*%
* Create an iterator for the hashtable; point '*itp' to it.
*/
isc_result_t
isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp);
/*%
* Destroy the iterator '*itp', set it to NULL
*/
void
isc_ht_iter_destroy(isc_ht_iter_t **itp);
/*%
* Set an iterator to the first entry.
*
* Returns:
* \li #ISC_R_SUCCESS -- success
* \li #ISC_R_NOMORE -- no data in the hashtable
*/
isc_result_t
isc_ht_iter_first(isc_ht_iter_t *it);
/*%
* Set an iterator to the next entry.
*
* Returns:
* \li #ISC_R_SUCCESS -- success
* \li #ISC_R_NOMORE -- end of hashtable reached
*/
isc_result_t
isc_ht_iter_next(isc_ht_iter_t *it);
/*%
* Set 'value' to the current value under the iterator
*/
void
isc_ht_iter_current(isc_ht_iter_t *it, void **valuep);
/*%
* Walks the hashtable, calling 'walkfn' on each node
*
* \li If 'walkfn' returns ISC_R_SUCCESS, walk is continued
* \li If 'walkfn' returns ISC_R_EXISTS, walk is continued but the
* node is removed
* \li If 'walkfn' returns anything else, walk is aborted and function returns
* this value
*
* Requires:
* \li 'ht' is a valid hashtable
* \li 'walkfn' is not NULL
*
* Returns:
* \li #ISC_R_SUCCESS -- all is well
* \li Any other, as returned by 'walkfn'
*/
isc_result_t
isc_ht_walk(isc_ht_t *ht, isc_ht_walkfn walkfn, void *udata);
/*%
* Returns the number of items in the hashtable.
*
* Requires:
*\li 'ht' is a valid hashtable
*/
unsigned int
isc_ht_count(isc_ht_t *ht);
#endif

View File

@ -248,4 +248,13 @@
*/
#define TIME_NOW(tp) RUNTIME_CHECK(isc_time_now((tp)) == ISC_R_SUCCESS)
/*%
* Misc.
*/
#ifdef __GNUC__
#define ISC_DEPRECATED __attribute__((deprecated))
#else
#define ISC_DEPRECATED /* none */
#endif /* __GNUC __ */
#endif /* ISC_UTIL_H */

View File

@ -675,7 +675,6 @@ mem_getunlocked(isc__mem_t *ctx, size_t size) {
new_size = size;
goto done;
}
/*
* If there are no blocks in the free list for this size, get a chunk
* of memory and then break it up into "new_size"-sized blocks, adding
@ -687,9 +686,11 @@ mem_getunlocked(isc__mem_t *ctx, size_t size) {
/*
* The free list uses the "rounded-up" size "new_size".
*/
ret = ctx->freelists[new_size];
ctx->freelists[new_size] = ctx->freelists[new_size]->next;
/*
* The stats[] uses the _actual_ "size" requested by the
* caller, with the caveat (in the code above) that "size" >= the

View File

@ -1723,7 +1723,10 @@ isc__task_beginexclusive(isc_task_t *task0) {
isc__taskmgr_t *manager = task->manager;
REQUIRE(task->state == task_state_running);
/* XXX: Require task == manager->excl? */
/*
* TODO REQUIRE(task == task->manager->excl);
* it should be here, it fails on shutdown server->task
*/
LOCK(&manager->lock);
if (manager->exclusive_requested) {

View File

@ -41,7 +41,7 @@ SRCS = isctest.c taskpool_test.c socket_test.c hash_test.c \
parse_test.c pool_test.c print_test.c regex_test.c \
socket_test.c safe_test.c time_test.c aes_test.c \
file_test.c buffer_test.c counter_test.c mem_test.c \
result_test.c
result_test.c ht_test.c
SUBDIRS =
TARGETS = taskpool_test@EXEEXT@ socket_test@EXEEXT@ hash_test@EXEEXT@ \
@ -51,7 +51,7 @@ TARGETS = taskpool_test@EXEEXT@ socket_test@EXEEXT@ hash_test@EXEEXT@ \
print_test@EXEEXT@ regex_test@EXEEXT@ socket_test@EXEEXT@ \
safe_test@EXEEXT@ time_test@EXEEXT@ aes_test@EXEEXT@ \
file_test@EXEEXT@ buffer_test@EXEEXT@ counter_test@EXEEXT@ \
mem_test@EXEEXT@ result_test@EXEEXT@
mem_test@EXEEXT@ result_test@EXEEXT@ ht_test@EXEEXT@
@BIND9_MAKE_RULES@
@ -144,6 +144,10 @@ result_test@EXEEXT@: result_test.@O@ ${ISCDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
result_test.@O@ ${ISCLIBS} ${LIBS}
ht_test@EXEEXT@: ht_test.@O@ ${ISCDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
ht_test.@O@ ${ISCLIBS} ${LIBS}
unit::
sh ${top_srcdir}/unit/unittest.sh

View File

@ -135,11 +135,74 @@ ATF_TC_BODY(isc_buffer_reallocate, tc) {
isc_test_end();
}
ATF_TC(isc_buffer_dynamic);
ATF_TC_HEAD(isc_buffer_dynamic, tc) {
atf_tc_set_md_var(tc, "descr", "dynamic buffer automatic reallocation");
}
ATF_TC_BODY(isc_buffer_dynamic, tc) {
isc_result_t result;
isc_buffer_t *b;
size_t last_length = 10;
int i;
result = isc_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
b = NULL;
result = isc_buffer_allocate(mctx, &b, last_length);
ATF_CHECK_EQ(result, ISC_R_SUCCESS);
ATF_REQUIRE(b != NULL);
ATF_CHECK_EQ(b->length, last_length);
isc_buffer_setautorealloc(b, ISC_TRUE);
isc_buffer_putuint8(b, 1);
for (i = 0; i < 1000; i++) {
isc_buffer_putstr(b, "thisisa24charslongstring");
}
ATF_CHECK(b->length-last_length >= 1000*24);
last_length+=1000*24;
for (i = 0; i < 10000; i++) {
isc_buffer_putuint8(b, 1);
}
ATF_CHECK(b->length-last_length >= 10000*1);
last_length += 10000*1;
for (i = 0; i < 10000; i++) {
isc_buffer_putuint16(b, 1);
}
ATF_CHECK(b->length-last_length >= 10000*2);
last_length += 10000*2;
for (i = 0; i < 10000; i++) {
isc_buffer_putuint24(b, 1);
}
ATF_CHECK(b->length-last_length >= 10000*3);
last_length+=10000*3;
for (i = 0; i < 10000; i++) {
isc_buffer_putuint32(b, 1);
}
ATF_CHECK(b->length-last_length >= 10000*4);
isc_buffer_free(&b);
isc_test_end();
}
/*
* Main
*/
ATF_TP_ADD_TCS(tp) {
ATF_TP_ADD_TC(tp, isc_buffer_reserve);
ATF_TP_ADD_TC(tp, isc_buffer_reallocate);
ATF_TP_ADD_TC(tp, isc_buffer_dynamic);
return (atf_no_error());
}

327
lib/isc/tests/ht_test.c Normal file
View File

@ -0,0 +1,327 @@
/*
* Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* ! \file */
#include <config.h>
#include <atf-c.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <isc/hash.h>
#include <isc/ht.h>
#include <isc/mem.h>
#include <isc/util.h>
static void *
default_memalloc(void *arg, size_t size) {
UNUSED(arg);
if (size == 0U)
size = 1;
return (malloc(size));
}
static void
default_memfree(void *arg, void *ptr) {
UNUSED(arg);
free(ptr);
}
static void test_ht_full(int bits, int count) {
isc_ht_t *ht = NULL;
isc_result_t result;
isc_mem_t *mctx = NULL;
isc_int64_t i;
result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
NULL, &mctx, 0);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
isc_ht_init(&ht, mctx, bits);
for (i = 1; i < count; i++) {
/*
* Note that the string we're snprintfing is always > 16 bytes
* so we are always filling the key.
*/
unsigned char key[16];
snprintf((char *)key, 16, "%lld key of a raw hashtable!!", i);
result = isc_ht_add(ht, key, 16, (void *) i);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
}
for (i = 1; i < count; i++) {
unsigned char key[16];
void *f = NULL;
snprintf((char *)key, 16, "%lld key of a raw hashtable!!", i);
result = isc_ht_find(ht, key, 16, &f);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
ATF_REQUIRE_EQ(i, (isc_int64_t) f);
}
for (i = 1; i < count; i++) {
unsigned char key[16];
snprintf((char *)key, 16, "%lld key of a raw hashtable!!", i);
result = isc_ht_add(ht, key, 16, (void *) i);
ATF_REQUIRE_EQ(result, ISC_R_EXISTS);
}
for (i = 1; i < count; i++) {
char key[64];
snprintf((char *)key, 64, "%lld key of a str hashtable!!", i);
result = isc_ht_add(ht, (const unsigned char *) key,
strlen(key), (void *) i);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
}
for (i = 1; i < count; i++) {
unsigned char key[16];
void *f = NULL;
snprintf((char *)key, 16, "%lld KEY of a raw hashtable!!", i);
result = isc_ht_find(ht, key, 16, &f);
ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
ATF_REQUIRE_EQ(f, NULL);
}
for (i = 1; i < count; i++) {
char key[64];
void *f = NULL;
snprintf((char *)key, 64, "%lld key of a str hashtable!!", i);
result = isc_ht_find(ht, (const unsigned char *) key,
strlen(key), &f);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
ATF_REQUIRE_EQ(f, (void *) i);
}
for (i = 1; i < count; i++) {
unsigned char key[16];
void *f = NULL;
snprintf((char *)key, 16, "%lld key of a raw hashtable!!", i);
result = isc_ht_delete(ht, key, 16);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = isc_ht_find(ht, key, 16, &f);
ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
ATF_REQUIRE_EQ(f, NULL);
}
for (i = 1; i < count; i++) {
unsigned char key[16];
snprintf((char *)key, 16, "%lld KEY of a raw hashtable!!", i);
result = isc_ht_add(ht, key, 16, (void *) i);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
}
for (i = 1; i < count; i++) {
char key[64];
void *f = NULL;
snprintf((char *)key, 64, "%lld key of a str hashtable!!", i);
result = isc_ht_delete(ht, (const unsigned char *) key,
strlen(key));
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = isc_ht_find(ht, (const unsigned char *) key,
strlen(key), &f);
ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
ATF_REQUIRE_EQ(f, NULL);
}
for (i = 1; i < count; i++) {
unsigned char key[16];
void *f = NULL;
snprintf((char *)key, 16, "%lld KEY of a raw hashtable!!", i);
result = isc_ht_find(ht, key, 16, &f);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
ATF_REQUIRE_EQ(i, (isc_int64_t) f);
}
for (i = 1; i < count; i++) {
unsigned char key[16];
void *f = NULL;
snprintf((char *)key, 16, "%lld key of a raw hashtable!!", i);
result = isc_ht_find(ht, key, 16, &f);
ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
ATF_REQUIRE_EQ(f, NULL);
}
isc_ht_destroy(&ht);
ATF_REQUIRE_EQ(ht, NULL);
}
static isc_uint32_t walked = 0;
typedef enum {
REGULAR,
ERASEEVEN,
ERASEODD,
CRASH
} walkmode_t;
static isc_result_t walker(void *udata, const unsigned char *key,
isc_uint32_t keysize, void *data)
{
char mykey[16];
isc_uint64_t ii = (isc_uint64_t) data;
walkmode_t mode = (isc_uint64_t) udata;
ATF_REQUIRE_EQ(keysize, 16);
snprintf(mykey, 16, "%lld key of a raw hashtable!!", ii);
ATF_REQUIRE_EQ(memcmp(mykey, key, 16), 0);
walked++;
switch (mode) {
case REGULAR:
break;
case ERASEEVEN:
if (ii % 2 == 0) {
return (ISC_R_EXISTS);
}
break;
case ERASEODD:
if (ii % 2 != 0) {
return (ISC_R_EXISTS);
}
break;
case CRASH:
if (walked == 100) {
/* something as odd as possible */
return (ISC_R_HOSTUNREACH);
}
break;
}
return (ISC_R_SUCCESS);
}
static void test_ht_walk() {
isc_ht_t *ht = NULL;
isc_result_t result;
isc_mem_t *mctx = NULL;
isc_int64_t i;
isc_uint32_t count = 10000;
result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
NULL, &mctx, 0);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = isc_ht_init(&ht, mctx, 16);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
ATF_REQUIRE(ht != NULL);
for (i = 1; i <= count; i++) {
/*
* Note that the string we're snprintfing is always > 16 bytes
* so we are always filling the key.
*/
unsigned char key[16];
snprintf((char *)key, 16, "%lld key of a raw hashtable!!", i);
result = isc_ht_add(ht, key, 16, (void *) i);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
}
walked = 0;
result = isc_ht_walk(ht, walker, (void *) REGULAR);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
ATF_REQUIRE_EQ(walked, count);
walked = 0;
result = isc_ht_walk(ht, walker, (void *) CRASH);
ATF_REQUIRE_EQ(result, ISC_R_HOSTUNREACH);
ATF_REQUIRE_EQ(walked, 100);
walked = 0;
result = isc_ht_walk(ht, walker, (void *) ERASEODD);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
ATF_REQUIRE_EQ(walked, count);
walked = 0;
result = isc_ht_walk(ht, walker, (void *) ERASEEVEN);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
ATF_REQUIRE_EQ(walked, count/2);
walked = 0;
result = isc_ht_walk(ht, walker, (void *) REGULAR);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
ATF_REQUIRE_EQ(walked, 0);
isc_ht_destroy(&ht);
ATF_REQUIRE_EQ(ht, NULL);
}
ATF_TC(isc_ht_20);
ATF_TC_HEAD(isc_ht_20, tc) {
atf_tc_set_md_var(tc, "descr", "20 bit, 2M elements test");
}
ATF_TC_BODY(isc_ht_20, tc) {
UNUSED(tc);
test_ht_full(20, 2000000);
}
ATF_TC(isc_ht_8);
ATF_TC_HEAD(isc_ht_8, tc) {
atf_tc_set_md_var(tc, "descr", "8 bit, 20000 elements crowded test");
}
ATF_TC_BODY(isc_ht_8, tc) {
UNUSED(tc);
test_ht_full(8, 20000);
}
ATF_TC(isc_ht_1);
ATF_TC_HEAD(isc_ht_1, tc) {
atf_tc_set_md_var(tc, "descr", "1 bit, 100 elements corner case test");
}
ATF_TC_BODY(isc_ht_1, tc) {
UNUSED(tc);
test_ht_full(1, 100);
}
ATF_TC(isc_ht_32);
ATF_TC_HEAD(isc_ht_32, tc) {
atf_tc_set_md_var(tc, "descr", "32 bit, 10000 elements corner case test");
}
ATF_TC_BODY(isc_ht_32, tc) {
UNUSED(tc);
test_ht_full(32, 10000);
}
ATF_TC(isc_ht_walk);
ATF_TC_HEAD(isc_ht_walk, tc) {
atf_tc_set_md_var(tc, "descr", "hashtable walking");
}
ATF_TC_BODY(isc_ht_walk, tc) {
UNUSED(tc);
test_ht_walk();
}
/*
* Main
*/
ATF_TP_ADD_TCS(tp) {
ATF_TP_ADD_TC(tp, isc_ht_20);
ATF_TP_ADD_TC(tp, isc_ht_8);
ATF_TP_ADD_TC(tp, isc_ht_1);
ATF_TP_ADD_TC(tp, isc_ht_32);
ATF_TP_ADD_TC(tp, isc_ht_walk);
return (atf_no_error());
}

View File

@ -308,6 +308,13 @@ isc_hmacsha512_invalidate
isc_hmacsha512_sign
isc_hmacsha512_update
isc_hmacsha512_verify
isc_ht_init
isc_ht_destroy
isc_ht_find
isc_ht_delete
isc_ht_iter_get
isc_ht_iter_inc
isc_ht_iter_value
isc_httpd_addheader
isc_httpd_addheaderuint
isc_httpd_response

View File

@ -1472,6 +1472,42 @@ static cfg_type_t cfg_type_rpz = {
rpz_fields
};
/*
* Catalog zones
*/
static cfg_type_t cfg_type_catz_zone = {
"zone", parse_keyvalue, print_keyvalue,
doc_keyvalue, &cfg_rep_string,
&zone_kw
};
static cfg_tuplefielddef_t catz_zone_fields[] = {
{ "zone name", &cfg_type_catz_zone, 0 },
{ "default-masters", &cfg_type_namesockaddrkeylist, 0 },
{ "in-memory", &cfg_type_boolean, 0 },
{ "min-update-interval", &cfg_type_uint32, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_catz_tuple = {
"catz tuple", cfg_parse_kv_tuple,
cfg_print_kv_tuple, cfg_doc_kv_tuple, &cfg_rep_tuple,
catz_zone_fields
};
static cfg_type_t cfg_type_catz_list = {
"zone list", cfg_parse_bracketed_list, cfg_print_bracketed_list,
cfg_doc_bracketed_list, &cfg_rep_list,
&cfg_type_catz_tuple
};
static cfg_tuplefielddef_t catz_fields[] = {
{ "zone list", &cfg_type_catz_list, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_catz = {
"catz", cfg_parse_kv_tuple, cfg_print_kv_tuple,
cfg_doc_kv_tuple, &cfg_rep_tuple, catz_fields
};
/*
* rate-limit
@ -1627,6 +1663,7 @@ view_clauses[] = {
{ "attach-cache", &cfg_type_astring, 0 },
{ "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT },
{ "cache-file", &cfg_type_qstring, 0 },
{ "catalog-zones", &cfg_type_catz, 0 },
{ "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
{ "cleaning-interval", &cfg_type_uint32, 0 },
{ "clients-per-query", &cfg_type_uint32, 0 },