[Dnsmasq-discuss] [PATCH] DHCPv6: Honor assigning IPv6 address based on MAC address

Pali Rohár pali.rohar at gmail.com
Tue Apr 21 15:16:43 BST 2020


Hello!

I have not got any reply about this patch for years.

So I would like to know, is some spam filter eating my emails and
therefore patch was not delivered?

Can somebody confirm if Simon got my patch or should I probably resent
it from different email address, to prevent spam filter problems?

On Friday 07 February 2020 23:08:32 Pali Rohár wrote:
> Hello Simon!
> 
> Could you please review / comment this patch?
> 
> I would like to know what is needed to be fixed or changed, so patch
> could be finally merged.
> 
> On Monday 17 December 2018 18:41:09 Pali Rohár wrote:
> > Currently IPv6 addresses are assigned to tuple (IAID, DUID). When system
> > changes IAID/DUID then old assigned IPv6 address cannot be reused, even
> > when in config file was DHCPv6 assignment based on MAC address (and not on
> > DUID).
> > 
> > IAID/DUID is changed when rebooting from one operating system to another;
> > or after reinstalling system. In reality it is normal that DUID of some
> > machine is changed, so people rather assign also IPv6 addresses based on
> > MAC address.
> > 
> > So assigning IPv6 based on MAC address in dnsmasq is currently semi-broken.
> > 
> > This patch tries to fix it and honors IPv6 config rules with MAC address,
> > to always assign particular IPv6 address to specific MAC address (when
> > configured). And ignores the fact if IAID/DUID was changed.
> > 
> > Normally IPv6 address should be assigned by IAID/DUID (which also state
> > DHCPv6 RFCs), but dnsmasq has already some support for assigning IPv6
> > address based on MAC address, when users configured in config file.
> > 
> > So this patch just tries to fix above problem for user configuration with
> > MAC addresses. It does not change assignment based on DUID.
> > 
> > Also this patch adds support for allowing IPv6 address to be associated
> > with multiple hardware addresses, and gives dnsmasq permission to abandon a
> > lease. This is similar functionality as already supported for IPv4 address.
> > ---
> >  man/dnsmasq.8 |  9 ++++++---
> >  src/rfc3315.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
> >  2 files changed, 59 insertions(+), 12 deletions(-)
> > 
> > diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
> > index f01a5ba..8614f08 100644
> > --- a/man/dnsmasq.8
> > +++ b/man/dnsmasq.8
> > @@ -1068,10 +1068,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 a20776d..c83cf2d 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);
> > @@ -746,7 +746,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);
> > @@ -755,8 +755,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
> > @@ -772,10 +778,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))
> > @@ -800,6 +809,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);
> > @@ -943,7 +958,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);
> > @@ -1064,6 +1079,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))
> > @@ -1089,6 +1115,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
> >  		    
> >  		    if (preferred_time == 0)
> >  		      message = _("deprecated");
> > +		      }
> >  		  }
> >  		else
> >  		  {
> > @@ -1135,11 +1162,24 @@ 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;
> > +		struct in6_addr addr;
> > +		struct dhcp_context *c;
> > +		int config_addr_ok = 1;
> >  
> >  		/* alignment */
> >  		memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
> > +
> > +		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);
> > @@ -1772,11 +1812,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;
> >  
> 
> -- 
> Pali Rohár
> pali.rohar at gmail.com

-- 
Pali Rohár
pali.rohar at gmail.com



More information about the Dnsmasq-discuss mailing list