diff options
author | Hans Dedecker <dedeckeh@gmail.com> | 2017-03-29 17:03:29 +0200 |
---|---|---|
committer | Hans Dedecker <dedeckeh@gmail.com> | 2017-03-30 14:48:02 +0200 |
commit | 3d9f4067d56660a2c75ab2ce9b801ae1a4ff4cde (patch) | |
tree | d3a1a5e9dedd1d4d32dc375e2bb37dfbd21016d3 /src/odhcpd.c | |
parent | bc6c3ace738fd4eb28c06be533f6bbc75d0587a5 (diff) |
rework IPv6 dns address selection (FS#635)
Don't return anymore the link local IPv6 address as DNS IPv6 address
since different OS implementations (e.g. android, ...) cannot handle
a link local IPv6 address as DNS address.
IPv6 DNS address selection is reworked as follows :
-Consider all global/ULA IPv6 address having a valid lifetime
-Give preference to global/ULA IPv6 addresses being not deprecated
-Give preference to ULA IPv6 addresses over IPv6 global addresses
-Give preference to the IPv6 address with the longest preferred lifetime in
its selected category (ULA or global)
-If no global/ULA IPv6 address is present use the IPv6 link local address
Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
Diffstat (limited to 'src/odhcpd.c')
-rw-r--r-- | src/odhcpd.c | 47 |
1 files changed, 46 insertions, 1 deletions
diff --git a/src/odhcpd.c b/src/odhcpd.c index 8a18fbf..8a1c66e 100644 --- a/src/odhcpd.c +++ b/src/odhcpd.c @@ -336,7 +336,7 @@ out: return ctxt.ret; } -int odhcpd_get_linklocal_interface_address(int ifindex, struct in6_addr *lladdr) +static int odhcpd_get_linklocal_interface_address(int ifindex, struct in6_addr *lladdr) { int status = -1; struct sockaddr_in6 addr = {AF_INET6, 0, 0, ALL_IPV6_ROUTERS, ifindex}; @@ -354,6 +354,51 @@ int odhcpd_get_linklocal_interface_address(int ifindex, struct in6_addr *lladdr) return status; } +/* + * DNS address selection criteria order : + * - use IPv6 address with valid lifetime if none is yet selected + * - use IPv6 address with a preferred lifetime if the already selected IPv6 address is deprecated + * - use an IPv6 ULA address if the already selected IPv6 address is not an ULA address + * - use the IPv6 address with the longest preferred lifetime + */ +int odhcpd_get_interface_dns_addr(const struct interface *iface, struct in6_addr *addr) +{ + time_t now = odhcpd_time(); + ssize_t m = -1; + + for (size_t i = 0; i < iface->ia_addr_len; ++i) { + if (iface->ia_addr[i].valid <= (uint32_t)now) + continue; + + if (m < 0) { + m = i; + continue; + } + + if (iface->ia_addr[m].preferred >= (uint32_t)now && + iface->ia_addr[i].preferred < (uint32_t)now) + continue; + + if (IN6_IS_ADDR_ULA(&iface->ia_addr[i].addr)) { + if (!IN6_IS_ADDR_ULA(&iface->ia_addr[m].addr)) { + m = i; + continue; + } + } else if (IN6_IS_ADDR_ULA(&iface->ia_addr[m].addr)) + continue; + + if (iface->ia_addr[i].preferred > iface->ia_addr[m].preferred) + m = i; + } + + if (m >= 0) { + *addr = iface->ia_addr[m].addr; + return 0; + } + + return odhcpd_get_linklocal_interface_address(iface->ifindex, addr); +} + int odhcpd_setup_route(const struct in6_addr *addr, const int prefixlen, const struct interface *iface, const struct in6_addr *gw, const uint32_t metric, const bool add) |