From 6b2b564ac34cb3c862f168e6b1457f9f0b9ca69c Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Sat, 10 Mar 2018 18:12:04 +0000 Subject: [PATCH] Enhance --synth-domain to allow names with sequential integers. --- CHANGELOG | 12 ++- man/dnsmasq.8 | 15 ++-- src/dnsmasq.h | 2 +- src/domain.c | 225 ++++++++++++++++++++++++++++++++------------------ src/option.c | 9 +- 5 files changed, 175 insertions(+), 88 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 87dcfef..4cc1858 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -49,7 +49,17 @@ version 2.79 Fix failure to delete dynamically created dhcp options from files in -dhcp-optsdir directories. Thanks to Lindgren Fredrik for the bug report. - + + Add to --synth-domain the ability to create names using + sequential numbers, as well as encodings of IP addresses. + For instance, + --synth-domain=thekelleys.org.uk,192.168.0.50,192.168.0.70,internal-* + creates 21 domain names of the form + internal-4.thekelleys.org.uk over the address range given, with + internal-0.thekelleys.org.uk being 192.168.0.50 and + internal-20.thekelleys.org.uk being 192.168.0.70 + Thanks to Andy Hawkins for the suggestion. + version 2.78 Fix logic of appending "." to PXE basename. Thanks to Chris diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 68e602e..bd99b48 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -626,13 +626,16 @@ address by repeating the flag; in that case the first instance is used for the reverse address-to-name mapping. Note that a name used in --interface-name may not appear in /etc/hosts. .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. +records either seqential numbers or 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,internal- +An examples should make this clearer. First sequential numbers. +.B --synth-domain=thekelleys.org.uk,192.168.0.50,192.168.0.70,internal-* +results in the name internal-0.thekelleys.org.uk. returning 192.168.0.50, internal-1.thekelleys.org.uk returning 192.168.0.51 and so on. (note the *) The same principle applies to IPv6 addresses (where the numbers may be very large). Reverse lookups from address to name behave as expected. + +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 '::' @@ -642,7 +645,7 @@ 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 -, or / +, or / in both forms of the option. .TP .B --add-mac[=base64|text] Add the MAC address of the requestor to DNS queries which are diff --git a/src/dnsmasq.h b/src/dnsmasq.h index f4d330a..6773b69 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -839,7 +839,7 @@ struct cond_domain { #ifdef HAVE_IPV6 struct in6_addr start6, end6; #endif - int is6; + int is6, indexed; struct cond_domain *next; }; diff --git a/src/domain.c b/src/domain.c index 853dc17..04d7cf8 100644 --- a/src/domain.c +++ b/src/domain.c @@ -55,83 +55,133 @@ int is_name_synthetic(int flags, char *name, struct all_addr *addr) if (pref && *pref != 0) continue; /* prefix match fail */ - - /* NB, must not alter name if we return zero */ - for (p = tail; *p; p++) + + if (c->indexed) { - char c = *p; + for (p = tail; *p; p++) + { + char c = *p; + + if (c < '0' || c > '9') + break; + } - if ((c >='0' && c <= '9') || c == '-') + if (*p != '.') continue; -#ifdef HAVE_IPV6 - if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f'))) - continue; + *p = 0; + + if (hostname_isequal(c->domain, p+1)) + { + if (prot == AF_INET) + { + unsigned int index = atoi(tail); + + if (!c->is6 && + index <= ntohl(c->end.s_addr) - ntohl(c->start.s_addr)) + { + addr->addr.addr4.s_addr = htonl(ntohl(c->start.s_addr) + index); + found = 1; + } + } +#ifdef HAVE_IPV6 + else + { + u64 index = atoll(tail); + + if (c->is6 && + index <= addr6part(&c->end6) - addr6part(&c->start6)) + { + u64 start = addr6part(&c->start6); + addr->addr.addr6 = c->start6; + setaddr6part(&addr->addr.addr6, start + index); + found = 1; + } + } #endif - - break; - } - - if (*p != '.') - continue; - - *p = 0; - - #ifdef HAVE_IPV6 - 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 == '-') - *p = '.'; + } } else -#endif { - /* swap . or : for - */ + /* NB, must not alter name if we return zero */ for (p = tail; *p; p++) - if (*p == '-') - { - if (prot == AF_INET) - *p = '.'; + { + char c = *p; + + if ((c >='0' && c <= '9') || c == '-') + continue; + #ifdef HAVE_IPV6 - else - *p = ':'; + if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f'))) + continue; #endif - } + + break; + } + + if (*p != '.') + continue; + + *p = 0; + +#ifdef HAVE_IPV6 + 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 == '-') + *p = '.'; + } + else +#endif + { + /* swap . or : for - */ + for (p = tail; *p; p++) + if (*p == '-') + { + if (prot == AF_INET) + *p = '.'; +#ifdef HAVE_IPV6 + else + *p = ':'; +#endif + } + } + + 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)) + found = 1; + } +#ifdef HAVE_IPV6 + else + { + u64 addrpart = addr6part(&addr->addr.addr6); + + if (c->is6 && + is_same_net6(&addr->addr.addr6, &c->start6, 64) && + addrpart >= addr6part(&c->start6) && + addrpart <= addr6part(&c->end6)) + found = 1; + } +#endif + } + } - 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)) - found = 1; - } -#ifdef HAVE_IPV6 - else - { - u64 addrpart = addr6part(&addr->addr.addr6); - - if (c->is6 && - is_same_net6(&addr->addr.addr6, &c->start6, 64) && - addrpart >= addr6part(&c->start6) && - addrpart <= addr6part(&c->end6)) - found = 1; - } -#endif - } - /* restore name */ for (p = tail; *p; p++) if (*p == '.' || *p == ':') *p = '-'; *p = '.'; - + + if (found) return 1; } @@ -149,14 +199,22 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name) char *p; *name = 0; - if (c->prefix) - strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN); + if (c->indexed) + { + unsigned int index = ntohl(addr->addr.addr4.s_addr) - ntohl(c->start.s_addr); + snprintf(name, MAXDNAME, "%s%u", c->prefix ? c->prefix : "", index); + } + else + { + 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 = '-'; + } - inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN); - for (p = name; *p; p++) - if (*p == '.') - *p = '-'; - strncat(name, ".", MAXDNAME); strncat(name, c->domain, MAXDNAME); @@ -169,23 +227,32 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name) char *p; *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 (!c->prefix && *name == ':') + if (c->indexed) { - *name = '0'; - inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN); + u64 index = addr6part(&addr->addr.addr6) - addr6part(&c->start6); + snprintf(name, MAXDNAME, "%s%llu", c->prefix ? c->prefix : "", index); } + else + { + if (c->prefix) + strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN); + + inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN); - /* V4-mapped have periods.... */ - for (p = name; *p; p++) - if (*p == ':' || *p == '.') - *p = '-'; + /* IPv6 presentation address can start with ":", but valid domain names + cannot start with "-" so prepend a zero in that case. */ + if (!c->prefix && *name == ':') + { + *name = '0'; + inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN); + } + + /* V4-mapped have periods.... */ + for (p = name; *p; p++) + if (*p == ':' || *p == '.') + *p = '-'; + + } strncat(name, ".", MAXDNAME); strncat(name, c->domain, MAXDNAME); diff --git a/src/option.c b/src/option.c index 6b26576..d358d99 100644 --- a/src/option.c +++ b/src/option.c @@ -2071,7 +2071,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma char *netpart; new->prefix = NULL; - + new->indexed = 0; + unhide_metas(comma); if ((netpart = split_chr(comma, '/'))) { @@ -2208,8 +2209,14 @@ 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 ((star = strrchr(new->prefix, '*')) && *(star+1) == 0) + { + *star = 0; + new->indexed = 1; + } } } else if (option == 's')