diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c --- a/usr.sbin/rtadvd/config.c +++ b/usr.sbin/rtadvd/config.c @@ -331,6 +331,39 @@ return (0); } +void expand_linklocal_rdnss_address(struct ifinfo *ifi) +{ + int success = 0; + struct ifaddrs *ifaddr, *ifa; + if (getifaddrs(&ifaddr) == -1) { + perror("getifaddrs"); + return; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + struct sockaddr_in6 *current_addr = + (struct sockaddr_in6 *) ifa->ifa_addr; + + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + if (strcmp(ifa->ifa_name, ifi->ifi_ifname)) + continue; + if (!IN6_IS_ADDR_LINKLOCAL(&(current_addr->sin6_addr))) + continue; + + if (inet_ntop(AF_INET6, &(current_addr->sin6_addr), abuf, INET6_ADDRSTRLEN)) { + syslog(LOG_INFO, "<%s> using link-local address %s for rdnss on %s", + __func__, abuf, ifi->ifi_ifname); + success = 1; + break; + } + } + freeifaddrs(ifaddr); + if (!success) + syslog(LOG_WARNING, "<%s> found LINKLOCAL keyword, no suitable address found for %s", + __func__, ifi->ifi_ifname); +} + struct ifinfo * getconfig(struct ifinfo *ifi) { @@ -826,6 +859,11 @@ c = strcspn(ap, ","); strncpy(abuf, ap, c); abuf[c] = '\0'; + + if (strcmp(abuf, "LINKLOCAL") == 0) { + expand_linklocal_rdnss_address(ifi); + } + ELM_MALLOC(rdna, goto getconfig_free_rdn); if (inet_pton(AF_INET6, abuf, &rdna->ra_dns) != 1) { syslog(LOG_ERR, "<%s> inet_pton failed for %s",