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
->port
);
279 return wg_req_done(&req
);
283 wg_user_peer_update(struct network
*net
, struct network_peer
*peer
, enum wg_update_cmd cmd
)
285 struct blob_attr
*cur
;
287 char addr
[INET6_ADDRSTRLEN
];
288 char key
[WG_KEY_LEN_HEX
];
291 if (wg_req_init(&req
, net
, true))
294 key_to_hex(key
, peer
->key
);
295 wg_req_set(&req
, "public_key", key
);
297 if (cmd
== WG_PEER_DELETE
) {
298 wg_req_set(&req
, "remove", "true");
302 wg_req_set(&req
, "replace_allowed_ips", "true");
304 inet_ntop(AF_INET6
, &peer
->local_addr
.in6
, addr
, sizeof(addr
));
305 wg_req_printf(&req
, "allowed_ip", "%s/128", addr
);
307 blobmsg_for_each_attr(cur
, peer
->ipaddr
, rem
) {
308 const char *str
= blobmsg_get_string(cur
);
312 if (strchr(str
, ':')) {
320 if (inet_pton(af
, str
, &in6
) != 1)
323 wg_req_printf(&req
, "allowed_ip", "%s/%d", str
, mask
);
326 blobmsg_for_each_attr(cur
, peer
->subnet
, rem
) {
327 const char *str
= blobmsg_get_string(cur
);
328 char buf
[INET6_ADDRSTRLEN
];
329 union network_addr addr
;
333 af
= strchr(str
, ':') ? AF_INET6
: AF_INET
;
334 if (network_get_subnet(af
, &addr
, &mask
, str
))
337 inet_ntop(af
, &addr
, buf
, sizeof(buf
));
338 wg_req_printf(&req
, "allowed_ip", "%s/%d", buf
, mask
);
342 return wg_req_done(&req
);
346 wg_user_peer_refresh(struct network
*net
)
348 struct network_peer
*peer
= NULL
;
350 uint8_t key
[WG_KEY_LEN
];
351 time_t now
= time(NULL
);
353 if (wg_req_init(&req
, net
, false))
356 while (wg_req_fetch(&req
)) {
357 if (!strcmp(req
.key
, "public_key")) {
359 wg_peer_update_done(net
, peer
);
360 if (key_from_hex(key
, req
.value
))
361 peer
= wg_peer_update_start(net
, key
);
370 if (!strcmp(req
.key
, "last_handshake_time_sec")) {
371 uint64_t sec
= strtoull(req
.value
, NULL
, 0);
373 wg_peer_set_last_handshake(net
, peer
, now
, sec
);
377 if (!strcmp(req
.key
, "rx_bytes")) {
378 uint64_t bytes
= strtoull(req
.value
, NULL
, 0);
380 wg_peer_set_rx_bytes(net
, peer
, bytes
);
384 if (!strcmp(req
.key
, "endpoint")) {
385 struct addrinfo
*resolved
;
386 struct addrinfo hints
= {
387 .ai_family
= AF_UNSPEC
,
388 .ai_socktype
= SOCK_DGRAM
,
389 .ai_protocol
= IPPROTO_UDP
,
393 if (!strlen(req
.value
))
396 if (req
.value
[0] == '[') {
398 port
= strchr(req
.value
, ']');
406 port
= strchr(req
.value
, ':');
416 if (getaddrinfo(req
.value
, port
, &hints
, &resolved
) != 0)
419 if ((resolved
->ai_family
== AF_INET
&& resolved
->ai_addrlen
== sizeof(struct sockaddr_in
)) ||
420 (resolved
->ai_family
== AF_INET6
&& resolved
->ai_addrlen
== sizeof(struct sockaddr_in6
)))
421 wg_peer_set_endpoint(net
, peer
, resolved
->ai_addr
, resolved
->ai_addrlen
);
423 freeaddrinfo(resolved
);
429 wg_peer_update_done(net
, peer
);
431 return wg_req_done(&req
);
435 wg_user_peer_connect(struct network
*net
, struct network_peer
*peer
,
436 union network_endpoint
*ep
)
439 char addr
[INET6_ADDRSTRLEN
];
440 char key
[WG_KEY_LEN_HEX
];
444 if (wg_req_init(&req
, net
, true))
447 key_to_hex(key
, peer
->key
);
448 wg_req_set(&req
, "public_key", key
);
450 if (ep
->in
.sin_family
== AF_INET6
)
451 ip
= &ep
->in6
.sin6_addr
;
453 ip
= &ep
->in
.sin_addr
;
455 inet_ntop(ep
->in
.sin_family
, ip
, addr
, sizeof(addr
));
456 port
= ntohs(ep
->in
.sin_port
);
458 if (ep
->in
.sin_family
== AF_INET6
)
459 wg_req_printf(&req
, "endpoint", "[%s]:%d", addr
, port
);
461 wg_req_printf(&req
, "endpoint", "%s:%d", addr
, port
);
463 if (net
->net_config
.keepalive
) {
464 wg_req_set_int(&req
, "persistent_keepalive_interval", 0);
465 wg_req_set_int(&req
, "persistent_keepalive_interval",
466 net
->net_config
.keepalive
);
469 return wg_req_done(&req
);
472 const struct wg_ops wg_user_ops
= {
474 .check
= wg_user_check
,
475 .init
= wg_user_init
,
476 .cleanup
= wg_user_cleanup
,
477 .init_local
= wg_user_init_local
,
478 .peer_update
= wg_user_peer_update
,
479 .peer_refresh
= wg_user_peer_refresh
,
480 .peer_connect
= wg_user_peer_connect
,