diff --git a/src/libsystemd-network/radv-internal.h b/src/libsystemd-network/radv-internal.h index c3f847ec05..5601be844d 100644 --- a/src/libsystemd-network/radv-internal.h +++ b/src/libsystemd-network/radv-internal.h @@ -36,6 +36,7 @@ assert_cc(SD_RADV_DEFAULT_MIN_TIMEOUT_USEC <= SD_RADV_DEFAULT_MAX_TIMEOUT_USEC) #define SD_RADV_MAX_RA_DELAY_TIME_USEC (500*USEC_PER_MSEC) #define SD_RADV_OPT_RDNSS 25 +#define SD_RADV_OPT_DNSSL 31 enum RAdvState { SD_RADV_STATE_IDLE = 0, @@ -75,6 +76,7 @@ struct sd_radv { size_t n_rdnss; struct sd_radv_opt_dns *rdnss; + struct sd_radv_opt_dns *dnssl; }; struct sd_radv_prefix { diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c index 70772b4f15..f05c44032d 100644 --- a/src/libsystemd-network/sd-radv.c +++ b/src/libsystemd-network/sd-radv.c @@ -26,12 +26,14 @@ #include "macro.h" #include "alloc-util.h" +#include "dns-domain.h" #include "fd-util.h" #include "icmp6-util.h" #include "in-addr-util.h" #include "radv-internal.h" #include "socket-util.h" #include "string-util.h" +#include "strv.h" #include "util.h" #include "random-util.h" @@ -204,6 +206,12 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst, msg.msg_iovlen++; } + if (ra->dnssl) { + iov[msg.msg_iovlen].iov_base = ra->dnssl; + iov[msg.msg_iovlen].iov_len = ra->dnssl->length * 8; + msg.msg_iovlen++; + } + if (sendmsg(ra->fd, &msg, 0) < 0) return -errno; @@ -590,6 +598,58 @@ _public_ int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime, return 0; } +_public_ int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime, + char **search_list) { + _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL; + size_t len = 0; + char **s; + uint8_t *p; + + assert_return(ra, -EINVAL); + + if (!search_list || *search_list == NULL) { + ra->dnssl = mfree(ra->dnssl); + + return 0; + } + + STRV_FOREACH(s, search_list) + len += strlen(*s) + 2; + + len = (sizeof(struct sd_radv_opt_dns) + len + 7) & ~0x7; + + opt_dnssl = malloc0(len); + if (!opt_dnssl) + return -ENOMEM; + + opt_dnssl->type = SD_RADV_OPT_DNSSL; + opt_dnssl->length = len / 8; + opt_dnssl->lifetime = htobe32(lifetime); + + p = (uint8_t *)(opt_dnssl + 1); + len -= sizeof(struct sd_radv_opt_dns); + + STRV_FOREACH(s, search_list) { + int r; + + r = dns_name_to_wire_format(*s, p, len, false); + if (r < 0) + return r; + + if (len < (size_t)r) + return -ENOBUFS; + + p += r; + len -= r; + } + + free(ra->dnssl); + ra->dnssl = opt_dnssl; + opt_dnssl = NULL; + + return 0; +} + _public_ int sd_radv_prefix_new(sd_radv_prefix **ret) { _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL; diff --git a/src/systemd/sd-radv.h b/src/systemd/sd-radv.h index ce10ae0606..0cc1d670b9 100644 --- a/src/systemd/sd-radv.h +++ b/src/systemd/sd-radv.h @@ -59,6 +59,7 @@ int sd_radv_set_preference(sd_radv *ra, unsigned preference); int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p); int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime, const struct in6_addr *dns, size_t n_dns); +int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime, char **search_list); /* Advertised prefixes */ int sd_radv_prefix_new(sd_radv_prefix **ret);