From d74942a03d9858eb5aa477b97fe6a3a5ebbf5216 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Tue, 7 Feb 2012 20:51:56 +0000 Subject: [PATCH] IPv6 address range parsing for --domain. Counted string DHCP option type printing --- src/cache.c | 14 +++--- src/dnsmasq.h | 11 ++--- src/option.c | 129 ++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 126 insertions(+), 28 deletions(-) diff --git a/src/cache.c b/src/cache.c index 1226165..896132b 100644 --- a/src/cache.c +++ b/src/cache.c @@ -913,7 +913,8 @@ char *get_domain(struct in_addr addr) struct cond_domain *c; for (c = daemon->cond_domain; c; c = c->next) - if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) && + if (!c->is6 && + ntohl(addr.s_addr) >= ntohl(c->start.s_addr) && ntohl(addr.s_addr) <= ntohl(c->end.s_addr)) return c->domain; @@ -924,14 +925,15 @@ char *get_domain(struct in_addr addr) #ifdef HAVE_IPV6 char *get_domain6(struct in6_addr *addr) { - struct cond_domain6 *c; + struct cond_domain *c; u64 addrpart = addr6part(addr); - for (c = daemon->cond_domain6; c; c = c->next) - if (is_same_net6(addr, &c->start, 64) && - addrpart >= addr6part(&c->start) && - addrpart <= addr6part(&c->end)) + for (c = daemon->cond_domain; c; c = c->next) + if (c->is6 && + is_same_net6(addr, &c->start6, 64) && + addrpart >= addr6part(&c->start6) && + addrpart <= addr6part(&c->end6)) return c->domain; return daemon->domain_suffix; diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 5ac1e99..722ab09 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -588,15 +588,13 @@ struct dhcp_bridge { struct cond_domain { char *domain; struct in_addr start, end; +#ifdef HAVE_IPV6 + struct in6_addr start6, end6; +#endif + int is6; struct cond_domain *next; }; -struct cond_domain6 { - char *domain; - struct in6_addr start, end; - struct cond_domain6 *next; -}; - struct dhcp_context { unsigned int lease_time, addr_epoch; struct in_addr netmask, broadcast; @@ -683,7 +681,6 @@ extern struct daemon { int group_set, osport; char *domain_suffix; struct cond_domain *cond_domain; - struct cond_domain6 *cond_domain6; char *runfile; char *lease_change_command; struct iname *if_names, *if_addrs, *if_except, *dhcp_except; diff --git a/src/option.c b/src/option.c index c807a8f..fbe1204 100644 --- a/src/option.c +++ b/src/option.c @@ -543,6 +543,30 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, buf[j++] = '.'; } } + else if ((ot[o].size & OT_CSTRING)) + { + int k, len; + unsigned char *p; + + i = 0, j = 0; + while (1) + { + p = &val[i]; + GETSHORT(len, p); + for (k = 0; k < len && j < buf_len; k++) + { + char c = *p++; + if (isprint((int)c)) + buf[j++] = c; + } + i += len +2; + if (i >= opt_len) + break; + + if (j < buf_len) + buf[j++] = ','; + } + } #endif else nodecode = 1; @@ -1628,14 +1652,15 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) unhide_metas(comma); if ((netpart = split_chr(comma, '/'))) { - int msize, mask; + int msize; + arg = split(netpart); - if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 || - !atoi_check(netpart, &msize)) + if (!atoi_check(netpart, &msize)) option = '?'; - else + else if (inet_pton(AF_INET, comma, &new->start)) { - mask = (1 << (32 - msize)) - 1; + int mask = (1 << (32 - msize)) - 1; + new->is6 = 0; new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask); new->end.s_addr = new->start.s_addr | htonl(mask); if (arg) @@ -1677,19 +1702,93 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) } } } - } - else if ((arg = split(comma))) - { - if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 || - (new->end.s_addr = inet_addr(arg)) == (in_addr_t)-1) +#ifdef HAVE_IPV6 + else if (inet_pton(AF_INET6, comma, &new->start6)) + { + 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); + + if (msize < 64) + option = '?'; + else if (arg) + { + /* generate the equivalent of + local=// + local=/xxx.yyy.zzz.ip6.arpa/ */ + + if (strcmp(arg, "local") != 0 || (msize & 4 != 0)) + option = '?'; + else + { + 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(73); /* strlen("32*ip6.arpa")+1 */ + + for (i = msize-1; i >= 0; i -= 4) + { + int dig = ((unsigned char *)&new->start6)[i>>3]; + p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); + } + p += sprintf(p, "ip6.arpa"); + + serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR; + serv->next = daemon->servers; + daemon->servers = serv; + } + } + } +#endif + else option = '?'; } - else if ((new->start.s_addr = new->end.s_addr = inet_addr(comma)) == (in_addr_t)-1) - option = '?'; + else + { + arg = split(comma); + if (inet_pton(AF_INET, comma, &new->start)) + { + new->is6 = 0; + if (!arg) + new->end.s_addr = new->start.s_addr; + else if (!inet_pton(AF_INET, arg, &new->end)) + option = '?'; + } +#ifdef HAVE_IPV6 + else if (inet_pton(AF_INET6, comma, &new->start6)) + { + new->is6 = 1; + if (!arg) + memcpy(&new->end6, &new->start6, IN6ADDRSZ); + else if (!inet_pton(AF_INET6, arg, &new->end6)) + option = '?'; + } +#endif + else + option = '?'; - new->domain = d; - new->next = daemon->cond_domain; - daemon->cond_domain = new; + new->domain = d; + new->next = daemon->cond_domain; + daemon->cond_domain = new; + + } } else daemon->domain_suffix = d;