257 lines
6.5 KiB
C
257 lines
6.5 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0 AND ISC
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) Red Hat
|
|
*
|
|
* 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 AUTHORS 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.
|
|
*/
|
|
|
|
/*
|
|
* Zone management.
|
|
*/
|
|
|
|
#include "zone.h"
|
|
#include <inttypes.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
#include <dns/dyndb.h>
|
|
#include <dns/view.h>
|
|
#include <dns/zone.h>
|
|
|
|
#include "instance.h"
|
|
#include "log.h"
|
|
#include "util.h"
|
|
|
|
extern const char *impname;
|
|
|
|
/*
|
|
* Create a new zone with origin 'name'. The zone stay invisible to clients
|
|
* until it is explicitly added to a view.
|
|
*/
|
|
isc_result_t
|
|
create_zone(sample_instance_t *const inst, dns_name_t *const name,
|
|
dns_zone_t **const rawp) {
|
|
isc_result_t result;
|
|
dns_zone_t *raw = NULL;
|
|
const char *zone_argv[1];
|
|
char zone_name[DNS_NAME_FORMATSIZE];
|
|
dns_acl_t *acl_any = NULL;
|
|
|
|
REQUIRE(inst != NULL);
|
|
REQUIRE(name != NULL);
|
|
REQUIRE(rawp != NULL && *rawp == NULL);
|
|
|
|
zone_argv[0] = inst->db_name;
|
|
|
|
dns_zone_create(&raw, inst->mctx, 0); /* FIXME: all zones are assigned
|
|
to loop 0 */
|
|
result = dns_zone_setorigin(raw, name);
|
|
if (result != ISC_R_SUCCESS) {
|
|
log_write(ISC_LOG_ERROR,
|
|
"create_zone: dns_zone_setorigin -> %s\n",
|
|
isc_result_totext(result));
|
|
goto cleanup;
|
|
}
|
|
dns_zone_setclass(raw, dns_rdataclass_in);
|
|
dns_zone_settype(raw, dns_zone_primary);
|
|
dns_zone_setdbtype(raw, 1, zone_argv);
|
|
|
|
result = dns_zonemgr_managezone(inst->zmgr, raw);
|
|
if (result != ISC_R_SUCCESS) {
|
|
log_write(ISC_LOG_ERROR,
|
|
"create_zone: dns_zonemgr_managezone -> %s\n",
|
|
isc_result_totext(result));
|
|
goto cleanup;
|
|
}
|
|
|
|
/* This is completely insecure - use some sensible values instead! */
|
|
result = dns_acl_any(inst->mctx, &acl_any);
|
|
if (result != ISC_R_SUCCESS) {
|
|
log_write(ISC_LOG_ERROR, "create_zone: dns_acl_any -> %s\n",
|
|
isc_result_totext(result));
|
|
goto cleanup;
|
|
}
|
|
dns_zone_setupdateacl(raw, acl_any);
|
|
dns_zone_setqueryacl(raw, acl_any);
|
|
dns_zone_setxfracl(raw, acl_any);
|
|
dns_acl_detach(&acl_any);
|
|
|
|
*rawp = raw;
|
|
return ISC_R_SUCCESS;
|
|
|
|
cleanup:
|
|
dns_name_format(name, zone_name, DNS_NAME_FORMATSIZE);
|
|
log_error_r("failed to create new zone '%s'", zone_name);
|
|
|
|
if (raw != NULL) {
|
|
if (dns_zone_getmgr(raw) != NULL) {
|
|
dns_zonemgr_releasezone(inst->zmgr, raw);
|
|
}
|
|
dns_zone_detach(&raw);
|
|
}
|
|
if (acl_any != NULL) {
|
|
dns_acl_detach(&acl_any);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Add zone to the view defined in inst->view. This will make the zone visible
|
|
* to clients.
|
|
*/
|
|
static isc_result_t
|
|
publish_zone(sample_instance_t *inst, dns_zone_t *zone) {
|
|
isc_result_t result;
|
|
bool freeze = false;
|
|
dns_zone_t *zone_in_view = NULL;
|
|
dns_view_t *view_in_zone = NULL;
|
|
|
|
REQUIRE(inst != NULL);
|
|
REQUIRE(zone != NULL);
|
|
|
|
/* Return success if the zone is already in the view as expected. */
|
|
result = dns_view_findzone(inst->view, dns_zone_getorigin(zone),
|
|
DNS_ZTFIND_EXACT, &zone_in_view);
|
|
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
|
|
goto cleanup;
|
|
}
|
|
|
|
view_in_zone = dns_zone_getview(zone);
|
|
if (view_in_zone != NULL) {
|
|
/* Zone has a view set -> view should contain the same zone. */
|
|
if (zone_in_view == zone) {
|
|
/* Zone is already published in the right view. */
|
|
CLEANUP_WITH(ISC_R_SUCCESS);
|
|
} else if (view_in_zone != inst->view) {
|
|
/*
|
|
* Un-published inactive zone will have
|
|
* inst->view in zone but will not be present
|
|
* in the view itself.
|
|
*/
|
|
dns_zone_log(zone, ISC_LOG_ERROR,
|
|
"zone->view doesn't "
|
|
"match data in the view");
|
|
CLEANUP_WITH(ISC_R_UNEXPECTED);
|
|
}
|
|
}
|
|
|
|
if (zone_in_view != NULL) {
|
|
dns_zone_log(zone, ISC_LOG_ERROR,
|
|
"cannot publish zone: view already "
|
|
"contains another zone with this name");
|
|
CLEANUP_WITH(ISC_R_UNEXPECTED);
|
|
}
|
|
|
|
if (inst->view->frozen) {
|
|
freeze = true;
|
|
dns_view_thaw(inst->view);
|
|
}
|
|
|
|
dns_zone_setview(zone, inst->view);
|
|
result = dns_view_addzone(inst->view, zone);
|
|
if (result != ISC_R_SUCCESS) {
|
|
log_write(ISC_LOG_ERROR,
|
|
"publish_zone: dns_view_addzone -> %s\n",
|
|
isc_result_totext(result));
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
if (zone_in_view != NULL) {
|
|
dns_zone_detach(&zone_in_view);
|
|
}
|
|
if (freeze) {
|
|
dns_view_freeze(inst->view);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* @warning Never call this on raw part of in-line secure zone, call it only
|
|
* on the secure zone!
|
|
*/
|
|
static isc_result_t
|
|
load_zone(dns_zone_t *zone) {
|
|
isc_result_t result;
|
|
bool zone_dynamic;
|
|
uint32_t serial;
|
|
|
|
result = dns_zone_load(zone, false);
|
|
if (result != ISC_R_SUCCESS && result != DNS_R_UPTODATE &&
|
|
result != DNS_R_DYNAMIC && result != DNS_R_CONTINUE)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
zone_dynamic = (result == DNS_R_DYNAMIC);
|
|
|
|
result = dns_zone_getserial(zone, &serial);
|
|
if (result != ISC_R_SUCCESS) {
|
|
log_write(ISC_LOG_ERROR,
|
|
"load_zone: dns_zone_getserial -> %s\n",
|
|
isc_result_totext(result));
|
|
goto cleanup;
|
|
}
|
|
dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u", serial);
|
|
|
|
if (zone_dynamic) {
|
|
dns_zone_notify(zone);
|
|
}
|
|
|
|
cleanup:
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Add zone to view and call dns_zone_load().
|
|
*/
|
|
isc_result_t
|
|
activate_zone(sample_instance_t *inst, dns_zone_t *raw) {
|
|
isc_result_t result;
|
|
|
|
/*
|
|
* Zone has to be published *before* zone load
|
|
* otherwise it will race with zone->view != NULL check
|
|
* in zone_maintenance() in zone.c.
|
|
*/
|
|
result = publish_zone(inst, raw);
|
|
if (result != ISC_R_SUCCESS) {
|
|
dns_zone_log(raw, ISC_LOG_ERROR, "cannot add zone to view: %s",
|
|
isc_result_totext(result));
|
|
goto cleanup;
|
|
}
|
|
|
|
result = load_zone(raw);
|
|
if (result != ISC_R_SUCCESS) {
|
|
log_write(ISC_LOG_ERROR, "activate_zone: load_zone -> %s\n",
|
|
isc_result_totext(result));
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
return result;
|
|
}
|