[Dnsmasq-discuss] [PATCH] DHCPv6: Add support for more than one hardware address per IPv6 address

Simon Kelley simon at thekelleys.org.uk
Fri Jan 1 20:23:36 GMT 2016


On 23/12/15 21:10, Pali Rohár wrote:
> This patch allows to assign one IPv6 address for more config entries
> specified by MAC address. This is similar function as for IPv4 addresses
> in DHCPv4 server code part.

This needs some thinking about: DHCPv6 is different from DHCPv4 in that
clients are not, at all, identified by MAC address, rather by client-id
and IAID. In addition, DHCPv6 handles multiple addresses and leases per
client.

What's important? To be able to specify more than on MAC address, any
one of which can be matched, or to have a single IPv6 address which is
removed from one IAID to another if the MAC addresses are paired?


Cheers,

Simon.



> ---
>  man/dnsmasq.8 |    9 ++++++---
>  src/rfc3315.c |   63 ++++++++++++++++++++++++++++++++++++++++++++++++---------
>  2 files changed, 60 insertions(+), 12 deletions(-)
> 
> diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
> index d51b10f..6a121fe 100644
> --- a/man/dnsmasq.8
> +++ b/man/dnsmasq.8
> @@ -978,10 +978,13 @@ will only match a
>  Token-Ring hardware address, since the ARP-address type for token ring
>  is 6. 
>  
> -As a special case, in DHCPv4, it is possible to include more than one
> -hardware address. eg:
> +It is possible to include more than one hardware address. eg for IPv4:
>  .B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2
> -This allows an IP address to be associated with
> +or for IPv6:
> +.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,[::2]
> +or for both:
> +.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2,[::2]
> +This allows an IPv4 and/or IPv6 address to be associated with
>  multiple hardware addresses, and gives dnsmasq permission to abandon a
>  DHCP lease to one of the hardware addresses when another one asks for
>  a lease. Beware that this is a dangerous thing to do, it will only
> diff --git a/src/rfc3315.c b/src/rfc3315.c
> index 3ed8623..19738b4 100644
> --- a/src/rfc3315.c
> +++ b/src/rfc3315.c
> @@ -54,7 +54,7 @@ static struct prefix_class *prefix_class_from_context(struct dhcp_context *conte
>  #endif
>  static void mark_context_used(struct state *state, struct in6_addr *addr);
>  static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
> -static int check_address(struct state *state, struct in6_addr *addr);
> +static int check_address(struct state *state, struct dhcp_config *config, struct in6_addr *addr);
>  static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option, 
>  			unsigned int *min_time, struct in6_addr *addr, time_t now);
>  static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
> @@ -704,7 +704,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>  		    /* If the client asks for an address on the same network as a configured address, 
>  		       offer the configured address instead, to make moving to newly-configured
>  		       addresses automatic. */
> -		    if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
> +		    if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, config, &addr))
>  		      {
>  			req_addr = &addr;
>  			mark_config_used(c, &addr);
> @@ -713,8 +713,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>  		      }
>  		    else if (!(c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
>  		      continue; /* not an address we're allowed */
> -		    else if (!check_address(state, req_addr))
> +		    else if (!check_address(state, config, req_addr))
>  		      continue; /* address leased elsewhere */
> +		    else if (state->mac_len && config &&
> +			     config_has_mac(config, state->mac, state->mac_len, state->mac_type) &&
> +			     match_netid(c->filter, solicit_tags, plain_range) &&
> +			     config_valid(config, c, &addr) &&
> +			     !IN6_ARE_ADDR_EQUAL(req_addr, &addr))
> +		      continue; /* another static address is configured */
>  		    
>  		    /* add address to output packet */
>  #ifdef OPTION6_PREFIX_CLASS
> @@ -730,10 +736,13 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>  	    
>  	    /* Suggest configured address(es) */
>  	    for (c = state->context; c; c = c->current) 
> -	      if (!(c->flags & CONTEXT_CONF_USED) &&
> +	      if ((!(c->flags & CONTEXT_CONF_USED) ||
> +		   (state->mac_len && config &&
> +		    config_has_mac(config, state->mac, state->mac_len, state->mac_type)
> +		   )) &&
>  		  match_netid(c->filter, solicit_tags, plain_range) &&
>  		  config_valid(config, c, &addr) && 
> -		  check_address(state, &addr))
> +		  check_address(state, config, &addr))
>  		{
>  		  mark_config_used(state->context, &addr);
>  		  if (have_config(config, CONFIG_TIME))
> @@ -758,6 +767,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>  		req_addr = &ltmp->addr6;
>  		if ((c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
>  		  {
> +		    if (state->mac_len && config &&
> +			config_has_mac(config, state->mac, state->mac_len, state->mac_type) &&
> +			match_netid(c->filter, solicit_tags, plain_range) &&
> +			config_valid(config, c, &addr) &&
> +			!IN6_ARE_ADDR_EQUAL(req_addr, &addr))
> +		      continue; /* skip this lease because another static address is configured */
>  #ifdef OPTION6_PREFIX_CLASS
>  		    if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
>  		      state->send_prefix_class = prefix_class_from_context(c);
> @@ -898,7 +913,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>  			put_opt6_string(_("address unavailable"));
>  			end_opt6(o1);
>  		      }
> -		    else if (!check_address(state, req_addr))
> +		    else if (!check_address(state, config, req_addr))
>  		      {
>  			/* Address leased to another DUID/IAID */
>  			o1 = new_opt6(OPTION6_STATUS_CODE);
> @@ -1017,6 +1032,17 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>  		    struct in6_addr addr;
>  		    unsigned int lease_time;
>  
> +		    /* check if another static address is preferred */
> +		    if (state->mac_len && config &&
> +		        config_has_mac(config, state->mac, state->mac_len, state->mac_type) &&
> +		        config_valid(config, this_context, &addr) &&
> +		        !IN6_ARE_ADDR_EQUAL(req_addr, &addr))
> +		      {
> +			preferred_time = valid_time = 0;
> +			message = _("deprecated");
> +		      }
> +		    else
> +		      {
>  		    get_context_tag(state, this_context);
>  		    
>  		    if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
> @@ -1042,6 +1068,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>  		    
>  		    if (preferred_time == 0)
>  		      message = _("deprecated");
> +		      }
>  		  }
>  		else
>  		  {
> @@ -1088,13 +1115,27 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>  		 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
>  	      {
>  		struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
> +		struct in6_addr addr;
> +		struct dhcp_context *c;
> +		int config_addr_ok = 1;
> +
> +		c = address6_valid(state->context, req_addr, tagif, 1);
> +
> +		if (c && state->mac_len && config &&
> +		    config_has_mac(config, state->mac, state->mac_len, state->mac_type) &&
> +		    config_valid(config, c, &addr) &&
> +		    !IN6_ARE_ADDR_EQUAL(req_addr, &addr))
> +		  {
> +		    config_addr_ok = 0;
> +		  }
>  		
> -		if (!address6_valid(state->context, req_addr, tagif, 1))
> +		if (!c || !config_addr_ok)
>  		  {
>  		    o1 = new_opt6(OPTION6_STATUS_CODE);
>  		    put_opt6_short(DHCP6NOTONLINK);
>  		    put_opt6_string(_("confirm failed"));
>  		    end_opt6(o1);
> +		    log6_quiet(state, "DHCPCONFIRM", req_addr, "(confirm failed)");
>  		    return 1;
>  		  }
>  
> @@ -1715,11 +1756,15 @@ static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr
>        context->flags |= CONTEXT_CONF_USED;
>  }
>  
> -/* make sure address not leased to another CLID/IAID */
> -static int check_address(struct state *state, struct in6_addr *addr)
> +/* check that ipv6 address belongs to config with same mac address as in state or ipv6 address is not leased to another CLID/IAID */
> +static int check_address(struct state *state, struct dhcp_config *config, struct in6_addr *addr)
>  { 
>    struct dhcp_lease *lease;
>  
> +  if (state->mac_len && config &&
> +      config_has_mac(config, state->mac, state->mac_len, state->mac_type))
> +    return 1;
> +
>    if (!(lease = lease6_find_by_addr(addr, 128, 0)))
>      return 1;
>  
> 




More information about the Dnsmasq-discuss mailing list