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.ro...@gmail.com

_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss

Reply via email to