]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/netdev/wireguard.c
kernel-install: fix dracut initrd detection (240 backward compatibility) (#11570)
[thirdparty/systemd.git] / src / network / netdev / wireguard.c
CommitLineData
d506b89c 1/* SPDX-License-Identifier: LGPL-2.1+ */
e5719363 2/***
96b2fb93 3 Copyright © 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
e5719363
JT
4***/
5
6#include <sys/ioctl.h>
7#include <net/if.h>
8
8173d1d0
YW
9#include "sd-resolve.h"
10
e5719363 11#include "alloc-util.h"
e5719363 12#include "fd-util.h"
e5719363 13#include "hexdecoct.h"
e5719363 14#include "networkd-link.h"
e5719363 15#include "networkd-manager.h"
a4c9ae40
YW
16#include "networkd-util.h"
17#include "parse-util.h"
1061dab1 18#include "resolve-private.h"
a4c9ae40
YW
19#include "string-util.h"
20#include "strv.h"
21#include "wireguard.h"
e5719363
JT
22#include "wireguard-netlink.h"
23
24static void resolve_endpoints(NetDev *netdev);
25
26static WireguardPeer *wireguard_peer_new(Wireguard *w, unsigned section) {
27 WireguardPeer *peer;
28
29 assert(w);
30
31 if (w->last_peer_section == section && w->peers)
32 return w->peers;
33
fc721553 34 peer = new(WireguardPeer, 1);
e5719363
JT
35 if (!peer)
36 return NULL;
fc721553
YW
37
38 *peer = (WireguardPeer) {
39 .flags = WGPEER_F_REPLACE_ALLOWEDIPS,
40 };
e5719363
JT
41
42 LIST_PREPEND(peers, w->peers, peer);
43 w->last_peer_section = section;
44
45 return peer;
46}
47
e1f717d4 48static int wireguard_set_ipmask_one(NetDev *netdev, sd_netlink_message *message, const WireguardIPmask *mask, uint16_t index) {
e5719363 49 int r;
e1f717d4
YW
50
51 assert(message);
52 assert(mask);
53 assert(index > 0);
54
55 /* This returns 1 on success, 0 on recoverable error, and negative errno on failure. */
56
57 r = sd_netlink_message_open_array(message, index);
58 if (r < 0)
59 return 0;
60
61 r = sd_netlink_message_append_u16(message, WGALLOWEDIP_A_FAMILY, mask->family);
62 if (r < 0)
63 goto cancel;
64
65 if (mask->family == AF_INET)
66 r = sd_netlink_message_append_in_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in);
67 else if (mask->family == AF_INET6)
68 r = sd_netlink_message_append_in6_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in6);
69 if (r < 0)
70 goto cancel;
71
72 r = sd_netlink_message_append_u8(message, WGALLOWEDIP_A_CIDR_MASK, mask->cidr);
73 if (r < 0)
74 goto cancel;
75
76 r = sd_netlink_message_close_container(message);
77 if (r < 0)
78 return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m");
79
80 return 1;
81
82cancel:
83 r = sd_netlink_message_cancel_array(message);
84 if (r < 0)
85 return log_netdev_error_errno(netdev, r, "Could not cancel wireguard allowed ip message attribute: %m");
86
87 return 0;
88}
89
90static int wireguard_set_peer_one(NetDev *netdev, sd_netlink_message *message, const WireguardPeer *peer, uint16_t index, WireguardIPmask **mask_start) {
91 WireguardIPmask *mask, *start;
92 uint16_t j = 0;
93 int r;
94
95 assert(message);
96 assert(peer);
97 assert(index > 0);
98 assert(mask_start);
99
100 /* This returns 1 on success, 0 on recoverable error, and negative errno on failure. */
101
102 start = *mask_start ?: peer->ipmasks;
103
104 r = sd_netlink_message_open_array(message, index);
105 if (r < 0)
106 return 0;
107
108 r = sd_netlink_message_append_data(message, WGPEER_A_PUBLIC_KEY, &peer->public_key, sizeof(peer->public_key));
109 if (r < 0)
110 goto cancel;
111
112 if (!start) {
113 r = sd_netlink_message_append_data(message, WGPEER_A_PRESHARED_KEY, &peer->preshared_key, WG_KEY_LEN);
114 if (r < 0)
115 goto cancel;
116
117 r = sd_netlink_message_append_u32(message, WGPEER_A_FLAGS, peer->flags);
118 if (r < 0)
119 goto cancel;
120
121 r = sd_netlink_message_append_u16(message, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval);
122 if (r < 0)
123 goto cancel;
124
125 if (peer->endpoint.sa.sa_family == AF_INET)
126 r = sd_netlink_message_append_data(message, WGPEER_A_ENDPOINT, &peer->endpoint.in, sizeof(peer->endpoint.in));
127 else if (peer->endpoint.sa.sa_family == AF_INET6)
128 r = sd_netlink_message_append_data(message, WGPEER_A_ENDPOINT, &peer->endpoint.in6, sizeof(peer->endpoint.in6));
129 if (r < 0)
130 goto cancel;
131 }
132
133 r = sd_netlink_message_open_container(message, WGPEER_A_ALLOWEDIPS);
134 if (r < 0)
135 goto cancel;
136
137 LIST_FOREACH(ipmasks, mask, start) {
138 r = wireguard_set_ipmask_one(netdev, message, mask, ++j);
139 if (r < 0)
140 return r;
141 if (r == 0)
142 break;
143 }
144
145 r = sd_netlink_message_close_container(message);
146 if (r < 0)
147 return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m");
148
149 r = sd_netlink_message_close_container(message);
150 if (r < 0)
151 return log_netdev_error_errno(netdev, r, "Could not add wireguard peer: %m");
152
153 *mask_start = mask; /* Start next cycle from this mask. */
154 return !mask;
155
156cancel:
157 r = sd_netlink_message_cancel_array(message);
158 if (r < 0)
159 return log_netdev_error_errno(netdev, r, "Could not cancel wireguard peers: %m");
160
161 return 0;
162}
163
164static int wireguard_set_interface(NetDev *netdev) {
e5719363 165 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
e1f717d4
YW
166 WireguardIPmask *mask_start = NULL;
167 WireguardPeer *peer, *peer_start;
e5719363 168 uint32_t serial;
e1f717d4
YW
169 Wireguard *w;
170 int r;
e5719363
JT
171
172 assert(netdev);
173 w = WIREGUARD(netdev);
174 assert(w);
175
e1f717d4
YW
176 for (peer_start = w->peers; peer_start; ) {
177 uint16_t i = 0;
e5719363 178
e5719363
JT
179 message = sd_netlink_message_unref(message);
180
181 r = sd_genl_message_new(netdev->manager->genl, SD_GENL_WIREGUARD, WG_CMD_SET_DEVICE, &message);
182 if (r < 0)
183 return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");
184
185 r = sd_netlink_message_append_string(message, WGDEVICE_A_IFNAME, netdev->ifname);
186 if (r < 0)
187 return log_netdev_error_errno(netdev, r, "Could not append wireguard interface name: %m");
188
189 if (peer_start == w->peers) {
190 r = sd_netlink_message_append_data(message, WGDEVICE_A_PRIVATE_KEY, &w->private_key, WG_KEY_LEN);
191 if (r < 0)
192 return log_netdev_error_errno(netdev, r, "Could not append wireguard private key: %m");
193
194 r = sd_netlink_message_append_u16(message, WGDEVICE_A_LISTEN_PORT, w->port);
195 if (r < 0)
196 return log_netdev_error_errno(netdev, r, "Could not append wireguard port: %m");
197
198 r = sd_netlink_message_append_u32(message, WGDEVICE_A_FWMARK, w->fwmark);
199 if (r < 0)
200 return log_netdev_error_errno(netdev, r, "Could not append wireguard fwmark: %m");
201
202 r = sd_netlink_message_append_u32(message, WGDEVICE_A_FLAGS, w->flags);
203 if (r < 0)
204 return log_netdev_error_errno(netdev, r, "Could not append wireguard flags: %m");
205 }
206
207 r = sd_netlink_message_open_container(message, WGDEVICE_A_PEERS);
208 if (r < 0)
209 return log_netdev_error_errno(netdev, r, "Could not append wireguard peer attributes: %m");
210
e5719363 211 LIST_FOREACH(peers, peer, peer_start) {
e1f717d4 212 r = wireguard_set_peer_one(netdev, message, peer, ++i, &mask_start);
e5719363 213 if (r < 0)
e1f717d4
YW
214 return r;
215 if (r == 0)
e5719363 216 break;
e5719363 217 }
e1f717d4 218 peer_start = peer; /* Start next cycle from this peer. */
e5719363
JT
219
220 r = sd_netlink_message_close_container(message);
221 if (r < 0)
222 return log_netdev_error_errno(netdev, r, "Could not close wireguard container: %m");
223
224 r = sd_netlink_send(netdev->manager->genl, message, &serial);
225 if (r < 0)
226 return log_netdev_error_errno(netdev, r, "Could not set wireguard device: %m");
e1f717d4 227 }
e5719363
JT
228
229 return 0;
230}
231
232static WireguardEndpoint* wireguard_endpoint_free(WireguardEndpoint *e) {
233 if (!e)
234 return NULL;
e5719363
JT
235 e->host = mfree(e->host);
236 e->port = mfree(e->port);
237 return mfree(e);
238}
239
1061dab1 240static void wireguard_endpoint_destroy_callback(WireguardEndpoint *e) {
8173d1d0
YW
241 assert(e);
242 assert(e->netdev);
243
244 netdev_unref(e->netdev);
245 wireguard_endpoint_free(e);
246}
247
e5719363
JT
248DEFINE_TRIVIAL_CLEANUP_FUNC(WireguardEndpoint*, wireguard_endpoint_free);
249
250static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
251 NetDev *netdev = userdata;
252 Wireguard *w;
253
254 assert(netdev);
255 w = WIREGUARD(netdev);
256 assert(w);
257
9e2bbf99 258 if (!netdev_is_managed(netdev))
56ba90c2 259 return 0;
e5719363 260
56ba90c2 261 assert(!w->unresolved_endpoints);
ae2a15bc 262 w->unresolved_endpoints = TAKE_PTR(w->failed_endpoints);
e5719363
JT
263
264 resolve_endpoints(netdev);
265
266 return 0;
267}
268
269/*
270 * Given the number of retries this function will return will an exponential
271 * increasing time in milliseconds to wait starting at 200ms and capped at 25 seconds.
272 */
273static int exponential_backoff_milliseconds(unsigned n_retries) {
274 return (2 << MAX(n_retries, 7U)) * 100 * USEC_PER_MSEC;
275}
276
277static int wireguard_resolve_handler(sd_resolve_query *q,
278 int ret,
279 const struct addrinfo *ai,
1061dab1 280 WireguardEndpoint *e) {
8173d1d0 281 _cleanup_(netdev_unrefp) NetDev *netdev_will_unrefed = NULL;
1061dab1 282 NetDev *netdev;
e5719363 283 Wireguard *w;
e5719363
JT
284 int r;
285
1061dab1
YW
286 assert(e);
287 assert(e->netdev);
e5719363 288
1061dab1 289 netdev = e->netdev;
e5719363
JT
290 w = WIREGUARD(netdev);
291 assert(w);
292
9e2bbf99 293 if (!netdev_is_managed(netdev))
8173d1d0 294 return 0;
e5719363
JT
295
296 if (ret != 0) {
297 log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", e->host, e->port, gai_strerror(ret));
298 LIST_PREPEND(endpoints, w->failed_endpoints, e);
8173d1d0
YW
299 (void) sd_resolve_query_set_destroy_callback(q, NULL); /* Avoid freeing endpoint by destroy callback. */
300 netdev_will_unrefed = netdev; /* But netdev needs to be unrefed. */
e5719363 301 } else if ((ai->ai_family == AF_INET && ai->ai_addrlen == sizeof(struct sockaddr_in)) ||
8173d1d0 302 (ai->ai_family == AF_INET6 && ai->ai_addrlen == sizeof(struct sockaddr_in6)))
e5719363
JT
303 memcpy(&e->peer->endpoint, ai->ai_addr, ai->ai_addrlen);
304 else
305 log_netdev_error(netdev, "Neither IPv4 nor IPv6 address found for peer endpoint: %s:%s", e->host, e->port);
306
307 if (w->unresolved_endpoints) {
308 resolve_endpoints(netdev);
309 return 0;
310 }
311
e1f717d4 312 (void) wireguard_set_interface(netdev);
e5719363 313 if (w->failed_endpoints) {
56ba90c2
YW
314 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
315
e5719363
JT
316 w->n_retries++;
317 r = sd_event_add_time(netdev->manager->event,
56ba90c2 318 &s,
e5719363
JT
319 CLOCK_MONOTONIC,
320 now(CLOCK_MONOTONIC) + exponential_backoff_milliseconds(w->n_retries),
321 0,
322 on_resolve_retry,
323 netdev);
56ba90c2 324 if (r < 0) {
e5719363 325 log_netdev_warning_errno(netdev, r, "Could not arm resolve retry handler: %m");
56ba90c2
YW
326 return 0;
327 }
328
302a796f 329 r = sd_event_source_set_destroy_callback(s, (sd_event_destroy_t) netdev_destroy_callback);
56ba90c2
YW
330 if (r < 0) {
331 log_netdev_warning_errno(netdev, r, "Failed to set destroy callback to event source: %m");
332 return 0;
333 }
334
335 (void) sd_event_source_set_floating(s, true);
336 netdev_ref(netdev);
e5719363
JT
337 }
338
339 return 0;
340}
341
342static void resolve_endpoints(NetDev *netdev) {
e5719363
JT
343 static const struct addrinfo hints = {
344 .ai_family = AF_UNSPEC,
345 .ai_socktype = SOCK_DGRAM,
346 .ai_protocol = IPPROTO_UDP
347 };
8173d1d0
YW
348 WireguardEndpoint *endpoint;
349 Wireguard *w;
350 int r = 0;
e5719363
JT
351
352 assert(netdev);
353 w = WIREGUARD(netdev);
354 assert(w);
355
356 LIST_FOREACH(endpoints, endpoint, w->unresolved_endpoints) {
1061dab1
YW
357 r = resolve_getaddrinfo(netdev->manager->resolve,
358 NULL,
359 endpoint->host,
360 endpoint->port,
361 &hints,
362 wireguard_resolve_handler,
363 wireguard_endpoint_destroy_callback,
364 endpoint);
e5719363
JT
365
366 if (r == -ENOBUFS)
367 break;
8173d1d0
YW
368 if (r < 0) {
369 log_netdev_error_errno(netdev, r, "Failed to create resolver: %m");
370 continue;
371 }
e5719363 372
8173d1d0
YW
373 /* Avoid freeing netdev. It will be unrefed by the destroy callback. */
374 netdev_ref(netdev);
375
376 LIST_REMOVE(endpoints, w->unresolved_endpoints, endpoint);
e5719363
JT
377 }
378}
379
e5719363
JT
380static int netdev_wireguard_post_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
381 Wireguard *w;
382
383 assert(netdev);
384 w = WIREGUARD(netdev);
385 assert(w);
386
e1f717d4 387 (void) wireguard_set_interface(netdev);
e5719363
JT
388 resolve_endpoints(netdev);
389 return 0;
390}
391
392int config_parse_wireguard_listen_port(const char *unit,
393 const char *filename,
394 unsigned line,
395 const char *section,
396 unsigned section_line,
397 const char *lvalue,
398 int ltype,
399 const char *rvalue,
400 void *data,
401 void *userdata) {
402 uint16_t *s = data;
403 uint16_t port = 0;
404 int r;
405
406 assert(rvalue);
407 assert(data);
408
409 if (!streq(rvalue, "auto")) {
410 r = parse_ip_port(rvalue, &port);
411 if (r < 0)
412 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid port specification, ignoring assignment: %s", rvalue);
413 }
414
415 *s = port;
416
417 return 0;
418}
419
420static int parse_wireguard_key(const char *unit,
421 const char *filename,
422 unsigned line,
423 const char *section,
424 unsigned section_line,
425 const char *lvalue,
426 int ltype,
427 const char *rvalue,
428 void *data,
429 void *userdata) {
430 _cleanup_free_ void *key = NULL;
431 size_t len;
432 int r;
433
434 assert(filename);
435 assert(rvalue);
436 assert(userdata);
437
438 r = unbase64mem(rvalue, strlen(rvalue), &key, &len);
439 if (r < 0) {
440 log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse wireguard key \"%s\", ignoring assignment: %m", rvalue);
441 return 0;
442 }
443 if (len != WG_KEY_LEN) {
444 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
445 "Wireguard key is too short, ignoring assignment: %s", rvalue);
446 return 0;
447 }
448
449 memcpy(userdata, key, WG_KEY_LEN);
450 return true;
451}
452
453int config_parse_wireguard_private_key(const char *unit,
454 const char *filename,
455 unsigned line,
456 const char *section,
457 unsigned section_line,
458 const char *lvalue,
459 int ltype,
460 const char *rvalue,
461 void *data,
462 void *userdata) {
463 Wireguard *w;
464
465 assert(data);
466
467 w = WIREGUARD(data);
468
469 assert(w);
470
471 return parse_wireguard_key(unit,
472 filename,
473 line,
474 section,
475 section_line,
476 lvalue,
477 ltype,
478 rvalue,
479 data,
480 &w->private_key);
481
482}
483
484int config_parse_wireguard_preshared_key(const char *unit,
485 const char *filename,
486 unsigned line,
487 const char *section,
488 unsigned section_line,
489 const char *lvalue,
490 int ltype,
491 const char *rvalue,
492 void *data,
493 void *userdata) {
494 Wireguard *w;
495 WireguardPeer *peer;
496
497 assert(data);
498
499 w = WIREGUARD(data);
500
501 assert(w);
502
503 peer = wireguard_peer_new(w, section_line);
504 if (!peer)
505 return log_oom();
506
507 return parse_wireguard_key(unit,
508 filename,
509 line,
510 section,
511 section_line,
512 lvalue,
513 ltype,
514 rvalue,
515 data,
516 peer->preshared_key);
517}
518
e5719363
JT
519int config_parse_wireguard_public_key(const char *unit,
520 const char *filename,
521 unsigned line,
522 const char *section,
523 unsigned section_line,
524 const char *lvalue,
525 int ltype,
526 const char *rvalue,
527 void *data,
528 void *userdata) {
529 Wireguard *w;
530 WireguardPeer *peer;
531
532 assert(data);
533
534 w = WIREGUARD(data);
535
536 assert(w);
537
538 peer = wireguard_peer_new(w, section_line);
539 if (!peer)
540 return log_oom();
541
542 return parse_wireguard_key(unit,
543 filename,
544 line,
545 section,
546 section_line,
547 lvalue,
548 ltype,
549 rvalue,
550 data,
551 peer->public_key);
552}
553
554int config_parse_wireguard_allowed_ips(const char *unit,
555 const char *filename,
556 unsigned line,
557 const char *section,
558 unsigned section_line,
559 const char *lvalue,
560 int ltype,
561 const char *rvalue,
562 void *data,
563 void *userdata) {
564 union in_addr_union addr;
565 unsigned char prefixlen;
566 int r, family;
567 Wireguard *w;
568 WireguardPeer *peer;
569 WireguardIPmask *ipmask;
570
571 assert(rvalue);
572 assert(data);
573
574 w = WIREGUARD(data);
575
576 peer = wireguard_peer_new(w, section_line);
577 if (!peer)
578 return log_oom();
579
580 for (;;) {
581 _cleanup_free_ char *word = NULL;
582
583 r = extract_first_word(&rvalue, &word, "," WHITESPACE, 0);
584 if (r == 0)
585 break;
586 if (r == -ENOMEM)
587 return log_oom();
588 if (r < 0) {
589 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split allowed ips \"%s\" option: %m", rvalue);
590 break;
591 }
592
593 r = in_addr_prefix_from_string_auto(word, &family, &addr, &prefixlen);
594 if (r < 0) {
595 log_syntax(unit, LOG_ERR, filename, line, r, "Network address is invalid, ignoring assignment: %s", word);
596 return 0;
597 }
598
fc721553 599 ipmask = new(WireguardIPmask, 1);
e5719363
JT
600 if (!ipmask)
601 return log_oom();
fc721553
YW
602
603 *ipmask = (WireguardIPmask) {
604 .family = family,
605 .ip.in6 = addr.in6,
606 .cidr = prefixlen,
607 };
e5719363
JT
608
609 LIST_PREPEND(ipmasks, peer->ipmasks, ipmask);
610 }
611
612 return 0;
613}
614
615int config_parse_wireguard_endpoint(const char *unit,
616 const char *filename,
617 unsigned line,
618 const char *section,
619 unsigned section_line,
620 const char *lvalue,
621 int ltype,
622 const char *rvalue,
623 void *data,
624 void *userdata) {
625 Wireguard *w;
626 WireguardPeer *peer;
627 size_t len;
628 const char *begin, *end = NULL;
629 _cleanup_free_ char *host = NULL, *port = NULL;
630 _cleanup_(wireguard_endpoint_freep) WireguardEndpoint *endpoint = NULL;
631
632 assert(data);
633 assert(rvalue);
634
635 w = WIREGUARD(data);
636
637 assert(w);
638
639 peer = wireguard_peer_new(w, section_line);
640 if (!peer)
641 return log_oom();
642
e5719363
JT
643 if (rvalue[0] == '[') {
644 begin = &rvalue[1];
645 end = strchr(rvalue, ']');
646 if (!end) {
647 log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find matching brace of endpoint, ignoring assignment: %s", rvalue);
648 return 0;
649 }
650 len = end - begin;
651 ++end;
652 if (*end != ':' || !*(end + 1)) {
653 log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find port of endpoint: %s", rvalue);
654 return 0;
655 }
656 ++end;
657 } else {
658 begin = rvalue;
659 end = strrchr(rvalue, ':');
660 if (!end || !*(end + 1)) {
661 log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find port of endpoint: %s", rvalue);
662 return 0;
663 }
664 len = end - begin;
665 ++end;
666 }
667
668 host = strndup(begin, len);
669 if (!host)
670 return log_oom();
671
672 port = strdup(end);
673 if (!port)
674 return log_oom();
675
fc721553
YW
676 endpoint = new(WireguardEndpoint, 1);
677 if (!endpoint)
678 return log_oom();
679
680 *endpoint = (WireguardEndpoint) {
681 .peer = TAKE_PTR(peer),
682 .host = TAKE_PTR(host),
683 .port = TAKE_PTR(port),
684 .netdev = data,
685 };
8173d1d0 686 LIST_PREPEND(endpoints, w->unresolved_endpoints, TAKE_PTR(endpoint));
e5719363
JT
687
688 return 0;
689}
690
691int config_parse_wireguard_keepalive(const char *unit,
692 const char *filename,
693 unsigned line,
694 const char *section,
695 unsigned section_line,
696 const char *lvalue,
697 int ltype,
698 const char *rvalue,
699 void *data,
700 void *userdata) {
701 int r;
702 uint16_t keepalive = 0;
703 Wireguard *w;
704 WireguardPeer *peer;
705
706 assert(rvalue);
707 assert(data);
708
709 w = WIREGUARD(data);
710
711 assert(w);
712
713 peer = wireguard_peer_new(w, section_line);
714 if (!peer)
715 return log_oom();
716
717 if (streq(rvalue, "off"))
718 keepalive = 0;
719 else {
720 r = safe_atou16(rvalue, &keepalive);
721 if (r < 0)
722 log_syntax(unit, LOG_ERR, filename, line, r, "The persistent keepalive interval must be 0-65535. Ignore assignment: %s", rvalue);
723 }
724
725 peer->persistent_keepalive_interval = keepalive;
726 return 0;
727}
728
729static void wireguard_init(NetDev *netdev) {
730 Wireguard *w;
731
732 assert(netdev);
733
734 w = WIREGUARD(netdev);
735
736 assert(w);
737
738 w->flags = WGDEVICE_F_REPLACE_PEERS;
739}
740
741static void wireguard_done(NetDev *netdev) {
742 Wireguard *w;
743 WireguardPeer *peer;
744 WireguardIPmask *mask;
c195364d 745 WireguardEndpoint *e;
e5719363
JT
746
747 assert(netdev);
748 w = WIREGUARD(netdev);
c195364d 749 assert(w);
e5719363
JT
750
751 while ((peer = w->peers)) {
752 LIST_REMOVE(peers, w->peers, peer);
753 while ((mask = peer->ipmasks)) {
754 LIST_REMOVE(ipmasks, peer->ipmasks, mask);
755 free(mask);
756 }
757 free(peer);
758 }
c195364d
YW
759
760 while ((e = w->unresolved_endpoints)) {
761 LIST_REMOVE(endpoints, w->unresolved_endpoints, e);
762 wireguard_endpoint_free(e);
763 }
764
765 while ((e = w->failed_endpoints)) {
766 LIST_REMOVE(endpoints, w->failed_endpoints, e);
767 wireguard_endpoint_free(e);
768 }
e5719363
JT
769}
770
771const NetDevVTable wireguard_vtable = {
772 .object_size = sizeof(Wireguard),
773 .sections = "Match\0NetDev\0WireGuard\0WireGuardPeer\0",
774 .post_create = netdev_wireguard_post_create,
775 .init = wireguard_init,
776 .done = wireguard_done,
777 .create_type = NETDEV_CREATE_INDEPENDENT,
778};