LCOV - code coverage report
Current view: top level - network/netdev - wireguard.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 483 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 29 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 432 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : /***
       3                 :            :   Copyright © 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
       4                 :            : ***/
       5                 :            : 
       6                 :            : #include <sys/ioctl.h>
       7                 :            : #include <net/if.h>
       8                 :            : 
       9                 :            : #include "sd-resolve.h"
      10                 :            : 
      11                 :            : #include "alloc-util.h"
      12                 :            : #include "event-util.h"
      13                 :            : #include "fd-util.h"
      14                 :            : #include "fileio.h"
      15                 :            : #include "hexdecoct.h"
      16                 :            : #include "memory-util.h"
      17                 :            : #include "netlink-util.h"
      18                 :            : #include "networkd-link.h"
      19                 :            : #include "networkd-manager.h"
      20                 :            : #include "networkd-util.h"
      21                 :            : #include "parse-util.h"
      22                 :            : #include "path-util.h"
      23                 :            : #include "resolve-private.h"
      24                 :            : #include "string-util.h"
      25                 :            : #include "strv.h"
      26                 :            : #include "wireguard.h"
      27                 :            : 
      28                 :            : static void resolve_endpoints(NetDev *netdev);
      29                 :            : 
      30                 :          0 : static void wireguard_peer_free(WireguardPeer *peer) {
      31                 :            :         WireguardIPmask *mask;
      32                 :            : 
      33         [ #  # ]:          0 :         if (!peer)
      34                 :          0 :                 return;
      35                 :            : 
      36         [ #  # ]:          0 :         if (peer->wireguard) {
      37   [ #  #  #  #  :          0 :                 LIST_REMOVE(peers, peer->wireguard->peers, peer);
             #  #  #  # ]
      38                 :            : 
      39                 :          0 :                 set_remove(peer->wireguard->peers_with_unresolved_endpoint, peer);
      40                 :          0 :                 set_remove(peer->wireguard->peers_with_failed_endpoint, peer);
      41                 :            : 
      42         [ #  # ]:          0 :                 if (peer->section)
      43                 :          0 :                         hashmap_remove(peer->wireguard->peers_by_section, peer->section);
      44                 :            :         }
      45                 :            : 
      46                 :          0 :         network_config_section_free(peer->section);
      47                 :            : 
      48         [ #  # ]:          0 :         while ((mask = peer->ipmasks)) {
      49   [ #  #  #  #  :          0 :                 LIST_REMOVE(ipmasks, peer->ipmasks, mask);
             #  #  #  # ]
      50                 :          0 :                 free(mask);
      51                 :            :         }
      52                 :            : 
      53                 :          0 :         free(peer->endpoint_host);
      54                 :          0 :         free(peer->endpoint_port);
      55                 :          0 :         free(peer->preshared_key_file);
      56                 :          0 :         explicit_bzero_safe(peer->preshared_key, WG_KEY_LEN);
      57                 :            : 
      58                 :          0 :         free(peer);
      59                 :            : }
      60                 :            : 
      61   [ #  #  #  # ]:          0 : DEFINE_NETWORK_SECTION_FUNCTIONS(WireguardPeer, wireguard_peer_free);
      62                 :            : 
      63                 :          0 : static int wireguard_peer_new_static(Wireguard *w, const char *filename, unsigned section_line, WireguardPeer **ret) {
      64                 :          0 :         _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
      65                 :          0 :         _cleanup_(wireguard_peer_freep) WireguardPeer *peer = NULL;
      66                 :            :         int r;
      67                 :            : 
      68         [ #  # ]:          0 :         assert(w);
      69         [ #  # ]:          0 :         assert(ret);
      70         [ #  # ]:          0 :         assert(filename);
      71         [ #  # ]:          0 :         assert(section_line > 0);
      72                 :            : 
      73                 :          0 :         r = network_config_section_new(filename, section_line, &n);
      74         [ #  # ]:          0 :         if (r < 0)
      75                 :          0 :                 return r;
      76                 :            : 
      77                 :          0 :         peer = hashmap_get(w->peers_by_section, n);
      78         [ #  # ]:          0 :         if (peer) {
      79                 :          0 :                 *ret = TAKE_PTR(peer);
      80                 :          0 :                 return 0;
      81                 :            :         }
      82                 :            : 
      83                 :          0 :         peer = new(WireguardPeer, 1);
      84         [ #  # ]:          0 :         if (!peer)
      85                 :          0 :                 return -ENOMEM;
      86                 :            : 
      87                 :          0 :         *peer = (WireguardPeer) {
      88                 :            :                 .flags = WGPEER_F_REPLACE_ALLOWEDIPS,
      89                 :            :                 .wireguard = w,
      90                 :          0 :                 .section = TAKE_PTR(n),
      91                 :            :         };
      92                 :            : 
      93   [ #  #  #  # ]:          0 :         LIST_PREPEND(peers, w->peers, peer);
      94                 :            : 
      95                 :          0 :         r = hashmap_ensure_allocated(&w->peers_by_section, &network_config_hash_ops);
      96         [ #  # ]:          0 :         if (r < 0)
      97                 :          0 :                 return r;
      98                 :            : 
      99                 :          0 :         r = hashmap_put(w->peers_by_section, peer->section, peer);
     100         [ #  # ]:          0 :         if (r < 0)
     101                 :          0 :                 return r;
     102                 :            : 
     103                 :          0 :         *ret = TAKE_PTR(peer);
     104                 :          0 :         return 0;
     105                 :            : }
     106                 :            : 
     107                 :          0 : static int wireguard_set_ipmask_one(NetDev *netdev, sd_netlink_message *message, const WireguardIPmask *mask, uint16_t index) {
     108                 :            :         int r;
     109                 :            : 
     110         [ #  # ]:          0 :         assert(message);
     111         [ #  # ]:          0 :         assert(mask);
     112         [ #  # ]:          0 :         assert(index > 0);
     113                 :            : 
     114                 :            :         /* This returns 1 on success, 0 on recoverable error, and negative errno on failure. */
     115                 :            : 
     116                 :          0 :         r = sd_netlink_message_open_array(message, index);
     117         [ #  # ]:          0 :         if (r < 0)
     118                 :          0 :                 return 0;
     119                 :            : 
     120                 :          0 :         r = sd_netlink_message_append_u16(message, WGALLOWEDIP_A_FAMILY, mask->family);
     121         [ #  # ]:          0 :         if (r < 0)
     122                 :          0 :                 goto cancel;
     123                 :            : 
     124                 :          0 :         r = netlink_message_append_in_addr_union(message, WGALLOWEDIP_A_IPADDR, mask->family, &mask->ip);
     125         [ #  # ]:          0 :         if (r < 0)
     126                 :          0 :                 goto cancel;
     127                 :            : 
     128                 :          0 :         r = sd_netlink_message_append_u8(message, WGALLOWEDIP_A_CIDR_MASK, mask->cidr);
     129         [ #  # ]:          0 :         if (r < 0)
     130                 :          0 :                 goto cancel;
     131                 :            : 
     132                 :          0 :         r = sd_netlink_message_close_container(message);
     133         [ #  # ]:          0 :         if (r < 0)
     134         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m");
     135                 :            : 
     136                 :          0 :         return 1;
     137                 :            : 
     138                 :          0 : cancel:
     139                 :          0 :         r = sd_netlink_message_cancel_array(message);
     140         [ #  # ]:          0 :         if (r < 0)
     141         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not cancel wireguard allowed ip message attribute: %m");
     142                 :            : 
     143                 :          0 :         return 0;
     144                 :            : }
     145                 :            : 
     146                 :          0 : static int wireguard_set_peer_one(NetDev *netdev, sd_netlink_message *message, const WireguardPeer *peer, uint16_t index, WireguardIPmask **mask_start) {
     147                 :            :         WireguardIPmask *mask, *start;
     148                 :          0 :         uint16_t j = 0;
     149                 :            :         int r;
     150                 :            : 
     151         [ #  # ]:          0 :         assert(message);
     152         [ #  # ]:          0 :         assert(peer);
     153         [ #  # ]:          0 :         assert(index > 0);
     154         [ #  # ]:          0 :         assert(mask_start);
     155                 :            : 
     156                 :            :         /* This returns 1 on success, 0 on recoverable error, and negative errno on failure. */
     157                 :            : 
     158         [ #  # ]:          0 :         start = *mask_start ?: peer->ipmasks;
     159                 :            : 
     160                 :          0 :         r = sd_netlink_message_open_array(message, index);
     161         [ #  # ]:          0 :         if (r < 0)
     162                 :          0 :                 return 0;
     163                 :            : 
     164                 :          0 :         r = sd_netlink_message_append_data(message, WGPEER_A_PUBLIC_KEY, &peer->public_key, sizeof(peer->public_key));
     165         [ #  # ]:          0 :         if (r < 0)
     166                 :          0 :                 goto cancel;
     167                 :            : 
     168         [ #  # ]:          0 :         if (!*mask_start) {
     169                 :          0 :                 r = sd_netlink_message_append_data(message, WGPEER_A_PRESHARED_KEY, &peer->preshared_key, WG_KEY_LEN);
     170         [ #  # ]:          0 :                 if (r < 0)
     171                 :          0 :                         goto cancel;
     172                 :            : 
     173                 :          0 :                 r = sd_netlink_message_append_u32(message, WGPEER_A_FLAGS, peer->flags);
     174         [ #  # ]:          0 :                 if (r < 0)
     175                 :          0 :                         goto cancel;
     176                 :            : 
     177                 :          0 :                 r = sd_netlink_message_append_u16(message, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval);
     178         [ #  # ]:          0 :                 if (r < 0)
     179                 :          0 :                         goto cancel;
     180                 :            : 
     181   [ #  #  #  # ]:          0 :                 if (IN_SET(peer->endpoint.sa.sa_family, AF_INET, AF_INET6)) {
     182                 :          0 :                         r = netlink_message_append_sockaddr_union(message, WGPEER_A_ENDPOINT, &peer->endpoint);
     183         [ #  # ]:          0 :                         if (r < 0)
     184                 :          0 :                                 goto cancel;
     185                 :            :                 }
     186                 :            :         }
     187                 :            : 
     188                 :          0 :         r = sd_netlink_message_open_container(message, WGPEER_A_ALLOWEDIPS);
     189         [ #  # ]:          0 :         if (r < 0)
     190                 :          0 :                 goto cancel;
     191                 :            : 
     192         [ #  # ]:          0 :         LIST_FOREACH(ipmasks, mask, start) {
     193                 :          0 :                 r = wireguard_set_ipmask_one(netdev, message, mask, ++j);
     194         [ #  # ]:          0 :                 if (r < 0)
     195                 :          0 :                         return r;
     196         [ #  # ]:          0 :                 if (r == 0)
     197                 :          0 :                         break;
     198                 :            :         }
     199                 :            : 
     200                 :          0 :         r = sd_netlink_message_close_container(message);
     201         [ #  # ]:          0 :         if (r < 0)
     202         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m");
     203                 :            : 
     204                 :          0 :         r = sd_netlink_message_close_container(message);
     205         [ #  # ]:          0 :         if (r < 0)
     206         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not add wireguard peer: %m");
     207                 :            : 
     208                 :          0 :         *mask_start = mask; /* Start next cycle from this mask. */
     209                 :          0 :         return !mask;
     210                 :            : 
     211                 :          0 : cancel:
     212                 :          0 :         r = sd_netlink_message_cancel_array(message);
     213         [ #  # ]:          0 :         if (r < 0)
     214         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not cancel wireguard peers: %m");
     215                 :            : 
     216                 :          0 :         return 0;
     217                 :            : }
     218                 :            : 
     219                 :          0 : static int wireguard_set_interface(NetDev *netdev) {
     220                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
     221                 :          0 :         WireguardIPmask *mask_start = NULL;
     222                 :            :         WireguardPeer *peer, *peer_start;
     223                 :            :         uint32_t serial;
     224                 :            :         Wireguard *w;
     225                 :            :         int r;
     226                 :            : 
     227         [ #  # ]:          0 :         assert(netdev);
     228                 :          0 :         w = WIREGUARD(netdev);
     229         [ #  # ]:          0 :         assert(w);
     230                 :            : 
     231         [ #  # ]:          0 :         for (peer_start = w->peers; peer_start; ) {
     232                 :          0 :                 uint16_t i = 0;
     233                 :            : 
     234                 :          0 :                 message = sd_netlink_message_unref(message);
     235                 :            : 
     236                 :          0 :                 r = sd_genl_message_new(netdev->manager->genl, SD_GENL_WIREGUARD, WG_CMD_SET_DEVICE, &message);
     237         [ #  # ]:          0 :                 if (r < 0)
     238         [ #  # ]:          0 :                         return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");
     239                 :            : 
     240                 :          0 :                 r = sd_netlink_message_append_string(message, WGDEVICE_A_IFNAME, netdev->ifname);
     241         [ #  # ]:          0 :                 if (r < 0)
     242         [ #  # ]:          0 :                         return log_netdev_error_errno(netdev, r, "Could not append wireguard interface name: %m");
     243                 :            : 
     244         [ #  # ]:          0 :                 if (peer_start == w->peers) {
     245                 :          0 :                         r = sd_netlink_message_append_data(message, WGDEVICE_A_PRIVATE_KEY, &w->private_key, WG_KEY_LEN);
     246         [ #  # ]:          0 :                         if (r < 0)
     247         [ #  # ]:          0 :                                 return log_netdev_error_errno(netdev, r, "Could not append wireguard private key: %m");
     248                 :            : 
     249                 :          0 :                         r = sd_netlink_message_append_u16(message, WGDEVICE_A_LISTEN_PORT, w->port);
     250         [ #  # ]:          0 :                         if (r < 0)
     251         [ #  # ]:          0 :                                 return log_netdev_error_errno(netdev, r, "Could not append wireguard port: %m");
     252                 :            : 
     253                 :          0 :                         r = sd_netlink_message_append_u32(message, WGDEVICE_A_FWMARK, w->fwmark);
     254         [ #  # ]:          0 :                         if (r < 0)
     255         [ #  # ]:          0 :                                 return log_netdev_error_errno(netdev, r, "Could not append wireguard fwmark: %m");
     256                 :            : 
     257                 :          0 :                         r = sd_netlink_message_append_u32(message, WGDEVICE_A_FLAGS, w->flags);
     258         [ #  # ]:          0 :                         if (r < 0)
     259         [ #  # ]:          0 :                                 return log_netdev_error_errno(netdev, r, "Could not append wireguard flags: %m");
     260                 :            :                 }
     261                 :            : 
     262                 :          0 :                 r = sd_netlink_message_open_container(message, WGDEVICE_A_PEERS);
     263         [ #  # ]:          0 :                 if (r < 0)
     264         [ #  # ]:          0 :                         return log_netdev_error_errno(netdev, r, "Could not append wireguard peer attributes: %m");
     265                 :            : 
     266         [ #  # ]:          0 :                 LIST_FOREACH(peers, peer, peer_start) {
     267                 :          0 :                         r = wireguard_set_peer_one(netdev, message, peer, ++i, &mask_start);
     268         [ #  # ]:          0 :                         if (r < 0)
     269                 :          0 :                                 return r;
     270         [ #  # ]:          0 :                         if (r == 0)
     271                 :          0 :                                 break;
     272                 :            :                 }
     273                 :          0 :                 peer_start = peer; /* Start next cycle from this peer. */
     274                 :            : 
     275                 :          0 :                 r = sd_netlink_message_close_container(message);
     276         [ #  # ]:          0 :                 if (r < 0)
     277         [ #  # ]:          0 :                         return log_netdev_error_errno(netdev, r, "Could not close wireguard container: %m");
     278                 :            : 
     279                 :          0 :                 r = sd_netlink_send(netdev->manager->genl, message, &serial);
     280         [ #  # ]:          0 :                 if (r < 0)
     281         [ #  # ]:          0 :                         return log_netdev_error_errno(netdev, r, "Could not set wireguard device: %m");
     282                 :            :         }
     283                 :            : 
     284                 :          0 :         return 0;
     285                 :            : }
     286                 :            : 
     287                 :          0 : static void wireguard_peer_destroy_callback(WireguardPeer *peer) {
     288                 :            :         NetDev *netdev;
     289                 :            : 
     290         [ #  # ]:          0 :         assert(peer);
     291         [ #  # ]:          0 :         assert(peer->wireguard);
     292                 :            : 
     293                 :          0 :         netdev = NETDEV(peer->wireguard);
     294                 :            : 
     295         [ #  # ]:          0 :         if (section_is_invalid(peer->section))
     296                 :          0 :                 wireguard_peer_free(peer);
     297                 :            : 
     298                 :          0 :         netdev_unref(netdev);
     299                 :          0 : }
     300                 :            : 
     301                 :          0 : static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
     302                 :          0 :         NetDev *netdev = userdata;
     303                 :            :         Wireguard *w;
     304                 :            : 
     305         [ #  # ]:          0 :         assert(netdev);
     306                 :          0 :         w = WIREGUARD(netdev);
     307         [ #  # ]:          0 :         assert(w);
     308                 :            : 
     309         [ #  # ]:          0 :         if (!netdev_is_managed(netdev))
     310                 :          0 :                 return 0;
     311                 :            : 
     312         [ #  # ]:          0 :         assert(set_isempty(w->peers_with_unresolved_endpoint));
     313                 :            : 
     314                 :          0 :         SWAP_TWO(w->peers_with_unresolved_endpoint, w->peers_with_failed_endpoint);
     315                 :            : 
     316                 :          0 :         resolve_endpoints(netdev);
     317                 :            : 
     318                 :          0 :         return 0;
     319                 :            : }
     320                 :            : 
     321                 :            : /*
     322                 :            :  * Given the number of retries this function will return will an exponential
     323                 :            :  * increasing time in milliseconds to wait starting at 200ms and capped at 25 seconds.
     324                 :            :  */
     325                 :          0 : static int exponential_backoff_milliseconds(unsigned n_retries) {
     326                 :          0 :         return (2 << MIN(n_retries, 7U)) * 100 * USEC_PER_MSEC;
     327                 :            : }
     328                 :            : 
     329                 :          0 : static int wireguard_resolve_handler(sd_resolve_query *q,
     330                 :            :                                      int ret,
     331                 :            :                                      const struct addrinfo *ai,
     332                 :            :                                      WireguardPeer *peer) {
     333                 :            :         NetDev *netdev;
     334                 :            :         Wireguard *w;
     335                 :            :         int r;
     336                 :            : 
     337         [ #  # ]:          0 :         assert(peer);
     338         [ #  # ]:          0 :         assert(peer->wireguard);
     339                 :            : 
     340                 :          0 :         w = peer->wireguard;
     341                 :          0 :         netdev = NETDEV(w);
     342                 :            : 
     343         [ #  # ]:          0 :         if (!netdev_is_managed(netdev))
     344                 :          0 :                 return 0;
     345                 :            : 
     346         [ #  # ]:          0 :         if (ret != 0) {
     347         [ #  # ]:          0 :                 log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", peer->endpoint_host, peer->endpoint_port, gai_strerror(ret));
     348                 :            : 
     349                 :          0 :                 r = set_ensure_allocated(&w->peers_with_failed_endpoint, NULL);
     350         [ #  # ]:          0 :                 if (r < 0) {
     351                 :          0 :                         log_oom();
     352                 :          0 :                         peer->section->invalid = true;
     353                 :          0 :                         goto resolve_next;
     354                 :            :                 }
     355                 :            : 
     356                 :          0 :                 r = set_put(w->peers_with_failed_endpoint, peer);
     357         [ #  # ]:          0 :                 if (r < 0) {
     358         [ #  # ]:          0 :                         log_netdev_error(netdev, "Failed to save a peer, dropping the peer: %m");
     359                 :          0 :                         peer->section->invalid = true;
     360                 :          0 :                         goto resolve_next;
     361                 :            :                 }
     362                 :            : 
     363   [ #  #  #  # ]:          0 :         } else if ((ai->ai_family == AF_INET && ai->ai_addrlen == sizeof(struct sockaddr_in)) ||
     364   [ #  #  #  # ]:          0 :                    (ai->ai_family == AF_INET6 && ai->ai_addrlen == sizeof(struct sockaddr_in6)))
     365                 :          0 :                 memcpy(&peer->endpoint, ai->ai_addr, ai->ai_addrlen);
     366                 :            :         else
     367         [ #  # ]:          0 :                 log_netdev_error(netdev, "Neither IPv4 nor IPv6 address found for peer endpoint %s:%s, ignoring the address.",
     368                 :            :                                  peer->endpoint_host, peer->endpoint_port);
     369                 :            : 
     370                 :          0 : resolve_next:
     371         [ #  # ]:          0 :         if (!set_isempty(w->peers_with_unresolved_endpoint)) {
     372                 :          0 :                 resolve_endpoints(netdev);
     373                 :          0 :                 return 0;
     374                 :            :         }
     375                 :            : 
     376                 :          0 :         (void) wireguard_set_interface(netdev);
     377                 :            : 
     378         [ #  # ]:          0 :         if (!set_isempty(w->peers_with_failed_endpoint)) {
     379                 :            :                 usec_t usec;
     380                 :            : 
     381                 :          0 :                 w->n_retries++;
     382                 :          0 :                 usec = usec_add(now(CLOCK_MONOTONIC), exponential_backoff_milliseconds(w->n_retries));
     383                 :          0 :                 r = event_reset_time(netdev->manager->event, &w->resolve_retry_event_source,
     384                 :            :                                      CLOCK_MONOTONIC, usec, 0, on_resolve_retry, netdev,
     385                 :            :                                      0, "wireguard-resolve-retry", true);
     386         [ #  # ]:          0 :                 if (r < 0) {
     387         [ #  # ]:          0 :                         log_netdev_warning_errno(netdev, r, "Could not arm resolve retry handler: %m");
     388                 :          0 :                         return 0;
     389                 :            :                 }
     390                 :            :         }
     391                 :            : 
     392                 :          0 :         return 0;
     393                 :            : }
     394                 :            : 
     395                 :          0 : static void resolve_endpoints(NetDev *netdev) {
     396                 :            :         static const struct addrinfo hints = {
     397                 :            :                 .ai_family = AF_UNSPEC,
     398                 :            :                 .ai_socktype = SOCK_DGRAM,
     399                 :            :                 .ai_protocol = IPPROTO_UDP
     400                 :            :         };
     401                 :            :         WireguardPeer *peer;
     402                 :            :         Wireguard *w;
     403                 :            :         Iterator i;
     404                 :            :         int r;
     405                 :            : 
     406         [ #  # ]:          0 :         assert(netdev);
     407                 :          0 :         w = WIREGUARD(netdev);
     408         [ #  # ]:          0 :         assert(w);
     409                 :            : 
     410         [ #  # ]:          0 :         SET_FOREACH(peer, w->peers_with_unresolved_endpoint, i) {
     411                 :          0 :                 r = resolve_getaddrinfo(netdev->manager->resolve,
     412                 :            :                                         NULL,
     413                 :            :                                         peer->endpoint_host,
     414                 :            :                                         peer->endpoint_port,
     415                 :            :                                         &hints,
     416                 :            :                                         wireguard_resolve_handler,
     417                 :            :                                         wireguard_peer_destroy_callback,
     418                 :            :                                         peer);
     419         [ #  # ]:          0 :                 if (r == -ENOBUFS)
     420                 :          0 :                         break;
     421         [ #  # ]:          0 :                 if (r < 0) {
     422         [ #  # ]:          0 :                         log_netdev_error_errno(netdev, r, "Failed to create resolver: %m");
     423                 :          0 :                         continue;
     424                 :            :                 }
     425                 :            : 
     426                 :            :                 /* Avoid freeing netdev. It will be unrefed by the destroy callback. */
     427                 :          0 :                 netdev_ref(netdev);
     428                 :            : 
     429                 :          0 :                 (void) set_remove(w->peers_with_unresolved_endpoint, peer);
     430                 :            :         }
     431                 :          0 : }
     432                 :            : 
     433                 :          0 : static int netdev_wireguard_post_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
     434         [ #  # ]:          0 :         assert(netdev);
     435         [ #  # ]:          0 :         assert(WIREGUARD(netdev));
     436                 :            : 
     437                 :          0 :         (void) wireguard_set_interface(netdev);
     438                 :          0 :         resolve_endpoints(netdev);
     439                 :          0 :         return 0;
     440                 :            : }
     441                 :            : 
     442                 :          0 : int config_parse_wireguard_listen_port(
     443                 :            :                 const char *unit,
     444                 :            :                 const char *filename,
     445                 :            :                 unsigned line,
     446                 :            :                 const char *section,
     447                 :            :                 unsigned section_line,
     448                 :            :                 const char *lvalue,
     449                 :            :                 int ltype,
     450                 :            :                 const char *rvalue,
     451                 :            :                 void *data,
     452                 :            :                 void *userdata) {
     453                 :            : 
     454                 :          0 :         uint16_t *s = data;
     455                 :            :         int r;
     456                 :            : 
     457         [ #  # ]:          0 :         assert(rvalue);
     458         [ #  # ]:          0 :         assert(data);
     459                 :            : 
     460   [ #  #  #  # ]:          0 :         if (isempty(rvalue) || streq(rvalue, "auto")) {
     461                 :          0 :                 *s = 0;
     462                 :          0 :                 return 0;
     463                 :            :         }
     464                 :            : 
     465                 :          0 :         r = parse_ip_port(rvalue, s);
     466         [ #  # ]:          0 :         if (r < 0) {
     467         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r,
     468                 :            :                            "Invalid port specification, ignoring assignment: %s", rvalue);
     469                 :          0 :                 return 0;
     470                 :            :         }
     471                 :            : 
     472                 :          0 :         return 0;
     473                 :            : }
     474                 :            : 
     475                 :          0 : static int wireguard_decode_key_and_warn(
     476                 :            :                 const char *rvalue,
     477                 :            :                 uint8_t ret[static WG_KEY_LEN],
     478                 :            :                 const char *unit,
     479                 :            :                 const char *filename,
     480                 :            :                 unsigned line,
     481                 :            :                 const char *lvalue) {
     482                 :            : 
     483                 :          0 :         _cleanup_(erase_and_freep) void *key = NULL;
     484                 :            :         size_t len;
     485                 :            :         int r;
     486                 :            : 
     487         [ #  # ]:          0 :         assert(rvalue);
     488         [ #  # ]:          0 :         assert(ret);
     489         [ #  # ]:          0 :         assert(filename);
     490         [ #  # ]:          0 :         assert(lvalue);
     491                 :            : 
     492         [ #  # ]:          0 :         if (isempty(rvalue)) {
     493         [ #  # ]:          0 :                 memzero(ret, WG_KEY_LEN);
     494                 :          0 :                 return 0;
     495                 :            :         }
     496                 :            : 
     497         [ #  # ]:          0 :         if (!streq(lvalue, "PublicKey"))
     498                 :          0 :                 (void) warn_file_is_world_accessible(filename, NULL, unit, line);
     499                 :            : 
     500                 :          0 :         r = unbase64mem_full(rvalue, strlen(rvalue), true, &key, &len);
     501         [ #  # ]:          0 :         if (r < 0)
     502         [ #  # ]:          0 :                 return log_syntax(unit, LOG_ERR, filename, line, r,
     503                 :            :                            "Failed to decode wireguard key provided by %s=, ignoring assignment: %m", lvalue);
     504         [ #  # ]:          0 :         if (len != WG_KEY_LEN)
     505         [ #  # ]:          0 :                 return log_syntax(unit, LOG_ERR, filename, line, 0,
     506                 :            :                            "Wireguard key provided by %s= has invalid length (%zu bytes), ignoring assignment.",
     507                 :            :                            lvalue, len);
     508                 :            : 
     509                 :          0 :         memcpy(ret, key, WG_KEY_LEN);
     510                 :          0 :         return 0;
     511                 :            : }
     512                 :            : 
     513                 :          0 : int config_parse_wireguard_private_key(
     514                 :            :                 const char *unit,
     515                 :            :                 const char *filename,
     516                 :            :                 unsigned line,
     517                 :            :                 const char *section,
     518                 :            :                 unsigned section_line,
     519                 :            :                 const char *lvalue,
     520                 :            :                 int ltype,
     521                 :            :                 const char *rvalue,
     522                 :            :                 void *data,
     523                 :            :                 void *userdata) {
     524                 :            : 
     525                 :            :         Wireguard *w;
     526                 :            : 
     527         [ #  # ]:          0 :         assert(data);
     528                 :          0 :         w = WIREGUARD(data);
     529         [ #  # ]:          0 :         assert(w);
     530                 :            : 
     531                 :          0 :         (void) wireguard_decode_key_and_warn(rvalue, w->private_key, unit, filename, line, lvalue);
     532                 :          0 :         return 0;
     533                 :            : }
     534                 :            : 
     535                 :          0 : int config_parse_wireguard_private_key_file(
     536                 :            :                 const char *unit,
     537                 :            :                 const char *filename,
     538                 :            :                 unsigned line,
     539                 :            :                 const char *section,
     540                 :            :                 unsigned section_line,
     541                 :            :                 const char *lvalue,
     542                 :            :                 int ltype,
     543                 :            :                 const char *rvalue,
     544                 :            :                 void *data,
     545                 :            :                 void *userdata) {
     546                 :            : 
     547                 :          0 :         _cleanup_free_ char *path = NULL;
     548                 :            :         Wireguard *w;
     549                 :            : 
     550         [ #  # ]:          0 :         assert(data);
     551                 :          0 :         w = WIREGUARD(data);
     552         [ #  # ]:          0 :         assert(w);
     553                 :            : 
     554         [ #  # ]:          0 :         if (isempty(rvalue)) {
     555                 :          0 :                 w->private_key_file = mfree(w->private_key_file);
     556                 :          0 :                 return 0;
     557                 :            :         }
     558                 :            : 
     559                 :          0 :         path = strdup(rvalue);
     560         [ #  # ]:          0 :         if (!path)
     561                 :          0 :                 return log_oom();
     562                 :            : 
     563         [ #  # ]:          0 :         if (path_simplify_and_warn(path, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue) < 0)
     564                 :          0 :                 return 0;
     565                 :            : 
     566                 :          0 :         return free_and_replace(w->private_key_file, path);
     567                 :            : }
     568                 :            : 
     569                 :          0 : int config_parse_wireguard_preshared_key(
     570                 :            :                 const char *unit,
     571                 :            :                 const char *filename,
     572                 :            :                 unsigned line,
     573                 :            :                 const char *section,
     574                 :            :                 unsigned section_line,
     575                 :            :                 const char *lvalue,
     576                 :            :                 int ltype,
     577                 :            :                 const char *rvalue,
     578                 :            :                 void *data,
     579                 :            :                 void *userdata) {
     580                 :            : 
     581                 :          0 :         _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
     582                 :            :         Wireguard *w;
     583                 :            :         int r;
     584                 :            : 
     585         [ #  # ]:          0 :         assert(data);
     586                 :          0 :         w = WIREGUARD(data);
     587         [ #  # ]:          0 :         assert(w);
     588                 :            : 
     589                 :          0 :         r = wireguard_peer_new_static(w, filename, section_line, &peer);
     590         [ #  # ]:          0 :         if (r < 0)
     591                 :          0 :                 return r;
     592                 :            : 
     593                 :          0 :         r = wireguard_decode_key_and_warn(rvalue, peer->preshared_key, unit, filename, line, lvalue);
     594         [ #  # ]:          0 :         if (r < 0)
     595                 :          0 :                 return r;
     596                 :            : 
     597                 :          0 :         TAKE_PTR(peer);
     598                 :          0 :         return 0;
     599                 :            : }
     600                 :            : 
     601                 :          0 : int config_parse_wireguard_preshared_key_file(
     602                 :            :                 const char *unit,
     603                 :            :                 const char *filename,
     604                 :            :                 unsigned line,
     605                 :            :                 const char *section,
     606                 :            :                 unsigned section_line,
     607                 :            :                 const char *lvalue,
     608                 :            :                 int ltype,
     609                 :            :                 const char *rvalue,
     610                 :            :                 void *data,
     611                 :            :                 void *userdata) {
     612                 :            : 
     613                 :          0 :         _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
     614                 :          0 :         _cleanup_free_ char *path = NULL;
     615                 :            :         Wireguard *w;
     616                 :            :         int r;
     617                 :            : 
     618         [ #  # ]:          0 :         assert(data);
     619                 :          0 :         w = WIREGUARD(data);
     620         [ #  # ]:          0 :         assert(w);
     621                 :            : 
     622                 :          0 :         r = wireguard_peer_new_static(w, filename, section_line, &peer);
     623         [ #  # ]:          0 :         if (r < 0)
     624                 :          0 :                 return r;
     625                 :            : 
     626         [ #  # ]:          0 :         if (isempty(rvalue)) {
     627                 :          0 :                 peer->preshared_key_file = mfree(peer->preshared_key_file);
     628                 :          0 :                 TAKE_PTR(peer);
     629                 :          0 :                 return 0;
     630                 :            :         }
     631                 :            : 
     632                 :          0 :         path = strdup(rvalue);
     633         [ #  # ]:          0 :         if (!path)
     634                 :          0 :                 return log_oom();
     635                 :            : 
     636         [ #  # ]:          0 :         if (path_simplify_and_warn(path, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue) < 0)
     637                 :          0 :                 return 0;
     638                 :            : 
     639                 :          0 :         free_and_replace(peer->preshared_key_file, path);
     640                 :          0 :         TAKE_PTR(peer);
     641                 :          0 :         return 0;
     642                 :            : }
     643                 :            : 
     644                 :          0 : int config_parse_wireguard_public_key(
     645                 :            :                 const char *unit,
     646                 :            :                 const char *filename,
     647                 :            :                 unsigned line,
     648                 :            :                 const char *section,
     649                 :            :                 unsigned section_line,
     650                 :            :                 const char *lvalue,
     651                 :            :                 int ltype,
     652                 :            :                 const char *rvalue,
     653                 :            :                 void *data,
     654                 :            :                 void *userdata) {
     655                 :            : 
     656                 :          0 :         _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
     657                 :            :         Wireguard *w;
     658                 :            :         int r;
     659                 :            : 
     660         [ #  # ]:          0 :         assert(data);
     661                 :          0 :         w = WIREGUARD(data);
     662         [ #  # ]:          0 :         assert(w);
     663                 :            : 
     664                 :          0 :         r = wireguard_peer_new_static(w, filename, section_line, &peer);
     665         [ #  # ]:          0 :         if (r < 0)
     666                 :          0 :                 return r;
     667                 :            : 
     668                 :          0 :         r = wireguard_decode_key_and_warn(rvalue, peer->public_key, unit, filename, line, lvalue);
     669         [ #  # ]:          0 :         if (r < 0)
     670                 :          0 :                 return r;
     671                 :            : 
     672                 :          0 :         TAKE_PTR(peer);
     673                 :          0 :         return 0;
     674                 :            : }
     675                 :            : 
     676                 :          0 : int config_parse_wireguard_allowed_ips(
     677                 :            :                 const char *unit,
     678                 :            :                 const char *filename,
     679                 :            :                 unsigned line,
     680                 :            :                 const char *section,
     681                 :            :                 unsigned section_line,
     682                 :            :                 const char *lvalue,
     683                 :            :                 int ltype,
     684                 :            :                 const char *rvalue,
     685                 :            :                 void *data,
     686                 :            :                 void *userdata) {
     687                 :            : 
     688                 :          0 :         _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
     689                 :            :         union in_addr_union addr;
     690                 :            :         unsigned char prefixlen;
     691                 :            :         int r, family;
     692                 :            :         Wireguard *w;
     693                 :            :         WireguardIPmask *ipmask;
     694                 :            : 
     695         [ #  # ]:          0 :         assert(rvalue);
     696         [ #  # ]:          0 :         assert(data);
     697                 :            : 
     698                 :          0 :         w = WIREGUARD(data);
     699         [ #  # ]:          0 :         assert(w);
     700                 :            : 
     701                 :          0 :         r = wireguard_peer_new_static(w, filename, section_line, &peer);
     702         [ #  # ]:          0 :         if (r < 0)
     703                 :          0 :                 return r;
     704                 :            : 
     705                 :          0 :         for (;;) {
     706   [ #  #  #  # ]:          0 :                 _cleanup_free_ char *word = NULL;
     707                 :            : 
     708                 :          0 :                 r = extract_first_word(&rvalue, &word, "," WHITESPACE, 0);
     709         [ #  # ]:          0 :                 if (r == 0)
     710                 :          0 :                         break;
     711         [ #  # ]:          0 :                 if (r == -ENOMEM)
     712                 :          0 :                         return log_oom();
     713         [ #  # ]:          0 :                 if (r < 0) {
     714         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
     715                 :            :                                    "Failed to split allowed ips \"%s\" option: %m", rvalue);
     716                 :          0 :                         break;
     717                 :            :                 }
     718                 :            : 
     719                 :          0 :                 r = in_addr_prefix_from_string_auto(word, &family, &addr, &prefixlen);
     720         [ #  # ]:          0 :                 if (r < 0) {
     721         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
     722                 :            :                                    "Network address is invalid, ignoring assignment: %s", word);
     723                 :          0 :                         continue;
     724                 :            :                 }
     725                 :            : 
     726                 :          0 :                 ipmask = new(WireguardIPmask, 1);
     727         [ #  # ]:          0 :                 if (!ipmask)
     728                 :          0 :                         return log_oom();
     729                 :            : 
     730                 :          0 :                 *ipmask = (WireguardIPmask) {
     731                 :            :                         .family = family,
     732                 :            :                         .ip.in6 = addr.in6,
     733                 :            :                         .cidr = prefixlen,
     734                 :            :                 };
     735                 :            : 
     736   [ #  #  #  # ]:          0 :                 LIST_PREPEND(ipmasks, peer->ipmasks, ipmask);
     737                 :            :         }
     738                 :            : 
     739                 :          0 :         TAKE_PTR(peer);
     740                 :          0 :         return 0;
     741                 :            : }
     742                 :            : 
     743                 :          0 : int config_parse_wireguard_endpoint(
     744                 :            :                 const char *unit,
     745                 :            :                 const char *filename,
     746                 :            :                 unsigned line,
     747                 :            :                 const char *section,
     748                 :            :                 unsigned section_line,
     749                 :            :                 const char *lvalue,
     750                 :            :                 int ltype,
     751                 :            :                 const char *rvalue,
     752                 :            :                 void *data,
     753                 :            :                 void *userdata) {
     754                 :            : 
     755                 :          0 :         _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
     756                 :            :         const char *begin, *end;
     757                 :            :         Wireguard *w;
     758                 :            :         size_t len;
     759                 :            :         int r;
     760                 :            : 
     761         [ #  # ]:          0 :         assert(data);
     762         [ #  # ]:          0 :         assert(rvalue);
     763                 :            : 
     764                 :          0 :         w = WIREGUARD(data);
     765         [ #  # ]:          0 :         assert(w);
     766                 :            : 
     767                 :          0 :         r = wireguard_peer_new_static(w, filename, section_line, &peer);
     768         [ #  # ]:          0 :         if (r < 0)
     769                 :          0 :                 return r;
     770                 :            : 
     771         [ #  # ]:          0 :         if (rvalue[0] == '[') {
     772                 :          0 :                 begin = &rvalue[1];
     773                 :          0 :                 end = strchr(rvalue, ']');
     774         [ #  # ]:          0 :                 if (!end) {
     775         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
     776                 :            :                                    "Unable to find matching brace of endpoint, ignoring assignment: %s",
     777                 :            :                                    rvalue);
     778                 :          0 :                         return 0;
     779                 :            :                 }
     780                 :          0 :                 len = end - begin;
     781                 :          0 :                 ++end;
     782   [ #  #  #  # ]:          0 :                 if (*end != ':' || !*(end + 1)) {
     783         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
     784                 :            :                                    "Unable to find port of endpoint, ignoring assignment: %s",
     785                 :            :                                    rvalue);
     786                 :          0 :                         return 0;
     787                 :            :                 }
     788                 :          0 :                 ++end;
     789                 :            :         } else {
     790                 :          0 :                 begin = rvalue;
     791                 :          0 :                 end = strrchr(rvalue, ':');
     792   [ #  #  #  # ]:          0 :                 if (!end || !*(end + 1)) {
     793         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
     794                 :            :                                    "Unable to find port of endpoint, ignoring assignment: %s",
     795                 :            :                                    rvalue);
     796                 :          0 :                         return 0;
     797                 :            :                 }
     798                 :          0 :                 len = end - begin;
     799                 :          0 :                 ++end;
     800                 :            :         }
     801                 :            : 
     802                 :          0 :         r = free_and_strndup(&peer->endpoint_host, begin, len);
     803         [ #  # ]:          0 :         if (r < 0)
     804                 :          0 :                 return log_oom();
     805                 :            : 
     806                 :          0 :         r = free_and_strdup(&peer->endpoint_port, end);
     807         [ #  # ]:          0 :         if (r < 0)
     808                 :          0 :                 return log_oom();
     809                 :            : 
     810                 :          0 :         r = set_ensure_allocated(&w->peers_with_unresolved_endpoint, NULL);
     811         [ #  # ]:          0 :         if (r < 0)
     812                 :          0 :                 return log_oom();
     813                 :            : 
     814                 :          0 :         r = set_put(w->peers_with_unresolved_endpoint, peer);
     815         [ #  # ]:          0 :         if (r < 0)
     816                 :          0 :                 return r;
     817                 :            : 
     818                 :          0 :         TAKE_PTR(peer);
     819                 :          0 :         return 0;
     820                 :            : }
     821                 :            : 
     822                 :          0 : int config_parse_wireguard_keepalive(
     823                 :            :                 const char *unit,
     824                 :            :                 const char *filename,
     825                 :            :                 unsigned line,
     826                 :            :                 const char *section,
     827                 :            :                 unsigned section_line,
     828                 :            :                 const char *lvalue,
     829                 :            :                 int ltype,
     830                 :            :                 const char *rvalue,
     831                 :            :                 void *data,
     832                 :            :                 void *userdata) {
     833                 :            : 
     834                 :          0 :         _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
     835                 :          0 :         uint16_t keepalive = 0;
     836                 :            :         Wireguard *w;
     837                 :            :         int r;
     838                 :            : 
     839         [ #  # ]:          0 :         assert(rvalue);
     840         [ #  # ]:          0 :         assert(data);
     841                 :            : 
     842                 :          0 :         w = WIREGUARD(data);
     843         [ #  # ]:          0 :         assert(w);
     844                 :            : 
     845                 :          0 :         r = wireguard_peer_new_static(w, filename, section_line, &peer);
     846         [ #  # ]:          0 :         if (r < 0)
     847                 :          0 :                 return r;
     848                 :            : 
     849         [ #  # ]:          0 :         if (streq(rvalue, "off"))
     850                 :          0 :                 keepalive = 0;
     851                 :            :         else {
     852                 :          0 :                 r = safe_atou16(rvalue, &keepalive);
     853         [ #  # ]:          0 :                 if (r < 0) {
     854         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
     855                 :            :                                    "The persistent keepalive interval must be 0-65535. Ignore assignment: %s",
     856                 :            :                                    rvalue);
     857                 :          0 :                         return 0;
     858                 :            :                 }
     859                 :            :         }
     860                 :            : 
     861                 :          0 :         peer->persistent_keepalive_interval = keepalive;
     862                 :            : 
     863                 :          0 :         TAKE_PTR(peer);
     864                 :          0 :         return 0;
     865                 :            : }
     866                 :            : 
     867                 :          0 : static void wireguard_init(NetDev *netdev) {
     868                 :            :         Wireguard *w;
     869                 :            : 
     870         [ #  # ]:          0 :         assert(netdev);
     871                 :          0 :         w = WIREGUARD(netdev);
     872         [ #  # ]:          0 :         assert(w);
     873                 :            : 
     874                 :          0 :         w->flags = WGDEVICE_F_REPLACE_PEERS;
     875                 :          0 : }
     876                 :            : 
     877                 :          0 : static void wireguard_done(NetDev *netdev) {
     878                 :            :         Wireguard *w;
     879                 :            : 
     880         [ #  # ]:          0 :         assert(netdev);
     881                 :          0 :         w = WIREGUARD(netdev);
     882         [ #  # ]:          0 :         assert(w);
     883                 :            : 
     884                 :          0 :         sd_event_source_unref(w->resolve_retry_event_source);
     885                 :            : 
     886                 :          0 :         explicit_bzero_safe(w->private_key, WG_KEY_LEN);
     887                 :          0 :         free(w->private_key_file);
     888                 :            : 
     889         [ #  # ]:          0 :         hashmap_free_with_destructor(w->peers_by_section, wireguard_peer_free);
     890                 :          0 :         set_free(w->peers_with_unresolved_endpoint);
     891                 :          0 :         set_free(w->peers_with_failed_endpoint);
     892                 :          0 : }
     893                 :            : 
     894                 :          0 : static int wireguard_read_key_file(const char *filename, uint8_t dest[static WG_KEY_LEN]) {
     895                 :          0 :         _cleanup_(erase_and_freep) char *key = NULL;
     896                 :            :         size_t key_len;
     897                 :            :         int r;
     898                 :            : 
     899         [ #  # ]:          0 :         if (!filename)
     900                 :          0 :                 return 0;
     901                 :            : 
     902         [ #  # ]:          0 :         assert(dest);
     903                 :            : 
     904                 :          0 :         r = read_full_file_full(filename, READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64, &key, &key_len);
     905         [ #  # ]:          0 :         if (r < 0)
     906                 :          0 :                 return r;
     907                 :            : 
     908         [ #  # ]:          0 :         if (key_len != WG_KEY_LEN)
     909                 :          0 :                 return -EINVAL;
     910                 :            : 
     911                 :          0 :         memcpy(dest, key, WG_KEY_LEN);
     912                 :          0 :         return 0;
     913                 :            : }
     914                 :            : 
     915                 :          0 : static int wireguard_peer_verify(WireguardPeer *peer) {
     916                 :          0 :         NetDev *netdev = NETDEV(peer->wireguard);
     917                 :            :         int r;
     918                 :            : 
     919         [ #  # ]:          0 :         if (section_is_invalid(peer->section))
     920                 :          0 :                 return -EINVAL;
     921                 :            : 
     922         [ #  # ]:          0 :         if (eqzero(peer->public_key))
     923         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
     924                 :            :                                               "%s: WireGuardPeer section without PublicKey= configured. "
     925                 :            :                                               "Ignoring [WireGuardPeer] section from line %u.",
     926                 :            :                                               peer->section->filename, peer->section->line);
     927                 :            : 
     928                 :          0 :         r = wireguard_read_key_file(peer->preshared_key_file, peer->preshared_key);
     929         [ #  # ]:          0 :         if (r < 0)
     930         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r,
     931                 :            :                                               "%s: Failed to read preshared key from '%s'. "
     932                 :            :                                               "Ignoring [WireGuardPeer] section from line %u.",
     933                 :            :                                               peer->section->filename, peer->preshared_key_file,
     934                 :            :                                               peer->section->line);
     935                 :            : 
     936                 :          0 :         return 0;
     937                 :            : }
     938                 :            : 
     939                 :          0 : static int wireguard_verify(NetDev *netdev, const char *filename) {
     940                 :            :         WireguardPeer *peer, *peer_next;
     941                 :            :         Wireguard *w;
     942                 :            :         int r;
     943                 :            : 
     944         [ #  # ]:          0 :         assert(netdev);
     945                 :          0 :         w = WIREGUARD(netdev);
     946         [ #  # ]:          0 :         assert(w);
     947                 :            : 
     948                 :          0 :         r = wireguard_read_key_file(w->private_key_file, w->private_key);
     949         [ #  # ]:          0 :         if (r < 0)
     950         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r,
     951                 :            :                                               "Failed to read private key from %s. Dropping network device %s.",
     952                 :            :                                               w->private_key_file, netdev->ifname);
     953                 :            : 
     954         [ #  # ]:          0 :         if (eqzero(w->private_key))
     955         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
     956                 :            :                                               "%s: Missing PrivateKey= or PrivateKeyFile=, "
     957                 :            :                                               "Dropping network device %s.",
     958                 :            :                                               filename, netdev->ifname);
     959                 :            : 
     960         [ #  # ]:          0 :         LIST_FOREACH_SAFE(peers, peer, peer_next, w->peers)
     961         [ #  # ]:          0 :                 if (wireguard_peer_verify(peer) < 0)
     962                 :          0 :                         wireguard_peer_free(peer);
     963                 :            : 
     964                 :          0 :         return 0;
     965                 :            : }
     966                 :            : 
     967                 :            : const NetDevVTable wireguard_vtable = {
     968                 :            :         .object_size = sizeof(Wireguard),
     969                 :            :         .sections = "Match\0NetDev\0WireGuard\0WireGuardPeer\0",
     970                 :            :         .post_create = netdev_wireguard_post_create,
     971                 :            :         .init = wireguard_init,
     972                 :            :         .done = wireguard_done,
     973                 :            :         .create_type = NETDEV_CREATE_INDEPENDENT,
     974                 :            :         .config_verify = wireguard_verify,
     975                 :            :         .generate_mac = true,
     976                 :            : };

Generated by: LCOV version 1.14