cde7b60662
In some cases, DUID will change for the same machine during network boot. Support assigning small blocks of IPv6 addresses to work around changing DUID.
761 lines
21 KiB
Diff
761 lines
21 KiB
Diff
From c491296241396d0144750f178ffd5c0e0b089a80 Mon Sep 17 00:00:00 2001
|
|
From: Simon Kelley <simon@thekelleys.org.uk>
|
|
Date: Thu, 6 Feb 2020 22:09:30 +0000
|
|
Subject: [PATCH] Extend 79aba0f10ad0157fb4f48afbbcb03f094caff97a for multiple
|
|
IPv6 addresses.
|
|
|
|
(cherry picked from commit 137286e9baecf6a3ba97722ef1b49c851b531810)
|
|
---
|
|
man/dnsmasq.8 | 7 +-
|
|
src/dhcp-common.c | 55 ++++--
|
|
src/dhcp6.c | 13 +-
|
|
src/dnsmasq.h | 13 +-
|
|
src/option.c | 416 +++++++++++++++++++++++++---------------------
|
|
src/rfc3315.c | 88 +++++-----
|
|
6 files changed, 330 insertions(+), 262 deletions(-)
|
|
|
|
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
|
|
index 95cd3ca..d1caeed 100644
|
|
--- a/man/dnsmasq.8
|
|
+++ b/man/dnsmasq.8
|
|
@@ -1008,14 +1008,15 @@ allowed to specify the client ID as text, like this:
|
|
|
|
A single
|
|
.B --dhcp-host
|
|
-may contain an IPv4 address or an IPv6 address, or both. IPv6 addresses must be bracketed by square brackets thus:
|
|
+may contain an IPv4 address or one or more IPv6 addresses, or both. IPv6 addresses must be bracketed by square brackets thus:
|
|
.B --dhcp-host=laptop,[1234::56]
|
|
IPv6 addresses may contain only the host-identifier part:
|
|
.B --dhcp-host=laptop,[::56]
|
|
in which case they act as wildcards in constructed dhcp ranges, with
|
|
-the appropriate network part inserted. For IPv6, the address may include a prefix length:
|
|
+the appropriate network part inserted. For IPv6, an address may include a prefix length:
|
|
.B --dhcp-host=laptop,[1234:50/126]
|
|
-which (in this case) specifies four addresses, 1234::50 to 1234::53. This is useful
|
|
+which (in this case) specifies four addresses, 1234::50 to 1234::53. This (an the ability
|
|
+to specify multiple addresses) is useful
|
|
when a host presents either a consistent name or hardware-ID, but varying DUIDs, since it allows
|
|
dnsmasq to honour the static address allocation but assign a different adddress for each DUID. This
|
|
typically occurs when chain netbooting, as each stage of the chain gets in turn allocates an address.
|
|
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
|
|
index 99d34c8..2933343 100644
|
|
--- a/src/dhcp-common.c
|
|
+++ b/src/dhcp-common.c
|
|
@@ -271,26 +271,35 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config
|
|
{
|
|
if (!context) /* called via find_config() from lease_update_from_configs() */
|
|
return 1;
|
|
-
|
|
- if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
|
|
- return 1;
|
|
|
|
#ifdef HAVE_DHCP6
|
|
- if ((context->flags & CONTEXT_V6) && (config->flags & CONFIG_WILDCARD))
|
|
- return 1;
|
|
-#endif
|
|
+ if (context->flags & CONTEXT_V6)
|
|
+ {
|
|
+ struct addrlist *addr_list;
|
|
|
|
- for (; context; context = context->current)
|
|
-#ifdef HAVE_DHCP6
|
|
- if (context->flags & CONTEXT_V6)
|
|
- {
|
|
- if ((config->flags & CONFIG_ADDR6) && is_same_net6(&config->addr6, &context->start6, context->prefix))
|
|
- return 1;
|
|
- }
|
|
- else
|
|
+ if (!(config->flags & CONFIG_ADDR6))
|
|
+ return 1;
|
|
+
|
|
+ for (; context; context = context->current)
|
|
+ for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
|
|
+ {
|
|
+ if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
|
|
+ return 1;
|
|
+
|
|
+ if (is_same_net6(&addr_list->addr.addr6, &context->start6, context->prefix))
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
#endif
|
|
- if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
|
|
+ {
|
|
+ if (!(config->flags & CONFIG_ADDR))
|
|
return 1;
|
|
+
|
|
+ for (; context; context = context->current)
|
|
+ if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
|
|
+ return 1;
|
|
+ }
|
|
|
|
return 0;
|
|
}
|
|
@@ -420,9 +429,19 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
|
if (prot == AF_INET6 &&
|
|
(!(conf_tmp = config_find_by_address6(configs, NULL, 0, &crec->addr.addr.addr.addr6)) || conf_tmp == config))
|
|
{
|
|
- memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
|
|
- config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
|
|
- config->flags &= ~CONFIG_PREFIX;
|
|
+ /* host must have exactly one address if comming from /etc/hosts. */
|
|
+ if (!config->addr6 && (config->addr6 = whine_malloc(sizeof(struct addrlist))))
|
|
+ {
|
|
+ config->addr6->next = NULL;
|
|
+ config->addr6->flags = 0;
|
|
+ }
|
|
+
|
|
+ if (config->addr6 && !config->addr6->next && !(config->addr6->flags & (ADDRLIST_WILDCARD|ADDRLIST_PREFIX)))
|
|
+ {
|
|
+ memcpy(&config->addr6->addr.addr6, &crec->addr.addr6, IN6ADDRSZ);
|
|
+ config->flags |= CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS;
|
|
+ }
|
|
+
|
|
continue;
|
|
}
|
|
#endif
|
|
diff --git a/src/dhcp6.c b/src/dhcp6.c
|
|
index 11a9d83..4e28e61 100644
|
|
--- a/src/dhcp6.c
|
|
+++ b/src/dhcp6.c
|
|
@@ -389,10 +389,15 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
|
|
struct dhcp_config *config;
|
|
|
|
for (config = configs; config; config = config->next)
|
|
- if ((config->flags & CONFIG_ADDR6) &&
|
|
- (!net || is_same_net6(&config->addr6, net, prefix)) &&
|
|
- is_same_net6(&config->addr6, addr, (config->flags & CONFIG_PREFIX) ? config->prefix : 128))
|
|
- return config;
|
|
+ if (config->flags & CONFIG_ADDR6)
|
|
+ {
|
|
+ struct addrlist *addr_list;
|
|
+
|
|
+ for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
|
|
+ if ((!net || is_same_net6(&addr_list->addr.addr6, net, prefix) || ((addr_list->flags & ADDRLIST_WILDCARD) && prefix == 64)) &&
|
|
+ is_same_net6(&addr_list->addr.addr6, addr, (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128))
|
|
+ return config;
|
|
+ }
|
|
|
|
return NULL;
|
|
}
|
|
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
|
index 86b8168..08484ba 100644
|
|
--- a/src/dnsmasq.h
|
|
+++ b/src/dnsmasq.h
|
|
@@ -350,9 +350,11 @@ struct ds_config {
|
|
struct ds_config *next;
|
|
};
|
|
|
|
-#define ADDRLIST_LITERAL 1
|
|
-#define ADDRLIST_IPV6 2
|
|
-#define ADDRLIST_REVONLY 4
|
|
+#define ADDRLIST_LITERAL 1
|
|
+#define ADDRLIST_IPV6 2
|
|
+#define ADDRLIST_REVONLY 4
|
|
+#define ADDRLIST_PREFIX 8
|
|
+#define ADDRLIST_WILDCARD 16
|
|
|
|
struct addrlist {
|
|
struct all_addr addr;
|
|
@@ -774,8 +776,7 @@ struct dhcp_config {
|
|
char *hostname, *domain;
|
|
struct dhcp_netid_list *netid;
|
|
#ifdef HAVE_DHCP6
|
|
- struct in6_addr addr6;
|
|
- int prefix;
|
|
+ struct addrlist *addr6;
|
|
#endif
|
|
struct in_addr addr;
|
|
time_t decline_time;
|
|
@@ -797,8 +798,6 @@ struct dhcp_config {
|
|
#define CONFIG_DECLINED 1024 /* address declined by client */
|
|
#define CONFIG_BANK 2048 /* from dhcp hosts file */
|
|
#define CONFIG_ADDR6 4096
|
|
-#define CONFIG_WILDCARD 8192
|
|
-#define CONFIG_PREFIX 32768 /* addr6 is a set, size given by prefix */
|
|
|
|
struct dhcp_opt {
|
|
int opt, len, flags;
|
|
diff --git a/src/option.c b/src/option.c
|
|
index 389eb02..2bbb11b 100644
|
|
--- a/src/option.c
|
|
+++ b/src/option.c
|
|
@@ -988,6 +988,19 @@ static void dhcp_config_free(struct dhcp_config *config)
|
|
free(list);
|
|
}
|
|
|
|
+#ifdef HAVE_DHCP6
|
|
+ if (config->flags & CONFIG_ADDR6)
|
|
+ {
|
|
+ struct addrlist *addr, *tmp;
|
|
+
|
|
+ for (addr = config->addr6; addr; addr = tmp)
|
|
+ {
|
|
+ tmp = addr->next;
|
|
+ free(addr);
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
if (config->flags & CONFIG_NAME)
|
|
free(config->hostname);
|
|
|
|
@@ -995,6 +1008,11 @@ static void dhcp_config_free(struct dhcp_config *config)
|
|
}
|
|
|
|
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+
|
|
/* This is too insanely large to keep in-line in the switch */
|
|
static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
|
{
|
|
@@ -3053,8 +3071,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|
case LOPT_BANK:
|
|
case 'G': /* --dhcp-host */
|
|
{
|
|
- int j, k = 0;
|
|
- char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
|
struct dhcp_config *new;
|
|
struct in_addr in;
|
|
|
|
@@ -3064,203 +3080,227 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|
new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
|
|
new->hwaddr = NULL;
|
|
new->netid = NULL;
|
|
+ new->addr6 = NULL;
|
|
|
|
- if ((a[0] = arg))
|
|
- for (k = 1; k < 7; k++)
|
|
- if (!(a[k] = split(a[k-1])))
|
|
- break;
|
|
-
|
|
- for (j = 0; j < k; j++)
|
|
- if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
|
|
- {
|
|
- char *arg = a[j];
|
|
-
|
|
- if ((arg[0] == 'i' || arg[0] == 'I') &&
|
|
- (arg[1] == 'd' || arg[1] == 'D') &&
|
|
- arg[2] == ':')
|
|
- {
|
|
- if (arg[3] == '*')
|
|
- new->flags |= CONFIG_NOCLID;
|
|
- else
|
|
- {
|
|
- int len;
|
|
- arg += 3; /* dump id: */
|
|
- if (strchr(arg, ':'))
|
|
- len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
|
|
- else
|
|
- {
|
|
- unhide_metas(arg);
|
|
- len = (int) strlen(arg);
|
|
- }
|
|
-
|
|
- if (len == -1)
|
|
- ret_err(_("bad hex constant"));
|
|
- else if ((new->clid = opt_malloc(len)))
|
|
- {
|
|
- new->flags |= CONFIG_CLID;
|
|
- new->clid_len = len;
|
|
- memcpy(new->clid, arg, len);
|
|
- }
|
|
- }
|
|
- }
|
|
- /* dhcp-host has strange backwards-compat needs. */
|
|
- else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
|
|
- {
|
|
- struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
|
|
- struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
|
|
- newtag->net = opt_malloc(strlen(arg + 4) + 1);
|
|
- newlist->next = new->netid;
|
|
- new->netid = newlist;
|
|
- newlist->list = newtag;
|
|
- strcpy(newtag->net, arg+4);
|
|
- unhide_metas(newtag->net);
|
|
- }
|
|
- else if (strstr(arg, "tag:") == arg)
|
|
- ret_err(_("cannot match tags in --dhcp-host"));
|
|
+ while (arg)
|
|
+ {
|
|
+ comma = split(arg);
|
|
+ if (strchr(arg, ':')) /* ethernet address, netid or binary CLID */
|
|
+ {
|
|
+ if ((arg[0] == 'i' || arg[0] == 'I') &&
|
|
+ (arg[1] == 'd' || arg[1] == 'D') &&
|
|
+ arg[2] == ':')
|
|
+ {
|
|
+ if (arg[3] == '*')
|
|
+ new->flags |= CONFIG_NOCLID;
|
|
+ else
|
|
+ {
|
|
+ int len;
|
|
+ arg += 3; /* dump id: */
|
|
+ if (strchr(arg, ':'))
|
|
+ len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
|
|
+ else
|
|
+ {
|
|
+ unhide_metas(arg);
|
|
+ len = (int) strlen(arg);
|
|
+ }
|
|
+
|
|
+ if (len == -1)
|
|
+ {
|
|
+ dhcp_config_free(new);
|
|
+ ret_err(_("bad hex constant"));
|
|
+ }
|
|
+ else if ((new->clid = opt_malloc(len)))
|
|
+ {
|
|
+ new->flags |= CONFIG_CLID;
|
|
+ new->clid_len = len;
|
|
+ memcpy(new->clid, arg, len);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ /* dhcp-host has strange backwards-compat needs. */
|
|
+ else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
|
|
+ {
|
|
+ struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
|
|
+ struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
|
|
+ newtag->net = opt_malloc(strlen(arg + 4) + 1);
|
|
+ newlist->next = new->netid;
|
|
+ new->netid = newlist;
|
|
+ newlist->list = newtag;
|
|
+ strcpy(newtag->net, arg+4);
|
|
+ unhide_metas(newtag->net);
|
|
+ }
|
|
+ else if (strstr(arg, "tag:") == arg)
|
|
+ {
|
|
+
|
|
+ dhcp_config_free(new);
|
|
+ ret_err(_("cannot match tags in --dhcp-host"));
|
|
+ }
|
|
#ifdef HAVE_DHCP6
|
|
- else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
|
|
- {
|
|
- char *pref;
|
|
-
|
|
- arg[strlen(arg)-1] = 0;
|
|
- arg++;
|
|
- pref = split_chr(arg, '/');
|
|
-
|
|
- if (!inet_pton(AF_INET6, arg, &new->addr6))
|
|
- ret_err(_("bad IPv6 address"));
|
|
-
|
|
- if (pref)
|
|
- {
|
|
- u64 addrpart = addr6part(&new->addr6);
|
|
-
|
|
- if (!atoi_check(pref, &new->prefix) ||
|
|
- new->prefix > 128 ||
|
|
- (((1<<(128-new->prefix))-1) & addrpart) != 0)
|
|
- {
|
|
- dhcp_config_free(new);
|
|
- ret_err(_("bad IPv6 prefix"));
|
|
- }
|
|
-
|
|
- new->flags |= CONFIG_PREFIX;
|
|
- }
|
|
-
|
|
- for (i= 0; i < 8; i++)
|
|
- if (new->addr6.s6_addr[i] != 0)
|
|
- break;
|
|
+ else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
|
|
+ {
|
|
+ char *pref;
|
|
+ struct in6_addr in6;
|
|
+ struct addrlist *new_addr;
|
|
+
|
|
+ arg[strlen(arg)-1] = 0;
|
|
+ arg++;
|
|
+ pref = split_chr(arg, '/');
|
|
+
|
|
+ if (!inet_pton(AF_INET6, arg, &in6))
|
|
+ {
|
|
+ dhcp_config_free(new);
|
|
+ ret_err(_("bad IPv6 address"));
|
|
+ }
|
|
|
|
- /* set WILDCARD if network part all zeros */
|
|
- if (i == 8)
|
|
- new->flags |= CONFIG_WILDCARD;
|
|
+ new_addr = opt_malloc(sizeof(struct addrlist));
|
|
+ new_addr->next = new->addr6;
|
|
+ new_addr->flags = 0;
|
|
+ new_addr->addr.addr6 = in6;
|
|
+ new->addr6 = new_addr;
|
|
+
|
|
+ if (pref)
|
|
+ {
|
|
+ u64 addrpart = addr6part(&in6);
|
|
+
|
|
+ if (!atoi_check(pref, &new_addr->prefixlen) ||
|
|
+ new_addr->prefixlen > 128 ||
|
|
+ (((1<<(128-new_addr->prefixlen))-1) & addrpart) != 0)
|
|
+ {
|
|
+ dhcp_config_free(new);
|
|
+ ret_err(_("bad IPv6 prefix"));
|
|
+ }
|
|
+
|
|
+ new_addr->flags |= ADDRLIST_PREFIX;
|
|
+ }
|
|
|
|
- new->flags |= CONFIG_ADDR6;
|
|
- }
|
|
+ for (i= 0; i < 8; i++)
|
|
+ if (in6.s6_addr[i] != 0)
|
|
+ break;
|
|
+
|
|
+ /* set WILDCARD if network part all zeros */
|
|
+ if (i == 8)
|
|
+ new_addr->flags |= ADDRLIST_WILDCARD;
|
|
+
|
|
+ new->flags |= CONFIG_ADDR6;
|
|
+ }
|
|
#endif
|
|
- else
|
|
- {
|
|
- struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
|
|
- if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
|
|
- &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
|
|
- ret_err(_("bad hex constant"));
|
|
- else
|
|
- {
|
|
-
|
|
- newhw->next = new->hwaddr;
|
|
- new->hwaddr = newhw;
|
|
- }
|
|
- }
|
|
- }
|
|
- else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
|
|
- {
|
|
- struct dhcp_config *configs;
|
|
-
|
|
- new->addr = in;
|
|
- new->flags |= CONFIG_ADDR;
|
|
-
|
|
- /* If the same IP appears in more than one host config, then DISCOVER
|
|
- for one of the hosts will get the address, but REQUEST will be NAKed,
|
|
- since the address is reserved by the other one -> protocol loop. */
|
|
- for (configs = daemon->dhcp_conf; configs; configs = configs->next)
|
|
- if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
|
|
+ else
|
|
{
|
|
- sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in));
|
|
- return 0;
|
|
- }
|
|
- }
|
|
- else
|
|
- {
|
|
- char *cp, *lastp = NULL, last = 0;
|
|
- int fac = 1, isdig = 0;
|
|
-
|
|
- if (strlen(a[j]) > 1)
|
|
- {
|
|
- lastp = a[j] + strlen(a[j]) - 1;
|
|
- last = *lastp;
|
|
- switch (last)
|
|
+ struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
|
|
+ if ((newhw->hwaddr_len = parse_hex(arg, newhw->hwaddr, DHCP_CHADDR_MAX,
|
|
+ &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
|
|
+ {
|
|
+ free(newhw);
|
|
+ dhcp_config_free(new);
|
|
+ ret_err(_("bad hex constant"));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+
|
|
+ newhw->next = new->hwaddr;
|
|
+ new->hwaddr = newhw;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ else if (strchr(arg, '.') && (inet_pton(AF_INET, arg, &in) > 0))
|
|
+ {
|
|
+ struct dhcp_config *configs;
|
|
+
|
|
+ new->addr = in;
|
|
+ new->flags |= CONFIG_ADDR;
|
|
+
|
|
+ /* If the same IP appears in more than one host config, then DISCOVER
|
|
+ for one of the hosts will get the address, but REQUEST will be NAKed,
|
|
+ since the address is reserved by the other one -> protocol loop. */
|
|
+ for (configs = daemon->dhcp_conf; configs; configs = configs->next)
|
|
+ if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
|
|
{
|
|
- case 'w':
|
|
- case 'W':
|
|
- fac *= 7;
|
|
- /* fall through */
|
|
- case 'd':
|
|
- case 'D':
|
|
- fac *= 24;
|
|
- /* fall through */
|
|
- case 'h':
|
|
- case 'H':
|
|
- fac *= 60;
|
|
- /* fall through */
|
|
- case 'm':
|
|
- case 'M':
|
|
- fac *= 60;
|
|
- /* fall through */
|
|
- case 's':
|
|
- case 'S':
|
|
- *lastp = 0;
|
|
- }
|
|
- }
|
|
-
|
|
- for (cp = a[j]; *cp; cp++)
|
|
- if (isdigit((unsigned char)*cp))
|
|
- isdig = 1;
|
|
- else if (*cp != ' ')
|
|
- break;
|
|
+ sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in));
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ char *cp, *lastp = NULL, last = 0;
|
|
+ int fac = 1, isdig = 0;
|
|
+
|
|
+ if (strlen(arg) > 1)
|
|
+ {
|
|
+ lastp = arg + strlen(arg) - 1;
|
|
+ last = *lastp;
|
|
+ switch (last)
|
|
+ {
|
|
+ case 'w':
|
|
+ case 'W':
|
|
+ fac *= 7;
|
|
+ /* fall through */
|
|
+ case 'd':
|
|
+ case 'D':
|
|
+ fac *= 24;
|
|
+ /* fall through */
|
|
+ case 'h':
|
|
+ case 'H':
|
|
+ fac *= 60;
|
|
+ /* fall through */
|
|
+ case 'm':
|
|
+ case 'M':
|
|
+ fac *= 60;
|
|
+ /* fall through */
|
|
+ case 's':
|
|
+ case 'S':
|
|
+ *lastp = 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (cp = arg; *cp; cp++)
|
|
+ if (isdigit((unsigned char)*cp))
|
|
+ isdig = 1;
|
|
+ else if (*cp != ' ')
|
|
+ break;
|
|
+
|
|
+ if (*cp)
|
|
+ {
|
|
+ if (lastp)
|
|
+ *lastp = last;
|
|
+ if (strcmp(arg, "infinite") == 0)
|
|
+ {
|
|
+ new->lease_time = 0xffffffff;
|
|
+ new->flags |= CONFIG_TIME;
|
|
+ }
|
|
+ else if (strcmp(arg, "ignore") == 0)
|
|
+ new->flags |= CONFIG_DISABLE;
|
|
+ else
|
|
+ {
|
|
+ if (!(new->hostname = canonicalise_opt(arg)) ||
|
|
+ !legal_hostname(new->hostname))
|
|
+ {
|
|
+ dhcp_config_free(new);
|
|
+ ret_err(_("bad DHCP host name"));
|
|
+ }
|
|
+
|
|
+ new->flags |= CONFIG_NAME;
|
|
+ new->domain = strip_hostname(new->hostname);
|
|
+ }
|
|
+ }
|
|
+ else if (isdig)
|
|
+ {
|
|
+ new->lease_time = atoi(arg) * fac;
|
|
+ /* Leases of a minute or less confuse
|
|
+ some clients, notably Apple's */
|
|
+ if (new->lease_time < 120)
|
|
+ new->lease_time = 120;
|
|
+ new->flags |= CONFIG_TIME;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ arg = comma;
|
|
+ }
|
|
|
|
- if (*cp)
|
|
- {
|
|
- if (lastp)
|
|
- *lastp = last;
|
|
- if (strcmp(a[j], "infinite") == 0)
|
|
- {
|
|
- new->lease_time = 0xffffffff;
|
|
- new->flags |= CONFIG_TIME;
|
|
- }
|
|
- else if (strcmp(a[j], "ignore") == 0)
|
|
- new->flags |= CONFIG_DISABLE;
|
|
- else
|
|
- {
|
|
- if (!(new->hostname = canonicalise_opt(a[j])) ||
|
|
- !legal_hostname(new->hostname))
|
|
- ret_err(_("bad DHCP host name"));
|
|
-
|
|
- new->flags |= CONFIG_NAME;
|
|
- new->domain = strip_hostname(new->hostname);
|
|
- }
|
|
- }
|
|
- else if (isdig)
|
|
- {
|
|
- new->lease_time = atoi(a[j]) * fac;
|
|
- /* Leases of a minute or less confuse
|
|
- some clients, notably Apple's */
|
|
- if (new->lease_time < 120)
|
|
- new->lease_time = 120;
|
|
- new->flags |= CONFIG_TIME;
|
|
- }
|
|
- }
|
|
-
|
|
daemon->dhcp_conf = new;
|
|
break;
|
|
}
|
|
-
|
|
+
|
|
case LOPT_TAG_IF: /* --tag-if */
|
|
{
|
|
struct tag_if *new = opt_malloc(sizeof(struct tag_if));
|
|
diff --git a/src/rfc3315.c b/src/rfc3315.c
|
|
index f4f032e..9dc33f9 100644
|
|
--- a/src/rfc3315.c
|
|
+++ b/src/rfc3315.c
|
|
@@ -1793,68 +1793,72 @@ static int config_implies(struct dhcp_config *config, struct dhcp_context *conte
|
|
{
|
|
int prefix;
|
|
struct in6_addr wild_addr;
|
|
-
|
|
+ struct addrlist *addr_list;
|
|
+
|
|
if (!config || !(config->flags & CONFIG_ADDR6))
|
|
return 0;
|
|
|
|
- prefix = (config->flags & CONFIG_PREFIX) ? config->prefix : 128;
|
|
- wild_addr = config->addr6;
|
|
-
|
|
- if (!is_same_net6(&context->start6, addr, context->prefix))
|
|
- return 0;
|
|
-
|
|
- if ((config->flags & CONFIG_WILDCARD))
|
|
+ for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
|
|
{
|
|
- if (context->prefix != 64)
|
|
- return 0;
|
|
+ prefix = (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128;
|
|
+ wild_addr = addr_list->addr.addr6;
|
|
+
|
|
+ if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
|
|
+ {
|
|
+ wild_addr = context->start6;
|
|
+ setaddr6part(&wild_addr, addr6part(&addr_list->addr.addr6));
|
|
+ }
|
|
+ else if (!is_same_net6(&context->start6, addr, context->prefix))
|
|
+ continue;
|
|
|
|
- wild_addr = context->start6;
|
|
- setaddr6part(&wild_addr, addr6part(&config->addr6));
|
|
+ if (is_same_net6(&wild_addr, addr, prefix))
|
|
+ return 1;
|
|
}
|
|
|
|
- if (is_same_net6(&wild_addr, addr, prefix))
|
|
- return 1;
|
|
-
|
|
return 0;
|
|
}
|
|
|
|
static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state)
|
|
{
|
|
u64 addrpart;
|
|
-
|
|
+ struct addrlist *addr_list;
|
|
+
|
|
if (!config || !(config->flags & CONFIG_ADDR6))
|
|
return 0;
|
|
|
|
- addrpart = addr6part(&config->addr6);
|
|
-
|
|
- if ((config->flags & CONFIG_WILDCARD))
|
|
+ for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
|
|
{
|
|
- if (context->prefix != 64)
|
|
- return 0;
|
|
+ addrpart = addr6part(&addr_list->addr.addr6);
|
|
+
|
|
+ if ((addr_list->flags & ADDRLIST_WILDCARD))
|
|
+ {
|
|
+ if (context->prefix != 64)
|
|
+ continue;
|
|
|
|
- *addr = context->start6;
|
|
- setaddr6part(addr, addrpart);
|
|
+ *addr = context->start6;
|
|
+ setaddr6part(addr, addrpart);
|
|
+ }
|
|
+ else if (is_same_net6(&context->start6, &addr_list->addr.addr6, context->prefix))
|
|
+ *addr = addr_list->addr.addr6;
|
|
+ else
|
|
+ continue;
|
|
+
|
|
+ while(1)
|
|
+ {
|
|
+ if (check_address(state, addr))
|
|
+ return 1;
|
|
+
|
|
+ if (!(addr_list->flags & ADDRLIST_PREFIX))
|
|
+ break;
|
|
+
|
|
+ addrpart++;
|
|
+ setaddr6part(addr, addrpart);
|
|
+ if (!is_same_net6(addr, &addr_list->addr.addr6, addr_list->prefixlen))
|
|
+ break;
|
|
+ }
|
|
}
|
|
- else if (is_same_net6(&context->start6, &config->addr6, context->prefix))
|
|
- *addr = config->addr6;
|
|
- else
|
|
- return 0;
|
|
|
|
- while(1) {
|
|
- if (check_address(state, addr))
|
|
- return 1;
|
|
-
|
|
- if (!(config->flags & CONFIG_PREFIX))
|
|
- return 0;
|
|
-
|
|
- /* config may specify a set of addresses, return first one not in use
|
|
- by another client */
|
|
-
|
|
- addrpart++;
|
|
- setaddr6part(addr, addrpart);
|
|
- if (!is_same_net6(addr, &config->addr6, config->prefix))
|
|
- return 0;
|
|
- }
|
|
+ return 0;
|
|
}
|
|
|
|
/* Calculate valid and preferred times to send in leases/renewals.
|
|
--
|
|
2.21.1
|
|
|