diff --git a/CHANGELOG b/CHANGELOG index 133090a..334fdd0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -52,6 +52,12 @@ version 2.80 Add --dhcp-name-match config option. Add --caa-record config option. + + Implement --address=/example.com/# as (more efficient) syntactic + sugar for --address=/example.com/0.0.0.0 and + --address=/example.com/:: + Returning null addresses is a useful technique for ad-blocking. + Thanks to Peter Russell for the suggestion. version 2.79 diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 3e8ee18..ebfadba 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -510,7 +510,12 @@ upstream nameserver by a more specific \fB--server\fP directive. As for \fB--server\fP, one or more domains with no address returns a no-such-domain answer, so \fB--address=/example.com/\fP is equivalent to \fB--server=/example.com/\fP and returns NXDOMAIN for example.com and -all its subdomains. +all its subdomains. An address specified as '#' translates to the NULL +address of 0.0.0.0 and its IPv6 equivalent of :: so +\fB--address=/example.com/#\fP will return NULL addresses for example.com and +its subdomains. This is partly syntactic sugar for \fB--address=/example.com/0.0.0.0\fP +and \fB--address=/example.com/::\fP but is also more efficient than including both +as seperate configuration lines. .TP .B --ipset=/[/...]/[,...] Places the resolved IP addresses of queries for one or more domains in diff --git a/src/forward.c b/src/forward.c index b25df30..459f4ed 100644 --- a/src/forward.c +++ b/src/forward.c @@ -118,6 +118,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne unsigned int matchlen = 0; struct server *serv; unsigned int flags = 0; + static struct all_addr zero; for (serv = daemon->servers; serv; serv=serv->next) if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC)) @@ -129,9 +130,16 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne *type = SERV_FOR_NODOTS; if (serv->flags & SERV_NO_ADDR) flags = F_NXDOMAIN; - else if (serv->flags & SERV_LITERAL_ADDRESS) + else if (serv->flags & SERV_LITERAL_ADDRESS) { - if (sflag & qtype) + /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */ + if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4))) + { + memset(&zero, 0, sizeof(zero)); + flags = qtype; + *addrpp = &zero; + } + else if (sflag & qtype) { flags = sflag; if (serv->addr.sa.sa_family == AF_INET) @@ -184,7 +192,14 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne flags = F_NXDOMAIN; else if (serv->flags & SERV_LITERAL_ADDRESS) { - if (sflag & qtype) + /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */ + if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4))) + { + memset(&zero, 0, sizeof(zero)); + flags = qtype; + *addrpp = &zero; + } + else if (sflag & qtype) { flags = sflag; if (serv->addr.sa.sa_family == AF_INET) diff --git a/src/option.c b/src/option.c index a393ec1..6ffd5d7 100644 --- a/src/option.c +++ b/src/option.c @@ -2467,11 +2467,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma } else if (strcmp(arg, "#") == 0) - { - newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */ - if (newlist->flags & SERV_LITERAL_ADDRESS) - ret_err(gen_err); - } + newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */ else { char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);