summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2021-07-18 18:18:56 +0100
committerSimon Kelley <simon@thekelleys.org.uk>2021-07-18 18:18:56 +0100
commitadf9dec1e6be3ef56412b7e556b2dd47ac7fee51 (patch)
tree25e298e660236c89ecd574c5002036a0dbdd5960
parent767d9cbd9692fb7722b05ac60ee261ad25a5d113 (diff)
downloaddnsmasq-adf9dec1e6be3ef56412b7e556b2dd47ac7fee51.tar.gz
Allow shorter IPv6 prefix lengths in (some) --synth-domain options.
-rw-r--r--CHANGELOG3
-rw-r--r--man/dnsmasq.83
-rw-r--r--src/dnsmasq.h4
-rw-r--r--src/domain.c68
-rw-r--r--src/option.c12
5 files changed, 51 insertions, 39 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 3f75852..7c305b3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -76,6 +76,9 @@ version 2.86
Disallowed queries are not forwarded; they are rejected
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
Fix problem with DNS retries in 2.83/2.84.
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index b6a1f27..b3c335e 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -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
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
.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.
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index a88cbc5..6e20636 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -960,10 +960,10 @@ struct dhcp_bridge {
};
struct cond_domain {
- char *domain, *prefix;
+ char *domain, *prefix; /* prefix is text-prefix on domain name */
struct in_addr start, end;
struct in6_addr start6, end6;
- int is6, indexed;
+ int is6, indexed, prefixlen;
struct cond_domain *next;
};
diff --git a/src/domain.c b/src/domain.c
index 189bdd1..91e0f22 100644
--- a/src/domain.c
+++ b/src/domain.c
@@ -18,8 +18,9 @@
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 int match_domain6(struct in6_addr *addr, struct cond_domain *c);
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 (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;
- }
- }
-
+ found = (prot == AF_INET) ? match_domain(addr->addr4, c) : match_domain6(&addr->addr6, c);
}
-
+
/* restore name */
for (p = tail; *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)
{
for (; c; c = c->next)
- if (!c->is6 &&
- ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
- ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
+ if (match_domain(addr, c))
return c;
-
+
return NULL;
}
@@ -267,16 +257,30 @@ char *get_domain(struct in_addr addr)
return daemon->domain_suffix;
}
-
-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)
{
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)
- if (c->is6 &&
- is_same_net6(addr, &c->start6, 64) &&
- addrpart >= addr6part(&c->start6) &&
- addrpart <= addr6part(&c->end6))
+ if (match_domain6(addr, c))
return c;
return NULL;
diff --git a/src/option.c b/src/option.c
index 964c3b1..e857c76 100644
--- a/src/option.c
+++ b/src/option.c
@@ -2268,6 +2268,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->prefix = NULL;
new->indexed = 0;
+ new->prefixlen = 0;
unhide_metas(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 addrpart = addr6part(&new->start6);
new->is6 = 1;
+ new->prefixlen = msize;
/* prefix==64 overflows the mask calculation above */
- if (msize == 64)
+ if (msize <= 64)
mask = (u64)-1LL;
new->end6 = new->start6;
setaddr6part(&new->start6, addrpart & ~mask);
setaddr6part(&new->end6, addrpart | mask);
- if (msize < 64)
+ if (msize < 64 && option == 's')
ret_err_free(gen_err, new);
else if (arg)
{
@@ -2393,15 +2395,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
else
{
char *star;
- new->next = daemon->synth_domains;
- daemon->synth_domains = new;
if (new->prefix &&
(star = strrchr(new->prefix, '*'))
&& *(star+1) == 0)
{
*star = 0;
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')