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