On Tue, 2020-01-21 at 23:38 +0100, Tore Anderson wrote: > * Simon Kelley > > > I have an alternative suggestion for the syntax of dhcp-host. > > It's less flexible, but simpler and easier to understand and to > > explain, > > and uses existing semantics rather than adding new keywords. > > > > The idea is just to add a prefix-length to the address. That allows > > you > > to define (eg) 1,2,4,8, or 16 addresses for use by a host simply > > and > > easily in a way which makes it difficult to accidentally overlap > > address > > ranges, and is fairly obvious to anyone who has done done any IPv6 > > network configuration. > > > > for instance to reserve four addresses for each host we cold do: > > > > dhcp-host=00:11:22:33:44:55,[fd12:3456::aa00/62] > > dhcp-host=00:11:22:33:44:56,[fd12:3456::aa04/62] > > dhcp-host=00:11:22:33:44:57,[fd12:3456::aa08/62] > > > > As a sanity check, if the "host part" of the address isn't zero, > > > > ie [fd12:3456::aa01/62] > > > > that could be rejected with an error. >
I like the idea of using a prefix. I have a new revision of the patch with this implemented at the bottom of this e-mail. It's far better and more flexible than the keywords approach I came up with initially, as it's now possible to mix individual addreses, prefixed ranges and prefixed wildcard addresses etc. # A list of addressses dhcp-host=52:54:00:3f:5c:c0,[fd12:3456:789a:1::aa02][fd12:3456:789a:1::aa04][fd12:3456:789a:1::aa06],host1 # Mixing a prefix and a single address dhcp-host=52:54:00:3f:5c:c0,[fd12:3456:789a:1::aa04/62][fd12:3456:789a:1::aa00],host1 # Prefixed wildcard dhcp-host=52:54:00:3f:5c:c0,[::aa04/62],host1 > I have done quite a bit of IPv6 networking, but the use of /62 here > is anything but «fairly obvious» to me. > > It would have been much more intuitive to use /126, in my opinion. > > Tore > I too found it a bit curios with /62 at first, as I understand it the interface identifier is always the 64 least significant bit's in IPv6 ref[1]. I think changing the patch to use the full 128 bit's as a mask is trivial. We may also support both by subtracting 64 from any prefix larger than 64 in the code? So /126 and /62 yield the same result. What does other people think? [1] https://en.wikipedia.org/wiki/IPv6_address#Unicast_and_anycast_address_format From a69c6400454cdf036808a0a40ac033688387f20d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Jens=C3=A5s?= <hjen...@redhat.com> Date: Mon, 13 Jan 2020 19:44:43 +0100 Subject: [PATCH] DHCPv6 - List and Range reservation for single host Add the possibility to provide list's of individual addresses as well as prefixed ranges of ipv6 addresses for a dhcp-host reservation. When a request matching the clid or mac address is recieved the server will iterate over all candidate addresses until it find's one that is not already leased to a different clid/iaid and advertise this address. Using multiple reservations for a single host makes it possible to maintain a static leases only configuration which support network booting systems with UEFI firmware that request a new address (a new SOLICIT with a new IA_NA option using a new IAID) for different boot modes, for instance 'PXE over IPv6', and 'HTTP-Boot over IPv6'. Open Virtual Machine Firmware (OVMF) and most UEFI firmware build on the EDK2 code base exhibit this behaviour. --- man/dnsmasq.8 | 16 ++++++++++++ src/dnsmasq.h | 15 ++++++++++-- src/option.c | 68 +++++++++++++++++++++++++++++++++++++++------------ src/rfc3315.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+), 18 deletions(-) diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index cb5cc73..57003d7 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -1079,6 +1079,22 @@ work reliably if only one of the hardware addresses is active at any time and there is no way for dnsmasq to enforce this. It is, for instance, useful to allocate a stable IP address to a laptop which has both wired and wireless interfaces. + +For DHCPv6 it is possible to provide multiple IPv6 addresses for a single +dhcp-host. It is also possible to use a prefix in the configuration to +set up a range of addresses. For example: +\fB--dhcp-host=52:54:00:3f:5c:c0,[fd12:3456::aa02][fd12:3456::aa04],host1\fP +will make the two addresses \fBfd12:3456::aa02\fP and \fBfd12:3456::aa04\fP +available to the host with hardware address 52:54:00:3f:5c:c0. +\fB--dhcp-host=52:54:00:3f:5c:c0,[fd12:3456::aa00/62],host1\fP +will make the range of 4 addresses between the base address (fd12:3456::aa00) +and the end address (fd12:3456::aa03) available to the host with hardware +address 52:54:00:3f:5c:c0. Multiple non-prefixed, prefixed or prefixed +wildcard addresses with only the host-identifier part can be mixed, eg: +\fB--dhcp-host=52:54:00:3f:5c:c0,[::aa03][::aa04/63][::aa08/62],host1\fP. +Providing multiple addresses is useful for network booting where individual +boot stages will request addresses with different IAID's. + .TP .B --dhcp-hostsfile=<path> Read DHCP host information from the specified file. If a directory diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 7fb440c..5c771b6 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -759,14 +759,24 @@ struct hwaddr_config { struct hwaddr_config *next; }; +#ifdef HAVE_DHCP6 +struct in6_addr_list { + struct in6_addr addr6; + int prefix; + unsigned long flags; + struct in6_addr_list *next; +}; +#endif + struct dhcp_config { - unsigned int flags; + unsigned long flags; int clid_len; /* length of client identifier */ unsigned char *clid; /* clientid */ char *hostname, *domain; struct dhcp_netid_list *netid; #ifdef HAVE_DHCP6 - struct in6_addr addr6; + struct in6_addr addr6; /* internal only, user opts in addr6_list */ + struct in6_addr_list *addr6_list; #endif struct in_addr addr; time_t decline_time; @@ -790,6 +800,7 @@ struct dhcp_config { #define CONFIG_ADDR6 4096 #define CONFIG_WILDCARD 8192 #define CONFIG_ADDR6_HOSTS 16384 /* address added by from /etc/hosts */ +#define CONFIG_ADDR6_CAND 32768 /* IPv6 address candidate(s) available */ struct dhcp_opt { int opt, len, flags; diff --git a/src/option.c b/src/option.c index f110b75..28a1f3f 100644 --- a/src/option.c +++ b/src/option.c @@ -1015,6 +1015,16 @@ static void dhcp_netid_list_free(struct dhcp_netid_list *netid) } } +static void dhcp_addr6_list_free(struct in6_addr_list *addr6_list) +{ + while (addr6_list) + { + struct in6_addr_list *tmp = addr6_list; + addr6_list = addr6_list->next; + free(tmp); + } +} + static void dhcp_config_free(struct dhcp_config *config) { if (config) @@ -1027,6 +1037,9 @@ static void dhcp_config_free(struct dhcp_config *config) free(tmp); } dhcp_netid_list_free(config->netid); +#ifdef HAVE_DHCP6 + dhcp_addr6_list_free(config->addr6_list); +#endif if (config->flags & CONFIG_CLID) free(config->clid); free(config); @@ -3264,24 +3277,47 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma #ifdef HAVE_DHCP6 else if (arg[0] == '[' && arg[strlen(arg)-1] == ']') { - arg[strlen(arg)-1] = 0; - arg++; - - if (!inet_pton(AF_INET6, arg, &new->addr6)) + char *closing_bracket; + char *prefix; + while (strlen(arg)) { - dhcp_config_free(new); - ret_err(_("bad IPv6 address")); + struct in6_addr_list *newaddr6 = malloc(sizeof(struct in6_addr_list)); + newaddr6->next = new->addr6_list; + new->addr6_list = newaddr6; + new->addr6_list->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0; + + closing_bracket = split_chr(arg, ']'); /* split and dump closing bracket */ + arg++; /* dump open bracket */ + + prefix = split_chr(arg, '/'); + if (prefix == NULL) + prefix = "64"; + new->addr6_list->prefix = atoi(prefix); + + if (!inet_pton(AF_INET6, arg, &new->addr6_list->addr6)) + { + dhcp_config_free(new); + ret_err(_("bad IPv6 address")); + } + + if ((new->addr6_list->prefix <= 63) && + (addr6part(&new->addr6_list->addr6) << new->addr6_list->prefix) != 0) + { + dhcp_config_free(new); + ret_err(_("bad IPv6 base address with prefix")); + } + + for (i = 0; i < 8; i++) + if (new->addr6_list->addr6.s6_addr[i] != 0) + break; + + /* set WILDCARD if network part all zeros */ + if (i == 8) + new->addr6_list->flags |= CONFIG_WILDCARD; + + strcpy(arg, closing_bracket); } - - for (i= 0; i < 8; i++) - if (new->addr6.s6_addr[i] != 0) - break; - - /* set WILDCARD if network part all zeros */ - if (i == 8) - new->flags |= CONFIG_WILDCARD; - - new->flags |= CONFIG_ADDR6; + new->flags |= CONFIG_ADDR6_CAND; } #endif else diff --git a/src/rfc3315.c b/src/rfc3315.c index 9471f5c..2462efe 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -664,6 +664,72 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ if (address_assigned) address_assigned = 2; + if (have_config(config, CONFIG_ADDR6_CAND)) + { + struct in6_addr_list *list; + struct in6_addr addr6; + int hextet; + u64 pbit; + + /* unset CONFIG_ADDR6, config->addr6 */ + if (have_config(config, CONFIG_ADDR6)) + { + config->flags ^= CONFIG_ADDR6; + config->addr6 = addr6; + } + + for (list = config->addr6_list; list; list = list->next) + { + if ((list->flags & CONFIG_WILDCARD) && (state->context->prefix == 64)) + { + addr6 = state->context->start6; + setaddr6part(&addr6, addr6part(&list->addr6)); + } + else + addr6 = list->addr6; + + if ((list->prefix > 63) && check_address(state, &addr6)) + { + /* unleased address found, set config->addr6 + flags */ + memcpy(&config->addr6, &addr6, sizeof(struct in6_addr)); + config->flags |= CONFIG_ADDR6; + break; + } + else if (list->prefix <= 63) + { + /* get prefix bits and invert with XOR */ + u64 prefixbits = (0xFFFFFFFFFFFFFFFF << (64 - list->prefix)) ^ 0xFFFFFFFFFFFFFFFF; + + for (pbit = 0; pbit <= prefixbits; pbit++) + { + if (check_address(state, &addr6)) + { + /* unleased address found, set config->addr6 + flags */ + memcpy(&config->addr6, &addr6, sizeof(struct in6_addr)); + config->flags |= CONFIG_ADDR6; + break; + } + + /* increment address */ + for (hextet = 15; hextet >= 0; --hextet) + { + if (addr6.s6_addr[hextet] < 255) + { + addr6.s6_addr[hextet]++; + break; + } + else + addr6.s6_addr[hextet] = 0; + } + + } + + if (have_config(config, CONFIG_ADDR6)) + break; + } + } + } + for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) { /* worry about alignment here. */ -- 2.24.1 _______________________________________________ Dnsmasq-discuss mailing list Dnsmasq-discuss@lists.thekelleys.org.uk http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss