211 lines
7.4 KiB
Diff
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
|
|
|