1862. [func] Add additional zone data constancy checks.

named-checkzone has extended checking of NS, MX and
                        SRV record and the hosts they reference.
                        named has extended post zone load checks.
                        New zone options: check-mx and integrity-check.
                        [RT #4940]
This commit is contained in:
Mark Andrews 2005-05-19 04:59:05 +00:00
parent d73541ea2e
commit c5223c9cb7
25 changed files with 1359 additions and 72 deletions

View file

@ -1,3 +1,10 @@
1862. [func] Add additional zone data constancy checks.
named-checkzone has extended checking of NS, MX and
SRV record and the hosts they reference.
named has extended post zone load checks.
New zone options: check-mx and integrity-check.
[RT #4940]
1861. [placeholder] rt14801
1860. [placeholder] rt14775

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: check-tool.c,v 1.16 2005/04/27 04:55:42 sra Exp $ */
/* $Id: check-tool.c,v 1.17 2005/05/19 04:58:59 marka Exp $ */
/*! \file */
@ -29,6 +29,8 @@
#include <isc/buffer.h>
#include <isc/log.h>
#include <isc/net.h>
#include <isc/netdb.h>
#include <isc/region.h>
#include <isc/stdio.h>
#include <isc/types.h>
@ -36,24 +38,39 @@
#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/types.h>
#include <dns/zone.h>
#ifdef HAVE_ADDRINFO
#ifdef HAVE_GETADDRINFO
#ifdef HAVE_GAISTRERROR
#define USE_GETADDRINFO
#endif
#endif
#endif
#define CHECK(r) \
do { \
do { \
result = (r); \
if (result != ISC_R_SUCCESS) \
goto cleanup; \
} while (0)
if (result != ISC_R_SUCCESS) \
goto cleanup; \
} while (0)
static const char *dbtype[] = { "rbt" };
int debug = 0;
isc_boolean_t nomerge = ISC_TRUE;
isc_boolean_t docheckmx = ISC_TRUE;
isc_boolean_t dochecksrv = ISC_TRUE;
isc_boolean_t docheckns = ISC_TRUE;
unsigned int zone_options = DNS_ZONEOPT_CHECKNS |
DNS_ZONEOPT_CHECKMX |
DNS_ZONEOPT_MANYERRORS |
DNS_ZONEOPT_CHECKNAMES |
DNS_ZONEOPT_INTEGRITYCHECK |
DNS_ZONEOPT_CHECKWILDCARD;
/*
@ -70,6 +87,279 @@ static isc_logcategory_t categories[] = {
{ NULL, 0 }
};
static isc_boolean_t
checkns(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner,
dns_rdataset_t *a, dns_rdataset_t *aaaa)
{
#ifdef USE_GETADDRINFO
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")];
isc_boolean_t answer = ISC_TRUE;
isc_boolean_t 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);
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)
strcat(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:
if (strcasecmp(ai->ai_canonname, namebuf) != 0) {
dns_zone_log(zone, ISC_LOG_ERROR,
"%s/NS '%s' (out of zone) "
"is a CNAME (illegal)",
ownerbuf, namebuf);
answer = ISC_FALSE;
}
break;
case EAI_NONAME:
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
case EAI_NODATA:
#endif
dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' (out of zone) "
"has no addresses records (A or AAAA)",
ownerbuf, namebuf);
return (ISC_FALSE);
default:
dns_zone_log(zone, ISC_LOG_WARNING,
"getaddrinfo(%s) failed: %s",
namebuf, gai_strerror(result));
return (ISC_TRUE);
}
if (a == NULL || aaaa == NULL)
return (answer);
/*
* 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 = ISC_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 = ISC_TRUE;
break;
}
}
if (!match) {
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)));
answer = ISC_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 = ISC_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 = ISC_TRUE;
break;
}
}
if (!match) {
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)));
answer = ISC_FALSE;
}
dns_rdata_reset(&rdata);
result = dns_rdataset_next(aaaa);
}
checkmissing:
/*
* Check that all addresses appear in the glue.
*/
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 = ISC_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 = ISC_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)));
answer = ISC_FALSE;
}
}
freeaddrinfo(ai);
return (answer);
#else
return (ISC_TRUE);
#endif
}
static isc_boolean_t
checkmx(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
#ifdef USE_GETADDRINFO
struct addrinfo hints, *ai;
char namebuf[DNS_NAME_FORMATSIZE + 1];
char ownerbuf[DNS_NAME_FORMATSIZE];
int result;
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)
strcat(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:
if (strcasecmp(ai->ai_canonname, namebuf) != 0)
dns_zone_log(zone, ISC_LOG_WARNING,
"%s/MX '%s' (out of zone) "
"is a CNAME (illegal)",
ownerbuf, namebuf);
freeaddrinfo(ai);
break;
case EAI_NONAME:
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
case EAI_NODATA:
#endif
dns_zone_log(zone, ISC_LOG_ERROR, "%s/MX '%s' (out of zone) "
"has no addresses records (A or AAAA)",
ownerbuf, namebuf);
return (ISC_FALSE);
default:
dns_zone_log(zone, ISC_LOG_WARNING,
"getaddrinfo(%s) failed: %s",
namebuf, gai_strerror(result));
return (ISC_TRUE);
}
#endif
return (ISC_TRUE);
}
static isc_boolean_t
checksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
#ifdef USE_GETADDRINFO
struct addrinfo hints, *ai;
char namebuf[DNS_NAME_FORMATSIZE + 1];
char ownerbuf[DNS_NAME_FORMATSIZE];
int result;
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)
strcat(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:
if (strcasecmp(ai->ai_canonname, namebuf) != 0)
dns_zone_log(zone, ISC_LOG_WARNING,
"%s/SRV '%s' (out of zone) "
"is a CNAME (illegal)",
ownerbuf, namebuf);
freeaddrinfo(ai);
break;
case EAI_NONAME:
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
case EAI_NODATA:
#endif
dns_zone_log(zone, ISC_LOG_ERROR, "%s/SRV '%s' (out of zone) "
"has no addresses records (A or AAAA)",
ownerbuf, namebuf);
return (ISC_FALSE);
default:
dns_zone_log(zone, ISC_LOG_WARNING,
"getaddrinfo(%s) failed: %s",
namebuf, gai_strerror(result));
return (ISC_TRUE);
}
#endif
return (ISC_TRUE);
}
isc_result_t
setup_logging(isc_mem_t *mctx, isc_log_t **logp) {
isc_logdestination_t destination;
@ -124,7 +414,7 @@ load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
dns_fixedname_init(&fixorigin);
origin = dns_fixedname_name(&fixorigin);
CHECK(dns_name_fromtext(origin, &buffer, dns_rootname,
ISC_FALSE, NULL));
ISC_FALSE, NULL));
CHECK(dns_zone_setorigin(zone, origin));
CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype));
CHECK(dns_zone_setfile(zone, filename));
@ -136,6 +426,12 @@ load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
dns_zone_setclass(zone, rdclass);
dns_zone_setoption(zone, zone_options, ISC_TRUE);
dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);
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));
if (zonep != NULL){

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: check-tool.h,v 1.9 2005/04/29 00:22:24 marka Exp $ */
/* $Id: check-tool.h,v 1.10 2005/05/19 04:58:59 marka Exp $ */
#ifndef CHECK_TOOL_H
#define CHECK_TOOL_H
@ -41,6 +41,9 @@ dump_zone(const char *zonename, dns_zone_t *zone, const char *filename);
extern int debug;
extern isc_boolean_t nomerge;
extern isc_boolean_t docheckmx;
extern isc_boolean_t docheckns;
extern isc_boolean_t dochecksrv;
extern unsigned int zone_options;
ISC_LANG_ENDDECLS

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: named-checkconf.c,v 1.31 2005/04/27 04:55:43 sra Exp $ */
/* $Id: named-checkconf.c,v 1.32 2005/05/19 04:58:59 marka Exp $ */
/*! \file */
@ -41,11 +41,14 @@
#include <dns/fixedname.h>
#include <dns/log.h>
#include <dns/name.h>
#include <dns/result.h>
#include <dns/zone.h>
#include "check-tool.h"
isc_log_t *logc = NULL;
static isc_entropy_t *ectx = NULL;
#define CHECK(r)\
do { \
@ -88,10 +91,54 @@ directory_callback(const char *clausename, cfg_obj_t *obj, void *arg) {
return (ISC_R_SUCCESS);
}
static isc_boolean_t
get_maps(cfg_obj_t **maps, const char *name, cfg_obj_t **obj) {
int i;
for (i = 0;; i++) {
if (maps[i] == NULL)
return (ISC_FALSE);
if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
return (ISC_TRUE);
}
}
static isc_boolean_t
get_checknames(cfg_obj_t **maps, cfg_obj_t **obj) {
cfg_listelt_t *element;
cfg_obj_t *checknames;
cfg_obj_t *type;
cfg_obj_t *value;
isc_result_t result;
int i;
for (i = 0;; i++) {
if (maps[i] == NULL)
return (ISC_FALSE);
checknames = NULL;
result = cfg_map_get(maps[i], "check-names", &checknames);
if (result != ISC_R_SUCCESS)
continue;
if (checknames != NULL && !cfg_obj_islist(checknames)) {
*obj = checknames;
return (ISC_TRUE);
}
for (element = cfg_list_first(checknames);
element != NULL;
element = cfg_list_next(element)) {
value = cfg_listelt_value(element);
type = cfg_tuple_get(value, "type");
if (strcasecmp(cfg_obj_asstring(type), "master") != 0)
continue;
*obj = cfg_tuple_get(value, "mode");
return (ISC_TRUE);
}
}
}
/*% configure the zone */
static isc_result_t
configure_zone(const char *vclass, const char *view, cfg_obj_t *zconfig,
isc_mem_t *mctx)
cfg_obj_t *vconfig, cfg_obj_t *config, isc_mem_t *mctx)
{
isc_result_t result;
const char *zclass;
@ -102,6 +149,13 @@ configure_zone(const char *vclass, const char *view, cfg_obj_t *zconfig,
cfg_obj_t *typeobj = NULL;
cfg_obj_t *fileobj = NULL;
cfg_obj_t *dbobj = NULL;
cfg_obj_t *obj = NULL;
cfg_obj_t *maps[4];
int i = 0;
zone_options = DNS_ZONEOPT_CHECKNS |
DNS_ZONEOPT_MANYERRORS |
DNS_ZONEOPT_INTEGRITYCHECK;
zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
classobj = cfg_tuple_get(zconfig, "class");
@ -109,7 +163,18 @@ configure_zone(const char *vclass, const char *view, cfg_obj_t *zconfig,
zclass = vclass;
else
zclass = cfg_obj_asstring(classobj);
zoptions = cfg_tuple_get(zconfig, "options");
maps[i++] = zoptions;
if (vconfig != NULL)
maps[i++] = cfg_tuple_get(vconfig, "options");
if (config != NULL) {
cfg_map_get(config, "options", &obj);
if (obj != NULL)
maps[i++] = obj;
}
maps[i++] = NULL;
cfg_map_get(zoptions, "type", &typeobj);
if (typeobj == NULL)
return (ISC_R_FAILURE);
@ -122,6 +187,43 @@ configure_zone(const char *vclass, const char *view, cfg_obj_t *zconfig,
if (fileobj == NULL)
return (ISC_R_FAILURE);
zfile = cfg_obj_asstring(fileobj);
obj = NULL;
if (get_maps(maps, "check-mx", &obj)) {
if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
zone_options |= DNS_ZONEOPT_CHECKMX;
zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
zone_options |= DNS_ZONEOPT_CHECKMX;
zone_options |= DNS_ZONEOPT_CHECKMXFAIL;
} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
zone_options &= ~DNS_ZONEOPT_CHECKMX;
zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
} else
INSIST(0);
} else {
zone_options |= DNS_ZONEOPT_CHECKMX;
zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
}
obj = NULL;
if (get_checknames(maps, &obj)) {
if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
zone_options |= DNS_ZONEOPT_CHECKNAMES;
zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
zone_options |= DNS_ZONEOPT_CHECKNAMES;
zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
zone_options &= ~DNS_ZONEOPT_CHECKNAMES;
zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
} else
INSIST(0);
} else {
zone_options |= DNS_ZONEOPT_CHECKNAMES;
zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
}
result = load_zone(mctx, zname, zfile, zclass, NULL);
if (result != ISC_R_SUCCESS)
fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass,
@ -155,7 +257,8 @@ configure_view(const char *vclass, const char *view, cfg_obj_t *config,
element = cfg_list_next(element))
{
cfg_obj_t *zconfig = cfg_listelt_value(element);
tresult = configure_zone(vclass, view, zconfig, mctx);
tresult = configure_zone(vclass, view, zconfig, vconfig,
config, mctx);
if (tresult != ISC_R_SUCCESS)
result = tresult;
}
@ -248,6 +351,9 @@ main(int argc, char **argv) {
case 'z':
load_zones = ISC_TRUE;
docheckmx = ISC_FALSE;
docheckns = ISC_FALSE;
dochecksrv = ISC_FALSE;
break;
default:
@ -268,6 +374,10 @@ main(int argc, char **argv) {
RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE)
== ISC_R_SUCCESS);
RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS);
RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE)
== ISC_R_SUCCESS);
dns_result_register();
RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS);
@ -294,6 +404,8 @@ main(int argc, char **argv) {
cfg_parser_destroy(&parser);
isc_hash_destroy();
isc_log_destroy(&logc);
isc_hash_destroy();

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: named-checkzone.c,v 1.34 2005/04/27 04:55:43 sra Exp $ */
/* $Id: named-checkzone.c,v 1.35 2005/05/19 04:58:59 marka Exp $ */
/*! \file */
@ -39,6 +39,7 @@
#include <dns/db.h>
#include <dns/fixedname.h>
#include <dns/log.h>
#include <dns/name.h>
#include <dns/rdataclass.h>
#include <dns/rdataset.h>
#include <dns/result.h>
@ -69,7 +70,9 @@ usage(void) {
fprintf(stderr,
"usage: named-checkzone [-djqvD] [-c class] [-o output] "
"[-t directory] [-w directory] [-k (ignore|warn|fail)] "
"[-n (ignore|warn|fail)] [-W (ignore|warn)] zonename filename\n");
"[-n (ignore|warn|fail)] [-m (ignore|warn|fail)] "
"[-i (full|local|none)] [-W (ignore|warn)] "
"zonename filename\n");
exit(1);
}
@ -91,7 +94,8 @@ main(int argc, char **argv) {
char *classname = classname_in;
const char *workdir = NULL;
while ((c = isc_commandline_parse(argc, argv, "c:dijk:n:qst:o:vw:DW:")) != EOF) {
while ((c = isc_commandline_parse(argc, argv,
"c:di:jk:m:n:qst:o:vw:DW:")) != EOF) {
switch (c) {
case 'c':
classname = isc_commandline_argument;
@ -101,20 +105,33 @@ main(int argc, char **argv) {
debug++;
break;
case 'j':
nomerge = ISC_FALSE;
case 'i':
if (!strcmp(isc_commandline_argument, "full")) {
zone_options |= DNS_ZONEOPT_INTEGRITYCHECK;
docheckmx = ISC_TRUE;
docheckns = ISC_TRUE;
dochecksrv = ISC_TRUE;
} else if (!strcmp(isc_commandline_argument,
"local")) {
zone_options |= DNS_ZONEOPT_INTEGRITYCHECK;
docheckmx = ISC_FALSE;
docheckns = ISC_FALSE;
dochecksrv = ISC_FALSE;
} else if (!strcmp(isc_commandline_argument,
"none")) {
zone_options &= ~DNS_ZONEOPT_INTEGRITYCHECK;
docheckmx = ISC_FALSE;
docheckns = ISC_FALSE;
dochecksrv = ISC_FALSE;
} else {
fprintf(stderr, "invalid argument to -i: %s\n",
isc_commandline_argument);
exit(1);
}
break;
case 'n':
if (!strcmp(isc_commandline_argument, "ignore"))
zone_options &= ~(DNS_ZONEOPT_CHECKNS|
DNS_ZONEOPT_FATALNS);
else if (!strcmp(isc_commandline_argument, "warn")) {
zone_options |= DNS_ZONEOPT_CHECKNS;
zone_options &= ~DNS_ZONEOPT_FATALNS;
} else if (!strcmp(isc_commandline_argument, "fail"))
zone_options |= DNS_ZONEOPT_CHECKNS|
DNS_ZONEOPT_FATALNS;
case 'j':
nomerge = ISC_FALSE;
break;
case 'k':
@ -129,6 +146,46 @@ main(int argc, char **argv) {
"ignore")) {
zone_options &= ~(DNS_ZONEOPT_CHECKNAMES |
DNS_ZONEOPT_CHECKNAMESFAIL);
} else {
fprintf(stderr, "invalid argument to -k: %s\n",
isc_commandline_argument);
exit(1);
}
break;
case 'n':
if (!strcmp(isc_commandline_argument, "ignore")) {
zone_options &= ~(DNS_ZONEOPT_CHECKNS|
DNS_ZONEOPT_FATALNS);
} else if (!strcmp(isc_commandline_argument, "warn")) {
zone_options |= DNS_ZONEOPT_CHECKNS;
zone_options &= ~DNS_ZONEOPT_FATALNS;
} else if (!strcmp(isc_commandline_argument, "fail")) {
zone_options |= DNS_ZONEOPT_CHECKNS|
DNS_ZONEOPT_FATALNS;
} else {
fprintf(stderr, "invalid argument to -n: %s\n",
isc_commandline_argument);
exit(1);
}
break;
case 'm':
if (!strcmp(isc_commandline_argument, "warn")) {
zone_options |= DNS_ZONEOPT_CHECKMX;
zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
} else if (!strcmp(isc_commandline_argument,
"fail")) {
zone_options |= DNS_ZONEOPT_CHECKMX |
DNS_ZONEOPT_CHECKMXFAIL;
} else if (!strcmp(isc_commandline_argument,
"ignore")) {
zone_options &= ~(DNS_ZONEOPT_CHECKMX |
DNS_ZONEOPT_CHECKMXFAIL);
} else {
fprintf(stderr, "invalid argument to -m: %s\n",
isc_commandline_argument);
exit(1);
}
break;

View file

@ -18,7 +18,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- $Id: named-checkzone.docbook,v 1.18 2005/05/13 01:35:38 marka Exp $ -->
<!-- $Id: named-checkzone.docbook,v 1.19 2005/05/19 04:58:59 marka Exp $ -->
<refentry>
<refentryinfo>
<date>June 13, 2000</date>
@ -57,7 +57,9 @@
<arg><option>-q</option></arg>
<arg><option>-v</option></arg>
<arg><option>-c <replaceable class="parameter">class</replaceable></option></arg>
<arg><option>-i <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-k <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-m <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-n <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-o <replaceable class="parameter">filename</replaceable></option></arg>
<arg><option>-t <replaceable class="parameter">directory</replaceable></option></arg>
@ -129,6 +131,42 @@
</listitem>
</varlistentry>
<varlistentry>
<term>-i <replaceable class="parameter">mode</replaceable></term>
<listitem>
<para>
Perform post load zone integrity checks. Possible modes are
<command>"full"</command> (default),
<command>"local"</command> and
<command>"none"</command>.
</para>
<para>
Mode <command>"full"</command> checks that MX records
refer to A or AAAA record (both in-zone and out-of-zone
hostnames). Mode <command>"local"</command> only
checks MX records which refer to in-zone hostnames.
</para>
<para>
Mode <command>"full"</command> checks that SRV records
refer to A or AAAA record (both in-zone and out-of-zone
hostnames). Mode <command>"local"</command> only
checks SRV records which refer to in-zone hostnames.
</para>
<para>
Mode <command>"full"</command> checks that delegation NS
records refer to A or AAAA record (both in-zone and out-of-zone
hostnames). It also checks that glue addresses records
in the zone match those advertised by the child.
Mode <command>"local"</command> only checks NS records which
refer to in-zone hostnames or that some required glue exists,
that is when the nameserver is in a child zone.
</para>
<para>
Mode <command>"none"</command> disables the checks.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-k <replaceable class="parameter">mode</replaceable></term>
<listitem>
@ -142,6 +180,18 @@
</listitem>
</varlistentry>
<varlistentry>
<term>-m <replaceable class="parameter">mode</replaceable></term>
<listitem>
<para>
Specify whether MX records should be checked to see if they
are addresses. Possible modes are <command>"fail"</command>,
<command>"warn"</command> (default) and
<command>"ignore"</command>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-n <replaceable class="parameter">mode</replaceable></term>
<listitem>

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: config.c,v 1.56 2005/04/27 04:55:49 sra Exp $ */
/* $Id: config.c,v 1.57 2005/05/19 04:59:00 marka Exp $ */
/*! \file */
@ -128,10 +128,12 @@ options {\n\
check-names master fail;\n\
check-names slave warn;\n\
check-names response ignore;\n\
check-mx warn;\n\
use-additional-cache true;\n\
acache-cleaning-interval 60;\n\
max-acache-size 0;\n\
dnssec-enable no; /* Make yes for 9.4. */ \n\
integrity-check yes;\n\
"
" /* zone */\n\

View file

@ -17,7 +17,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- $Id: named.conf.docbook,v 1.10 2005/05/13 01:35:40 marka Exp $ -->
<!-- $Id: named.conf.docbook,v 1.11 2005/05/19 04:59:00 marka Exp $ -->
<refentry>
<refentryinfo>
<date>Aug 13, 2004</date>
@ -240,6 +240,8 @@ options {
max-cache-size <replaceable>size_no_default</replaceable>;
check-names ( master | slave | response )
( fail | warn | ignore );
check-mx ( fail | warn | ignore );
integrity-check <replaceable>boolean</replaceable>;
cache-file <replaceable>quoted_string</replaceable>;
suppress-initial-notify <replaceable>boolean</replaceable>; // not yet implemented
preferred-glue <replaceable>string</replaceable>;
@ -370,6 +372,8 @@ view <replaceable>string</replaceable> <replaceable>optional_class</replaceable>
max-cache-size <replaceable>size_no_default</replaceable>;
check-names ( master | slave | response )
( fail | warn | ignore );
check-mx ( fail | warn | ignore );
integrity-check <replaceable>boolean</replaceable>;
cache-file <replaceable>quoted_string</replaceable>;
suppress-initial-notify <replaceable>boolean</replaceable>; // not yet implemented
preferred-glue <replaceable>string</replaceable>;
@ -458,6 +462,8 @@ zone <replaceable>string</replaceable> <replaceable>optional_class</replaceable>
database <replaceable>string</replaceable>;
delegation-only <replaceable>boolean</replaceable>;
check-names ( fail | warn | ignore );
check-mx ( fail | warn | ignore );
integrity-check <replaceable>boolean</replaceable>;
dialup <replaceable>dialuptype</replaceable>;
ixfr-from-differences <replaceable>boolean</replaceable>;
journal <replaceable>quoted_string</replaceable>;

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: update.c,v 1.121 2005/04/27 04:55:55 sra Exp $ */
/* $Id: update.c,v 1.122 2005/05/19 04:59:00 marka Exp $ */
#include <config.h>
@ -36,6 +36,7 @@
#include <dns/rdataclass.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
#include <dns/rdatastruct.h>
#include <dns/rdatatype.h>
#include <dns/soa.h>
#include <dns/ssu.h>
@ -2129,6 +2130,112 @@ remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) {
return (result);
}
/*
* This implements the post load integrity checks for mx records.
*/
static isc_result_t
check_mx(ns_client_t *client, dns_zone_t *zone,
dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff)
{
char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")];
char ownerbuf[DNS_NAME_FORMATSIZE];
char namebuf[DNS_NAME_FORMATSIZE];
char altbuf[DNS_NAME_FORMATSIZE];
dns_difftuple_t *t;
dns_fixedname_t fixed;
dns_name_t *foundname;
dns_rdata_mx_t mx;
dns_rdata_t rdata;
isc_boolean_t ok = ISC_TRUE;
isc_boolean_t isaddress;
isc_result_t result;
struct in6_addr addr6;
struct in_addr addr;
unsigned int options;
dns_fixedname_init(&fixed);
foundname = dns_fixedname_name(&fixed);
dns_rdata_init(&rdata);
options = dns_zone_getoptions(zone);
for (t = ISC_LIST_HEAD(diff->tuples);
t != NULL;
t = ISC_LIST_NEXT(t, link)) {
if (t->op != DNS_DIFFOP_DEL ||
t->rdata.type != dns_rdatatype_mx)
continue;
result = dns_rdata_tostruct(&t->rdata, &mx, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
/*
* Check if we will error out if we attempt to reload the
* zone.
*/
dns_name_format(&mx.mx, namebuf, sizeof(namebuf));
dns_name_format(&t->name, ownerbuf, sizeof(ownerbuf));
isaddress = ISC_FALSE;
if ((options & DNS_RDATA_CHECKMX) != 0 &&
strlcpy(tmp, namebuf, sizeof(tmp)) < sizeof(tmp)) {
if (tmp[strlen(tmp) - 1] == '.')
tmp[strlen(tmp) - 1] = '\0';
if (inet_aton(tmp, &addr) == 1 ||
inet_pton(AF_INET6, tmp, &addr6) == 1)
isaddress = ISC_TRUE;
}
if (isaddress && (options & DNS_RDATA_CHECKMXFAIL) != 0) {
update_log(client, zone, ISC_LOG_ERROR,
"%s/MX: '%s': %s",
ownerbuf, namebuf,
dns_result_totext(DNS_R_MXISADDRESS));
ok = ISC_FALSE;
} else if (isaddress) {
update_log(client, zone, ISC_LOG_WARNING,
"%s/MX: warning: '%s': %s",
ownerbuf, namebuf,
dns_result_totext(DNS_R_MXISADDRESS));
}
/*
* Check zone integrity checks.
*/
if ((options & DNS_ZONEOPT_INTEGRITYCHECK) == 0)
continue;
result = dns_db_find(db, &mx.mx, newver, dns_rdatatype_a,
0, 0, NULL, foundname, NULL, NULL);
if (result == ISC_R_SUCCESS)
continue;
if (result == DNS_R_NXRRSET) {
result = dns_db_find(db, &mx.mx, newver,
dns_rdatatype_aaaa,
0, 0, NULL, foundname,
NULL, NULL);
if (result == ISC_R_SUCCESS)
continue;
}
if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN) {
update_log(client, zone, ISC_LOG_ERROR,
"%s/MX '%s' has no address records "
"(A or AAAA)", ownerbuf, namebuf);
ok = ISC_FALSE;
} else if (result == DNS_R_CNAME) {
update_log(client, zone, ISC_LOG_ERROR,
"%s/MX '%s' is a CNAME (illegal)",
ownerbuf, namebuf);
ok = ISC_FALSE;
} else if (result == DNS_R_DNAME) {
dns_name_format(foundname, altbuf, sizeof altbuf);
update_log(client, zone, ISC_LOG_ERROR,
"%s/MX '%s' is below a DNAME '%s' (illegal)",
ownerbuf, namebuf, altbuf);
ok = ISC_FALSE;
}
}
return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED);
}
static void
update_action(isc_task_t *task, isc_event_t *event) {
update_event_t *uev = (update_event_t *) event;
@ -2628,6 +2735,8 @@ update_action(isc_task_t *task, isc_event_t *event) {
CHECK(increment_soa_serial(db, ver, &diff, mctx));
}
CHECK(check_mx(client, zone, db, ver, &diff));
CHECK(remove_orphaned_ds(db, ver, &diff));
if (dns_db_issecure(db)) {

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zoneconf.c,v 1.120 2005/04/27 04:55:56 sra Exp $ */
/* $Id: zoneconf.c,v 1.121 2005/05/19 04:59:01 marka Exp $ */
/*% */
@ -613,6 +613,7 @@ ns_zone_configure(cfg_obj_t *config, cfg_obj_t *vconfig, cfg_obj_t *zconfig,
}
RETERR(dns_zone_setkeydirectory(zone, filename));
}
obj = NULL;
result = ns_config_get(maps, "check-wildcard", &obj);
if (result == ISC_R_SUCCESS)
@ -620,6 +621,69 @@ ns_zone_configure(cfg_obj_t *config, cfg_obj_t *vconfig, cfg_obj_t *zconfig,
else
check = ISC_FALSE;
dns_zone_setoption(zone, DNS_ZONEOPT_CHECKWILDCARD, check);
obj = NULL;
result = ns_config_get(maps, "check-mx", &obj);
INSIST(obj != NULL);
if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
fail = ISC_FALSE;
check = ISC_TRUE;
} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
fail = check = ISC_TRUE;
} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
fail = check = ISC_FALSE;
} else
INSIST(0);
dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMX, check);
dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMXFAIL, fail);
obj = NULL;
result = ns_config_get(maps, "integrity-check", &obj);
INSIST(obj != NULL);
dns_zone_setoption(zone, DNS_ZONEOPT_INTEGRITYCHECK,
cfg_obj_asboolean(obj));
}
/*
* Configure update-related options. These apply to
* primary masters only.
*/
if (ztype == dns_zone_master) {
dns_acl_t *updateacl;
RETERR(configure_zone_acl(zconfig, vconfig, config,
"allow-update", ac, zone,
dns_zone_setupdateacl,
dns_zone_clearupdateacl));
updateacl = dns_zone_getupdateacl(zone);
if (updateacl != NULL && dns_acl_isinsecure(updateacl))
isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
"zone '%s' allows updates by IP "
"address, which is insecure",
zname);
RETERR(configure_zone_ssutable(zoptions, zone));
obj = NULL;
result = ns_config_get(maps, "sig-validity-interval", &obj);
INSIST(result == ISC_R_SUCCESS);
dns_zone_setsigvalidityinterval(zone,
cfg_obj_asuint32(obj) * 86400);
obj = NULL;
result = ns_config_get(maps, "key-directory", &obj);
if (result == ISC_R_SUCCESS) {
filename = cfg_obj_asstring(obj);
if (!isc_file_isabsolute(filename)) {
cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
"key-directory '%s' "
"is not absolute", filename);
return (ISC_R_FAILURE);
}
RETERR(dns_zone_setkeydirectory(zone, filename));
}
} else if (ztype == dns_zone_slave) {
RETERR(configure_zone_acl(zconfig, vconfig, config,
"allow-update-forwarding", ac, zone,

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: named.conf,v 1.12 2004/03/05 05:01:58 marka Exp $ */
/* $Id: named.conf,v 1.13 2005/05/19 04:59:01 marka Exp $ */
controls { /* empty */ };
@ -43,6 +43,7 @@ controls {
zone "example.nil" {
type master;
file "example.db";
integrity-check no;
allow-update { any; };
allow-transfer { any; };
};
@ -50,6 +51,7 @@ zone "example.nil" {
zone "update.nil" {
type master;
file "update.db";
integrity-check no;
allow-update { any; };
allow-transfer { any; };
also-notify { 10.53.0.2; };

View file

@ -18,7 +18,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- File: $Id: Bv9ARM-book.xml,v 1.268 2005/05/13 01:35:42 marka Exp $ -->
<!-- File: $Id: Bv9ARM-book.xml,v 1.269 2005/05/19 04:59:01 marka Exp $ -->
<book>
<title>BIND 9 Administrator Reference Manual</title>
@ -4307,7 +4307,9 @@ category notify { null; };
<optional> forwarders { <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> ; <optional> <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> ; ... </optional> }; </optional>
<optional> dual-stack-servers <optional>port <replaceable>ip_port</replaceable></optional> { ( <replaceable>domain_name</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> | <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> ) ; ... }; </optional>
<optional> check-names ( <replaceable>master</replaceable> | <replaceable>slave</replaceable> | <replaceable>response</replaceable> )( <replaceable>warn</replaceable> | <replaceable>fail</replaceable> | <replaceable>ignore</replaceable> ); </optional>
<optional> check-mx ( <replaceable>warn</replaceable> | <replaceable>fail</replaceable> | <replaceable>ignore</replaceable> ); </optional>
<optional> check-wildcard <replaceable>yes_or_no</replaceable>; </optional>
<optional> integrity-checks <replaceable>yes_or_no</replaceable>; </optional>
<optional> allow-notify { <replaceable>address_match_list</replaceable> }; </optional>
<optional> allow-query { <replaceable>address_match_list</replaceable> }; </optional>
<optional> allow-query-cache { <replaceable>address_match_list</replaceable> }; </optional>
@ -5423,6 +5425,18 @@ options {
</listitem>
</varlistentry>
<varlistentry>
<term><command>check-mx</command></term>
<listitem>
<para>
Check whether the MX record appears to refer to a IP address.
The default is to <command>warn</command>. Other possible
values are <command>fail</command> and
<command>ignore</command>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>check-wildcard</command></term>
<listitem>
@ -5438,6 +5452,24 @@ options {
</listitem>
</varlistentry>
<varlistentry>
<term><command>integrity-check</command></term>
<listitem>
<para>
Perform post load zone integrity checks on master
zones. This checks that MX and SRV records refer
to address (A or AAAA) records and that glue
address records exist for delegated zones. For
MX and SRV records only in-zone hostnames are
checked (for out-of-zone hostnames use named-checkzone).
For NS records only names below top of zone are
checked (for out-of-zone names and glue consistancy
checks use named-checkzone). The default is
<command>yes</command>.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect3>
@ -7497,7 +7529,9 @@ view "external" {
<optional> allow-update-forwarding { <replaceable>address_match_list</replaceable> } ; </optional>
<optional> also-notify { <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> ; <optional> <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> ; ... </optional> }; </optional>
<optional> check-names (<constant>warn</constant>|<constant>fail</constant>|<constant>ignore</constant>) ; </optional>
<optional> check-mx (<constant>warn</constant>|<constant>fail</constant>|<constant>ignore</constant>) ; </optional>
<optional> check-wildcard <replaceable>yes_or_no</replaceable>; </optional>
<optional> integrity-checks <replaceable>yes_or_no</replaceable> ; </optional>
<optional> dialup <replaceable>dialup_option</replaceable> ; </optional>
<optional> delegation-only <replaceable>yes_or_no</replaceable> ; </optional>
<optional> file <replaceable>string</replaceable> ; </optional>
@ -7884,6 +7918,16 @@ view "external" {
</listitem>
</varlistentry>
<varlistentry>
<term><command>check-mx</command></term>
<listitem>
<para>
See the description of
<command>check-mx</command> in <xref linkend="boolean_options"/>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>check-wildcard</command></term>
<listitem>
@ -7894,6 +7938,16 @@ view "external" {
</listitem>
</varlistentry>
<varlistentry>
<term><command>integrity-check</command></term>
<listitem>
<para>
See the description of
<command>integrity-check</command> in <xref linkend="boolean_options"/>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>database</command></term>
<listitem>

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: check.c,v 1.57 2005/04/27 04:56:43 sra Exp $ */
/* $Id: check.c,v 1.58 2005/05/19 04:59:02 marka Exp $ */
/*! \file */
@ -799,6 +799,8 @@ check_zoneconf(cfg_obj_t *zconfig, cfg_obj_t *voptions, cfg_obj_t *config,
{ "database", MASTERZONE | SLAVEZONE | STUBZONE },
{ "key-directory", MASTERZONE },
{ "check-wildcard", MASTERZONE },
{ "check-mx", MASTERZONE },
{ "integrity-check", MASTERZONE },
};
static optionstable dialups[] = {

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: master.h,v 1.42 2005/04/27 04:56:56 sra Exp $ */
/* $Id: master.h,v 1.43 2005/05/19 04:59:04 marka Exp $ */
#ifndef DNS_MASTER_H
#define DNS_MASTER_H 1
@ -52,6 +52,8 @@
#define DNS_MASTER_CHECKNAMES 0x00000100
#define DNS_MASTER_CHECKNAMESFAIL 0x00000200
#define DNS_MASTER_CHECKWILDCARD 0x00000400 /* Check for internal wildcards. */
#define DNS_MASTER_CHECKMX 0x00000800
#define DNS_MASTER_CHECKMXFAIL 0x00001000
ISC_LANG_BEGINDECLS

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: name.h,v 1.115 2005/04/27 04:56:57 sra Exp $ */
/* $Id: name.h,v 1.116 2005/05/19 04:59:04 marka Exp $ */
#ifndef DNS_NAME_H
#define DNS_NAME_H 1
@ -145,6 +145,8 @@ struct dns_name {
#define DNS_NAME_CHECKNAMES 0x0002 /*%< Used by rdata. */
#define DNS_NAME_CHECKNAMESFAIL 0x0004 /*%< Used by rdata. */
#define DNS_NAME_CHECKREVERSE 0x0008 /*%< Used by rdata. */
#define DNS_NAME_CHECKMX 0x0010 /*%< Used by rdata. */
#define DNS_NAME_CHECKMXFAIL 0x0020 /*%< Used by rdata. */
LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_rootname;
LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_wildcardname;

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rdata.h,v 1.62 2005/04/29 00:23:01 marka Exp $ */
/* $Id: rdata.h,v 1.63 2005/05/19 04:59:04 marka Exp $ */
#ifndef DNS_RDATA_H
#define DNS_RDATA_H 1
@ -143,6 +143,8 @@ struct dns_rdata {
#define DNS_RDATA_CHECKNAMES DNS_NAME_CHECKNAMES
#define DNS_RDATA_CHECKNAMESFAIL DNS_NAME_CHECKNAMESFAIL
#define DNS_RDATA_CHECKREVERSE DNS_NAME_CHECKREVERSE
#define DNS_RDATA_CHECKMX DNS_NAME_CHECKMX
#define DNS_RDATA_CHECKMXFAIL DNS_NAME_CHECKMXFAIL
/***
*** Initialization

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: result.h,v 1.108 2005/04/29 00:23:02 marka Exp $ */
/* $Id: result.h,v 1.109 2005/05/19 04:59:04 marka Exp $ */
#ifndef DNS_RESULT_H
#define DNS_RESULT_H 1
@ -145,8 +145,9 @@
#define DNS_R_UNKNOWNCOMMAND (ISC_RESULTCLASS_DNS + 99)
#define DNS_R_MUSTBESECURE (ISC_RESULTCLASS_DNS + 100)
#define DNS_R_COVERINGNSEC (ISC_RESULTCLASS_DNS + 101)
#define DNS_R_MXISADDRESS (ISC_RESULTCLASS_DNS + 102)
#define DNS_R_NRESULTS 102 /*%< Number of results */
#define DNS_R_NRESULTS 103 /*%< Number of results */
/*
* DNS wire format rcodes.

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: types.h,v 1.114 2005/04/27 04:57:00 sra Exp $ */
/* $Id: types.h,v 1.115 2005/05/19 04:59:04 marka Exp $ */
#ifndef DNS_TYPES_H
#define DNS_TYPES_H 1
@ -298,7 +298,17 @@ typedef void
(*dns_updatecallback_t)(void *, isc_result_t, dns_message_t *);
typedef int
(*dns_rdatasetorderfunc_t)(dns_rdata_t *rdata, void *arg);
(*dns_rdatasetorderfunc_t)(dns_rdata_t *, void *);
typedef isc_boolean_t
(*dns_checkmxfunc_t)(dns_zone_t *, dns_name_t *, dns_name_t *);
typedef isc_boolean_t
(*dns_checksrvfunc_t)(dns_zone_t *, dns_name_t *, dns_name_t *);
typedef isc_boolean_t
(*dns_checknsfunc_t)(dns_zone_t *, dns_name_t *, dns_name_t *,
dns_rdataset_t *, dns_rdataset_t *);
typedef isc_boolean_t
(*dns_isselffunc_t)(dns_view_t *, dns_tsigkey_t *, isc_sockaddr_t *,

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zone.h,v 1.133 2005/04/27 04:57:01 sra Exp $ */
/* $Id: zone.h,v 1.134 2005/05/19 04:59:05 marka Exp $ */
#ifndef DNS_ZONE_H
#define DNS_ZONE_H 1
@ -55,6 +55,9 @@ typedef enum {
#define DNS_ZONEOPT_CHECKNAMES 0x00000800U /*%< check-names */
#define DNS_ZONEOPT_CHECKNAMESFAIL 0x00001000U /*%< fatal check-name failures */
#define DNS_ZONEOPT_CHECKWILDCARD 0x00002000U /*%< check for internal wildcards */
#define DNS_ZONEOPT_CHECKMX 0x00004000U /*%< check-mx */
#define DNS_ZONEOPT_CHECKMXFAIL 0x00008000U /*%< fatal check-mx failures */
#define DNS_ZONEOPT_INTEGRITYCHECK 0x00010000U /*%< perform integrity checks */
#ifndef NOMINUM_PUBLIC
/*
@ -1448,6 +1451,36 @@ dns_zone_setacache(dns_zone_t *zone, dns_acache_t *acache);
* 'zone' will have a reference to 'acache'
*/
void
dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx);
/*
* Set the post load integrity callback function 'checkmx'.
* 'checkmx' will be called if the MX is not within the zone.
*
* Require:
* 'zone' to be a valid zone.
*/
void
dns_zone_setchecksrv(dns_zone_t *zone, dns_checkmxfunc_t checksrv);
/*
* Set the post load integrity callback function 'checksrv'.
* 'checksrv' will be called if the SRV TARGET is not within the zone.
*
* Require:
* 'zone' to be a valid zone.
*/
void
dns_zone_setcheckns(dns_zone_t *zone, dns_checknsfunc_t checkns);
/*
* Set the post load integrity callback function 'checkmx'.
* 'checkmx' will be called if the MX is not within the zone.
*
* Require:
* 'zone' to be a valid zone.
*/
void
dns_zone_setnotifydelay(dns_zone_t *zone, isc_uint32_t delay);
/*

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: master.c,v 1.152 2005/04/27 04:56:47 sra Exp $ */
/* $Id: master.c,v 1.153 2005/05/19 04:59:02 marka Exp $ */
/*! \file */
@ -959,11 +959,16 @@ load(dns_loadctx_t *lctx) {
options |= DNS_RDATA_CHECKNAMES;
if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0)
options |= DNS_RDATA_CHECKNAMESFAIL;
if ((lctx->options & DNS_MASTER_CHECKMX) != 0)
options |= DNS_RDATA_CHECKMX;
if ((lctx->options & DNS_MASTER_CHECKMXFAIL) != 0)
options |= DNS_RDATA_CHECKMXFAIL;
source = isc_lex_getsourcename(lctx->lex);
do {
initialws = ISC_FALSE;
line = isc_lex_getsourceline(lctx->lex);
GETTOKEN(lctx->lex, ISC_LEXOPT_INITIALWS, &token, ISC_TRUE);
GETTOKEN(lctx->lex, ISC_LEXOPT_INITIALWS | ISC_LEXOPT_QSTRING,
&token, ISC_TRUE);
line = isc_lex_getsourceline(lctx->lex);
if (token.type == isc_tokentype_eof) {
@ -999,7 +1004,8 @@ load(dns_loadctx_t *lctx) {
* Still working on the same name.
*/
initialws = ISC_TRUE;
} else if (token.type == isc_tokentype_string) {
} else if (token.type == isc_tokentype_string ||
token.type == isc_tokentype_qstring) {
/*
* "$" Support.

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rdata.c,v 1.188 2005/04/27 04:56:50 sra Exp $ */
/* $Id: rdata.c,v 1.189 2005/05/19 04:59:03 marka Exp $ */
/*! \file */
@ -197,6 +197,10 @@ static void
warn_badname(dns_name_t *name, isc_lex_t *lexer,
dns_rdatacallbacks_t *callbacks);
static void
warn_badmx(isc_token_t *token, isc_lex_t *lexer,
dns_rdatacallbacks_t *callbacks);
static inline int
getquad(const void *src, struct in_addr *dst,
isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks)
@ -1578,6 +1582,22 @@ fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks) {
}
}
static void
warn_badmx(isc_token_t *token, isc_lex_t *lexer,
dns_rdatacallbacks_t *callbacks)
{
const char *file;
unsigned long line;
if (lexer != NULL) {
file = isc_lex_getsourcename(lexer);
line = isc_lex_getsourceline(lexer);
(*callbacks->warn)(callbacks, "%s:%u: warning: '%s': %s",
file, line, DNS_AS_STR(*token),
dns_result_totext(DNS_R_MXISADDRESS));
}
}
static void
warn_badname(dns_name_t *name, isc_lex_t *lexer,
dns_rdatacallbacks_t *callbacks)

View file

@ -15,15 +15,37 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: mx_15.c,v 1.52 2004/03/05 05:10:15 marka Exp $ */
/* $Id: mx_15.c,v 1.53 2005/05/19 04:59:05 marka Exp $ */
/* reviewed: Wed Mar 15 18:05:46 PST 2000 by brister */
#ifndef RDATA_GENERIC_MX_15_C
#define RDATA_GENERIC_MX_15_C
#include <string.h>
#include <isc/net.h>
#define RRTYPE_MX_ATTRIBUTES (0)
static isc_boolean_t
check_mx(isc_token_t *token) {
char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")];
struct in_addr addr;
struct in6_addr addr6;
if (strlcpy(tmp, DNS_AS_STR(*token), sizeof(tmp)) >= sizeof(tmp))
return (ISC_TRUE);
if (tmp[strlen(tmp) - 1] == '.')
tmp[strlen(tmp) - 1] = '\0';
if (inet_aton(tmp, &addr) == 1 ||
inet_pton(AF_INET6, tmp, &addr6) == 1)
return (ISC_FALSE);
return (ISC_TRUE);
}
static inline isc_result_t
fromtext_mx(ARGS_FROMTEXT) {
isc_token_t token;
@ -45,6 +67,15 @@ fromtext_mx(ARGS_FROMTEXT) {
RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
ISC_FALSE));
ok = ISC_TRUE;
if ((options & DNS_RDATA_CHECKMX) != 0)
ok = check_mx(&token);
if (!ok && (options & DNS_RDATA_CHECKMXFAIL) != 0)
RETTOK(DNS_R_MXISADDRESS);
if (!ok && callbacks != NULL)
warn_badmx(&token, lexer, callbacks);
dns_name_init(&name, NULL);
buffer_fromregion(&buffer, &token.value.as_region);
origin = (origin != NULL) ? origin : dns_rootname;

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: result.c,v 1.119 2005/04/29 00:22:51 marka Exp $ */
/* $Id: result.c,v 1.120 2005/05/19 04:59:03 marka Exp $ */
/*! \file */
@ -153,7 +153,8 @@ static const char *text[DNS_R_NRESULTS] = {
"unknown command", /*%< 99 DNS_R_UNKNOWNCOMMAND */
"must-be-secure", /*%< 100 DNS_R_MUSTBESECURE */
"covering NSEC record returned" /*%< 101 DNS_R_COVERINGNSEC */
"covering NSEC record returned", /*%< 101 DNS_R_COVERINGNSEC */
"MX is an address" /*%< 102 DNS_R_MXISADDRESS */
};
static const char *rcode_text[DNS_R_NRCODERESULTS] = {

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zone.c,v 1.433 2005/04/27 04:56:53 sra Exp $ */
/* $Id: zone.c,v 1.434 2005/05/19 04:59:03 marka Exp $ */
/*! \file */
@ -38,6 +38,7 @@
#include <dns/adb.h>
#include <dns/callbacks.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
#include <dns/events.h>
#include <dns/journal.h>
#include <dns/log.h>
@ -179,13 +180,13 @@ struct dns_zone {
unsigned int notifycnt;
isc_sockaddr_t notifyfrom;
isc_task_t *task;
isc_sockaddr_t notifysrc4;
isc_sockaddr_t notifysrc6;
isc_sockaddr_t xfrsource4;
isc_sockaddr_t xfrsource6;
isc_sockaddr_t altxfrsource4;
isc_sockaddr_t altxfrsource6;
isc_sockaddr_t sourceaddr;
isc_sockaddr_t notifysrc4;
isc_sockaddr_t notifysrc6;
isc_sockaddr_t xfrsource4;
isc_sockaddr_t xfrsource6;
isc_sockaddr_t altxfrsource4;
isc_sockaddr_t altxfrsource6;
isc_sockaddr_t sourceaddr;
dns_xfrin_ctx_t *xfr; /* task locked */
dns_tsigkey_t *tsigkey; /* key used for xfr */
/* Access Control Lists */
@ -211,6 +212,9 @@ struct dns_zone {
isc_uint32_t sigvalidityinterval;
dns_view_t *view;
dns_acache_t *acache;
dns_checkmxfunc_t checkmx;
dns_checksrvfunc_t checksrv;
dns_checknsfunc_t checkns;
/*%
* Zones in certain states such as "waiting for zone transfer"
* or "zone transfer in progress" are kept on per-state linked lists
@ -586,6 +590,9 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->sigvalidityinterval = 30 * 24 * 3600;
zone->view = NULL;
zone->acache = NULL;
zone->checkmx = NULL;
zone->checksrv = NULL;
zone->checkns = NULL;
ISC_LINK_INIT(zone, statelink);
zone->statelist = NULL;
zone->counters = NULL;
@ -1025,24 +1032,34 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
goto cleanup;
}
/*
* Store the current time before the zone is loaded, so that if the
* file changes between the time of the load and the time that
* zone->loadtime is set, then the file will still be reloaded
* the next time dns_zone_load is called.
*/
TIME_NOW(&loadtime);
/*
* Don't do the load if the file that stores the zone is older
* than the last time the zone was loaded. If the zone has not
* been loaded yet, zone->loadtime will be the epoch.
*/
if (zone->masterfile != NULL && ! isc_time_isepoch(&zone->loadtime)) {
if (zone->masterfile != NULL) {
/*
* The file is already loaded. If we are just doing a
* "rndc reconfig", we are done.
*/
if ((flags & DNS_ZONELOADFLAG_NOSTAT) != 0) {
if (!isc_time_isepoch(&zone->loadtime) &&
(flags & DNS_ZONELOADFLAG_NOSTAT) != 0) {
result = ISC_R_SUCCESS;
goto cleanup;
}
if (! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE)) {
result = isc_file_getmodtime(zone->masterfile,
&filetime);
if (result == ISC_R_SUCCESS &&
result = isc_file_getmodtime(zone->masterfile, &filetime);
if (result == ISC_R_SUCCESS) {
if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE) &&
isc_time_compare(&filetime, &zone->loadtime) < 0) {
dns_zone_log(zone, ISC_LOG_DEBUG(1),
"skipping load: master file older "
@ -1050,6 +1067,7 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
result = DNS_R_UPTODATE;
goto cleanup;
}
loadtime = filetime;
}
}
@ -1073,14 +1091,6 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
dns_zone_log(zone, ISC_LOG_DEBUG(1), "starting load");
/*
* Store the current time before the zone is loaded, so that if the
* file changes between the time of the load and the time that
* zone->loadtime is set, then the file will still be reloaded
* the next time dns_zone_load is called.
*/
TIME_NOW(&loadtime);
result = dns_db_create(zone->mctx, zone->db_argv[0],
&zone->origin, (zone->type == dns_zone_stub) ?
dns_dbtype_stub : dns_dbtype_zone,
@ -1161,6 +1171,10 @@ zone_gotreadhandle(isc_task_t *task, isc_event_t *event) {
options |= DNS_MASTER_CHECKNAMES;
if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNAMESFAIL))
options |= DNS_MASTER_CHECKNAMESFAIL;
if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKMX))
options |= DNS_MASTER_CHECKMX;
if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKMXFAIL))
options |= DNS_MASTER_CHECKMXFAIL;
if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKWILDCARD))
options |= DNS_MASTER_CHECKWILDCARD;
result = dns_master_loadfileinc(load->zone->masterfile,
@ -1233,6 +1247,10 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
options |= DNS_MASTER_CHECKNAMES;
if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL))
options |= DNS_MASTER_CHECKNAMESFAIL;
if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMX))
options |= DNS_MASTER_CHECKMX;
if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL))
options |= DNS_MASTER_CHECKMXFAIL;
if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD))
options |= DNS_MASTER_CHECKWILDCARD;
@ -1293,6 +1311,375 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
return (result);
}
static isc_boolean_t
zone_check_mx(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
dns_name_t *owner)
{
isc_result_t result;
char ownerbuf[DNS_NAME_FORMATSIZE];
char namebuf[DNS_NAME_FORMATSIZE];
char altbuf[DNS_NAME_FORMATSIZE];
dns_fixedname_t fixed;
dns_name_t *foundname;
int level;
/*
* Outside of zone.
*/
if (!dns_name_issubdomain(name, &zone->origin)) {
if (zone->checkmx != NULL)
return ((zone->checkmx)(zone, name, owner));
return (ISC_TRUE);
}
if (zone->type == dns_zone_master)
level = ISC_LOG_ERROR;
else
level = ISC_LOG_WARNING;
dns_fixedname_init(&fixed);
foundname = dns_fixedname_name(&fixed);
result = dns_db_find(db, name, NULL, dns_rdatatype_a,
0, 0, NULL, foundname, NULL, NULL);
if (result == ISC_R_SUCCESS)
return (ISC_TRUE);
if (result == DNS_R_NXRRSET) {
result = dns_db_find(db, name, NULL, dns_rdatatype_aaaa,
0, 0, NULL, foundname, NULL, NULL);
if (result == ISC_R_SUCCESS)
return (ISC_TRUE);
}
dns_name_format(owner, ownerbuf, sizeof ownerbuf);
dns_name_format(name, namebuf, sizeof namebuf);
if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN ||
result == DNS_R_EMPTYNAME) {
dns_zone_log(zone, level,
"%s/MX '%s' has no address records (A or AAAA)",
ownerbuf, namebuf);
return (ISC_FALSE);
}
if (result == DNS_R_CNAME) {
dns_zone_log(zone, level, "%s/MX '%s' is a CNAME (illegal)",
ownerbuf, namebuf);
return (ISC_FALSE);
}
if (result == DNS_R_DNAME) {
dns_name_format(foundname, altbuf, sizeof altbuf);
dns_zone_log(zone, level,
"%s/MX '%s' is below a DNAME '%s' (illegal)",
ownerbuf, namebuf, altbuf);
return (ISC_FALSE);
}
if (zone->checkmx != NULL && result == DNS_R_DELEGATION)
return ((zone->checkmx)(zone, name, owner));
return (ISC_TRUE);
}
static isc_boolean_t
zone_check_srv(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
dns_name_t *owner)
{
isc_result_t result;
char ownerbuf[DNS_NAME_FORMATSIZE];
char namebuf[DNS_NAME_FORMATSIZE];
char altbuf[DNS_NAME_FORMATSIZE];
dns_fixedname_t fixed;
dns_name_t *foundname;
int level;
/*
* Outside of zone.
*/
if (!dns_name_issubdomain(name, &zone->origin)) {
if (zone->checksrv != NULL)
return ((zone->checksrv)(zone, name, owner));
return (ISC_TRUE);
}
if (zone->type == dns_zone_master)
level = ISC_LOG_ERROR;
else
level = ISC_LOG_WARNING;
dns_fixedname_init(&fixed);
foundname = dns_fixedname_name(&fixed);
result = dns_db_find(db, name, NULL, dns_rdatatype_a,
0, 0, NULL, foundname, NULL, NULL);
if (result == ISC_R_SUCCESS)
return (ISC_TRUE);
if (result == DNS_R_NXRRSET) {
result = dns_db_find(db, name, NULL, dns_rdatatype_aaaa,
0, 0, NULL, foundname, NULL, NULL);
if (result == ISC_R_SUCCESS)
return (ISC_TRUE);
}
dns_name_format(owner, ownerbuf, sizeof ownerbuf);
dns_name_format(name, namebuf, sizeof namebuf);
if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN ||
result == DNS_R_EMPTYNAME) {
dns_zone_log(zone, level,
"%s/SRV '%s' has no address records (A or AAAA)",
ownerbuf, namebuf);
return (ISC_FALSE);
}
if (result == DNS_R_CNAME) {
dns_zone_log(zone, level, "%s/SRV '%s' is a CNAME (illegal)",
ownerbuf, namebuf);
return (ISC_FALSE);
}
if (result == DNS_R_DNAME) {
dns_name_format(foundname, altbuf, sizeof altbuf);
dns_zone_log(zone, level,
"%s/SRV '%s' is below a DNAME '%s' (illegal)",
ownerbuf, namebuf, altbuf);
return (ISC_FALSE);
}
if (zone->checksrv != NULL && result == DNS_R_DELEGATION)
return ((zone->checksrv)(zone, name, owner));
return (ISC_TRUE);
}
static isc_boolean_t
zone_check_glue(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
dns_name_t *owner)
{
isc_boolean_t answer = ISC_TRUE;
isc_result_t result, tresult;
char ownerbuf[DNS_NAME_FORMATSIZE];
char namebuf[DNS_NAME_FORMATSIZE];
char altbuf[DNS_NAME_FORMATSIZE];
dns_fixedname_t fixed;
dns_name_t *foundname;
dns_rdataset_t a;
dns_rdataset_t aaaa;
int level;
/*
* Outside of zone.
*/
if (!dns_name_issubdomain(name, &zone->origin)) {
if (zone->checkns != NULL)
return ((zone->checkns)(zone, name, owner, NULL, NULL));
return (ISC_TRUE);
}
if (zone->type == dns_zone_master)
level = ISC_LOG_ERROR;
else
level = ISC_LOG_WARNING;
dns_fixedname_init(&fixed);
foundname = dns_fixedname_name(&fixed);
dns_rdataset_init(&a);
dns_rdataset_init(&aaaa);
result = dns_db_find(db, name, NULL, dns_rdatatype_a,
DNS_DBFIND_GLUEOK, 0, NULL,
foundname, &a, NULL);
if (result == ISC_R_SUCCESS) {
dns_rdataset_disassociate(&a);
return (ISC_TRUE);
} else if (result == DNS_R_DELEGATION)
dns_rdataset_disassociate(&a);
if (result == DNS_R_NXRRSET || result == DNS_R_DELEGATION ||
result == DNS_R_GLUE) {
tresult = dns_db_find(db, name, NULL, dns_rdatatype_aaaa,
DNS_DBFIND_GLUEOK, 0, NULL,
foundname, &aaaa, NULL);
if (tresult == ISC_R_SUCCESS) {
dns_rdataset_disassociate(&aaaa);
return (ISC_TRUE);
}
if (tresult == DNS_R_DELEGATION)
dns_rdataset_disassociate(&aaaa);
if (result == DNS_R_GLUE || tresult == DNS_R_GLUE) {
/*
* Check glue against child zone.
*/
if (zone->checkns != NULL)
answer = (zone->checkns)(zone, name, owner,
&a, &aaaa);
if (dns_rdataset_isassociated(&a))
dns_rdataset_disassociate(&a);
if (dns_rdataset_isassociated(&aaaa))
dns_rdataset_disassociate(&aaaa);
return (answer);
}
} else
tresult = result;
dns_name_format(owner, ownerbuf, sizeof ownerbuf);
dns_name_format(name, namebuf, sizeof namebuf);
if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN ||
result == DNS_R_EMPTYNAME || result == DNS_R_DELEGATION) {
const char *what;
if (dns_name_issubdomain(name, owner))
what = "REQUIRED GLUE ";
else if (result == DNS_R_DELEGATION)
what = "SIBLING GLUE ";
else
what = "";
dns_zone_log(zone, level,
"%s/NS '%s' has no %saddress records (A or AAAA)",
ownerbuf, namebuf, what);
/*
* Log missing address record.
*/
if (result == DNS_R_DELEGATION && zone->checkns != NULL)
answer = (zone->checkns)(zone, name, owner, &a, &aaaa);
answer = ISC_FALSE;
} else if (result == DNS_R_CNAME) {
dns_zone_log(zone, level, "%s/NS '%s' is a CNAME (illegal)",
ownerbuf, namebuf);
answer = ISC_FALSE;
} else if (result == DNS_R_DNAME) {
dns_name_format(foundname, altbuf, sizeof altbuf);
dns_zone_log(zone, level,
"%s/NS '%s' is below a DNAME '%s' (illegal)",
ownerbuf, namebuf, altbuf);
answer = ISC_FALSE;
}
if (dns_rdataset_isassociated(&a))
dns_rdataset_disassociate(&a);
if (dns_rdataset_isassociated(&aaaa))
dns_rdataset_disassociate(&aaaa);
return (answer);
}
static isc_boolean_t
integrity_checks(dns_zone_t *zone, dns_db_t *db) {
dns_dbiterator_t *dbiterator = NULL;
dns_dbnode_t *node = NULL;
dns_rdataset_t rdataset;
dns_fixedname_t fixed;
dns_fixedname_t fixedbottom;
dns_rdata_mx_t mx;
dns_rdata_ns_t ns;
dns_rdata_in_srv_t srv;
dns_rdata_t rdata;
dns_name_t *name;
dns_name_t *bottom;
isc_result_t result;
isc_boolean_t ok = ISC_TRUE;
dns_fixedname_init(&fixed);
name = dns_fixedname_name(&fixed);
dns_fixedname_init(&fixedbottom);
bottom = dns_fixedname_name(&fixedbottom);
dns_rdataset_init(&rdataset);
dns_rdata_init(&rdata);
result = dns_db_createiterator(db, ISC_FALSE, &dbiterator);
if (result != ISC_R_SUCCESS)
return (ISC_TRUE);
result = dns_dbiterator_first(dbiterator);
while (result == ISC_R_SUCCESS) {
result = dns_dbiterator_current(dbiterator, &node, name);
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* Is this name visible in the zone?
*/
if (!dns_name_issubdomain(name, &zone->origin) ||
(dns_name_countlabels(bottom) > 0 &&
dns_name_issubdomain(name, bottom)))
goto next;
/*
* Don't check the NS records at the origin.
*/
if (dns_name_equal(name, &zone->origin))
goto checkmx;
result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ns,
0, 0, &rdataset, NULL);
if (result != ISC_R_SUCCESS)
goto checkmx;
/*
* Remember bottom of zone.
*/
dns_name_dup(name, NULL, bottom);
result = dns_rdataset_first(&rdataset);
while (result == ISC_R_SUCCESS) {
dns_rdataset_current(&rdataset, &rdata);
result = dns_rdata_tostruct(&rdata, &ns, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (!zone_check_glue(zone, db, &ns.name, name))
ok = ISC_FALSE;
dns_rdata_reset(&rdata);
result = dns_rdataset_next(&rdataset);
}
dns_rdataset_disassociate(&rdataset);
checkmx:
result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_mx,
0, 0, &rdataset, NULL);
if (result != ISC_R_SUCCESS)
goto checksrv;
result = dns_rdataset_first(&rdataset);
while (result == ISC_R_SUCCESS) {
dns_rdataset_current(&rdataset, &rdata);
result = dns_rdata_tostruct(&rdata, &mx, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (!zone_check_mx(zone, db, &mx.mx, name))
ok = ISC_FALSE;
dns_rdata_reset(&rdata);
result = dns_rdataset_next(&rdataset);
}
dns_rdataset_disassociate(&rdataset);
checksrv:
if (zone->rdclass != dns_rdataclass_in)
goto next;
result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_srv,
0, 0, &rdataset, NULL);
if (result != ISC_R_SUCCESS)
goto next;
result = dns_rdataset_first(&rdataset);
while (result == ISC_R_SUCCESS) {
dns_rdataset_current(&rdataset, &rdata);
result = dns_rdata_tostruct(&rdata, &srv, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (!zone_check_srv(zone, db, &srv.target, name))
ok = ISC_FALSE;
dns_rdata_reset(&rdata);
result = dns_rdataset_next(&rdataset);
}
dns_rdataset_disassociate(&rdataset);
next:
dns_db_detachnode(db, &node);
result = dns_dbiterator_next(dbiterator);
}
cleanup:
if (node != NULL)
dns_db_detachnode(db, &node);
dns_dbiterator_destroy(&dbiterator);
return (ok);
}
static isc_result_t
zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
isc_result_t result)
@ -1410,6 +1797,13 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
result = DNS_R_BADZONE;
goto cleanup;
}
if (zone->type == dns_zone_master &&
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_INTEGRITYCHECK) &&
!integrity_checks(zone, db)) {
result = DNS_R_BADZONE;
goto cleanup;
}
if (zone->db != NULL) {
if (!isc_serial_ge(serial, zone->serial)) {
dns_zone_log(zone, ISC_LOG_ERROR,
@ -1555,7 +1949,8 @@ zone_check_ns(dns_zone_t *zone, dns_db_t *db, dns_name_t *name) {
}
dns_name_format(name, namebuf, sizeof namebuf);
if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN) {
if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN ||
result == DNS_R_EMPTYNAME) {
dns_zone_log(zone, level,
"NS '%s' has no address records (A or AAAA)",
namebuf);
@ -7062,6 +7457,24 @@ dns_zone_checknames(dns_zone_t *zone, dns_name_t *name, dns_rdata_t *rdata) {
return (ISC_R_SUCCESS);
}
void
dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx) {
REQUIRE(DNS_ZONE_VALID(zone));
zone->checkmx = checkmx;
}
void
dns_zone_setchecksrv(dns_zone_t *zone, dns_checksrvfunc_t checksrv) {
REQUIRE(DNS_ZONE_VALID(zone));
zone->checksrv = checksrv;
}
void
dns_zone_setcheckns(dns_zone_t *zone, dns_checknsfunc_t checkns) {
REQUIRE(DNS_ZONE_VALID(zone));
zone->checkns = checkns;
}
void
dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg) {
REQUIRE(DNS_ZONE_VALID(zone));

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: namedconf.c,v 1.49 2005/05/12 04:38:23 marka Exp $ */
/* $Id: namedconf.c,v 1.50 2005/05/19 04:59:05 marka Exp $ */
/*! \file */
@ -793,6 +793,8 @@ zone_clauses[] = {
{ "zone-statistics", &cfg_type_boolean, 0 },
{ "key-directory", &cfg_type_qstring, 0 },
{ "check-wildcard", &cfg_type_boolean, 0 },
{ "integrity-check", &cfg_type_boolean, 0 },
{ "check-mx", &cfg_type_checkmode, 0 },
{ NULL, NULL, 0 }
};