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