diff options
author | Lennart Poettering <lennart@poettering.net> | 2024-10-22 09:05:36 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-22 09:05:36 +0200 |
commit | 2d74427a7cfa2f4feb9e5aabf7a1a00b1718801b (patch) | |
tree | 0c3e5b8334a4e4301bf569cc26833890451f106f /src/libsystemd-network/sd-dhcp6-lease.c | |
parent | test: CET/EET are deprecated, use Europe/Berlin and Kyiv (diff) | |
parent | resolve: move sd-* api into libsystemd-network (diff) | |
download | systemd-2d74427a7cfa2f4feb9e5aabf7a1a00b1718801b.tar.xz systemd-2d74427a7cfa2f4feb9e5aabf7a1a00b1718801b.zip |
Merge pull request #30952 from rpigott/resolved-dnr
RFC9463: Discovery of Network-designated Resolvers
Diffstat (limited to 'src/libsystemd-network/sd-dhcp6-lease.c')
-rw-r--r-- | src/libsystemd-network/sd-dhcp6-lease.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index 261ab83c64..647dea88bd 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -9,6 +9,7 @@ #include "dhcp6-internal.h" #include "dhcp6-lease-internal.h" #include "network-common.h" +#include "sort-util.h" #include "strv.h" #include "unaligned.h" @@ -464,6 +465,98 @@ int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***ret) { return strv_length(lease->domains); } +static int dhcp6_lease_add_dnr(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) { + int r; + + assert(lease); + + _cleanup_(sd_dns_resolver_done) sd_dns_resolver res = {}; + + size_t offset = 0; + + /* priority */ + if (optlen - offset < sizeof(uint16_t)) + return -EBADMSG; + res.priority = unaligned_read_be16(optval + offset); + offset += sizeof(uint16_t); + + /* adn */ + if (optlen - offset < sizeof(uint16_t)) + return -EBADMSG; + size_t ilen = unaligned_read_be16(optval + offset); + offset += sizeof(uint16_t); + if (offset + ilen > optlen) + return -EBADMSG; + + r = dhcp6_option_parse_domainname(optval + offset, ilen, &res.auth_name); + if (r < 0) + return r; + offset += ilen; + + /* RFC9463 § 3.1.6: adn only mode */ + if (offset == optlen) + return 0; + + /* addrs */ + if (optlen - offset < sizeof(uint16_t)) + return -EBADMSG; + ilen = unaligned_read_be16(optval + offset); + offset += sizeof(uint16_t); + if (offset + ilen > optlen) + return -EBADMSG; + + _cleanup_free_ struct in6_addr *addrs = NULL; + size_t n_addrs = 0; + + r = dhcp6_option_parse_addresses(optval + offset, ilen, &addrs, &n_addrs); + if (r < 0) + return r; + if (n_addrs == 0) + return -EBADMSG; + offset += ilen; + + res.addrs = new(union in_addr_union, n_addrs); + if (!res.addrs) + return -ENOMEM; + + for (size_t i = 0; i < n_addrs; i++) { + union in_addr_union addr = {.in6 = addrs[i]}; + /* RFC9463 § 6.2 client MUST discard multicast and host loopback addresses */ + if (in_addr_is_multicast(AF_INET6, &addr) || + in_addr_is_localhost(AF_INET6, &addr)) + return -EBADMSG; + res.addrs[i] = addr; + } + res.n_addrs = n_addrs; + res.family = AF_INET6; + + /* svc params */ + r = dnr_parse_svc_params(optval + offset, optlen-offset, &res); + if (r < 0) + return r; + + /* Append this resolver */ + if (!GREEDY_REALLOC(lease->dnr, lease->n_dnr+1)) + return -ENOMEM; + + lease->dnr[lease->n_dnr++] = TAKE_STRUCT(res); + + typesafe_qsort(lease->dnr, lease->n_dnr, dns_resolver_prio_compare); + + return 1; +} + +int sd_dhcp6_lease_get_dnr(sd_dhcp6_lease *lease, sd_dns_resolver **ret) { + assert_return(lease, -EINVAL); + assert_return(ret, -EINVAL); + + if (!lease->dnr) + return -ENODATA; + + *ret = lease->dnr; + return lease->n_dnr; +} + int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) { int r; @@ -870,6 +963,15 @@ static int dhcp6_lease_parse_message( irt = unaligned_be32_sec_to_usec(optval, /* max_as_infinity = */ false); break; + case SD_DHCP6_OPTION_V6_DNR: + r = dhcp6_lease_add_dnr(lease, optval, optlen); + if (r < 0) + return log_dhcp6_client_errno(client, r, "Failed to parse DNR option, ignoring: %m"); + if (r == 0) + log_dhcp6_client(client, "Received ADN-only DNRv6 option, ignoring."); + + break; + case SD_DHCP6_OPTION_VENDOR_OPTS: r = dhcp6_lease_add_vendor_option(lease, optval, optlen); if (r < 0) @@ -920,6 +1022,7 @@ static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) { dhcp6_ia_free(lease->ia_na); dhcp6_ia_free(lease->ia_pd); free(lease->dns); + dns_resolver_done_many(lease->dnr, lease->n_dnr); free(lease->fqdn); free(lease->captive_portal); strv_free(lease->domains); |