summaryrefslogtreecommitdiffstats
path: root/src/libsystemd-network
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-network')
-rw-r--r--src/libsystemd-network/network-internal.c94
-rw-r--r--src/libsystemd-network/network-internal.h3
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;