diff options
Diffstat (limited to 'src/libsystemd-network')
-rw-r--r-- | src/libsystemd-network/network-internal.c | 94 | ||||
-rw-r--r-- | src/libsystemd-network/network-internal.h | 3 |
2 files changed, 97 insertions, 0 deletions
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index c8aa021ee0..9a1d1fda16 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -14,6 +14,7 @@ #include "log.h" #include "network-internal.h" #include "parse-util.h" +#include "strv.h" size_t serialize_in_addrs(FILE *f, const struct in_addr *addresses, @@ -131,6 +132,99 @@ int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { return size; } +int serialize_dnr(FILE *f, const sd_dns_resolver *dnr, size_t n_dnr, bool *with_leading_space) { + int r; + + bool _space = false; + if (!with_leading_space) + with_leading_space = &_space; + + int n = 0; + _cleanup_strv_free_ char **names = NULL; + r = dns_resolvers_to_dot_strv(dnr, n_dnr, &names); + if (r < 0) + return r; + if (r > 0) + fputstrv(f, names, NULL, with_leading_space); + n += r; + return n; +} + +static int coalesce_dnr(sd_dns_resolver *dnr, size_t n_dnr, int family, const char *auth_name, + union in_addr_union *addr) { + assert(dnr || n_dnr == 0); + assert(auth_name); + assert(addr); + + /* Look through list of DNR for matching resolvers to add our addr to. Since DoT is assumed, no need + * to compare transports/dohpath/etc. */ + FOREACH_ARRAY(res, dnr, n_dnr) { + if (family == res->family && streq(auth_name, res->auth_name)) { + if (!GREEDY_REALLOC(res->addrs, res->n_addrs + 1)) + return -ENOMEM; + res->addrs[res->n_addrs++] = *addr; + return true; + } + } + + return false; +} + +/* Deserialized resolvers are assumed to offer DoT service. */ +int deserialize_dnr(sd_dns_resolver **ret, const char *string) { + int r; + + assert(ret); + assert(string); + + sd_dns_resolver *dnr = NULL; + size_t n = 0; + CLEANUP_ARRAY(dnr, n, dns_resolver_done_many); + int priority = 0; + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&string, &word, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; + + uint16_t port; + int family; + _cleanup_free_ union in_addr_union *addr = new(union in_addr_union, 1); + _cleanup_free_ char *auth_name = NULL; + + r = in_addr_port_ifindex_name_from_string_auto(word, &family, addr, &port, NULL, &auth_name); + if (r < 0) + return r; + + r = coalesce_dnr(dnr, n, family, auth_name, addr); + if (r < 0) + return r; + if (r > 0) + continue; + + if (!GREEDY_REALLOC(dnr, n+1)) + return -ENOMEM; + + priority = n+1; + dnr[n++] = (sd_dns_resolver) { + .priority = priority, /* not serialized, but this will preserve the order */ + .auth_name = TAKE_PTR(auth_name), + .family = family, + .addrs = TAKE_PTR(addr), + .n_addrs = 1, + .transports = SD_DNS_ALPN_DOT, + .port = port, + }; + } + + *ret = TAKE_PTR(dnr); + return n; +} + void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) { assert(f); assert(key); diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index 5aa225e977..6a102e92c4 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -17,6 +17,9 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, bool *with_leading_space); int deserialize_in6_addrs(struct in6_addr **addresses, const char *string); +int serialize_dnr(FILE *f, const sd_dns_resolver *dnr, size_t n_dnr, bool *with_leading_space); +int deserialize_dnr(sd_dns_resolver **ret, const char *string); + /* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */ struct sd_dhcp_route; struct sd_dhcp_lease; |