From 37c9ccebd1261b5d44b30bad035f1cf8a4d3f540 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Wed, 9 Jan 2013 19:51:04 +0000 Subject: [PATCH] DHCPv6 address allocation - same DUID, two IAIDs --- src/dhcp6.c | 38 +++++++++++++++++++++++--------------- src/dnsmasq.h | 3 +++ src/rfc3315.c | 40 +++++++++++++++++++++++----------------- 3 files changed, 49 insertions(+), 32 deletions(-) diff --git a/src/dhcp6.c b/src/dhcp6.c index dd88058..9922c85 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -328,6 +328,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl return 0; } +/* can dynamically allocate addr */ struct dhcp_context *address6_available(struct dhcp_context *context, struct in6_addr *taddr, struct dhcp_netid *netids) @@ -352,6 +353,22 @@ struct dhcp_context *address6_available(struct dhcp_context *context, return NULL; } +/* address OK if configured */ +struct dhcp_context *address6_valid(struct dhcp_context *context, + struct in6_addr *taddr, + struct dhcp_netid *netids) +{ + struct dhcp_context *tmp; + + for (tmp = context; tmp; tmp = tmp->current) + if ((tmp->flags & CONTEXT_STATIC) && + is_same_net6(&tmp->start6, taddr, tmp->prefix) && + match_netid(tmp->filter, netids, 1)) + return tmp; + + return NULL; +} + struct dhcp_context *narrow_context6(struct dhcp_context *context, struct in6_addr *taddr, struct dhcp_netid *netids) @@ -366,21 +383,12 @@ struct dhcp_context *narrow_context6(struct dhcp_context *context, struct dhcp_context *tmp; - if (!(tmp = address6_available(context, taddr, netids))) - { - for (tmp = context; tmp; tmp = tmp->current) - if (match_netid(tmp->filter, netids, 1) && - is_same_net6(taddr, &tmp->start6, tmp->prefix) && - (tmp->flags & CONTEXT_STATIC)) - break; - - if (!tmp) - for (tmp = context; tmp; tmp = tmp->current) - if (match_netid(tmp->filter, netids, 1) && - is_same_net6(taddr, &tmp->start6, tmp->prefix) && - !(tmp->flags & CONTEXT_PROXY)) - break; - } + if (!(tmp = address6_available(context, taddr, netids)) && + !(tmp = address6_valid(context, taddr, netids))) + for (tmp = context; tmp; tmp = tmp->current) + if (match_netid(tmp->filter, netids, 1) && + is_same_net6(taddr, &tmp->start6, tmp->prefix)) + break; /* Only one context allowed now */ if (tmp) diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 5eadaa1..d3a34ea 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1149,6 +1149,9 @@ int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr); struct dhcp_context *address6_available(struct dhcp_context *context, struct in6_addr *taddr, struct dhcp_netid *netids); +struct dhcp_context *address6_valid(struct dhcp_context *context, + struct in6_addr *taddr, + struct dhcp_netid *netids); struct dhcp_context *narrow_context6(struct dhcp_context *context, struct in6_addr *taddr, struct dhcp_netid *netids); diff --git a/src/rfc3315.c b/src/rfc3315.c index 560fdc1..f24a3c6 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -525,32 +525,38 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh { struct in6_addr *req_addr = opt6_ptr(ia_option, 0); requested_time = opt6_uint(ia_option, 16, 4); - - if (!address6_available(context, req_addr, tags) && - (!have_config(config, CONFIG_ADDR6) || memcmp(&config->addr6, req_addr, IN6ADDRSZ) != 0)) + struct dhcp_context *dynamic; + + if ((dynamic = address6_available(context, req_addr, tags)) || address6_valid(context, req_addr, tags)) { - if (msg_type == DHCP6REQUEST) + if (!dynamic && !(have_config(config, CONFIG_ADDR6) && memcmp(&config->addr6, req_addr, IN6ADDRSZ) == 0)) { - /* host has a lease, but it's not on the correct link */ + /* Static range, not configured. */ o1 = new_opt6(OPTION6_STATUS_CODE); - put_opt6_short(DHCP6NOTONLINK); - put_opt6_string("Not on link"); + put_opt6_short(DHCP6UNSPEC); + put_opt6_string("Address unavailable"); end_opt6(o1); } + else if (lease6_find_by_addr(req_addr, 128, 0) && + !(lease = lease6_find(clid, clid_len, ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, iaid, req_addr))) + { + /* Address leased to another DUID/IAID */ + o1 = new_opt6(OPTION6_STATUS_CODE); + put_opt6_short(DHCP6UNSPEC); + put_opt6_string("Address in use"); + end_opt6(o1); + } + else + addrp = req_addr; } - else if ((lease = lease6_find(NULL, 0, ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, - iaid, req_addr)) && - (clid_len != lease->clid_len || - memcmp(clid, lease->clid, clid_len) != 0)) + else if (msg_type == DHCP6REQUEST) { - /* Address leased to another DUID */ + /* requested address not on the correct link */ o1 = new_opt6(OPTION6_STATUS_CODE); - put_opt6_short(DHCP6UNSPEC); - put_opt6_string("Address in use"); + put_opt6_short(DHCP6NOTONLINK); + put_opt6_string("Not on link"); end_opt6(o1); - } - else - addrp = req_addr; + } } else {