]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
wireguard: use NetworkConfigSection to manage [WireGuardPeer] sections
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 28 Feb 2019 08:12:02 +0000 (17:12 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 13 Mar 2019 02:59:18 +0000 (11:59 +0900)
This also contains huge refactoring of wireguard support.

src/network/netdev/wireguard.c
src/network/netdev/wireguard.h

index 7d35afae6d74c7d9c0ebcdaba683c9c85488a4e5..3560c25eecd9fd70ddade51b8eb03f5ebce01554 100644 (file)
 
 static void resolve_endpoints(NetDev *netdev);
 
-static WireguardPeer *wireguard_peer_new(Wireguard *w, unsigned section) {
-        WireguardPeer *peer;
+static void wireguard_peer_free(WireguardPeer *peer) {
+        WireguardIPmask *mask;
+
+        if (!peer)
+                return;
+
+        if (peer->wireguard) {
+                LIST_REMOVE(peers, peer->wireguard->peers, peer);
+
+                set_remove(peer->wireguard->peers_with_unresolved_endpoint, peer);
+                set_remove(peer->wireguard->peers_with_failed_endpoint, peer);
+
+                if (peer->section)
+                        hashmap_remove(peer->wireguard->peers_by_section, peer->section);
+        }
+
+        network_config_section_free(peer->section);
+
+        while ((mask = peer->ipmasks)) {
+                LIST_REMOVE(ipmasks, peer->ipmasks, mask);
+                free(mask);
+        }
+
+        free(peer->endpoint_host);
+        free(peer->endpoint_port);
+
+        free(peer);
+}
+
+DEFINE_NETWORK_SECTION_FUNCTIONS(WireguardPeer, wireguard_peer_free);
+
+static int wireguard_peer_new_static(Wireguard *w, const char *filename, unsigned section_line, WireguardPeer **ret) {
+        _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+        _cleanup_(wireguard_peer_freep) WireguardPeer *peer = NULL;
+        int r;
 
         assert(w);
+        assert(ret);
+        assert(filename);
+        assert(section_line > 0);
 
-        if (w->last_peer_section == section && w->peers)
-                return w->peers;
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
+
+        peer = hashmap_get(w->peers_by_section, n);
+        if (peer) {
+                *ret = TAKE_PTR(peer);
+                return 0;
+        }
 
         peer = new(WireguardPeer, 1);
         if (!peer)
-                return NULL;
+                return -ENOMEM;
 
         *peer = (WireguardPeer) {
                 .flags = WGPEER_F_REPLACE_ALLOWEDIPS,
+                .wireguard = w,
+                .section = TAKE_PTR(n),
         };
 
         LIST_PREPEND(peers, w->peers, peer);
-        w->last_peer_section = section;
 
-        return peer;
+        r = hashmap_ensure_allocated(&w->peers_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
+
+        r = hashmap_put(w->peers_by_section, peer->section, peer);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(peer);
+        return 0;
 }
 
 static int wireguard_set_ipmask_one(NetDev *netdev, sd_netlink_message *message, const WireguardIPmask *mask, uint16_t index) {
@@ -226,23 +279,19 @@ static int wireguard_set_interface(NetDev *netdev) {
         return 0;
 }
 
-static WireguardEndpoint* wireguard_endpoint_free(WireguardEndpoint *e) {
-        if (!e)
-                return NULL;
-        e->host = mfree(e->host);
-        e->port = mfree(e->port);
-        return mfree(e);
-}
+static void wireguard_peer_destroy_callback(WireguardPeer *peer) {
+        NetDev *netdev;
 
-static void wireguard_endpoint_destroy_callback(WireguardEndpoint *e) {
-        assert(e);
-        assert(e->netdev);
+        assert(peer);
+        assert(peer->wireguard);
 
-        netdev_unref(e->netdev);
-        wireguard_endpoint_free(e);
-}
+        netdev = NETDEV(peer->wireguard);
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(WireguardEndpoint*, wireguard_endpoint_free);
+        if (section_is_invalid(peer->section))
+                wireguard_peer_free(peer);
+
+        netdev_unref(netdev);
+}
 
 static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
         NetDev *netdev = userdata;
@@ -255,8 +304,9 @@ static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
         if (!netdev_is_managed(netdev))
                 return 0;
 
-        assert(!w->unresolved_endpoints);
-        w->unresolved_endpoints = TAKE_PTR(w->failed_endpoints);
+        assert(set_isempty(w->peers_with_unresolved_endpoint));
+
+        SWAP_TWO(w->peers_with_unresolved_endpoint, w->peers_with_failed_endpoint);
 
         resolve_endpoints(netdev);
 
@@ -274,40 +324,53 @@ static int exponential_backoff_milliseconds(unsigned n_retries) {
 static int wireguard_resolve_handler(sd_resolve_query *q,
                                      int ret,
                                      const struct addrinfo *ai,
-                                     WireguardEndpoint *e) {
-        _cleanup_(netdev_unrefp) NetDev *netdev_will_unrefed = NULL;
+                                     WireguardPeer *peer) {
         NetDev *netdev;
         Wireguard *w;
         int r;
 
-        assert(e);
-        assert(e->netdev);
+        assert(peer);
+        assert(peer->wireguard);
 
-        netdev = e->netdev;
-        w = WIREGUARD(netdev);
-        assert(w);
+        w = peer->wireguard;
+        netdev = NETDEV(w);
 
         if (!netdev_is_managed(netdev))
                 return 0;
 
         if (ret != 0) {
-                log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", e->host, e->port, gai_strerror(ret));
-                LIST_PREPEND(endpoints, w->failed_endpoints, e);
-                (void) sd_resolve_query_set_destroy_callback(q, NULL); /* Avoid freeing endpoint by destroy callback. */
-                netdev_will_unrefed = netdev; /* But netdev needs to be unrefed. */
+                log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", peer->endpoint_host, peer->endpoint_port, gai_strerror(ret));
+
+                r = set_ensure_allocated(&w->peers_with_failed_endpoint, NULL);
+                if (r < 0) {
+                        log_oom();
+                        peer->section->invalid = true;
+                        goto resolve_next;
+                }
+
+                r = set_put(w->peers_with_failed_endpoint, peer);
+                if (r < 0) {
+                        log_netdev_error(netdev, "Failed to save a peer, dropping the peer: %m");
+                        peer->section->invalid = true;
+                        goto resolve_next;
+                }
+
         } else if ((ai->ai_family == AF_INET && ai->ai_addrlen == sizeof(struct sockaddr_in)) ||
                    (ai->ai_family == AF_INET6 && ai->ai_addrlen == sizeof(struct sockaddr_in6)))
-                memcpy(&e->peer->endpoint, ai->ai_addr, ai->ai_addrlen);
+                memcpy(&peer->endpoint, ai->ai_addr, ai->ai_addrlen);
         else
-                log_netdev_error(netdev, "Neither IPv4 nor IPv6 address found for peer endpoint: %s:%s", e->host, e->port);
+                log_netdev_error(netdev, "Neither IPv4 nor IPv6 address found for peer endpoint %s:%s, ignoring the address.",
+                                 peer->endpoint_host, peer->endpoint_port);
 
-        if (w->unresolved_endpoints) {
+resolve_next:
+        if (!set_isempty(w->peers_with_unresolved_endpoint)) {
                 resolve_endpoints(netdev);
                 return 0;
         }
 
         (void) wireguard_set_interface(netdev);
-        if (w->failed_endpoints) {
+
+        if (!set_isempty(w->peers_with_failed_endpoint)) {
                 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
 
                 w->n_retries++;
@@ -342,24 +405,24 @@ static void resolve_endpoints(NetDev *netdev) {
                 .ai_socktype = SOCK_DGRAM,
                 .ai_protocol = IPPROTO_UDP
         };
-        WireguardEndpoint *endpoint;
+        WireguardPeer *peer;
         Wireguard *w;
+        Iterator i;
         int r = 0;
 
         assert(netdev);
         w = WIREGUARD(netdev);
         assert(w);
 
-        LIST_FOREACH(endpoints, endpoint, w->unresolved_endpoints) {
+        SET_FOREACH(peer, w->peers_with_unresolved_endpoint, i) {
                 r = resolve_getaddrinfo(netdev->manager->resolve,
                                         NULL,
-                                        endpoint->host,
-                                        endpoint->port,
+                                        peer->endpoint_host,
+                                        peer->endpoint_port,
                                         &hints,
                                         wireguard_resolve_handler,
-                                        wireguard_endpoint_destroy_callback,
-                                        endpoint);
-
+                                        wireguard_peer_destroy_callback,
+                                        peer);
                 if (r == -ENOBUFS)
                         break;
                 if (r < 0) {
@@ -370,7 +433,7 @@ static void resolve_endpoints(NetDev *netdev) {
                 /* Avoid freeing netdev. It will be unrefed by the destroy callback. */
                 netdev_ref(netdev);
 
-                LIST_REMOVE(endpoints, w->unresolved_endpoints, endpoint);
+                (void) set_remove(w->peers_with_unresolved_endpoint, peer);
         }
 }
 
@@ -404,9 +467,12 @@ int config_parse_wireguard_listen_port(const char *unit,
         assert(data);
 
         if (!streq(rvalue, "auto")) {
-                r = parse_ip_port(rvalue, &port);
-                if (r < 0)
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Invalid port specification, ignoring assignment: %s", rvalue);
+                r = parse_ip_port(rvalue, s);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Invalid port specification, ignoring assignment: %s", rvalue);
+                        return 0;
+                }
         }
 
         *s = port;
@@ -434,7 +500,8 @@ static int parse_wireguard_key(const char *unit,
 
         r = unbase64mem(rvalue, strlen(rvalue), &key, &len);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse wireguard key \"%s\", ignoring assignment: %m", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Could not parse wireguard key \"%s\", ignoring assignment: %m", rvalue);
                 return 0;
         }
         if (len != WG_KEY_LEN) {
@@ -465,16 +532,8 @@ int config_parse_wireguard_private_key(const char *unit,
 
         assert(w);
 
-        return parse_wireguard_key(unit,
-                                   filename,
-                                   line,
-                                   section,
-                                   section_line,
-                                   lvalue,
-                                   ltype,
-                                   rvalue,
-                                   data,
-                                   &w->private_key);
+        return parse_wireguard_key(unit, filename, line, section, section_line,
+                                   lvalue, ltype, rvalue, data, &w->private_key);
 
 }
 
@@ -488,8 +547,10 @@ int config_parse_wireguard_preshared_key(const char *unit,
                                          const char *rvalue,
                                          void *data,
                                          void *userdata) {
+
+        _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
         Wireguard *w;
-        WireguardPeer *peer;
+        int r;
 
         assert(data);
 
@@ -497,20 +558,17 @@ int config_parse_wireguard_preshared_key(const char *unit,
 
         assert(w);
 
-        peer = wireguard_peer_new(w, section_line);
-        if (!peer)
-                return log_oom();
+        r = wireguard_peer_new_static(w, filename, section_line, &peer);
+        if (r < 0)
+                return r;
 
-        return parse_wireguard_key(unit,
-                                   filename,
-                                   line,
-                                   section,
-                                   section_line,
-                                   lvalue,
-                                   ltype,
-                                   rvalue,
-                                   data,
-                                   peer->preshared_key);
+        r = parse_wireguard_key(unit, filename, line, section, section_line,
+                                lvalue, ltype, rvalue, data, peer->preshared_key);
+        if (r < 0)
+                return r;
+
+        TAKE_PTR(peer);
+        return 0;
 }
 
 int config_parse_wireguard_public_key(const char *unit,
@@ -523,8 +581,10 @@ int config_parse_wireguard_public_key(const char *unit,
                                       const char *rvalue,
                                       void *data,
                                       void *userdata) {
+
+        _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
         Wireguard *w;
-        WireguardPeer *peer;
+        int r;
 
         assert(data);
 
@@ -532,20 +592,17 @@ int config_parse_wireguard_public_key(const char *unit,
 
         assert(w);
 
-        peer = wireguard_peer_new(w, section_line);
-        if (!peer)
-                return log_oom();
+        r = wireguard_peer_new_static(w, filename, section_line, &peer);
+        if (r < 0)
+                return r;
+
+        r = parse_wireguard_key(unit, filename, line, section, section_line,
+                                lvalue, ltype, rvalue, data, peer->public_key);
+        if (r < 0)
+                return r;
 
-        return parse_wireguard_key(unit,
-                                   filename,
-                                   line,
-                                   section,
-                                   section_line,
-                                   lvalue,
-                                   ltype,
-                                   rvalue,
-                                   data,
-                                   peer->public_key);
+        TAKE_PTR(peer);
+        return 0;
 }
 
 int config_parse_wireguard_allowed_ips(const char *unit,
@@ -558,11 +615,12 @@ int config_parse_wireguard_allowed_ips(const char *unit,
                                        const char *rvalue,
                                        void *data,
                                        void *userdata) {
+
+        _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
         union in_addr_union addr;
         unsigned char prefixlen;
         int r, family;
         Wireguard *w;
-        WireguardPeer *peer;
         WireguardIPmask *ipmask;
 
         assert(rvalue);
@@ -570,9 +628,11 @@ int config_parse_wireguard_allowed_ips(const char *unit,
 
         w = WIREGUARD(data);
 
-        peer = wireguard_peer_new(w, section_line);
-        if (!peer)
-                return log_oom();
+        assert(w);
+
+        r = wireguard_peer_new_static(w, filename, section_line, &peer);
+        if (r < 0)
+                return r;
 
         for (;;) {
                 _cleanup_free_ char *word = NULL;
@@ -583,14 +643,16 @@ int config_parse_wireguard_allowed_ips(const char *unit,
                 if (r == -ENOMEM)
                         return log_oom();
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split allowed ips \"%s\" option: %m", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to split allowed ips \"%s\" option: %m", rvalue);
                         break;
                 }
 
                 r = in_addr_prefix_from_string_auto(word, &family, &addr, &prefixlen);
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Network address is invalid, ignoring assignment: %s", word);
-                        return 0;
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Network address is invalid, ignoring assignment: %s", word);
+                        continue;
                 }
 
                 ipmask = new(WireguardIPmask, 1);
@@ -606,6 +668,7 @@ int config_parse_wireguard_allowed_ips(const char *unit,
                 LIST_PREPEND(ipmasks, peer->ipmasks, ipmask);
         }
 
+        TAKE_PTR(peer);
         return 0;
 }
 
@@ -619,12 +682,12 @@ int config_parse_wireguard_endpoint(const char *unit,
                                     const char *rvalue,
                                     void *data,
                                     void *userdata) {
+
+        _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
+        const char *begin, *end;
         Wireguard *w;
-        WireguardPeer *peer;
         size_t len;
-        const char *begin, *end = NULL;
-        _cleanup_free_ char *host = NULL, *port = NULL;
-        _cleanup_(wireguard_endpoint_freep) WireguardEndpoint *endpoint = NULL;
+        int r;
 
         assert(data);
         assert(rvalue);
@@ -633,21 +696,25 @@ int config_parse_wireguard_endpoint(const char *unit,
 
         assert(w);
 
-        peer = wireguard_peer_new(w, section_line);
-        if (!peer)
-                return log_oom();
+        r = wireguard_peer_new_static(w, filename, section_line, &peer);
+        if (r < 0)
+                return r;
 
         if (rvalue[0] == '[') {
                 begin = &rvalue[1];
                 end = strchr(rvalue, ']');
                 if (!end) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find matching brace of endpoint, ignoring assignment: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Unable to find matching brace of endpoint, ignoring assignment: %s",
+                                   rvalue);
                         return 0;
                 }
                 len = end - begin;
                 ++end;
                 if (*end != ':' || !*(end + 1)) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find port of endpoint: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Unable to find port of endpoint, ignoring assignment: %s",
+                                   rvalue);
                         return 0;
                 }
                 ++end;
@@ -655,33 +722,32 @@ int config_parse_wireguard_endpoint(const char *unit,
                 begin = rvalue;
                 end = strrchr(rvalue, ':');
                 if (!end || !*(end + 1)) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find port of endpoint: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Unable to find port of endpoint, ignoring assignment: %s",
+                                   rvalue);
                         return 0;
                 }
                 len = end - begin;
                 ++end;
         }
 
-        host = strndup(begin, len);
-        if (!host)
+        peer->endpoint_host = strndup(begin, len);
+        if (!peer->endpoint_host)
                 return log_oom();
 
-        port = strdup(end);
-        if (!port)
+        peer->endpoint_port = strdup(end);
+        if (!peer->endpoint_port)
                 return log_oom();
 
-        endpoint = new(WireguardEndpoint, 1);
-        if (!endpoint)
+        r = set_ensure_allocated(&w->peers_with_unresolved_endpoint, NULL);
+        if (r < 0)
                 return log_oom();
 
-        *endpoint = (WireguardEndpoint) {
-                .peer = TAKE_PTR(peer),
-                .host = TAKE_PTR(host),
-                .port = TAKE_PTR(port),
-                .netdev = data,
-        };
-        LIST_PREPEND(endpoints, w->unresolved_endpoints, TAKE_PTR(endpoint));
+        r = set_put(w->peers_with_unresolved_endpoint, peer);
+        if (r < 0)
+                return r;
 
+        TAKE_PTR(peer);
         return 0;
 }
 
@@ -695,10 +761,11 @@ int config_parse_wireguard_keepalive(const char *unit,
                                      const char *rvalue,
                                      void *data,
                                      void *userdata) {
-        int r;
+
+        _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
         uint16_t keepalive = 0;
         Wireguard *w;
-        WireguardPeer *peer;
+        int r;
 
         assert(rvalue);
         assert(data);
@@ -707,19 +774,25 @@ int config_parse_wireguard_keepalive(const char *unit,
 
         assert(w);
 
-        peer = wireguard_peer_new(w, section_line);
-        if (!peer)
-                return log_oom();
+        r = wireguard_peer_new_static(w, filename, section_line, &peer);
+        if (r < 0)
+                return r;
 
         if (streq(rvalue, "off"))
                 keepalive = 0;
         else {
                 r = safe_atou16(rvalue, &keepalive);
-                if (r < 0)
-                        log_syntax(unit, LOG_ERR, filename, line, r, "The persistent keepalive interval must be 0-65535. Ignore assignment: %s", rvalue);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "The persistent keepalive interval must be 0-65535. Ignore assignment: %s",
+                                   rvalue);
+                        return 0;
+                }
         }
 
         peer->persistent_keepalive_interval = keepalive;
+
+        TAKE_PTR(peer);
         return 0;
 }
 
@@ -737,32 +810,29 @@ static void wireguard_init(NetDev *netdev) {
 
 static void wireguard_done(NetDev *netdev) {
         Wireguard *w;
-        WireguardPeer *peer;
-        WireguardIPmask *mask;
-        WireguardEndpoint *e;
 
         assert(netdev);
         w = WIREGUARD(netdev);
         assert(w);
 
-        while ((peer = w->peers)) {
-                LIST_REMOVE(peers, w->peers, peer);
-                while ((mask = peer->ipmasks)) {
-                        LIST_REMOVE(ipmasks, peer->ipmasks, mask);
-                        free(mask);
-                }
-                free(peer);
-        }
+        hashmap_free_with_destructor(w->peers_by_section, wireguard_peer_free);
+        set_free(w->peers_with_unresolved_endpoint);
+        set_free(w->peers_with_failed_endpoint);
+}
 
-        while ((e = w->unresolved_endpoints)) {
-                LIST_REMOVE(endpoints, w->unresolved_endpoints, e);
-                wireguard_endpoint_free(e);
-        }
+static int wireguard_verify(NetDev *netdev, const char *filename) {
+        WireguardPeer *peer, *peer_next;
+        Wireguard *w;
 
-        while ((e = w->failed_endpoints)) {
-                LIST_REMOVE(endpoints, w->failed_endpoints, e);
-                wireguard_endpoint_free(e);
-        }
+        assert(netdev);
+        w = WIREGUARD(netdev);
+        assert(w);
+
+        LIST_FOREACH_SAFE(peers, peer, peer_next, w->peers)
+                if (section_is_invalid(peer->section))
+                        wireguard_peer_free(peer);
+
+        return 0;
 }
 
 const NetDevVTable wireguard_vtable = {
@@ -772,4 +842,5 @@ const NetDevVTable wireguard_vtable = {
         .init = wireguard_init,
         .done = wireguard_done,
         .create_type = NETDEV_CREATE_INDEPENDENT,
+        .config_verify = wireguard_verify,
 };
index 143e93cdc5f2a148590bbd2214eeaf1f04515507..72e895bf43451512c6ddb7da4fbc030406bfbc90 100644 (file)
@@ -7,10 +7,6 @@ typedef struct Wireguard Wireguard;
 #include "socket-util.h"
 #include "wireguard-netlink.h"
 
-#ifndef IFNAMSIZ
-#define IFNAMSIZ 16
-#endif
-
 typedef struct WireguardIPmask {
         uint16_t family;
         union in_addr_union ip;
@@ -20,43 +16,37 @@ typedef struct WireguardIPmask {
 } WireguardIPmask;
 
 typedef struct WireguardPeer {
+        Wireguard *wireguard;
+        NetworkConfigSection *section;
+
         uint8_t public_key[WG_KEY_LEN];
         uint8_t preshared_key[WG_KEY_LEN];
         uint32_t flags;
+        uint16_t persistent_keepalive_interval;
 
         union sockaddr_union endpoint;
-
-        uint16_t persistent_keepalive_interval;
+        char *endpoint_host;
+        char *endpoint_port;
 
         LIST_HEAD(WireguardIPmask, ipmasks);
         LIST_FIELDS(struct WireguardPeer, peers);
 } WireguardPeer;
 
-typedef struct WireguardEndpoint {
-        char *host;
-        char *port;
-
-        NetDev *netdev;
-        WireguardPeer *peer;
-
-        LIST_FIELDS(struct WireguardEndpoint, endpoints);
-} WireguardEndpoint;
-
 struct Wireguard {
         NetDev meta;
         unsigned last_peer_section;
 
         uint32_t flags;
-
         uint8_t private_key[WG_KEY_LEN];
+        uint16_t port;
         uint32_t fwmark;
 
-        uint16_t port;
+        Hashmap *peers_by_section;
+        Set *peers_with_unresolved_endpoint;
+        Set *peers_with_failed_endpoint;
 
         LIST_HEAD(WireguardPeer, peers);
 
-        LIST_HEAD(WireguardEndpoint, unresolved_endpoints);
-        LIST_HEAD(WireguardEndpoint, failed_endpoints);
         unsigned n_retries;
 };