Support IPv6 in --bogus-nxdomian and --ignore-address

This commit is contained in:
Simon Kelley
2021-07-04 22:27:00 +01:00
parent 4558c26fcd
commit 5bcca1219a
5 changed files with 76 additions and 32 deletions

View File

@@ -327,8 +327,8 @@ are re-written. So
maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
.TP
.B \-B, --bogus-nxdomain=<ipaddr>[/prefix]
Transform replies which contain the IP specified address or subnet into "No such
domain" replies. This is intended to counteract a devious move made by
Transform replies which contain the specified address or subnet into "No such
domain" replies. IPv4 and IPv6 are supported. This is intended to counteract a devious move made by
Verisign in September 2003 when they started returning the address of
an advertising web page in response to queries for unregistered names,
instead of the correct NXDOMAIN response. This option tells dnsmasq to
@@ -336,7 +336,7 @@ fake the correct response when it sees this behaviour. As at Sept 2003
the IP address being returned by Verisign is 64.94.110.11
.TP
.B --ignore-address=<ipaddr>[/prefix]
Ignore replies to A-record queries which include the specified address or subnet.
Ignore replies to A or AAAA queries which include the specified address or subnet.
No error is generated, dnsmasq simply continues to listen for another reply.
This is useful to defeat blocking strategies which rely on quickly supplying a
forged answer to a DNS request for certain domain, before the correct answer can arrive.

View File

@@ -329,7 +329,8 @@ union all_addr {
struct bogus_addr {
struct in_addr addr, mask;
int is6, prefix;
union all_addr addr;
struct bogus_addr *next;
};
@@ -1368,6 +1369,7 @@ int hostname_issubdomain(char *a, char *b);
time_t dnsmasq_time(void);
int netmask_length(struct in_addr mask);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
int is_same_net_prefix(struct in_addr a, struct in_addr b, int prefix);
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
u64 addr6part(struct in6_addr *addr);
void setaddr6part(struct in6_addr *addr, u64 host);

View File

@@ -2527,30 +2527,47 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case 'B': /* --bogus-nxdomain */
case LOPT_IGNORE_ADDR: /* --ignore-address */
{
struct in_addr addr;
int prefix = 32;
union all_addr addr;
int prefix, is6 = 0;
struct bogus_addr *baddr;
unhide_metas(arg);
if (!arg ||
((comma = split_chr(arg, '/')) && !atoi_check(comma, &prefix)) ||
(inet_pton(AF_INET, arg, &addr) != 1))
ret_err(gen_err); /* error */
((comma = split_chr(arg, '/')) && !atoi_check(comma, &prefix)))
ret_err(gen_err);
if (inet_pton(AF_INET6, arg, &addr.addr6) == 1)
is6 = 1;
else if (inet_pton(AF_INET, arg, &addr.addr4) != 1)
ret_err(gen_err);
if (!comma)
{
if (is6)
prefix = 128;
else
prefix = 32;
}
if (prefix > 128 || (!is6 && prefix > 32))
ret_err(gen_err);
baddr = opt_malloc(sizeof(struct bogus_addr));
if (option == 'B')
{
baddr->next = daemon->bogus_addr;
daemon->bogus_addr = baddr;
}
else
{
struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
if (option == 'B')
{
baddr->next = daemon->bogus_addr;
daemon->bogus_addr = baddr;
}
else
{
baddr->next = daemon->ignore_addr;
daemon->ignore_addr = baddr;
}
baddr->mask.s_addr = htonl(~((1 << (32 - prefix)) - 1));
baddr->addr.s_addr = addr.s_addr & baddr->mask.s_addr;
baddr->next = daemon->ignore_addr;
daemon->ignore_addr = baddr;
}
baddr->prefix = prefix;
baddr->is6 = is6;
baddr->addr = addr;
break;
}

View File

@@ -1079,7 +1079,6 @@ static int check_bad_address(struct dns_header *header, size_t qlen, struct bogu
int i, qtype, qclass, rdlen;
unsigned long ttl;
struct bogus_addr *baddrp;
struct in_addr addr;
/* skip over questions */
if (!(p = skip_questions(header, qlen)))
@@ -1101,17 +1100,33 @@ static int check_bad_address(struct dns_header *header, size_t qlen, struct bogu
if (ttlp)
*ttlp = ttl;
if (qclass == C_IN && qtype == T_A)
if (qclass == C_IN)
{
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
return 0;
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
if (qtype == T_A)
{
struct in_addr addr;
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
return 0;
memcpy(&addr, p, INADDRSZ);
if ((addr.s_addr & baddrp->mask.s_addr) == baddrp->addr.s_addr)
return 1;
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
if (!baddrp->is6 && is_same_net_prefix(addr, baddrp->addr.addr4, baddrp->prefix))
return 1;
}
else if (qtype == T_AAAA)
{
struct in6_addr addr;
if (!CHECK_LEN(header, p, qlen, IN6ADDRSZ))
return 0;
memcpy(&addr, p, IN6ADDRSZ);
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
if (baddrp->is6 && is_same_net6(&addr, &baddrp->addr.addr6, baddrp->prefix))
return 1;
}
}

View File

@@ -438,6 +438,16 @@ int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
}
int is_same_net_prefix(struct in_addr a, struct in_addr b, int prefix)
{
struct in_addr mask;
mask.s_addr = htonl(~((1 << (32 - prefix)) - 1));
return is_same_net(a, b, mask);
}
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
{
int pfbytes = prefixlen >> 3;