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