[Dnsmasq-discuss] [PATCH] DHCPv6 - List or Range reservation for single host

Simon Kelley simon at thekelleys.org.uk
Mon Jan 20 21:46:18 GMT 2020


On 16/01/2020 18:09, Harald Jensås wrote:
> Hi,
> 
> Changing the topic and dropping the history as this is a full re-write
> of the patch based on the previous feedback and discussion. Instead of
> multiple dhcp-host entries, a single dhcp-host entry can be defined
> with either  a list: or range: of addresses, this should eliminate the
> issue with ordering of entries in the configuration file.
> 
> 

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.

Happy to be shot down in flames, but that seems to be a simple to
implement and to explain way of doing what you want to achieve.



Cheers,

Simon.



> 
> --
> Harald
> 
> 
> 
>>From cfd8881d57ba9e0e26c183318f0118a5ca65c705 Mon Sep 17 00:00:00 2001
> From: Harald Jensås <hjensas at redhat.com>
> Date: Mon, 13 Jan 2020 19:44:43 +0100
> Subject: [PATCH] DHCPv6 - List or Range reservation for single host
> 
> Add the possibility to provide either a list  or a range
> of ipv6 addresses for a dhcp-host reservation. When a
> request matching the clid or mac address is recieved the
> server will iterate over the available 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 | 11 +++++++++
>  src/dnsmasq.h | 13 +++++++++-
>  src/option.c  | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++-
>  src/rfc3315.c | 60 +++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 149 insertions(+), 2 deletions(-)
> 
> diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
> index cb5cc73..454fca3 100644
> --- a/man/dnsmasq.8
> +++ b/man/dnsmasq.8
> @@ -1079,6 +1079,17 @@ 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 a list or a range of IPv6 addresses.
> +\fB--dhcp-host=52:54:00:3f:5c:c0,list:[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,range:fd12:3456::aa01-fd12:3456::aa63,host1\fP
> +will make the range of addresses between the start address (fd12:3456::aa01) and
> +the end address (fd12:3456::aa63) available to the host with hardware address
> +52:54:00:3f:5c:c0. Providing a range or list of 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..a77955b 100644
> --- a/src/dnsmasq.h
> +++ b/src/dnsmasq.h
> @@ -759,14 +759,23 @@ struct hwaddr_config {
>    struct hwaddr_config *next;
>  };
>  
> +#ifdef HAVE_DHCP6
> +struct in6_addr_list {
> +  struct in6_addr addr6;
> +  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 start6, end6; /* range of addresses */
> +  struct in6_addr_list *addr6_list;
>  #endif
>    struct in_addr addr;
>    time_t decline_time;
> @@ -790,6 +799,8 @@ 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_RANGE   32768
> +#define CONFIG_ADDR6_LIST    65536
>  
>  struct dhcp_opt {
>    int opt, len, flags;
> diff --git a/src/option.c b/src/option.c
> index f110b75..2a4a9e2 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,7 @@ static void dhcp_config_free(struct dhcp_config *config)
>  	  free(tmp);
>          }
>        dhcp_netid_list_free(config->netid);
> +      dhcp_addr6_list_free(config->addr6_list);
>        if (config->flags & CONFIG_CLID)
>          free(config->clid);
>        free(config);
> @@ -3262,8 +3273,62 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
>  		  ret_err(_("cannot match tags in --dhcp-host"));
>  		}
>  #ifdef HAVE_DHCP6
> -	      else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
> +	      /* dhcp-host have a range of addresses */
> +	      else if (strstr(arg, "range:") == arg)
>  		{
> +		  char *dash;
> +		  arg += 6; /* dump range: */
> +	          dash = split_chr(arg, '-');
> +
> +		  if (!inet_pton(AF_INET6, arg, &new->start6))
> +		    {
> +		      dhcp_config_free(new);
> +		      ret_err(_("bad IPv6 start address"));
> +		    }
> +
> +		  if (!inet_pton(AF_INET6, dash, &new->end6))
> +		    {
> +		      dhcp_config_free(new);
> +		      ret_err(_("bad IPv6 end address"));
> +		    }
> +
> +		  if (addr6part(&new->start6) > addr6part(&new->end6))
> +	            {
> +		      struct in6_addr tmp = new->start6;
> +		      new->start6 = new->end6;
> +		      new->end6 = tmp;
> +	            }
> +
> +		  /* set CONFIG_ADDR6_RANGE flag */
> +		  new->flags |= CONFIG_ADDR6_RANGE;
> +
> +		}
> +	      /* handle list of ipv6 addresses, [addr#1][addr#2][addr#3] */
> +	      else if (strstr(arg, "list:") == arg)
> +	        {
> +		  char *closing_bracket;
> +		  arg += 5; /* dump list */
> +		  while (strlen(arg))
> +	            {
> +		      closing_bracket = split_chr(arg, ']'); /* split and dump closing bracket */
> +
> +		      struct in6_addr_list *newaddr6 = opt_malloc(sizeof(struct in6_addr_list));
> +		      newaddr6->next = new->addr6_list;
> +		      new->addr6_list = newaddr6;
> +
> +		      arg++; /* dump open bracket */
> +		      if (!inet_pton(AF_INET6, arg, &new->addr6_list->addr6))
> +		        {
> +		          dhcp_config_free(new);
> +		          ret_err(_("bad IPv6 address"));
> +		        }
> +		      strcpy(arg, closing_bracket);
> +		    }
> +		    new->flags |= CONFIG_ADDR6_LIST;
> +		}
> +	      /* handle single address */
> +	      else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
> +	        {
>  		  arg[strlen(arg)-1] = 0;
>  		  arg++;
>  		  
> diff --git a/src/rfc3315.c b/src/rfc3315.c
> index 9471f5c..7096ccb 100644
> --- a/src/rfc3315.c
> +++ b/src/rfc3315.c
> @@ -664,6 +664,66 @@ 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_RANGE))
> +	      {
> +		int octet;
> +		struct in6_addr addr6;
> +		addr6 = config->start6;
> +
> +		/* unset CONFIG_ADDR6 and config->addr6 in case this is a another iteration */
> +	        if (have_config(config, CONFIG_ADDR6))
> +		  {
> +		    config->flags ^= CONFIG_ADDR6;
> +		    config->addr6 = addr6;
> +		  }
> +
> +		while (addr6part(&addr6) <= addr6part(&config->end6))
> +		  {
> +		    /* Check if address not leased to another CLID/IAID */
> +		    if (check_address(state, &addr6))
> +		      {
> +			memcpy(&config->addr6, &addr6, sizeof(struct in6_addr));
> +			config->flags |= CONFIG_ADDR6;
> +			break;
> +		      }
> +		    else
> +		      {
> +			/* Increment the address */
> +			for (octet = 15; octet >= 0; --octet)
> +			  if (addr6.s6_addr[octet] < 255)
> +			    {
> +			      addr6.s6_addr[octet]++;
> +			      break;
> +			    }
> +			  else
> +			    addr6.s6_addr[octet] = 0;
> +		      }
> +		  }
> +	      }
> +	    else if (have_config(config, CONFIG_ADDR6_LIST))
> +	      {
> +		struct in6_addr_list *list;
> +		struct in6_addr addr6;
> +
> +		/* unset CONFIG_ADDR6 and config->addr6 in case this is a another iteration */
> +	        if (have_config(config, CONFIG_ADDR6))
> +		  {
> +		    config->flags ^= CONFIG_ADDR6;
> +		    config->addr6 = addr6;
> +		  }
> +
> +		for (list = config->addr6_list; list; list = list->next)
> +		  {
> +		    addr6 = list->addr6;
> +		    if (check_address(state, &addr6))
> +		      {
> +		        memcpy(&config->addr6, &addr6, sizeof(struct in6_addr));
> +		        config->flags |= 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. */
> 




More information about the Dnsmasq-discuss mailing list