fix: formatting

This commit is contained in:
Mark Puha 2025-06-14 15:02:32 +02:00
parent 5d3c2a6096
commit 66de01f211
10 changed files with 3170 additions and 3696 deletions

View file

@ -6,13 +6,13 @@
#ifndef CONTAINERS_H #ifndef CONTAINERS_H
#define CONTAINERS_H #define CONTAINERS_H
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <net/if.h> #include <net/if.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <time.h>
#if defined(__linux__) #if defined(__linux__)
#include <linux/wireguard.h> #include <linux/wireguard.h>
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__)
@ -28,17 +28,14 @@
#endif #endif
/* Cross platform __kernel_timespec */ /* Cross platform __kernel_timespec */
struct timespec64 struct timespec64 {
{
int64_t tv_sec; int64_t tv_sec;
int64_t tv_nsec; int64_t tv_nsec;
}; };
struct wgallowedip struct wgallowedip {
{
uint16_t family; uint16_t family;
union union {
{
struct in_addr ip4; struct in_addr ip4;
struct in6_addr ip6; struct in6_addr ip6;
}; };
@ -46,8 +43,7 @@ struct wgallowedip
struct wgallowedip *next_allowedip; struct wgallowedip *next_allowedip;
}; };
enum enum {
{
WGPEER_REMOVE_ME = 1U << 0, WGPEER_REMOVE_ME = 1U << 0,
WGPEER_REPLACE_ALLOWEDIPS = 1U << 1, WGPEER_REPLACE_ALLOWEDIPS = 1U << 1,
WGPEER_HAS_PUBLIC_KEY = 1U << 2, WGPEER_HAS_PUBLIC_KEY = 1U << 2,
@ -57,15 +53,13 @@ enum
WGPEER_HAS_SPECIAL_HANDSHAKE = 1U << 6 WGPEER_HAS_SPECIAL_HANDSHAKE = 1U << 6
}; };
struct wgpeer struct wgpeer {
{
uint32_t flags; uint32_t flags;
uint8_t public_key[WG_KEY_LEN]; uint8_t public_key[WG_KEY_LEN];
uint8_t preshared_key[WG_KEY_LEN]; uint8_t preshared_key[WG_KEY_LEN];
union union {
{
struct sockaddr addr; struct sockaddr addr;
struct sockaddr_in addr4; struct sockaddr_in addr4;
struct sockaddr_in6 addr6; struct sockaddr_in6 addr6;
@ -82,8 +76,7 @@ struct wgpeer
struct wgpeer *next_peer; struct wgpeer *next_peer;
}; };
enum enum {
{
WGDEVICE_REPLACE_PEERS = 1U << 0, WGDEVICE_REPLACE_PEERS = 1U << 0,
WGDEVICE_HAS_PRIVATE_KEY = 1U << 1, WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
WGDEVICE_HAS_PUBLIC_KEY = 1U << 2, WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
@ -109,8 +102,7 @@ enum
WGDEVICE_HAS_ITIME = 1U << 22 WGDEVICE_HAS_ITIME = 1U << 22
}; };
struct wgdevice struct wgdevice {
{
char name[IFNAMSIZ]; char name[IFNAMSIZ];
uint32_t ifindex; uint32_t ifindex;
@ -144,23 +136,15 @@ struct wgdevice
uint32_t itime; uint32_t itime;
}; };
#define for_each_wgpeer(__dev, __peer) \ #define for_each_wgpeer(__dev, __peer) for ((__peer) = (__dev)->first_peer; (__peer); (__peer) = (__peer)->next_peer)
for ((__peer) = (__dev)->first_peer; (__peer); (__peer) = (__peer)->next_peer) #define for_each_wgallowedip(__peer, __allowedip) for ((__allowedip) = (__peer)->first_allowedip; (__allowedip); (__allowedip) = (__allowedip)->next_allowedip)
#define for_each_wgallowedip(__peer, __allowedip) \
for ((__allowedip) = (__peer)->first_allowedip; (__allowedip); \
(__allowedip) = (__allowedip)->next_allowedip)
static inline void free_wgdevice(struct wgdevice *dev) static inline void free_wgdevice(struct wgdevice *dev)
{ {
if (!dev) if (!dev)
return; return;
for (struct wgpeer *peer = dev->first_peer, *np = peer ? peer->next_peer : NULL; peer; for (struct wgpeer *peer = dev->first_peer, *np = peer ? peer->next_peer : NULL; peer; peer = np, np = peer ? peer->next_peer : NULL) {
peer = np, np = peer ? peer->next_peer : NULL) for (struct wgallowedip *allowedip = peer->first_allowedip, *na = allowedip ? allowedip->next_allowedip : NULL; allowedip; allowedip = na, na = allowedip ? allowedip->next_allowedip : NULL)
{
for (struct wgallowedip *allowedip = peer->first_allowedip,
*na = allowedip ? allowedip->next_allowedip : NULL;
allowedip;
allowedip = na, na = allowedip ? allowedip->next_allowedip : NULL)
free(allowedip); free(allowedip);
free(peer); free(peer);
} }

View file

@ -5,9 +5,9 @@
*/ */
#include <assert.h> #include <assert.h>
#include <dev/wg/if_wg.h>
#include <sys/nv.h> #include <sys/nv.h>
#include <sys/sockio.h> #include <sys/sockio.h>
#include <dev/wg/if_wg.h>
#define IPC_SUPPORTS_KERNEL_INTERFACE #define IPC_SUPPORTS_KERNEL_INTERFACE
@ -34,14 +34,12 @@ static int kernel_get_wireguard_interfaces(struct string_list* list)
ifgr.ifgr_groups = calloc(1, ifgr.ifgr_len); ifgr.ifgr_groups = calloc(1, ifgr.ifgr_len);
if (!ifgr.ifgr_groups) if (!ifgr.ifgr_groups)
return -errno; return -errno;
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) < 0) if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) < 0) {
{
ret = -errno; ret = -errno;
goto out; goto out;
} }
for (ifg = ifgr.ifgr_groups; ifg && ifgr.ifgr_len > 0; ++ifg) for (ifg = ifgr.ifgr_groups; ifg && ifgr.ifgr_len > 0; ++ifg) {
{
if ((ret = string_list_add(list, ifg->ifgrq_member)) < 0) if ((ret = string_list_add(list, ifg->ifgrq_member)) < 0)
goto out; goto out;
ifgr.ifgr_len -= sizeof(struct ifg_req); ifgr.ifgr_len -= sizeof(struct ifg_req);
@ -86,92 +84,72 @@ static int kernel_get_device(struct wgdevice** device, const char* ifname)
if (!nvl_device) if (!nvl_device)
goto err; goto err;
if (nvlist_exists_number(nvl_device, "listen-port")) if (nvlist_exists_number(nvl_device, "listen-port")) {
{
number = nvlist_get_number(nvl_device, "listen-port"); number = nvlist_get_number(nvl_device, "listen-port");
if (number <= UINT16_MAX) if (number <= UINT16_MAX) {
{
dev->listen_port = number; dev->listen_port = number;
dev->flags |= WGDEVICE_HAS_LISTEN_PORT; dev->flags |= WGDEVICE_HAS_LISTEN_PORT;
} }
} }
if (nvlist_exists_number(nvl_device, "jc")) if (nvlist_exists_number(nvl_device, "jc")) {
{
number = nvlist_get_number(nvl_device, "jc"); number = nvlist_get_number(nvl_device, "jc");
if (number <= UINT16_MAX) if (number <= UINT16_MAX){
{
dev->junk_packet_count = number; dev->junk_packet_count = number;
dev->flags |= WGDEVICE_HAS_JC; dev->flags |= WGDEVICE_HAS_JC;
} }
} }
if (nvlist_exists_number(nvl_device, "jmin")) if (nvlist_exists_number(nvl_device, "jmin")) {
{
number = nvlist_get_number(nvl_device, "jmin"); number = nvlist_get_number(nvl_device, "jmin");
if (number <= UINT16_MAX) if (number <= UINT16_MAX){
{
dev->junk_packet_min_size = number; dev->junk_packet_min_size = number;
dev->flags |= WGDEVICE_HAS_JMIN; dev->flags |= WGDEVICE_HAS_JMIN;
} }
} }
if (nvlist_exists_number(nvl_device, "jmax")) if (nvlist_exists_number(nvl_device, "jmax")) {
{
number = nvlist_get_number(nvl_device, "jmax"); number = nvlist_get_number(nvl_device, "jmax");
if (number <= UINT16_MAX) if (number <= UINT16_MAX){
{
dev->junk_packet_max_size = number; dev->junk_packet_max_size = number;
dev->flags |= WGDEVICE_HAS_JMAX; dev->flags |= WGDEVICE_HAS_JMAX;
} }
} }
if (nvlist_exists_number(nvl_device, "s1")) if (nvlist_exists_number(nvl_device, "s1")) {
{
number = nvlist_get_number(nvl_device, "s1"); number = nvlist_get_number(nvl_device, "s1");
if (number <= UINT16_MAX) if (number <= UINT16_MAX){
{
dev->init_packet_junk_size = number; dev->init_packet_junk_size = number;
dev->flags |= WGDEVICE_HAS_S1; dev->flags |= WGDEVICE_HAS_S1;
} }
} }
if (nvlist_exists_number(nvl_device, "s2")) if (nvlist_exists_number(nvl_device, "s2")) {
{
number = nvlist_get_number(nvl_device, "s2"); number = nvlist_get_number(nvl_device, "s2");
if (number <= UINT16_MAX) if (number <= UINT16_MAX){
{
dev->response_packet_junk_size = number; dev->response_packet_junk_size = number;
dev->flags |= WGDEVICE_HAS_S2; dev->flags |= WGDEVICE_HAS_S2;
} }
} }
if (nvlist_exists_number(nvl_device, "h1")) if (nvlist_exists_number(nvl_device, "h1")) {
{
number = nvlist_get_number(nvl_device, "h1"); number = nvlist_get_number(nvl_device, "h1");
if (number <= UINT32_MAX) if (number <= UINT32_MAX){
{
dev->init_packet_magic_header = number; dev->init_packet_magic_header = number;
dev->flags |= WGDEVICE_HAS_H1; dev->flags |= WGDEVICE_HAS_H1;
} }
} }
if (nvlist_exists_number(nvl_device, "h2")) if (nvlist_exists_number(nvl_device, "h2")) {
{
number = nvlist_get_number(nvl_device, "h2"); number = nvlist_get_number(nvl_device, "h2");
if (number <= UINT32_MAX) if (number <= UINT32_MAX){
{
dev->response_packet_magic_header = number; dev->response_packet_magic_header = number;
dev->flags |= WGDEVICE_HAS_H2; dev->flags |= WGDEVICE_HAS_H2;
} }
} }
if (nvlist_exists_number(nvl_device, "h3")) if (nvlist_exists_number(nvl_device, "h3")) {
{
number = nvlist_get_number(nvl_device, "h3"); number = nvlist_get_number(nvl_device, "h3");
if (number <= UINT32_MAX) if (number <= UINT32_MAX){
{
dev->underload_packet_magic_header = number; dev->underload_packet_magic_header = number;
dev->flags |= WGDEVICE_HAS_H3; dev->flags |= WGDEVICE_HAS_H3;
} }
} }
if (nvlist_exists_number(nvl_device, "h4")) if (nvlist_exists_number(nvl_device, "h4")) {
{
number = nvlist_get_number(nvl_device, "h4"); number = nvlist_get_number(nvl_device, "h4");
if (number <= UINT32_MAX) if (number <= UINT32_MAX){
{
dev->transport_packet_magic_header = number; dev->transport_packet_magic_header = number;
dev->flags |= WGDEVICE_HAS_H4; dev->flags |= WGDEVICE_HAS_H4;
} }
@ -258,29 +236,23 @@ static int kernel_get_device(struct wgdevice** device, const char* ifname)
} }
} }
if (nvlist_exists_number(nvl_device, "user-cookie")) if (nvlist_exists_number(nvl_device, "user-cookie")) {
{
number = nvlist_get_number(nvl_device, "user-cookie"); number = nvlist_get_number(nvl_device, "user-cookie");
if (number <= UINT32_MAX) if (number <= UINT32_MAX) {
{
dev->fwmark = number; dev->fwmark = number;
dev->flags |= WGDEVICE_HAS_FWMARK; dev->flags |= WGDEVICE_HAS_FWMARK;
} }
} }
if (nvlist_exists_binary(nvl_device, "public-key")) if (nvlist_exists_binary(nvl_device, "public-key")) {
{
binary = nvlist_get_binary(nvl_device, "public-key", &size); binary = nvlist_get_binary(nvl_device, "public-key", &size);
if (binary && size == sizeof(dev->public_key)) if (binary && size == sizeof(dev->public_key)) {
{
memcpy(dev->public_key, binary, sizeof(dev->public_key)); memcpy(dev->public_key, binary, sizeof(dev->public_key));
dev->flags |= WGDEVICE_HAS_PUBLIC_KEY; dev->flags |= WGDEVICE_HAS_PUBLIC_KEY;
} }
} }
if (nvlist_exists_binary(nvl_device, "private-key")) if (nvlist_exists_binary(nvl_device, "private-key")) {
{
binary = nvlist_get_binary(nvl_device, "private-key", &size); binary = nvlist_get_binary(nvl_device, "private-key", &size);
if (binary && size == sizeof(dev->private_key)) if (binary && size == sizeof(dev->private_key)) {
{
memcpy(dev->private_key, binary, sizeof(dev->private_key)); memcpy(dev->private_key, binary, sizeof(dev->private_key));
dev->flags |= WGDEVICE_HAS_PRIVATE_KEY; dev->flags |= WGDEVICE_HAS_PRIVATE_KEY;
} }
@ -290,8 +262,7 @@ static int kernel_get_device(struct wgdevice** device, const char* ifname)
nvl_peers = nvlist_get_nvlist_array(nvl_device, "peers", &peer_count); nvl_peers = nvlist_get_nvlist_array(nvl_device, "peers", &peer_count);
if (!nvl_peers) if (!nvl_peers)
goto skip_peers; goto skip_peers;
for (i = 0; i < peer_count; ++i) for (i = 0; i < peer_count; ++i) {
{
struct wgpeer *peer; struct wgpeer *peer;
struct wgallowedip *aip = NULL; struct wgallowedip *aip = NULL;
const nvlist_t *const *nvl_aips; const nvlist_t *const *nvl_aips;
@ -300,40 +271,31 @@ static int kernel_get_device(struct wgdevice** device, const char* ifname)
peer = calloc(1, sizeof(*peer)); peer = calloc(1, sizeof(*peer));
if (!peer) if (!peer)
goto err_peer; goto err_peer;
if (nvlist_exists_binary(nvl_peers[i], "public-key")) if (nvlist_exists_binary(nvl_peers[i], "public-key")) {
{
binary = nvlist_get_binary(nvl_peers[i], "public-key", &size); binary = nvlist_get_binary(nvl_peers[i], "public-key", &size);
if (binary && size == sizeof(peer->public_key)) if (binary && size == sizeof(peer->public_key)) {
{
memcpy(peer->public_key, binary, sizeof(peer->public_key)); memcpy(peer->public_key, binary, sizeof(peer->public_key));
peer->flags |= WGPEER_HAS_PUBLIC_KEY; peer->flags |= WGPEER_HAS_PUBLIC_KEY;
} }
} }
if (nvlist_exists_binary(nvl_peers[i], "preshared-key")) if (nvlist_exists_binary(nvl_peers[i], "preshared-key")) {
{
binary = nvlist_get_binary(nvl_peers[i], "preshared-key", &size); binary = nvlist_get_binary(nvl_peers[i], "preshared-key", &size);
if (binary && size == sizeof(peer->preshared_key)) if (binary && size == sizeof(peer->preshared_key)) {
{
memcpy(peer->preshared_key, binary, sizeof(peer->preshared_key)); memcpy(peer->preshared_key, binary, sizeof(peer->preshared_key));
if (!key_is_zero(peer->preshared_key)) if (!key_is_zero(peer->preshared_key))
peer->flags |= WGPEER_HAS_PRESHARED_KEY; peer->flags |= WGPEER_HAS_PRESHARED_KEY;
} }
} }
if (nvlist_exists_number(nvl_peers[i], "persistent-keepalive-interval")) if (nvlist_exists_number(nvl_peers[i], "persistent-keepalive-interval")) {
{
number = nvlist_get_number(nvl_peers[i], "persistent-keepalive-interval"); number = nvlist_get_number(nvl_peers[i], "persistent-keepalive-interval");
if (number <= UINT16_MAX) if (number <= UINT16_MAX) {
{
peer->persistent_keepalive_interval = number; peer->persistent_keepalive_interval = number;
peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL; peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
} }
} }
if (nvlist_exists_binary(nvl_peers[i], "endpoint")) if (nvlist_exists_binary(nvl_peers[i], "endpoint")) {
{ const struct sockaddr *endpoint = nvlist_get_binary(nvl_peers[i], "endpoint", &size);
const struct sockaddr* endpoint = if (endpoint && size <= sizeof(peer->endpoint) && size >= sizeof(peer->endpoint.addr) &&
nvlist_get_binary(nvl_peers[i], "endpoint", &size);
if (endpoint && size <= sizeof(peer->endpoint) &&
size >= sizeof(peer->endpoint.addr) &&
(endpoint->sa_family == AF_INET || endpoint->sa_family == AF_INET6)) (endpoint->sa_family == AF_INET || endpoint->sa_family == AF_INET6))
memcpy(&peer->endpoint.addr, endpoint, size); memcpy(&peer->endpoint.addr, endpoint, size);
} }
@ -341,14 +303,10 @@ static int kernel_get_device(struct wgdevice** device, const char* ifname)
peer->rx_bytes = nvlist_get_number(nvl_peers[i], "rx-bytes"); peer->rx_bytes = nvlist_get_number(nvl_peers[i], "rx-bytes");
if (nvlist_exists_number(nvl_peers[i], "tx-bytes")) if (nvlist_exists_number(nvl_peers[i], "tx-bytes"))
peer->tx_bytes = nvlist_get_number(nvl_peers[i], "tx-bytes"); peer->tx_bytes = nvlist_get_number(nvl_peers[i], "tx-bytes");
if (nvlist_exists_binary(nvl_peers[i], "last-handshake-time")) if (nvlist_exists_binary(nvl_peers[i], "last-handshake-time")) {
{
binary = nvlist_get_binary(nvl_peers[i], "last-handshake-time", &size); binary = nvlist_get_binary(nvl_peers[i], "last-handshake-time", &size);
if (binary && size == sizeof(peer->last_handshake_time)) if (binary && size == sizeof(peer->last_handshake_time))
memcpy( memcpy(&peer->last_handshake_time, binary, sizeof(peer->last_handshake_time));
&peer->last_handshake_time,
binary,
sizeof(peer->last_handshake_time));
} }
if (!nvlist_exists_nvlist_array(nvl_peers[i], "allowed-ips")) if (!nvlist_exists_nvlist_array(nvl_peers[i], "allowed-ips"))
@ -356,35 +314,28 @@ static int kernel_get_device(struct wgdevice** device, const char* ifname)
nvl_aips = nvlist_get_nvlist_array(nvl_peers[i], "allowed-ips", &aip_count); nvl_aips = nvlist_get_nvlist_array(nvl_peers[i], "allowed-ips", &aip_count);
if (!aip_count || !nvl_aips) if (!aip_count || !nvl_aips)
goto skip_allowed_ips; goto skip_allowed_ips;
for (j = 0; j < aip_count; ++j) for (j = 0; j < aip_count; ++j) {
{
if (!nvlist_exists_number(nvl_aips[j], "cidr")) if (!nvlist_exists_number(nvl_aips[j], "cidr"))
continue; continue;
if (!nvlist_exists_binary(nvl_aips[j], "ipv4") && if (!nvlist_exists_binary(nvl_aips[j], "ipv4") && !nvlist_exists_binary(nvl_aips[j], "ipv6"))
!nvlist_exists_binary(nvl_aips[j], "ipv6"))
continue; continue;
aip = calloc(1, sizeof(*aip)); aip = calloc(1, sizeof(*aip));
if (!aip) if (!aip)
goto err_allowed_ips; goto err_allowed_ips;
number = nvlist_get_number(nvl_aips[j], "cidr"); number = nvlist_get_number(nvl_aips[j], "cidr");
if (nvlist_exists_binary(nvl_aips[j], "ipv4")) if (nvlist_exists_binary(nvl_aips[j], "ipv4")) {
{
binary = nvlist_get_binary(nvl_aips[j], "ipv4", &size); binary = nvlist_get_binary(nvl_aips[j], "ipv4", &size);
if (!binary || number > 32) if (!binary || number > 32) {
{
ret = EINVAL; ret = EINVAL;
goto err_allowed_ips; goto err_allowed_ips;
} }
aip->family = AF_INET; aip->family = AF_INET;
aip->cidr = number; aip->cidr = number;
memcpy(&aip->ip4, binary, sizeof(aip->ip4)); memcpy(&aip->ip4, binary, sizeof(aip->ip4));
} } else {
else
{
assert(nvlist_exists_binary(nvl_aips[j], "ipv6")); assert(nvlist_exists_binary(nvl_aips[j], "ipv6"));
binary = nvlist_get_binary(nvl_aips[j], "ipv6", &size); binary = nvlist_get_binary(nvl_aips[j], "ipv6", &size);
if (!binary || number > 128) if (!binary || number > 128) {
{
ret = EINVAL; ret = EINVAL;
goto err_allowed_ips; goto err_allowed_ips;
} }
@ -440,6 +391,7 @@ err:
return ret; return ret;
} }
static int kernel_set_device(struct wgdevice *dev) static int kernel_set_device(struct wgdevice *dev)
{ {
struct wg_data_io wgd = { 0 }; struct wg_data_io wgd = { 0 };
@ -454,16 +406,15 @@ static int kernel_set_device(struct wgdevice* dev)
if (!nvl_device) if (!nvl_device)
goto err; goto err;
for_each_wgpeer(dev, peer)++ peer_count; for_each_wgpeer(dev, peer)
if (peer_count) ++peer_count;
{ if (peer_count) {
nvl_peers = calloc(peer_count, sizeof(*nvl_peers)); nvl_peers = calloc(peer_count, sizeof(*nvl_peers));
if (!nvl_peers) if (!nvl_peers)
goto err; goto err;
} }
if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY)
nvlist_add_binary( nvlist_add_binary(nvl_device, "private-key", dev->private_key, sizeof(dev->private_key));
nvl_device, "private-key", dev->private_key, sizeof(dev->private_key));
if (dev->flags & WGDEVICE_HAS_LISTEN_PORT) if (dev->flags & WGDEVICE_HAS_LISTEN_PORT)
nvlist_add_number(nvl_device, "listen-port", dev->listen_port); nvlist_add_number(nvl_device, "listen-port", dev->listen_port);
if (dev->flags & WGDEVICE_HAS_JC) if (dev->flags & WGDEVICE_HAS_JC)
@ -502,14 +453,12 @@ static int kernel_set_device(struct wgdevice* dev)
nvlist_add_binary(nvl_device, "j3", dev->j3, strlen(dev->j3) + 1); nvlist_add_binary(nvl_device, "j3", dev->j3, strlen(dev->j3) + 1);
if (dev->flags & WGDEVICE_HAS_ITIME) if (dev->flags & WGDEVICE_HAS_ITIME)
nvlist_add_number(nvl_device, "itime", dev->itime); nvlist_add_number(nvl_device, "itime", dev->itime);
if (dev->flags & WGDEVICE_HAS_FWMARK) if (dev->flags & WGDEVICE_HAS_FWMARK)
nvlist_add_number(nvl_device, "user-cookie", dev->fwmark); nvlist_add_number(nvl_device, "user-cookie", dev->fwmark);
if (dev->flags & WGDEVICE_REPLACE_PEERS) if (dev->flags & WGDEVICE_REPLACE_PEERS)
nvlist_add_bool(nvl_device, "replace-peers", true); nvlist_add_bool(nvl_device, "replace-peers", true);
for_each_wgpeer(dev, peer) for_each_wgpeer(dev, peer) {
{
size_t aip_count = 0, j = 0; size_t aip_count = 0, j = 0;
nvlist_t **nvl_aips = NULL; nvlist_t **nvl_aips = NULL;
struct wgallowedip *aip; struct wgallowedip *aip;
@ -517,39 +466,25 @@ static int kernel_set_device(struct wgdevice* dev)
nvl_peers[i] = nvlist_create(0); nvl_peers[i] = nvlist_create(0);
if (!nvl_peers[i]) if (!nvl_peers[i])
goto err_peer; goto err_peer;
for_each_wgallowedip(peer, aip)++ aip_count; for_each_wgallowedip(peer, aip)
if (aip_count) ++aip_count;
{ if (aip_count) {
nvl_aips = calloc(aip_count, sizeof(*nvl_aips)); nvl_aips = calloc(aip_count, sizeof(*nvl_aips));
if (!nvl_aips) if (!nvl_aips)
goto err_peer; goto err_peer;
} }
nvlist_add_binary( nvlist_add_binary(nvl_peers[i], "public-key", peer->public_key, sizeof(peer->public_key));
nvl_peers[i], "public-key", peer->public_key, sizeof(peer->public_key));
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) if (peer->flags & WGPEER_HAS_PRESHARED_KEY)
nvlist_add_binary( nvlist_add_binary(nvl_peers[i], "preshared-key", peer->preshared_key, sizeof(peer->preshared_key));
nvl_peers[i],
"preshared-key",
peer->preshared_key,
sizeof(peer->preshared_key));
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL)
nvlist_add_number( nvlist_add_number(nvl_peers[i], "persistent-keepalive-interval", peer->persistent_keepalive_interval);
nvl_peers[i], if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6)
"persistent-keepalive-interval", nvlist_add_binary(nvl_peers[i], "endpoint", &peer->endpoint.addr, peer->endpoint.addr.sa_len);
peer->persistent_keepalive_interval);
if (peer->endpoint.addr.sa_family == AF_INET ||
peer->endpoint.addr.sa_family == AF_INET6)
nvlist_add_binary(
nvl_peers[i],
"endpoint",
&peer->endpoint.addr,
peer->endpoint.addr.sa_len);
if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS) if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS)
nvlist_add_bool(nvl_peers[i], "replace-allowedips", true); nvlist_add_bool(nvl_peers[i], "replace-allowedips", true);
if (peer->flags & WGPEER_REMOVE_ME) if (peer->flags & WGPEER_REMOVE_ME)
nvlist_add_bool(nvl_peers[i], "remove", true); nvlist_add_bool(nvl_peers[i], "remove", true);
for_each_wgallowedip(peer, aip) for_each_wgallowedip(peer, aip) {
{
nvl_aips[j] = nvlist_create(0); nvl_aips[j] = nvlist_create(0);
if (!nvl_aips[j]) if (!nvl_aips[j])
goto err_peer; goto err_peer;
@ -560,10 +495,8 @@ static int kernel_set_device(struct wgdevice* dev)
nvlist_add_binary(nvl_aips[j], "ipv6", &aip->ip6, sizeof(aip->ip6)); nvlist_add_binary(nvl_aips[j], "ipv6", &aip->ip6, sizeof(aip->ip6));
++j; ++j;
} }
if (j) if (j) {
{ nvlist_add_nvlist_array(nvl_peers[i], "allowed-ips", (const nvlist_t *const *)nvl_aips, j);
nvlist_add_nvlist_array(
nvl_peers[i], "allowed-ips", (const nvlist_t* const*)nvl_aips, j);
for (j = 0; j < aip_count; ++j) for (j = 0; j < aip_count; ++j)
nvlist_destroy(nvl_aips[j]); nvlist_destroy(nvl_aips[j]);
free(nvl_aips); free(nvl_aips);
@ -580,10 +513,8 @@ static int kernel_set_device(struct wgdevice* dev)
nvl_peers[i] = NULL; nvl_peers[i] = NULL;
goto err; goto err;
} }
if (i) if (i) {
{ nvlist_add_nvlist_array(nvl_device, "peers", (const nvlist_t *const *)nvl_peers, i);
nvlist_add_nvlist_array(
nvl_device, "peers", (const nvlist_t* const*)nvl_peers, i);
for (i = 0; i < peer_count; ++i) for (i = 0; i < peer_count; ++i)
nvlist_destroy(nvl_peers[i]); nvlist_destroy(nvl_peers[i]);
free(nvl_peers); free(nvl_peers);

View file

@ -3,33 +3,31 @@
* Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/ */
#include "containers.h" #include <stdbool.h>
#include "encoding.h" #include <stddef.h>
#include "netlink.h" #include <stdint.h>
#include "uapi/linux/linux/wireguard.h" #include <stdio.h>
#include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/genetlink.h> #include <linux/genetlink.h>
#include <linux/if_link.h> #include <linux/if_link.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/wireguard.h> #include <linux/wireguard.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <stdbool.h> #include "containers.h"
#include <stddef.h> #include "encoding.h"
#include <stdint.h> #include "netlink.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#define IPC_SUPPORTS_KERNEL_INTERFACE #define IPC_SUPPORTS_KERNEL_INTERFACE
#define SOCKET_BUFFER_SIZE (mnl_ideal_socket_buffer_size()) #define SOCKET_BUFFER_SIZE (mnl_ideal_socket_buffer_size())
struct interface struct interface {
{
const char *name; const char *name;
bool is_wireguard; bool is_wireguard;
}; };
@ -38,8 +36,7 @@ static int parse_linkinfo(const struct nlattr* attr, void* data)
{ {
struct interface *interface = data; struct interface *interface = data;
if (mnl_attr_get_type(attr) == IFLA_INFO_KIND && if (mnl_attr_get_type(attr) == IFLA_INFO_KIND && !strcmp(WG_GENL_NAME, mnl_attr_get_str(attr)))
!strcmp(WG_GENL_NAME, mnl_attr_get_str(attr)))
interface->is_wireguard = true; interface->is_wireguard = true;
return MNL_CB_OK; return MNL_CB_OK;
} }
@ -90,14 +87,12 @@ static int kernel_get_wireguard_interfaces(struct string_list* list)
goto cleanup; goto cleanup;
nl = mnl_socket_open(NETLINK_ROUTE); nl = mnl_socket_open(NETLINK_ROUTE);
if (!nl) if (!nl) {
{
ret = -errno; ret = -errno;
goto cleanup; goto cleanup;
} }
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
{
ret = -errno; ret = -errno;
goto cleanup; goto cleanup;
} }
@ -112,27 +107,23 @@ static int kernel_get_wireguard_interfaces(struct string_list* list)
ifm->ifi_family = AF_UNSPEC; ifm->ifi_family = AF_UNSPEC;
message_len = nlh->nlmsg_len; message_len = nlh->nlmsg_len;
if (mnl_socket_sendto(nl, rtnl_buffer, message_len) < 0) if (mnl_socket_sendto(nl, rtnl_buffer, message_len) < 0) {
{
ret = -errno; ret = -errno;
goto cleanup; goto cleanup;
} }
another: another:
if ((len = mnl_socket_recvfrom(nl, rtnl_buffer, SOCKET_BUFFER_SIZE)) < 0) if ((len = mnl_socket_recvfrom(nl, rtnl_buffer, SOCKET_BUFFER_SIZE)) < 0) {
{
ret = -errno; ret = -errno;
goto cleanup; goto cleanup;
} }
if ((len = mnl_cb_run(rtnl_buffer, len, seq, portid, read_devices_cb, list)) < 0) if ((len = mnl_cb_run(rtnl_buffer, len, seq, portid, read_devices_cb, list)) < 0) {
{
/* Netlink returns NLM_F_DUMP_INTR if the set of all tunnels changed /* Netlink returns NLM_F_DUMP_INTR if the set of all tunnels changed
* during the dump. That's unfortunate, but is pretty common on busy * during the dump. That's unfortunate, but is pretty common on busy
* systems that are adding and removing tunnels all the time. Rather * systems that are adding and removing tunnels all the time. Rather
* than retrying, potentially indefinitely, we just work with the * than retrying, potentially indefinitely, we just work with the
* partial results. */ * partial results. */
if (errno != EINTR) if (errno != EINTR) {
{
ret = -errno; ret = -errno;
goto cleanup; goto cleanup;
} }
@ -165,13 +156,11 @@ again:
nlh = mnlg_msg_prepare(nlg, WG_CMD_SET_DEVICE, NLM_F_REQUEST | NLM_F_ACK); nlh = mnlg_msg_prepare(nlg, WG_CMD_SET_DEVICE, NLM_F_REQUEST | NLM_F_ACK);
mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, dev->name); mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, dev->name);
if (!peer) if (!peer) {
{
uint32_t flags = 0; uint32_t flags = 0;
if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY)
mnl_attr_put( mnl_attr_put(nlh, WGDEVICE_A_PRIVATE_KEY, sizeof(dev->private_key), dev->private_key);
nlh, WGDEVICE_A_PRIVATE_KEY, sizeof(dev->private_key), dev->private_key);
if (dev->flags & WGDEVICE_HAS_LISTEN_PORT) if (dev->flags & WGDEVICE_HAS_LISTEN_PORT)
mnl_attr_put_u16(nlh, WGDEVICE_A_LISTEN_PORT, dev->listen_port); mnl_attr_put_u16(nlh, WGDEVICE_A_LISTEN_PORT, dev->listen_port);
if (dev->flags & WGDEVICE_HAS_JC) if (dev->flags & WGDEVICE_HAS_JC)
@ -210,7 +199,6 @@ again:
mnl_attr_put_strz(nlh, WGDEVICE_A_J3, dev->j3); mnl_attr_put_strz(nlh, WGDEVICE_A_J3, dev->j3);
if (dev->flags & WGDEVICE_HAS_ITIME) if (dev->flags & WGDEVICE_HAS_ITIME)
mnl_attr_put_u32(nlh, WGDEVICE_A_ITIME, dev->itime); mnl_attr_put_u32(nlh, WGDEVICE_A_ITIME, dev->itime);
if (dev->flags & WGDEVICE_HAS_FWMARK) if (dev->flags & WGDEVICE_HAS_FWMARK)
mnl_attr_put_u32(nlh, WGDEVICE_A_FWMARK, dev->fwmark); mnl_attr_put_u32(nlh, WGDEVICE_A_FWMARK, dev->fwmark);
if (dev->flags & WGDEVICE_REPLACE_PEERS) if (dev->flags & WGDEVICE_REPLACE_PEERS)
@ -222,71 +210,38 @@ again:
goto send; goto send;
peers_nest = peer_nest = allowedips_nest = allowedip_nest = NULL; peers_nest = peer_nest = allowedips_nest = allowedip_nest = NULL;
peers_nest = mnl_attr_nest_start(nlh, WGDEVICE_A_PEERS); peers_nest = mnl_attr_nest_start(nlh, WGDEVICE_A_PEERS);
for (peer = peer ? peer : dev->first_peer; peer; peer = peer->next_peer) for (peer = peer ? peer : dev->first_peer; peer; peer = peer->next_peer) {
{
uint32_t flags = 0; uint32_t flags = 0;
peer_nest = mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, 0); peer_nest = mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, 0);
if (!peer_nest) if (!peer_nest)
goto toobig_peers; goto toobig_peers;
if (!mnl_attr_put_check( if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_PUBLIC_KEY, sizeof(peer->public_key), peer->public_key))
nlh,
SOCKET_BUFFER_SIZE,
WGPEER_A_PUBLIC_KEY,
sizeof(peer->public_key),
peer->public_key))
goto toobig_peers; goto toobig_peers;
if (peer->flags & WGPEER_REMOVE_ME) if (peer->flags & WGPEER_REMOVE_ME)
flags |= WGPEER_F_REMOVE_ME; flags |= WGPEER_F_REMOVE_ME;
if (!allowedip) if (!allowedip) {
{
if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS) if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS)
flags |= WGPEER_F_REPLACE_ALLOWEDIPS; flags |= WGPEER_F_REPLACE_ALLOWEDIPS;
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) if (peer->flags & WGPEER_HAS_PRESHARED_KEY) {
{ if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_PRESHARED_KEY, sizeof(peer->preshared_key), peer->preshared_key))
if (!mnl_attr_put_check(
nlh,
SOCKET_BUFFER_SIZE,
WGPEER_A_PRESHARED_KEY,
sizeof(peer->preshared_key),
peer->preshared_key))
goto toobig_peers; goto toobig_peers;
} }
if (peer->endpoint.addr.sa_family == AF_INET) if (peer->endpoint.addr.sa_family == AF_INET) {
{ if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ENDPOINT, sizeof(peer->endpoint.addr4), &peer->endpoint.addr4))
if (!mnl_attr_put_check( goto toobig_peers;
nlh, } else if (peer->endpoint.addr.sa_family == AF_INET6) {
SOCKET_BUFFER_SIZE, if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ENDPOINT, sizeof(peer->endpoint.addr6), &peer->endpoint.addr6))
WGPEER_A_ENDPOINT,
sizeof(peer->endpoint.addr4),
&peer->endpoint.addr4))
goto toobig_peers; goto toobig_peers;
} }
else if (peer->endpoint.addr.sa_family == AF_INET6) if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) {
{ if (!mnl_attr_put_u16_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval))
if (!mnl_attr_put_check(
nlh,
SOCKET_BUFFER_SIZE,
WGPEER_A_ENDPOINT,
sizeof(peer->endpoint.addr6),
&peer->endpoint.addr6))
goto toobig_peers;
}
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL)
{
if (!mnl_attr_put_u16_check(
nlh,
SOCKET_BUFFER_SIZE,
WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
peer->persistent_keepalive_interval))
goto toobig_peers; goto toobig_peers;
} }
} }
if (peer->flags & WGPEER_HAS_ADVANCED_SECURITY) if (peer->flags & WGPEER_HAS_ADVANCED_SECURITY) {
{
if (peer->advanced_security) if (peer->advanced_security)
mnl_attr_put_check( mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ADVANCED_SECURITY, 0, NULL);
nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ADVANCED_SECURITY, 0, NULL);
flags |= WGPEER_F_HAS_ADVANCED_SECURITY; flags |= WGPEER_F_HAS_ADVANCED_SECURITY;
} }
if (peer->flags & WGPEER_HAS_SPECIAL_HANDSHAKE) if (peer->flags & WGPEER_HAS_SPECIAL_HANDSHAKE)
@ -296,52 +251,30 @@ again:
nlh, SOCKET_BUFFER_SIZE, WGPEER_A_SPECIAL_HANDSHAKE, 0, NULL); nlh, SOCKET_BUFFER_SIZE, WGPEER_A_SPECIAL_HANDSHAKE, 0, NULL);
flags |= WGPEER_F_HAS_SPECIAL_HANDSHAKE; flags |= WGPEER_F_HAS_SPECIAL_HANDSHAKE;
} }
if (flags) if (flags) {
{
if (!mnl_attr_put_u32_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_FLAGS, flags)) if (!mnl_attr_put_u32_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_FLAGS, flags))
goto toobig_peers; goto toobig_peers;
} }
if (peer->first_allowedip) if (peer->first_allowedip) {
{
if (!allowedip) if (!allowedip)
allowedip = peer->first_allowedip; allowedip = peer->first_allowedip;
allowedips_nest = allowedips_nest = mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ALLOWEDIPS);
mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ALLOWEDIPS);
if (!allowedips_nest) if (!allowedips_nest)
goto toobig_allowedips; goto toobig_allowedips;
for (; allowedip; allowedip = allowedip->next_allowedip) for (; allowedip; allowedip = allowedip->next_allowedip) {
{
allowedip_nest = mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, 0); allowedip_nest = mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, 0);
if (!allowedip_nest) if (!allowedip_nest)
goto toobig_allowedips; goto toobig_allowedips;
if (!mnl_attr_put_u16_check( if (!mnl_attr_put_u16_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_FAMILY, allowedip->family))
nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_FAMILY, allowedip->family))
goto toobig_allowedips; goto toobig_allowedips;
if (allowedip->family == AF_INET) if (allowedip->family == AF_INET) {
{ if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_IPADDR, sizeof(allowedip->ip4), &allowedip->ip4))
if (!mnl_attr_put_check( goto toobig_allowedips;
nlh, } else if (allowedip->family == AF_INET6) {
SOCKET_BUFFER_SIZE, if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_IPADDR, sizeof(allowedip->ip6), &allowedip->ip6))
WGALLOWEDIP_A_IPADDR,
sizeof(allowedip->ip4),
&allowedip->ip4))
goto toobig_allowedips; goto toobig_allowedips;
} }
else if (allowedip->family == AF_INET6) if (!mnl_attr_put_u8_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_CIDR_MASK, allowedip->cidr))
{
if (!mnl_attr_put_check(
nlh,
SOCKET_BUFFER_SIZE,
WGALLOWEDIP_A_IPADDR,
sizeof(allowedip->ip6),
&allowedip->ip6))
goto toobig_allowedips;
}
if (!mnl_attr_put_u8_check(
nlh,
SOCKET_BUFFER_SIZE,
WGALLOWEDIP_A_CIDR_MASK,
allowedip->cidr))
goto toobig_allowedips; goto toobig_allowedips;
mnl_attr_nest_end(nlh, allowedip_nest); mnl_attr_nest_end(nlh, allowedip_nest);
allowedip_nest = NULL; allowedip_nest = NULL;
@ -370,14 +303,12 @@ toobig_peers:
mnl_attr_nest_end(nlh, peers_nest); mnl_attr_nest_end(nlh, peers_nest);
goto send; goto send;
send: send:
if (mnlg_socket_send(nlg, nlh) < 0) if (mnlg_socket_send(nlg, nlh) < 0) {
{
ret = -errno; ret = -errno;
goto out; goto out;
} }
errno = 0; errno = 0;
if (mnlg_socket_recv_run(nlg, NULL, NULL) < 0) if (mnlg_socket_recv_run(nlg, NULL, NULL) < 0) {
{
ret = errno ? -errno : -EINVAL; ret = errno ? -errno : -EINVAL;
goto out; goto out;
} }
@ -394,8 +325,7 @@ static int parse_allowedip(const struct nlattr* attr, void* data)
{ {
struct wgallowedip *allowedip = data; struct wgallowedip *allowedip = data;
switch (mnl_attr_get_type(attr)) switch (mnl_attr_get_type(attr)) {
{
case WGALLOWEDIP_A_UNSPEC: case WGALLOWEDIP_A_UNSPEC:
break; break;
case WGALLOWEDIP_A_FAMILY: case WGALLOWEDIP_A_FAMILY:
@ -423,23 +353,20 @@ static int parse_allowedips(const struct nlattr* attr, void* data)
struct wgallowedip *new_allowedip = calloc(1, sizeof(*new_allowedip)); struct wgallowedip *new_allowedip = calloc(1, sizeof(*new_allowedip));
int ret; int ret;
if (!new_allowedip) if (!new_allowedip) {
{
perror("calloc"); perror("calloc");
return MNL_CB_ERROR; return MNL_CB_ERROR;
} }
if (!peer->first_allowedip) if (!peer->first_allowedip)
peer->first_allowedip = peer->last_allowedip = new_allowedip; peer->first_allowedip = peer->last_allowedip = new_allowedip;
else else {
{
peer->last_allowedip->next_allowedip = new_allowedip; peer->last_allowedip->next_allowedip = new_allowedip;
peer->last_allowedip = new_allowedip; peer->last_allowedip = new_allowedip;
} }
ret = mnl_attr_parse_nested(attr, parse_allowedip, new_allowedip); ret = mnl_attr_parse_nested(attr, parse_allowedip, new_allowedip);
if (!ret) if (!ret)
return ret; return ret;
if (!((new_allowedip->family == AF_INET && new_allowedip->cidr <= 32) || if (!((new_allowedip->family == AF_INET && new_allowedip->cidr <= 32) || (new_allowedip->family == AF_INET6 && new_allowedip->cidr <= 128)))
(new_allowedip->family == AF_INET6 && new_allowedip->cidr <= 128)))
return MNL_CB_ERROR; return MNL_CB_ERROR;
return MNL_CB_OK; return MNL_CB_OK;
} }
@ -448,25 +375,18 @@ static int parse_peer(const struct nlattr* attr, void* data)
{ {
struct wgpeer *peer = data; struct wgpeer *peer = data;
switch (mnl_attr_get_type(attr)) switch (mnl_attr_get_type(attr)) {
{
case WGPEER_A_UNSPEC: case WGPEER_A_UNSPEC:
break; break;
case WGPEER_A_PUBLIC_KEY: case WGPEER_A_PUBLIC_KEY:
if (mnl_attr_get_payload_len(attr) == sizeof(peer->public_key)) if (mnl_attr_get_payload_len(attr) == sizeof(peer->public_key)) {
{ memcpy(peer->public_key, mnl_attr_get_payload(attr), sizeof(peer->public_key));
memcpy(
peer->public_key, mnl_attr_get_payload(attr), sizeof(peer->public_key));
peer->flags |= WGPEER_HAS_PUBLIC_KEY; peer->flags |= WGPEER_HAS_PUBLIC_KEY;
} }
break; break;
case WGPEER_A_PRESHARED_KEY: case WGPEER_A_PRESHARED_KEY:
if (mnl_attr_get_payload_len(attr) == sizeof(peer->preshared_key)) if (mnl_attr_get_payload_len(attr) == sizeof(peer->preshared_key)) {
{ memcpy(peer->preshared_key, mnl_attr_get_payload(attr), sizeof(peer->preshared_key));
memcpy(
peer->preshared_key,
mnl_attr_get_payload(attr),
sizeof(peer->preshared_key));
if (!key_is_zero(peer->preshared_key)) if (!key_is_zero(peer->preshared_key))
peer->flags |= WGPEER_HAS_PRESHARED_KEY; peer->flags |= WGPEER_HAS_PRESHARED_KEY;
} }
@ -477,12 +397,9 @@ static int parse_peer(const struct nlattr* attr, void* data)
if (mnl_attr_get_payload_len(attr) < sizeof(*addr)) if (mnl_attr_get_payload_len(attr) < sizeof(*addr))
break; break;
addr = mnl_attr_get_payload(attr); addr = mnl_attr_get_payload(attr);
if (addr->sa_family == AF_INET && if (addr->sa_family == AF_INET && mnl_attr_get_payload_len(attr) == sizeof(peer->endpoint.addr4))
mnl_attr_get_payload_len(attr) == sizeof(peer->endpoint.addr4))
memcpy(&peer->endpoint.addr4, addr, sizeof(peer->endpoint.addr4)); memcpy(&peer->endpoint.addr4, addr, sizeof(peer->endpoint.addr4));
else if ( else if (addr->sa_family == AF_INET6 && mnl_attr_get_payload_len(attr) == sizeof(peer->endpoint.addr6))
addr->sa_family == AF_INET6 &&
mnl_attr_get_payload_len(attr) == sizeof(peer->endpoint.addr6))
memcpy(&peer->endpoint.addr6, addr, sizeof(peer->endpoint.addr6)); memcpy(&peer->endpoint.addr6, addr, sizeof(peer->endpoint.addr6));
break; break;
} }
@ -492,10 +409,7 @@ static int parse_peer(const struct nlattr* attr, void* data)
break; break;
case WGPEER_A_LAST_HANDSHAKE_TIME: case WGPEER_A_LAST_HANDSHAKE_TIME:
if (mnl_attr_get_payload_len(attr) == sizeof(peer->last_handshake_time)) if (mnl_attr_get_payload_len(attr) == sizeof(peer->last_handshake_time))
memcpy( memcpy(&peer->last_handshake_time, mnl_attr_get_payload(attr), sizeof(peer->last_handshake_time));
&peer->last_handshake_time,
mnl_attr_get_payload(attr),
sizeof(peer->last_handshake_time));
break; break;
case WGPEER_A_RX_BYTES: case WGPEER_A_RX_BYTES:
if (!mnl_attr_validate(attr, MNL_TYPE_U64)) if (!mnl_attr_validate(attr, MNL_TYPE_U64))
@ -506,17 +420,14 @@ static int parse_peer(const struct nlattr* attr, void* data)
peer->tx_bytes = mnl_attr_get_u64(attr); peer->tx_bytes = mnl_attr_get_u64(attr);
break; break;
case WGPEER_A_FLAGS: case WGPEER_A_FLAGS:
if (!mnl_attr_validate(attr, MNL_TYPE_U32)) if (!mnl_attr_validate(attr, MNL_TYPE_U32)) {
{
uint32_t flags = mnl_attr_get_u32(attr); uint32_t flags = mnl_attr_get_u32(attr);
if (flags & WGPEER_F_HAS_ADVANCED_SECURITY && if (flags & WGPEER_F_HAS_ADVANCED_SECURITY && !(peer->flags & WGPEER_HAS_ADVANCED_SECURITY)) {
!(peer->flags & WGPEER_HAS_ADVANCED_SECURITY))
{
peer->flags |= WGPEER_HAS_ADVANCED_SECURITY; peer->flags |= WGPEER_HAS_ADVANCED_SECURITY;
peer->advanced_security = false; peer->advanced_security = false;
} }
else if ( if (
flags & WGPEER_F_HAS_SPECIAL_HANDSHAKE && flags & WGPEER_F_HAS_SPECIAL_HANDSHAKE &&
!(peer->flags & WGPEER_HAS_SPECIAL_HANDSHAKE)) !(peer->flags & WGPEER_HAS_SPECIAL_HANDSHAKE))
{ {
@ -526,12 +437,10 @@ static int parse_peer(const struct nlattr* attr, void* data)
} }
break; break;
case WGPEER_A_ADVANCED_SECURITY: case WGPEER_A_ADVANCED_SECURITY:
if (!mnl_attr_validate(attr, MNL_TYPE_FLAG)) if (!mnl_attr_validate(attr, MNL_TYPE_FLAG)) {
{
peer->advanced_security = true; peer->advanced_security = true;
if (!(peer->flags & WGPEER_HAS_ADVANCED_SECURITY)) if (!(peer->flags & WGPEER_HAS_ADVANCED_SECURITY)) {
{
peer->flags |= WGPEER_HAS_ADVANCED_SECURITY; peer->flags |= WGPEER_HAS_ADVANCED_SECURITY;
} }
} }
@ -560,15 +469,13 @@ static int parse_peers(const struct nlattr* attr, void* data)
struct wgpeer *new_peer = calloc(1, sizeof(*new_peer)); struct wgpeer *new_peer = calloc(1, sizeof(*new_peer));
int ret; int ret;
if (!new_peer) if (!new_peer) {
{
perror("calloc"); perror("calloc");
return MNL_CB_ERROR; return MNL_CB_ERROR;
} }
if (!device->first_peer) if (!device->first_peer)
device->first_peer = device->last_peer = new_peer; device->first_peer = device->last_peer = new_peer;
else else {
{
device->last_peer->next_peer = new_peer; device->last_peer->next_peer = new_peer;
device->last_peer = new_peer; device->last_peer = new_peer;
} }
@ -584,8 +491,7 @@ static int parse_device(const struct nlattr* attr, void* data)
{ {
struct wgdevice *device = data; struct wgdevice *device = data;
switch (mnl_attr_get_type(attr)) switch (mnl_attr_get_type(attr)) {
{
case WGDEVICE_A_UNSPEC: case WGDEVICE_A_UNSPEC:
break; break;
case WGDEVICE_A_IFINDEX: case WGDEVICE_A_IFINDEX:
@ -593,29 +499,20 @@ static int parse_device(const struct nlattr* attr, void* data)
device->ifindex = mnl_attr_get_u32(attr); device->ifindex = mnl_attr_get_u32(attr);
break; break;
case WGDEVICE_A_IFNAME: case WGDEVICE_A_IFNAME:
if (!mnl_attr_validate(attr, MNL_TYPE_STRING)) if (!mnl_attr_validate(attr, MNL_TYPE_STRING)) {
{
strncpy(device->name, mnl_attr_get_str(attr), sizeof(device->name) - 1); strncpy(device->name, mnl_attr_get_str(attr), sizeof(device->name) - 1);
device->name[sizeof(device->name) - 1] = '\0'; device->name[sizeof(device->name) - 1] = '\0';
} }
break; break;
case WGDEVICE_A_PRIVATE_KEY: case WGDEVICE_A_PRIVATE_KEY:
if (mnl_attr_get_payload_len(attr) == sizeof(device->private_key)) if (mnl_attr_get_payload_len(attr) == sizeof(device->private_key)) {
{ memcpy(device->private_key, mnl_attr_get_payload(attr), sizeof(device->private_key));
memcpy(
device->private_key,
mnl_attr_get_payload(attr),
sizeof(device->private_key));
device->flags |= WGDEVICE_HAS_PRIVATE_KEY; device->flags |= WGDEVICE_HAS_PRIVATE_KEY;
} }
break; break;
case WGDEVICE_A_PUBLIC_KEY: case WGDEVICE_A_PUBLIC_KEY:
if (mnl_attr_get_payload_len(attr) == sizeof(device->public_key)) if (mnl_attr_get_payload_len(attr) == sizeof(device->public_key)) {
{ memcpy(device->public_key, mnl_attr_get_payload(attr), sizeof(device->public_key));
memcpy(
device->public_key,
mnl_attr_get_payload(attr),
sizeof(device->public_key));
device->flags |= WGDEVICE_HAS_PUBLIC_KEY; device->flags |= WGDEVICE_HAS_PUBLIC_KEY;
} }
break; break;
@ -630,64 +527,55 @@ static int parse_device(const struct nlattr* attr, void* data)
case WGDEVICE_A_PEERS: case WGDEVICE_A_PEERS:
return mnl_attr_parse_nested(attr, parse_peers, device); return mnl_attr_parse_nested(attr, parse_peers, device);
case WGDEVICE_A_JC: case WGDEVICE_A_JC:
if (!mnl_attr_validate(attr, MNL_TYPE_U16)) if (!mnl_attr_validate(attr, MNL_TYPE_U16)) {
{
device->junk_packet_count = mnl_attr_get_u16(attr); device->junk_packet_count = mnl_attr_get_u16(attr);
device->flags |= WGDEVICE_HAS_JC; device->flags |= WGDEVICE_HAS_JC;
} }
break; break;
case WGDEVICE_A_JMIN: case WGDEVICE_A_JMIN:
if (!mnl_attr_validate(attr, MNL_TYPE_U16)) if (!mnl_attr_validate(attr, MNL_TYPE_U16)) {
{
device->junk_packet_min_size = mnl_attr_get_u16(attr); device->junk_packet_min_size = mnl_attr_get_u16(attr);
device->flags |= WGDEVICE_HAS_JMIN; device->flags |= WGDEVICE_HAS_JMIN;
} }
break; break;
case WGDEVICE_A_JMAX: case WGDEVICE_A_JMAX:
if (!mnl_attr_validate(attr, MNL_TYPE_U16)) if (!mnl_attr_validate(attr, MNL_TYPE_U16)) {
{
device->junk_packet_max_size = mnl_attr_get_u16(attr); device->junk_packet_max_size = mnl_attr_get_u16(attr);
device->flags |= WGDEVICE_HAS_JMAX; device->flags |= WGDEVICE_HAS_JMAX;
} }
break; break;
case WGDEVICE_A_S1: case WGDEVICE_A_S1:
if (!mnl_attr_validate(attr, MNL_TYPE_U16)) if (!mnl_attr_validate(attr, MNL_TYPE_U16)) {
{
device->init_packet_junk_size = mnl_attr_get_u16(attr); device->init_packet_junk_size = mnl_attr_get_u16(attr);
device->flags |= WGDEVICE_HAS_S1; device->flags |= WGDEVICE_HAS_S1;
} }
break; break;
case WGDEVICE_A_S2: case WGDEVICE_A_S2:
if (!mnl_attr_validate(attr, MNL_TYPE_U16)) if (!mnl_attr_validate(attr, MNL_TYPE_U16)) {
{
device->response_packet_junk_size = mnl_attr_get_u16(attr); device->response_packet_junk_size = mnl_attr_get_u16(attr);
device->flags |= WGDEVICE_HAS_S2; device->flags |= WGDEVICE_HAS_S2;
} }
break; break;
case WGDEVICE_A_H1: case WGDEVICE_A_H1:
if (!mnl_attr_validate(attr, MNL_TYPE_U32)) if (!mnl_attr_validate(attr, MNL_TYPE_U32)) {
{
device->init_packet_magic_header = mnl_attr_get_u32(attr); device->init_packet_magic_header = mnl_attr_get_u32(attr);
device->flags |= WGDEVICE_HAS_H1; device->flags |= WGDEVICE_HAS_H1;
} }
break; break;
case WGDEVICE_A_H2: case WGDEVICE_A_H2:
if (!mnl_attr_validate(attr, MNL_TYPE_U32)) if (!mnl_attr_validate(attr, MNL_TYPE_U32)) {
{
device->response_packet_magic_header = mnl_attr_get_u32(attr); device->response_packet_magic_header = mnl_attr_get_u32(attr);
device->flags |= WGDEVICE_HAS_H2; device->flags |= WGDEVICE_HAS_H2;
} }
break; break;
case WGDEVICE_A_H3: case WGDEVICE_A_H3:
if (!mnl_attr_validate(attr, MNL_TYPE_U32)) if (!mnl_attr_validate(attr, MNL_TYPE_U32)) {
{
device->underload_packet_magic_header = mnl_attr_get_u32(attr); device->underload_packet_magic_header = mnl_attr_get_u32(attr);
device->flags |= WGDEVICE_HAS_H3; device->flags |= WGDEVICE_HAS_H3;
} }
break; break;
case WGDEVICE_A_H4: case WGDEVICE_A_H4:
if (!mnl_attr_validate(attr, MNL_TYPE_U32)) if (!mnl_attr_validate(attr, MNL_TYPE_U32)) {
{
device->transport_packet_magic_header = mnl_attr_get_u32(attr); device->transport_packet_magic_header = mnl_attr_get_u32(attr);
device->flags |= WGDEVICE_HAS_H4; device->flags |= WGDEVICE_HAS_H4;
} }
@ -769,21 +657,15 @@ static void coalesce_peers(struct wgdevice* device)
{ {
struct wgpeer *old_next_peer, *peer = device->first_peer; struct wgpeer *old_next_peer, *peer = device->first_peer;
while (peer && peer->next_peer) while (peer && peer->next_peer) {
{ if (memcmp(peer->public_key, peer->next_peer->public_key, sizeof(peer->public_key))) {
if (memcmp(
peer->public_key, peer->next_peer->public_key, sizeof(peer->public_key)))
{
peer = peer->next_peer; peer = peer->next_peer;
continue; continue;
} }
if (!peer->first_allowedip) if (!peer->first_allowedip) {
{
peer->first_allowedip = peer->next_peer->first_allowedip; peer->first_allowedip = peer->next_peer->first_allowedip;
peer->last_allowedip = peer->next_peer->last_allowedip; peer->last_allowedip = peer->next_peer->last_allowedip;
} } else {
else
{
peer->last_allowedip->next_allowedip = peer->next_peer->first_allowedip; peer->last_allowedip->next_allowedip = peer->next_peer->first_allowedip;
peer->last_allowedip = peer->next_peer->last_allowedip; peer->last_allowedip = peer->next_peer->last_allowedip;
} }
@ -800,8 +682,7 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
struct mnlg_socket *nlg; struct mnlg_socket *nlg;
/* libmnl doesn't check the buffer size, so enforce that before using. */ /* libmnl doesn't check the buffer size, so enforce that before using. */
if (strlen(iface) >= IFNAMSIZ) if (strlen(iface) >= IFNAMSIZ) {
{
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return -ENAMETOOLONG; return -ENAMETOOLONG;
} }
@ -813,24 +694,20 @@ try_again:
return -errno; return -errno;
nlg = mnlg_socket_open(WG_GENL_NAME, WG_GENL_VERSION); nlg = mnlg_socket_open(WG_GENL_NAME, WG_GENL_VERSION);
if (!nlg) if (!nlg) {
{
free_wgdevice(*device); free_wgdevice(*device);
*device = NULL; *device = NULL;
return -errno; return -errno;
} }
nlh = nlh = mnlg_msg_prepare(nlg, WG_CMD_GET_DEVICE, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
mnlg_msg_prepare(nlg, WG_CMD_GET_DEVICE, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, iface); mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, iface);
if (mnlg_socket_send(nlg, nlh) < 0) if (mnlg_socket_send(nlg, nlh) < 0) {
{
ret = -errno; ret = -errno;
goto out; goto out;
} }
errno = 0; errno = 0;
if (mnlg_socket_recv_run(nlg, read_device_cb, *device) < 0) if (mnlg_socket_recv_run(nlg, read_device_cb, *device) < 0) {
{
ret = errno ? -errno : -EINVAL; ret = errno ? -errno : -EINVAL;
goto out; goto out;
} }
@ -839,8 +716,7 @@ try_again:
out: out:
if (nlg) if (nlg)
mnlg_socket_close(nlg); mnlg_socket_close(nlg);
if (ret) if (ret) {
{
free_wgdevice(*device); free_wgdevice(*device);
if (ret == -EINTR) if (ret == -EINTR)
goto try_again; goto try_again;

View file

@ -3,19 +3,19 @@
* Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/ */
#include "containers.h"
#include <errno.h> #include <errno.h>
#include <net/if.h>
#include <net/if_wg.h>
#include <netinet/in.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/sockio.h> #include <sys/sockio.h>
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <net/if.h>
#include <net/if_wg.h>
#include <netinet/in.h>
#include "containers.h"
#define IPC_SUPPORTS_KERNEL_INTERFACE #define IPC_SUPPORTS_KERNEL_INTERFACE
@ -42,14 +42,12 @@ static int kernel_get_wireguard_interfaces(struct string_list* list)
ifgr.ifgr_groups = calloc(1, ifgr.ifgr_len); ifgr.ifgr_groups = calloc(1, ifgr.ifgr_len);
if (!ifgr.ifgr_groups) if (!ifgr.ifgr_groups)
return -errno; return -errno;
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) < 0) if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) < 0) {
{
ret = -errno; ret = -errno;
goto out; goto out;
} }
for (ifg = ifgr.ifgr_groups; ifg && ifgr.ifgr_len > 0; ++ifg) for (ifg = ifgr.ifgr_groups; ifg && ifgr.ifgr_len > 0; ++ifg) {
{
if ((ret = string_list_add(list, ifg->ifgrq_member)) < 0) if ((ret = string_list_add(list, ifg->ifgrq_member)) < 0)
goto out; goto out;
ifgr.ifgr_len -= sizeof(struct ifg_req); ifgr.ifgr_len -= sizeof(struct ifg_req);
@ -76,8 +74,7 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
*device = NULL; *device = NULL;
strlcpy(wgdata.wgd_name, iface, sizeof(wgdata.wgd_name)); strlcpy(wgdata.wgd_name, iface, sizeof(wgdata.wgd_name));
for (size_t last_size = wgdata.wgd_size;; last_size = wgdata.wgd_size) for (size_t last_size = wgdata.wgd_size;; last_size = wgdata.wgd_size) {
{
if (ioctl(s, SIOCGWG, (caddr_t)&wgdata) < 0) if (ioctl(s, SIOCGWG, (caddr_t)&wgdata) < 0)
goto out; goto out;
if (last_size >= wgdata.wgd_size) if (last_size >= wgdata.wgd_size)
@ -93,80 +90,67 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
goto out; goto out;
strlcpy(dev->name, iface, sizeof(dev->name)); strlcpy(dev->name, iface, sizeof(dev->name));
if (wg_iface->i_flags & WG_INTERFACE_HAS_RTABLE) if (wg_iface->i_flags & WG_INTERFACE_HAS_RTABLE) {
{
dev->fwmark = wg_iface->i_rtable; dev->fwmark = wg_iface->i_rtable;
dev->flags |= WGDEVICE_HAS_FWMARK; dev->flags |= WGDEVICE_HAS_FWMARK;
} }
if (wg_iface->i_flags & WG_INTERFACE_HAS_PORT) if (wg_iface->i_flags & WG_INTERFACE_HAS_PORT) {
{
dev->listen_port = wg_iface->i_port; dev->listen_port = wg_iface->i_port;
dev->flags |= WGDEVICE_HAS_LISTEN_PORT; dev->flags |= WGDEVICE_HAS_LISTEN_PORT;
} }
if (wg_iface->i_flags & WG_INTERFACE_HAS_PUBLIC) if (wg_iface->i_flags & WG_INTERFACE_HAS_PUBLIC) {
{
memcpy(dev->public_key, wg_iface->i_public, sizeof(dev->public_key)); memcpy(dev->public_key, wg_iface->i_public, sizeof(dev->public_key));
dev->flags |= WGDEVICE_HAS_PUBLIC_KEY; dev->flags |= WGDEVICE_HAS_PUBLIC_KEY;
} }
if (wg_iface->i_flags & WG_INTERFACE_HAS_PRIVATE) if (wg_iface->i_flags & WG_INTERFACE_HAS_PRIVATE) {
{
memcpy(dev->private_key, wg_iface->i_private, sizeof(dev->private_key)); memcpy(dev->private_key, wg_iface->i_private, sizeof(dev->private_key));
dev->flags |= WGDEVICE_HAS_PRIVATE_KEY; dev->flags |= WGDEVICE_HAS_PRIVATE_KEY;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_JC) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_JC) {
{
dev->junk_packet_count = wg_iface->i_junk_packet_count; dev->junk_packet_count = wg_iface->i_junk_packet_count;
dev->flags |= WGDEVICE_HAS_JC; dev->flags |= WGDEVICE_HAS_JC;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_JMIN) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_JMIN) {
{
dev->junk_packet_min_size = wg_iface->i_junk_packet_min_size; dev->junk_packet_min_size = wg_iface->i_junk_packet_min_size;
dev->flags |= WGDEVICE_HAS_JMIN; dev->flags |= WGDEVICE_HAS_JMIN;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_JMAX) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_JMAX) {
{
dev->junk_packet_max_size = wg_iface->i_junk_packet_max_size; dev->junk_packet_max_size = wg_iface->i_junk_packet_max_size;
dev->flags |= WGDEVICE_HAS_JMAX; dev->flags |= WGDEVICE_HAS_JMAX;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_S1) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_S1) {
{
dev->init_packet_junk_size = wg_iface->i_init_packet_junk_size; dev->init_packet_junk_size = wg_iface->i_init_packet_junk_size;
dev->flags |= WGDEVICE_HAS_S1; dev->flags |= WGDEVICE_HAS_S1;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_S2) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_S2) {
{
dev->response_packet_junk_size = wg_iface->i_response_packet_junk_size; dev->response_packet_junk_size = wg_iface->i_response_packet_junk_size;
dev->flags |= WGDEVICE_HAS_S2; dev->flags |= WGDEVICE_HAS_S2;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_H1) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_H1) {
{
dev->init_packet_magic_header = wg_iface->i_init_packet_magic_header; dev->init_packet_magic_header = wg_iface->i_init_packet_magic_header;
dev->flags |= WGDEVICE_HAS_H1; dev->flags |= WGDEVICE_HAS_H1;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_H2) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_H2) {
{
dev->response_packet_magic_header = wg_iface->i_response_packet_magic_header; dev->response_packet_magic_header = wg_iface->i_response_packet_magic_header;
dev->flags |= WGDEVICE_HAS_H2; dev->flags |= WGDEVICE_HAS_H2;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_H3) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_H3) {
{
dev->underload_packet_magic_header = wg_iface->i_underload_packet_magic_header; dev->underload_packet_magic_header = wg_iface->i_underload_packet_magic_header;
dev->flags |= WGDEVICE_HAS_H3; dev->flags |= WGDEVICE_HAS_H3;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_H4) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_H4) {
{
dev->transport_packet_magic_header = wg_iface->i_transport_packet_magic_header; dev->transport_packet_magic_header = wg_iface->i_transport_packet_magic_header;
dev->flags |= WGDEVICE_HAS_H4; dev->flags |= WGDEVICE_HAS_H4;
} }
@ -226,8 +210,7 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
} }
wg_peer = &wg_iface->i_peers[0]; wg_peer = &wg_iface->i_peers[0];
for (size_t i = 0; i < wg_iface->i_peers_count; ++i) for (size_t i = 0; i < wg_iface->i_peers_count; ++i) {
{
peer = calloc(1, sizeof(*peer)); peer = calloc(1, sizeof(*peer));
if (!peer) if (!peer)
goto out; goto out;
@ -238,27 +221,23 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
dev->last_peer->next_peer = peer; dev->last_peer->next_peer = peer;
dev->last_peer = peer; dev->last_peer = peer;
if (wg_peer->p_flags & WG_PEER_HAS_PUBLIC) if (wg_peer->p_flags & WG_PEER_HAS_PUBLIC) {
{
memcpy(peer->public_key, wg_peer->p_public, sizeof(peer->public_key)); memcpy(peer->public_key, wg_peer->p_public, sizeof(peer->public_key));
peer->flags |= WGPEER_HAS_PUBLIC_KEY; peer->flags |= WGPEER_HAS_PUBLIC_KEY;
} }
if (wg_peer->p_flags & WG_PEER_HAS_PSK) if (wg_peer->p_flags & WG_PEER_HAS_PSK) {
{
memcpy(peer->preshared_key, wg_peer->p_psk, sizeof(peer->preshared_key)); memcpy(peer->preshared_key, wg_peer->p_psk, sizeof(peer->preshared_key));
if (!key_is_zero(peer->preshared_key)) if (!key_is_zero(peer->preshared_key))
peer->flags |= WGPEER_HAS_PRESHARED_KEY; peer->flags |= WGPEER_HAS_PRESHARED_KEY;
} }
if (wg_peer->p_flags & WG_PEER_HAS_PKA) if (wg_peer->p_flags & WG_PEER_HAS_PKA) {
{
peer->persistent_keepalive_interval = wg_peer->p_pka; peer->persistent_keepalive_interval = wg_peer->p_pka;
peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL; peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
} }
if (wg_peer->p_flags & WG_PEER_HAS_ENDPOINT && if (wg_peer->p_flags & WG_PEER_HAS_ENDPOINT && wg_peer->p_sa.sa_len <= sizeof(peer->endpoint.addr))
wg_peer->p_sa.sa_len <= sizeof(peer->endpoint.addr))
memcpy(&peer->endpoint.addr, &wg_peer->p_sa, wg_peer->p_sa.sa_len); memcpy(&peer->endpoint.addr, &wg_peer->p_sa, wg_peer->p_sa.sa_len);
peer->rx_bytes = wg_peer->p_rxbytes; peer->rx_bytes = wg_peer->p_rxbytes;
@ -268,8 +247,7 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
peer->last_handshake_time.tv_nsec = wg_peer->p_last_handshake.tv_nsec; peer->last_handshake_time.tv_nsec = wg_peer->p_last_handshake.tv_nsec;
wg_aip = &wg_peer->p_aips[0]; wg_aip = &wg_peer->p_aips[0];
for (size_t j = 0; j < wg_peer->p_aips_count; ++j) for (size_t j = 0; j < wg_peer->p_aips_count; ++j) {
{
aip = calloc(1, sizeof(*aip)); aip = calloc(1, sizeof(*aip));
if (!aip) if (!aip)
goto out; goto out;
@ -281,13 +259,10 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
peer->last_allowedip = aip; peer->last_allowedip = aip;
aip->family = wg_aip->a_af; aip->family = wg_aip->a_af;
if (wg_aip->a_af == AF_INET) if (wg_aip->a_af == AF_INET) {
{
memcpy(&aip->ip4, &wg_aip->a_ipv4, sizeof(aip->ip4)); memcpy(&aip->ip4, &wg_aip->a_ipv4, sizeof(aip->ip4));
aip->cidr = wg_aip->a_cidr; aip->cidr = wg_aip->a_cidr;
} } else if (wg_aip->a_af == AF_INET6) {
else if (wg_aip->a_af == AF_INET6)
{
memcpy(&aip->ip6, &wg_aip->a_ipv6, sizeof(aip->ip6)); memcpy(&aip->ip6, &wg_aip->a_ipv6, sizeof(aip->ip6));
aip->cidr = wg_aip->a_cidr; aip->cidr = wg_aip->a_cidr;
} }
@ -317,30 +292,27 @@ static int kernel_set_device(struct wgdevice* dev)
if (s < 0) if (s < 0)
return -errno; return -errno;
for_each_wgpeer(dev, peer) for_each_wgpeer(dev, peer) {
{
wgdata.wgd_size += sizeof(struct wg_peer_io); wgdata.wgd_size += sizeof(struct wg_peer_io);
for_each_wgallowedip(peer, aip) wgdata.wgd_size += sizeof(struct wg_aip_io); for_each_wgallowedip(peer, aip)
wgdata.wgd_size += sizeof(struct wg_aip_io);
} }
wg_iface = wgdata.wgd_interface = calloc(1, wgdata.wgd_size); wg_iface = wgdata.wgd_interface = calloc(1, wgdata.wgd_size);
if (!wgdata.wgd_interface) if (!wgdata.wgd_interface)
return -errno; return -errno;
strlcpy(wgdata.wgd_name, dev->name, sizeof(wgdata.wgd_name)); strlcpy(wgdata.wgd_name, dev->name, sizeof(wgdata.wgd_name));
if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) {
{
memcpy(wg_iface->i_private, dev->private_key, sizeof(wg_iface->i_private)); memcpy(wg_iface->i_private, dev->private_key, sizeof(wg_iface->i_private));
wg_iface->i_flags |= WG_INTERFACE_HAS_PRIVATE; wg_iface->i_flags |= WG_INTERFACE_HAS_PRIVATE;
} }
if (dev->flags & WGDEVICE_HAS_LISTEN_PORT) if (dev->flags & WGDEVICE_HAS_LISTEN_PORT) {
{
wg_iface->i_port = dev->listen_port; wg_iface->i_port = dev->listen_port;
wg_iface->i_flags |= WG_INTERFACE_HAS_PORT; wg_iface->i_flags |= WG_INTERFACE_HAS_PORT;
} }
if (dev->flags & WGDEVICE_HAS_FWMARK) if (dev->flags & WGDEVICE_HAS_FWMARK) {
{
wg_iface->i_rtable = dev->fwmark; wg_iface->i_rtable = dev->fwmark;
wg_iface->i_flags |= WG_INTERFACE_HAS_RTABLE; wg_iface->i_flags |= WG_INTERFACE_HAS_RTABLE;
} }
@ -348,56 +320,48 @@ static int kernel_set_device(struct wgdevice* dev)
if (dev->flags & WGDEVICE_REPLACE_PEERS) if (dev->flags & WGDEVICE_REPLACE_PEERS)
wg_iface->i_flags |= WG_INTERFACE_REPLACE_PEERS; wg_iface->i_flags |= WG_INTERFACE_REPLACE_PEERS;
if (dev->flags & WGDEVICE_HAS_JC)
{ if (dev->flags & WGDEVICE_HAS_JC) {
wg_iface->i_junk_packet_count = dev->junk_packet_count; wg_iface->i_junk_packet_count = dev->junk_packet_count;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_JC; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_JC;
} }
if (dev->flags & WGDEVICE_HAS_JMIN) if (dev->flags & WGDEVICE_HAS_JMIN) {
{
wg_iface->i_junk_packet_min_size = dev->junk_packet_min_size; wg_iface->i_junk_packet_min_size = dev->junk_packet_min_size;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_JMIN; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_JMIN;
} }
if (dev->flags & WGDEVICE_HAS_JMAX) if (dev->flags & WGDEVICE_HAS_JMAX) {
{
wg_iface->i_junk_packet_max_size = dev->junk_packet_max_size; wg_iface->i_junk_packet_max_size = dev->junk_packet_max_size;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_JMAX; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_JMAX;
} }
if (dev->flags & WGDEVICE_HAS_S1) if (dev->flags & WGDEVICE_HAS_S1) {
{
wg_iface->i_init_packet_junk_size = dev->init_packet_junk_size; wg_iface->i_init_packet_junk_size = dev->init_packet_junk_size;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_S1; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_S1;
} }
if (dev->flags & WGDEVICE_HAS_S2) if (dev->flags & WGDEVICE_HAS_S2) {
{
wg_iface->i_response_packet_junk_size = dev->response_packet_junk_size; wg_iface->i_response_packet_junk_size = dev->response_packet_junk_size;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_S2; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_S2;
} }
if (dev->flags & WGDEVICE_HAS_H1) if (dev->flags & WGDEVICE_HAS_H1) {
{
wg_iface->i_init_packet_magic_header = dev->init_packet_magic_header; wg_iface->i_init_packet_magic_header = dev->init_packet_magic_header;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H1; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H1;
} }
if (dev->flags & WGDEVICE_HAS_H2) if (dev->flags & WGDEVICE_HAS_H2) {
{
wg_iface->i_response_packet_magic_header = dev->response_packet_magic_header; wg_iface->i_response_packet_magic_header = dev->response_packet_magic_header;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H2; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H2;
} }
if (dev->flags & WGDEVICE_HAS_H3) if (dev->flags & WGDEVICE_HAS_H3) {
{
wg_iface->i_underload_packet_magic_header = dev->underload_packet_magic_header; wg_iface->i_underload_packet_magic_header = dev->underload_packet_magic_header;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H3; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H3;
} }
if (dev->flags & WGDEVICE_HAS_H4) if (dev->flags & WGDEVICE_HAS_H4) {
{
wg_iface->i_transport_packet_magic_header = dev->transport_packet_magic_header; wg_iface->i_transport_packet_magic_header = dev->transport_packet_magic_header;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H4; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H4;
} }
@ -458,29 +422,23 @@ static int kernel_set_device(struct wgdevice* dev)
peer_count = 0; peer_count = 0;
wg_peer = &wg_iface->i_peers[0]; wg_peer = &wg_iface->i_peers[0];
for_each_wgpeer(dev, peer) for_each_wgpeer(dev, peer) {
{
wg_peer->p_flags = WG_PEER_HAS_PUBLIC; wg_peer->p_flags = WG_PEER_HAS_PUBLIC;
memcpy(wg_peer->p_public, peer->public_key, sizeof(wg_peer->p_public)); memcpy(wg_peer->p_public, peer->public_key, sizeof(wg_peer->p_public));
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) if (peer->flags & WGPEER_HAS_PRESHARED_KEY) {
{
memcpy(wg_peer->p_psk, peer->preshared_key, sizeof(wg_peer->p_psk)); memcpy(wg_peer->p_psk, peer->preshared_key, sizeof(wg_peer->p_psk));
wg_peer->p_flags |= WG_PEER_HAS_PSK; wg_peer->p_flags |= WG_PEER_HAS_PSK;
} }
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) {
{
wg_peer->p_pka = peer->persistent_keepalive_interval; wg_peer->p_pka = peer->persistent_keepalive_interval;
wg_peer->p_flags |= WG_PEER_HAS_PKA; wg_peer->p_flags |= WG_PEER_HAS_PKA;
} }
if ((peer->endpoint.addr.sa_family == AF_INET || if ((peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) &&
peer->endpoint.addr.sa_family == AF_INET6) && peer->endpoint.addr.sa_len <= sizeof(wg_peer->p_endpoint)) {
peer->endpoint.addr.sa_len <= sizeof(wg_peer->p_endpoint)) memcpy(&wg_peer->p_endpoint, &peer->endpoint.addr, peer->endpoint.addr.sa_len);
{
memcpy(
&wg_peer->p_endpoint, &peer->endpoint.addr, peer->endpoint.addr.sa_len);
wg_peer->p_flags |= WG_PEER_HAS_ENDPOINT; wg_peer->p_flags |= WG_PEER_HAS_ENDPOINT;
} }
@ -492,8 +450,7 @@ static int kernel_set_device(struct wgdevice* dev)
aip_count = 0; aip_count = 0;
wg_aip = &wg_peer->p_aips[0]; wg_aip = &wg_peer->p_aips[0];
for_each_wgallowedip(peer, aip) for_each_wgallowedip(peer, aip) {
{
wg_aip->a_af = aip->family; wg_aip->a_af = aip->family;
wg_aip->a_cidr = aip->cidr; wg_aip->a_cidr = aip->cidr;

View file

@ -3,10 +3,6 @@
* Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/ */
#include "containers.h"
#include "ctype.h"
#include "curve25519.h"
#include "encoding.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
@ -18,6 +14,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
#include "containers.h"
#include "curve25519.h"
#include "encoding.h"
#include "ctype.h"
#ifdef _WIN32 #ifdef _WIN32
#include "ipc-uapi-windows.h" #include "ipc-uapi-windows.h"
@ -41,8 +41,7 @@ static int userspace_set_device(struct wgdevice* dev)
return -errno; return -errno;
fprintf(f, "set=1\n"); fprintf(f, "set=1\n");
if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) {
{
key_to_hex(hex, dev->private_key); key_to_hex(hex, dev->private_key);
fprintf(f, "private_key=%s\n", hex); fprintf(f, "private_key=%s\n", hex);
} }
@ -70,6 +69,7 @@ static int userspace_set_device(struct wgdevice* dev)
fprintf(f, "h3=%u\n", dev->underload_packet_magic_header); fprintf(f, "h3=%u\n", dev->underload_packet_magic_header);
if (dev->flags & WGDEVICE_HAS_H4) if (dev->flags & WGDEVICE_HAS_H4)
fprintf(f, "h4=%u\n", dev->transport_packet_magic_header); fprintf(f, "h4=%u\n", dev->transport_packet_magic_header);
if (dev->flags & WGDEVICE_HAS_I1) if (dev->flags & WGDEVICE_HAS_I1)
fprintf(f, "i1=%s\n", dev->i1); fprintf(f, "i1=%s\n", dev->i1);
if (dev->flags & WGDEVICE_HAS_I2) if (dev->flags & WGDEVICE_HAS_I2)
@ -89,14 +89,10 @@ static int userspace_set_device(struct wgdevice* dev)
if (dev->flags & WGDEVICE_HAS_ITIME) if (dev->flags & WGDEVICE_HAS_ITIME)
fprintf(f, "itime=%u\n", dev->itime); fprintf(f, "itime=%u\n", dev->itime);
printf("i1: %s\n", dev->i1); for_each_wgpeer(dev, peer) {
for_each_wgpeer(dev, peer)
{
key_to_hex(hex, peer->public_key); key_to_hex(hex, peer->public_key);
fprintf(f, "public_key=%s\n", hex); fprintf(f, "public_key=%s\n", hex);
if (peer->flags & WGPEER_HAS_ADVANCED_SECURITY) if (peer->flags & WGPEER_HAS_ADVANCED_SECURITY) {
{
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
@ -105,33 +101,21 @@ static int userspace_set_device(struct wgdevice* dev)
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
if (peer->flags & WGPEER_REMOVE_ME) if (peer->flags & WGPEER_REMOVE_ME) {
{
fprintf(f, "remove=true\n"); fprintf(f, "remove=true\n");
continue; continue;
} }
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) if (peer->flags & WGPEER_HAS_PRESHARED_KEY) {
{
key_to_hex(hex, peer->preshared_key); key_to_hex(hex, peer->preshared_key);
fprintf(f, "preshared_key=%s\n", hex); fprintf(f, "preshared_key=%s\n", hex);
} }
if (peer->endpoint.addr.sa_family == AF_INET || if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) {
peer->endpoint.addr.sa_family == AF_INET6)
{
addr_len = 0; addr_len = 0;
if (peer->endpoint.addr.sa_family == AF_INET) if (peer->endpoint.addr.sa_family == AF_INET)
addr_len = sizeof(struct sockaddr_in); addr_len = sizeof(struct sockaddr_in);
else if (peer->endpoint.addr.sa_family == AF_INET6) else if (peer->endpoint.addr.sa_family == AF_INET6)
addr_len = sizeof(struct sockaddr_in6); addr_len = sizeof(struct sockaddr_in6);
if (!getnameinfo( if (!getnameinfo(&peer->endpoint.addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST)) {
&peer->endpoint.addr,
addr_len,
host,
sizeof(host),
service,
sizeof(service),
NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST))
{
if (peer->endpoint.addr.sa_family == AF_INET6 && strchr(host, ':')) if (peer->endpoint.addr.sa_family == AF_INET6 && strchr(host, ':'))
fprintf(f, "endpoint=[%s]:%s\n", host, service); fprintf(f, "endpoint=[%s]:%s\n", host, service);
else else
@ -139,25 +123,17 @@ static int userspace_set_device(struct wgdevice* dev)
} }
} }
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL)
fprintf( fprintf(f, "persistent_keepalive_interval=%u\n", peer->persistent_keepalive_interval);
f,
"persistent_keepalive_interval=%u\n",
peer->persistent_keepalive_interval);
if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS) if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS)
fprintf(f, "replace_allowed_ips=true\n"); fprintf(f, "replace_allowed_ips=true\n");
for_each_wgallowedip(peer, allowedip) for_each_wgallowedip(peer, allowedip) {
{ if (allowedip->family == AF_INET) {
if (allowedip->family == AF_INET)
{
if (!inet_ntop(AF_INET, &allowedip->ip4, ip, INET6_ADDRSTRLEN)) if (!inet_ntop(AF_INET, &allowedip->ip4, ip, INET6_ADDRSTRLEN))
continue; continue;
} } else if (allowedip->family == AF_INET6) {
else if (allowedip->family == AF_INET6)
{
if (!inet_ntop(AF_INET6, &allowedip->ip6, ip, INET6_ADDRSTRLEN)) if (!inet_ntop(AF_INET6, &allowedip->ip6, ip, INET6_ADDRSTRLEN))
continue; continue;
} } else
else
continue; continue;
fprintf(f, "allowed_ip=%s/%d\n", ip, allowedip->cidr); fprintf(f, "allowed_ip=%s/%d\n", ip, allowedip->cidr);
} }
@ -165,8 +141,7 @@ static int userspace_set_device(struct wgdevice* dev)
fprintf(f, "\n"); fprintf(f, "\n");
fflush(f); fflush(f);
while (getline(&key, &line_buffer_len, f) > 0) while (getline(&key, &line_buffer_len, f) > 0) {
{
line_len = strlen(key); line_len = strlen(key);
ret = set_errno; ret = set_errno;
if (line_len == 1 && key[0] == '\n') if (line_len == 1 && key[0] == '\n')
@ -176,8 +151,7 @@ static int userspace_set_device(struct wgdevice* dev)
break; break;
*value++ = key[--line_len] = '\0'; *value++ = key[--line_len] = '\0';
if (!strcmp(key, "errno")) if (!strcmp(key, "errno")) {
{
long long num; long long num;
char *end; char *end;
if (value[0] != '-' && !char_is_digit(value[0])) if (value[0] != '-' && !char_is_digit(value[0]))
@ -196,8 +170,7 @@ out:
return ret; return ret;
} }
#define NUM(max) \ #define NUM(max) ({ \
({ \
unsigned long long num; \ unsigned long long num; \
char *end; \ char *end; \
if (!char_is_digit(value[0])) \ if (!char_is_digit(value[0])) \
@ -223,8 +196,7 @@ static int userspace_get_device(struct wgdevice** out, const char* iface)
return -errno; return -errno;
f = userspace_interface_file(iface); f = userspace_interface_file(iface);
if (!f) if (!f) {
{
ret = -errno; ret = -errno;
free(dev); free(dev);
*out = NULL; *out = NULL;
@ -237,8 +209,7 @@ static int userspace_get_device(struct wgdevice** out, const char* iface)
strncpy(dev->name, iface, IFNAMSIZ - 1); strncpy(dev->name, iface, IFNAMSIZ - 1);
dev->name[IFNAMSIZ - 1] = '\0'; dev->name[IFNAMSIZ - 1] = '\0';
while (getline(&key, &line_buffer_len, f) > 0) while (getline(&key, &line_buffer_len, f) > 0) {
{
line_len = strlen(key); line_len = strlen(key);
if (line_len == 1 && key[0] == '\n') if (line_len == 1 && key[0] == '\n')
goto err; goto err;
@ -247,119 +218,83 @@ static int userspace_get_device(struct wgdevice** out, const char* iface)
break; break;
*value++ = key[--line_len] = '\0'; *value++ = key[--line_len] = '\0';
if (!peer && !strcmp(key, "private_key")) if (!peer && !strcmp(key, "private_key")) {
{
if (!key_from_hex(dev->private_key, value)) if (!key_from_hex(dev->private_key, value))
break; break;
curve25519_generate_public(dev->public_key, dev->private_key); curve25519_generate_public(dev->public_key, dev->private_key);
dev->flags |= WGDEVICE_HAS_PRIVATE_KEY | WGDEVICE_HAS_PUBLIC_KEY; dev->flags |= WGDEVICE_HAS_PRIVATE_KEY | WGDEVICE_HAS_PUBLIC_KEY;
} } else if (!peer && !strcmp(key, "listen_port")) {
else if (!peer && !strcmp(key, "listen_port"))
{
dev->listen_port = NUM(0xffffU); dev->listen_port = NUM(0xffffU);
dev->flags |= WGDEVICE_HAS_LISTEN_PORT; dev->flags |= WGDEVICE_HAS_LISTEN_PORT;
} } else if (!peer && !strcmp(key, "fwmark")) {
else if (!peer && !strcmp(key, "fwmark"))
{
dev->fwmark = NUM(0xffffffffU); dev->fwmark = NUM(0xffffffffU);
dev->flags |= WGDEVICE_HAS_FWMARK; dev->flags |= WGDEVICE_HAS_FWMARK;
} } else if(!peer && !strcmp(key, "jc")) {
else if (!peer && !strcmp(key, "jc"))
{
dev->junk_packet_count = NUM(0xffffU); dev->junk_packet_count = NUM(0xffffU);
dev->flags |= WGDEVICE_HAS_JC; dev->flags |= WGDEVICE_HAS_JC;
} } else if(!peer && !strcmp(key, "jmin")) {
else if (!peer && !strcmp(key, "jmin"))
{
dev->junk_packet_min_size = NUM(0xffffU); dev->junk_packet_min_size = NUM(0xffffU);
dev->flags |= WGDEVICE_HAS_JMIN; dev->flags |= WGDEVICE_HAS_JMIN;
} } else if(!peer && !strcmp(key, "jmax")) {
else if (!peer && !strcmp(key, "jmax"))
{
dev->junk_packet_max_size = NUM(0xffffU); dev->junk_packet_max_size = NUM(0xffffU);
dev->flags |= WGDEVICE_HAS_JMAX; dev->flags |= WGDEVICE_HAS_JMAX;
} } else if(!peer && !strcmp(key, "s1")) {
else if (!peer && !strcmp(key, "s1"))
{
dev->init_packet_junk_size = NUM(0xffffU); dev->init_packet_junk_size = NUM(0xffffU);
dev->flags |= WGDEVICE_HAS_S1; dev->flags |= WGDEVICE_HAS_S1;
} } else if(!peer && !strcmp(key, "s2")) {
else if (!peer && !strcmp(key, "s2"))
{
dev->response_packet_junk_size = NUM(0xffffU); dev->response_packet_junk_size = NUM(0xffffU);
dev->flags |= WGDEVICE_HAS_S2; dev->flags |= WGDEVICE_HAS_S2;
} } else if(!peer && !strcmp(key, "h1")) {
else if (!peer && !strcmp(key, "h1"))
{
dev->init_packet_magic_header = NUM(0xffffffffU); dev->init_packet_magic_header = NUM(0xffffffffU);
dev->flags |= WGDEVICE_HAS_H1; dev->flags |= WGDEVICE_HAS_H1;
} } else if(!peer && !strcmp(key, "h2")) {
else if (!peer && !strcmp(key, "h2"))
{
dev->response_packet_magic_header = NUM(0xffffffffU); dev->response_packet_magic_header = NUM(0xffffffffU);
dev->flags |= WGDEVICE_HAS_H2; dev->flags |= WGDEVICE_HAS_H2;
} } else if(!peer && !strcmp(key, "h3")) {
else if (!peer && !strcmp(key, "h3"))
{
dev->underload_packet_magic_header = NUM(0xffffffffU); dev->underload_packet_magic_header = NUM(0xffffffffU);
dev->flags |= WGDEVICE_HAS_H3; dev->flags |= WGDEVICE_HAS_H3;
} } else if(!peer && !strcmp(key, "h4")) {
else if (!peer && !strcmp(key, "h4"))
{
dev->transport_packet_magic_header = NUM(0xffffffffU); dev->transport_packet_magic_header = NUM(0xffffffffU);
dev->flags |= WGDEVICE_HAS_H4; dev->flags |= WGDEVICE_HAS_H4;
} } else if (!peer && !strcmp(key, "i1")) {
else if (!peer && !strcmp(key, "i1"))
{
dev->i1 = strdup(value); dev->i1 = strdup(value);
dev->flags |= WGDEVICE_HAS_I1; dev->flags |= WGDEVICE_HAS_I1;
} }
else if (!peer && !strcmp(key, "i2")) else if (!peer && !strcmp(key, "i2")) {
{
dev->i2 = strdup(value); dev->i2 = strdup(value);
dev->flags |= WGDEVICE_HAS_I2; dev->flags |= WGDEVICE_HAS_I2;
} }
else if (!peer && !strcmp(key, "i3")) else if (!peer && !strcmp(key, "i3")) {
{
dev->i3 = strdup(value); dev->i3 = strdup(value);
dev->flags |= WGDEVICE_HAS_I3; dev->flags |= WGDEVICE_HAS_I3;
} }
else if (!peer && !strcmp(key, "i4")) else if (!peer && !strcmp(key, "i4")) {
{
dev->i4 = strdup(value); dev->i4 = strdup(value);
dev->flags |= WGDEVICE_HAS_I4; dev->flags |= WGDEVICE_HAS_I4;
} }
else if (!peer && !strcmp(key, "i5")) else if (!peer && !strcmp(key, "i5")) {
{
dev->i5 = strdup(value); dev->i5 = strdup(value);
dev->flags |= WGDEVICE_HAS_I5; dev->flags |= WGDEVICE_HAS_I5;
} }
else if (!peer && !strcmp(key, "j1")) else if (!peer && !strcmp(key, "j1")) {
{
dev->j1 = strdup(value); dev->j1 = strdup(value);
dev->flags |= WGDEVICE_HAS_J1; dev->flags |= WGDEVICE_HAS_J1;
} }
else if (!peer && !strcmp(key, "j2")) else if (!peer && !strcmp(key, "j2")) {
{
dev->j2 = strdup(value); dev->j2 = strdup(value);
dev->flags |= WGDEVICE_HAS_J2; dev->flags |= WGDEVICE_HAS_J2;
} }
else if (!peer && !strcmp(key, "j3")) else if (!peer && !strcmp(key, "j3")) {
{
dev->j3 = strdup(value); dev->j3 = strdup(value);
dev->flags |= WGDEVICE_HAS_J3; dev->flags |= WGDEVICE_HAS_J3;
} }
else if (!peer && !strcmp(key, "itime")) else if (!peer && !strcmp(key, "itime")) {
{
dev->itime = NUM(0xffffffffU); dev->itime = NUM(0xffffffffU);
dev->flags |= WGDEVICE_HAS_ITIME; dev->flags |= WGDEVICE_HAS_ITIME;
} } else if (!strcmp(key, "public_key")) {
else if (!strcmp(key, "public_key"))
{
struct wgpeer *new_peer = calloc(1, sizeof(*new_peer)); struct wgpeer *new_peer = calloc(1, sizeof(*new_peer));
if (!new_peer) if (!new_peer) {
{
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
@ -372,26 +307,22 @@ static int userspace_get_device(struct wgdevice** out, const char* iface)
if (!key_from_hex(peer->public_key, value)) if (!key_from_hex(peer->public_key, value))
break; break;
peer->flags |= WGPEER_HAS_PUBLIC_KEY; peer->flags |= WGPEER_HAS_PUBLIC_KEY;
} } else if (peer && !strcmp(key, "preshared_key")) {
else if (peer && !strcmp(key, "preshared_key"))
{
if (!key_from_hex(peer->preshared_key, value)) if (!key_from_hex(peer->preshared_key, value))
break; break;
if (!key_is_zero(peer->preshared_key)) if (!key_is_zero(peer->preshared_key))
peer->flags |= WGPEER_HAS_PRESHARED_KEY; peer->flags |= WGPEER_HAS_PRESHARED_KEY;
} } else if (peer && !strcmp(key, "endpoint")) {
else if (peer && !strcmp(key, "endpoint"))
{
char *begin, *end; char *begin, *end;
struct addrinfo *resolved; struct addrinfo *resolved;
struct addrinfo hints = { struct addrinfo hints = {
.ai_family = AF_UNSPEC, .ai_family = AF_UNSPEC,
.ai_socktype = SOCK_DGRAM, .ai_socktype = SOCK_DGRAM,
.ai_protocol = IPPROTO_UDP}; .ai_protocol = IPPROTO_UDP
};
if (!strlen(value)) if (!strlen(value))
break; break;
if (value[0] == '[') if (value[0] == '[') {
{
begin = &value[1]; begin = &value[1];
end = strchr(value, ']'); end = strchr(value, ']');
if (!end) if (!end)
@ -399,47 +330,36 @@ static int userspace_get_device(struct wgdevice** out, const char* iface)
*end++ = '\0'; *end++ = '\0';
if (*end++ != ':' || !*end) if (*end++ != ':' || !*end)
break; break;
} } else {
else
{
begin = value; begin = value;
end = strrchr(value, ':'); end = strrchr(value, ':');
if (!end || !*(end + 1)) if (!end || !*(end + 1))
break; break;
*end++ = '\0'; *end++ = '\0';
} }
if (getaddrinfo(begin, end, &hints, &resolved) != 0) if (getaddrinfo(begin, end, &hints, &resolved) != 0) {
{
ret = ENETUNREACH; ret = ENETUNREACH;
goto err; goto err;
} }
if ((resolved->ai_family == AF_INET && if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) ||
resolved->ai_addrlen == sizeof(struct sockaddr_in)) || (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6)))
(resolved->ai_family == AF_INET6 &&
resolved->ai_addrlen == sizeof(struct sockaddr_in6)))
memcpy(&peer->endpoint.addr, resolved->ai_addr, resolved->ai_addrlen); memcpy(&peer->endpoint.addr, resolved->ai_addr, resolved->ai_addrlen);
else else {
{
freeaddrinfo(resolved); freeaddrinfo(resolved);
break; break;
} }
freeaddrinfo(resolved); freeaddrinfo(resolved);
} } else if (peer && !strcmp(key, "persistent_keepalive_interval")) {
else if (peer && !strcmp(key, "persistent_keepalive_interval"))
{
peer->persistent_keepalive_interval = NUM(0xffffU); peer->persistent_keepalive_interval = NUM(0xffffU);
peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL; peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
} } else if (peer && !strcmp(key, "allowed_ip")) {
else if (peer && !strcmp(key, "allowed_ip"))
{
struct wgallowedip *new_allowedip; struct wgallowedip *new_allowedip;
char *end, *mask = value, *ip = strsep(&mask, "/"); char *end, *mask = value, *ip = strsep(&mask, "/");
if (!mask || !char_is_digit(mask[0])) if (!mask || !char_is_digit(mask[0]))
break; break;
new_allowedip = calloc(1, sizeof(*new_allowedip)); new_allowedip = calloc(1, sizeof(*new_allowedip));
if (!new_allowedip) if (!new_allowedip) {
{
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
@ -449,23 +369,17 @@ static int userspace_get_device(struct wgdevice** out, const char* iface)
peer->first_allowedip = new_allowedip; peer->first_allowedip = new_allowedip;
allowedip = new_allowedip; allowedip = new_allowedip;
allowedip->family = AF_UNSPEC; allowedip->family = AF_UNSPEC;
if (strchr(ip, ':')) if (strchr(ip, ':')) {
{
if (inet_pton(AF_INET6, ip, &allowedip->ip6) == 1) if (inet_pton(AF_INET6, ip, &allowedip->ip6) == 1)
allowedip->family = AF_INET6; allowedip->family = AF_INET6;
} } else {
else
{
if (inet_pton(AF_INET, ip, &allowedip->ip4) == 1) if (inet_pton(AF_INET, ip, &allowedip->ip4) == 1)
allowedip->family = AF_INET; allowedip->family = AF_INET;
} }
allowedip->cidr = strtoul(mask, &end, 10); allowedip->cidr = strtoul(mask, &end, 10);
if (*end || allowedip->family == AF_UNSPEC || if (*end || allowedip->family == AF_UNSPEC || (allowedip->family == AF_INET6 && allowedip->cidr > 128) || (allowedip->family == AF_INET && allowedip->cidr > 32))
(allowedip->family == AF_INET6 && allowedip->cidr > 128) ||
(allowedip->family == AF_INET && allowedip->cidr > 32))
break; break;
} } else if (peer && !strcmp(key, "last_handshake_time_sec"))
else if (peer && !strcmp(key, "last_handshake_time_sec"))
peer->last_handshake_time.tv_sec = NUM(0x7fffffffffffffffULL); peer->last_handshake_time.tv_sec = NUM(0x7fffffffffffffffULL);
else if (peer && !strcmp(key, "last_handshake_time_nsec")) else if (peer && !strcmp(key, "last_handshake_time_nsec"))
peer->last_handshake_time.tv_nsec = NUM(0x7fffffffffffffffULL); peer->last_handshake_time.tv_nsec = NUM(0x7fffffffffffffffULL);
@ -479,13 +393,13 @@ static int userspace_get_device(struct wgdevice** out, const char* iface)
ret = -EPROTO; ret = -EPROTO;
err: err:
free(key); free(key);
if (ret) if (ret) {
{
free_wgdevice(dev); free_wgdevice(dev);
*out = NULL; *out = NULL;
} }
fclose(f); fclose(f);
errno = -ret; errno = -ret;
return ret; return ret;
} }
#undef NUM #undef NUM

View file

@ -4,15 +4,15 @@
*/ */
#include "containers.h" #include "containers.h"
#include <cfgmgr32.h>
#include <ddk/ndisguid.h>
#include <devguid.h>
#include <hashtable.h>
#include <initguid.h>
#include <iphlpapi.h>
#include <setupapi.h>
#include <windows.h> #include <windows.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#include <iphlpapi.h>
#include <initguid.h>
#include <devguid.h>
#include <ddk/ndisguid.h>
#include <wireguard.h> #include <wireguard.h>
#include <hashtable.h>
#define IPC_SUPPORTS_KERNEL_INTERFACE #define IPC_SUPPORTS_KERNEL_INTERFACE
@ -23,24 +23,15 @@ extern bool is_win7;
static int kernel_get_wireguard_interfaces(struct string_list *list) static int kernel_get_wireguard_interfaces(struct string_list *list)
{ {
HDEVINFO dev_info = SetupDiGetClassDevsExW( HDEVINFO dev_info = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, is_win7 ? L"ROOT\\WIREGUARD" : L"SWD\\WireGuard", NULL, DIGCF_PRESENT, NULL, NULL, NULL);
&GUID_DEVCLASS_NET,
is_win7 ? L"ROOT\\WIREGUARD" : L"SWD\\WireGuard",
NULL,
DIGCF_PRESENT,
NULL,
NULL,
NULL);
bool will_have_cached_kernel_interfaces = true; bool will_have_cached_kernel_interfaces = true;
if (dev_info == INVALID_HANDLE_VALUE) if (dev_info == INVALID_HANDLE_VALUE) {
{
errno = EACCES; errno = EACCES;
return -errno; return -errno;
} }
for (DWORD i = 0;; ++i) for (DWORD i = 0;; ++i) {
{
DWORD buf_len; DWORD buf_len;
WCHAR adapter_name[MAX_ADAPTER_NAME]; WCHAR adapter_name[MAX_ADAPTER_NAME];
SP_DEVINFO_DATA dev_info_data = { .cbSize = sizeof(SP_DEVINFO_DATA) }; SP_DEVINFO_DATA dev_info_data = { .cbSize = sizeof(SP_DEVINFO_DATA) };
@ -49,22 +40,15 @@ static int kernel_get_wireguard_interfaces(struct string_list* list)
char *interface_name; char *interface_name;
struct hashtable_entry *entry; struct hashtable_entry *entry;
if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) {
{
if (GetLastError() == ERROR_NO_MORE_ITEMS) if (GetLastError() == ERROR_NO_MORE_ITEMS)
break; break;
continue; continue;
} }
if (!SetupDiGetDevicePropertyW( if (!SetupDiGetDevicePropertyW(dev_info, &dev_info_data, &devpkey_name,
dev_info, &prop_type, (PBYTE)adapter_name,
&dev_info_data, sizeof(adapter_name), NULL, 0) ||
&devpkey_name,
&prop_type,
(PBYTE)adapter_name,
sizeof(adapter_name),
NULL,
0) ||
prop_type != DEVPROP_TYPE_STRING) prop_type != DEVPROP_TYPE_STRING)
continue; continue;
adapter_name[_countof(adapter_name) - 1] = L'0'; adapter_name[_countof(adapter_name) - 1] = L'0';
@ -76,16 +60,13 @@ static int kernel_get_wireguard_interfaces(struct string_list* list)
interface_name = malloc(buf_len); interface_name = malloc(buf_len);
if (!interface_name) if (!interface_name)
continue; continue;
buf_len = WideCharToMultiByte( buf_len = WideCharToMultiByte(CP_UTF8, 0, adapter_name, -1, interface_name, buf_len, NULL, NULL);
CP_UTF8, 0, adapter_name, -1, interface_name, buf_len, NULL, NULL); if (!buf_len) {
if (!buf_len)
{
free(interface_name); free(interface_name);
continue; continue;
} }
if (CM_Get_DevNode_Status(&status, &problem_code, dev_info_data.DevInst, 0) == if (CM_Get_DevNode_Status(&status, &problem_code, dev_info_data.DevInst, 0) == CR_SUCCESS &&
CR_SUCCESS &&
(status & (DN_DRIVER_LOADED | DN_STARTED)) == (DN_DRIVER_LOADED | DN_STARTED)) (status & (DN_DRIVER_LOADED | DN_STARTED)) == (DN_DRIVER_LOADED | DN_STARTED))
string_list_add(list, interface_name); string_list_add(list, interface_name);
@ -94,15 +75,12 @@ static int kernel_get_wireguard_interfaces(struct string_list* list)
if (!entry) if (!entry)
continue; continue;
if (SetupDiGetDeviceInstanceIdW(dev_info, &dev_info_data, NULL, 0, &buf_len) || if (SetupDiGetDeviceInstanceIdW(dev_info, &dev_info_data, NULL, 0, &buf_len) || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
GetLastError() != ERROR_INSUFFICIENT_BUFFER)
continue; continue;
entry->value = calloc(sizeof(WCHAR), buf_len); entry->value = calloc(sizeof(WCHAR), buf_len);
if (!entry->value) if (!entry->value)
continue; continue;
if (!SetupDiGetDeviceInstanceIdW( if (!SetupDiGetDeviceInstanceIdW(dev_info, &dev_info_data, entry->value, buf_len, &buf_len)) {
dev_info, &dev_info_data, entry->value, buf_len, &buf_len))
{
free(entry->value); free(entry->value);
entry->value = NULL; entry->value = NULL;
continue; continue;
@ -121,42 +99,27 @@ static HANDLE kernel_interface_handle(const char* iface)
WCHAR *interfaces = NULL; WCHAR *interfaces = NULL;
HANDLE handle; HANDLE handle;
if (have_cached_kernel_interfaces) if (have_cached_kernel_interfaces) {
{ struct hashtable_entry *entry = hashtable_find_entry(&cached_kernel_interfaces, iface);
struct hashtable_entry* entry = if (entry) {
hashtable_find_entry(&cached_kernel_interfaces, iface);
if (entry)
{
DWORD buf_len; DWORD buf_len;
if (CM_Get_Device_Interface_List_SizeW( if (CM_Get_Device_Interface_List_SizeW(
&buf_len, &buf_len, (GUID *)&GUID_DEVINTERFACE_NET, (DEVINSTID_W)entry->value,
(GUID*)&GUID_DEVINTERFACE_NET,
(DEVINSTID_W)entry->value,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS) CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS)
goto err_hash; goto err_hash;
interfaces = calloc(buf_len, sizeof(*interfaces)); interfaces = calloc(buf_len, sizeof(*interfaces));
if (!interfaces) if (!interfaces)
goto err_hash; goto err_hash;
if (CM_Get_Device_Interface_ListW( if (CM_Get_Device_Interface_ListW(
(GUID*)&GUID_DEVINTERFACE_NET, (GUID *)&GUID_DEVINTERFACE_NET, (DEVINSTID_W)entry->value, interfaces, buf_len,
(DEVINSTID_W)entry->value, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS || !interfaces[0]) {
interfaces,
buf_len,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS ||
!interfaces[0])
{
free(interfaces); free(interfaces);
interfaces = NULL; interfaces = NULL;
goto err_hash; goto err_hash;
} }
handle = CreateFileW( handle = CreateFileW(interfaces, GENERIC_READ | GENERIC_WRITE,
interfaces, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
GENERIC_READ | GENERIC_WRITE, OPEN_EXISTING, 0, NULL);
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
0,
NULL);
free(interfaces); free(interfaces);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
goto err_hash; goto err_hash;
@ -167,19 +130,11 @@ static HANDLE kernel_interface_handle(const char* iface)
} }
} }
dev_info = SetupDiGetClassDevsExW( dev_info = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, is_win7 ? L"ROOT\\WIREGUARD" : L"SWD\\WireGuard", NULL, DIGCF_PRESENT, NULL, NULL, NULL);
&GUID_DEVCLASS_NET,
is_win7 ? L"ROOT\\WIREGUARD" : L"SWD\\WireGuard",
NULL,
DIGCF_PRESENT,
NULL,
NULL,
NULL);
if (dev_info == INVALID_HANDLE_VALUE) if (dev_info == INVALID_HANDLE_VALUE)
return NULL; return NULL;
for (DWORD i = 0; !interfaces; ++i) for (DWORD i = 0; !interfaces; ++i) {
{
bool found; bool found;
DWORD buf_len; DWORD buf_len;
WCHAR *buf, adapter_name[MAX_ADAPTER_NAME]; WCHAR *buf, adapter_name[MAX_ADAPTER_NAME];
@ -187,22 +142,15 @@ static HANDLE kernel_interface_handle(const char* iface)
DEVPROPTYPE prop_type; DEVPROPTYPE prop_type;
char *interface_name; char *interface_name;
if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) {
{
if (GetLastError() == ERROR_NO_MORE_ITEMS) if (GetLastError() == ERROR_NO_MORE_ITEMS)
break; break;
continue; continue;
} }
if (!SetupDiGetDevicePropertyW( if (!SetupDiGetDevicePropertyW(dev_info, &dev_info_data, &devpkey_name,
dev_info, &prop_type, (PBYTE)adapter_name,
&dev_info_data, sizeof(adapter_name), NULL, 0) ||
&devpkey_name,
&prop_type,
(PBYTE)adapter_name,
sizeof(adapter_name),
NULL,
0) ||
prop_type != DEVPROP_TYPE_STRING) prop_type != DEVPROP_TYPE_STRING)
continue; continue;
adapter_name[_countof(adapter_name) - 1] = L'0'; adapter_name[_countof(adapter_name) - 1] = L'0';
@ -214,10 +162,8 @@ static HANDLE kernel_interface_handle(const char* iface)
interface_name = malloc(buf_len); interface_name = malloc(buf_len);
if (!interface_name) if (!interface_name)
continue; continue;
buf_len = WideCharToMultiByte( buf_len = WideCharToMultiByte(CP_UTF8, 0, adapter_name, -1, interface_name, buf_len, NULL, NULL);
CP_UTF8, 0, adapter_name, -1, interface_name, buf_len, NULL, NULL); if (!buf_len) {
if (!buf_len)
{
free(interface_name); free(interface_name);
continue; continue;
} }
@ -226,32 +172,23 @@ static HANDLE kernel_interface_handle(const char* iface)
if (!found) if (!found)
continue; continue;
if (SetupDiGetDeviceInstanceIdW(dev_info, &dev_info_data, NULL, 0, &buf_len) || if (SetupDiGetDeviceInstanceIdW(dev_info, &dev_info_data, NULL, 0, &buf_len) || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
GetLastError() != ERROR_INSUFFICIENT_BUFFER)
continue; continue;
buf = calloc(sizeof(*buf), buf_len); buf = calloc(sizeof(*buf), buf_len);
if (!buf) if (!buf)
continue; continue;
if (!SetupDiGetDeviceInstanceIdW( if (!SetupDiGetDeviceInstanceIdW(dev_info, &dev_info_data, buf, buf_len, &buf_len))
dev_info, &dev_info_data, buf, buf_len, &buf_len))
goto cleanup_instance_id; goto cleanup_instance_id;
if (CM_Get_Device_Interface_List_SizeW( if (CM_Get_Device_Interface_List_SizeW(
&buf_len, &buf_len, (GUID *)&GUID_DEVINTERFACE_NET, (DEVINSTID_W)buf,
(GUID*)&GUID_DEVINTERFACE_NET,
(DEVINSTID_W)buf,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS) CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS)
goto cleanup_instance_id; goto cleanup_instance_id;
interfaces = calloc(buf_len, sizeof(*interfaces)); interfaces = calloc(buf_len, sizeof(*interfaces));
if (!interfaces) if (!interfaces)
goto cleanup_instance_id; goto cleanup_instance_id;
if (CM_Get_Device_Interface_ListW( if (CM_Get_Device_Interface_ListW(
(GUID*)&GUID_DEVINTERFACE_NET, (GUID *)&GUID_DEVINTERFACE_NET, (DEVINSTID_W)buf, interfaces, buf_len,
(DEVINSTID_W)buf, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS || !interfaces[0]) {
interfaces,
buf_len,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS ||
!interfaces[0])
{
free(interfaces); free(interfaces);
interfaces = NULL; interfaces = NULL;
goto cleanup_instance_id; goto cleanup_instance_id;
@ -260,22 +197,15 @@ static HANDLE kernel_interface_handle(const char* iface)
free(buf); free(buf);
} }
SetupDiDestroyDeviceInfoList(dev_info); SetupDiDestroyDeviceInfoList(dev_info);
if (!interfaces) if (!interfaces) {
{
errno = ENOENT; errno = ENOENT;
return NULL; return NULL;
} }
handle = CreateFileW( handle = CreateFileW(interfaces, GENERIC_READ | GENERIC_WRITE,
interfaces, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
GENERIC_READ | GENERIC_WRITE, OPEN_EXISTING, 0, NULL);
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
0,
NULL);
free(interfaces); free(interfaces);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE) {
{
errno = EACCES; errno = EACCES;
return NULL; return NULL;
} }
@ -300,11 +230,9 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
if (!handle) if (!handle)
return -errno; return -errno;
while (!DeviceIoControl(handle, WG_IOCTL_GET, NULL, 0, buf, buf_len, &buf_len, NULL)) while (!DeviceIoControl(handle, WG_IOCTL_GET, NULL, 0, buf, buf_len, &buf_len, NULL)) {
{
free(buf); free(buf);
if (GetLastError() != ERROR_MORE_DATA) if (GetLastError() != ERROR_MORE_DATA) {
{
errno = EACCES; errno = EACCES;
return -errno; return -errno;
} }
@ -320,66 +248,54 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
strncpy(dev->name, iface, sizeof(dev->name)); strncpy(dev->name, iface, sizeof(dev->name));
dev->name[sizeof(dev->name) - 1] = '\0'; dev->name[sizeof(dev->name) - 1] = '\0';
if (wg_iface->Flags & WG_IOCTL_INTERFACE_HAS_LISTEN_PORT) if (wg_iface->Flags & WG_IOCTL_INTERFACE_HAS_LISTEN_PORT) {
{
dev->listen_port = wg_iface->ListenPort; dev->listen_port = wg_iface->ListenPort;
dev->flags |= WGDEVICE_HAS_LISTEN_PORT; dev->flags |= WGDEVICE_HAS_LISTEN_PORT;
} }
if (wg_iface->Flags & WG_IOCTL_INTERFACE_HAS_PUBLIC_KEY) if (wg_iface->Flags & WG_IOCTL_INTERFACE_HAS_PUBLIC_KEY) {
{
memcpy(dev->public_key, wg_iface->PublicKey, sizeof(dev->public_key)); memcpy(dev->public_key, wg_iface->PublicKey, sizeof(dev->public_key));
dev->flags |= WGDEVICE_HAS_PUBLIC_KEY; dev->flags |= WGDEVICE_HAS_PUBLIC_KEY;
} }
if (wg_iface->Flags & WG_IOCTL_INTERFACE_HAS_PRIVATE_KEY) if (wg_iface->Flags & WG_IOCTL_INTERFACE_HAS_PRIVATE_KEY) {
{
memcpy(dev->private_key, wg_iface->PrivateKey, sizeof(dev->private_key)); memcpy(dev->private_key, wg_iface->PrivateKey, sizeof(dev->private_key));
dev->flags |= WGDEVICE_HAS_PRIVATE_KEY; dev->flags |= WGDEVICE_HAS_PRIVATE_KEY;
} }
if (wg_iface->Flags & WG_IOCTL_INTERFACE_JC) if (wg_iface->Flags & WG_IOCTL_INTERFACE_JC) {
{
dev->junk_packet_count = wg_iface->JunkPacketCount; dev->junk_packet_count = wg_iface->JunkPacketCount;
dev->flags |= WGDEVICE_HAS_JC; dev->flags |= WGDEVICE_HAS_JC;
} }
if (wg_iface->Flags & WG_IOCTL_INTERFACE_JMIN) if (wg_iface->Flags & WG_IOCTL_INTERFACE_JMIN) {
{
dev->junk_packet_min_size = wg_iface->JunkPacketMinSize; dev->junk_packet_min_size = wg_iface->JunkPacketMinSize;
dev->flags |= WGDEVICE_HAS_JMIN; dev->flags |= WGDEVICE_HAS_JMIN;
} }
if (wg_iface->Flags & WG_IOCTL_INTERFACE_JMAX) if (wg_iface->Flags & WG_IOCTL_INTERFACE_JMAX) {
{
dev->junk_packet_max_size = wg_iface->JunkPacketMaxSize; dev->junk_packet_max_size = wg_iface->JunkPacketMaxSize;
dev->flags |= WGDEVICE_HAS_JMAX; dev->flags |= WGDEVICE_HAS_JMAX;
} }
if (wg_iface->Flags & WG_IOCTL_INTERFACE_S1) if (wg_iface->Flags & WG_IOCTL_INTERFACE_S1) {
{
dev->init_packet_junk_size = wg_iface->InitPacketJunkSize; dev->init_packet_junk_size = wg_iface->InitPacketJunkSize;
dev->flags |= WGDEVICE_HAS_S1; dev->flags |= WGDEVICE_HAS_S1;
} }
if (wg_iface->Flags & WG_IOCTL_INTERFACE_S2) if (wg_iface->Flags & WG_IOCTL_INTERFACE_S2) {
{
dev->response_packet_junk_size = wg_iface->ResponsePacketJunkSize; dev->response_packet_junk_size = wg_iface->ResponsePacketJunkSize;
dev->flags |= WGDEVICE_HAS_S2; dev->flags |= WGDEVICE_HAS_S2;
} }
if (wg_iface->Flags & WG_IOCTL_INTERFACE_H1) if (wg_iface->Flags & WG_IOCTL_INTERFACE_H1) {
{
dev->init_packet_magic_header = wg_iface->InitPacketMagicHeader; dev->init_packet_magic_header = wg_iface->InitPacketMagicHeader;
dev->flags |= WGDEVICE_HAS_H1; dev->flags |= WGDEVICE_HAS_H1;
} }
if (wg_iface->Flags & WG_IOCTL_INTERFACE_H2) if (wg_iface->Flags & WG_IOCTL_INTERFACE_H2) {
{
dev->response_packet_magic_header = wg_iface->ResponsePacketMagicHeader; dev->response_packet_magic_header = wg_iface->ResponsePacketMagicHeader;
dev->flags |= WGDEVICE_HAS_H2; dev->flags |= WGDEVICE_HAS_H2;
} }
if (wg_iface->Flags & WG_IOCTL_INTERFACE_H3) if (wg_iface->Flags & WG_IOCTL_INTERFACE_H3) {
{
dev->underload_packet_magic_header = wg_iface->UnderloadPacketMagicHeader; dev->underload_packet_magic_header = wg_iface->UnderloadPacketMagicHeader;
dev->flags |= WGDEVICE_HAS_H3; dev->flags |= WGDEVICE_HAS_H3;
} }
if (wg_iface->Flags & WG_IOCTL_INTERFACE_H4) if (wg_iface->Flags & WG_IOCTL_INTERFACE_H4) {
{
dev->transport_packet_magic_header = wg_iface->TransportPacketMagicHeader; dev->transport_packet_magic_header = wg_iface->TransportPacketMagicHeader;
dev->flags |= WGDEVICE_HAS_H4; dev->flags |= WGDEVICE_HAS_H4;
} }
@ -446,8 +362,7 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
} }
wg_peer = buf + sizeof(WG_IOCTL_INTERFACE); wg_peer = buf + sizeof(WG_IOCTL_INTERFACE);
for (ULONG i = 0; i < wg_iface->PeersCount; ++i) for (ULONG i = 0; i < wg_iface->PeersCount; ++i) {
{
peer = calloc(1, sizeof(*peer)); peer = calloc(1, sizeof(*peer));
if (!peer) if (!peer)
goto out; goto out;
@ -458,28 +373,23 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
dev->last_peer->next_peer = peer; dev->last_peer->next_peer = peer;
dev->last_peer = peer; dev->last_peer = peer;
if (wg_peer->Flags & WG_IOCTL_PEER_HAS_PUBLIC_KEY) if (wg_peer->Flags & WG_IOCTL_PEER_HAS_PUBLIC_KEY) {
{
memcpy(peer->public_key, wg_peer->PublicKey, sizeof(peer->public_key)); memcpy(peer->public_key, wg_peer->PublicKey, sizeof(peer->public_key));
peer->flags |= WGPEER_HAS_PUBLIC_KEY; peer->flags |= WGPEER_HAS_PUBLIC_KEY;
} }
if (wg_peer->Flags & WG_IOCTL_PEER_HAS_PRESHARED_KEY) if (wg_peer->Flags & WG_IOCTL_PEER_HAS_PRESHARED_KEY) {
{ memcpy(peer->preshared_key, wg_peer->PresharedKey, sizeof(peer->preshared_key));
memcpy(
peer->preshared_key, wg_peer->PresharedKey, sizeof(peer->preshared_key));
if (!key_is_zero(peer->preshared_key)) if (!key_is_zero(peer->preshared_key))
peer->flags |= WGPEER_HAS_PRESHARED_KEY; peer->flags |= WGPEER_HAS_PRESHARED_KEY;
} }
if (wg_peer->Flags & WG_IOCTL_PEER_HAS_PERSISTENT_KEEPALIVE) if (wg_peer->Flags & WG_IOCTL_PEER_HAS_PERSISTENT_KEEPALIVE) {
{
peer->persistent_keepalive_interval = wg_peer->PersistentKeepalive; peer->persistent_keepalive_interval = wg_peer->PersistentKeepalive;
peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL; peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
} }
if (wg_peer->Flags & WG_IOCTL_PEER_HAS_ENDPOINT) if (wg_peer->Flags & WG_IOCTL_PEER_HAS_ENDPOINT) {
{
if (wg_peer->Endpoint.si_family == AF_INET) if (wg_peer->Endpoint.si_family == AF_INET)
peer->endpoint.addr4 = wg_peer->Endpoint.Ipv4; peer->endpoint.addr4 = wg_peer->Endpoint.Ipv4;
else if (wg_peer->Endpoint.si_family == AF_INET6) else if (wg_peer->Endpoint.si_family == AF_INET6)
@ -489,16 +399,13 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
peer->rx_bytes = wg_peer->RxBytes; peer->rx_bytes = wg_peer->RxBytes;
peer->tx_bytes = wg_peer->TxBytes; peer->tx_bytes = wg_peer->TxBytes;
if (wg_peer->LastHandshake) if (wg_peer->LastHandshake) {
{ peer->last_handshake_time.tv_sec = wg_peer->LastHandshake / 10000000 - 11644473600LL;
peer->last_handshake_time.tv_sec =
wg_peer->LastHandshake / 10000000 - 11644473600LL;
peer->last_handshake_time.tv_nsec = wg_peer->LastHandshake % 10000000 * 100; peer->last_handshake_time.tv_nsec = wg_peer->LastHandshake % 10000000 * 100;
} }
wg_aip = (void *)wg_peer + sizeof(WG_IOCTL_PEER); wg_aip = (void *)wg_peer + sizeof(WG_IOCTL_PEER);
for (ULONG j = 0; j < wg_peer->AllowedIPsCount; ++j) for (ULONG j = 0; j < wg_peer->AllowedIPsCount; ++j) {
{
aip = calloc(1, sizeof(*aip)); aip = calloc(1, sizeof(*aip));
if (!aip) if (!aip)
goto out; goto out;
@ -510,13 +417,10 @@ static int kernel_get_device(struct wgdevice** device, const char* iface)
peer->last_allowedip = aip; peer->last_allowedip = aip;
aip->family = wg_aip->AddressFamily; aip->family = wg_aip->AddressFamily;
if (wg_aip->AddressFamily == AF_INET) if (wg_aip->AddressFamily == AF_INET) {
{
memcpy(&aip->ip4, &wg_aip->Address.V4, sizeof(aip->ip4)); memcpy(&aip->ip4, &wg_aip->Address.V4, sizeof(aip->ip4));
aip->cidr = wg_aip->Cidr; aip->cidr = wg_aip->Cidr;
} } else if (wg_aip->AddressFamily == AF_INET6) {
else if (wg_aip->AddressFamily == AF_INET6)
{
memcpy(&aip->ip6, &wg_aip->Address.V6, sizeof(aip->ip6)); memcpy(&aip->ip6, &wg_aip->Address.V6, sizeof(aip->ip6));
aip->cidr = wg_aip->Cidr; aip->cidr = wg_aip->Cidr;
} }
@ -548,18 +452,14 @@ static int kernel_set_device(struct wgdevice* dev)
if (!handle) if (!handle)
return -errno; return -errno;
for_each_wgpeer(dev, peer) for_each_wgpeer(dev, peer) {
{ if (DWORD_MAX - buf_len < sizeof(WG_IOCTL_PEER)) {
if (DWORD_MAX - buf_len < sizeof(WG_IOCTL_PEER))
{
errno = EOVERFLOW; errno = EOVERFLOW;
goto out; goto out;
} }
buf_len += sizeof(WG_IOCTL_PEER); buf_len += sizeof(WG_IOCTL_PEER);
for_each_wgallowedip(peer, aip) for_each_wgallowedip(peer, aip) {
{ if (DWORD_MAX - buf_len < sizeof(WG_IOCTL_ALLOWED_IP)) {
if (DWORD_MAX - buf_len < sizeof(WG_IOCTL_ALLOWED_IP))
{
errno = EOVERFLOW; errno = EOVERFLOW;
goto out; goto out;
} }
@ -570,14 +470,12 @@ static int kernel_set_device(struct wgdevice* dev)
if (!wg_iface) if (!wg_iface)
goto out; goto out;
if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) {
{
memcpy(wg_iface->PrivateKey, dev->private_key, sizeof(wg_iface->PrivateKey)); memcpy(wg_iface->PrivateKey, dev->private_key, sizeof(wg_iface->PrivateKey));
wg_iface->Flags |= WG_IOCTL_INTERFACE_HAS_PRIVATE_KEY; wg_iface->Flags |= WG_IOCTL_INTERFACE_HAS_PRIVATE_KEY;
} }
if (dev->flags & WGDEVICE_HAS_LISTEN_PORT) if (dev->flags & WGDEVICE_HAS_LISTEN_PORT) {
{
wg_iface->ListenPort = dev->listen_port; wg_iface->ListenPort = dev->listen_port;
wg_iface->Flags |= WG_IOCTL_INTERFACE_HAS_LISTEN_PORT; wg_iface->Flags |= WG_IOCTL_INTERFACE_HAS_LISTEN_PORT;
} }
@ -585,59 +483,51 @@ static int kernel_set_device(struct wgdevice* dev)
if (dev->flags & WGDEVICE_REPLACE_PEERS) if (dev->flags & WGDEVICE_REPLACE_PEERS)
wg_iface->Flags |= WG_IOCTL_INTERFACE_REPLACE_PEERS; wg_iface->Flags |= WG_IOCTL_INTERFACE_REPLACE_PEERS;
if (dev->flags & WGDEVICE_HAS_JC) if (dev->flags & WGDEVICE_HAS_JC) {
{
wg_iface->JunkPacketCount = dev->junk_packet_count; wg_iface->JunkPacketCount = dev->junk_packet_count;
wg_iface->Flags |= WG_IOCTL_INTERFACE_JC; wg_iface->Flags |= WG_IOCTL_INTERFACE_JC;
} }
if (dev->flags & WGDEVICE_HAS_JMIN) if (dev->flags & WGDEVICE_HAS_JMIN) {
{
wg_iface->JunkPacketMinSize = dev->junk_packet_min_size; wg_iface->JunkPacketMinSize = dev->junk_packet_min_size;
wg_iface->Flags |= WG_IOCTL_INTERFACE_JMIN; wg_iface->Flags |= WG_IOCTL_INTERFACE_JMIN;
} }
if (dev->flags & WGDEVICE_HAS_JMAX) if (dev->flags & WGDEVICE_HAS_JMAX) {
{
wg_iface->JunkPacketMaxSize = dev->junk_packet_max_size; wg_iface->JunkPacketMaxSize = dev->junk_packet_max_size;
wg_iface->Flags |= WG_IOCTL_INTERFACE_JMAX; wg_iface->Flags |= WG_IOCTL_INTERFACE_JMAX;
} }
if (dev->flags & WGDEVICE_HAS_S1) if (dev->flags & WGDEVICE_HAS_S1) {
{
wg_iface->InitPacketJunkSize = dev->init_packet_junk_size; wg_iface->InitPacketJunkSize = dev->init_packet_junk_size;
wg_iface->Flags |= WG_IOCTL_INTERFACE_S1; wg_iface->Flags |= WG_IOCTL_INTERFACE_S1;
} }
if (dev->flags & WGDEVICE_HAS_S2) if (dev->flags & WGDEVICE_HAS_S2) {
{
wg_iface->ResponsePacketJunkSize = dev->response_packet_junk_size; wg_iface->ResponsePacketJunkSize = dev->response_packet_junk_size;
wg_iface->Flags |= WG_IOCTL_INTERFACE_S2; wg_iface->Flags |= WG_IOCTL_INTERFACE_S2;
} }
if (dev->flags & WGDEVICE_HAS_H1) if (dev->flags & WGDEVICE_HAS_H1) {
{
wg_iface->InitPacketMagicHeader = dev->init_packet_magic_header; wg_iface->InitPacketMagicHeader = dev->init_packet_magic_header;
wg_iface->Flags |= WG_IOCTL_INTERFACE_H1; wg_iface->Flags |= WG_IOCTL_INTERFACE_H1;
} }
if (dev->flags & WGDEVICE_HAS_H2) if (dev->flags & WGDEVICE_HAS_H2) {
{
wg_iface->ResponsePacketMagicHeader = dev->response_packet_magic_header; wg_iface->ResponsePacketMagicHeader = dev->response_packet_magic_header;
wg_iface->Flags |= WG_IOCTL_INTERFACE_H2; wg_iface->Flags |= WG_IOCTL_INTERFACE_H2;
} }
if (dev->flags & WGDEVICE_HAS_H3) if (dev->flags & WGDEVICE_HAS_H3) {
{
wg_iface->UnderloadPacketMagicHeader = dev->underload_packet_magic_header; wg_iface->UnderloadPacketMagicHeader = dev->underload_packet_magic_header;
wg_iface->Flags |= WG_IOCTL_INTERFACE_H3; wg_iface->Flags |= WG_IOCTL_INTERFACE_H3;
} }
if (dev->flags & WGDEVICE_HAS_H4) if (dev->flags & WGDEVICE_HAS_H4) {
{
wg_iface->TransportPacketMagicHeader = dev->transport_packet_magic_header; wg_iface->TransportPacketMagicHeader = dev->transport_packet_magic_header;
wg_iface->Flags |= WG_IOCTL_INTERFACE_H4; wg_iface->Flags |= WG_IOCTL_INTERFACE_H4;
} }
if (dev->flags & WG_DEVICE_HAS_I1) if (dev->flags & WG_DEVICE_HAS_I1)
{ {
const size_t i1_size = strlen(dev->i1) + 1; const size_t i1_size = strlen(dev->i1) + 1;
@ -702,33 +592,24 @@ static int kernel_set_device(struct wgdevice* dev)
peer_count = 0; peer_count = 0;
wg_peer = (void *)wg_iface + sizeof(WG_IOCTL_INTERFACE); wg_peer = (void *)wg_iface + sizeof(WG_IOCTL_INTERFACE);
for_each_wgpeer(dev, peer) for_each_wgpeer(dev, peer) {
{
wg_peer->Flags = WG_IOCTL_PEER_HAS_PUBLIC_KEY; wg_peer->Flags = WG_IOCTL_PEER_HAS_PUBLIC_KEY;
memcpy(wg_peer->PublicKey, peer->public_key, sizeof(wg_peer->PublicKey)); memcpy(wg_peer->PublicKey, peer->public_key, sizeof(wg_peer->PublicKey));
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) if (peer->flags & WGPEER_HAS_PRESHARED_KEY) {
{ memcpy(wg_peer->PresharedKey, peer->preshared_key, sizeof(wg_peer->PresharedKey));
memcpy(
wg_peer->PresharedKey,
peer->preshared_key,
sizeof(wg_peer->PresharedKey));
wg_peer->Flags |= WG_IOCTL_PEER_HAS_PRESHARED_KEY; wg_peer->Flags |= WG_IOCTL_PEER_HAS_PRESHARED_KEY;
} }
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) {
{
wg_peer->PersistentKeepalive = peer->persistent_keepalive_interval; wg_peer->PersistentKeepalive = peer->persistent_keepalive_interval;
wg_peer->Flags |= WG_IOCTL_PEER_HAS_PERSISTENT_KEEPALIVE; wg_peer->Flags |= WG_IOCTL_PEER_HAS_PERSISTENT_KEEPALIVE;
} }
if (peer->endpoint.addr.sa_family == AF_INET) if (peer->endpoint.addr.sa_family == AF_INET) {
{
wg_peer->Endpoint.Ipv4 = peer->endpoint.addr4; wg_peer->Endpoint.Ipv4 = peer->endpoint.addr4;
wg_peer->Flags |= WG_IOCTL_PEER_HAS_ENDPOINT; wg_peer->Flags |= WG_IOCTL_PEER_HAS_ENDPOINT;
} } else if (peer->endpoint.addr.sa_family == AF_INET6) {
else if (peer->endpoint.addr.sa_family == AF_INET6)
{
wg_peer->Endpoint.Ipv6 = peer->endpoint.addr6; wg_peer->Endpoint.Ipv6 = peer->endpoint.addr6;
wg_peer->Flags |= WG_IOCTL_PEER_HAS_ENDPOINT; wg_peer->Flags |= WG_IOCTL_PEER_HAS_ENDPOINT;
} }
@ -741,8 +622,7 @@ static int kernel_set_device(struct wgdevice* dev)
aip_count = 0; aip_count = 0;
wg_aip = (void *)wg_peer + sizeof(WG_IOCTL_PEER); wg_aip = (void *)wg_peer + sizeof(WG_IOCTL_PEER);
for_each_wgallowedip(peer, aip) for_each_wgallowedip(peer, aip) {
{
wg_aip->AddressFamily = aip->family; wg_aip->AddressFamily = aip->family;
wg_aip->Cidr = aip->cidr; wg_aip->Cidr = aip->cidr;
@ -761,9 +641,7 @@ static int kernel_set_device(struct wgdevice* dev)
} }
wg_iface->PeersCount = peer_count; wg_iface->PeersCount = peer_count;
if (!DeviceIoControl( if (!DeviceIoControl(handle, WG_IOCTL_SET, NULL, 0, wg_iface, buf_len, &buf_len, NULL)) {
handle, WG_IOCTL_SET, NULL, 0, wg_iface, buf_len, &buf_len, NULL))
{
errno = EACCES; errno = EACCES;
goto out; goto out;
} }

View file

@ -6,18 +6,18 @@
/* This is a minimized version of libmnl meant to be #include'd */ /* This is a minimized version of libmnl meant to be #include'd */
#include <errno.h>
#include <linux/genetlink.h>
#include <linux/netlink.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/genetlink.h>
#define MNL_SOCKET_AUTOPID 0 #define MNL_SOCKET_AUTOPID 0
#define MNL_ALIGNTO 4 #define MNL_ALIGNTO 4
@ -25,8 +25,7 @@
#define MNL_NLMSG_HDRLEN MNL_ALIGN(sizeof(struct nlmsghdr)) #define MNL_NLMSG_HDRLEN MNL_ALIGN(sizeof(struct nlmsghdr))
#define MNL_ATTR_HDRLEN MNL_ALIGN(sizeof(struct nlattr)) #define MNL_ATTR_HDRLEN MNL_ALIGN(sizeof(struct nlattr))
enum mnl_attr_data_type enum mnl_attr_data_type {
{
MNL_TYPE_UNSPEC, MNL_TYPE_UNSPEC,
MNL_TYPE_U8, MNL_TYPE_U8,
MNL_TYPE_U16, MNL_TYPE_U16,
@ -48,10 +47,8 @@ enum mnl_attr_data_type
(attr) = mnl_attr_next(attr)) (attr) = mnl_attr_next(attr))
#define mnl_attr_for_each_nested(attr, nest) \ #define mnl_attr_for_each_nested(attr, nest) \
for ((attr) = mnl_attr_get_payload(nest); mnl_attr_ok( \ for ((attr) = mnl_attr_get_payload(nest); \
(attr), \ mnl_attr_ok((attr), (char *)mnl_attr_get_payload(nest) + mnl_attr_get_payload_len(nest) - (char *)(attr)); \
(char*)mnl_attr_get_payload(nest) + mnl_attr_get_payload_len(nest) - \
(char*)(attr)); \
(attr) = mnl_attr_next(attr)) (attr) = mnl_attr_next(attr))
#define mnl_attr_for_each_payload(payload, payload_size) \ #define mnl_attr_for_each_payload(payload, payload_size) \
@ -82,7 +79,10 @@ static size_t mnl_ideal_socket_buffer_size(void)
return size; return size;
} }
static size_t mnl_nlmsg_size(size_t len) { return len + MNL_NLMSG_HDRLEN; } static size_t mnl_nlmsg_size(size_t len)
{
return len + MNL_NLMSG_HDRLEN;
}
static struct nlmsghdr *mnl_nlmsg_put_header(void *buf) static struct nlmsghdr *mnl_nlmsg_put_header(void *buf)
{ {
@ -116,7 +116,8 @@ static void* mnl_nlmsg_get_payload_offset(const struct nlmsghdr* nlh, size_t off
static bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len) static bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
{ {
return len >= (int)sizeof(struct nlmsghdr) && return len >= (int)sizeof(struct nlmsghdr) &&
nlh->nlmsg_len >= sizeof(struct nlmsghdr) && (int)nlh->nlmsg_len <= len; nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
(int)nlh->nlmsg_len <= len;
} }
static struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len) static struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len)
@ -157,7 +158,8 @@ static void* mnl_attr_get_payload(const struct nlattr* attr)
static bool mnl_attr_ok(const struct nlattr *attr, int len) static bool mnl_attr_ok(const struct nlattr *attr, int len)
{ {
return len >= (int)sizeof(struct nlattr) && attr->nla_len >= sizeof(struct nlattr) && return len >= (int)sizeof(struct nlattr) &&
attr->nla_len >= sizeof(struct nlattr) &&
(int)attr->nla_len <= len; (int)attr->nla_len <= len;
} }
@ -168,51 +170,42 @@ static struct nlattr* mnl_attr_next(const struct nlattr* attr)
static int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max) static int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
{ {
if (mnl_attr_get_type(attr) > max) if (mnl_attr_get_type(attr) > max) {
{
errno = EOPNOTSUPP; errno = EOPNOTSUPP;
return -1; return -1;
} }
return 1; return 1;
} }
static int __mnl_attr_validate( static int __mnl_attr_validate(const struct nlattr *attr,
const struct nlattr* attr, enum mnl_attr_data_type type, size_t exp_len)
enum mnl_attr_data_type type,
size_t exp_len)
{ {
uint16_t attr_len = mnl_attr_get_payload_len(attr); uint16_t attr_len = mnl_attr_get_payload_len(attr);
const char *attr_data = mnl_attr_get_payload(attr); const char *attr_data = mnl_attr_get_payload(attr);
if (attr_len < exp_len) if (attr_len < exp_len) {
{
errno = ERANGE; errno = ERANGE;
return -1; return -1;
} }
switch (type) switch(type) {
{
case MNL_TYPE_FLAG: case MNL_TYPE_FLAG:
if (attr_len > 0) if (attr_len > 0) {
{
errno = ERANGE; errno = ERANGE;
return -1; return -1;
} }
break; break;
case MNL_TYPE_NUL_STRING: case MNL_TYPE_NUL_STRING:
if (attr_len == 0) if (attr_len == 0) {
{
errno = ERANGE; errno = ERANGE;
return -1; return -1;
} }
if (attr_data[attr_len - 1] != '\0') if (attr_data[attr_len-1] != '\0') {
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
break; break;
case MNL_TYPE_STRING: case MNL_TYPE_STRING:
if (attr_len == 0) if (attr_len == 0) {
{
errno = ERANGE; errno = ERANGE;
return -1; return -1;
} }
@ -222,8 +215,7 @@ static int __mnl_attr_validate(
if (attr_len == 0) if (attr_len == 0)
break; break;
if (attr_len < MNL_ATTR_HDRLEN) if (attr_len < MNL_ATTR_HDRLEN) {
{
errno = ERANGE; errno = ERANGE;
return -1; return -1;
} }
@ -232,8 +224,7 @@ static int __mnl_attr_validate(
break; break;
} }
if (exp_len && attr_len > exp_len) if (exp_len && attr_len > exp_len) {
{
errno = ERANGE; errno = ERANGE;
return -1; return -1;
} }
@ -252,8 +243,7 @@ static int mnl_attr_validate(const struct nlattr* attr, enum mnl_attr_data_type
{ {
int exp_len; int exp_len;
if (type >= MNL_TYPE_MAX) if (type >= MNL_TYPE_MAX) {
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -261,28 +251,27 @@ static int mnl_attr_validate(const struct nlattr* attr, enum mnl_attr_data_type
return __mnl_attr_validate(attr, type, exp_len); return __mnl_attr_validate(attr, type, exp_len);
} }
static int mnl_attr_parse( static int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset,
const struct nlmsghdr* nlh, mnl_attr_cb_t cb, void *data)
unsigned int offset, {
mnl_attr_cb_t cb, int ret = MNL_CB_OK;
const struct nlattr *attr;
mnl_attr_for_each(attr, nlh, offset)
if ((ret = cb(attr, data)) <= MNL_CB_STOP)
return ret;
return ret;
}
static int mnl_attr_parse_nested(const struct nlattr *nested, mnl_attr_cb_t cb,
void *data) void *data)
{ {
int ret = MNL_CB_OK; int ret = MNL_CB_OK;
const struct nlattr *attr; const struct nlattr *attr;
mnl_attr_for_each( mnl_attr_for_each_nested(attr, nested)
attr, nlh, offset) if ((ret = cb(attr, data)) <= MNL_CB_STOP) return ret; if ((ret = cb(attr, data)) <= MNL_CB_STOP)
return ret; return ret;
}
static int
mnl_attr_parse_nested(const struct nlattr* nested, mnl_attr_cb_t cb, void* data)
{
int ret = MNL_CB_OK;
const struct nlattr* attr;
mnl_attr_for_each_nested(
attr, nested) if ((ret = cb(attr, data)) <= MNL_CB_STOP) return ret;
return ret; return ret;
} }
@ -313,8 +302,8 @@ static const char* mnl_attr_get_str(const struct nlattr* attr)
return mnl_attr_get_payload(attr); return mnl_attr_get_payload(attr);
} }
static void static void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len,
mnl_attr_put(struct nlmsghdr* nlh, uint16_t type, size_t len, const void* data) const void *data)
{ {
struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh); struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh);
uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len; uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len;
@ -323,7 +312,6 @@ mnl_attr_put(struct nlmsghdr* nlh, uint16_t type, size_t len, const void* data)
attr->nla_type = type; attr->nla_type = type;
attr->nla_len = payload_len; attr->nla_len = payload_len;
memcpy(mnl_attr_get_payload(attr), data, len); memcpy(mnl_attr_get_payload(attr), data, len);
nlh->nlmsg_len += MNL_ALIGN(payload_len); nlh->nlmsg_len += MNL_ALIGN(payload_len);
pad = MNL_ALIGN(len) - len; pad = MNL_ALIGN(len) - len;
if (pad > 0) if (pad > 0)
@ -354,12 +342,8 @@ static struct nlattr* mnl_attr_nest_start(struct nlmsghdr* nlh, uint16_t type)
return start; return start;
} }
static bool mnl_attr_put_check( static bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen,
struct nlmsghdr* nlh, uint16_t type, size_t len, const void *data)
size_t buflen,
uint16_t type,
size_t len,
const void* data)
{ {
if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen) if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen)
return false; return false;
@ -367,26 +351,26 @@ static bool mnl_attr_put_check(
return true; return true;
} }
static bool static bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen,
mnl_attr_put_u8_check(struct nlmsghdr* nlh, size_t buflen, uint16_t type, uint8_t data) uint16_t type, uint8_t data)
{ {
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint8_t), &data); return mnl_attr_put_check(nlh, buflen, type, sizeof(uint8_t), &data);
} }
static bool static bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen,
mnl_attr_put_u16_check(struct nlmsghdr* nlh, size_t buflen, uint16_t type, uint16_t data) uint16_t type, uint16_t data)
{ {
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint16_t), &data); return mnl_attr_put_check(nlh, buflen, type, sizeof(uint16_t), &data);
} }
static bool static bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen,
mnl_attr_put_u32_check(struct nlmsghdr* nlh, size_t buflen, uint16_t type, uint32_t data) uint16_t type, uint32_t data)
{ {
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint32_t), &data); return mnl_attr_put_check(nlh, buflen, type, sizeof(uint32_t), &data);
} }
static struct nlattr* static struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh, size_t buflen,
mnl_attr_nest_start_check(struct nlmsghdr* nlh, size_t buflen, uint16_t type) uint16_t type)
{ {
if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen) if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen)
return NULL; return NULL;
@ -403,9 +387,7 @@ static void mnl_attr_nest_cancel(struct nlmsghdr* nlh, struct nlattr* start)
nlh->nlmsg_len -= mnl_nlmsg_get_payload_tail(nlh) - (void *)start; nlh->nlmsg_len -= mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
} }
static int mnl_cb_noop( static int mnl_cb_noop(__attribute__((unused)) const struct nlmsghdr *nlh, __attribute__((unused)) void *data)
__attribute__((unused)) const struct nlmsghdr* nlh,
__attribute__((unused)) void* data)
{ {
return MNL_CB_OK; return MNL_CB_OK;
} }
@ -414,8 +396,7 @@ static int mnl_cb_error(const struct nlmsghdr* nlh, __attribute__((unused)) void
{ {
const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) {
{
errno = EBADMSG; errno = EBADMSG;
return MNL_CB_ERROR; return MNL_CB_ERROR;
} }
@ -428,9 +409,7 @@ static int mnl_cb_error(const struct nlmsghdr* nlh, __attribute__((unused)) void
return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR; return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
} }
static int mnl_cb_stop( static int mnl_cb_stop(__attribute__((unused)) const struct nlmsghdr *nlh, __attribute__((unused)) void *data)
__attribute__((unused)) const struct nlmsghdr* nlh,
__attribute__((unused)) void* data)
{ {
return MNL_CB_STOP; return MNL_CB_STOP;
} }
@ -442,60 +421,45 @@ static const mnl_cb_t default_cb_array[NLMSG_MIN_TYPE] = {
[NLMSG_OVERRUN] = mnl_cb_noop, [NLMSG_OVERRUN] = mnl_cb_noop,
}; };
static int __mnl_cb_run( static int __mnl_cb_run(const void *buf, size_t numbytes,
const void* buf, unsigned int seq, unsigned int portid,
size_t numbytes, mnl_cb_t cb_data, void *data,
unsigned int seq,
unsigned int portid,
mnl_cb_t cb_data,
void* data,
const mnl_cb_t *cb_ctl_array, const mnl_cb_t *cb_ctl_array,
unsigned int cb_ctl_array_len) unsigned int cb_ctl_array_len)
{ {
int ret = MNL_CB_OK, len = numbytes; int ret = MNL_CB_OK, len = numbytes;
const struct nlmsghdr *nlh = buf; const struct nlmsghdr *nlh = buf;
while (mnl_nlmsg_ok(nlh, len)) while (mnl_nlmsg_ok(nlh, len)) {
{
if (!mnl_nlmsg_portid_ok(nlh, portid)) if (!mnl_nlmsg_portid_ok(nlh, portid)) {
{
errno = ESRCH; errno = ESRCH;
return -1; return -1;
} }
if (!mnl_nlmsg_seq_ok(nlh, seq)) if (!mnl_nlmsg_seq_ok(nlh, seq)) {
{
errno = EPROTO; errno = EPROTO;
return -1; return -1;
} }
if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) {
{
errno = EINTR; errno = EINTR;
return -1; return -1;
} }
if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) {
{ if (cb_data){
if (cb_data)
{
ret = cb_data(nlh, data); ret = cb_data(nlh, data);
if (ret <= MNL_CB_STOP) if (ret <= MNL_CB_STOP)
goto out; goto out;
} }
} } else if (nlh->nlmsg_type < cb_ctl_array_len) {
else if (nlh->nlmsg_type < cb_ctl_array_len) if (cb_ctl_array && cb_ctl_array[nlh->nlmsg_type]) {
{
if (cb_ctl_array && cb_ctl_array[nlh->nlmsg_type])
{
ret = cb_ctl_array[nlh->nlmsg_type](nlh, data); ret = cb_ctl_array[nlh->nlmsg_type](nlh, data);
if (ret <= MNL_CB_STOP) if (ret <= MNL_CB_STOP)
goto out; goto out;
} }
} } else if (default_cb_array[nlh->nlmsg_type]) {
else if (default_cb_array[nlh->nlmsg_type])
{
ret = default_cb_array[nlh->nlmsg_type](nlh, data); ret = default_cb_array[nlh->nlmsg_type](nlh, data);
if (ret <= MNL_CB_STOP) if (ret <= MNL_CB_STOP)
goto out; goto out;
@ -506,33 +470,21 @@ out:
return ret; return ret;
} }
static int mnl_cb_run2( static int mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq,
const void* buf, unsigned int portid, mnl_cb_t cb_data, void *data,
size_t numbytes, const mnl_cb_t *cb_ctl_array, unsigned int cb_ctl_array_len)
unsigned int seq,
unsigned int portid,
mnl_cb_t cb_data,
void* data,
const mnl_cb_t* cb_ctl_array,
unsigned int cb_ctl_array_len)
{ {
return __mnl_cb_run( return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data,
buf, numbytes, seq, portid, cb_data, data, cb_ctl_array, cb_ctl_array_len); cb_ctl_array, cb_ctl_array_len);
} }
static int mnl_cb_run( static int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
const void* buf, unsigned int portid, mnl_cb_t cb_data, void *data)
size_t numbytes,
unsigned int seq,
unsigned int portid,
mnl_cb_t cb_data,
void* data)
{ {
return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, NULL, 0); return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, NULL, 0);
} }
struct mnl_socket struct mnl_socket {
{
int fd; int fd;
struct sockaddr_nl addr; struct sockaddr_nl addr;
}; };
@ -551,8 +503,7 @@ static struct mnl_socket* __mnl_socket_open(int bus, int flags)
return NULL; return NULL;
nl->fd = socket(AF_NETLINK, SOCK_RAW | flags, bus); nl->fd = socket(AF_NETLINK, SOCK_RAW | flags, bus);
if (nl->fd == -1) if (nl->fd == -1) {
{
free(nl); free(nl);
return NULL; return NULL;
} }
@ -560,7 +511,10 @@ static struct mnl_socket* __mnl_socket_open(int bus, int flags)
return nl; return nl;
} }
static struct mnl_socket* mnl_socket_open(int bus) { return __mnl_socket_open(bus, 0); } static struct mnl_socket *mnl_socket_open(int bus)
{
return __mnl_socket_open(bus, 0);
}
static int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid) static int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid)
{ {
@ -580,26 +534,29 @@ static int mnl_socket_bind(struct mnl_socket* nl, unsigned int groups, pid_t pid
if (ret < 0) if (ret < 0)
return ret; return ret;
if (addr_len != sizeof(nl->addr)) if (addr_len != sizeof(nl->addr)) {
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
if (nl->addr.nl_family != AF_NETLINK) if (nl->addr.nl_family != AF_NETLINK) {
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
return 0; return 0;
} }
static ssize_t mnl_socket_sendto(const struct mnl_socket* nl, const void* buf, size_t len) static ssize_t mnl_socket_sendto(const struct mnl_socket *nl, const void *buf,
size_t len)
{ {
static const struct sockaddr_nl snl = {.nl_family = AF_NETLINK}; static const struct sockaddr_nl snl = {
return sendto(nl->fd, buf, len, 0, (struct sockaddr*)&snl, sizeof(snl)); .nl_family = AF_NETLINK
};
return sendto(nl->fd, buf, len, 0,
(struct sockaddr *) &snl, sizeof(snl));
} }
static ssize_t mnl_socket_recvfrom(const struct mnl_socket* nl, void* buf, size_t bufsiz) static ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf,
size_t bufsiz)
{ {
ssize_t ret; ssize_t ret;
struct sockaddr_nl addr; struct sockaddr_nl addr;
@ -620,13 +577,11 @@ static ssize_t mnl_socket_recvfrom(const struct mnl_socket* nl, void* buf, size_
if (ret == -1) if (ret == -1)
return ret; return ret;
if (msg.msg_flags & MSG_TRUNC) if (msg.msg_flags & MSG_TRUNC) {
{
errno = ENOSPC; errno = ENOSPC;
return -1; return -1;
} }
if (msg.msg_namelen != sizeof(struct sockaddr_nl)) if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -642,8 +597,7 @@ static int mnl_socket_close(struct mnl_socket* nl)
/* This is a wrapper for generic netlink, originally from Jiri Pirko <jiri@mellanox.com>: */ /* This is a wrapper for generic netlink, originally from Jiri Pirko <jiri@mellanox.com>: */
struct mnlg_socket struct mnlg_socket {
{
struct mnl_socket *nl; struct mnl_socket *nl;
char *buf; char *buf;
uint16_t id; uint16_t id;
@ -652,11 +606,8 @@ struct mnlg_socket
unsigned int portid; unsigned int portid;
}; };
static struct nlmsghdr* __mnlg_msg_prepare( static struct nlmsghdr *__mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
struct mnlg_socket* nlg, uint16_t flags, uint16_t id,
uint8_t cmd,
uint16_t flags,
uint16_t id,
uint8_t version) uint8_t version)
{ {
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
@ -675,8 +626,8 @@ static struct nlmsghdr* __mnlg_msg_prepare(
return nlh; return nlh;
} }
static struct nlmsghdr* static struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
mnlg_msg_prepare(struct mnlg_socket* nlg, uint8_t cmd, uint16_t flags) uint16_t flags)
{ {
return __mnlg_msg_prepare(nlg, cmd, flags, nlg->id, nlg->version); return __mnlg_msg_prepare(nlg, cmd, flags, nlg->id, nlg->version);
} }
@ -698,8 +649,7 @@ static int mnlg_cb_error(const struct nlmsghdr* nlh, void* data)
const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
(void)data; (void)data;
if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) {
{
errno = EBADMSG; errno = EBADMSG;
return MNL_CB_ERROR; return MNL_CB_ERROR;
} }
@ -715,8 +665,7 @@ static int mnlg_cb_error(const struct nlmsghdr* nlh, void* data)
static int mnlg_cb_stop(const struct nlmsghdr *nlh, void *data) static int mnlg_cb_stop(const struct nlmsghdr *nlh, void *data)
{ {
(void)data; (void)data;
if (nlh->nlmsg_flags & NLM_F_MULTI && nlh->nlmsg_len == mnl_nlmsg_size(sizeof(int))) if (nlh->nlmsg_flags & NLM_F_MULTI && nlh->nlmsg_len == mnl_nlmsg_size(sizeof(int))) {
{
int error = *(int *)mnl_nlmsg_get_payload(nlh); int error = *(int *)mnl_nlmsg_get_payload(nlh);
/* Netlink subsystems returns the errno value with different signess */ /* Netlink subsystems returns the errno value with different signess */
if (error < 0) if (error < 0)
@ -740,20 +689,13 @@ static int mnlg_socket_recv_run(struct mnlg_socket* nlg, mnl_cb_t data_cb, void*
{ {
int err; int err;
do do {
{ err = mnl_socket_recvfrom(nlg->nl, nlg->buf,
err = mnl_socket_recvfrom(nlg->nl, nlg->buf, mnl_ideal_socket_buffer_size()); mnl_ideal_socket_buffer_size());
if (err <= 0) if (err <= 0)
break; break;
err = mnl_cb_run2( err = mnl_cb_run2(nlg->buf, err, nlg->seq, nlg->portid,
nlg->buf, data_cb, data, mnlg_cb_array, MNL_ARRAY_SIZE(mnlg_cb_array));
err,
nlg->seq,
nlg->portid,
data_cb,
data,
mnlg_cb_array,
MNL_ARRAY_SIZE(mnlg_cb_array));
} while (err > 0); } while (err > 0);
return err; return err;
@ -767,7 +709,8 @@ static int get_family_id_attr_cb(const struct nlattr* attr, void* data)
if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0) if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
return MNL_CB_ERROR; return MNL_CB_ERROR;
if (type == CTRL_ATTR_FAMILY_ID && mnl_attr_validate(attr, MNL_TYPE_U16) < 0) if (type == CTRL_ATTR_FAMILY_ID &&
mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
return MNL_CB_ERROR; return MNL_CB_ERROR;
tb[type] = attr; tb[type] = attr;
return MNL_CB_OK; return MNL_CB_OK;
@ -802,33 +745,29 @@ static struct mnlg_socket* mnlg_socket_open(const char* family_name, uint8_t ver
goto err_buf_alloc; goto err_buf_alloc;
nlg->nl = mnl_socket_open(NETLINK_GENERIC); nlg->nl = mnl_socket_open(NETLINK_GENERIC);
if (!nlg->nl) if (!nlg->nl) {
{
err = -errno; err = -errno;
goto err_mnl_socket_open; goto err_mnl_socket_open;
} }
if (mnl_socket_bind(nlg->nl, 0, MNL_SOCKET_AUTOPID) < 0) if (mnl_socket_bind(nlg->nl, 0, MNL_SOCKET_AUTOPID) < 0) {
{
err = -errno; err = -errno;
goto err_mnl_socket_bind; goto err_mnl_socket_bind;
} }
nlg->portid = mnl_socket_get_portid(nlg->nl); nlg->portid = mnl_socket_get_portid(nlg->nl);
nlh = __mnlg_msg_prepare( nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY,
nlg, CTRL_CMD_GETFAMILY, NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1); NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1);
mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name); mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name);
if (mnlg_socket_send(nlg, nlh) < 0) if (mnlg_socket_send(nlg, nlh) < 0) {
{
err = -errno; err = -errno;
goto err_mnlg_socket_send; goto err_mnlg_socket_send;
} }
errno = 0; errno = 0;
if (mnlg_socket_recv_run(nlg, get_family_id_cb, &nlg->id) < 0) if (mnlg_socket_recv_run(nlg, get_family_id_cb, &nlg->id) < 0) {
{
errno = errno == ENOENT ? EPROTONOSUPPORT : errno; errno = errno == ENOENT ? EPROTONOSUPPORT : errno;
err = errno ? -errno : -ENOSYS; err = errno ? -errno : -ENOSYS;
goto err_mnlg_socket_recv_run; goto err_mnlg_socket_recv_run;

View file

@ -7,12 +7,13 @@
#ifndef __IF_WG_H__ #ifndef __IF_WG_H__
#define __IF_WG_H__ #define __IF_WG_H__
#include <sys/errno.h>
#include <sys/limits.h> #include <sys/limits.h>
#include <sys/errno.h>
#include <net/if.h> #include <net/if.h>
#include <netinet/in.h> #include <netinet/in.h>
/* /*
* This is the public interface to the WireGuard network interface. * This is the public interface to the WireGuard network interface.
* *
@ -27,12 +28,10 @@
#define a_ipv4 a_addr.addr_ipv4 #define a_ipv4 a_addr.addr_ipv4
#define a_ipv6 a_addr.addr_ipv6 #define a_ipv6 a_addr.addr_ipv6
struct wg_aip_io struct wg_aip_io {
{
sa_family_t a_af; sa_family_t a_af;
int a_cidr; int a_cidr;
union wg_aip_addr union wg_aip_addr {
{
struct in_addr addr_ipv4; struct in_addr addr_ipv4;
struct in6_addr addr_ipv6; struct in6_addr addr_ipv6;
} a_addr; } a_addr;
@ -50,15 +49,13 @@ struct wg_aip_io
#define p_sin p_endpoint.sa_sin #define p_sin p_endpoint.sa_sin
#define p_sin6 p_endpoint.sa_sin6 #define p_sin6 p_endpoint.sa_sin6
struct wg_peer_io struct wg_peer_io {
{
int p_flags; int p_flags;
int p_protocol_version; int p_protocol_version;
uint8_t p_public[WG_KEY_LEN]; uint8_t p_public[WG_KEY_LEN];
uint8_t p_psk[WG_KEY_LEN]; uint8_t p_psk[WG_KEY_LEN];
uint16_t p_pka; uint16_t p_pka;
union wg_peer_endpoint union wg_peer_endpoint {
{
struct sockaddr sa_sa; struct sockaddr sa_sa;
struct sockaddr_in sa_sin; struct sockaddr_in sa_sin;
struct sockaddr_in6 sa_sin6; struct sockaddr_in6 sa_sin6;
@ -94,8 +91,7 @@ struct wg_peer_io
#define WG_INTERFACE_DEVICE_HAS_J3 (1 << 21) #define WG_INTERFACE_DEVICE_HAS_J3 (1 << 21)
#define WG_INTERFACE_DEVICE_HAS_ITIME (1 << 22) #define WG_INTERFACE_DEVICE_HAS_ITIME (1 << 22)
struct wg_interface_io struct wg_interface_io {
{
uint16_t i_flags; uint16_t i_flags;
in_port_t i_port; in_port_t i_port;
int i_rtable; int i_rtable;
@ -125,8 +121,7 @@ struct wg_interface_io
uint32_t i_itime; uint32_t i_itime;
}; };
struct wg_data_io struct wg_data_io {
{
char wgd_name[IFNAMSIZ]; char wgd_name[IFNAMSIZ];
size_t wgd_size; /* total size of the memory pointed to by wgd_interface */ size_t wgd_size; /* total size of the memory pointed to by wgd_interface */
struct wg_interface_io *wgd_interface; struct wg_interface_io *wgd_interface;

View file

@ -6,11 +6,11 @@
#ifndef _WIREGUARD_NT_H #ifndef _WIREGUARD_NT_H
#define _WIREGUARD_NT_H #define _WIREGUARD_NT_H
#include <in6addr.h>
#include <inaddr.h>
#include <ntdef.h> #include <ntdef.h>
#include <ws2def.h> #include <ws2def.h>
#include <ws2ipdef.h> #include <ws2ipdef.h>
#include <inaddr.h>
#include <in6addr.h>
#define WG_KEY_LEN 32 #define WG_KEY_LEN 32
@ -94,6 +94,7 @@ typedef struct _WG_IOCTL_INTERFACE
ULONG ResponsePacketMagicHeader; ULONG ResponsePacketMagicHeader;
ULONG UnderloadPacketMagicHeader; ULONG UnderloadPacketMagicHeader;
ULONG TransportPacketMagicHeader; ULONG TransportPacketMagicHeader;
UCHAR* I1; UCHAR* I1;
UCHAR* I2; UCHAR* I2;
UCHAR* I3; UCHAR* I3;
@ -105,14 +106,13 @@ typedef struct _WG_IOCTL_INTERFACE
ULONG Itime; ULONG Itime;
} __attribute__((aligned(8))) WG_IOCTL_INTERFACE; } __attribute__((aligned(8))) WG_IOCTL_INTERFACE;
#define WG_IOCTL_GET \ #define WG_IOCTL_GET CTL_CODE(45208U, 321, METHOD_OUT_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)
CTL_CODE(45208U, 321, METHOD_OUT_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA) #define WG_IOCTL_SET CTL_CODE(45208U, 322, METHOD_IN_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)
#define WG_IOCTL_SET \
CTL_CODE(45208U, 322, METHOD_IN_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)
#define DEVPKEY_WG_NAME \ #define DEVPKEY_WG_NAME (DEVPROPKEY) { \
(DEVPROPKEY){ \
{ 0x65726957, 0x7547, 0x7261, { 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79 } }, \ { 0x65726957, 0x7547, 0x7261, { 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79 } }, \
DEVPROPID_FIRST_USABLE + 1} DEVPROPID_FIRST_USABLE + 1 \
}
#endif #endif

View file

@ -42,7 +42,7 @@ int main(int argc, const char *argv[])
PROG_NAME = argv[0]; PROG_NAME = argv[0];
if (argc == 2 && (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version") || !strcmp(argv[1], "version"))) { if (argc == 2 && (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version") || !strcmp(argv[1], "version"))) {
printf("wireguard-tools v%s - https://git.zx2c4.com/wireguard-tools/\n", WIREGUARD_TOOLS_VERSION); printf("amneziawg-tools v%s - https://amnezia.org\n", WIREGUARD_TOOLS_VERSION);
return 0; return 0;
} }
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "help"))) { if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "help"))) {