Statefull IPv6 addresses are assigned to DHCPv6 clients from a
local prefix based on criteria which need to be fulfilled.
One of those criteria requires the IPv6 address still having
preferred lifetime which was not checked when constructing
the contents of the statefile.
Another criteria requires the prefix length not being smaller
than or equal to 64 when ra_management equals 0 or 1 which was
neither correctly checked when constructing the statefile.
This can lead to invalid hostname/IPv6 entries in the statefile
and thus possible connectivity issues when using DNS resolving.
Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
+static inline bool valid_addr(const struct odhcpd_ipaddr *addr, time_t now)
+{
+ return (addr->prefix <= 96 && addr->preferred > (uint32_t)now);
+}
+
+static size_t elect_addr(const struct odhcpd_ipaddr *addrs, const size_t addrlen)
+{
+ size_t i, m;
+
+ for (i = 0, m = 0; i < addrlen; ++i) {
+ if (addrs[i].preferred > addrs[m].preferred ||
+ (addrs[i].preferred == addrs[m].preferred &&
+ memcmp(&addrs[i].addr, &addrs[m].addr, 16) > 0))
+ m = i;
+ }
+
+ return m;
+}
+
static int send_reconf(struct interface *iface, struct dhcpv6_assignment *assign)
{
struct {
static int send_reconf(struct interface *iface, struct dhcpv6_assignment *assign)
{
struct {
struct in6_addr addr;
struct odhcpd_ipaddr *addrs = (c->managed) ? c->managed : iface->ia_addr;
size_t addrlen = (c->managed) ? (size_t)c->managed_size : iface->ia_addr_len;
struct in6_addr addr;
struct odhcpd_ipaddr *addrs = (c->managed) ? c->managed : iface->ia_addr;
size_t addrlen = (c->managed) ? (size_t)c->managed_size : iface->ia_addr_len;
- size_t m = 0;
-
- for (size_t i = 0; i < addrlen; ++i)
- if (addrs[i].preferred > addrs[m].preferred ||
- (addrs[i].preferred == addrs[m].preferred &&
- memcmp(&addrs[i].addr, &addrs[m].addr, 16) > 0))
- m = i;
+ size_t m = elect_addr(addrs, addrlen);
for (size_t i = 0; i < addrlen; ++i) {
for (size_t i = 0; i < addrlen; ++i) {
- if (addrs[i].prefix > 96 || (!INFINITE_VALID(c->valid_until) && c->valid_until <= now) ||
+ if (!valid_addr(&addrs[i], now) || (!INFINITE_VALID(c->valid_until) && c->valid_until <= now) ||
(iface->managed < RELAYD_MANAGED_NO_AFLAG && i != m &&
(iface->managed < RELAYD_MANAGED_NO_AFLAG && i != m &&
- addrs[i].prefix == 64))
+ addrs[i].prefix <= 64))
continue;
addr = addrs[i].addr;
continue;
addr = addrs[i].addr;
struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->ia_addr;
size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->ia_addr_len;
struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->ia_addr;
size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->ia_addr_len;
- size_t m = 0;
-
- for (size_t i = 0; i < addrlen; ++i)
- if (addrs[i].preferred > addrs[m].preferred ||
- (addrs[i].preferred == addrs[m].preferred &&
- memcmp(&addrs[i].addr, &addrs[m].addr, 16) > 0))
- m = i;
+ size_t m = elect_addr(addrs, addrlen);
for (size_t i = 0; i < addrlen; ++i) {
uint32_t prefix_pref = addrs[i].preferred;
uint32_t prefix_valid = addrs[i].valid;
for (size_t i = 0; i < addrlen; ++i) {
uint32_t prefix_pref = addrs[i].preferred;
uint32_t prefix_valid = addrs[i].valid;
- if (addrs[i].prefix > 96 ||
- addrs[i].preferred <= (uint32_t)now)
+ if (!valid_addr(&addrs[i], now))
continue;
if (prefix_pref != UINT32_MAX)
continue;
if (prefix_pref != UINT32_MAX)
size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->ia_addr_len;
for (size_t i = 0; i < addrlen; ++i) {
size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->ia_addr_len;
for (size_t i = 0; i < addrlen; ++i) {
- if (addrs[i].prefix > 96 ||
- addrs[i].preferred <= (uint32_t)now)
+ if (!valid_addr(&addrs[i], now))
continue;
struct in6_addr addr = addrs[i].addr;
continue;
struct in6_addr addr = addrs[i].addr;
char addrbuf[INET6_ADDRSTRLEN];
for (size_t i = 0; i < addrlen; ++i) {
char addrbuf[INET6_ADDRSTRLEN];
for (size_t i = 0; i < addrlen; ++i) {
- if (addrs[i].prefix > 96 || addrs[i].preferred <= (uint32_t)now)
+ if (!valid_addr(&addrs[i], now))
continue;
struct in6_addr addr = addrs[i].addr;
continue;
struct in6_addr addr = addrs[i].addr;