Compare commits

...
6 Commits
Author SHA1 Message Date
Simon Kelley cac9ca38f6 Treat ANY queries the same as CNAME queries WRT to DNSSEC on CNAME targets. 2021-09-08 21:21:22 +01:00
DL6ER 51d56df7a3 Add RFC 4833 DHCP options "posix-timezone" and "tzdb-timezone".
Signed-off-by: DL6ER <dl6er@dl6er.de>
2021-09-04 22:24:14 +01:00
Simon Kelley 860a9a57d6 Get logging of DNSSEC status right when Checking Disabled bit set. 2021-09-02 10:07:08 +01:00
Dominik DL6ER c83e33d608 Final logging tweaks. 2021-09-01 21:19:47 +01:00
Simon Kelley 7b80c75d9d Rationalise query-reply logging.
Try and log exactly what was returned, rather than just what
got cached. Also give validation status of RRsets if extra logging specified.

This commit also fixes a long-standing bug in caching of CNAME chains
leading to a PTR record.

Based on and inspired by a patch from Dominik DL6ER <dl6er@dl6er.de>
2021-08-31 18:23:03 +01:00
Geoff Back 79337f99ae Support limited wildcards in the input tags for --tag-if. 2021-08-29 13:27:27 +01:00
6 changed files with 383 additions and 288 deletions

No files matched your search

+3
View File
@@ -163,6 +163,9 @@ version 2.85
Tweak TFTP code to check sender of all received packets, as
specified in RFC 1350 para 4.
Support some wildcard matching of input tags to --tag-if.
Thanks to Geoff Back for the idea and the patch.
version 2.84
Fix a problem, introduced in 2.83, which could see DNS replies
+6
View File
@@ -1435,6 +1435,12 @@ Any number of set: and tag: forms may appear, in any order.
tag set by another
.B --tag-if,
the line which sets the tag must precede the one which tests it.
As an extension, the tag:<tag> clauses support limited wildcard matching,
similar to the matching in the \fB--interface\fP directive. This allows, for
example, using \fB--tag-if=set:ppp,tag:ppp*\fP to set the tag 'ppp' for all requests
received on any matching interface (ppp0, ppp1, etc). This can be used in conjunction
with the tag:!<tag> format meaning that no tag matching the wildcard may be set.
.TP
.B \-J, --dhcp-ignore=tag:<tag>[,tag:<tag>]
When all the given tags appear in the tag set ignore the host and do
+12 -8
View File
@@ -488,8 +488,6 @@ struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class
else
#endif
{
/* Don't log DNSSEC records here, done elsewhere */
log_query(flags | F_UPSTREAM, name, addr, NULL);
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
ttl = daemon->max_cache_ttl;
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
@@ -1855,7 +1853,7 @@ char *querystr(char *desc, unsigned short type)
if (types)
sprintf(buff, "<%s>", types);
else
sprintf(buff, "type=%d", type);
sprintf(buff, "<type=%d>", type);
}
}
@@ -1897,17 +1895,24 @@ static char *edestr(int ede)
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
{
char *source, *dest = daemon->addrbuff;
char *source, *dest = arg;
char *verb = "is";
char *extra = "";
if (!option_bool(OPT_LOG))
return;
#ifdef HAVE_DNSSEC
if ((flags & F_DNSSECOK) && option_bool(OPT_EXTRALOG))
extra = " (DNSSEC signed)";
#endif
name = sanitise(name);
if (addr)
{
dest = daemon->addrbuff;
if (flags & F_KEYTAG)
sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest);
else if (flags & F_RCODE)
@@ -1929,13 +1934,12 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
sprintf(extra, " (EDE: %s)", edestr(addr->log.ede));
}
}
else
else if (flags & (F_IPV4 | F_IPV6))
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
addr, daemon->addrbuff, ADDRSTRLEN);
else
dest = arg;
}
else
dest = arg;
if (flags & F_REVERSE)
{
+36 -1
View File
@@ -79,13 +79,46 @@ ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz;
}
/* like match_netid() except that the check can have a trailing * for wildcard */
/* started as a direct copy of match_netid() */
int match_netid_wild(struct dhcp_netid *check, struct dhcp_netid *pool)
{
struct dhcp_netid *tmp1;
for (; check; check = check->next)
{
const int check_len = strlen(check->net);
const int is_wc = (check->net[check_len - 1] == '*');
/* '#' for not is for backwards compat. */
if (check->net[0] != '!' && check->net[0] != '#')
{
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (is_wc ? (strncmp(check->net, tmp1->net, check_len-1) == 0) :
(strcmp(check->net, tmp1->net) == 0))
break;
if (!tmp1)
return 0;
}
else
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (is_wc ? (strncmp((check->net)+1, tmp1->net, check_len-2) == 0) :
(strcmp((check->net)+1, tmp1->net) == 0))
return 0;
}
return 1;
}
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
{
struct tag_if *exprs;
struct dhcp_netid_list *list;
/* this now uses match_netid_wild() above so that tag_if can
* be used to set a 'group of interfaces' tag.
*/
for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
if (match_netid(exprs->tag, tags, 1))
if (match_netid_wild(exprs->tag, tags))
for (list = exprs->set; list; list = list->next)
{
list->list->next = tags;
@@ -620,6 +653,8 @@ static const struct opttab_t {
{ "client-arch", 93, 2 | OT_DEC },
{ "client-interface-id", 94, 0 },
{ "client-machine-id", 97, 0 },
{ "posix-timezone", 100, OT_NAME }, /* RFC 4833, Sec. 2 */
{ "tzdb-timezone", 101, OT_NAME }, /* RFC 4833, Sec. 2 */
{ "subnet-select", 118, OT_INTERNAL },
{ "domain-search", 119, OT_RFC1035_NAME },
{ "sip-server", 120, 0 },
+2 -2
View File
@@ -1893,7 +1893,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
/* Find all the targets we're looking for answers to.
The zeroth array element is for the query, subsequent ones
for CNAME targets, unless the query is for a CNAME. */
for CNAME targets, unless the query is for a CNAME or ANY. */
if (!expand_workspace(&targets, &target_sz, 0))
return STAT_BOGUS;
@@ -1912,7 +1912,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
if (qtype == T_RRSIG)
return STAT_INSECURE;
if (qtype != T_CNAME)
if (qtype != T_CNAME && qtype != T_ANY)
for (j = ntohs(header->ancount); j != 0; j--)
{
if (!(p1 = skip_name(p1, header, plen, 10)))
+324 -277
View File
@@ -394,18 +394,13 @@ static int private_net6(struct in6_addr *a, int ban_localhost)
((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
}
static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name, int *doctored)
static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, int *doctored)
{
int i, qtype, qclass, rdlen;
for (i = count; i != 0; i--)
{
if (name && option_bool(OPT_LOG))
{
if (!extract_name(header, qlen, &p, name, 1, 10))
return 0;
}
else if (!(p = skip_name(p, header, qlen, 10)))
if (!(p = skip_name(p, header, qlen, 10)))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -444,34 +439,6 @@ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *
break;
}
}
else if (qtype == T_TXT && name && option_bool(OPT_LOG))
{
unsigned char *p1 = p;
if (!CHECK_LEN(header, p1, qlen, rdlen))
return 0;
while ((p1 - p) < rdlen)
{
unsigned int i, len = *p1;
unsigned char *p2 = p1;
if ((p1 + len - p) >= rdlen)
return 0; /* bad packet */
/* make counted string zero-term and sanitise */
for (i = 0; i < len; i++)
{
if (!isprint((int)*(p2+1)))
break;
*p2 = *(p2+1);
p2++;
}
*p2 = 0;
my_syslog(LOG_INFO, "reply %s is %s", name, p1);
/* restore */
memmove(p1 + 1, p1, i);
*p1 = len;
p1 += len+1;
}
}
if (!ADD_RDLEN(header, p, qlen, rdlen))
return 0; /* bad packet */
@@ -480,7 +447,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *
return p;
}
static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doctored)
static int find_soa(struct dns_header *header, size_t qlen, int *doctored)
{
unsigned char *p;
int qtype, qclass, rdlen;
@@ -489,7 +456,7 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doc
/* first move to NS section and find TTL from any SOA section */
if (!(p = skip_questions(header, qlen)) ||
!(p = do_doctor(p, ntohs(header->ancount), header, qlen, name, doctored)))
!(p = do_doctor(p, ntohs(header->ancount), header, qlen, doctored)))
return 0; /* bad packet */
for (i = ntohs(header->nscount); i != 0; i--)
@@ -525,7 +492,7 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doc
}
/* rewrite addresses in additional section too */
if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL, doctored))
if (!do_doctor(p, ntohs(header->arcount), header, qlen, doctored))
return 0;
if (!found_soa)
@@ -534,6 +501,40 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doc
return minttl;
}
/* Print TXT reply to log */
static int print_txt(struct dns_header *header, const size_t qlen, char *name,
unsigned char *p, const int ardlen, int secflag)
{
unsigned char *p1 = p;
if (!CHECK_LEN(header, p1, qlen, ardlen))
return 0;
/* Loop over TXT payload */
while ((p1 - p) < ardlen)
{
unsigned int i, len = *p1;
unsigned char *p3 = p1;
if ((p1 + len - p) >= ardlen)
return 0; /* bad packet */
/* make counted string zero-term and sanitise */
for (i = 0; i < len; i++)
{
if (!isprint((int)*(p3+1)))
break;
*p3 = *(p3+1);
p3++;
}
*p3 = 0;
log_query(secflag | F_FORWARD | F_UPSTREAM, name, NULL, (char*)p1);
/* restore */
memmove(p1 + 1, p1, i);
*p1 = len;
p1 += len+1;
}
return 1;
}
/* Note that the following code can create CNAME chains that don't point to a real record,
either because of lack of memory, or lack of SOA records. These are treated by the cache code as
expired and cleaned out that way.
@@ -543,7 +544,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
int secure, int *doctored)
{
unsigned char *p, *p1, *endrr, *namep;
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
int j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
unsigned long ttl = 0;
union all_addr addr;
#ifdef HAVE_IPSET
@@ -551,15 +552,21 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
#else
(void)ipsets; /* unused */
#endif
int found = 0, cname_count = CNAME_CHAIN;
struct crec *cpp = NULL;
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
#ifdef HAVE_DNSSEC
int cname_short = 0;
#endif
unsigned long cttl = ULONG_MAX, attl;
cache_start_insert();
/* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
if (daemon->doctors || option_bool(OPT_LOG) || option_bool(OPT_DNSSEC_VALID))
/* find_soa is needed for dns_doctor side effects, so don't call it lazily if there are any. */
if (daemon->doctors || option_bool(OPT_DNSSEC_VALID))
{
searched_soa = 1;
ttl = find_soa(header, qlen, name, doctored);
ttl = find_soa(header, qlen, doctored);
if (*doctored)
{
@@ -567,159 +574,46 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
return 0;
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID))
for (i = 0; i < ntohs(header->ancount); i++)
if (daemon->rr_status[i] != 0)
for (j = 0; j < ntohs(header->ancount); j++)
if (daemon->rr_status[j] != 0)
return 0;
#endif
}
}
/* go through the questions. */
p = (unsigned char *)(header+1);
namep = p = (unsigned char *)(header+1);
for (i = ntohs(header->qdcount); i != 0; i--)
{
int found = 0, cname_count = CNAME_CHAIN;
struct crec *cpp = NULL;
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
#ifdef HAVE_DNSSEC
int cname_short = 0;
#endif
unsigned long cttl = ULONG_MAX, attl;
namep = p;
if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */
GETSHORT(qtype, p);
GETSHORT(qclass, p);
if (ntohs(header->qdcount) != 1 || !extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */
GETSHORT(qtype, p);
GETSHORT(qclass, p);
if (qclass != C_IN)
return 0;
/* PTRs: we chase CNAMEs here, since we have no way to
represent them in the cache. */
if (qtype == T_PTR)
{
int insert = 1, name_encoding = in_arpa_name_2_addr(name, &addr);
if (qclass != C_IN)
continue;
/* PTRs: we chase CNAMEs here, since we have no way to
represent them in the cache. */
if (qtype == T_PTR)
{
int name_encoding = in_arpa_name_2_addr(name, &addr);
if (!name_encoding)
continue;
if (!(flags & F_NXDOMAIN))
{
cname_loop:
if (!(p1 = skip_questions(header, qlen)))
return 0;
for (j = 0; j < ntohs(header->ancount); j++)
{
int secflag = 0;
unsigned char *tmp = namep;
/* the loop body overwrites the original name, so get it back here. */
if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
!(res = extract_name(header, qlen, &p1, name, 0, 10)))
return 0; /* bad packet */
GETSHORT(aqtype, p1);
GETSHORT(aqclass, p1);
GETLONG(attl, p1);
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
{
(p1) -= 4;
PUTLONG(daemon->max_ttl, p1);
}
GETSHORT(ardlen, p1);
endrr = p1+ardlen;
/* TTL of record is minimum of CNAMES and PTR */
if (attl < cttl)
cttl = attl;
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
{
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j] != 0)
{
/* validated RR anywhere in CNAME chain, don't cache. */
if (cname_short || aqtype == T_CNAME)
return 0;
secflag = F_DNSSECOK;
/* limit TTL based on signature. */
if (daemon->rr_status[j] < cttl)
cttl = daemon->rr_status[j];
}
#endif
if (aqtype == T_CNAME)
{
if (!cname_count--)
return 0; /* looped CNAMES, we can't cache. */
#ifdef HAVE_DNSSEC
cname_short = 1;
#endif
goto cname_loop;
}
cache_insert(name, &addr, C_IN, now, cttl, name_encoding | secflag | F_REVERSE);
found = 1;
}
p1 = endrr;
if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */
}
}
if (!found && !option_bool(OPT_NO_NEG))
{
if (!searched_soa)
{
searched_soa = 1;
ttl = find_soa(header, qlen, NULL, doctored);
}
if (ttl)
cache_insert(NULL, &addr, C_IN, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | (secure ? F_DNSSECOK : 0));
}
}
else
if (!(flags & F_NXDOMAIN))
{
/* everything other than PTR */
struct crec *newc;
int addrlen = 0;
if (qtype == T_A)
{
addrlen = INADDRSZ;
flags |= F_IPV4;
}
else if (qtype == T_AAAA)
{
addrlen = IN6ADDRSZ;
flags |= F_IPV6;
}
else if (qtype == T_SRV)
flags |= F_SRV;
else
continue;
cname_loop1:
cname_loop:
if (!(p1 = skip_questions(header, qlen)))
return 0;
for (j = 0; j < ntohs(header->ancount); j++)
{
int secflag = 0;
if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
return 0; /* bad packet */
GETSHORT(aqtype, p1);
GETSHORT(aqclass, p1);
GETLONG(attl, p1);
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
{
(p1) -= 4;
@@ -728,128 +622,281 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
GETSHORT(ardlen, p1);
endrr = p1+ardlen;
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
/* TTL of record is minimum of CNAMES and PTR */
if (attl < cttl)
cttl = attl;
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
{
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j] != 0)
if (option_bool(OPT_DNSSEC_VALID) && !no_cache_dnssec && daemon->rr_status[j] != 0)
{
/* validated RR anywhere in CNAME chain, don't cache. */
if (cname_short || aqtype == T_CNAME)
insert = 0;
secflag = F_DNSSECOK;
/* limit TTl based on sig. */
if (daemon->rr_status[j] < attl)
attl = daemon->rr_status[j];
/* limit TTL based on signature. */
if (daemon->rr_status[j] < cttl)
cttl = daemon->rr_status[j];
}
#endif
#endif
if (aqtype == T_CNAME)
log_query(secflag | F_CNAME | F_FORWARD | F_UPSTREAM, name, NULL, NULL);
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
if (aqtype == T_CNAME)
{
if (!cname_count--)
return 0; /* looped CNAMES */
if ((newc = cache_insert(name, NULL, C_IN, now, attl, F_CNAME | F_FORWARD | secflag)))
{
newc->addr.cname.target.cache = NULL;
newc->addr.cname.is_name_ptr = 0;
if (cpp)
{
next_uid(newc);
cpp->addr.cname.target.cache = newc;
cpp->addr.cname.uid = newc->uid;
}
}
cpp = newc;
if (attl < cttl)
cttl = attl;
namep = p1;
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
goto cname_loop1;
}
else if (!(flags & F_NXDOMAIN))
{
found = 1;
if (flags & F_SRV)
{
unsigned char *tmp = namep;
if (!CHECK_LEN(header, p1, qlen, 6))
return 0; /* bad packet */
GETSHORT(addr.srv.priority, p1);
GETSHORT(addr.srv.weight, p1);
GETSHORT(addr.srv.srvport, p1);
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
addr.srv.targetlen = strlen(name) + 1; /* include terminating zero */
if (!(addr.srv.target = blockdata_alloc(name, addr.srv.targetlen)))
return 0;
/* we overwrote the original name, so get it back here. */
if (!extract_name(header, qlen, &tmp, name, 1, 0))
return 0;
}
else
{
/* 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)
{
if ((flags & F_IPV4) &&
private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
return 1;
if ((flags & F_IPV6) &&
private_net6(&addr.addr6, !option_bool(OPT_LOCAL_REBIND)))
return 1;
}
#ifdef HAVE_IPSET
if (ipsets && (flags & (F_IPV4 | F_IPV6)))
{
ipsets_cur = ipsets;
while (*ipsets_cur)
{
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
}
}
return 0; /* looped CNAMES, we can't cache. */
#ifdef HAVE_DNSSEC
cname_short = 1;
#endif
}
newc = cache_insert(name, &addr, C_IN, now, attl, flags | F_FORWARD | secflag);
if (newc && cpp)
goto cname_loop;
}
found = 1;
if (!name_encoding)
log_query(secflag | F_FORWARD | F_UPSTREAM, name, NULL, querystr(NULL, aqtype));
else
{
log_query(name_encoding | secflag | F_REVERSE | F_UPSTREAM, name, &addr, NULL);
if (insert)
cache_insert(name, &addr, C_IN, now, cttl, name_encoding | secflag | F_REVERSE);
}
}
p1 = endrr;
if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */
}
}
if (!found && !option_bool(OPT_NO_NEG))
{
if (!searched_soa)
{
searched_soa = 1;
ttl = find_soa(header, qlen, doctored);
}
flags |= F_NEG | (secure ? F_DNSSECOK : 0);
if (name_encoding && ttl)
{
flags |= F_REVERSE | name_encoding;
cache_insert(NULL, &addr, C_IN, now, ttl, flags);
}
log_query(flags | F_UPSTREAM, name, &addr, NULL);
}
}
else
{
/* everything other than PTR */
struct crec *newc;
int addrlen = 0, insert = 1;
if (qtype == T_A)
{
addrlen = INADDRSZ;
flags |= F_IPV4;
}
else if (qtype == T_AAAA)
{
addrlen = IN6ADDRSZ;
flags |= F_IPV6;
}
else if (qtype == T_SRV)
flags |= F_SRV;
else
insert = 0; /* NOTE: do not cache data from CNAME queries. */
cname_loop1:
if (!(p1 = skip_questions(header, qlen)))
return 0;
for (j = 0; j < ntohs(header->ancount); j++)
{
int secflag = 0;
if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
return 0; /* bad packet */
GETSHORT(aqtype, p1);
GETSHORT(aqclass, p1);
GETLONG(attl, p1);
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
{
(p1) -= 4;
PUTLONG(daemon->max_ttl, p1);
}
GETSHORT(ardlen, p1);
endrr = p1+ardlen;
/* Not what we're looking for? */
if (aqclass != C_IN || res == 2)
{
p1 = endrr;
if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */
continue;
}
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && !no_cache_dnssec && daemon->rr_status[j] != 0)
{
secflag = F_DNSSECOK;
/* limit TTl based on sig. */
if (daemon->rr_status[j] < attl)
attl = daemon->rr_status[j];
}
#endif
if (aqtype == T_CNAME)
{
if (!cname_count--)
return 0; /* looped CNAMES */
log_query(secflag | F_CNAME | F_FORWARD | F_UPSTREAM, name, NULL, NULL);
if (insert)
{
if ((newc = cache_insert(name, NULL, C_IN, now, attl, F_CNAME | F_FORWARD | secflag)))
{
newc->addr.cname.target.cache = NULL;
newc->addr.cname.is_name_ptr = 0;
if (cpp)
{
next_uid(newc);
cpp->addr.cname.target.cache = newc;
cpp->addr.cname.uid = newc->uid;
}
cpp = NULL;
}
cpp = newc;
if (attl < cttl)
cttl = attl;
}
p1 = endrr;
if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */
namep = p1;
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
goto cname_loop1;
}
else if (aqtype != qtype)
{
#ifdef HAVE_DNSSEC
if (!option_bool(OPT_DNSSEC_VALID) || aqtype != T_RRSIG)
#endif
log_query(secflag | F_FORWARD | F_UPSTREAM, name, NULL, querystr(NULL, aqtype));
}
else if (!(flags & F_NXDOMAIN))
{
found = 1;
if (flags & F_SRV)
{
unsigned char *tmp = namep;
if (!CHECK_LEN(header, p1, qlen, 6))
return 0; /* bad packet */
GETSHORT(addr.srv.priority, p1);
GETSHORT(addr.srv.weight, p1);
GETSHORT(addr.srv.srvport, p1);
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
addr.srv.targetlen = strlen(name) + 1; /* include terminating zero */
if (!(addr.srv.target = blockdata_alloc(name, addr.srv.targetlen)))
return 0;
/* we overwrote the original name, so get it back here. */
if (!extract_name(header, qlen, &tmp, name, 1, 0))
return 0;
}
else if (flags & (F_IPV4 | F_IPV6))
{
/* 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)
{
if ((flags & F_IPV4) &&
private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
return 1;
if ((flags & F_IPV6) &&
private_net6(&addr.addr6, !option_bool(OPT_LOCAL_REBIND)))
return 1;
}
#ifdef HAVE_IPSET
if (ipsets && (flags & (F_IPV4 | F_IPV6)))
{
ipsets_cur = ipsets;
while (*ipsets_cur)
{
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
}
}
#endif
}
if (insert)
{
newc = cache_insert(name, &addr, C_IN, now, attl, flags | F_FORWARD | secflag);
if (newc && cpp)
{
next_uid(newc);
cpp->addr.cname.target.cache = newc;
cpp->addr.cname.uid = newc->uid;
}
cpp = NULL;
}
if (aqtype == T_TXT)
{
if (!print_txt(header, qlen, name, p1, ardlen, secflag))
return 0;
}
else
log_query(flags | F_FORWARD | secflag | F_UPSTREAM, name, &addr, querystr(NULL, aqtype));
}
if (!found && !option_bool(OPT_NO_NEG))
p1 = endrr;
if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */
}
if (!found && !option_bool(OPT_NO_NEG))
{
if (!searched_soa)
{
if (!searched_soa)
searched_soa = 1;
ttl = find_soa(header, qlen, doctored);
}
/* If there's no SOA to get the TTL from, but there is a CNAME
pointing at this, inherit its TTL */
if (ttl || cpp)
{
if (ttl == 0)
ttl = cttl;
log_query(F_UPSTREAM | F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0), name, NULL, NULL);
if (insert)
{
searched_soa = 1;
ttl = find_soa(header, qlen, NULL, doctored);
}
/* If there's no SOA to get the TTL from, but there is a CNAME
pointing at this, inherit its TTL */
if (ttl || cpp)
{
newc = cache_insert(name, NULL, C_IN, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
newc = cache_insert(name, NULL, C_IN, now, ttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
if (newc && cpp)
{
next_uid(newc);