A name which is not listed can be a CNAME for one which is. That is
how some trackers get past name-based blocking.
An answer whose CNAMEs reach a listed name is now turned into NXDOMAIN
with EDE "Blocked", as --bogus-nxdomain does, and not cached.
For instance:
With HaGeZi Ultimate on my BPI-R3 router, smetrics.target.com and
smetrics.walmart.com, which the list does not have, are CNAMEs into
omtrdc.net and 2o7.net, which it does. With this patch both are
blocked.
man/dnsmasq.8 | 3 +++
src/blocklist.c | 36 ++++++++++++++++++++++++++++++++++++
src/dnsmasq.h | 1 +
src/forward.c | 30 ++++++++++++++++++++++++++++++
4 files changed, 70 insertions(+)
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index d7a2c98..2ba2ef7 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -628,6 +628,9 @@ or sent to a
\fB--server\fP given for that domain with an address, are not blocked.
A \fB--server\fP using # does not exempt a name, since it hands the
query back to the default servers.
+An answer from upstream which goes through a CNAME to a listed name is
+blocked as well, and not cached. One for a name with a \fB--server\fP of
+its own is passed on, but not cached.
The file is read again on SIGHUP; if it cannot be read then, the old list
is kept. Available only if dnsmasq
diff --git a/src/blocklist.c b/src/blocklist.c
index 22cc4ba..338c717 100644
--- a/src/blocklist.c
+++ b/src/blocklist.c
@@ -290,4 +290,40 @@ int blocklist_match(char *name)
return 0;
}
+/* Does an answer go through a CNAME to a listed name? Caching it would
+ put the listed name in the cache, where a query for that name would
+ be answered without being checked. */
+int blocklist_cname(struct dns_header *header, size_t plen)
+{
+ unsigned char *p;
+ int i;
+
+ if (!(p = skip_questions(header, plen)))
+ return 0;
+
+ for (i = ntohs(header->ancount); i != 0; i--)
+ {
+ unsigned short type, rdlen;
+ unsigned char *rdata;
+
+ if (!(p = skip_name(p, header, plen, 10)))
+ return 0;
+
+ GETSHORT(type, p);
+ p += 6; /* class and TTL */
+ GETSHORT(rdlen, p);
+ rdata = p;
+
+ if (type == T_CNAME &&
+ extract_name(header, plen, &rdata, daemon->workspacename,
EXTR_NAME_EXTRACT, 0) &&
+ blocklist_match(daemon->workspacename))
+ return 1;
+
+ if (!ADD_RDLEN(header, p, plen, rdlen))
+ return 0;
+ }
+
+ return 0;
+}
+
#endif
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 02357fd..141d135 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1971,6 +1971,7 @@ void dump_packet_icmp(int mask, void *packet, size_t len,
union mysockaddr *src,
#ifdef HAVE_BLOCKLIST
void blocklist_init(int reload);
int blocklist_match(char *name);
+int blocklist_cname(struct dns_header *header, size_t plen);
#endif
/* domain-match.c */
diff --git a/src/forward.c b/src/forward.c
index cfb4685..91ef1f4 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -732,6 +732,9 @@ static size_t process_reply(struct dns_header *header,
time_t now, struct server
int is_sign;
unsigned int rcode = RCODE(header);
size_t plen;
+#ifdef HAVE_BLOCKLIST
+ int blocked = 0;
+#endif
(void)ad_reqd;
(void)do_bit;
@@ -836,6 +839,33 @@ static size_t process_reply(struct dns_header *header,
time_t now, struct server
if (daemon->doctors && do_doctor(header, n, daemon->namebuff))
cache_secure = 0;
+#ifdef HAVE_BLOCKLIST
+ /* An answer through a CNAME to a listed name is blocked like the
+ name. It is not cached either, or a query for the listed name
+ would find it there. One for a name with a --server of its own is
+ passed on, but still not cached. */
+ if (daemon->blocklist_file && blocklist_cname(header, n))
+ {
+ if (server && server->domain_len != 0)
+ no_cache = 1;
+ else
+ blocked = 1;
+ }
+
+ if (blocked)
+ {
+ header->ancount = htons(0);
+ header->nscount = htons(0);
+ header->arcount = htons(0);
+ SET_RCODE(header, NXDOMAIN);
+ header->hb3 &= ~HB3_AA;
+ cache_secure = 0;
+ ede = EDE_BLOCKED;
+ if (extract_name(header, n, NULL, daemon->namebuff,
EXTR_NAME_EXTRACT, 0))
+ log_query(F_NXDOMAIN | F_NEG | F_FORWARD | F_HOSTS,
daemon->namebuff, NULL, "blocklist", 0);
+ }
+ else
+#endif
/* check_for_bogus_wildcard() does its own caching, so
don't call extract_addresses() if it triggers. */
if (daemon->bogus_addr && rcode != NXDOMAIN &&
--
2.53.0
_______________________________________________
Dnsmasq-discuss mailing list
[email protected]
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss