1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
5 * Based on wireguard-tools:
6 * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
16 #include <sys/types.h>
17 #include <sys/socket.h>
20 #include <arpa/inet.h>
25 #define SOCK_PATH RUNSTATEDIR "/wireguard/"
26 #define SOCK_SUFFIX ".sock"
40 key_to_hex(char hex
[static WG_KEY_LEN_HEX
], const uint8_t key
[static WG_KEY_LEN
])
44 for (i
= 0; i
< WG_KEY_LEN
; ++i
) {
45 hex
[i
* 2] = 87U + (key
[i
] >> 4) + ((((key
[i
] >> 4) - 10U) >> 8) & ~38U);
46 hex
[i
* 2 + 1] = 87U + (key
[i
] & 0xf) + ((((key
[i
] & 0xf) - 10U) >> 8) & ~38U);
53 key_from_hex(uint8_t key
[static WG_KEY_LEN
], const char *hex
)
55 uint8_t c
, c_acc
, c_alpha0
, c_alpha
, c_num0
, c_num
, c_val
;
56 volatile uint8_t ret
= 0;
58 if (strlen(hex
) != WG_KEY_LEN_HEX
- 1)
61 for (unsigned int i
= 0; i
< WG_KEY_LEN_HEX
- 1; i
+= 2) {
64 c_num0
= (c_num
- 10U) >> 8;
65 c_alpha
= (c
& ~32U) - 55U;
66 c_alpha0
= ((c_alpha
- 10U) ^ (c_alpha
- 16U)) >> 8;
67 ret
|= ((c_num0
| c_alpha0
) - 1) >> 8;
68 c_val
= (c_num0
& c_num
) | (c_alpha0
& c_alpha
);
71 c
= (uint8_t)hex
[i
+ 1];
73 c_num0
= (c_num
- 10U) >> 8;
74 c_alpha
= (c
& ~32U) - 55U;
75 c_alpha0
= ((c_alpha
- 10U) ^ (c_alpha
- 16U)) >> 8;
76 ret
|= ((c_num0
| c_alpha0
) - 1) >> 8;
77 c_val
= (c_num0
& c_num
) | (c_alpha0
& c_alpha
);
78 key
[i
/ 2] = c_acc
| c_val
;
81 return 1 & ((ret
- 1) >> 8);
84 static bool wg_user_check(struct network
*net
)
86 struct sockaddr_un addr
= { .sun_family
= AF_UNIX
};
90 if (snprintf(addr
.sun_path
, sizeof(addr
.sun_path
), SOCK_PATH
"%s" SOCK_SUFFIX
, network_name(net
)) < 0)
92 if (stat(addr
.sun_path
, &sbuf
) < 0)
94 if (!S_ISSOCK(sbuf
.st_mode
))
96 ret
= fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
99 ret
= connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
100 if (ret
< 0 && errno
== ECONNREFUSED
) { /* If the process is gone, we try to clean up the socket. */
102 unlink(addr
.sun_path
);
109 static FILE *wg_user_file(struct network
*net
)
112 struct sockaddr_un addr
= { .sun_family
= AF_UNIX
};
117 ret
= snprintf(addr
.sun_path
, sizeof(addr
.sun_path
), SOCK_PATH
"%s" SOCK_SUFFIX
, network_name(net
));
120 ret
= stat(addr
.sun_path
, &sbuf
);
124 if (!S_ISSOCK(sbuf
.st_mode
))
127 ret
= fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
131 ret
= connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
133 if (errno
== ECONNREFUSED
) /* If the process is gone, we try to clean up the socket. */
134 unlink(addr
.sun_path
);
137 f
= fdopen(fd
, "r+");
151 static void wg_req_set(struct wg_req
*req
, const char *key
, const char *value
)
153 fprintf(req
->f
, "%s=%s\n", key
, value
);
156 static void wg_req_set_int(struct wg_req
*req
, const char *key
, int value
)
158 fprintf(req
->f
, "%s=%d\n", key
, value
);
161 #define wg_req_printf(req, name, format, ...) fprintf((req)->f, "%s=" format "\n", name, ##__VA_ARGS__)
163 static int wg_req_init(struct wg_req
*req
, struct network
*net
, bool set
)
165 memset(req
, 0, sizeof(*req
));
167 req
->f
= wg_user_file(net
);
171 wg_req_set(req
, set
? "set" : "get", "1");
176 static bool wg_req_fetch(struct wg_req
*req
)
181 fprintf(req
->f
, "\n");
185 if (getline(&req
->buf
, &req
->buf_len
, req
->f
) <= 0)
189 len
= strlen(req
->key
);
190 if (len
== 1 && req
->key
[0] == '\n')
193 req
->value
= strchr(req
->key
, '=');
194 if (!req
->value
|| !len
|| req
->key
[len
- 1] != '\n')
197 *(req
->value
++) = req
->key
[--len
] = 0;
198 if (!strcmp(req
->key
, "errno"))
199 req
->ret
= atoi(req
->value
);
204 static void wg_req_complete(struct wg_req
*req
)
206 while (wg_req_fetch(req
));
209 static int wg_req_done(struct wg_req
*req
)
212 wg_req_complete(req
);
222 wg_user_test(struct network
*net
)
226 if (wg_req_init(&req
, net
, false))
229 return wg_req_done(&req
);
233 wg_network_reset(struct network
*net
, uint8_t *key
)
236 char key_str
[WG_KEY_LEN_HEX
];
238 if (wg_req_init(&req
, net
, true))
241 wg_req_set(&req
, "replace_peers", "true");
243 key_to_hex(key_str
, key
);
244 wg_req_set(&req
, "private_key", key_str
);
246 return wg_req_done(&req
);
250 wg_user_init(struct network
*net
)
254 err
= wg_user_test(net
);
258 return wg_network_reset(net
, net
->config
.key
);
262 wg_user_cleanup(struct network
*net
)
264 uint8_t key
[WG_KEY_LEN
] = {};
266 wg_network_reset(net
, key
);
270 wg_user_init_local(struct network
*net
, struct network_peer
*peer
)
274 if (wg_req_init(&req
, net
, true))
277 wg_req_set_int(&req
, "listen_port", peer
? peer
->port
: 0);
279 return wg_req_done(&req
);
283 wg_user_peer_req_add_allowed_ip(struct wg_req
*req
, struct network_peer
*peer
)
285 char addr
[INET6_ADDRSTRLEN
];
286 struct blob_attr
*cur
;
289 inet_ntop(AF_INET6
, &peer
->local_addr
.in6
, addr
, sizeof(addr
));
290 wg_req_printf(req
, "allowed_ip", "%s/128", addr
);
292 blobmsg_for_each_attr(cur
, peer
->ipaddr
, rem
) {
293 const char *str
= blobmsg_get_string(cur
);
297 if (strchr(str
, ':')) {
305 if (inet_pton(af
, str
, &in6
) != 1)
308 wg_req_printf(req
, "allowed_ip", "%s/%d", str
, mask
);
311 blobmsg_for_each_attr(cur
, peer
->subnet
, rem
) {
312 const char *str
= blobmsg_get_string(cur
);
313 char buf
[INET6_ADDRSTRLEN
];
314 union network_addr addr
;
318 af
= strchr(str
, ':') ? AF_INET6
: AF_INET
;
319 if (network_get_subnet(af
, &addr
, &mask
, str
))
322 inet_ntop(af
, &addr
, buf
, sizeof(buf
));
323 wg_req_printf(req
, "allowed_ip", "%s/%d", buf
, mask
);
328 wg_user_peer_update(struct network
*net
, struct network_peer
*peer
, enum wg_update_cmd cmd
)
330 struct network_host
*host
;
332 char key
[WG_KEY_LEN_HEX
];
334 if (wg_req_init(&req
, net
, true))
337 key_to_hex(key
, peer
->key
);
338 wg_req_set(&req
, "public_key", key
);
340 if (cmd
== WG_PEER_DELETE
) {
341 wg_req_set(&req
, "remove", "true");
345 wg_req_set(&req
, "replace_allowed_ips", "true");
346 wg_user_peer_req_add_allowed_ip(&req
, peer
);
347 for_each_routed_host(host
, net
, peer
)
348 wg_user_peer_req_add_allowed_ip(&req
, &host
->peer
);
351 return wg_req_done(&req
);
355 wg_user_peer_refresh(struct network
*net
)
357 struct network_peer
*peer
= NULL
;
359 uint8_t key
[WG_KEY_LEN
];
360 time_t now
= time(NULL
);
362 if (wg_req_init(&req
, net
, false))
365 while (wg_req_fetch(&req
)) {
366 if (!strcmp(req
.key
, "public_key")) {
368 wg_peer_update_done(net
, peer
);
369 if (key_from_hex(key
, req
.value
))
370 peer
= wg_peer_update_start(net
, key
);
379 if (!strcmp(req
.key
, "last_handshake_time_sec")) {
380 uint64_t sec
= strtoull(req
.value
, NULL
, 0);
382 wg_peer_set_last_handshake(net
, peer
, now
, sec
);
386 if (!strcmp(req
.key
, "rx_bytes")) {
387 uint64_t bytes
= strtoull(req
.value
, NULL
, 0);
389 wg_peer_set_rx_bytes(net
, peer
, bytes
);
393 if (!strcmp(req
.key
, "endpoint")) {
394 struct addrinfo
*resolved
;
395 struct addrinfo hints
= {
396 .ai_family
= AF_UNSPEC
,
397 .ai_socktype
= SOCK_DGRAM
,
398 .ai_protocol
= IPPROTO_UDP
,
402 if (!strlen(req
.value
))
405 if (req
.value
[0] == '[') {
407 port
= strchr(req
.value
, ']');
415 port
= strchr(req
.value
, ':');
425 if (getaddrinfo(req
.value
, port
, &hints
, &resolved
) != 0)
428 if ((resolved
->ai_family
== AF_INET
&& resolved
->ai_addrlen
== sizeof(struct sockaddr_in
)) ||
429 (resolved
->ai_family
== AF_INET6
&& resolved
->ai_addrlen
== sizeof(struct sockaddr_in6
)))
430 wg_peer_set_endpoint(net
, peer
, resolved
->ai_addr
, resolved
->ai_addrlen
);
432 freeaddrinfo(resolved
);
438 wg_peer_update_done(net
, peer
);
440 return wg_req_done(&req
);
444 wg_user_peer_connect(struct network
*net
, struct network_peer
*peer
,
445 union network_endpoint
*ep
)
448 char addr
[INET6_ADDRSTRLEN
];
449 char key
[WG_KEY_LEN_HEX
];
453 if (wg_req_init(&req
, net
, true))
456 key_to_hex(key
, peer
->key
);
457 wg_req_set(&req
, "public_key", key
);
459 if (ep
->in
.sin_family
== AF_INET6
)
460 ip
= &ep
->in6
.sin6_addr
;
462 ip
= &ep
->in
.sin_addr
;
464 inet_ntop(ep
->in
.sin_family
, ip
, addr
, sizeof(addr
));
465 port
= ntohs(ep
->in
.sin_port
);
467 if (ep
->in
.sin_family
== AF_INET6
)
468 wg_req_printf(&req
, "endpoint", "[%s]:%d", addr
, port
);
470 wg_req_printf(&req
, "endpoint", "%s:%d", addr
, port
);
472 if (net
->net_config
.keepalive
) {
473 wg_req_set_int(&req
, "persistent_keepalive_interval", 0);
474 wg_req_set_int(&req
, "persistent_keepalive_interval",
475 net
->net_config
.keepalive
);
478 return wg_req_done(&req
);
481 const struct wg_ops wg_user_ops
= {
483 .check
= wg_user_check
,
484 .init
= wg_user_init
,
485 .cleanup
= wg_user_cleanup
,
486 .init_local
= wg_user_init_local
,
487 .peer_update
= wg_user_peer_update
,
488 .peer_refresh
= wg_user_peer_refresh
,
489 .peer_connect
= wg_user_peer_connect
,