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;
}
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;
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};
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)
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]);
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];
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;