Add --filter and --filter-AAAA options.

This commit is contained in:
Simon Kelley
2021-10-07 23:12:59 +01:00
parent 72fac0810c
commit 37a70d39e0
7 changed files with 67 additions and 19 deletions

View File

@@ -8,7 +8,10 @@ version 2.87
Add --nftset option, like --ipset but for the newer nftables.
Thanks to Chen Zhenge for the patch.
Add --filter-A and --filter-AAAA options, to remove IPv4 or IPv6
addresses from DNS answers.
version 2.86
Handle DHCPREBIND requests in the DHCPv6 server code.
Thanks to Aichun Li for spotting this omission, and the initial

View File

@@ -348,6 +348,12 @@ the public DNS and can cause problems by triggering dial-on-demand links. This f
to filter such requests. The requests blocked are for records of types SOA and SRV, and type ANY where the
requested name has underscores, to catch LDAP requests.
.TP
.B --filter-A
Remove A records from answers. No IPv4 addresses will be returned.
.TP
.B --filter-AAAA
Remove AAAA records from answers. No IPv6 addresses will be returned.
.TP
.B \-r, --resolv-file=<file>
Read the IP addresses of the upstream nameservers from <file>, instead of
/etc/resolv.conf. For the format of this file see

View File

@@ -275,7 +275,9 @@ struct event_desc {
#define OPT_UMBRELLA_DEVID 64
#define OPT_CMARK_ALST_EN 65
#define OPT_QUIET_TFTP 66
#define OPT_LAST 67
#define OPT_FILTER_A 67
#define OPT_FILTER_AAAA 68
#define OPT_LAST 69
#define OPTION_BITS (sizeof(unsigned int)*8)
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
@@ -1749,7 +1751,11 @@ int do_poll(int timeout);
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. */
#define RRFILTER_EDNS0 0
#define RRFILTER_DNSSEC 1
#define RRFILTER_A 2
#define RRFILTER_AAAA 3
/* edns0.c */
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
size_t *len, unsigned char **p, int *is_sign, int *is_last);

View File

@@ -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, 0);
plen = rrfilter(header, plen, RRFILTER_EDNS0);
/* Now, force addition of a new one */
p = NULL;

View File

@@ -629,7 +629,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, 0);
n = rrfilter(header, n, RRFILTER_EDNS0);
pheader = NULL;
}
else
@@ -718,7 +718,17 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
cache_secure = 0;
}
}
/* Before extract_addresses() */
if (rcode == NOERROR)
{
if (option_bool(OPT_FILTER_A))
n = rrfilter(header, n, RRFILTER_A);
if (option_bool(OPT_FILTER_AAAA))
n = rrfilter(header, n, RRFILTER_AAAA);
}
if (extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
{
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
@@ -748,7 +758,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, 1);
n = rrfilter(header, n, RRFILTER_DNSSEC);
}
#endif
@@ -772,7 +782,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
u16 swap = htons((u16)ede);
n = add_pseudoheader(header, n, limit, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 1);
}
return n;
}

View File

@@ -175,7 +175,9 @@ struct myoption {
#define LOPT_CMARK_ALST 366
#define LOPT_QUIET_TFTP 367
#define LOPT_NFTSET 368
#define LOPT_FILTER_A 369
#define LOPT_FILTER_AAAA 370
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
#else
@@ -212,6 +214,8 @@ static const struct myoption opts[] =
{ "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
{ "selfmx", 0, 0, 'e' },
{ "filterwin2k", 0, 0, 'f' },
{ "filter-A", 0, 0, LOPT_FILTER_A },
{ "filter-AAAA", 0, 0, LOPT_FILTER_AAAA },
{ "pid-file", 2, 0, 'x' },
{ "strict-order", 0, 0, 'o' },
{ "server", 1, 0, 'S' },
@@ -382,6 +386,8 @@ static struct {
{ 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
{ 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
{ 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
{ LOPT_FILTER_A, OPT_FILTER_A, NULL, gettext_noop("Don't include IPv4 addresses in DNS answers."), NULL },
{ LOPT_FILTER_AAAA, OPT_FILTER_AAAA, NULL, gettext_noop("Don't include IPv6 addresses in DNS answers."), NULL },
{ 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
{ 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },

View File

@@ -156,7 +156,7 @@ static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, i
}
/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */
/* 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)
{
static unsigned char **rrs;
@@ -192,20 +192,37 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
if (!ADD_RDLEN(header, p, plen, rdlen))
return plen;
/* Don't remove the answer. */
if (i < ntohs(header->ancount) && type == qtype && class == qclass)
continue;
if (mode == 0) /* EDNS */
if (mode == RRFILTER_EDNS0) /* EDNS */
{
/* EDNS mode, remove T_OPT from additional section only */
if (i < (ntohs(header->nscount) + ntohs(header->ancount)) || type != T_OPT)
continue;
}
else if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
/* DNSSEC mode, remove SIGs and NSECs from all three sections. */
continue;
else if (mode == RRFILTER_DNSSEC)
{
if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
/* DNSSEC mode, remove SIGs and NSECs from all three sections. */
continue;
/* Don't remove the answer. */
if (i < ntohs(header->ancount) && type == qtype && class == qclass)
continue;
}
else
{
/* Only looking at answer section now. */
if (i >= ntohs(header->ancount))
break;
if (class != C_IN)
continue;
if (mode == RRFILTER_A && type != T_A)
continue;
if (mode == RRFILTER_AAAA && type != T_AAAA)
continue;
}
if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
return plen;