diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 3ea487b..2638930 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -519,17 +519,18 @@ the name. More than one name may be associated with an interface address by repeating the flag; in that case the first instance is used for the reverse address-to-name mapping. .TP -.B --synth-domain=,
+.B --synth-domain=,
[,] Create artificial A/AAAA and PTR records for an address range. The records use the address, with periods (or colons for IPv6) replaced with dashes. An example should make this clearer. -.B --synth-domain=thekelleys.org.uk,192.168.0.0/24 -will result in a query for 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 a zero is added -in front of the label. ::1 becomes 0--1. +.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal- +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. The address range can be of the form , or / diff --git a/src/dnsmasq.h b/src/dnsmasq.h index cccab44..e177cea 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -673,7 +673,7 @@ struct dhcp_bridge { }; struct cond_domain { - char *domain; + char *domain, *prefix; struct in_addr start, end; #ifdef HAVE_IPV6 struct in6_addr start6, end6; diff --git a/src/domain.c b/src/domain.c index 2812fb7..821f769 100644 --- a/src/domain.c +++ b/src/domain.c @@ -34,48 +34,69 @@ int is_name_synthetic(int flags, char *name, struct all_addr *addr) prot = AF_INET6; #endif - /* NB, must not alter name if we return zero */ - for (p = name; *p; p++) + for (c = daemon->synth_domains; c; c = c->next) { - char c = *p; + int found = 0; + char *tail, *pref; - if ((c >='0' && c <= '9') || c == '-') + for (tail = name, pref = c->prefix; *tail != 0 && pref && *pref != 0; tail++, pref++) + { + unsigned int c1 = (unsigned char) *pref; + unsigned int c2 = (unsigned char) *tail; + + if (c1 >= 'A' && c1 <= 'Z') + c1 += 'a' - 'A'; + if (c2 >= 'A' && c2 <= 'Z') + c2 += 'a' - 'A'; + + if (c1 != c2) + break; + } + + if (pref && *pref != 0) + continue; /* prefix match fail */ + + /* NB, must not alter name if we return zero */ + for (p = tail; *p; p++) + { + char c = *p; + + if ((c >='0' && c <= '9') || c == '-') + continue; + +#ifdef HAVE_IPV6 + if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f'))) + continue; +#endif + + break; + } + + if (*p != '.') continue; -#ifdef HAVE_IPV6 - if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f'))) - continue; -#endif + *p = 0; - break; - } - - if (*p != '.') - return 0; - - *p = 0; - - for (p = name; *p; p++) - if (*p == '-') - { - if (prot == AF_INET) - *p = '.'; + /* swap . or : for - */ + for (p = tail; *p; p++) + if (*p == '-') + { + if (prot == AF_INET) + *p = '.'; #ifdef HAVE_IPV6 - else - *p = ':'; + else + *p = ':'; #endif - } - - if (inet_pton(prot, name, addr)) - for (c = daemon->synth_domains; c; c = c->next) - if (hostname_isequal(c->domain, p+1)) + } + + if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr)) { if (prot == AF_INET) { if (!c->is6 && ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) && ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr)) - break; + found = 1; } #ifdef HAVE_IPV6 else @@ -86,20 +107,23 @@ int is_name_synthetic(int flags, char *name, struct all_addr *addr) is_same_net6(&addr->addr.addr6, &c->start6, 64) && addrpart >= addr6part(&c->start6) && addrpart <= addr6part(&c->end6)) - break; + found = 1; } #endif } + + /* restore name */ + for (p = tail; *p; p++) + if (*p == '.' || *p == ':') + *p = '-'; + + *p = '.'; + + if (found) + return 1; + } - /* restore name */ - for (p = name; *p; p++) - if (*p == '.' || *p == ':') - *p = '-'; - - *p = '.'; - - return (c != NULL); - + return 0; } @@ -111,7 +135,11 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name) { char *p; - inet_ntop(AF_INET, &addr->addr.addr4, name, ADDRSTRLEN); + *name = 0; + if (c->prefix) + strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN); + + inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN); for (p = name; *p; p++) if (*p == '.') *p = '-'; @@ -127,11 +155,15 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name) { char *p; - inet_ntop(AF_INET6, &addr->addr.addr6, name, ADDRSTRLEN); + *name = 0; + if (c->prefix) + strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN); + + inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN); /* IPv6 presentation address can start with ":", but valid domain names cannot start with "-" so prepend a zero in that case. */ - if (*name == ':') + if (!c->prefix && *name == ':') { *name = '0'; inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN); diff --git a/src/option.c b/src/option.c index a92b712..77d9db5 100644 --- a/src/option.c +++ b/src/option.c @@ -408,7 +408,7 @@ static struct { { LOPT_AUTHSFS, ARG_DUP, "[,...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL }, { LOPT_AUTHPEER, ARG_DUP, "[,...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL }, { LOPT_IPSET, ARG_DUP, "//[,...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL }, - { LOPT_SYNTH, ARG_DUP, ",", gettext_noop("Specify a domain and address range for sythesised names"), NULL }, + { LOPT_SYNTH, ARG_DUP, ",,[]", gettext_noop("Specify a domain and address range for sythesised names"), NULL }, #ifdef OPTION6_PREFIX_CLASS { LOPT_PREF_CLSS, ARG_DUP, "set:tag,", gettext_noop("Specify DHCPv6 prefix class"), NULL }, #endif @@ -1707,6 +1707,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma struct cond_domain *new = opt_malloc(sizeof(struct cond_domain)); char *netpart; + new->prefix = NULL; + unhide_metas(comma); if ((netpart = split_chr(comma, '/'))) { @@ -1723,26 +1725,26 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma new->end.s_addr = new->start.s_addr | htonl(mask); if (arg) { - /* generate the equivalent of - local=// - local=/xxx.yyy.zzz.in-addr.arpa/ */ - - if (strcmp(arg, "local") != 0 || - option != 's' || - (msize != 8 && msize != 16 && msize != 24)) + if (option != 's') + new->prefix = canonicalise_opt(arg); + else if (strcmp(arg, "local") != 0 || + (msize != 8 && msize != 16 && msize != 24)) ret_err(gen_err); else { + /* generate the equivalent of + local=// + local=/xxx.yyy.zzz.in-addr.arpa/ */ struct server *serv = opt_malloc(sizeof(struct server)); in_addr_t a = ntohl(new->start.s_addr) >> 8; char *p; - + memset(serv, 0, sizeof(struct server)); serv->domain = d; serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR; serv->next = daemon->servers; daemon->servers = serv; - + serv = opt_malloc(sizeof(struct server)); memset(serv, 0, sizeof(struct server)); p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */ @@ -1754,7 +1756,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma p += sprintf(p, "%d.", a & 0xff); a = a >> 8; p += sprintf(p, "%d.in-addr.arpa", a & 0xff); - + serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR; serv->next = daemon->servers; daemon->servers = serv; @@ -1767,11 +1769,11 @@ 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; - + /* prefix==64 overflows the mask calculation above */ if (msize == 64) mask = (u64)-1LL; - + new->end6 = new->start6; setaddr6part(&new->start6, addrpart & ~mask); setaddr6part(&new->end6, addrpart | mask); @@ -1780,16 +1782,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ret_err(gen_err); else if (arg) { - /* generate the equivalent of - local=// - local=/xxx.yyy.zzz.ip6.arpa/ */ - - if (strcmp(arg, "local") != 0 || - option != 's' || - ((msize & 4) != 0)) + if (option != 's') + new->prefix = canonicalise_opt(arg); + else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0)) ret_err(gen_err); else { + /* generate the equivalent of + local=// + local=/xxx.yyy.zzz.ip6.arpa/ */ struct server *serv = opt_malloc(sizeof(struct server)); char *p;