From a8088e331afe66182d7929973992965aa4fc7359 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Wed, 27 Nov 2024 23:12:41 +0000 Subject: [PATCH] Modify the behaviour of --synth-domain for IPv6. When deriving a domain name from an IPv6 address, an address such as 1234:: would become 1234--.example.com, which is not legal in IDNA2008. Stop using the :: compression method, so 1234:: becomes 1234-0000-0000-0000-0000-0000-0000-0000.example.com --- CHANGELOG | 7 +++++++ man/dnsmasq.8 | 11 +++++------ src/domain.c | 53 +++++++++++++++++---------------------------------- src/option.c | 5 ++++- 4 files changed, 33 insertions(+), 43 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c2be103..2f2bbb8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -44,6 +44,13 @@ version 2.91 returns truncated, do likewise. If upstream is OK, but the answer is too big for downstream, truncate the answer. + Modify the behaviour of --synth-domain for IPv6. + When deriving a domain name from an IPv6 address, an address + such as 1234:: would become 1234--.example.com, which is + not legal in IDNA2008. Stop using the :: compression method, + so 1234:: becomes + 1234-0000-0000-0000-0000-0000-0000-0000.example.com + version 2.90 Fix reversion in --rev-server introduced in 2.88 which diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index b70ecdb..8573e0b 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -769,12 +769,11 @@ results in the name internal-0.thekelleys.org.uk. returning 192.168.0.50, intern Second, .B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal- (no *) will result in a query for internal-192-168-0-56.thekelleys.org.uk returning -192.168.0.56 and a reverse query vice versa. The same applies to IPv6, -but IPv6 addresses may start with '::' -but DNS labels may not start with '-' so in this case if no prefix is -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 +192.168.0.56 and a reverse query vice versa. The same applies to IPv6; +the representation doesn't use the :: compression feature or +the special representation of V4 mapped IPv6 addresses as these +can generate illegal domain names, so all domains are of the form +internal-1000-0000-0000-0000-0000-0000-0000-0008.example.com The address range can be of the form , or / in both forms of the option. For IPv6 the start and end addresses diff --git a/src/domain.c b/src/domain.c index f4c0bf7..f7a54e4 100644 --- a/src/domain.c +++ b/src/domain.c @@ -115,26 +115,15 @@ int is_name_synthetic(int flags, char *name, union all_addr *addrp) *p = 0; - if (prot == AF_INET6 && strstr(tail, "--ffff-") == tail) - { - /* special hack for v4-mapped. */ - memcpy(tail, "::ffff:", 7); - for (p = tail + 7; *p; p++) - if (*p == '-') + /* swap . or : for - */ + for (p = tail; *p; p++) + if (*p == '-') + { + if (prot == AF_INET) *p = '.'; - } - else - { - /* swap . or : for - */ - for (p = tail; *p; p++) - if (*p == '-') - { - if (prot == AF_INET) - *p = '.'; - else - *p = ':'; - } - } + else + *p = ':'; + } 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); @@ -194,9 +183,8 @@ int is_rev_synth(int flag, union all_addr *addr, char *name) if ((flag & F_IPV6) && (c = search_domain6(&addr->addr6, daemon->synth_domains))) { - char *p; - *name = 0; + if (c->indexed) { u64 index = addr6part(&addr->addr6) - addr6part(&c->start6); @@ -204,24 +192,17 @@ int is_rev_synth(int flag, union all_addr *addr, char *name) } else { - if (c->prefix) - strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN); - - inet_ntop(AF_INET6, &addr->addr6, name + strlen(name), ADDRSTRLEN); + int i; + char frag[6]; - /* IPv6 presentation address can start with ":", but valid domain names - cannot start with "-" so prepend a zero in that case. */ - if (!c->prefix && *name == ':') + if (c->prefix) + strncpy(name, c->prefix, MAXDNAME); + + for (i = 0; i < 16; i += 2) { - *name = '0'; - inet_ntop(AF_INET6, &addr->addr6, name+1, ADDRSTRLEN); + sprintf(frag, "%s%02x%02x", i == 0 ? "" : "-", addr->addr6.s6_addr[i], addr->addr6.s6_addr[i+1]); + strncat(name, frag, MAXDNAME); } - - /* V4-mapped have periods.... */ - for (p = name; *p; p++) - if (*p == ':' || *p == '.') - *p = '-'; - } strncat(name, ".", MAXDNAME); diff --git a/src/option.c b/src/option.c index ee505f8..b21fcba 100644 --- a/src/option.c +++ b/src/option.c @@ -2636,8 +2636,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma { if (option != 's') { + /* IPv6 address is longest and represented as + xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx + which is 39 chars */ if (!(new->prefix = canonicalise_opt(arg)) || - strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN) + strlen(new->prefix) > (MAXLABEL - 39)) ret_err_free(_("bad prefix"), new); } else if (strcmp(arg, "local") != 0)