mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 22:15:20 +00:00
Check that a zone that serves A/AAAA is served over IPv4/IPv6
named-checkzone will now, as part of the zone's integrity checks, look to see if there are A or AAAA records being served and if so check that the nameservers have A or AAAA records respectively. These are a sometimes overlooked checks that, if not met, can mean that a service that is supposed to reachable over IPv6 will not be resolvable when the recursive resolver is IPv6 only. Similarly for IPv4 servers when there are IPv4 only resolvers.
This commit is contained in:
@@ -144,12 +144,97 @@ logged(char *key, int value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
checkisservedby(dns_zone_t *zone, dns_rdatatype_t type,
|
||||
const dns_name_t *name) {
|
||||
char namebuf[DNS_NAME_FORMATSIZE + 1];
|
||||
char ownerbuf[DNS_NAME_FORMATSIZE + 1];
|
||||
/*
|
||||
* Not all getaddrinfo implementations distinguish NODATA
|
||||
* from NXDOMAIN with PF_INET6 so use PF_UNSPEC and look at
|
||||
* the returned ai_family values.
|
||||
*/
|
||||
struct addrinfo hints = {
|
||||
.ai_flags = AI_CANONNAME,
|
||||
.ai_family = PF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = IPPROTO_TCP,
|
||||
};
|
||||
struct addrinfo *ai = NULL, *cur;
|
||||
bool has_type = false;
|
||||
int eai;
|
||||
|
||||
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
||||
/*
|
||||
* Turn off search.
|
||||
*/
|
||||
if (dns_name_countlabels(name) > 1U) {
|
||||
strlcat(namebuf, ".", sizeof(namebuf));
|
||||
}
|
||||
eai = getaddrinfo(namebuf, NULL, &hints, &ai);
|
||||
|
||||
switch (eai) {
|
||||
case 0:
|
||||
cur = ai;
|
||||
while (cur != NULL) {
|
||||
if (cur->ai_family == AF_INET &&
|
||||
type == dns_rdatatype_a)
|
||||
{
|
||||
has_type = true;
|
||||
break;
|
||||
}
|
||||
if (cur->ai_family == AF_INET6 &&
|
||||
type == dns_rdatatype_aaaa)
|
||||
{
|
||||
has_type = true;
|
||||
break;
|
||||
}
|
||||
cur = cur->ai_next;
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
return has_type;
|
||||
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
|
||||
case EAI_NODATA:
|
||||
#endif /* if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) */
|
||||
case EAI_NONAME:
|
||||
if (!logged(namebuf, ERR_NO_ADDRESSES)) {
|
||||
dns_name_format(dns_zone_getorigin(zone), ownerbuf,
|
||||
sizeof(ownerbuf));
|
||||
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
||||
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);
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
|
||||
dns_name_format(dns_zone_getorigin(zone), ownerbuf,
|
||||
sizeof(ownerbuf));
|
||||
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
||||
dns_zone_log(zone, ISC_LOG_WARNING,
|
||||
"getaddrinfo(%s) failed: %s", namebuf,
|
||||
gai_strerror(eai));
|
||||
add(namebuf, ERR_LOOKUP_FAILURE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
isc_result_t result;
|
||||
struct addrinfo hints = {
|
||||
.ai_flags = AI_CANONNAME,
|
||||
.ai_family = PF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = IPPROTO_TCP,
|
||||
};
|
||||
struct addrinfo *ai = NULL, *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")];
|
||||
@@ -157,7 +242,7 @@ checkns(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner,
|
||||
bool match;
|
||||
const char *type;
|
||||
void *ptr = NULL;
|
||||
int result;
|
||||
int eai;
|
||||
|
||||
REQUIRE(a == NULL || !dns_rdataset_isassociated(a) ||
|
||||
a->type == dns_rdatatype_a);
|
||||
@@ -168,12 +253,6 @@ checkns(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner,
|
||||
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.
|
||||
@@ -183,9 +262,9 @@ checkns(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner,
|
||||
}
|
||||
dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
|
||||
|
||||
result = getaddrinfo(namebuf, NULL, &hints, &ai);
|
||||
eai = getaddrinfo(namebuf, NULL, &hints, &ai);
|
||||
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
||||
switch (result) {
|
||||
switch (eai) {
|
||||
case 0:
|
||||
/*
|
||||
* Work around broken getaddrinfo() implementations that
|
||||
@@ -228,7 +307,7 @@ checkns(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner,
|
||||
if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
|
||||
dns_zone_log(zone, ISC_LOG_WARNING,
|
||||
"getaddrinfo(%s) failed: %s", namebuf,
|
||||
gai_strerror(result));
|
||||
gai_strerror(eai));
|
||||
add(namebuf, ERR_LOOKUP_FAILURE);
|
||||
}
|
||||
return true;
|
||||
@@ -358,25 +437,27 @@ checkmissing:
|
||||
add(namebuf, ERR_MISSING_GLUE);
|
||||
}
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
if (ai != NULL) {
|
||||
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;
|
||||
struct addrinfo hints = {
|
||||
.ai_flags = AI_CANONNAME,
|
||||
.ai_family = PF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = IPPROTO_TCP,
|
||||
};
|
||||
struct addrinfo *ai = NULL, *cur;
|
||||
char namebuf[DNS_NAME_FORMATSIZE + 1];
|
||||
char ownerbuf[DNS_NAME_FORMATSIZE];
|
||||
int result;
|
||||
int eai;
|
||||
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.
|
||||
@@ -386,9 +467,9 @@ checkmx(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
|
||||
}
|
||||
dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
|
||||
|
||||
result = getaddrinfo(namebuf, NULL, &hints, &ai);
|
||||
eai = getaddrinfo(namebuf, NULL, &hints, &ai);
|
||||
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
||||
switch (result) {
|
||||
switch (eai) {
|
||||
case 0:
|
||||
/*
|
||||
* Work around broken getaddrinfo() implementations that
|
||||
@@ -421,7 +502,9 @@ checkmx(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
|
||||
}
|
||||
}
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
if (ai != NULL) {
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
return answer;
|
||||
|
||||
case EAI_NONAME:
|
||||
@@ -442,7 +525,7 @@ checkmx(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
|
||||
if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
|
||||
dns_zone_log(zone, ISC_LOG_WARNING,
|
||||
"getaddrinfo(%s) failed: %s", namebuf,
|
||||
gai_strerror(result));
|
||||
gai_strerror(eai));
|
||||
add(namebuf, ERR_LOOKUP_FAILURE);
|
||||
}
|
||||
return true;
|
||||
@@ -451,19 +534,19 @@ checkmx(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
|
||||
|
||||
static bool
|
||||
checksrv(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
|
||||
struct addrinfo hints, *ai, *cur;
|
||||
struct addrinfo hints = {
|
||||
.ai_flags = AI_CANONNAME,
|
||||
.ai_family = PF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = IPPROTO_TCP,
|
||||
};
|
||||
struct addrinfo *ai = NULL, *cur;
|
||||
char namebuf[DNS_NAME_FORMATSIZE + 1];
|
||||
char ownerbuf[DNS_NAME_FORMATSIZE];
|
||||
int result;
|
||||
int eai;
|
||||
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.
|
||||
@@ -473,9 +556,9 @@ checksrv(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
|
||||
}
|
||||
dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
|
||||
|
||||
result = getaddrinfo(namebuf, NULL, &hints, &ai);
|
||||
eai = getaddrinfo(namebuf, NULL, &hints, &ai);
|
||||
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
||||
switch (result) {
|
||||
switch (eai) {
|
||||
case 0:
|
||||
/*
|
||||
* Work around broken getaddrinfo() implementations that
|
||||
@@ -508,7 +591,9 @@ checksrv(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
|
||||
}
|
||||
}
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
if (ai != NULL) {
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
return answer;
|
||||
|
||||
case EAI_NONAME:
|
||||
@@ -529,7 +614,7 @@ checksrv(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
|
||||
if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
|
||||
dns_zone_log(zone, ISC_LOG_WARNING,
|
||||
"getaddrinfo(%s) failed: %s", namebuf,
|
||||
gai_strerror(result));
|
||||
gai_strerror(eai));
|
||||
add(namebuf, ERR_LOOKUP_FAILURE);
|
||||
}
|
||||
return true;
|
||||
@@ -603,6 +688,7 @@ load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
|
||||
}
|
||||
if (docheckns) {
|
||||
dns_zone_setcheckns(zone, checkns);
|
||||
dns_zone_setcheckisservedby(zone, checkisservedby);
|
||||
}
|
||||
if (dochecksrv) {
|
||||
dns_zone_setchecksrv(zone, checksrv);
|
||||
|
Reference in New Issue
Block a user