diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 408eb1b..7ddd05b 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -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=[/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=[/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. diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 81bd11e..5c8364c 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -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); diff --git a/src/option.c b/src/option.c index fba5fd9..bba88e5 100644 --- a/src/option.c +++ b/src/option.c @@ -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; } diff --git a/src/rfc1035.c b/src/rfc1035.c index 24ff00d..43d1060 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -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) { - memcpy(&addr, p, INADDRSZ); + struct in_addr addr; - if ((addr.s_addr & baddrp->mask.s_addr) == baddrp->addr.s_addr) - return 1; + if (!CHECK_LEN(header, p, qlen, INADDRSZ)) + return 0; + + memcpy(&addr, p, INADDRSZ); + + 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; } } diff --git a/src/util.c b/src/util.c index 6176dc9..1425764 100644 --- a/src/util.c +++ b/src/util.c @@ -436,7 +436,17 @@ int netmask_length(struct in_addr mask) 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) {