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