]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/netdev/wireguard.c
network: wireguard: rename and split set_wireguard_interface()
[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
56ba90c2
YW
258 if (!netdev->manager)
259 /* The netdev is detached. */
260 return 0;
e5719363 261
56ba90c2 262 assert(!w->unresolved_endpoints);
ae2a15bc 263 w->unresolved_endpoints = TAKE_PTR(w->failed_endpoints);
e5719363
JT
264
265 resolve_endpoints(netdev);
266
267 return 0;
268}
269
270/*
271 * Given the number of retries this function will return will an exponential
272 * increasing time in milliseconds to wait starting at 200ms and capped at 25 seconds.
273 */
274static int exponential_backoff_milliseconds(unsigned n_retries) {
275 return (2 << MAX(n_retries, 7U)) * 100 * USEC_PER_MSEC;
276}
277
278static int wireguard_resolve_handler(sd_resolve_query *q,
279 int ret,
280 const struct addrinfo *ai,
1061dab1 281 WireguardEndpoint *e) {
8173d1d0 282 _cleanup_(netdev_unrefp) NetDev *netdev_will_unrefed = NULL;
1061dab1 283 NetDev *netdev;
e5719363 284 Wireguard *w;
e5719363
JT
285 int r;
286
1061dab1
YW
287 assert(e);
288 assert(e->netdev);
e5719363 289
1061dab1 290 netdev = e->netdev;
e5719363
JT
291 w = WIREGUARD(netdev);
292 assert(w);
293
8173d1d0
YW
294 if (!netdev->manager)
295 /* The netdev is detached. */
296 return 0;
e5719363
JT
297
298 if (ret != 0) {
299 log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", e->host, e->port, gai_strerror(ret));
300 LIST_PREPEND(endpoints, w->failed_endpoints, e);
8173d1d0
YW
301 (void) sd_resolve_query_set_destroy_callback(q, NULL); /* Avoid freeing endpoint by destroy callback. */
302 netdev_will_unrefed = netdev; /* But netdev needs to be unrefed. */
e5719363 303 } else if ((ai->ai_family == AF_INET && ai->ai_addrlen == sizeof(struct sockaddr_in)) ||
8173d1d0 304 (ai->ai_family == AF_INET6 && ai->ai_addrlen == sizeof(struct sockaddr_in6)))
e5719363
JT
305 memcpy(&e->peer->endpoint, ai->ai_addr, ai->ai_addrlen);
306 else
307 log_netdev_error(netdev, "Neither IPv4 nor IPv6 address found for peer endpoint: %s:%s", e->host, e->port);
308
309 if (w->unresolved_endpoints) {
310 resolve_endpoints(netdev);
311 return 0;
312 }
313
e1f717d4 314 (void) wireguard_set_interface(netdev);
e5719363 315 if (w->failed_endpoints) {
56ba90c2
YW
316 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
317
e5719363
JT
318 w->n_retries++;
319 r = sd_event_add_time(netdev->manager->event,
56ba90c2 320 &s,
e5719363
JT
321 CLOCK_MONOTONIC,
322 now(CLOCK_MONOTONIC) + exponential_backoff_milliseconds(w->n_retries),
323 0,
324 on_resolve_retry,
325 netdev);
56ba90c2 326 if (r < 0) {
e5719363 327 log_netdev_warning_errno(netdev, r, "Could not arm resolve retry handler: %m");
56ba90c2
YW
328 return 0;
329 }
330
302a796f 331 r = sd_event_source_set_destroy_callback(s, (sd_event_destroy_t) netdev_destroy_callback);
56ba90c2
YW
332 if (r < 0) {
333 log_netdev_warning_errno(netdev, r, "Failed to set destroy callback to event source: %m");
334 return 0;
335 }
336
337 (void) sd_event_source_set_floating(s, true);
338 netdev_ref(netdev);
e5719363
JT
339 }
340
341 return 0;
342}
343
344static void resolve_endpoints(NetDev *netdev) {
e5719363
JT
345 static const struct addrinfo hints = {
346 .ai_family = AF_UNSPEC,
347 .ai_socktype = SOCK_DGRAM,
348 .ai_protocol = IPPROTO_UDP
349 };
8173d1d0
YW
350 WireguardEndpoint *endpoint;
351 Wireguard *w;
352 int r = 0;
e5719363
JT
353
354 assert(netdev);
355 w = WIREGUARD(netdev);
356 assert(w);
357
358 LIST_FOREACH(endpoints, endpoint, w->unresolved_endpoints) {
1061dab1
YW
359 r = resolve_getaddrinfo(netdev->manager->resolve,
360 NULL,
361 endpoint->host,
362 endpoint->port,
363 &hints,
364 wireguard_resolve_handler,
365 wireguard_endpoint_destroy_callback,
366 endpoint);
e5719363
JT
367
368 if (r == -ENOBUFS)
369 break;
8173d1d0
YW
370 if (r < 0) {
371 log_netdev_error_errno(netdev, r, "Failed to create resolver: %m");
372 continue;
373 }
e5719363 374
8173d1d0
YW
375 /* Avoid freeing netdev. It will be unrefed by the destroy callback. */
376 netdev_ref(netdev);
377
378 LIST_REMOVE(endpoints, w->unresolved_endpoints, endpoint);
e5719363
JT
379 }
380}
381
e5719363
JT
382static int netdev_wireguard_post_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
383 Wireguard *w;
384
385 assert(netdev);
386 w = WIREGUARD(netdev);
387 assert(w);
388
e1f717d4 389 (void) wireguard_set_interface(netdev);
e5719363
JT
390 resolve_endpoints(netdev);
391 return 0;
392}
393
394int config_parse_wireguard_listen_port(const char *unit,
395 const char *filename,
396 unsigned line,
397 const char *section,
398 unsigned section_line,
399 const char *lvalue,
400 int ltype,
401 const char *rvalue,
402 void *data,
403 void *userdata) {
404 uint16_t *s = data;
405 uint16_t port = 0;
406 int r;
407
408 assert(rvalue);
409 assert(data);
410
411 if (!streq(rvalue, "auto")) {
412 r = parse_ip_port(rvalue, &port);
413 if (r < 0)
414 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid port specification, ignoring assignment: %s", rvalue);
415 }
416
417 *s = port;
418
419 return 0;
420}
421
422static int parse_wireguard_key(const char *unit,
423 const char *filename,
424 unsigned line,
425 const char *section,
426 unsigned section_line,
427 const char *lvalue,
428 int ltype,
429 const char *rvalue,
430 void *data,
431 void *userdata) {
432 _cleanup_free_ void *key = NULL;
433 size_t len;
434 int r;
435
436 assert(filename);
437 assert(rvalue);
438 assert(userdata);
439
440 r = unbase64mem(rvalue, strlen(rvalue), &key, &len);
441 if (r < 0) {
442 log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse wireguard key \"%s\", ignoring assignment: %m", rvalue);
443 return 0;
444 }
445 if (len != WG_KEY_LEN) {
446 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
447 "Wireguard key is too short, ignoring assignment: %s", rvalue);
448 return 0;
449 }
450
451 memcpy(userdata, key, WG_KEY_LEN);
452 return true;
453}
454
455int config_parse_wireguard_private_key(const char *unit,
456 const char *filename,
457 unsigned line,
458 const char *section,
459 unsigned section_line,
460 const char *lvalue,
461 int ltype,
462 const char *rvalue,
463 void *data,
464 void *userdata) {
465 Wireguard *w;
466
467 assert(data);
468
469 w = WIREGUARD(data);
470
471 assert(w);
472
473 return parse_wireguard_key(unit,
474 filename,
475 line,
476 section,
477 section_line,
478 lvalue,
479 ltype,
480 rvalue,
481 data,
482 &w->private_key);
483
484}
485
486int config_parse_wireguard_preshared_key(const char *unit,
487 const char *filename,
488 unsigned line,
489 const char *section,
490 unsigned section_line,
491 const char *lvalue,
492 int ltype,
493 const char *rvalue,
494 void *data,
495 void *userdata) {
496 Wireguard *w;
497 WireguardPeer *peer;
498
499 assert(data);
500
501 w = WIREGUARD(data);
502
503 assert(w);
504
505 peer = wireguard_peer_new(w, section_line);
506 if (!peer)
507 return log_oom();
508
509 return parse_wireguard_key(unit,
510 filename,
511 line,
512 section,
513 section_line,
514 lvalue,
515 ltype,
516 rvalue,
517 data,
518 peer->preshared_key);
519}
520
e5719363
JT
521int config_parse_wireguard_public_key(const char *unit,
522 const char *filename,
523 unsigned line,
524 const char *section,
525 unsigned section_line,
526 const char *lvalue,
527 int ltype,
528 const char *rvalue,
529 void *data,
530 void *userdata) {
531 Wireguard *w;
532 WireguardPeer *peer;
533
534 assert(data);
535
536 w = WIREGUARD(data);
537
538 assert(w);
539
540 peer = wireguard_peer_new(w, section_line);
541 if (!peer)
542 return log_oom();
543
544 return parse_wireguard_key(unit,
545 filename,
546 line,
547 section,
548 section_line,
549 lvalue,
550 ltype,
551 rvalue,
552 data,
553 peer->public_key);
554}
555
556int config_parse_wireguard_allowed_ips(const char *unit,
557 const char *filename,
558 unsigned line,
559 const char *section,
560 unsigned section_line,
561 const char *lvalue,
562 int ltype,
563 const char *rvalue,
564 void *data,
565 void *userdata) {
566 union in_addr_union addr;
567 unsigned char prefixlen;
568 int r, family;
569 Wireguard *w;
570 WireguardPeer *peer;
571 WireguardIPmask *ipmask;
572
573 assert(rvalue);
574 assert(data);
575
576 w = WIREGUARD(data);
577
578 peer = wireguard_peer_new(w, section_line);
579 if (!peer)
580 return log_oom();
581
582 for (;;) {
583 _cleanup_free_ char *word = NULL;
584
585 r = extract_first_word(&rvalue, &word, "," WHITESPACE, 0);
586 if (r == 0)
587 break;
588 if (r == -ENOMEM)
589 return log_oom();
590 if (r < 0) {
591 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split allowed ips \"%s\" option: %m", rvalue);
592 break;
593 }
594
595 r = in_addr_prefix_from_string_auto(word, &family, &addr, &prefixlen);
596 if (r < 0) {
597 log_syntax(unit, LOG_ERR, filename, line, r, "Network address is invalid, ignoring assignment: %s", word);
598 return 0;
599 }
600
fc721553 601 ipmask = new(WireguardIPmask, 1);
e5719363
JT
602 if (!ipmask)
603 return log_oom();
fc721553
YW
604
605 *ipmask = (WireguardIPmask) {
606 .family = family,
607 .ip.in6 = addr.in6,
608 .cidr = prefixlen,
609 };
e5719363
JT
610
611 LIST_PREPEND(ipmasks, peer->ipmasks, ipmask);
612 }
613
614 return 0;
615}
616
617int config_parse_wireguard_endpoint(const char *unit,
618 const char *filename,
619 unsigned line,
620 const char *section,
621 unsigned section_line,
622 const char *lvalue,
623 int ltype,
624 const char *rvalue,
625 void *data,
626 void *userdata) {
627 Wireguard *w;
628 WireguardPeer *peer;
629 size_t len;
630 const char *begin, *end = NULL;
631 _cleanup_free_ char *host = NULL, *port = NULL;
632 _cleanup_(wireguard_endpoint_freep) WireguardEndpoint *endpoint = NULL;
633
634 assert(data);
635 assert(rvalue);
636
637 w = WIREGUARD(data);
638
639 assert(w);
640
641 peer = wireguard_peer_new(w, section_line);
642 if (!peer)
643 return log_oom();
644
e5719363
JT
645 if (rvalue[0] == '[') {
646 begin = &rvalue[1];
647 end = strchr(rvalue, ']');
648 if (!end) {
649 log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find matching brace of endpoint, ignoring assignment: %s", rvalue);
650 return 0;
651 }
652 len = end - begin;
653 ++end;
654 if (*end != ':' || !*(end + 1)) {
655 log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find port of endpoint: %s", rvalue);
656 return 0;
657 }
658 ++end;
659 } else {
660 begin = rvalue;
661 end = strrchr(rvalue, ':');
662 if (!end || !*(end + 1)) {
663 log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find port of endpoint: %s", rvalue);
664 return 0;
665 }
666 len = end - begin;
667 ++end;
668 }
669
670 host = strndup(begin, len);
671 if (!host)
672 return log_oom();
673
674 port = strdup(end);
675 if (!port)
676 return log_oom();
677
fc721553
YW
678 endpoint = new(WireguardEndpoint, 1);
679 if (!endpoint)
680 return log_oom();
681
682 *endpoint = (WireguardEndpoint) {
683 .peer = TAKE_PTR(peer),
684 .host = TAKE_PTR(host),
685 .port = TAKE_PTR(port),
686 .netdev = data,
687 };
8173d1d0 688 LIST_PREPEND(endpoints, w->unresolved_endpoints, TAKE_PTR(endpoint));
e5719363
JT
689
690 return 0;
691}
692
693int config_parse_wireguard_keepalive(const char *unit,
694 const char *filename,
695 unsigned line,
696 const char *section,
697 unsigned section_line,
698 const char *lvalue,
699 int ltype,
700 const char *rvalue,
701 void *data,
702 void *userdata) {
703 int r;
704 uint16_t keepalive = 0;
705 Wireguard *w;
706 WireguardPeer *peer;
707
708 assert(rvalue);
709 assert(data);
710
711 w = WIREGUARD(data);
712
713 assert(w);
714
715 peer = wireguard_peer_new(w, section_line);
716 if (!peer)
717 return log_oom();
718
719 if (streq(rvalue, "off"))
720 keepalive = 0;
721 else {
722 r = safe_atou16(rvalue, &keepalive);
723 if (r < 0)
724 log_syntax(unit, LOG_ERR, filename, line, r, "The persistent keepalive interval must be 0-65535. Ignore assignment: %s", rvalue);
725 }
726
727 peer->persistent_keepalive_interval = keepalive;
728 return 0;
729}
730
731static void wireguard_init(NetDev *netdev) {
732 Wireguard *w;
733
734 assert(netdev);
735
736 w = WIREGUARD(netdev);
737
738 assert(w);
739
740 w->flags = WGDEVICE_F_REPLACE_PEERS;
741}
742
743static void wireguard_done(NetDev *netdev) {
744 Wireguard *w;
745 WireguardPeer *peer;
746 WireguardIPmask *mask;
c195364d 747 WireguardEndpoint *e;
e5719363
JT
748
749 assert(netdev);
750 w = WIREGUARD(netdev);
c195364d 751 assert(w);
e5719363
JT
752
753 while ((peer = w->peers)) {
754 LIST_REMOVE(peers, w->peers, peer);
755 while ((mask = peer->ipmasks)) {
756 LIST_REMOVE(ipmasks, peer->ipmasks, mask);
757 free(mask);
758 }
759 free(peer);
760 }
c195364d
YW
761
762 while ((e = w->unresolved_endpoints)) {
763 LIST_REMOVE(endpoints, w->unresolved_endpoints, e);
764 wireguard_endpoint_free(e);
765 }
766
767 while ((e = w->failed_endpoints)) {
768 LIST_REMOVE(endpoints, w->failed_endpoints, e);
769 wireguard_endpoint_free(e);
770 }
e5719363
JT
771}
772
773const NetDevVTable wireguard_vtable = {
774 .object_size = sizeof(Wireguard),
775 .sections = "Match\0NetDev\0WireGuard\0WireGuardPeer\0",
776 .post_create = netdev_wireguard_post_create,
777 .init = wireguard_init,
778 .done = wireguard_done,
779 .create_type = NETDEV_CREATE_INDEPENDENT,
780};