Generalise CNAME handling.

Cope with cached and configured CNAMES for all record types we
support, including local-config but not cached types such as TXT.

Also, if we have a locally configured CNAME but no target for the
requested type, don't forward the query.
This commit is contained in:
Simon Kelley
2019-10-25 16:13:38 +01:00
parent 2a20cc6da8
commit b59a5c2567

View File

@@ -1362,7 +1362,36 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
GETSHORT(qclass, p);
ans = 0; /* have we answered this question */
while ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)))
{
char *cname_target = cache_get_cname_target(crecp);
/* If the client asked for DNSSEC don't use cached data. */
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
!do_bit ||
(option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
{
if (crecp->flags & F_CONFIG || qtype == T_CNAME)
ans = 1;
if (!(crecp->flags & F_DNSSECOK))
sec_data = 0;
if (!dryrun)
{
log_query(crecp->flags, name, NULL, record_source(crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset,
T_CNAME, C_IN, "d", cname_target))
anscount++;
}
strcpy(name, cname_target);
}
}
if (qtype == T_TXT || qtype == T_ANY)
{
struct txt_record *t;
@@ -1604,7 +1633,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
}
}
}
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
{
unsigned short type = (flag == F_IPV6) ? T_AAAA : T_A;
@@ -1614,7 +1643,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
continue;
/* interface name stuff */
intname_restart:
for (intr = daemon->int_names; intr; intr = intr->next)
if (hostname_isequal(name, intr->name))
break;
@@ -1672,8 +1700,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
continue;
}
cname_restart:
if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
if ((crecp = cache_find_by_name(NULL, name, now, flag | (dryrun ? F_NO_RR : 0))))
{
int localise = 0;
@@ -1689,7 +1716,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
localise = 1;
break;
}
} while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
} while ((crecp = cache_find_by_name(crecp, name, now, flag)));
crecp = save;
}
@@ -1707,27 +1734,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (!(crecp->flags & F_DNSSECOK))
sec_data = 0;
if (crecp->flags & F_CNAME)
{
char *cname_target = cache_get_cname_target(crecp);
if (!dryrun)
{
log_query(crecp->flags, name, NULL, record_source(crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset,
T_CNAME, C_IN, "d", cname_target))
anscount++;
}
strcpy(name, cname_target);
/* check if target interface_name */
if (crecp->addr.cname.uid == SRC_INTERFACE)
goto intname_restart;
else
goto cname_restart;
}
if (crecp->flags & F_NEG)
{
ans = 1;
@@ -1761,7 +1767,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
anscount++;
}
}
} while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
} while ((crecp = cache_find_by_name(crecp, name, now, flag)));
}
else if (is_name_synthetic(flag, name, &addr))
{
@@ -1776,27 +1782,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
}
}
if (qtype == T_CNAME || qtype == T_ANY)
{
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) &&
(qtype == T_CNAME || (crecp->flags & F_CONFIG)) &&
((crecp->flags & F_CONFIG) || !do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
{
if (!(crecp->flags & F_DNSSECOK))
sec_data = 0;
ans = 1;
if (!dryrun)
{
log_query(crecp->flags, name, NULL, record_source(crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset,
T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
anscount++;
}
}
}
if (qtype == T_MX || qtype == T_ANY)
{
int found = 0;
@@ -1880,8 +1865,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (!found)
{
cname_srv_restart:
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | F_SRV | (dryrun ? F_NO_RR : 0))) &&
if ((crecp = cache_find_by_name(NULL, name, now, F_SRV | (dryrun ? F_NO_RR : 0))) &&
(!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
{
if (!(crecp->flags & F_DNSSECOK))
@@ -1891,23 +1875,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
found = ans = 1;
do {
if (crecp->flags & F_CNAME)
{
char *cname_target = cache_get_cname_target(crecp);
if (!dryrun)
{
log_query(crecp->flags, name, NULL, record_source(crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset,
T_CNAME, C_IN, "d", cname_target))
anscount++;
}
strcpy(name, cname_target);
goto cname_srv_restart;
}
else if (crecp->flags & F_NEG)
if (crecp->flags & F_NEG)
{
if (crecp->flags & F_NXDOMAIN)
nxdomain = 1;
@@ -1935,7 +1903,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
return 0; /* bad packet */
}
}
} while ((crecp = cache_find_by_name(crecp, name, now, F_SRV | F_CNAME)));
} while ((crecp = cache_find_by_name(crecp, name, now, F_SRV)));
}
}