diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2021-10-07 23:12:59 +0100 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2021-10-07 23:12:59 +0100 |
commit | 37a70d39e0cd49f086b757937fa8735e6263cd7a (patch) | |
tree | 500fb00f9ab210abf98cab71bf026e6c947d5371 | |
parent | 72fac0810cf1ba380fbd2021ea666594e58d25ad (diff) | |
download | dnsmasq-37a70d39e0cd49f086b757937fa8735e6263cd7a.tar.gz |
Add --filter and --filter-AAAA options.
-rw-r--r-- | CHANGELOG | 5 | ||||
-rw-r--r-- | man/dnsmasq.8 | 6 | ||||
-rw-r--r-- | src/dnsmasq.h | 10 | ||||
-rw-r--r-- | src/edns0.c | 2 | ||||
-rw-r--r-- | src/forward.c | 18 | ||||
-rw-r--r-- | src/option.c | 8 | ||||
-rw-r--r-- | src/rrfilter.c | 37 |
7 files changed, 67 insertions, 19 deletions
@@ -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; |