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,143 +28,127 @@
#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 in6_addr ip6;
struct in_addr ip4; };
struct in6_addr ip6; uint8_t cidr;
}; struct wgallowedip *next_allowedip;
uint8_t cidr;
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, WGPEER_HAS_PRESHARED_KEY = 1U << 3,
WGPEER_HAS_PRESHARED_KEY = 1U << 3, WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL = 1U << 4,
WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL = 1U << 4, WGPEER_HAS_ADVANCED_SECURITY = 1U << 5,
WGPEER_HAS_ADVANCED_SECURITY = 1U << 5, 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; } endpoint;
} endpoint;
struct timespec64 last_handshake_time; struct timespec64 last_handshake_time;
uint64_t rx_bytes, tx_bytes; uint64_t rx_bytes, tx_bytes;
uint16_t persistent_keepalive_interval; uint16_t persistent_keepalive_interval;
bool advanced_security; bool advanced_security;
bool special_handshake; bool special_handshake;
struct wgallowedip *first_allowedip, *last_allowedip; struct wgallowedip *first_allowedip, *last_allowedip;
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, WGDEVICE_HAS_LISTEN_PORT = 1U << 3,
WGDEVICE_HAS_LISTEN_PORT = 1U << 3, WGDEVICE_HAS_FWMARK = 1U << 4,
WGDEVICE_HAS_FWMARK = 1U << 4, WGDEVICE_HAS_JC = 1U << 5,
WGDEVICE_HAS_JC = 1U << 5, WGDEVICE_HAS_JMIN = 1U << 6,
WGDEVICE_HAS_JMIN = 1U << 6, WGDEVICE_HAS_JMAX = 1U << 7,
WGDEVICE_HAS_JMAX = 1U << 7, WGDEVICE_HAS_S1 = 1U << 8,
WGDEVICE_HAS_S1 = 1U << 8, WGDEVICE_HAS_S2 = 1U << 9,
WGDEVICE_HAS_S2 = 1U << 9, WGDEVICE_HAS_H1 = 1U << 10,
WGDEVICE_HAS_H1 = 1U << 10, WGDEVICE_HAS_H2 = 1U << 11,
WGDEVICE_HAS_H2 = 1U << 11, WGDEVICE_HAS_H3 = 1U << 12,
WGDEVICE_HAS_H3 = 1U << 12, WGDEVICE_HAS_H4 = 1U << 13,
WGDEVICE_HAS_H4 = 1U << 13, WGDEVICE_HAS_I1 = 1U << 14,
WGDEVICE_HAS_I1 = 1U << 14, WGDEVICE_HAS_I2 = 1U << 15,
WGDEVICE_HAS_I2 = 1U << 15, WGDEVICE_HAS_I3 = 1U << 16,
WGDEVICE_HAS_I3 = 1U << 16, WGDEVICE_HAS_I4 = 1U << 17,
WGDEVICE_HAS_I4 = 1U << 17, WGDEVICE_HAS_I5 = 1U << 18,
WGDEVICE_HAS_I5 = 1U << 18, WGDEVICE_HAS_J1 = 1U << 19,
WGDEVICE_HAS_J1 = 1U << 19, WGDEVICE_HAS_J2 = 1U << 20,
WGDEVICE_HAS_J2 = 1U << 20, WGDEVICE_HAS_J3 = 1U << 21,
WGDEVICE_HAS_J3 = 1U << 21, 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;
uint32_t flags; uint32_t flags;
uint8_t public_key[WG_KEY_LEN]; uint8_t public_key[WG_KEY_LEN];
uint8_t private_key[WG_KEY_LEN]; uint8_t private_key[WG_KEY_LEN];
uint32_t fwmark; uint32_t fwmark;
uint16_t listen_port; uint16_t listen_port;
struct wgpeer *first_peer, *last_peer; struct wgpeer *first_peer, *last_peer;
uint16_t junk_packet_count; uint16_t junk_packet_count;
uint16_t junk_packet_min_size; uint16_t junk_packet_min_size;
uint16_t junk_packet_max_size; uint16_t junk_packet_max_size;
uint16_t init_packet_junk_size; uint16_t init_packet_junk_size;
uint16_t response_packet_junk_size; uint16_t response_packet_junk_size;
uint32_t init_packet_magic_header; uint32_t init_packet_magic_header;
uint32_t response_packet_magic_header; uint32_t response_packet_magic_header;
uint32_t underload_packet_magic_header; uint32_t underload_packet_magic_header;
uint32_t transport_packet_magic_header; uint32_t transport_packet_magic_header;
char* i1; char* i1;
char* i2; char* i2;
char* i3; char* i3;
char* i4; char* i4;
char* i5; char* i5;
char* j1; char* j1;
char* j2; char* j2;
char* j3; char* j3;
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)
{ free(allowedip);
for (struct wgallowedip *allowedip = peer->first_allowedip, free(peer);
*na = allowedip ? allowedip->next_allowedip : NULL; }
allowedip; free(dev);
allowedip = na, na = allowedip ? allowedip->next_allowedip : NULL)
free(allowedip);
free(peer);
}
free(dev);
} }
#endif #endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -3,521 +3,478 @@
* 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
static int get_dgram_socket(void) static int get_dgram_socket(void)
{ {
static int sock = -1; static int sock = -1;
if (sock < 0) if (sock < 0)
sock = socket(AF_INET, SOCK_DGRAM, 0); sock = socket(AF_INET, SOCK_DGRAM, 0);
return sock; return sock;
} }
static int kernel_get_wireguard_interfaces(struct string_list* list) static int kernel_get_wireguard_interfaces(struct string_list *list)
{ {
struct ifgroupreq ifgr = {.ifgr_name = "wg"}; struct ifgroupreq ifgr = { .ifgr_name = "wg" };
struct ifg_req* ifg; struct ifg_req *ifg;
int s = get_dgram_socket(), ret = 0; int s = get_dgram_socket(), ret = 0;
if (s < 0) if (s < 0)
return -errno; return -errno;
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) < 0) if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) < 0)
return errno == ENOENT ? 0 : -errno; return errno == ENOENT ? 0 : -errno;
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); }
}
out: out:
free(ifgr.ifgr_groups); free(ifgr.ifgr_groups);
return ret; return ret;
} }
static int kernel_get_device(struct wgdevice** device, const char* iface) static int kernel_get_device(struct wgdevice **device, const char *iface)
{ {
struct wg_data_io wgdata = {.wgd_size = 0}; struct wg_data_io wgdata = { .wgd_size = 0 };
struct wg_interface_io* wg_iface; struct wg_interface_io *wg_iface;
struct wg_peer_io* wg_peer; struct wg_peer_io *wg_peer;
struct wg_aip_io* wg_aip; struct wg_aip_io *wg_aip;
struct wgdevice* dev; struct wgdevice *dev;
struct wgpeer* peer; struct wgpeer *peer;
struct wgallowedip* aip; struct wgallowedip *aip;
int s = get_dgram_socket(), ret; int s = get_dgram_socket(), ret;
if (s < 0) if (s < 0)
return -errno; return -errno;
*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) break;
break; wgdata.wgd_interface = realloc(wgdata.wgd_interface, wgdata.wgd_size);
wgdata.wgd_interface = realloc(wgdata.wgd_interface, wgdata.wgd_size); if (!wgdata.wgd_interface)
if (!wgdata.wgd_interface) goto out;
goto out; }
}
wg_iface = wgdata.wgd_interface; wg_iface = wgdata.wgd_interface;
dev = calloc(1, sizeof(*dev)); dev = calloc(1, sizeof(*dev));
if (!dev) if (!dev)
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; }
}
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_I1) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_I1)
{ {
wg_iface->i_i1 = strdup(dev->i1); wg_iface->i_i1 = strdup(dev->i1);
wg_iface->i_flags |= WGDEVICE_HAS_I1; wg_iface->i_flags |= WGDEVICE_HAS_I1;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_I2) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_I2)
{ {
wg_iface->i_i2 = strdup(dev->i2); wg_iface->i_i2 = strdup(dev->i2);
wg_iface->i_flags |= WGDEVICE_HAS_I2; wg_iface->i_flags |= WGDEVICE_HAS_I2;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_I3) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_I3)
{ {
wg_iface->i_i3 = strdup(dev->i3); wg_iface->i_i3 = strdup(dev->i3);
wg_iface->i_flags |= WGDEVICE_HAS_I3; wg_iface->i_flags |= WGDEVICE_HAS_I3;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_I4) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_I4)
{ {
wg_iface->i_i4 = strdup(dev->i4); wg_iface->i_i4 = strdup(dev->i4);
wg_iface->i_flags |= WGDEVICE_HAS_I4; wg_iface->i_flags |= WGDEVICE_HAS_I4;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_I5) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_I5)
{ {
wg_iface->i_i5 = strdup(dev->i5); wg_iface->i_i5 = strdup(dev->i5);
wg_iface->i_flags |= WGDEVICE_HAS_I5; wg_iface->i_flags |= WGDEVICE_HAS_I5;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_J1) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_J1)
{ {
wg_iface->i_j1 = strdup(dev->j1); wg_iface->i_j1 = strdup(dev->j1);
wg_iface->i_flags |= WGDEVICE_HAS_J1; wg_iface->i_flags |= WGDEVICE_HAS_J1;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_J2) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_J2)
{ {
wg_iface->i_j2 = strdup(dev->j2); wg_iface->i_j2 = strdup(dev->j2);
wg_iface->i_flags |= WGDEVICE_HAS_J2; wg_iface->i_flags |= WGDEVICE_HAS_J2;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_J3) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_J3)
{ {
wg_iface->i_j3 = strdup(dev->j3); wg_iface->i_j3 = strdup(dev->j3);
wg_iface->i_flags |= WGDEVICE_HAS_J3; wg_iface->i_flags |= WGDEVICE_HAS_J3;
} }
if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_ITIME) if (wg_iface->i_flags & WG_INTERFACE_DEVICE_HAS_ITIME)
{ {
wg_iface->i_itime = dev->itime; wg_iface->i_itime = dev->itime;
wg_iface->i_flags |= WGDEVICE_HAS_ITIME; wg_iface->i_flags |= WGDEVICE_HAS_ITIME;
} }
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;
if (dev->first_peer == NULL) if (dev->first_peer == NULL)
dev->first_peer = peer; dev->first_peer = peer;
else else
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;
peer->tx_bytes = wg_peer->p_txbytes; peer->tx_bytes = wg_peer->p_txbytes;
peer->last_handshake_time.tv_sec = wg_peer->p_last_handshake.tv_sec; peer->last_handshake_time.tv_sec = wg_peer->p_last_handshake.tv_sec;
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;
if (peer->first_allowedip == NULL) if (peer->first_allowedip == NULL)
peer->first_allowedip = aip; peer->first_allowedip = aip;
else else
peer->last_allowedip->next_allowedip = aip; peer->last_allowedip->next_allowedip = aip;
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) {
} memcpy(&aip->ip6, &wg_aip->a_ipv6, sizeof(aip->ip6));
else if (wg_aip->a_af == AF_INET6) aip->cidr = wg_aip->a_cidr;
{ }
memcpy(&aip->ip6, &wg_aip->a_ipv6, sizeof(aip->ip6)); ++wg_aip;
aip->cidr = wg_aip->a_cidr; }
} wg_peer = (struct wg_peer_io *)wg_aip;
++wg_aip; }
} *device = dev;
wg_peer = (struct wg_peer_io*)wg_aip; errno = 0;
}
*device = dev;
errno = 0;
out: out:
ret = -errno; ret = -errno;
free(wgdata.wgd_interface); free(wgdata.wgd_interface);
return ret; return ret;
} }
static int kernel_set_device(struct wgdevice* dev) static int kernel_set_device(struct wgdevice *dev)
{ {
struct wg_data_io wgdata = {.wgd_size = sizeof(struct wg_interface_io)}; struct wg_data_io wgdata = { .wgd_size = sizeof(struct wg_interface_io) };
struct wg_interface_io* wg_iface; struct wg_interface_io *wg_iface;
struct wg_peer_io* wg_peer; struct wg_peer_io *wg_peer;
struct wg_aip_io* wg_aip; struct wg_aip_io *wg_aip;
struct wgpeer* peer; struct wgpeer *peer;
struct wgallowedip* aip; struct wgallowedip *aip;
int s = get_dgram_socket(), ret; int s = get_dgram_socket(), ret;
size_t peer_count, aip_count; size_t peer_count, aip_count;
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)
for_each_wgallowedip(peer, aip) wgdata.wgd_size += sizeof(struct wg_aip_io); 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; }
}
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)
{
wg_iface->i_junk_packet_count = dev->junk_packet_count;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_JC;
}
if (dev->flags & WGDEVICE_HAS_JMIN) if (dev->flags & WGDEVICE_HAS_JC) {
{ wg_iface->i_junk_packet_count = dev->junk_packet_count;
wg_iface->i_junk_packet_min_size = dev->junk_packet_min_size; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_JC;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_JMIN; }
}
if (dev->flags & WGDEVICE_HAS_JMAX) if (dev->flags & WGDEVICE_HAS_JMIN) {
{ wg_iface->i_junk_packet_min_size = dev->junk_packet_min_size;
wg_iface->i_junk_packet_max_size = dev->junk_packet_max_size; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_JMIN;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_JMAX; }
}
if (dev->flags & WGDEVICE_HAS_S1) if (dev->flags & WGDEVICE_HAS_JMAX) {
{ wg_iface->i_junk_packet_max_size = dev->junk_packet_max_size;
wg_iface->i_init_packet_junk_size = dev->init_packet_junk_size; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_JMAX;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_S1; }
}
if (dev->flags & WGDEVICE_HAS_S2) if (dev->flags & WGDEVICE_HAS_S1) {
{ wg_iface->i_init_packet_junk_size = dev->init_packet_junk_size;
wg_iface->i_response_packet_junk_size = dev->response_packet_junk_size; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_S1;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_S2; }
}
if (dev->flags & WGDEVICE_HAS_H1) if (dev->flags & WGDEVICE_HAS_S2) {
{ wg_iface->i_response_packet_junk_size = dev->response_packet_junk_size;
wg_iface->i_init_packet_magic_header = dev->init_packet_magic_header; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_S2;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H1; }
}
if (dev->flags & WGDEVICE_HAS_H2) if (dev->flags & WGDEVICE_HAS_H1) {
{ wg_iface->i_init_packet_magic_header = dev->init_packet_magic_header;
wg_iface->i_response_packet_magic_header = dev->response_packet_magic_header; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H1;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H2; }
}
if (dev->flags & WGDEVICE_HAS_H3) if (dev->flags & WGDEVICE_HAS_H2) {
{ wg_iface->i_response_packet_magic_header = dev->response_packet_magic_header;
wg_iface->i_underload_packet_magic_header = dev->underload_packet_magic_header; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H2;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H3; }
}
if (dev->flags & WGDEVICE_HAS_H4) if (dev->flags & WGDEVICE_HAS_H3) {
{ wg_iface->i_underload_packet_magic_header = dev->underload_packet_magic_header;
wg_iface->i_transport_packet_magic_header = dev->transport_packet_magic_header; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H3;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H4; }
}
if (dev->flags & WGDEVICE_HAS_I1) if (dev->flags & WGDEVICE_HAS_H4) {
{ wg_iface->i_transport_packet_magic_header = dev->transport_packet_magic_header;
wg_iface->i_i1 = strdup(dev->i1); wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_H4;
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_I1; }
}
if (dev->flags & WGDEVICE_HAS_I2) if (dev->flags & WGDEVICE_HAS_I1)
{ {
wg_iface->i_i2 = strdup(dev->i2); wg_iface->i_i1 = strdup(dev->i1);
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_I2; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_I1;
} }
if (dev->flags & WGDEVICE_HAS_I3) if (dev->flags & WGDEVICE_HAS_I2)
{ {
wg_iface->i_i3 = strdup(dev->i3); wg_iface->i_i2 = strdup(dev->i2);
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_I3; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_I2;
} }
if (dev->flags & WGDEVICE_HAS_I4) if (dev->flags & WGDEVICE_HAS_I3)
{ {
wg_iface->i_i4 = strdup(dev->i4); wg_iface->i_i3 = strdup(dev->i3);
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_I4; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_I3;
} }
if (dev->flags & WGDEVICE_HAS_I5) if (dev->flags & WGDEVICE_HAS_I4)
{ {
wg_iface->i_i5 = strdup(dev->i5); wg_iface->i_i4 = strdup(dev->i4);
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_I5; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_I4;
} }
if (dev->flags & WGDEVICE_HAS_J1) if (dev->flags & WGDEVICE_HAS_I5)
{ {
wg_iface->i_j1 = strdup(dev->j1); wg_iface->i_i5 = strdup(dev->i5);
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_J1; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_I5;
} }
if (dev->flags & WGDEVICE_HAS_J2) if (dev->flags & WGDEVICE_HAS_J1)
{ {
wg_iface->i_j2 = strdup(dev->j2); wg_iface->i_j1 = strdup(dev->j1);
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_J2; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_J1;
} }
if (dev->flags & WGDEVICE_HAS_J3) if (dev->flags & WGDEVICE_HAS_J2)
{ {
wg_iface->i_j3 = strdup(dev->j3); wg_iface->i_j2 = strdup(dev->j2);
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_J3; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_J2;
} }
if (dev->flags & WGDEVICE_HAS_ITIME) if (dev->flags & WGDEVICE_HAS_J3)
{ {
wg_iface->i_itime = dev->itime; wg_iface->i_j3 = strdup(dev->j3);
wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_ITIME; wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_J3;
} }
peer_count = 0; if (dev->flags & WGDEVICE_HAS_ITIME)
wg_peer = &wg_iface->i_peers[0]; {
for_each_wgpeer(dev, peer) wg_iface->i_itime = dev->itime;
{ wg_iface->i_flags |= WG_INTERFACE_DEVICE_HAS_ITIME;
wg_peer->p_flags = WG_PEER_HAS_PUBLIC; }
memcpy(wg_peer->p_public, peer->public_key, sizeof(wg_peer->p_public));
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) peer_count = 0;
{ wg_peer = &wg_iface->i_peers[0];
memcpy(wg_peer->p_psk, peer->preshared_key, sizeof(wg_peer->p_psk)); for_each_wgpeer(dev, peer) {
wg_peer->p_flags |= WG_PEER_HAS_PSK; wg_peer->p_flags = WG_PEER_HAS_PUBLIC;
} memcpy(wg_peer->p_public, peer->public_key, sizeof(wg_peer->p_public));
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) if (peer->flags & WGPEER_HAS_PRESHARED_KEY) {
{ memcpy(wg_peer->p_psk, peer->preshared_key, sizeof(wg_peer->p_psk));
wg_peer->p_pka = peer->persistent_keepalive_interval; wg_peer->p_flags |= WG_PEER_HAS_PSK;
wg_peer->p_flags |= WG_PEER_HAS_PKA; }
}
if ((peer->endpoint.addr.sa_family == AF_INET || if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) {
peer->endpoint.addr.sa_family == AF_INET6) && wg_peer->p_pka = peer->persistent_keepalive_interval;
peer->endpoint.addr.sa_len <= sizeof(wg_peer->p_endpoint)) wg_peer->p_flags |= WG_PEER_HAS_PKA;
{ }
memcpy(
&wg_peer->p_endpoint, &peer->endpoint.addr, peer->endpoint.addr.sa_len);
wg_peer->p_flags |= WG_PEER_HAS_ENDPOINT;
}
if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS) if ((peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) &&
wg_peer->p_flags |= WG_PEER_REPLACE_AIPS; peer->endpoint.addr.sa_len <= sizeof(wg_peer->p_endpoint)) {
memcpy(&wg_peer->p_endpoint, &peer->endpoint.addr, peer->endpoint.addr.sa_len);
wg_peer->p_flags |= WG_PEER_HAS_ENDPOINT;
}
if (peer->flags & WGPEER_REMOVE_ME) if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS)
wg_peer->p_flags |= WG_PEER_REMOVE; wg_peer->p_flags |= WG_PEER_REPLACE_AIPS;
aip_count = 0; if (peer->flags & WGPEER_REMOVE_ME)
wg_aip = &wg_peer->p_aips[0]; wg_peer->p_flags |= WG_PEER_REMOVE;
for_each_wgallowedip(peer, aip)
{
wg_aip->a_af = aip->family;
wg_aip->a_cidr = aip->cidr;
if (aip->family == AF_INET) aip_count = 0;
memcpy(&wg_aip->a_ipv4, &aip->ip4, sizeof(wg_aip->a_ipv4)); wg_aip = &wg_peer->p_aips[0];
else if (aip->family == AF_INET6) for_each_wgallowedip(peer, aip) {
memcpy(&wg_aip->a_ipv6, &aip->ip6, sizeof(wg_aip->a_ipv6)); wg_aip->a_af = aip->family;
else wg_aip->a_cidr = aip->cidr;
continue;
++aip_count;
++wg_aip;
}
wg_peer->p_aips_count = aip_count;
++peer_count;
wg_peer = (struct wg_peer_io*)wg_aip;
}
wg_iface->i_peers_count = peer_count;
if (ioctl(s, SIOCSWG, (caddr_t)&wgdata) < 0) if (aip->family == AF_INET)
goto out; memcpy(&wg_aip->a_ipv4, &aip->ip4, sizeof(wg_aip->a_ipv4));
errno = 0; else if (aip->family == AF_INET6)
memcpy(&wg_aip->a_ipv6, &aip->ip6, sizeof(wg_aip->a_ipv6));
else
continue;
++aip_count;
++wg_aip;
}
wg_peer->p_aips_count = aip_count;
++peer_count;
wg_peer = (struct wg_peer_io *)wg_aip;
}
wg_iface->i_peers_count = peer_count;
if (ioctl(s, SIOCSWG, (caddr_t)&wgdata) < 0)
goto out;
errno = 0;
out: out:
ret = -errno; ret = -errno;
free(wgdata.wgd_interface); free(wgdata.wgd_interface);
return ret; return ret;
} }

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"
@ -25,467 +25,381 @@
#include "ipc-uapi-unix.h" #include "ipc-uapi-unix.h"
#endif #endif
static int userspace_set_device(struct wgdevice* dev) static int userspace_set_device(struct wgdevice *dev)
{ {
char hex[WG_KEY_LEN_HEX], ip[INET6_ADDRSTRLEN], host[4096 + 1], service[512 + 1]; char hex[WG_KEY_LEN_HEX], ip[INET6_ADDRSTRLEN], host[4096 + 1], service[512 + 1];
struct wgpeer* peer; struct wgpeer *peer;
struct wgallowedip* allowedip; struct wgallowedip *allowedip;
FILE* f; FILE *f;
int ret, set_errno = -EPROTO; int ret, set_errno = -EPROTO;
socklen_t addr_len; socklen_t addr_len;
size_t line_buffer_len = 0, line_len; size_t line_buffer_len = 0, line_len;
char * key = NULL, *value; char *key = NULL, *value;
f = userspace_interface_file(dev->name); f = userspace_interface_file(dev->name);
if (!f) if (!f)
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); }
} if (dev->flags & WGDEVICE_HAS_LISTEN_PORT)
if (dev->flags & WGDEVICE_HAS_LISTEN_PORT) fprintf(f, "listen_port=%u\n", dev->listen_port);
fprintf(f, "listen_port=%u\n", dev->listen_port); if (dev->flags & WGDEVICE_HAS_FWMARK)
if (dev->flags & WGDEVICE_HAS_FWMARK) fprintf(f, "fwmark=%u\n", dev->fwmark);
fprintf(f, "fwmark=%u\n", dev->fwmark); if (dev->flags & WGDEVICE_REPLACE_PEERS)
if (dev->flags & WGDEVICE_REPLACE_PEERS) fprintf(f, "replace_peers=true\n");
fprintf(f, "replace_peers=true\n"); if (dev->flags & WGDEVICE_HAS_JC)
if (dev->flags & WGDEVICE_HAS_JC) fprintf(f, "jc=%u\n", dev->junk_packet_count);
fprintf(f, "jc=%u\n", dev->junk_packet_count); if (dev->flags & WGDEVICE_HAS_JMIN)
if (dev->flags & WGDEVICE_HAS_JMIN) fprintf(f, "jmin=%u\n", dev->junk_packet_min_size);
fprintf(f, "jmin=%u\n", dev->junk_packet_min_size); if (dev->flags & WGDEVICE_HAS_JMAX)
if (dev->flags & WGDEVICE_HAS_JMAX) fprintf(f, "jmax=%u\n", dev->junk_packet_max_size);
fprintf(f, "jmax=%u\n", dev->junk_packet_max_size); if (dev->flags & WGDEVICE_HAS_S1)
if (dev->flags & WGDEVICE_HAS_S1) fprintf(f, "s1=%u\n", dev->init_packet_junk_size);
fprintf(f, "s1=%u\n", dev->init_packet_junk_size); if (dev->flags & WGDEVICE_HAS_S2)
if (dev->flags & WGDEVICE_HAS_S2) fprintf(f, "s2=%u\n", dev->response_packet_junk_size);
fprintf(f, "s2=%u\n", dev->response_packet_junk_size); if (dev->flags & WGDEVICE_HAS_H1)
if (dev->flags & WGDEVICE_HAS_H1) fprintf(f, "h1=%u\n", dev->init_packet_magic_header);
fprintf(f, "h1=%u\n", dev->init_packet_magic_header); if (dev->flags & WGDEVICE_HAS_H2)
if (dev->flags & WGDEVICE_HAS_H2) fprintf(f, "h2=%u\n", dev->response_packet_magic_header);
fprintf(f, "h2=%u\n", dev->response_packet_magic_header); if (dev->flags & WGDEVICE_HAS_H3)
if (dev->flags & WGDEVICE_HAS_H3) 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)
fprintf(f, "i1=%s\n", dev->i1);
if (dev->flags & WGDEVICE_HAS_I2)
fprintf(f, "i2=%s\n", dev->i2);
if (dev->flags & WGDEVICE_HAS_I3)
fprintf(f, "i3=%s\n", dev->i3);
if (dev->flags & WGDEVICE_HAS_I4)
fprintf(f, "i4=%s\n", dev->i4);
if (dev->flags & WGDEVICE_HAS_I5)
fprintf(f, "i5=%s\n", dev->i5);
if (dev->flags & WGDEVICE_HAS_J1)
fprintf(f, "j1=%s\n", dev->j1);
if (dev->flags & WGDEVICE_HAS_J2)
fprintf(f, "j2=%s\n", dev->j2);
if (dev->flags & WGDEVICE_HAS_J3)
fprintf(f, "j3=%s\n", dev->j3);
if (dev->flags & WGDEVICE_HAS_ITIME)
fprintf(f, "itime=%u\n", dev->itime);
printf("i1: %s\n", dev->i1); if (dev->flags & WGDEVICE_HAS_I1)
fprintf(f, "i1=%s\n", dev->i1);
if (dev->flags & WGDEVICE_HAS_I2)
fprintf(f, "i2=%s\n", dev->i2);
if (dev->flags & WGDEVICE_HAS_I3)
fprintf(f, "i3=%s\n", dev->i3);
if (dev->flags & WGDEVICE_HAS_I4)
fprintf(f, "i4=%s\n", dev->i4);
if (dev->flags & WGDEVICE_HAS_I5)
fprintf(f, "i5=%s\n", dev->i5);
if (dev->flags & WGDEVICE_HAS_J1)
fprintf(f, "j1=%s\n", dev->j1);
if (dev->flags & WGDEVICE_HAS_J2)
fprintf(f, "j2=%s\n", dev->j2);
if (dev->flags & WGDEVICE_HAS_J3)
fprintf(f, "j3=%s\n", dev->j3);
if (dev->flags & WGDEVICE_HAS_ITIME)
fprintf(f, "itime=%u\n", dev->itime);
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;
{ goto out;
ret = -EINVAL; }
goto out; if (peer->flags & WGPEER_HAS_SPECIAL_HANDSHAKE)
} {
if (peer->flags & WGPEER_HAS_SPECIAL_HANDSHAKE) ret = -EINVAL;
{ goto out;
ret = -EINVAL; }
goto out; if (peer->flags & WGPEER_REMOVE_ME) {
} fprintf(f, "remove=true\n");
if (peer->flags & WGPEER_REMOVE_ME) continue;
{ }
fprintf(f, "remove=true\n"); if (peer->flags & WGPEER_HAS_PRESHARED_KEY) {
continue; key_to_hex(hex, peer->preshared_key);
} fprintf(f, "preshared_key=%s\n", hex);
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) }
{ if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) {
key_to_hex(hex, peer->preshared_key); addr_len = 0;
fprintf(f, "preshared_key=%s\n", hex); if (peer->endpoint.addr.sa_family == AF_INET)
} addr_len = sizeof(struct sockaddr_in);
if (peer->endpoint.addr.sa_family == AF_INET || else if (peer->endpoint.addr.sa_family == AF_INET6)
peer->endpoint.addr.sa_family == AF_INET6) addr_len = sizeof(struct sockaddr_in6);
{ if (!getnameinfo(&peer->endpoint.addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST)) {
addr_len = 0; if (peer->endpoint.addr.sa_family == AF_INET6 && strchr(host, ':'))
if (peer->endpoint.addr.sa_family == AF_INET) fprintf(f, "endpoint=[%s]:%s\n", host, service);
addr_len = sizeof(struct sockaddr_in); else
else if (peer->endpoint.addr.sa_family == AF_INET6) fprintf(f, "endpoint=%s:%s\n", host, service);
addr_len = sizeof(struct sockaddr_in6); }
if (!getnameinfo( }
&peer->endpoint.addr, if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL)
addr_len, fprintf(f, "persistent_keepalive_interval=%u\n", peer->persistent_keepalive_interval);
host, if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS)
sizeof(host), fprintf(f, "replace_allowed_ips=true\n");
service, for_each_wgallowedip(peer, allowedip) {
sizeof(service), if (allowedip->family == AF_INET) {
NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST)) if (!inet_ntop(AF_INET, &allowedip->ip4, ip, INET6_ADDRSTRLEN))
{ continue;
if (peer->endpoint.addr.sa_family == AF_INET6 && strchr(host, ':')) } else if (allowedip->family == AF_INET6) {
fprintf(f, "endpoint=[%s]:%s\n", host, service); if (!inet_ntop(AF_INET6, &allowedip->ip6, ip, INET6_ADDRSTRLEN))
else continue;
fprintf(f, "endpoint=%s:%s\n", host, service); } else
} continue;
} fprintf(f, "allowed_ip=%s/%d\n", ip, allowedip->cidr);
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) }
fprintf( }
f, fprintf(f, "\n");
"persistent_keepalive_interval=%u\n", fflush(f);
peer->persistent_keepalive_interval);
if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS)
fprintf(f, "replace_allowed_ips=true\n");
for_each_wgallowedip(peer, allowedip)
{
if (allowedip->family == AF_INET)
{
if (!inet_ntop(AF_INET, &allowedip->ip4, ip, INET6_ADDRSTRLEN))
continue;
}
else if (allowedip->family == AF_INET6)
{
if (!inet_ntop(AF_INET6, &allowedip->ip6, ip, INET6_ADDRSTRLEN))
continue;
}
else
continue;
fprintf(f, "allowed_ip=%s/%d\n", ip, allowedip->cidr);
}
}
fprintf(f, "\n");
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') goto out;
goto out; value = strchr(key, '=');
value = strchr(key, '='); if (!value || line_len == 0 || key[line_len - 1] != '\n')
if (!value || line_len == 0 || key[line_len - 1] != '\n') 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])) break;
break; num = strtoll(value, &end, 10);
num = strtoll(value, &end, 10); if (*end || num > INT_MAX || num < INT_MIN)
if (*end || num > INT_MAX || num < INT_MIN) break;
break; set_errno = num;
set_errno = num; }
} }
} ret = errno ? -errno : -EPROTO;
ret = errno ? -errno : -EPROTO;
out: out:
free(key); free(key);
fclose(f); fclose(f);
errno = -ret; errno = -ret;
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])) \ break; \
break; \ num = strtoull(value, &end, 10); \
num = strtoull(value, &end, 10); \ if (*end || num > max) \
if (*end || num > max) \ break; \
break; \ num; \
num; \ })
})
static int userspace_get_device(struct wgdevice** out, const char* iface) static int userspace_get_device(struct wgdevice **out, const char *iface)
{ {
struct wgdevice* dev; struct wgdevice *dev;
struct wgpeer* peer = NULL; struct wgpeer *peer = NULL;
struct wgallowedip* allowedip = NULL; struct wgallowedip *allowedip = NULL;
size_t line_buffer_len = 0, line_len; size_t line_buffer_len = 0, line_len;
char * key = NULL, *value; char *key = NULL, *value;
FILE* f; FILE *f;
int ret = -EPROTO; int ret = -EPROTO;
*out = dev = calloc(1, sizeof(*dev)); *out = dev = calloc(1, sizeof(*dev));
if (!dev) if (!dev)
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; return ret;
return ret; }
}
fprintf(f, "get=1\n\n"); fprintf(f, "get=1\n\n");
fflush(f); fflush(f);
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; value = strchr(key, '=');
value = strchr(key, '='); if (!value || line_len == 0 || key[line_len - 1] != '\n')
if (!value || line_len == 0 || key[line_len - 1] != '\n') 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")) {
} dev->listen_port = NUM(0xffffU);
else if (!peer && !strcmp(key, "listen_port")) dev->flags |= WGDEVICE_HAS_LISTEN_PORT;
{ } else if (!peer && !strcmp(key, "fwmark")) {
dev->listen_port = NUM(0xffffU); dev->fwmark = NUM(0xffffffffU);
dev->flags |= WGDEVICE_HAS_LISTEN_PORT; dev->flags |= WGDEVICE_HAS_FWMARK;
} } else if(!peer && !strcmp(key, "jc")) {
else if (!peer && !strcmp(key, "fwmark")) dev->junk_packet_count = NUM(0xffffU);
{ dev->flags |= WGDEVICE_HAS_JC;
dev->fwmark = NUM(0xffffffffU); } else if(!peer && !strcmp(key, "jmin")) {
dev->flags |= WGDEVICE_HAS_FWMARK; dev->junk_packet_min_size = NUM(0xffffU);
} dev->flags |= WGDEVICE_HAS_JMIN;
else if (!peer && !strcmp(key, "jc")) } else if(!peer && !strcmp(key, "jmax")) {
{ dev->junk_packet_max_size = NUM(0xffffU);
dev->junk_packet_count = NUM(0xffffU); dev->flags |= WGDEVICE_HAS_JMAX;
dev->flags |= WGDEVICE_HAS_JC; } else if(!peer && !strcmp(key, "s1")) {
} dev->init_packet_junk_size = NUM(0xffffU);
else if (!peer && !strcmp(key, "jmin")) dev->flags |= WGDEVICE_HAS_S1;
{ } else if(!peer && !strcmp(key, "s2")) {
dev->junk_packet_min_size = NUM(0xffffU); dev->response_packet_junk_size = NUM(0xffffU);
dev->flags |= WGDEVICE_HAS_JMIN; dev->flags |= WGDEVICE_HAS_S2;
} } else if(!peer && !strcmp(key, "h1")) {
else if (!peer && !strcmp(key, "jmax")) dev->init_packet_magic_header = NUM(0xffffffffU);
{ dev->flags |= WGDEVICE_HAS_H1;
dev->junk_packet_max_size = NUM(0xffffU); } else if(!peer && !strcmp(key, "h2")) {
dev->flags |= WGDEVICE_HAS_JMAX; dev->response_packet_magic_header = NUM(0xffffffffU);
} dev->flags |= WGDEVICE_HAS_H2;
else if (!peer && !strcmp(key, "s1")) } else if(!peer && !strcmp(key, "h3")) {
{ dev->underload_packet_magic_header = NUM(0xffffffffU);
dev->init_packet_junk_size = NUM(0xffffU); dev->flags |= WGDEVICE_HAS_H3;
dev->flags |= WGDEVICE_HAS_S1; } else if(!peer && !strcmp(key, "h4")) {
} dev->transport_packet_magic_header = NUM(0xffffffffU);
else if (!peer && !strcmp(key, "s2")) dev->flags |= WGDEVICE_HAS_H4;
{ } else if (!peer && !strcmp(key, "i1")) {
dev->response_packet_junk_size = NUM(0xffffU); dev->i1 = strdup(value);
dev->flags |= WGDEVICE_HAS_S2; dev->flags |= WGDEVICE_HAS_I1;
} }
else if (!peer && !strcmp(key, "h1")) else if (!peer && !strcmp(key, "i2")) {
{ dev->i2 = strdup(value);
dev->init_packet_magic_header = NUM(0xffffffffU); dev->flags |= WGDEVICE_HAS_I2;
dev->flags |= WGDEVICE_HAS_H1; }
} else if (!peer && !strcmp(key, "i3")) {
else if (!peer && !strcmp(key, "h2")) dev->i3 = strdup(value);
{ dev->flags |= WGDEVICE_HAS_I3;
dev->response_packet_magic_header = NUM(0xffffffffU); }
dev->flags |= WGDEVICE_HAS_H2; else if (!peer && !strcmp(key, "i4")) {
} dev->i4 = strdup(value);
else if (!peer && !strcmp(key, "h3")) dev->flags |= WGDEVICE_HAS_I4;
{ }
dev->underload_packet_magic_header = NUM(0xffffffffU); else if (!peer && !strcmp(key, "i5")) {
dev->flags |= WGDEVICE_HAS_H3; dev->i5 = strdup(value);
} dev->flags |= WGDEVICE_HAS_I5;
else if (!peer && !strcmp(key, "h4")) }
{ else if (!peer && !strcmp(key, "j1")) {
dev->transport_packet_magic_header = NUM(0xffffffffU); dev->j1 = strdup(value);
dev->flags |= WGDEVICE_HAS_H4; dev->flags |= WGDEVICE_HAS_J1;
} }
else if (!peer && !strcmp(key, "i1")) else if (!peer && !strcmp(key, "j2")) {
{ dev->j2 = strdup(value);
dev->i1 = strdup(value); dev->flags |= WGDEVICE_HAS_J2;
dev->flags |= WGDEVICE_HAS_I1; }
} else if (!peer && !strcmp(key, "j3")) {
else if (!peer && !strcmp(key, "i2")) dev->j3 = strdup(value);
{ dev->flags |= WGDEVICE_HAS_J3;
dev->i2 = strdup(value); }
dev->flags |= WGDEVICE_HAS_I2; else if (!peer && !strcmp(key, "itime")) {
} dev->itime = NUM(0xffffffffU);
else if (!peer && !strcmp(key, "i3")) dev->flags |= WGDEVICE_HAS_ITIME;
{ } else if (!strcmp(key, "public_key")) {
dev->i3 = strdup(value); struct wgpeer *new_peer = calloc(1, sizeof(*new_peer));
dev->flags |= WGDEVICE_HAS_I3;
}
else if (!peer && !strcmp(key, "i4"))
{
dev->i4 = strdup(value);
dev->flags |= WGDEVICE_HAS_I4;
}
else if (!peer && !strcmp(key, "i5"))
{
dev->i5 = strdup(value);
dev->flags |= WGDEVICE_HAS_I5;
}
else if (!peer && !strcmp(key, "j1"))
{
dev->j1 = strdup(value);
dev->flags |= WGDEVICE_HAS_J1;
}
else if (!peer && !strcmp(key, "j2"))
{
dev->j2 = strdup(value);
dev->flags |= WGDEVICE_HAS_J2;
}
else if (!peer && !strcmp(key, "j3"))
{
dev->j3 = strdup(value);
dev->flags |= WGDEVICE_HAS_J3;
}
else if (!peer && !strcmp(key, "itime"))
{
dev->itime = NUM(0xffffffffU);
dev->flags |= WGDEVICE_HAS_ITIME;
}
else if (!strcmp(key, "public_key"))
{
struct wgpeer* new_peer = calloc(1, sizeof(*new_peer));
if (!new_peer) if (!new_peer) {
{ ret = -ENOMEM;
ret = -ENOMEM; goto err;
goto err; }
} allowedip = NULL;
allowedip = NULL; if (peer)
if (peer) peer->next_peer = new_peer;
peer->next_peer = new_peer; else
else dev->first_peer = new_peer;
dev->first_peer = new_peer; peer = new_peer;
peer = new_peer; 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")) {
} if (!key_from_hex(peer->preshared_key, value))
else if (peer && !strcmp(key, "preshared_key")) break;
{ if (!key_is_zero(peer->preshared_key))
if (!key_from_hex(peer->preshared_key, value)) peer->flags |= WGPEER_HAS_PRESHARED_KEY;
break; } else if (peer && !strcmp(key, "endpoint")) {
if (!key_is_zero(peer->preshared_key)) char *begin, *end;
peer->flags |= WGPEER_HAS_PRESHARED_KEY; struct addrinfo *resolved;
} struct addrinfo hints = {
else if (peer && !strcmp(key, "endpoint")) .ai_family = AF_UNSPEC,
{ .ai_socktype = SOCK_DGRAM,
char * begin, *end; .ai_protocol = IPPROTO_UDP
struct addrinfo* resolved; };
struct addrinfo hints = { if (!strlen(value))
.ai_family = AF_UNSPEC, break;
.ai_socktype = SOCK_DGRAM, if (value[0] == '[') {
.ai_protocol = IPPROTO_UDP}; begin = &value[1];
if (!strlen(value)) end = strchr(value, ']');
break; if (!end)
if (value[0] == '[') break;
{ *end++ = '\0';
begin = &value[1]; if (*end++ != ':' || !*end)
end = strchr(value, ']'); break;
if (!end) } else {
break; begin = value;
*end++ = '\0'; end = strrchr(value, ':');
if (*end++ != ':' || !*end) if (!end || !*(end + 1))
break; break;
} *end++ = '\0';
else }
{ if (getaddrinfo(begin, end, &hints, &resolved) != 0) {
begin = value; ret = ENETUNREACH;
end = strrchr(value, ':'); goto err;
if (!end || !*(end + 1)) }
break; if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) ||
*end++ = '\0'; (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6)))
} memcpy(&peer->endpoint.addr, resolved->ai_addr, resolved->ai_addrlen);
if (getaddrinfo(begin, end, &hints, &resolved) != 0) else {
{ freeaddrinfo(resolved);
ret = ENETUNREACH; break;
goto err; }
} freeaddrinfo(resolved);
if ((resolved->ai_family == AF_INET && } else if (peer && !strcmp(key, "persistent_keepalive_interval")) {
resolved->ai_addrlen == sizeof(struct sockaddr_in)) || peer->persistent_keepalive_interval = NUM(0xffffU);
(resolved->ai_family == AF_INET6 && peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
resolved->ai_addrlen == sizeof(struct sockaddr_in6))) } else if (peer && !strcmp(key, "allowed_ip")) {
memcpy(&peer->endpoint.addr, resolved->ai_addr, resolved->ai_addrlen); struct wgallowedip *new_allowedip;
else char *end, *mask = value, *ip = strsep(&mask, "/");
{
freeaddrinfo(resolved);
break;
}
freeaddrinfo(resolved);
}
else if (peer && !strcmp(key, "persistent_keepalive_interval"))
{
peer->persistent_keepalive_interval = NUM(0xffffU);
peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
}
else if (peer && !strcmp(key, "allowed_ip"))
{
struct wgallowedip* new_allowedip;
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; }
} if (allowedip)
if (allowedip) allowedip->next_allowedip = new_allowedip;
allowedip->next_allowedip = new_allowedip; else
else 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)
{ allowedip->family = AF_INET6;
if (inet_pton(AF_INET6, ip, &allowedip->ip6) == 1) } else {
allowedip->family = AF_INET6; if (inet_pton(AF_INET, ip, &allowedip->ip4) == 1)
} allowedip->family = AF_INET;
else }
{ allowedip->cidr = strtoul(mask, &end, 10);
if (inet_pton(AF_INET, ip, &allowedip->ip4) == 1) if (*end || allowedip->family == AF_UNSPEC || (allowedip->family == AF_INET6 && allowedip->cidr > 128) || (allowedip->family == AF_INET && allowedip->cidr > 32))
allowedip->family = AF_INET; break;
} } else if (peer && !strcmp(key, "last_handshake_time_sec"))
allowedip->cidr = strtoul(mask, &end, 10); peer->last_handshake_time.tv_sec = NUM(0x7fffffffffffffffULL);
if (*end || allowedip->family == AF_UNSPEC || else if (peer && !strcmp(key, "last_handshake_time_nsec"))
(allowedip->family == AF_INET6 && allowedip->cidr > 128) || peer->last_handshake_time.tv_nsec = NUM(0x7fffffffffffffffULL);
(allowedip->family == AF_INET && allowedip->cidr > 32)) else if (peer && !strcmp(key, "rx_bytes"))
break; peer->rx_bytes = NUM(0xffffffffffffffffULL);
} else if (peer && !strcmp(key, "tx_bytes"))
else if (peer && !strcmp(key, "last_handshake_time_sec")) peer->tx_bytes = NUM(0xffffffffffffffffULL);
peer->last_handshake_time.tv_sec = NUM(0x7fffffffffffffffULL); else if (!strcmp(key, "errno"))
else if (peer && !strcmp(key, "last_handshake_time_nsec")) ret = -NUM(0x7fffffffU);
peer->last_handshake_time.tv_nsec = NUM(0x7fffffffffffffffULL); }
else if (peer && !strcmp(key, "rx_bytes")) ret = -EPROTO;
peer->rx_bytes = NUM(0xffffffffffffffffULL);
else if (peer && !strcmp(key, "tx_bytes"))
peer->tx_bytes = NUM(0xffffffffffffffffULL);
else if (!strcmp(key, "errno"))
ret = -NUM(0x7fffffffU);
}
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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

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.
* *
@ -24,56 +25,52 @@
#define SIOCSWG _IOWR('i', 210, struct wg_data_io) #define SIOCSWG _IOWR('i', 210, struct wg_data_io)
#define SIOCGWG _IOWR('i', 211, struct wg_data_io) #define SIOCGWG _IOWR('i', 211, struct wg_data_io)
#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 in6_addr addr_ipv6;
struct in_addr addr_ipv4; } a_addr;
struct in6_addr addr_ipv6;
} a_addr;
}; };
#define WG_PEER_HAS_PUBLIC (1 << 0) #define WG_PEER_HAS_PUBLIC (1 << 0)
#define WG_PEER_HAS_PSK (1 << 1) #define WG_PEER_HAS_PSK (1 << 1)
#define WG_PEER_HAS_PKA (1 << 2) #define WG_PEER_HAS_PKA (1 << 2)
#define WG_PEER_HAS_ENDPOINT (1 << 3) #define WG_PEER_HAS_ENDPOINT (1 << 3)
#define WG_PEER_REPLACE_AIPS (1 << 4) #define WG_PEER_REPLACE_AIPS (1 << 4)
#define WG_PEER_REMOVE (1 << 5) #define WG_PEER_REMOVE (1 << 5)
#define WG_PEER_UPDATE (1 << 6) #define WG_PEER_UPDATE (1 << 6)
#define p_sa p_endpoint.sa_sa #define p_sa p_endpoint.sa_sa
#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_in sa_sin;
struct sockaddr sa_sa; struct sockaddr_in6 sa_sin6;
struct sockaddr_in sa_sin; } p_endpoint;
struct sockaddr_in6 sa_sin6; uint64_t p_txbytes;
} p_endpoint; uint64_t p_rxbytes;
uint64_t p_txbytes; struct timespec p_last_handshake; /* nanotime */
uint64_t p_rxbytes; size_t p_aips_count;
struct timespec p_last_handshake; /* nanotime */ struct wg_aip_io p_aips[];
size_t p_aips_count;
struct wg_aip_io p_aips[];
}; };
#define WG_INTERFACE_HAS_PUBLIC (1 << 0) #define WG_INTERFACE_HAS_PUBLIC (1 << 0)
#define WG_INTERFACE_HAS_PRIVATE (1 << 1) #define WG_INTERFACE_HAS_PRIVATE (1 << 1)
#define WG_INTERFACE_HAS_PORT (1 << 2) #define WG_INTERFACE_HAS_PORT (1 << 2)
#define WG_INTERFACE_HAS_RTABLE (1 << 3) #define WG_INTERFACE_HAS_RTABLE (1 << 3)
#define WG_INTERFACE_REPLACE_PEERS (1 << 4) #define WG_INTERFACE_REPLACE_PEERS (1 << 4)
#define WG_INTERFACE_DEVICE_HAS_JC (1 << 5) #define WG_INTERFACE_DEVICE_HAS_JC (1 << 5)
#define WG_INTERFACE_DEVICE_HAS_JMIN (1 << 6) #define WG_INTERFACE_DEVICE_HAS_JMIN (1 << 6)
@ -94,25 +91,24 @@ 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; uint8_t i_public[WG_KEY_LEN];
uint8_t i_public[WG_KEY_LEN]; uint8_t i_private[WG_KEY_LEN];
uint8_t i_private[WG_KEY_LEN]; size_t i_peers_count;
size_t i_peers_count; struct wg_peer_io i_peers[];
struct wg_peer_io i_peers[];
uint16_t i_junk_packet_count; uint16_t i_junk_packet_count;
uint16_t i_junk_packet_min_size; uint16_t i_junk_packet_min_size;
uint16_t i_junk_packet_max_size; uint16_t i_junk_packet_max_size;
uint16_t i_init_packet_junk_size; uint16_t i_init_packet_junk_size;
uint16_t i_response_packet_junk_size; uint16_t i_response_packet_junk_size;
uint32_t i_init_packet_magic_header; uint32_t i_init_packet_magic_header;
uint32_t i_response_packet_magic_header; uint32_t i_response_packet_magic_header;
uint32_t i_underload_packet_magic_header; uint32_t i_underload_packet_magic_header;
uint32_t i_transport_packet_magic_header; uint32_t i_transport_packet_magic_header;
uint8_t* i_i1; uint8_t* i_i1;
uint8_t* i_i2; uint8_t* i_i2;
@ -125,11 +121,10 @@ 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;
}; };
#endif /* __IF_WG_H__ */ #endif /* __IF_WG_H__ */

View file

@ -6,113 +6,113 @@
#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
typedef struct _WG_IOCTL_ALLOWED_IP typedef struct _WG_IOCTL_ALLOWED_IP
{ {
union union
{ {
IN_ADDR V4; IN_ADDR V4;
IN6_ADDR V6; IN6_ADDR V6;
} Address; } Address;
ADDRESS_FAMILY AddressFamily; ADDRESS_FAMILY AddressFamily;
UCHAR Cidr; UCHAR Cidr;
} __attribute__((aligned(8))) WG_IOCTL_ALLOWED_IP; } __attribute__((aligned(8))) WG_IOCTL_ALLOWED_IP;
typedef enum typedef enum
{ {
WG_IOCTL_PEER_HAS_PUBLIC_KEY = 1 << 0, WG_IOCTL_PEER_HAS_PUBLIC_KEY = 1 << 0,
WG_IOCTL_PEER_HAS_PRESHARED_KEY = 1 << 1, WG_IOCTL_PEER_HAS_PRESHARED_KEY = 1 << 1,
WG_IOCTL_PEER_HAS_PERSISTENT_KEEPALIVE = 1 << 2, WG_IOCTL_PEER_HAS_PERSISTENT_KEEPALIVE = 1 << 2,
WG_IOCTL_PEER_HAS_ENDPOINT = 1 << 3, WG_IOCTL_PEER_HAS_ENDPOINT = 1 << 3,
WG_IOCTL_PEER_HAS_PROTOCOL_VERSION = 1 << 4, WG_IOCTL_PEER_HAS_PROTOCOL_VERSION = 1 << 4,
WG_IOCTL_PEER_REPLACE_ALLOWED_IPS = 1 << 5, WG_IOCTL_PEER_REPLACE_ALLOWED_IPS = 1 << 5,
WG_IOCTL_PEER_REMOVE = 1 << 6, WG_IOCTL_PEER_REMOVE = 1 << 6,
WG_IOCTL_PEER_UPDATE = 1 << 7 WG_IOCTL_PEER_UPDATE = 1 << 7
} WG_IOCTL_PEER_FLAG; } WG_IOCTL_PEER_FLAG;
typedef struct _WG_IOCTL_PEER typedef struct _WG_IOCTL_PEER
{ {
WG_IOCTL_PEER_FLAG Flags; WG_IOCTL_PEER_FLAG Flags;
ULONG ProtocolVersion; /* 0 = latest protocol, 1 = this protocol. */ ULONG ProtocolVersion; /* 0 = latest protocol, 1 = this protocol. */
UCHAR PublicKey[WG_KEY_LEN]; UCHAR PublicKey[WG_KEY_LEN];
UCHAR PresharedKey[WG_KEY_LEN]; UCHAR PresharedKey[WG_KEY_LEN];
USHORT PersistentKeepalive; USHORT PersistentKeepalive;
SOCKADDR_INET Endpoint; SOCKADDR_INET Endpoint;
ULONG64 TxBytes; ULONG64 TxBytes;
ULONG64 RxBytes; ULONG64 RxBytes;
ULONG64 LastHandshake; ULONG64 LastHandshake;
ULONG AllowedIPsCount; ULONG AllowedIPsCount;
} __attribute__((aligned(8))) WG_IOCTL_PEER; } __attribute__((aligned(8))) WG_IOCTL_PEER;
typedef enum typedef enum
{ {
WG_IOCTL_INTERFACE_HAS_PUBLIC_KEY = 1 << 0, WG_IOCTL_INTERFACE_HAS_PUBLIC_KEY = 1 << 0,
WG_IOCTL_INTERFACE_HAS_PRIVATE_KEY = 1 << 1, WG_IOCTL_INTERFACE_HAS_PRIVATE_KEY = 1 << 1,
WG_IOCTL_INTERFACE_HAS_LISTEN_PORT = 1 << 2, WG_IOCTL_INTERFACE_HAS_LISTEN_PORT = 1 << 2,
WG_IOCTL_INTERFACE_REPLACE_PEERS = 1 << 3, WG_IOCTL_INTERFACE_REPLACE_PEERS = 1 << 3,
WG_IOCTL_INTERFACE_PEERS = 1 << 4, WG_IOCTL_INTERFACE_PEERS = 1 << 4,
WG_IOCTL_INTERFACE_JC = 1 << 5, WG_IOCTL_INTERFACE_JC = 1 << 5,
WG_IOCTL_INTERFACE_JMIN = 1 << 6, WG_IOCTL_INTERFACE_JMIN = 1 << 6,
WG_IOCTL_INTERFACE_JMAX = 1 << 7, WG_IOCTL_INTERFACE_JMAX = 1 << 7,
WG_IOCTL_INTERFACE_S1 = 1 << 8, WG_IOCTL_INTERFACE_S1 = 1 << 8,
WG_IOCTL_INTERFACE_S2 = 1 << 9, WG_IOCTL_INTERFACE_S2 = 1 << 9,
WG_IOCTL_INTERFACE_H1 = 1 << 10, WG_IOCTL_INTERFACE_H1 = 1 << 10,
WG_IOCTL_INTERFACE_H2 = 1 << 11, WG_IOCTL_INTERFACE_H2 = 1 << 11,
WG_IOCTL_INTERFACE_H3 = 1 << 12, WG_IOCTL_INTERFACE_H3 = 1 << 12,
WG_IOCTL_INTERFACE_H4 = 1 << 13, WG_IOCTL_INTERFACE_H4 = 1 << 13,
WG_IOCTL_INTERFACE_I1 = 1U << 14, WG_IOCTL_INTERFACE_I1 = 1U << 14,
WG_IOCTL_INTERFACE_I2 = 1U << 15, WG_IOCTL_INTERFACE_I2 = 1U << 15,
WG_IOCTL_INTERFACE_I3 = 1U << 16, WG_IOCTL_INTERFACE_I3 = 1U << 16,
WG_IOCTL_INTERFACE_I4 = 1U << 17, WG_IOCTL_INTERFACE_I4 = 1U << 17,
WG_IOCTL_INTERFACE_I5 = 1U << 18, WG_IOCTL_INTERFACE_I5 = 1U << 18,
WG_IOCTL_INTERFACE_J1 = 1U << 19, WG_IOCTL_INTERFACE_J1 = 1U << 19,
WG_IOCTL_INTERFACE_J2 = 1U << 20, WG_IOCTL_INTERFACE_J2 = 1U << 20,
WG_IOCTL_INTERFACE_J3 = 1U << 21, WG_IOCTL_INTERFACE_J3 = 1U << 21,
WG_IOCTL_INTERFACE_ITIME = 1U << 22 WG_IOCTL_INTERFACE_ITIME = 1U << 22
} WG_IOCTL_INTERFACE_FLAG; } WG_IOCTL_INTERFACE_FLAG;
typedef struct _WG_IOCTL_INTERFACE typedef struct _WG_IOCTL_INTERFACE
{ {
WG_IOCTL_INTERFACE_FLAG Flags; WG_IOCTL_INTERFACE_FLAG Flags;
USHORT ListenPort; USHORT ListenPort;
UCHAR PrivateKey[WG_KEY_LEN]; UCHAR PrivateKey[WG_KEY_LEN];
UCHAR PublicKey[WG_KEY_LEN]; UCHAR PublicKey[WG_KEY_LEN];
ULONG PeersCount; ULONG PeersCount;
USHORT JunkPacketCount; USHORT JunkPacketCount;
USHORT JunkPacketMinSize; USHORT JunkPacketMinSize;
USHORT JunkPacketMaxSize; USHORT JunkPacketMaxSize;
USHORT InitPacketJunkSize; USHORT InitPacketJunkSize;
USHORT ResponsePacketJunkSize; USHORT ResponsePacketJunkSize;
ULONG InitPacketMagicHeader; ULONG InitPacketMagicHeader;
ULONG ResponsePacketMagicHeader; ULONG ResponsePacketMagicHeader;
ULONG UnderloadPacketMagicHeader; ULONG UnderloadPacketMagicHeader;
ULONG TransportPacketMagicHeader; ULONG TransportPacketMagicHeader;
UCHAR* I1;
UCHAR* I2; UCHAR* I1;
UCHAR* I3; UCHAR* I2;
UCHAR* I4; UCHAR* I3;
UCHAR* I5; UCHAR* I4;
UCHAR* J1; UCHAR* I5;
UCHAR* J2; UCHAR* J1;
UCHAR* J3; UCHAR* J2;
ULONG Itime; UCHAR* J3;
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 (DEVPROPKEY) { \
{ 0x65726957, 0x7547, 0x7261, { 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79 } }, \
DEVPROPID_FIRST_USABLE + 1 \
}
#define DEVPKEY_WG_NAME \
(DEVPROPKEY){ \
{0x65726957, 0x7547, 0x7261, {0x64, 0x4e, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79}}, \
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"))) {