summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2021-10-07 23:12:59 +0100
committerSimon Kelley <simon@thekelleys.org.uk>2021-10-07 23:12:59 +0100
commit37a70d39e0cd49f086b757937fa8735e6263cd7a (patch)
tree500fb00f9ab210abf98cab71bf026e6c947d5371
parent72fac0810cf1ba380fbd2021ea666594e58d25ad (diff)
downloaddnsmasq-37a70d39e0cd49f086b757937fa8735e6263cd7a.tar.gz
Add --filter and --filter-AAAA options.
-rw-r--r--CHANGELOG5
-rw-r--r--man/dnsmasq.86
-rw-r--r--src/dnsmasq.h10
-rw-r--r--src/edns0.c2
-rw-r--r--src/forward.c18
-rw-r--r--src/option.c8
-rw-r--r--src/rrfilter.c37
7 files changed, 67 insertions, 19 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 6896f39..7a2e168 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -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
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index cdac947..19559a0 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -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
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 3fdc1b0..bf7685d 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -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);
diff --git a/src/edns0.c b/src/edns0.c
index 7bd26b8..9cf1d11 100644
--- a/src/edns0.c
+++ b/src/edns0.c
@@ -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;
diff --git a/src/forward.c b/src/forward.c
index ceecfcd..04635b3 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -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;
}
diff --git a/src/option.c b/src/option.c
index 1355745..ac2ba20 100644
--- a/src/option.c
+++ b/src/option.c
@@ -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 },
diff --git a/src/rrfilter.c b/src/rrfilter.c
index 58c6d8f..ef276c0 100644
--- a/src/rrfilter.c
+++ b/src/rrfilter.c
@@ -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;