Add EDE "filtered" extended error when --filter-A or --filter-AAAA act.
If a NODATA answer is returned instead of actual data for A or AAAA queries because of the existence of --filter-A or --filter-AAAA config options, then mark the replies with an EDE "filtered" tag. Basic patch by Petr Menšík, tweaked by Simon Kelley to apply onto the preceding caching patches. Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
parent
875d5184ba
commit
3c40a9846b
|
@ -1388,7 +1388,7 @@ void report_addresses(struct dns_header *header, size_t len, u32 mark);
|
|||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int ad_reqd, int do_bit, int have_pseudoheader,
|
||||
int *stale);
|
||||
int *stale, int *filtered);
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
time_t now);
|
||||
int check_for_ignored_address(struct dns_header *header, size_t qlen);
|
||||
|
@ -1844,7 +1844,7 @@ void poll_listen(int fd, short event);
|
|||
int do_poll(int timeout);
|
||||
|
||||
/* rrfilter.c */
|
||||
size_t rrfilter(struct dns_header *header, size_t plen, int mode);
|
||||
size_t rrfilter(struct dns_header *header, size_t *plen, int mode);
|
||||
u16 *rrfilter_desc(int type);
|
||||
int expand_workspace(unsigned char ***wkspc, int *szp, int new);
|
||||
/* modes. */
|
||||
|
|
|
@ -178,7 +178,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
|
|||
memcpy(buff, datap, rdlen);
|
||||
|
||||
/* now, delete OPT RR */
|
||||
plen = rrfilter(header, plen, RRFILTER_EDNS0);
|
||||
rrfilter(header, &plen, RRFILTER_EDNS0);
|
||||
|
||||
/* Now, force addition of a new one */
|
||||
p = NULL;
|
||||
|
|
|
@ -734,7 +734,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||
if (added_pheader)
|
||||
{
|
||||
/* client didn't send EDNS0, we added one, strip it off before returning answer. */
|
||||
n = rrfilter(header, n, RRFILTER_EDNS0);
|
||||
rrfilter(header, &n, RRFILTER_EDNS0);
|
||||
pheader = NULL;
|
||||
}
|
||||
else
|
||||
|
@ -864,11 +864,16 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||
|
||||
if (rcode == NOERROR)
|
||||
{
|
||||
size_t modified = 0;
|
||||
|
||||
if (option_bool(OPT_FILTER_A))
|
||||
n = rrfilter(header, n, RRFILTER_A);
|
||||
modified = rrfilter(header, &n, RRFILTER_A);
|
||||
|
||||
if (option_bool(OPT_FILTER_AAAA))
|
||||
n = rrfilter(header, n, RRFILTER_AAAA);
|
||||
modified += rrfilter(header, &n, RRFILTER_AAAA);
|
||||
|
||||
if (modified > 0)
|
||||
ede = EDE_FILTERED;
|
||||
}
|
||||
|
||||
if (doctored)
|
||||
|
@ -892,7 +897,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||
|
||||
/* If the requestor didn't set the DO bit, don't return DNSSEC info. */
|
||||
if (!do_bit)
|
||||
n = rrfilter(header, n, RRFILTER_DNSSEC);
|
||||
rrfilter(header, &n, RRFILTER_DNSSEC);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1866,7 +1871,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||
#endif
|
||||
else
|
||||
{
|
||||
int stale;
|
||||
int stale, filtered;
|
||||
int ad_reqd = do_bit;
|
||||
u16 hb3 = header->hb3, hb4 = header->hb4;
|
||||
int fd = listen->fd;
|
||||
|
@ -1906,17 +1911,28 @@ void receive_query(struct listener *listen, time_t now)
|
|||
/**********************************************/
|
||||
|
||||
m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
|
||||
dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale);
|
||||
dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale, &filtered);
|
||||
|
||||
if (m >= 1)
|
||||
{
|
||||
if (stale && have_pseudoheader)
|
||||
if (have_pseudoheader)
|
||||
{
|
||||
u16 swap = htons(EDE_STALE);
|
||||
int ede = EDE_UNSET;
|
||||
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + udp_size, daemon->edns_pktsz,
|
||||
EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
if (filtered)
|
||||
ede = EDE_FILTERED;
|
||||
else if (stale)
|
||||
ede = EDE_STALE;
|
||||
|
||||
if (ede != EDE_UNSET)
|
||||
{
|
||||
u16 swap = htons(ede);
|
||||
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + udp_size, daemon->edns_pktsz,
|
||||
EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet_udp(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, listen->fd);
|
||||
#endif
|
||||
|
@ -2186,7 +2202,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||
unsigned char *pheader;
|
||||
unsigned int mark = 0;
|
||||
int have_mark = 0;
|
||||
int first, last, stale, do_stale = 0;
|
||||
int first, last, filtered, stale, do_stale = 0;
|
||||
unsigned int flags = 0;
|
||||
u16 hb3, hb4;
|
||||
|
||||
|
@ -2419,7 +2435,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||
else
|
||||
/* m > 0 if answered from cache */
|
||||
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
|
||||
dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale);
|
||||
dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale, &filtered);
|
||||
|
||||
/* Do this by steam now we're not in the select() loop */
|
||||
check_log_writer(1);
|
||||
|
@ -2561,13 +2577,23 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
}
|
||||
}
|
||||
else if (stale)
|
||||
{
|
||||
u16 swap = htons((u16)EDE_STALE);
|
||||
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
ede = EDE_UNSET;
|
||||
|
||||
if (filtered)
|
||||
ede = EDE_FILTERED;
|
||||
else if (stale)
|
||||
ede = EDE_STALE;
|
||||
|
||||
if (ede != EDE_UNSET)
|
||||
{
|
||||
u16 swap = htons((u16)ede);
|
||||
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
check_log_writer(1);
|
||||
|
||||
*length = htons(m);
|
||||
|
|
|
@ -1432,7 +1432,7 @@ static int cache_validated(const struct crec *crecp)
|
|||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int ad_reqd, int do_bit, int have_pseudoheader,
|
||||
int *stale)
|
||||
int *stale, int *filtered)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp;
|
||||
|
@ -1450,6 +1450,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||
|
||||
if (stale)
|
||||
*stale = 0;
|
||||
|
||||
if (filtered)
|
||||
*filtered = 0;
|
||||
|
||||
/* never answer queries with RD unset, to avoid cache snooping. */
|
||||
if (ntohs(header->ancount) != 0 ||
|
||||
|
@ -1718,8 +1721,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||
/* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
|
||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
continue;
|
||||
|
||||
|
||||
|
||||
if (!(crecp->flags & F_DNSSECOK))
|
||||
sec_data = 0;
|
||||
|
||||
|
@ -1900,6 +1902,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||
|
||||
if (!dryrun)
|
||||
log_query(F_NEG | F_CONFIG | flag, name, NULL, NULL, 0);
|
||||
|
||||
if (filtered)
|
||||
*filtered = 1;
|
||||
}
|
||||
else if (crecp->flags & F_NEG)
|
||||
{
|
||||
|
@ -1975,6 +1980,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||
|
||||
if (!dryrun)
|
||||
log_query(F_NEG | F_CONFIG | flag, name, NULL, NULL, 0);
|
||||
|
||||
if (filtered)
|
||||
*filtered = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,41 +156,43 @@ static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, i
|
|||
}
|
||||
|
||||
|
||||
/* mode may be remove EDNS0 or DNSSEC RRs or remove A or AAAA from answer section. */
|
||||
size_t rrfilter(struct dns_header *header, size_t plen, int mode)
|
||||
/* mode may be remove EDNS0 or DNSSEC RRs or remove A or AAAA from answer section.
|
||||
* returns number of modified records. */
|
||||
size_t rrfilter(struct dns_header *header, size_t *plen, int mode)
|
||||
{
|
||||
static unsigned char **rrs = NULL;
|
||||
static int rr_sz = 0;
|
||||
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
|
||||
size_t rr_found = 0;
|
||||
int i, rdlen, qtype, qclass, chop_an, chop_ns, chop_ar;
|
||||
|
||||
if (ntohs(header->qdcount) != 1 ||
|
||||
!(p = skip_name(p, header, plen, 4)))
|
||||
return plen;
|
||||
!(p = skip_name(p, header, *plen, 4)))
|
||||
return 0;
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
/* First pass, find pointers to start and end of all the records we wish to elide:
|
||||
records added for DNSSEC, unless explicitly queried for */
|
||||
for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0;
|
||||
for (chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0;
|
||||
i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
|
||||
i++)
|
||||
{
|
||||
unsigned char *pstart = p;
|
||||
int type, class;
|
||||
|
||||
if (!(p = skip_name(p, header, plen, 10)))
|
||||
return plen;
|
||||
if (!(p = skip_name(p, header, *plen, 10)))
|
||||
return rr_found;
|
||||
|
||||
GETSHORT(type, p);
|
||||
GETSHORT(class, p);
|
||||
p += 4; /* TTL */
|
||||
GETSHORT(rdlen, p);
|
||||
|
||||
if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
return plen;
|
||||
if (!ADD_RDLEN(header, p, *plen, rdlen))
|
||||
return rr_found;
|
||||
|
||||
if (mode == RRFILTER_EDNS0) /* EDNS */
|
||||
{
|
||||
|
@ -225,7 +227,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
|
|||
}
|
||||
|
||||
if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
|
||||
return plen;
|
||||
return rr_found;
|
||||
|
||||
rrs[rr_found++] = pstart;
|
||||
rrs[rr_found++] = p;
|
||||
|
@ -240,7 +242,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
|
|||
|
||||
/* Nothing to do. */
|
||||
if (rr_found == 0)
|
||||
return plen;
|
||||
return rr_found;
|
||||
|
||||
/* Second pass, look for pointers in names in the records we're keeping and make sure they don't
|
||||
point to records we're going to elide. This is theoretically possible, but unlikely. If
|
||||
|
@ -248,38 +250,38 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
|
|||
p = (unsigned char *)(header+1);
|
||||
|
||||
/* question first */
|
||||
if (!check_name(&p, header, plen, 0, rrs, rr_found))
|
||||
return plen;
|
||||
if (!check_name(&p, header, *plen, 0, rrs, rr_found))
|
||||
return rr_found;
|
||||
p += 4; /* qclass, qtype */
|
||||
|
||||
/* Now answers and NS */
|
||||
if (!check_rrs(p, header, plen, 0, rrs, rr_found))
|
||||
return plen;
|
||||
if (!check_rrs(p, header, *plen, 0, rrs, rr_found))
|
||||
return rr_found;
|
||||
|
||||
/* Third pass, actually fix up pointers in the records */
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
check_name(&p, header, plen, 1, rrs, rr_found);
|
||||
check_name(&p, header, *plen, 1, rrs, rr_found);
|
||||
p += 4; /* qclass, qtype */
|
||||
|
||||
check_rrs(p, header, plen, 1, rrs, rr_found);
|
||||
check_rrs(p, header, *plen, 1, rrs, rr_found);
|
||||
|
||||
/* Fourth pass, elide records */
|
||||
for (p = rrs[0], i = 1; i < rr_found; i += 2)
|
||||
for (p = rrs[0], i = 1; (unsigned)i < rr_found; i += 2)
|
||||
{
|
||||
unsigned char *start = rrs[i];
|
||||
unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + plen;
|
||||
unsigned char *end = ((unsigned)i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + *plen;
|
||||
|
||||
memmove(p, start, end-start);
|
||||
p += end-start;
|
||||
}
|
||||
|
||||
plen = p - (unsigned char *)header;
|
||||
*plen = p - (unsigned char *)header;
|
||||
header->ancount = htons(ntohs(header->ancount) - chop_an);
|
||||
header->nscount = htons(ntohs(header->nscount) - chop_ns);
|
||||
header->arcount = htons(ntohs(header->arcount) - chop_ar);
|
||||
|
||||
return plen;
|
||||
return rr_found;
|
||||
}
|
||||
|
||||
/* This is used in the DNSSEC code too, hence it's exported */
|
||||
|
|
Loading…
Reference in New Issue