]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: use destroy callback to clear resolved wireguard endpoints
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 4 Nov 2018 11:42:14 +0000 (20:42 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 5 Nov 2018 04:19:02 +0000 (13:19 +0900)
src/network/netdev/wireguard.c
src/network/netdev/wireguard.h

index 1cab31302e82c8456eca4b3adf99645b8a578c8b..de685157efde81f1d39b90ec122b319818f96dba 100644 (file)
@@ -6,6 +6,8 @@
 #include <sys/ioctl.h>
 #include <net/if.h>
 
+#include "sd-resolve.h"
+
 #include "alloc-util.h"
 #include "parse-util.h"
 #include "fd-util.h"
@@ -195,12 +197,21 @@ static int set_wireguard_interface(NetDev *netdev) {
 static WireguardEndpoint* wireguard_endpoint_free(WireguardEndpoint *e) {
         if (!e)
                 return NULL;
-        netdev_unref(e->netdev);
         e->host = mfree(e->host);
         e->port = mfree(e->port);
         return mfree(e);
 }
 
+static void wireguard_endpoint_destroy_callback(void *userdata) {
+        WireguardEndpoint *e = userdata;
+
+        assert(e);
+        assert(e->netdev);
+
+        netdev_unref(e->netdev);
+        wireguard_endpoint_free(e);
+}
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(WireguardEndpoint*, wireguard_endpoint_free);
 
 static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
@@ -232,9 +243,10 @@ static int wireguard_resolve_handler(sd_resolve_query *q,
                                      int ret,
                                      const struct addrinfo *ai,
                                      void *userdata) {
-        NetDev *netdev;
+        _cleanup_(netdev_unrefp) NetDev *netdev_will_unrefed = NULL;
+        NetDev *netdev = NULL;
+        WireguardEndpoint *e;
         Wireguard *w;
-        _cleanup_(wireguard_endpoint_freep) WireguardEndpoint *e;
         int r;
 
         assert(userdata);
@@ -245,14 +257,17 @@ static int wireguard_resolve_handler(sd_resolve_query *q,
         w = WIREGUARD(netdev);
         assert(w);
 
-        w->resolve_query = sd_resolve_query_unref(w->resolve_query);
+        if (!netdev->manager)
+                /* The netdev is detached. */
+                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);
-                e = NULL;
+                (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. */
         } 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)))
+                   (ai->ai_family == AF_INET6 && ai->ai_addrlen == sizeof(struct sockaddr_in6)))
                 memcpy(&e->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);
@@ -280,22 +295,24 @@ static int wireguard_resolve_handler(sd_resolve_query *q,
 }
 
 static void resolve_endpoints(NetDev *netdev) {
-        int r = 0;
-        Wireguard *w;
-        WireguardEndpoint *endpoint;
         static const struct addrinfo hints = {
                 .ai_family = AF_UNSPEC,
                 .ai_socktype = SOCK_DGRAM,
                 .ai_protocol = IPPROTO_UDP
         };
+        WireguardEndpoint *endpoint;
+        Wireguard *w;
+        int r = 0;
 
         assert(netdev);
         w = WIREGUARD(netdev);
         assert(w);
 
         LIST_FOREACH(endpoints, endpoint, w->unresolved_endpoints) {
+                _cleanup_(sd_resolve_query_unrefp) sd_resolve_query *q = NULL;
+
                 r = sd_resolve_getaddrinfo(netdev->manager->resolve,
-                                           &w->resolve_query,
+                                           &q,
                                            endpoint->host,
                                            endpoint->port,
                                            &hints,
@@ -304,11 +321,23 @@ static void resolve_endpoints(NetDev *netdev) {
 
                 if (r == -ENOBUFS)
                         break;
+                if (r < 0) {
+                        log_netdev_error_errno(netdev, r, "Failed to create resolver: %m");
+                        continue;
+                }
 
-                LIST_REMOVE(endpoints, w->unresolved_endpoints, endpoint);
+                r = sd_resolve_query_set_destroy_callback(q, wireguard_endpoint_destroy_callback);
+                if (r < 0) {
+                        log_netdev_error_errno(netdev, r, "Failed to set destroy callback to resolving query: %m");
+                        continue;
+                }
 
-                if (r < 0)
-                        log_netdev_error_errno(netdev, r, "Failed create resolver: %m");
+                (void) sd_resolve_query_set_floating(q, true);
+
+                /* Avoid freeing netdev. It will be unrefed by the destroy callback. */
+                netdev_ref(netdev);
+
+                LIST_REMOVE(endpoints, w->unresolved_endpoints, endpoint);
         }
 }
 
@@ -612,9 +641,8 @@ int config_parse_wireguard_endpoint(const char *unit,
         endpoint->peer = TAKE_PTR(peer);
         endpoint->host = TAKE_PTR(host);
         endpoint->port = TAKE_PTR(port);
-        endpoint->netdev = netdev_ref(data);
-        LIST_PREPEND(endpoints, w->unresolved_endpoints, endpoint);
-        endpoint = NULL;
+        endpoint->netdev = data;
+        LIST_PREPEND(endpoints, w->unresolved_endpoints, TAKE_PTR(endpoint));
 
         return 0;
 }
index 80a5bf87a0a8f5809a6e6cbc8300b365d104937a..7e6feb298b191042b7967b4f81cca73fb3c1af7d 100644 (file)
@@ -63,7 +63,6 @@ struct Wireguard {
         LIST_HEAD(WireguardEndpoint, unresolved_endpoints);
         LIST_HEAD(WireguardEndpoint, failed_endpoints);
         unsigned n_retries;
-        sd_resolve_query *resolve_query;
 };
 
 DEFINE_NETDEV_CAST(WIREGUARD, Wireguard);