summaryrefslogtreecommitdiffhomepage
path: root/src/odhcpd.c
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2017-03-29 17:03:29 +0200
committerHans Dedecker <dedeckeh@gmail.com>2017-03-30 14:48:02 +0200
commit3d9f4067d56660a2c75ab2ce9b801ae1a4ff4cde (patch)
treed3a1a5e9dedd1d4d32dc375e2bb37dfbd21016d3 /src/odhcpd.c
parentbc6c3ace738fd4eb28c06be533f6bbc75d0587a5 (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.c47
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)