dnsmasq/SOURCES/dnsmasq-2.87-filter-AAAA.patch

211 lines
7.4 KiB
Diff

From b4102039739ffbf9654b25ac974edca24e98c27c Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Thu, 7 Oct 2021 23:12:59 +0100
Subject: [PATCH] Add --filter and --filter-AAAA options.
(cherry picked from commit 37a70d39e0cd49f086b757937fa8735e6263cd7a)
---
man/dnsmasq.8 | 6 ++++++
src/dnsmasq.h | 10 ++++++++--
src/edns0.c | 2 +-
src/forward.c | 16 +++++++++++++---
src/option.c | 8 +++++++-
src/rrfilter.c | 37 +++++++++++++++++++++++++++----------
6 files changed, 62 insertions(+), 17 deletions(-)
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 8bb81b6..e47ee5f 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 6fa2593..5f6d63b 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -270,7 +270,9 @@ struct event_desc {
#define OPT_SINGLE_PORT 60
#define OPT_LEASE_RENEW 61
#define OPT_LOG_DEBUG 62
-#define OPT_LAST 63
+#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) )
@@ -1706,7 +1708,11 @@ int do_poll(int timeout);
size_t rrfilter(struct dns_header *header, size_t plen, int mode);
short *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 33b5283..b1615ae 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 388b0c3..36c769a 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -710,7 +710,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
@@ -793,7 +793,17 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
SET_RCODE(header, NOERROR);
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, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
{
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
@@ -822,7 +832,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
diff --git a/src/option.c b/src/option.c
index 8b40332..44bc46f 100644
--- a/src/option.c
+++ b/src/option.c
@@ -171,7 +171,9 @@ struct myoption {
#define LOPT_DYNHOST 362
#define LOPT_LOG_DEBUG 363
#define LOPT_DNSSEC_LIMITS 364
-
+#define LOPT_FILTER_A 369
+#define LOPT_FILTER_AAAA 370
+
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
#else
@@ -208,6 +210,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' },
@@ -374,6 +378,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 32ef34a..262c114 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;
--
2.50.1