summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/dhcpv6.c4
-rw-r--r--src/odhcpd.c47
-rw-r--r--src/odhcpd.h3
-rw-r--r--src/router.c4
4 files changed, 52 insertions, 6 deletions
diff --git a/src/dhcpv6.c b/src/dhcpv6.c
index 4cd9e02..ebb0c80 100644
--- a/src/dhcpv6.c
+++ b/src/dhcpv6.c
@@ -232,7 +232,7 @@ static void handle_client_request(void *addr, void *data, size_t len,
size_t dns_cnt = iface->dns_cnt;
if ((dns_cnt == 0) &&
- !odhcpd_get_linklocal_interface_address(iface->ifindex, &dns_addr)) {
+ !odhcpd_get_interface_dns_addr(iface, &dns_addr)) {
dns_addr_ptr = &dns_addr;
dns_cnt = 1;
}
@@ -464,7 +464,7 @@ static void relay_server_response(uint8_t *data, size_t len)
size_t rewrite_cnt = iface->dns_cnt;
if (rewrite_cnt == 0) {
- if (odhcpd_get_linklocal_interface_address(iface->ifindex, &addr))
+ if (odhcpd_get_interface_dns_addr(iface, &addr))
return; // Unable to get interface address
rewrite = &addr;
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)
diff --git a/src/odhcpd.h b/src/odhcpd.h
index 9733090..4ddadbe 100644
--- a/src/odhcpd.h
+++ b/src/odhcpd.h
@@ -203,7 +203,8 @@ ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest,
const struct interface *iface);
ssize_t odhcpd_get_interface_addresses(int ifindex,
struct odhcpd_ipaddr *addrs, size_t cnt);
-int odhcpd_get_linklocal_interface_address(int ifindex, struct in6_addr *lladdr);
+int odhcpd_get_interface_dns_addr(const struct interface *iface,
+ struct in6_addr *addr);
struct interface* odhcpd_get_interface_by_name(const char *name);
int odhcpd_get_interface_config(const char *ifname, const char *what);
int odhcpd_get_mac(const struct interface *iface, uint8_t mac[6]);
diff --git a/src/router.c b/src/router.c
index 6e5111a..feae5c7 100644
--- a/src/router.c
+++ b/src/router.c
@@ -319,7 +319,7 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
struct in6_addr dns_pref, *dns_addr = &dns_pref;
size_t dns_cnt = 1;
- odhcpd_get_linklocal_interface_address(iface->ifindex, &dns_pref);
+ odhcpd_get_interface_dns_addr(iface, &dns_pref);
for (ssize_t i = 0; i < ipcnt; ++i) {
struct odhcpd_ipaddr *addr = &addrs[i];
@@ -617,7 +617,7 @@ static void forward_router_advertisement(uint8_t *data, size_t len)
size_t rewrite_cnt = iface->dns_cnt;
if (rewrite_cnt == 0) {
- if (odhcpd_get_linklocal_interface_address(iface->ifindex, &addr))
+ if (odhcpd_get_interface_dns_addr(iface, &addr))
continue; // Unable to comply
rewrite = &addr;