Allow shorter IPv6 prefix lengths in (some) --synth-domain options.

This commit is contained in:
Simon Kelley
2021-07-18 18:18:56 +01:00
parent 767d9cbd96
commit adf9dec1e6
5 changed files with 51 additions and 39 deletions

View File

@@ -76,6 +76,9 @@ version 2.86
Disallowed queries are not forwarded; they are rejected Disallowed queries are not forwarded; they are rejected
with a REFUSED error code. with a REFUSED error code.
Allow smaller then 64 prefix lengths in synth-domain, with caveats.
--synth-domain=1234:4567::/56,example.com is now valid.
version 2.85 version 2.85
Fix problem with DNS retries in 2.83/2.84. Fix problem with DNS retries in 2.83/2.84.

View File

@@ -705,7 +705,8 @@ configured a zero is added in front of the label. ::1 becomes 0--1.
V4 mapped IPv6 addresses, which have a representation like ::ffff:1.2.3.4 are handled specially, and become like 0--ffff-1-2-3-4 V4 mapped IPv6 addresses, which have a representation like ::ffff:1.2.3.4 are handled specially, and become like 0--ffff-1-2-3-4
The address range can be of the form The address range can be of the form
<ip address>,<ip address> or <ip address>/<netmask> in both forms of the option. <start address>,<end address> or <ip address>/<prefix-length> in both forms of the option. For IPv6 the start and end addresses
must fall in the same /64 network, or prefix-length must be greater than or equal to 64 except that shorter prefix lengths than 64 are allowed only if non-sequential names are in use.
.TP .TP
.B --dumpfile=<path/to/file> .B --dumpfile=<path/to/file>
Specify the location of a pcap-format file which dnsmasq uses to dump copies of network packets for debugging purposes. If the file exists when dnsmasq starts, it is not deleted; new packets are added to the end. Specify the location of a pcap-format file which dnsmasq uses to dump copies of network packets for debugging purposes. If the file exists when dnsmasq starts, it is not deleted; new packets are added to the end.

View File

@@ -960,10 +960,10 @@ struct dhcp_bridge {
}; };
struct cond_domain { struct cond_domain {
char *domain, *prefix; char *domain, *prefix; /* prefix is text-prefix on domain name */
struct in_addr start, end; struct in_addr start, end;
struct in6_addr start6, end6; struct in6_addr start6, end6;
int is6, indexed; int is6, indexed, prefixlen;
struct cond_domain *next; struct cond_domain *next;
}; };

View File

@@ -18,8 +18,9 @@
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c); static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c);
static int match_domain(struct in_addr addr, struct cond_domain *c);
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c); static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
static int match_domain6(struct in6_addr *addr, struct cond_domain *c);
int is_name_synthetic(int flags, char *name, union all_addr *addr) int is_name_synthetic(int flags, char *name, union all_addr *addr)
{ {
@@ -135,28 +136,9 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr)
} }
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr)) if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
{ found = (prot == AF_INET) ? match_domain(addr->addr4, c) : match_domain6(&addr->addr6, c);
if (prot == AF_INET)
{
if (!c->is6 &&
ntohl(addr->addr4.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr->addr4.s_addr) <= ntohl(c->end.s_addr))
found = 1;
}
else
{
u64 addrpart = addr6part(&addr->addr6);
if (c->is6 &&
is_same_net6(&addr->addr6, &c->start6, 64) &&
addrpart >= addr6part(&c->start6) &&
addrpart <= addr6part(&c->end6))
found = 1;
}
}
} }
/* restore name */ /* restore name */
for (p = tail; *p; p++) for (p = tail; *p; p++)
if (*p == '.' || *p == ':') if (*p == '.' || *p == ':')
@@ -246,14 +228,22 @@ int is_rev_synth(int flag, union all_addr *addr, char *name)
} }
static int match_domain(struct in_addr addr, struct cond_domain *c)
{
if (!c->is6 &&
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return 1;
return 0;
}
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c) static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c)
{ {
for (; c; c = c->next) for (; c; c = c->next)
if (!c->is6 && if (match_domain(addr, c))
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return c; return c;
return NULL; return NULL;
} }
@@ -267,16 +257,30 @@ char *get_domain(struct in_addr addr)
return daemon->domain_suffix; return daemon->domain_suffix;
} }
static int match_domain6(struct in6_addr *addr, struct cond_domain *c)
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
{ {
u64 addrpart = addr6part(addr); u64 addrpart = addr6part(addr);
if (c->is6)
{
if (c->prefixlen >= 64)
{
if (is_same_net6(addr, &c->start6, 64) &&
addrpart >= addr6part(&c->start6) &&
addrpart <= addr6part(&c->end6))
return 1;
}
else if (is_same_net6(addr, &c->start6, c->prefixlen))
return 1;
}
return 0;
}
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
{
for (; c; c = c->next) for (; c; c = c->next)
if (c->is6 && if (match_domain6(addr, c))
is_same_net6(addr, &c->start6, 64) &&
addrpart >= addr6part(&c->start6) &&
addrpart <= addr6part(&c->end6))
return c; return c;
return NULL; return NULL;

View File

@@ -2268,6 +2268,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->prefix = NULL; new->prefix = NULL;
new->indexed = 0; new->indexed = 0;
new->prefixlen = 0;
unhide_metas(comma); unhide_metas(comma);
if ((netpart = split_chr(comma, '/'))) if ((netpart = split_chr(comma, '/')))
@@ -2313,16 +2314,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
u64 mask = (1LLU << (128 - msize)) - 1LLU; u64 mask = (1LLU << (128 - msize)) - 1LLU;
u64 addrpart = addr6part(&new->start6); u64 addrpart = addr6part(&new->start6);
new->is6 = 1; new->is6 = 1;
new->prefixlen = msize;
/* prefix==64 overflows the mask calculation above */ /* prefix==64 overflows the mask calculation above */
if (msize == 64) if (msize <= 64)
mask = (u64)-1LL; mask = (u64)-1LL;
new->end6 = new->start6; new->end6 = new->start6;
setaddr6part(&new->start6, addrpart & ~mask); setaddr6part(&new->start6, addrpart & ~mask);
setaddr6part(&new->end6, addrpart | mask); setaddr6part(&new->end6, addrpart | mask);
if (msize < 64) if (msize < 64 && option == 's')
ret_err_free(gen_err, new); ret_err_free(gen_err, new);
else if (arg) else if (arg)
{ {
@@ -2393,15 +2395,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
else else
{ {
char *star; char *star;
new->next = daemon->synth_domains;
daemon->synth_domains = new;
if (new->prefix && if (new->prefix &&
(star = strrchr(new->prefix, '*')) (star = strrchr(new->prefix, '*'))
&& *(star+1) == 0) && *(star+1) == 0)
{ {
*star = 0; *star = 0;
new->indexed = 1; new->indexed = 1;
if (new->is6 && new->prefixlen < 64)
ret_err_free(_("prefix too small"), new);
} }
new->next = daemon->synth_domains;
daemon->synth_domains = new;
} }
} }
else if (option == 's') else if (option == 's')