diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 52a7df0..2032a37 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -395,11 +395,13 @@ were previously disabled. .TP .B --stop-dns-rebind Reject (and log) addresses from upstream nameservers which are in the -private IP ranges. This blocks an attack where a browser behind a -firewall is used to probe machines on the local network. +private ranges. This blocks an attack where a browser behind a +firewall is used to probe machines on the local network. For IPv6, the +private range covers the IPv4-mapped addresses in private space plus +all link-local (LL) and site-local (ULA) addresses. .TP .B --rebind-localhost-ok -Exempt 127.0.0.0/8 from rebinding checks. This address range is +Exempt 127.0.0.0/8 and ::1 from rebinding checks. This address range is returned by realtime black hole servers, so blocking it may disable these services. .TP diff --git a/src/rfc1035.c b/src/rfc1035.c index f1edc45..fefe63d 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -843,17 +843,31 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t if ((flags & F_IPV4) && private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND))) return 1; - - if ((flags & F_IPV6) && - IN6_IS_ADDR_V4MAPPED(&addr.addr6)) + + /* Block IPv4-mapped IPv6 addresses in private IPv4 address space */ + if (flags & F_IPV6) { - struct in_addr v4; - v4.s_addr = ((const uint32_t *) (&addr.addr6))[3]; - if (private_net(v4, !option_bool(OPT_LOCAL_REBIND))) + if (IN6_IS_ADDR_V4MAPPED(&addr.addr6)) + { + struct in_addr v4; + v4.s_addr = ((const uint32_t *) (&addr.addr6))[3]; + if (private_net(v4, !option_bool(OPT_LOCAL_REBIND))) + return 1; + } + + /* Check for link-local (LL) and site-local (ULA) IPv6 addresses */ + if (IN6_IS_ADDR_LINKLOCAL(&addr.addr6) || + IN6_IS_ADDR_SITELOCAL(&addr.addr6)) + return 1; + + /* Check for the IPv6 loopback address (::1) when + option rebind-localhost-ok is NOT set */ + if (!option_bool(OPT_LOCAL_REBIND) && + IN6_IS_ADDR_LOOPBACK(&addr.addr6)) return 1; } } - + #ifdef HAVE_IPSET if (ipsets && (flags & (F_IPV4 | F_IPV6))) {