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.
---

This is my original patch rebased on top of current git master branch.
Previous email with this patch probably dropped into spambox and was not
processed. So please let me know if now this email was correctly received.

---
 src/rfc3315.c | 55 +++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 47 insertions(+), 8 deletions(-)

diff --git a/src/rfc3315.c b/src/rfc3315.c
index b3f0a0a..e588b13 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -48,7 +48,7 @@ static int build_ia(struct state *state, int *t1cntr);
 static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
 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 int config_valid(struct dhcp_config *config, struct dhcp_context 
*context, struct in6_addr *addr, struct state *state, time_t now);
 static struct addrlist *config_implies(struct dhcp_config *config, struct 
dhcp_context *context, struct in6_addr *addr);
 static void add_address(struct state *state, struct dhcp_context *context, 
unsigned int lease_time, void *ia_option, 
@@ -688,8 +688,13 @@ 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_implies(config, c, &req_addr))
+                     continue; /* another static address is configured */
                    
                    /* add address to output packet */
                    add_address(state, c, lease_time, ia_option, &min_time, 
&req_addr, now);
@@ -701,7 +706,10 @@ 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, state, now))
                {
@@ -725,6 +733,11 @@ 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_implies(config, c, &req_addr))
+                     continue; /* skip this lease because another static 
address is configured */
                    add_address(state, c, c->lease_time, NULL, &min_time, 
&req_addr, now);
                    mark_context_used(state, &req_addr);
                    get_context_tag(state, c);
@@ -859,7 +872,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);
@@ -975,6 +988,16 @@ static int dhcp6_no_relay(struct state *state, int 
msg_type, void *inbuff, size_
                  {
                    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_implies(config, this_context, &req_addr))
+                     {
+                       preferred_time = valid_time = 0;
+                       message = _("deprecated");
+                     }
+                   else
+                     {
                    get_context_tag(state, this_context);
                    
                    if (config_implies(config, this_context, &req_addr) && 
have_config(config, CONFIG_TIME))
@@ -1000,6 +1023,7 @@ static int dhcp6_no_relay(struct state *state, int 
msg_type, void *inbuff, size_
                    
                    if (preferred_time == 0)
                      message = _("deprecated");
+                     }
                  }
                else
                  {
@@ -1046,11 +1070,22 @@ 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 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_implies(config, c, &req_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);
@@ -1668,11 +1703,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;
 
@@ -1749,7 +1788,7 @@ static int config_valid(struct dhcp_config *config, 
struct dhcp_context *context
          {
            setaddr6part(addr, addrpart+i);
            
-           if (check_address(state, addr))
+           if (check_address(state, config, addr))
              return 1;
          }
       }
-- 
2.20.1


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

Reply via email to