mirror of
https://github.com/isc-projects/bind9.git
synced 2026-02-25 02:42:33 -05:00
After switching to per-thread resources in the zonemgr, the performance was decreased because the memory context, zonetask and loadtask was picked from the pool at random. Pin the zone to single threadid (.tid) and align the memory context, zonetask and loadtask to be the same, this sets the hard affinity of the zone to the netmgr thread.
690 lines
17 KiB
C
690 lines
17 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/*! \file */
|
|
|
|
#include <inttypes.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
|
|
#include <isc/buffer.h>
|
|
#include <isc/log.h>
|
|
#include <isc/mem.h>
|
|
#include <isc/net.h>
|
|
#include <isc/netdb.h>
|
|
#include <isc/print.h>
|
|
#include <isc/region.h>
|
|
#include <isc/result.h>
|
|
#include <isc/stdio.h>
|
|
#include <isc/string.h>
|
|
#include <isc/symtab.h>
|
|
#include <isc/types.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dns/db.h>
|
|
#include <dns/dbiterator.h>
|
|
#include <dns/fixedname.h>
|
|
#include <dns/log.h>
|
|
#include <dns/name.h>
|
|
#include <dns/rdata.h>
|
|
#include <dns/rdataclass.h>
|
|
#include <dns/rdataset.h>
|
|
#include <dns/rdatasetiter.h>
|
|
#include <dns/rdatatype.h>
|
|
#include <dns/types.h>
|
|
#include <dns/zone.h>
|
|
|
|
#include <isccfg/log.h>
|
|
|
|
#include <ns/log.h>
|
|
|
|
#include "check-tool.h"
|
|
|
|
#ifndef CHECK_SIBLING
|
|
#define CHECK_SIBLING 1
|
|
#endif /* ifndef CHECK_SIBLING */
|
|
|
|
#ifndef CHECK_LOCAL
|
|
#define CHECK_LOCAL 1
|
|
#endif /* ifndef CHECK_LOCAL */
|
|
|
|
#define CHECK(r) \
|
|
do { \
|
|
result = (r); \
|
|
if (result != ISC_R_SUCCESS) \
|
|
goto cleanup; \
|
|
} while (0)
|
|
|
|
#define ERR_IS_CNAME 1
|
|
#define ERR_NO_ADDRESSES 2
|
|
#define ERR_LOOKUP_FAILURE 3
|
|
#define ERR_EXTRA_A 4
|
|
#define ERR_EXTRA_AAAA 5
|
|
#define ERR_MISSING_GLUE 5
|
|
#define ERR_IS_MXCNAME 6
|
|
#define ERR_IS_SRVCNAME 7
|
|
|
|
static const char *dbtype[] = { "rbt" };
|
|
|
|
int debug = 0;
|
|
const char *journal = NULL;
|
|
bool nomerge = true;
|
|
#if CHECK_LOCAL
|
|
bool docheckmx = true;
|
|
bool dochecksrv = true;
|
|
bool docheckns = true;
|
|
#else /* if CHECK_LOCAL */
|
|
bool docheckmx = false;
|
|
bool dochecksrv = false;
|
|
bool docheckns = false;
|
|
#endif /* if CHECK_LOCAL */
|
|
dns_zoneopt_t zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_CHECKMX |
|
|
DNS_ZONEOPT_MANYERRORS | DNS_ZONEOPT_CHECKNAMES |
|
|
DNS_ZONEOPT_CHECKINTEGRITY |
|
|
#if CHECK_SIBLING
|
|
DNS_ZONEOPT_CHECKSIBLING |
|
|
#endif /* if CHECK_SIBLING */
|
|
DNS_ZONEOPT_CHECKWILDCARD |
|
|
DNS_ZONEOPT_WARNMXCNAME | DNS_ZONEOPT_WARNSRVCNAME;
|
|
|
|
/*
|
|
* This needs to match the list in bin/named/log.c.
|
|
*/
|
|
static isc_logcategory_t categories[] = { { "", 0 },
|
|
{ "unmatched", 0 },
|
|
{ NULL, 0 } };
|
|
|
|
static isc_symtab_t *symtab = NULL;
|
|
static isc_mem_t *sym_mctx;
|
|
|
|
static void
|
|
freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
|
|
UNUSED(type);
|
|
UNUSED(value);
|
|
isc_mem_free(userarg, key);
|
|
}
|
|
|
|
static void
|
|
add(char *key, int value) {
|
|
isc_result_t result;
|
|
isc_symvalue_t symvalue;
|
|
|
|
if (sym_mctx == NULL) {
|
|
isc_mem_create(&sym_mctx);
|
|
}
|
|
|
|
if (symtab == NULL) {
|
|
result = isc_symtab_create(sym_mctx, 100, freekey, sym_mctx,
|
|
false, &symtab);
|
|
if (result != ISC_R_SUCCESS) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
key = isc_mem_strdup(sym_mctx, key);
|
|
|
|
symvalue.as_pointer = NULL;
|
|
result = isc_symtab_define(symtab, key, value, symvalue,
|
|
isc_symexists_reject);
|
|
if (result != ISC_R_SUCCESS) {
|
|
isc_mem_free(sym_mctx, key);
|
|
}
|
|
}
|
|
|
|
static bool
|
|
logged(char *key, int value) {
|
|
isc_result_t result;
|
|
|
|
if (symtab == NULL) {
|
|
return (false);
|
|
}
|
|
|
|
result = isc_symtab_lookup(symtab, key, value, NULL);
|
|
if (result == ISC_R_SUCCESS) {
|
|
return (true);
|
|
}
|
|
return (false);
|
|
}
|
|
|
|
static bool
|
|
checkns(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner,
|
|
dns_rdataset_t *a, dns_rdataset_t *aaaa) {
|
|
dns_rdataset_t *rdataset;
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
struct addrinfo hints, *ai, *cur;
|
|
char namebuf[DNS_NAME_FORMATSIZE + 1];
|
|
char ownerbuf[DNS_NAME_FORMATSIZE];
|
|
char addrbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
|
|
bool answer = true;
|
|
bool match;
|
|
const char *type;
|
|
void *ptr = NULL;
|
|
int result;
|
|
|
|
REQUIRE(a == NULL || !dns_rdataset_isassociated(a) ||
|
|
a->type == dns_rdatatype_a);
|
|
REQUIRE(aaaa == NULL || !dns_rdataset_isassociated(aaaa) ||
|
|
aaaa->type == dns_rdatatype_aaaa);
|
|
|
|
if (a == NULL || aaaa == NULL) {
|
|
return (answer);
|
|
}
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_flags = AI_CANONNAME;
|
|
hints.ai_family = PF_UNSPEC;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
hints.ai_protocol = IPPROTO_TCP;
|
|
|
|
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
|
/*
|
|
* Turn off search.
|
|
*/
|
|
if (dns_name_countlabels(name) > 1U) {
|
|
strlcat(namebuf, ".", sizeof(namebuf));
|
|
}
|
|
dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
|
|
|
|
result = getaddrinfo(namebuf, NULL, &hints, &ai);
|
|
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
|
switch (result) {
|
|
case 0:
|
|
/*
|
|
* Work around broken getaddrinfo() implementations that
|
|
* fail to set ai_canonname on first entry.
|
|
*/
|
|
cur = ai;
|
|
while (cur != NULL && cur->ai_canonname == NULL &&
|
|
cur->ai_next != NULL) {
|
|
cur = cur->ai_next;
|
|
}
|
|
if (cur != NULL && cur->ai_canonname != NULL &&
|
|
strcasecmp(cur->ai_canonname, namebuf) != 0 &&
|
|
!logged(namebuf, ERR_IS_CNAME))
|
|
{
|
|
dns_zone_log(zone, ISC_LOG_ERROR,
|
|
"%s/NS '%s' (out of zone) "
|
|
"is a CNAME '%s' (illegal)",
|
|
ownerbuf, namebuf, cur->ai_canonname);
|
|
/* XXX950 make fatal for 9.5.0 */
|
|
/* answer = false; */
|
|
add(namebuf, ERR_IS_CNAME);
|
|
}
|
|
break;
|
|
case EAI_NONAME:
|
|
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
|
|
case EAI_NODATA:
|
|
#endif /* if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) */
|
|
if (!logged(namebuf, ERR_NO_ADDRESSES)) {
|
|
dns_zone_log(zone, ISC_LOG_ERROR,
|
|
"%s/NS '%s' (out of zone) "
|
|
"has no addresses records (A or AAAA)",
|
|
ownerbuf, namebuf);
|
|
add(namebuf, ERR_NO_ADDRESSES);
|
|
}
|
|
/* XXX950 make fatal for 9.5.0 */
|
|
return (true);
|
|
|
|
default:
|
|
if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
|
|
dns_zone_log(zone, ISC_LOG_WARNING,
|
|
"getaddrinfo(%s) failed: %s", namebuf,
|
|
gai_strerror(result));
|
|
add(namebuf, ERR_LOOKUP_FAILURE);
|
|
}
|
|
return (true);
|
|
}
|
|
|
|
/*
|
|
* Check that all glue records really exist.
|
|
*/
|
|
if (!dns_rdataset_isassociated(a)) {
|
|
goto checkaaaa;
|
|
}
|
|
result = dns_rdataset_first(a);
|
|
while (result == ISC_R_SUCCESS) {
|
|
dns_rdataset_current(a, &rdata);
|
|
match = false;
|
|
for (cur = ai; cur != NULL; cur = cur->ai_next) {
|
|
if (cur->ai_family != AF_INET) {
|
|
continue;
|
|
}
|
|
ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
|
|
if (memcmp(ptr, rdata.data, rdata.length) == 0) {
|
|
match = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!match && !logged(namebuf, ERR_EXTRA_A)) {
|
|
dns_zone_log(zone, ISC_LOG_ERROR,
|
|
"%s/NS '%s' "
|
|
"extra GLUE A record (%s)",
|
|
ownerbuf, namebuf,
|
|
inet_ntop(AF_INET, rdata.data, addrbuf,
|
|
sizeof(addrbuf)));
|
|
add(namebuf, ERR_EXTRA_A);
|
|
/* XXX950 make fatal for 9.5.0 */
|
|
/* answer = false; */
|
|
}
|
|
dns_rdata_reset(&rdata);
|
|
result = dns_rdataset_next(a);
|
|
}
|
|
|
|
checkaaaa:
|
|
if (!dns_rdataset_isassociated(aaaa)) {
|
|
goto checkmissing;
|
|
}
|
|
result = dns_rdataset_first(aaaa);
|
|
while (result == ISC_R_SUCCESS) {
|
|
dns_rdataset_current(aaaa, &rdata);
|
|
match = false;
|
|
for (cur = ai; cur != NULL; cur = cur->ai_next) {
|
|
if (cur->ai_family != AF_INET6) {
|
|
continue;
|
|
}
|
|
ptr = &((struct sockaddr_in6 *)(cur->ai_addr))
|
|
->sin6_addr;
|
|
if (memcmp(ptr, rdata.data, rdata.length) == 0) {
|
|
match = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) {
|
|
dns_zone_log(zone, ISC_LOG_ERROR,
|
|
"%s/NS '%s' "
|
|
"extra GLUE AAAA record (%s)",
|
|
ownerbuf, namebuf,
|
|
inet_ntop(AF_INET6, rdata.data, addrbuf,
|
|
sizeof(addrbuf)));
|
|
add(namebuf, ERR_EXTRA_AAAA);
|
|
/* XXX950 make fatal for 9.5.0. */
|
|
/* answer = false; */
|
|
}
|
|
dns_rdata_reset(&rdata);
|
|
result = dns_rdataset_next(aaaa);
|
|
}
|
|
|
|
checkmissing:
|
|
/*
|
|
* Check that all addresses appear in the glue.
|
|
*/
|
|
if (!logged(namebuf, ERR_MISSING_GLUE)) {
|
|
bool missing_glue = false;
|
|
for (cur = ai; cur != NULL; cur = cur->ai_next) {
|
|
switch (cur->ai_family) {
|
|
case AF_INET:
|
|
rdataset = a;
|
|
ptr = &((struct sockaddr_in *)(cur->ai_addr))
|
|
->sin_addr;
|
|
type = "A";
|
|
break;
|
|
case AF_INET6:
|
|
rdataset = aaaa;
|
|
ptr = &((struct sockaddr_in6 *)(cur->ai_addr))
|
|
->sin6_addr;
|
|
type = "AAAA";
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
match = false;
|
|
if (dns_rdataset_isassociated(rdataset)) {
|
|
result = dns_rdataset_first(rdataset);
|
|
} else {
|
|
result = ISC_R_FAILURE;
|
|
}
|
|
while (result == ISC_R_SUCCESS && !match) {
|
|
dns_rdataset_current(rdataset, &rdata);
|
|
if (memcmp(ptr, rdata.data, rdata.length) == 0)
|
|
{
|
|
match = true;
|
|
}
|
|
dns_rdata_reset(&rdata);
|
|
result = dns_rdataset_next(rdataset);
|
|
}
|
|
if (!match) {
|
|
dns_zone_log(zone, ISC_LOG_ERROR,
|
|
"%s/NS '%s' "
|
|
"missing GLUE %s record (%s)",
|
|
ownerbuf, namebuf, type,
|
|
inet_ntop(cur->ai_family, ptr,
|
|
addrbuf,
|
|
sizeof(addrbuf)));
|
|
/* XXX950 make fatal for 9.5.0. */
|
|
/* answer = false; */
|
|
missing_glue = true;
|
|
}
|
|
}
|
|
if (missing_glue) {
|
|
add(namebuf, ERR_MISSING_GLUE);
|
|
}
|
|
}
|
|
freeaddrinfo(ai);
|
|
return (answer);
|
|
}
|
|
|
|
static bool
|
|
checkmx(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
|
|
struct addrinfo hints, *ai, *cur;
|
|
char namebuf[DNS_NAME_FORMATSIZE + 1];
|
|
char ownerbuf[DNS_NAME_FORMATSIZE];
|
|
int result;
|
|
int level = ISC_LOG_ERROR;
|
|
bool answer = true;
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_flags = AI_CANONNAME;
|
|
hints.ai_family = PF_UNSPEC;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
hints.ai_protocol = IPPROTO_TCP;
|
|
|
|
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
|
/*
|
|
* Turn off search.
|
|
*/
|
|
if (dns_name_countlabels(name) > 1U) {
|
|
strlcat(namebuf, ".", sizeof(namebuf));
|
|
}
|
|
dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
|
|
|
|
result = getaddrinfo(namebuf, NULL, &hints, &ai);
|
|
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
|
switch (result) {
|
|
case 0:
|
|
/*
|
|
* Work around broken getaddrinfo() implementations that
|
|
* fail to set ai_canonname on first entry.
|
|
*/
|
|
cur = ai;
|
|
while (cur != NULL && cur->ai_canonname == NULL &&
|
|
cur->ai_next != NULL) {
|
|
cur = cur->ai_next;
|
|
}
|
|
if (cur != NULL && cur->ai_canonname != NULL &&
|
|
strcasecmp(cur->ai_canonname, namebuf) != 0)
|
|
{
|
|
if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0) {
|
|
level = ISC_LOG_WARNING;
|
|
}
|
|
if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) {
|
|
if (!logged(namebuf, ERR_IS_MXCNAME)) {
|
|
dns_zone_log(zone, level,
|
|
"%s/MX '%s' (out of zone)"
|
|
" is a CNAME '%s' "
|
|
"(illegal)",
|
|
ownerbuf, namebuf,
|
|
cur->ai_canonname);
|
|
add(namebuf, ERR_IS_MXCNAME);
|
|
}
|
|
if (level == ISC_LOG_ERROR) {
|
|
answer = false;
|
|
}
|
|
}
|
|
}
|
|
freeaddrinfo(ai);
|
|
return (answer);
|
|
|
|
case EAI_NONAME:
|
|
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
|
|
case EAI_NODATA:
|
|
#endif /* if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) */
|
|
if (!logged(namebuf, ERR_NO_ADDRESSES)) {
|
|
dns_zone_log(zone, ISC_LOG_ERROR,
|
|
"%s/MX '%s' (out of zone) "
|
|
"has no addresses records (A or AAAA)",
|
|
ownerbuf, namebuf);
|
|
add(namebuf, ERR_NO_ADDRESSES);
|
|
}
|
|
/* XXX950 make fatal for 9.5.0. */
|
|
return (true);
|
|
|
|
default:
|
|
if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
|
|
dns_zone_log(zone, ISC_LOG_WARNING,
|
|
"getaddrinfo(%s) failed: %s", namebuf,
|
|
gai_strerror(result));
|
|
add(namebuf, ERR_LOOKUP_FAILURE);
|
|
}
|
|
return (true);
|
|
}
|
|
}
|
|
|
|
static bool
|
|
checksrv(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
|
|
struct addrinfo hints, *ai, *cur;
|
|
char namebuf[DNS_NAME_FORMATSIZE + 1];
|
|
char ownerbuf[DNS_NAME_FORMATSIZE];
|
|
int result;
|
|
int level = ISC_LOG_ERROR;
|
|
bool answer = true;
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_flags = AI_CANONNAME;
|
|
hints.ai_family = PF_UNSPEC;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
hints.ai_protocol = IPPROTO_TCP;
|
|
|
|
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
|
/*
|
|
* Turn off search.
|
|
*/
|
|
if (dns_name_countlabels(name) > 1U) {
|
|
strlcat(namebuf, ".", sizeof(namebuf));
|
|
}
|
|
dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
|
|
|
|
result = getaddrinfo(namebuf, NULL, &hints, &ai);
|
|
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
|
switch (result) {
|
|
case 0:
|
|
/*
|
|
* Work around broken getaddrinfo() implementations that
|
|
* fail to set ai_canonname on first entry.
|
|
*/
|
|
cur = ai;
|
|
while (cur != NULL && cur->ai_canonname == NULL &&
|
|
cur->ai_next != NULL) {
|
|
cur = cur->ai_next;
|
|
}
|
|
if (cur != NULL && cur->ai_canonname != NULL &&
|
|
strcasecmp(cur->ai_canonname, namebuf) != 0)
|
|
{
|
|
if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0) {
|
|
level = ISC_LOG_WARNING;
|
|
}
|
|
if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) {
|
|
if (!logged(namebuf, ERR_IS_SRVCNAME)) {
|
|
dns_zone_log(zone, level,
|
|
"%s/SRV '%s'"
|
|
" (out of zone) is a "
|
|
"CNAME '%s' (illegal)",
|
|
ownerbuf, namebuf,
|
|
cur->ai_canonname);
|
|
add(namebuf, ERR_IS_SRVCNAME);
|
|
}
|
|
if (level == ISC_LOG_ERROR) {
|
|
answer = false;
|
|
}
|
|
}
|
|
}
|
|
freeaddrinfo(ai);
|
|
return (answer);
|
|
|
|
case EAI_NONAME:
|
|
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
|
|
case EAI_NODATA:
|
|
#endif /* if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) */
|
|
if (!logged(namebuf, ERR_NO_ADDRESSES)) {
|
|
dns_zone_log(zone, ISC_LOG_ERROR,
|
|
"%s/SRV '%s' (out of zone) "
|
|
"has no addresses records (A or AAAA)",
|
|
ownerbuf, namebuf);
|
|
add(namebuf, ERR_NO_ADDRESSES);
|
|
}
|
|
/* XXX950 make fatal for 9.5.0. */
|
|
return (true);
|
|
|
|
default:
|
|
if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
|
|
dns_zone_log(zone, ISC_LOG_WARNING,
|
|
"getaddrinfo(%s) failed: %s", namebuf,
|
|
gai_strerror(result));
|
|
add(namebuf, ERR_LOOKUP_FAILURE);
|
|
}
|
|
return (true);
|
|
}
|
|
}
|
|
|
|
isc_result_t
|
|
setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) {
|
|
isc_logdestination_t destination;
|
|
isc_logconfig_t *logconfig = NULL;
|
|
isc_log_t *log = NULL;
|
|
|
|
isc_log_create(mctx, &log, &logconfig);
|
|
isc_log_registercategories(log, categories);
|
|
isc_log_setcontext(log);
|
|
dns_log_init(log);
|
|
dns_log_setcontext(log);
|
|
cfg_log_init(log);
|
|
ns_log_init(log);
|
|
|
|
destination.file.stream = errout;
|
|
destination.file.name = NULL;
|
|
destination.file.versions = ISC_LOG_ROLLNEVER;
|
|
destination.file.maximum_size = 0;
|
|
isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC,
|
|
ISC_LOG_DYNAMIC, &destination, 0);
|
|
|
|
RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL) ==
|
|
ISC_R_SUCCESS);
|
|
|
|
*logp = log;
|
|
return (ISC_R_SUCCESS);
|
|
}
|
|
|
|
/*% load the zone */
|
|
isc_result_t
|
|
load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
|
|
dns_masterformat_t fileformat, const char *classname,
|
|
dns_ttl_t maxttl, dns_zone_t **zonep) {
|
|
isc_result_t result;
|
|
dns_rdataclass_t rdclass;
|
|
isc_textregion_t region;
|
|
isc_buffer_t buffer;
|
|
dns_fixedname_t fixorigin;
|
|
dns_name_t *origin;
|
|
dns_zone_t *zone = NULL;
|
|
|
|
REQUIRE(zonep == NULL || *zonep == NULL);
|
|
|
|
if (debug) {
|
|
fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
|
|
zonename, filename, classname);
|
|
}
|
|
|
|
CHECK(dns_zone_create(&zone, mctx, 0));
|
|
|
|
dns_zone_settype(zone, dns_zone_primary);
|
|
|
|
isc_buffer_constinit(&buffer, zonename, strlen(zonename));
|
|
isc_buffer_add(&buffer, strlen(zonename));
|
|
origin = dns_fixedname_initname(&fixorigin);
|
|
CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL));
|
|
CHECK(dns_zone_setorigin(zone, origin));
|
|
dns_zone_setdbtype(zone, 1, (const char *const *)dbtype);
|
|
if (strcmp(filename, "-") == 0) {
|
|
CHECK(dns_zone_setstream(zone, stdin, fileformat,
|
|
&dns_master_style_default));
|
|
} else {
|
|
CHECK(dns_zone_setfile(zone, filename, fileformat,
|
|
&dns_master_style_default));
|
|
}
|
|
if (journal != NULL) {
|
|
CHECK(dns_zone_setjournal(zone, journal));
|
|
}
|
|
|
|
DE_CONST(classname, region.base);
|
|
region.length = strlen(classname);
|
|
CHECK(dns_rdataclass_fromtext(&rdclass, ®ion));
|
|
|
|
dns_zone_setclass(zone, rdclass);
|
|
dns_zone_setoption(zone, zone_options, true);
|
|
dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);
|
|
|
|
dns_zone_setmaxttl(zone, maxttl);
|
|
|
|
if (docheckmx) {
|
|
dns_zone_setcheckmx(zone, checkmx);
|
|
}
|
|
if (docheckns) {
|
|
dns_zone_setcheckns(zone, checkns);
|
|
}
|
|
if (dochecksrv) {
|
|
dns_zone_setchecksrv(zone, checksrv);
|
|
}
|
|
|
|
CHECK(dns_zone_load(zone, false));
|
|
|
|
if (zonep != NULL) {
|
|
*zonep = zone;
|
|
zone = NULL;
|
|
}
|
|
|
|
cleanup:
|
|
if (zone != NULL) {
|
|
dns_zone_detach(&zone);
|
|
}
|
|
return (result);
|
|
}
|
|
|
|
/*% dump the zone */
|
|
isc_result_t
|
|
dump_zone(const char *zonename, dns_zone_t *zone, const char *filename,
|
|
dns_masterformat_t fileformat, const dns_master_style_t *style,
|
|
const uint32_t rawversion) {
|
|
isc_result_t result;
|
|
FILE *output = stdout;
|
|
const char *flags;
|
|
|
|
flags = (fileformat == dns_masterformat_text) ? "w" : "wb";
|
|
|
|
if (debug) {
|
|
if (filename != NULL && strcmp(filename, "-") != 0) {
|
|
fprintf(stderr, "dumping \"%s\" to \"%s\"\n", zonename,
|
|
filename);
|
|
} else {
|
|
fprintf(stderr, "dumping \"%s\"\n", zonename);
|
|
}
|
|
}
|
|
|
|
if (filename != NULL && strcmp(filename, "-") != 0) {
|
|
result = isc_stdio_open(filename, flags, &output);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
fprintf(stderr,
|
|
"could not open output "
|
|
"file \"%s\" for writing\n",
|
|
filename);
|
|
return (ISC_R_FAILURE);
|
|
}
|
|
}
|
|
|
|
result = dns_zone_dumptostream(zone, output, fileformat, style,
|
|
rawversion);
|
|
if (output != stdout) {
|
|
(void)isc_stdio_close(output);
|
|
}
|
|
|
|
return (result);
|
|
}
|