feat: first batch of awg-1.5

This commit is contained in:
Mark Puha 2025-06-12 20:15:01 +02:00
parent c0b400c6df
commit 71219488c1
6 changed files with 990 additions and 632 deletions

View file

@ -57,6 +57,15 @@ enum wgdevice_attribute {
WGDEVICE_A_H2,
WGDEVICE_A_H3,
WGDEVICE_A_H4,
WGDEVICE_A_I1,
WGDEVICE_A_I2,
WGDEVICE_A_I3,
WGDEVICE_A_I4,
WGDEVICE_A_I5,
WGDEVICE_A_J1,
WGDEVICE_A_J2,
WGDEVICE_A_J3,
WGDEVICE_A_ITIME,
__WGDEVICE_A_LAST
};

View file

@ -410,6 +410,22 @@ err:
return false;
}
static inline bool parse_string(char **device_value, const char *name, const char *value) {
size_t len = strlen(value);
if (!len) {
fprintf(stderr, "Unable to parse empty string for: %s\n", name);
return false;
}
if( len >= MAX_AWG_JUNK_LEN) {
fprintf(stderr, "Unable to process hex string longer than: %d\n", MAX_AWG_JUNK_LEN);
return false;
}
*device_value = strdup(value);
return true;
}
static inline bool parse_uint16(uint16_t *device_value, const char *name, const char *value) {
if (!strlen(value)) {
@ -558,6 +574,42 @@ static bool process_line(struct config_ctx *ctx, const char *line)
ret = parse_uint32(&ctx->device->transport_packet_magic_header, "H4", value);
if (ret)
ctx->device->flags |= WGDEVICE_HAS_H4;
} else if (key_match("I1")) {
ret = parse_string(&ctx->device->i1, "I1", value);
if (ret)
ctx->device->flags |= WGDEVICE_HAS_I1;
} else if (key_match("I2")) {
ret = parse_string(&ctx->device->i2, "I2", value);
if (ret)
ctx->device->flags |= WGDEVICE_HAS_I2;
} else if (key_match("I3")) {
ret = parse_string(&ctx->device->i3, "I3", value);
if (ret)
ctx->device->flags |= WGDEVICE_HAS_I3;
} else if (key_match("I4")) {
ret = parse_string(&ctx->device->i4, "I4", value);
if (ret)
ctx->device->flags |= WGDEVICE_HAS_I4;
} else if (key_match("I5")) {
ret = parse_string(&ctx->device->i5, "I5", value);
if (ret)
ctx->device->flags |= WGDEVICE_HAS_I5;
} else if (key_match("J1")) {
ret = parse_string(&ctx->device->j1, "J1", value);
if (ret)
ctx->device->flags |= WGDEVICE_HAS_J1;
} else if (key_match("J2")) {
ret = parse_string(&ctx->device->j2, "J2", value);
if (ret)
ctx->device->flags |= WGDEVICE_HAS_J2;
} else if (key_match("J3")) {
ret = parse_string(&ctx->device->j3, "J3", value);
if (ret)
ctx->device->flags |= WGDEVICE_HAS_J3;
} else if (key_match("ITIME")) {
ret = parse_string(&ctx->device->itime, "Itime", value);
if (ret)
ctx->device->flags |= WGDEVICE_HAS_ITIME;
} else
goto error;
} else if (ctx->is_peer_section) {
@ -763,6 +815,69 @@ struct wgdevice *config_read_cmd(const char *argv[], int argc)
device->flags |= WGDEVICE_HAS_H4;
argv += 2;
argc -= 2;
} else if (!strcmp(argv[0], "i1") && argc >= 2 && !peer) {
if (!parse_string(&device->i1, "i1", argv[1]))
goto error;
device->flags |= WGDEVICE_HAS_I1;
argv += 2;
argc -= 2;
} else if (!strcmp(argv[0], "i2") && argc >= 2 && !peer) {
if (!parse_string(&device->i2, "i2", argv[1]))
goto error;
device->flags |= WGDEVICE_HAS_I2;
argv += 2;
argc -=2;
} else if (!strcmp(argv[0], "i3") && argc >= 2 && !peer) {
if (!parse_string(&device->i3, "i3", argv[1]))
goto error;
device->flags |= WGDEVICE_HAS_I3;
argv += 2;
argc -=2;
} else if (!strcmp(argv[0], "i4") && argc >= 2 && !peer) {
if (!parse_string(&device->i4, "i4", argv[1]))
goto error;
device->flags |= WGDEVICE_HAS_I4;
argv += 2;
argc -=2;
} else if (!strcmp(argv[0], "i5") && argc >= 2 && !peer) {
if (!parse_string(&device->i5, "i5", argv[1]))
goto error;
device->flags |= WGDEVICE_HAS_I5;
argv += 2;
argc -=2;
} else if (!strcmp(argv[0], "j1") && argc >= 2 && !peer) {
if (!parse_string(&device->j1, "j1", argv[1]))
goto error;
device->flags |= WGDEVICE_HAS_J1;
argv += 2;
argc -=2;
} else if (!strcmp(argv[0], "j2") && argc >= 2 && !peer) {
if (!parse_string(&device->j2, "j2", argv[1]))
goto error;
device->flags |= WGDEVICE_HAS_J2;
argv += 2;
argc -=2;
} else if (!strcmp(argv[0], "j3") && argc >= 2 && !peer) {
if (!parse_string(&device->j3, "j3", argv[1]))
goto error;
device->flags |= WGDEVICE_HAS_J3;
argv += 2;
argc -=2;
} else if (!strcmp(argv[0], "itime") && argc >= 2 && !peer) {
if (!parse_string(&device->itime, "itime", argv[1]))
goto error;
device->flags |= WGDEVICE_HAS_ITIME;
argv += 2;
argc -=2;
} else if (!strcmp(argv[0], "peer") && argc >= 2) {
struct wgpeer *new_peer = calloc(1, sizeof(*new_peer));

View file

@ -6,13 +6,13 @@
#ifndef 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 <netinet/in.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <time.h>
#if defined(__linux__)
#include <linux/wireguard.h>
#elif defined(__OpenBSD__)
@ -23,15 +23,22 @@
#define WG_KEY_LEN 32
#endif
#ifndef MAX_AWG_JUNK_LEN
#define MAX_AWG_JUNK_LEN 5 * 1024
#endif
/* Cross platform __kernel_timespec */
struct timespec64 {
struct timespec64
{
int64_t tv_sec;
int64_t tv_nsec;
};
struct wgallowedip {
struct wgallowedip
{
uint16_t family;
union {
union
{
struct in_addr ip4;
struct in6_addr ip6;
};
@ -39,7 +46,8 @@ struct wgallowedip {
struct wgallowedip* next_allowedip;
};
enum {
enum
{
WGPEER_REMOVE_ME = 1U << 0,
WGPEER_REPLACE_ALLOWEDIPS = 1U << 1,
WGPEER_HAS_PUBLIC_KEY = 1U << 2,
@ -48,13 +56,15 @@ enum {
WGPEER_HAS_ADVANCED_SECURITY = 1U << 5
};
struct wgpeer {
struct wgpeer
{
uint32_t flags;
uint8_t public_key[WG_KEY_LEN];
uint8_t preshared_key[WG_KEY_LEN];
union {
union
{
struct sockaddr addr;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
@ -70,7 +80,8 @@ struct wgpeer {
struct wgpeer* next_peer;
};
enum {
enum
{
WGDEVICE_REPLACE_PEERS = 1U << 0,
WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
@ -84,10 +95,20 @@ enum {
WGDEVICE_HAS_H1 = 1U << 10,
WGDEVICE_HAS_H2 = 1U << 11,
WGDEVICE_HAS_H3 = 1U << 12,
WGDEVICE_HAS_H4 = 1U << 13
WGDEVICE_HAS_H4 = 1U << 13,
WGDEVICE_HAS_I1 = 1U << 14,
WGDEVICE_HAS_I2 = 1U << 15,
WGDEVICE_HAS_I3 = 1U << 16,
WGDEVICE_HAS_I4 = 1U << 17,
WGDEVICE_HAS_I5 = 1U << 18,
WGDEVICE_HAS_J1 = 1U << 19,
WGDEVICE_HAS_J2 = 1U << 20,
WGDEVICE_HAS_J3 = 1U << 21,
WGDEVICE_HAS_ITIME = 1U << 22
};
struct wgdevice {
struct wgdevice
{
char name[IFNAMSIZ];
uint32_t ifindex;
@ -110,17 +131,34 @@ struct wgdevice {
uint32_t response_packet_magic_header;
uint32_t underload_packet_magic_header;
uint32_t transport_packet_magic_header;
char* i1;
char* i2;
char* i3;
char* i4;
char* i5;
char* j1;
char* j2;
char* j3;
char* itime;
};
#define for_each_wgpeer(__dev, __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_wgpeer(__dev, __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)
static inline void free_wgdevice(struct wgdevice* dev)
{
if (!dev)
return;
for (struct wgpeer *peer = dev->first_peer, *np = peer ? peer->next_peer : NULL; peer; 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 wgpeer *peer = dev->first_peer, *np = peer ? peer->next_peer : NULL; peer;
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);
free(peer);
}

View file

@ -3,31 +3,32 @@
* Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "containers.h"
#include "encoding.h"
#include "netlink.h"
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/genetlink.h>
#include <linux/if_link.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/wireguard.h>
#include <netinet/in.h>
#include "containers.h"
#include "encoding.h"
#include "netlink.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.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 SOCKET_BUFFER_SIZE (mnl_ideal_socket_buffer_size())
struct interface {
struct interface
{
const char* name;
bool is_wireguard;
};
@ -36,7 +37,8 @@ static int parse_linkinfo(const struct nlattr *attr, void *data)
{
struct interface* interface = data;
if (mnl_attr_get_type(attr) == IFLA_INFO_KIND && !strcmp(WG_GENL_NAME, mnl_attr_get_str(attr)))
if (mnl_attr_get_type(attr) == IFLA_INFO_KIND &&
!strcmp(WG_GENL_NAME, mnl_attr_get_str(attr)))
interface->is_wireguard = true;
return MNL_CB_OK;
}
@ -87,12 +89,14 @@ static int kernel_get_wireguard_interfaces(struct string_list *list)
goto cleanup;
nl = mnl_socket_open(NETLINK_ROUTE);
if (!nl) {
if (!nl)
{
ret = -errno;
goto cleanup;
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
{
ret = -errno;
goto cleanup;
}
@ -107,23 +111,27 @@ static int kernel_get_wireguard_interfaces(struct string_list *list)
ifm->ifi_family = AF_UNSPEC;
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;
goto cleanup;
}
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;
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
* during the dump. That's unfortunate, but is pretty common on busy
* systems that are adding and removing tunnels all the time. Rather
* than retrying, potentially indefinitely, we just work with the
* partial results. */
if (errno != EINTR) {
if (errno != EINTR)
{
ret = -errno;
goto cleanup;
}
@ -156,11 +164,13 @@ again:
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);
if (!peer) {
if (!peer)
{
uint32_t flags = 0;
if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY)
mnl_attr_put(nlh, WGDEVICE_A_PRIVATE_KEY, sizeof(dev->private_key), dev->private_key);
mnl_attr_put(
nlh, WGDEVICE_A_PRIVATE_KEY, sizeof(dev->private_key), dev->private_key);
if (dev->flags & WGDEVICE_HAS_LISTEN_PORT)
mnl_attr_put_u16(nlh, WGDEVICE_A_LISTEN_PORT, dev->listen_port);
if (dev->flags & WGDEVICE_HAS_JC)
@ -192,64 +202,119 @@ again:
goto send;
peers_nest = peer_nest = allowedips_nest = allowedip_nest = NULL;
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;
peer_nest = mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, 0);
if (!peer_nest)
goto toobig_peers;
if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_PUBLIC_KEY, sizeof(peer->public_key), peer->public_key))
if (!mnl_attr_put_check(
nlh,
SOCKET_BUFFER_SIZE,
WGPEER_A_PUBLIC_KEY,
sizeof(peer->public_key),
peer->public_key))
goto toobig_peers;
if (peer->flags & WGPEER_REMOVE_ME)
flags |= WGPEER_F_REMOVE_ME;
if (!allowedip) {
if (!allowedip)
{
if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS)
flags |= WGPEER_F_REPLACE_ALLOWEDIPS;
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 (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))
goto toobig_peers;
}
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))
goto toobig_peers;
} else if (peer->endpoint.addr.sa_family == AF_INET6) {
if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ENDPOINT, sizeof(peer->endpoint.addr6), &peer->endpoint.addr6))
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))
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))
else if (peer->endpoint.addr.sa_family == AF_INET6)
{
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;
}
}
if (peer->flags & WGPEER_HAS_ADVANCED_SECURITY) {
if (peer->flags & WGPEER_HAS_ADVANCED_SECURITY)
{
if (peer->advanced_security)
mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ADVANCED_SECURITY, 0, NULL);
mnl_attr_put_check(
nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ADVANCED_SECURITY, 0, NULL);
flags |= WGPEER_F_HAS_ADVANCED_SECURITY;
}
if (flags) {
if (flags)
{
if (!mnl_attr_put_u32_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_FLAGS, flags))
goto toobig_peers;
}
if (peer->first_allowedip) {
if (peer->first_allowedip)
{
if (!allowedip)
allowedip = peer->first_allowedip;
allowedips_nest = mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ALLOWEDIPS);
allowedips_nest =
mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ALLOWEDIPS);
if (!allowedips_nest)
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);
if (!allowedip_nest)
goto toobig_allowedips;
if (!mnl_attr_put_u16_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_FAMILY, allowedip->family))
if (!mnl_attr_put_u16_check(
nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_FAMILY, allowedip->family))
goto toobig_allowedips;
if (allowedip->family == AF_INET) {
if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_IPADDR, sizeof(allowedip->ip4), &allowedip->ip4))
goto toobig_allowedips;
} else if (allowedip->family == AF_INET6) {
if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_IPADDR, sizeof(allowedip->ip6), &allowedip->ip6))
if (allowedip->family == AF_INET)
{
if (!mnl_attr_put_check(
nlh,
SOCKET_BUFFER_SIZE,
WGALLOWEDIP_A_IPADDR,
sizeof(allowedip->ip4),
&allowedip->ip4))
goto toobig_allowedips;
}
if (!mnl_attr_put_u8_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_CIDR_MASK, allowedip->cidr))
else if (allowedip->family == AF_INET6)
{
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;
mnl_attr_nest_end(nlh, allowedip_nest);
allowedip_nest = NULL;
@ -278,12 +343,14 @@ toobig_peers:
mnl_attr_nest_end(nlh, peers_nest);
goto send;
send:
if (mnlg_socket_send(nlg, nlh) < 0) {
if (mnlg_socket_send(nlg, nlh) < 0)
{
ret = -errno;
goto out;
}
errno = 0;
if (mnlg_socket_recv_run(nlg, NULL, NULL) < 0) {
if (mnlg_socket_recv_run(nlg, NULL, NULL) < 0)
{
ret = errno ? -errno : -EINVAL;
goto out;
}
@ -300,7 +367,8 @@ static int parse_allowedip(const struct nlattr *attr, void *data)
{
struct wgallowedip* allowedip = data;
switch (mnl_attr_get_type(attr)) {
switch (mnl_attr_get_type(attr))
{
case WGALLOWEDIP_A_UNSPEC:
break;
case WGALLOWEDIP_A_FAMILY:
@ -328,20 +396,23 @@ static int parse_allowedips(const struct nlattr *attr, void *data)
struct wgallowedip* new_allowedip = calloc(1, sizeof(*new_allowedip));
int ret;
if (!new_allowedip) {
if (!new_allowedip)
{
perror("calloc");
return MNL_CB_ERROR;
}
if (!peer->first_allowedip)
peer->first_allowedip = peer->last_allowedip = new_allowedip;
else {
else
{
peer->last_allowedip->next_allowedip = new_allowedip;
peer->last_allowedip = new_allowedip;
}
ret = mnl_attr_parse_nested(attr, parse_allowedip, new_allowedip);
if (!ret)
return ret;
if (!((new_allowedip->family == AF_INET && new_allowedip->cidr <= 32) || (new_allowedip->family == AF_INET6 && new_allowedip->cidr <= 128)))
if (!((new_allowedip->family == AF_INET && new_allowedip->cidr <= 32) ||
(new_allowedip->family == AF_INET6 && new_allowedip->cidr <= 128)))
return MNL_CB_ERROR;
return MNL_CB_OK;
}
@ -350,18 +421,25 @@ static int parse_peer(const struct nlattr *attr, void *data)
{
struct wgpeer* peer = data;
switch (mnl_attr_get_type(attr)) {
switch (mnl_attr_get_type(attr))
{
case WGPEER_A_UNSPEC:
break;
case WGPEER_A_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));
if (mnl_attr_get_payload_len(attr) == sizeof(peer->public_key))
{
memcpy(
peer->public_key, mnl_attr_get_payload(attr), sizeof(peer->public_key));
peer->flags |= WGPEER_HAS_PUBLIC_KEY;
}
break;
case WGPEER_A_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));
if (mnl_attr_get_payload_len(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))
peer->flags |= WGPEER_HAS_PRESHARED_KEY;
}
@ -372,9 +450,12 @@ static int parse_peer(const struct nlattr *attr, void *data)
if (mnl_attr_get_payload_len(attr) < sizeof(*addr))
break;
addr = mnl_attr_get_payload(attr);
if (addr->sa_family == AF_INET && mnl_attr_get_payload_len(attr) == sizeof(peer->endpoint.addr4))
if (addr->sa_family == AF_INET &&
mnl_attr_get_payload_len(attr) == sizeof(peer->endpoint.addr4))
memcpy(&peer->endpoint.addr4, addr, sizeof(peer->endpoint.addr4));
else if (addr->sa_family == AF_INET6 && mnl_attr_get_payload_len(attr) == sizeof(peer->endpoint.addr6))
else if (
addr->sa_family == AF_INET6 &&
mnl_attr_get_payload_len(attr) == sizeof(peer->endpoint.addr6))
memcpy(&peer->endpoint.addr6, addr, sizeof(peer->endpoint.addr6));
break;
}
@ -384,7 +465,10 @@ static int parse_peer(const struct nlattr *attr, void *data)
break;
case WGPEER_A_LAST_HANDSHAKE_TIME:
if (mnl_attr_get_payload_len(attr) == sizeof(peer->last_handshake_time))
memcpy(&peer->last_handshake_time, mnl_attr_get_payload(attr), sizeof(peer->last_handshake_time));
memcpy(
&peer->last_handshake_time,
mnl_attr_get_payload(attr),
sizeof(peer->last_handshake_time));
break;
case WGPEER_A_RX_BYTES:
if (!mnl_attr_validate(attr, MNL_TYPE_U64))
@ -395,20 +479,25 @@ static int parse_peer(const struct nlattr *attr, void *data)
peer->tx_bytes = mnl_attr_get_u64(attr);
break;
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);
if (flags & WGPEER_F_HAS_ADVANCED_SECURITY && !(peer->flags & WGPEER_HAS_ADVANCED_SECURITY)) {
if (flags & WGPEER_F_HAS_ADVANCED_SECURITY &&
!(peer->flags & WGPEER_HAS_ADVANCED_SECURITY))
{
peer->flags |= WGPEER_HAS_ADVANCED_SECURITY;
peer->advanced_security = false;
}
}
break;
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;
if (!(peer->flags & WGPEER_HAS_ADVANCED_SECURITY)) {
if (!(peer->flags & WGPEER_HAS_ADVANCED_SECURITY))
{
peer->flags |= WGPEER_HAS_ADVANCED_SECURITY;
}
}
@ -426,13 +515,15 @@ static int parse_peers(const struct nlattr *attr, void *data)
struct wgpeer* new_peer = calloc(1, sizeof(*new_peer));
int ret;
if (!new_peer) {
if (!new_peer)
{
perror("calloc");
return MNL_CB_ERROR;
}
if (!device->first_peer)
device->first_peer = device->last_peer = new_peer;
else {
else
{
device->last_peer->next_peer = new_peer;
device->last_peer = new_peer;
}
@ -448,7 +539,8 @@ static int parse_device(const struct nlattr *attr, void *data)
{
struct wgdevice* device = data;
switch (mnl_attr_get_type(attr)) {
switch (mnl_attr_get_type(attr))
{
case WGDEVICE_A_UNSPEC:
break;
case WGDEVICE_A_IFINDEX:
@ -456,20 +548,29 @@ static int parse_device(const struct nlattr *attr, void *data)
device->ifindex = mnl_attr_get_u32(attr);
break;
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);
device->name[sizeof(device->name) - 1] = '\0';
}
break;
case WGDEVICE_A_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));
if (mnl_attr_get_payload_len(attr) == sizeof(device->private_key))
{
memcpy(
device->private_key,
mnl_attr_get_payload(attr),
sizeof(device->private_key));
device->flags |= WGDEVICE_HAS_PRIVATE_KEY;
}
break;
case WGDEVICE_A_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));
if (mnl_attr_get_payload_len(attr) == sizeof(device->public_key))
{
memcpy(
device->public_key,
mnl_attr_get_payload(attr),
sizeof(device->public_key));
device->flags |= WGDEVICE_HAS_PUBLIC_KEY;
}
break;
@ -484,58 +585,113 @@ static int parse_device(const struct nlattr *attr, void *data)
case WGDEVICE_A_PEERS:
return mnl_attr_parse_nested(attr, parse_peers, device);
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->flags |= WGDEVICE_HAS_JC;
}
break;
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->flags |= WGDEVICE_HAS_JMIN;
}
break;
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->flags |= WGDEVICE_HAS_JMAX;
}
break;
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->flags |= WGDEVICE_HAS_S1;
}
break;
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->flags |= WGDEVICE_HAS_S2;
}
break;
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->flags |= WGDEVICE_HAS_H1;
}
break;
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->flags |= WGDEVICE_HAS_H2;
}
break;
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->flags |= WGDEVICE_HAS_H3;
}
break;
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->flags |= WGDEVICE_HAS_H4;
}
case WGDEVICE_A_I1:
if (!mnl_attr_validate(attr, MNL_TYPE_STRING) {
device->i1 = strdup(mnl_attr_get_str(attr));
device->flags |= WGDEVICE_HAS_I1;
}
case WGDEVICE_A_I2:
if (!mnl_attr_validate(attr, MNL_TYPE_STRING) {
device->i2 = strdup(mnl_attr_get_str(attr));
device->flags |= WGDEVICE_HAS_I2;
}
case WGDEVICE_A_I3:
if (!mnl_attr_validate(attr, MNL_TYPE_STRING) {
device->i3 = strdup(mnl_attr_get_str(attr));
device->flags |= WGDEVICE_HAS_I3;
}
case WGDEVICE_A_I4:
if (!mnl_attr_validate(attr, MNL_TYPE_STRING) {
device->i4 = strdup(mnl_attr_get_str(attr));
device->flags |= WGDEVICE_HAS_I4;
}
case WGDEVICE_A_I5:
if (!mnl_attr_validate(attr, MNL_TYPE_STRING) {
device->i5 = strdup(mnl_attr_get_str(attr));
device->flags |= WGDEVICE_HAS_I5;
}
case WGDEVICE_A_J1:
if (!mnl_attr_validate(attr, MNL_TYPE_STRING) {
device->j1 = strdup(mnl_attr_get_str(attr));
device->flags |= WGDEVICE_HAS_J1;
}
case WGDEVICE_A_J2:
if (!mnl_attr_validate(attr, MNL_TYPE_STRING) {
device->j2 = strdup(mnl_attr_get_str(attr));
device->flags |= WGDEVICE_HAS_J2;
}
case WGDEVICE_A_J3:
if (!mnl_attr_validate(attr, MNL_TYPE_STRING) {
device->j3 = strdup(mnl_attr_get_str(attr));
device->flags |= WGDEVICE_HAS_J3;
}
case WGDEVICE_A_ITIME:
if (!mnl_attr_validate(attr, MNL_TYPE_STRING) {
device->itime = strdup(mnl_attr_get_str(attr));
device->flags |= WGDEVICE_HAS_ITIME;
}
break;
}
@ -551,15 +707,21 @@ static void coalesce_peers(struct wgdevice *device)
{
struct wgpeer *old_next_peer, *peer = device->first_peer;
while (peer && peer->next_peer) {
if (memcmp(peer->public_key, peer->next_peer->public_key, sizeof(peer->public_key))) {
while (peer && peer->next_peer)
{
if (memcmp(
peer->public_key, peer->next_peer->public_key, sizeof(peer->public_key)))
{
peer = peer->next_peer;
continue;
}
if (!peer->first_allowedip) {
if (!peer->first_allowedip)
{
peer->first_allowedip = peer->next_peer->first_allowedip;
peer->last_allowedip = peer->next_peer->last_allowedip;
} else {
}
else
{
peer->last_allowedip->next_allowedip = peer->next_peer->first_allowedip;
peer->last_allowedip = peer->next_peer->last_allowedip;
}
@ -576,7 +738,8 @@ static int kernel_get_device(struct wgdevice **device, const char *iface)
struct mnlg_socket* nlg;
/* libmnl doesn't check the buffer size, so enforce that before using. */
if (strlen(iface) >= IFNAMSIZ) {
if (strlen(iface) >= IFNAMSIZ)
{
errno = ENAMETOOLONG;
return -ENAMETOOLONG;
}
@ -588,20 +751,24 @@ try_again:
return -errno;
nlg = mnlg_socket_open(WG_GENL_NAME, WG_GENL_VERSION);
if (!nlg) {
if (!nlg)
{
free_wgdevice(*device);
*device = NULL;
return -errno;
}
nlh = mnlg_msg_prepare(nlg, WG_CMD_GET_DEVICE, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
nlh =
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);
if (mnlg_socket_send(nlg, nlh) < 0) {
if (mnlg_socket_send(nlg, nlh) < 0)
{
ret = -errno;
goto out;
}
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;
goto out;
}
@ -610,7 +777,8 @@ try_again:
out:
if (nlg)
mnlg_socket_close(nlg);
if (ret) {
if (ret)
{
free_wgdevice(*device);
if (ret == -EINTR)
goto try_again;

View file

@ -65,6 +65,25 @@ int showconf_main(int argc, const char *argv[])
if (device->flags & WGDEVICE_HAS_H4)
printf("H4 = %u\n", device->transport_packet_magic_header);
if (device->flags & WGDEVICE_HAS_I1)
printf("I1 = %s\n", device->i1);
if (device->flags & WGDEVICE_HAS_I2)
printf("I2 = %s\n", device->i2);
if (device->flags & WGDEVICE_HAS_I3)
printf("I3 = %s\n", device->i3);
if (device->flags & WGDEVICE_HAS_I4)
printf("I4 = %s\n", device->i4);
if (device->flags & WGDEVICE_HAS_I5)
printf("I5 = %s\n", device->i5);
if (device->flags & WGDEVICE_HAS_J1)
printf("J1 = %s\n", device->j1);
if (device->flags & WGDEVICE_HAS_J2)
printf("J2 = %s\n", device->j2);
if (device->flags & WGDEVICE_HAS_J3)
printf("J3 = %s\n", device->j3);
if (device->flags & WGDEVICE_HAS_ITIME)
printf("Itime = %s\n", device->itime);
printf("\n");
for_each_wgpeer(device, peer) {
key_to_base64(base64, peer->public_key);

View file

@ -191,6 +191,15 @@ enum wgdevice_attribute {
WGDEVICE_A_H2,
WGDEVICE_A_H3,
WGDEVICE_A_H4,
WGDEVICE_A_I1,
WGDEVICE_A_I2,
WGDEVICE_A_I3,
WGDEVICE_A_I4,
WGDEVICE_A_I5,
WGDEVICE_A_J1,
WGDEVICE_A_J2,
WGDEVICE_A_J3,
WGDEVICE_A_ITIME,
WGDEVICE_A_PEER,
__WGDEVICE_A_LAST
};