Fix caching of dangling CNAMEs.

This commit is contained in:
Simon Kelley
2013-10-15 10:20:13 +01:00
parent e136725c5b
commit 45cca58592
2 changed files with 74 additions and 74 deletions

View File

@@ -149,6 +149,9 @@ version 2.67
no address, and vice-versa. Thanks to Yury Konovalov for no address, and vice-versa. Thanks to Yury Konovalov for
spotting the problem. spotting the problem.
Do a better job caching dangling CNAMEs. Thanks to Yves
Dorfsman for spotting the problem.
version 2.66 version 2.66
Add the ability to act as an authoritative DNS Add the ability to act as an authoritative DNS

View File

@@ -1011,91 +1011,88 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
else else
continue; continue;
if (!(flags & F_NXDOMAIN)) cname_loop1:
if (!(p1 = skip_questions(header, qlen)))
return 0;
for (j = ntohs(header->ancount); j != 0; j--)
{ {
cname_loop1: if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
if (!(p1 = skip_questions(header, qlen))) return 0; /* bad packet */
return 0;
for (j = ntohs(header->ancount); j != 0; j--) GETSHORT(aqtype, p1);
GETSHORT(aqclass, p1);
GETLONG(attl, p1);
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
{ {
if (!(res = extract_name(header, qlen, &p1, name, 0, 10))) (p1) -= 4;
return 0; /* bad packet */ PUTLONG(daemon->max_ttl, p1);
}
GETSHORT(aqtype, p1); GETSHORT(ardlen, p1);
GETSHORT(aqclass, p1); endrr = p1+ardlen;
GETLONG(attl, p1);
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign) if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
{
if (aqtype == T_CNAME)
{ {
(p1) -= 4; if (!cname_count--)
PUTLONG(daemon->max_ttl, p1); return 0; /* looped CNAMES */
} newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
GETSHORT(ardlen, p1); if (newc)
endrr = p1+ardlen;
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
{
if (aqtype == T_CNAME)
{ {
if (!cname_count--) newc->addr.cname.target.cache = NULL;
return 0; /* looped CNAMES */ if (cpp)
newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
if (newc)
{
newc->addr.cname.target.cache = NULL;
if (cpp)
{
cpp->addr.cname.target.cache = newc;
cpp->addr.cname.uid = newc->uid;
}
}
cpp = newc;
if (attl < cttl)
cttl = attl;
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
goto cname_loop1;
}
else
{
found = 1;
/* copy address into aligned storage */
if (!CHECK_LEN(header, p1, qlen, addrlen))
return 0; /* bad packet */
memcpy(&addr, p1, addrlen);
/* check for returned address in private space */
if (check_rebind &&
(flags & F_IPV4) &&
private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
return 1;
#ifdef HAVE_IPSET
if (ipsets && (flags & (F_IPV4 | F_IPV6)))
{
ipsets_cur = ipsets;
while (*ipsets_cur)
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
}
#endif
newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
if (newc && cpp)
{ {
cpp->addr.cname.target.cache = newc; cpp->addr.cname.target.cache = newc;
cpp->addr.cname.uid = newc->uid; cpp->addr.cname.uid = newc->uid;
} }
cpp = NULL;
} }
cpp = newc;
if (attl < cttl)
cttl = attl;
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
goto cname_loop1;
}
else if (!(flags & F_NXDOMAIN))
{
found = 1;
/* copy address into aligned storage */
if (!CHECK_LEN(header, p1, qlen, addrlen))
return 0; /* bad packet */
memcpy(&addr, p1, addrlen);
/* check for returned address in private space */
if (check_rebind &&
(flags & F_IPV4) &&
private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
return 1;
#ifdef HAVE_IPSET
if (ipsets && (flags & (F_IPV4 | F_IPV6)))
{
ipsets_cur = ipsets;
while (*ipsets_cur)
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
}
#endif
newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
if (newc && cpp)
{
cpp->addr.cname.target.cache = newc;
cpp->addr.cname.uid = newc->uid;
}
cpp = NULL;
} }
p1 = endrr;
if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */
} }
p1 = endrr;
if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */
} }
if (!found && !option_bool(OPT_NO_NEG)) if (!found && !option_bool(OPT_NO_NEG))
@@ -2035,7 +2032,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (trunc) if (trunc)
header->hb3 |= HB3_TC; header->hb3 |= HB3_TC;
if (anscount == 0 && nxdomain) if (nxdomain)
SET_RCODE(header, NXDOMAIN); SET_RCODE(header, NXDOMAIN);
else else
SET_RCODE(header, NOERROR); /* no error */ SET_RCODE(header, NOERROR); /* no error */