mirror of
https://github.com/amnezia-vpn/amneziawg-tools.git
synced 2025-08-03 10:02:50 +02:00
feat: first batch of awg-1.5
This commit is contained in:
parent
c0b400c6df
commit
71219488c1
6 changed files with 990 additions and 632 deletions
|
@ -57,6 +57,15 @@ enum wgdevice_attribute {
|
||||||
WGDEVICE_A_H2,
|
WGDEVICE_A_H2,
|
||||||
WGDEVICE_A_H3,
|
WGDEVICE_A_H3,
|
||||||
WGDEVICE_A_H4,
|
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
|
__WGDEVICE_A_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
115
src/config.c
115
src/config.c
|
@ -410,6 +410,22 @@ err:
|
||||||
return false;
|
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) {
|
static inline bool parse_uint16(uint16_t *device_value, const char *name, const char *value) {
|
||||||
|
|
||||||
if (!strlen(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);
|
ret = parse_uint32(&ctx->device->transport_packet_magic_header, "H4", value);
|
||||||
if (ret)
|
if (ret)
|
||||||
ctx->device->flags |= WGDEVICE_HAS_H4;
|
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
|
} else
|
||||||
goto error;
|
goto error;
|
||||||
} else if (ctx->is_peer_section) {
|
} 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;
|
device->flags |= WGDEVICE_HAS_H4;
|
||||||
argv += 2;
|
argv += 2;
|
||||||
argc -= 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) {
|
} else if (!strcmp(argv[0], "peer") && argc >= 2) {
|
||||||
struct wgpeer *new_peer = calloc(1, sizeof(*new_peer));
|
struct wgpeer *new_peer = calloc(1, sizeof(*new_peer));
|
||||||
|
|
||||||
|
|
|
@ -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__)
|
||||||
|
@ -23,15 +23,22 @@
|
||||||
#define WG_KEY_LEN 32
|
#define WG_KEY_LEN 32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX_AWG_JUNK_LEN
|
||||||
|
#define MAX_AWG_JUNK_LEN 5 * 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Cross platform __kernel_timespec */
|
/* Cross platform __kernel_timespec */
|
||||||
struct timespec64 {
|
struct timespec64
|
||||||
|
{
|
||||||
int64_t tv_sec;
|
int64_t tv_sec;
|
||||||
int64_t tv_nsec;
|
int64_t tv_nsec;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wgallowedip {
|
struct wgallowedip
|
||||||
|
{
|
||||||
uint16_t family;
|
uint16_t family;
|
||||||
union {
|
union
|
||||||
|
{
|
||||||
struct in_addr ip4;
|
struct in_addr ip4;
|
||||||
struct in6_addr ip6;
|
struct in6_addr ip6;
|
||||||
};
|
};
|
||||||
|
@ -39,7 +46,8 @@ struct wgallowedip {
|
||||||
struct wgallowedip* next_allowedip;
|
struct wgallowedip* next_allowedip;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
WGPEER_REMOVE_ME = 1U << 0,
|
WGPEER_REMOVE_ME = 1U << 0,
|
||||||
WGPEER_REPLACE_ALLOWEDIPS = 1U << 1,
|
WGPEER_REPLACE_ALLOWEDIPS = 1U << 1,
|
||||||
WGPEER_HAS_PUBLIC_KEY = 1U << 2,
|
WGPEER_HAS_PUBLIC_KEY = 1U << 2,
|
||||||
|
@ -48,13 +56,15 @@ enum {
|
||||||
WGPEER_HAS_ADVANCED_SECURITY = 1U << 5
|
WGPEER_HAS_ADVANCED_SECURITY = 1U << 5
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
||||||
|
@ -70,7 +80,8 @@ struct wgpeer {
|
||||||
struct wgpeer* next_peer;
|
struct wgpeer* next_peer;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
WGDEVICE_REPLACE_PEERS = 1U << 0,
|
WGDEVICE_REPLACE_PEERS = 1U << 0,
|
||||||
WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
|
WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
|
||||||
WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
|
WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
|
||||||
|
@ -84,10 +95,20 @@ enum {
|
||||||
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_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];
|
char name[IFNAMSIZ];
|
||||||
uint32_t ifindex;
|
uint32_t ifindex;
|
||||||
|
|
||||||
|
@ -110,17 +131,34 @@ struct wgdevice {
|
||||||
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* 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_wgpeer(__dev, __peer) \
|
||||||
#define for_each_wgallowedip(__peer, __allowedip) for ((__allowedip) = (__peer)->first_allowedip; (__allowedip); (__allowedip) = (__allowedip)->next_allowedip)
|
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)
|
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; peer = np, np = peer ? peer->next_peer : NULL) {
|
for (struct wgpeer *peer = dev->first_peer, *np = peer ? peer->next_peer : NULL; peer;
|
||||||
for (struct wgallowedip *allowedip = peer->first_allowedip, *na = allowedip ? allowedip->next_allowedip : NULL; allowedip; allowedip = na, na = allowedip ? allowedip->next_allowedip : 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);
|
free(allowedip);
|
||||||
free(peer);
|
free(peer);
|
||||||
}
|
}
|
||||||
|
|
352
src/ipc-linux.h
352
src/ipc-linux.h
|
@ -3,31 +3,32 @@
|
||||||
* 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 <stdbool.h>
|
#include "containers.h"
|
||||||
#include <stddef.h>
|
#include "encoding.h"
|
||||||
#include <stdint.h>
|
#include "netlink.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <linux/genetlink.h>
|
#include <linux/genetlink.h>
|
||||||
#include <linux/if_link.h>
|
#include <linux/if_link.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
#include <linux/wireguard.h>
|
#include <linux/wireguard.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include "containers.h"
|
#include <stdbool.h>
|
||||||
#include "encoding.h"
|
#include <stddef.h>
|
||||||
#include "netlink.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 IPC_SUPPORTS_KERNEL_INTERFACE
|
||||||
|
|
||||||
#define SOCKET_BUFFER_SIZE (mnl_ideal_socket_buffer_size())
|
#define SOCKET_BUFFER_SIZE (mnl_ideal_socket_buffer_size())
|
||||||
|
|
||||||
struct interface {
|
struct interface
|
||||||
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
bool is_wireguard;
|
bool is_wireguard;
|
||||||
};
|
};
|
||||||
|
@ -36,7 +37,8 @@ static int parse_linkinfo(const struct nlattr *attr, void *data)
|
||||||
{
|
{
|
||||||
struct interface* interface = data;
|
struct interface* interface = data;
|
||||||
|
|
||||||
if (mnl_attr_get_type(attr) == IFLA_INFO_KIND && !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;
|
interface->is_wireguard = true;
|
||||||
return MNL_CB_OK;
|
return MNL_CB_OK;
|
||||||
}
|
}
|
||||||
|
@ -87,12 +89,14 @@ static int kernel_get_wireguard_interfaces(struct string_list *list)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
nl = mnl_socket_open(NETLINK_ROUTE);
|
nl = mnl_socket_open(NETLINK_ROUTE);
|
||||||
if (!nl) {
|
if (!nl)
|
||||||
|
{
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
|
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
|
||||||
|
{
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -107,23 +111,27 @@ static int kernel_get_wireguard_interfaces(struct string_list *list)
|
||||||
ifm->ifi_family = AF_UNSPEC;
|
ifm->ifi_family = AF_UNSPEC;
|
||||||
message_len = nlh->nlmsg_len;
|
message_len = nlh->nlmsg_len;
|
||||||
|
|
||||||
if (mnl_socket_sendto(nl, rtnl_buffer, message_len) < 0) {
|
if (mnl_socket_sendto(nl, rtnl_buffer, message_len) < 0)
|
||||||
|
{
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
another:
|
another:
|
||||||
if ((len = mnl_socket_recvfrom(nl, rtnl_buffer, SOCKET_BUFFER_SIZE)) < 0) {
|
if ((len = mnl_socket_recvfrom(nl, rtnl_buffer, SOCKET_BUFFER_SIZE)) < 0)
|
||||||
|
{
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if ((len = mnl_cb_run(rtnl_buffer, len, seq, portid, read_devices_cb, list)) < 0) {
|
if ((len = mnl_cb_run(rtnl_buffer, len, seq, portid, read_devices_cb, list)) < 0)
|
||||||
|
{
|
||||||
/* Netlink returns NLM_F_DUMP_INTR if the set of all tunnels changed
|
/* Netlink returns NLM_F_DUMP_INTR if the set of all tunnels changed
|
||||||
* during the dump. That's unfortunate, but is pretty common on busy
|
* during the dump. That's unfortunate, but is pretty common on busy
|
||||||
* systems that are adding and removing tunnels all the time. Rather
|
* systems that are adding and removing tunnels all the time. Rather
|
||||||
* than retrying, potentially indefinitely, we just work with the
|
* than retrying, potentially indefinitely, we just work with the
|
||||||
* partial results. */
|
* partial results. */
|
||||||
if (errno != EINTR) {
|
if (errno != EINTR)
|
||||||
|
{
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -156,11 +164,13 @@ again:
|
||||||
nlh = mnlg_msg_prepare(nlg, WG_CMD_SET_DEVICE, NLM_F_REQUEST | NLM_F_ACK);
|
nlh = mnlg_msg_prepare(nlg, WG_CMD_SET_DEVICE, NLM_F_REQUEST | NLM_F_ACK);
|
||||||
mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, dev->name);
|
mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, dev->name);
|
||||||
|
|
||||||
if (!peer) {
|
if (!peer)
|
||||||
|
{
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
|
|
||||||
if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY)
|
if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY)
|
||||||
mnl_attr_put(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)
|
if (dev->flags & WGDEVICE_HAS_LISTEN_PORT)
|
||||||
mnl_attr_put_u16(nlh, WGDEVICE_A_LISTEN_PORT, dev->listen_port);
|
mnl_attr_put_u16(nlh, WGDEVICE_A_LISTEN_PORT, dev->listen_port);
|
||||||
if (dev->flags & WGDEVICE_HAS_JC)
|
if (dev->flags & WGDEVICE_HAS_JC)
|
||||||
|
@ -192,64 +202,119 @@ again:
|
||||||
goto send;
|
goto send;
|
||||||
peers_nest = peer_nest = allowedips_nest = allowedip_nest = NULL;
|
peers_nest = peer_nest = allowedips_nest = allowedip_nest = NULL;
|
||||||
peers_nest = mnl_attr_nest_start(nlh, WGDEVICE_A_PEERS);
|
peers_nest = mnl_attr_nest_start(nlh, WGDEVICE_A_PEERS);
|
||||||
for (peer = peer ? peer : dev->first_peer; peer; peer = peer->next_peer) {
|
for (peer = peer ? peer : dev->first_peer; peer; peer = peer->next_peer)
|
||||||
|
{
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
|
|
||||||
peer_nest = mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, 0);
|
peer_nest = mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, 0);
|
||||||
if (!peer_nest)
|
if (!peer_nest)
|
||||||
goto toobig_peers;
|
goto toobig_peers;
|
||||||
if (!mnl_attr_put_check(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;
|
goto toobig_peers;
|
||||||
if (peer->flags & WGPEER_REMOVE_ME)
|
if (peer->flags & WGPEER_REMOVE_ME)
|
||||||
flags |= WGPEER_F_REMOVE_ME;
|
flags |= WGPEER_F_REMOVE_ME;
|
||||||
if (!allowedip) {
|
if (!allowedip)
|
||||||
|
{
|
||||||
if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS)
|
if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS)
|
||||||
flags |= WGPEER_F_REPLACE_ALLOWEDIPS;
|
flags |= WGPEER_F_REPLACE_ALLOWEDIPS;
|
||||||
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) {
|
if (peer->flags & WGPEER_HAS_PRESHARED_KEY)
|
||||||
if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_PRESHARED_KEY, sizeof(peer->preshared_key), peer->preshared_key))
|
{
|
||||||
|
if (!mnl_attr_put_check(
|
||||||
|
nlh,
|
||||||
|
SOCKET_BUFFER_SIZE,
|
||||||
|
WGPEER_A_PRESHARED_KEY,
|
||||||
|
sizeof(peer->preshared_key),
|
||||||
|
peer->preshared_key))
|
||||||
goto toobig_peers;
|
goto toobig_peers;
|
||||||
}
|
}
|
||||||
if (peer->endpoint.addr.sa_family == AF_INET) {
|
if (peer->endpoint.addr.sa_family == AF_INET)
|
||||||
if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ENDPOINT, sizeof(peer->endpoint.addr4), &peer->endpoint.addr4))
|
{
|
||||||
goto toobig_peers;
|
if (!mnl_attr_put_check(
|
||||||
} else if (peer->endpoint.addr.sa_family == AF_INET6) {
|
nlh,
|
||||||
if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ENDPOINT, sizeof(peer->endpoint.addr6), &peer->endpoint.addr6))
|
SOCKET_BUFFER_SIZE,
|
||||||
|
WGPEER_A_ENDPOINT,
|
||||||
|
sizeof(peer->endpoint.addr4),
|
||||||
|
&peer->endpoint.addr4))
|
||||||
goto toobig_peers;
|
goto toobig_peers;
|
||||||
}
|
}
|
||||||
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) {
|
else if (peer->endpoint.addr.sa_family == AF_INET6)
|
||||||
if (!mnl_attr_put_u16_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval))
|
{
|
||||||
|
if (!mnl_attr_put_check(
|
||||||
|
nlh,
|
||||||
|
SOCKET_BUFFER_SIZE,
|
||||||
|
WGPEER_A_ENDPOINT,
|
||||||
|
sizeof(peer->endpoint.addr6),
|
||||||
|
&peer->endpoint.addr6))
|
||||||
|
goto toobig_peers;
|
||||||
|
}
|
||||||
|
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL)
|
||||||
|
{
|
||||||
|
if (!mnl_attr_put_u16_check(
|
||||||
|
nlh,
|
||||||
|
SOCKET_BUFFER_SIZE,
|
||||||
|
WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
|
||||||
|
peer->persistent_keepalive_interval))
|
||||||
goto toobig_peers;
|
goto toobig_peers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (peer->flags & WGPEER_HAS_ADVANCED_SECURITY) {
|
if (peer->flags & WGPEER_HAS_ADVANCED_SECURITY)
|
||||||
|
{
|
||||||
if (peer->advanced_security)
|
if (peer->advanced_security)
|
||||||
mnl_attr_put_check(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;
|
flags |= WGPEER_F_HAS_ADVANCED_SECURITY;
|
||||||
}
|
}
|
||||||
if (flags) {
|
if (flags)
|
||||||
|
{
|
||||||
if (!mnl_attr_put_u32_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_FLAGS, flags))
|
if (!mnl_attr_put_u32_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_FLAGS, flags))
|
||||||
goto toobig_peers;
|
goto toobig_peers;
|
||||||
}
|
}
|
||||||
if (peer->first_allowedip) {
|
if (peer->first_allowedip)
|
||||||
|
{
|
||||||
if (!allowedip)
|
if (!allowedip)
|
||||||
allowedip = peer->first_allowedip;
|
allowedip = peer->first_allowedip;
|
||||||
allowedips_nest = 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)
|
if (!allowedips_nest)
|
||||||
goto toobig_allowedips;
|
goto toobig_allowedips;
|
||||||
for (; allowedip; allowedip = allowedip->next_allowedip) {
|
for (; allowedip; allowedip = allowedip->next_allowedip)
|
||||||
|
{
|
||||||
allowedip_nest = mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, 0);
|
allowedip_nest = mnl_attr_nest_start_check(nlh, SOCKET_BUFFER_SIZE, 0);
|
||||||
if (!allowedip_nest)
|
if (!allowedip_nest)
|
||||||
goto toobig_allowedips;
|
goto toobig_allowedips;
|
||||||
if (!mnl_attr_put_u16_check(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;
|
goto toobig_allowedips;
|
||||||
if (allowedip->family == AF_INET) {
|
if (allowedip->family == AF_INET)
|
||||||
if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_IPADDR, sizeof(allowedip->ip4), &allowedip->ip4))
|
{
|
||||||
goto toobig_allowedips;
|
if (!mnl_attr_put_check(
|
||||||
} else if (allowedip->family == AF_INET6) {
|
nlh,
|
||||||
if (!mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_IPADDR, sizeof(allowedip->ip6), &allowedip->ip6))
|
SOCKET_BUFFER_SIZE,
|
||||||
|
WGALLOWEDIP_A_IPADDR,
|
||||||
|
sizeof(allowedip->ip4),
|
||||||
|
&allowedip->ip4))
|
||||||
goto toobig_allowedips;
|
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;
|
goto toobig_allowedips;
|
||||||
mnl_attr_nest_end(nlh, allowedip_nest);
|
mnl_attr_nest_end(nlh, allowedip_nest);
|
||||||
allowedip_nest = NULL;
|
allowedip_nest = NULL;
|
||||||
|
@ -278,12 +343,14 @@ toobig_peers:
|
||||||
mnl_attr_nest_end(nlh, peers_nest);
|
mnl_attr_nest_end(nlh, peers_nest);
|
||||||
goto send;
|
goto send;
|
||||||
send:
|
send:
|
||||||
if (mnlg_socket_send(nlg, nlh) < 0) {
|
if (mnlg_socket_send(nlg, nlh) < 0)
|
||||||
|
{
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (mnlg_socket_recv_run(nlg, NULL, NULL) < 0) {
|
if (mnlg_socket_recv_run(nlg, NULL, NULL) < 0)
|
||||||
|
{
|
||||||
ret = errno ? -errno : -EINVAL;
|
ret = errno ? -errno : -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -300,7 +367,8 @@ static int parse_allowedip(const struct nlattr *attr, void *data)
|
||||||
{
|
{
|
||||||
struct wgallowedip* allowedip = data;
|
struct wgallowedip* allowedip = data;
|
||||||
|
|
||||||
switch (mnl_attr_get_type(attr)) {
|
switch (mnl_attr_get_type(attr))
|
||||||
|
{
|
||||||
case WGALLOWEDIP_A_UNSPEC:
|
case WGALLOWEDIP_A_UNSPEC:
|
||||||
break;
|
break;
|
||||||
case WGALLOWEDIP_A_FAMILY:
|
case WGALLOWEDIP_A_FAMILY:
|
||||||
|
@ -328,20 +396,23 @@ static int parse_allowedips(const struct nlattr *attr, void *data)
|
||||||
struct wgallowedip* new_allowedip = calloc(1, sizeof(*new_allowedip));
|
struct wgallowedip* new_allowedip = calloc(1, sizeof(*new_allowedip));
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!new_allowedip) {
|
if (!new_allowedip)
|
||||||
|
{
|
||||||
perror("calloc");
|
perror("calloc");
|
||||||
return MNL_CB_ERROR;
|
return MNL_CB_ERROR;
|
||||||
}
|
}
|
||||||
if (!peer->first_allowedip)
|
if (!peer->first_allowedip)
|
||||||
peer->first_allowedip = peer->last_allowedip = new_allowedip;
|
peer->first_allowedip = peer->last_allowedip = new_allowedip;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
peer->last_allowedip->next_allowedip = new_allowedip;
|
peer->last_allowedip->next_allowedip = new_allowedip;
|
||||||
peer->last_allowedip = new_allowedip;
|
peer->last_allowedip = new_allowedip;
|
||||||
}
|
}
|
||||||
ret = mnl_attr_parse_nested(attr, parse_allowedip, new_allowedip);
|
ret = mnl_attr_parse_nested(attr, parse_allowedip, new_allowedip);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return ret;
|
return ret;
|
||||||
if (!((new_allowedip->family == AF_INET && new_allowedip->cidr <= 32) || (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_ERROR;
|
||||||
return MNL_CB_OK;
|
return MNL_CB_OK;
|
||||||
}
|
}
|
||||||
|
@ -350,18 +421,25 @@ static int parse_peer(const struct nlattr *attr, void *data)
|
||||||
{
|
{
|
||||||
struct wgpeer* peer = data;
|
struct wgpeer* peer = data;
|
||||||
|
|
||||||
switch (mnl_attr_get_type(attr)) {
|
switch (mnl_attr_get_type(attr))
|
||||||
|
{
|
||||||
case WGPEER_A_UNSPEC:
|
case WGPEER_A_UNSPEC:
|
||||||
break;
|
break;
|
||||||
case WGPEER_A_PUBLIC_KEY:
|
case WGPEER_A_PUBLIC_KEY:
|
||||||
if (mnl_attr_get_payload_len(attr) == sizeof(peer->public_key)) {
|
if (mnl_attr_get_payload_len(attr) == sizeof(peer->public_key))
|
||||||
memcpy(peer->public_key, mnl_attr_get_payload(attr), sizeof(peer->public_key));
|
{
|
||||||
|
memcpy(
|
||||||
|
peer->public_key, mnl_attr_get_payload(attr), sizeof(peer->public_key));
|
||||||
peer->flags |= WGPEER_HAS_PUBLIC_KEY;
|
peer->flags |= WGPEER_HAS_PUBLIC_KEY;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WGPEER_A_PRESHARED_KEY:
|
case WGPEER_A_PRESHARED_KEY:
|
||||||
if (mnl_attr_get_payload_len(attr) == sizeof(peer->preshared_key)) {
|
if (mnl_attr_get_payload_len(attr) == sizeof(peer->preshared_key))
|
||||||
memcpy(peer->preshared_key, mnl_attr_get_payload(attr), sizeof(peer->preshared_key));
|
{
|
||||||
|
memcpy(
|
||||||
|
peer->preshared_key,
|
||||||
|
mnl_attr_get_payload(attr),
|
||||||
|
sizeof(peer->preshared_key));
|
||||||
if (!key_is_zero(peer->preshared_key))
|
if (!key_is_zero(peer->preshared_key))
|
||||||
peer->flags |= WGPEER_HAS_PRESHARED_KEY;
|
peer->flags |= WGPEER_HAS_PRESHARED_KEY;
|
||||||
}
|
}
|
||||||
|
@ -372,9 +450,12 @@ static int parse_peer(const struct nlattr *attr, void *data)
|
||||||
if (mnl_attr_get_payload_len(attr) < sizeof(*addr))
|
if (mnl_attr_get_payload_len(attr) < sizeof(*addr))
|
||||||
break;
|
break;
|
||||||
addr = mnl_attr_get_payload(attr);
|
addr = mnl_attr_get_payload(attr);
|
||||||
if (addr->sa_family == AF_INET && 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));
|
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));
|
memcpy(&peer->endpoint.addr6, addr, sizeof(peer->endpoint.addr6));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -384,7 +465,10 @@ static int parse_peer(const struct nlattr *attr, void *data)
|
||||||
break;
|
break;
|
||||||
case WGPEER_A_LAST_HANDSHAKE_TIME:
|
case WGPEER_A_LAST_HANDSHAKE_TIME:
|
||||||
if (mnl_attr_get_payload_len(attr) == sizeof(peer->last_handshake_time))
|
if (mnl_attr_get_payload_len(attr) == sizeof(peer->last_handshake_time))
|
||||||
memcpy(&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;
|
break;
|
||||||
case WGPEER_A_RX_BYTES:
|
case WGPEER_A_RX_BYTES:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_U64))
|
if (!mnl_attr_validate(attr, MNL_TYPE_U64))
|
||||||
|
@ -395,20 +479,25 @@ static int parse_peer(const struct nlattr *attr, void *data)
|
||||||
peer->tx_bytes = mnl_attr_get_u64(attr);
|
peer->tx_bytes = mnl_attr_get_u64(attr);
|
||||||
break;
|
break;
|
||||||
case WGPEER_A_FLAGS:
|
case WGPEER_A_FLAGS:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_U32)) {
|
if (!mnl_attr_validate(attr, MNL_TYPE_U32))
|
||||||
|
{
|
||||||
uint32_t flags = mnl_attr_get_u32(attr);
|
uint32_t flags = mnl_attr_get_u32(attr);
|
||||||
|
|
||||||
if (flags & WGPEER_F_HAS_ADVANCED_SECURITY && !(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->flags |= WGPEER_HAS_ADVANCED_SECURITY;
|
||||||
peer->advanced_security = false;
|
peer->advanced_security = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WGPEER_A_ADVANCED_SECURITY:
|
case WGPEER_A_ADVANCED_SECURITY:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_FLAG)) {
|
if (!mnl_attr_validate(attr, MNL_TYPE_FLAG))
|
||||||
|
{
|
||||||
peer->advanced_security = true;
|
peer->advanced_security = true;
|
||||||
|
|
||||||
if (!(peer->flags & WGPEER_HAS_ADVANCED_SECURITY)) {
|
if (!(peer->flags & WGPEER_HAS_ADVANCED_SECURITY))
|
||||||
|
{
|
||||||
peer->flags |= WGPEER_HAS_ADVANCED_SECURITY;
|
peer->flags |= WGPEER_HAS_ADVANCED_SECURITY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -426,13 +515,15 @@ static int parse_peers(const struct nlattr *attr, void *data)
|
||||||
struct wgpeer* new_peer = calloc(1, sizeof(*new_peer));
|
struct wgpeer* new_peer = calloc(1, sizeof(*new_peer));
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!new_peer) {
|
if (!new_peer)
|
||||||
|
{
|
||||||
perror("calloc");
|
perror("calloc");
|
||||||
return MNL_CB_ERROR;
|
return MNL_CB_ERROR;
|
||||||
}
|
}
|
||||||
if (!device->first_peer)
|
if (!device->first_peer)
|
||||||
device->first_peer = device->last_peer = new_peer;
|
device->first_peer = device->last_peer = new_peer;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
device->last_peer->next_peer = new_peer;
|
device->last_peer->next_peer = new_peer;
|
||||||
device->last_peer = new_peer;
|
device->last_peer = new_peer;
|
||||||
}
|
}
|
||||||
|
@ -448,7 +539,8 @@ static int parse_device(const struct nlattr *attr, void *data)
|
||||||
{
|
{
|
||||||
struct wgdevice* device = data;
|
struct wgdevice* device = data;
|
||||||
|
|
||||||
switch (mnl_attr_get_type(attr)) {
|
switch (mnl_attr_get_type(attr))
|
||||||
|
{
|
||||||
case WGDEVICE_A_UNSPEC:
|
case WGDEVICE_A_UNSPEC:
|
||||||
break;
|
break;
|
||||||
case WGDEVICE_A_IFINDEX:
|
case WGDEVICE_A_IFINDEX:
|
||||||
|
@ -456,20 +548,29 @@ static int parse_device(const struct nlattr *attr, void *data)
|
||||||
device->ifindex = mnl_attr_get_u32(attr);
|
device->ifindex = mnl_attr_get_u32(attr);
|
||||||
break;
|
break;
|
||||||
case WGDEVICE_A_IFNAME:
|
case WGDEVICE_A_IFNAME:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_STRING)) {
|
if (!mnl_attr_validate(attr, MNL_TYPE_STRING))
|
||||||
|
{
|
||||||
strncpy(device->name, mnl_attr_get_str(attr), sizeof(device->name) - 1);
|
strncpy(device->name, mnl_attr_get_str(attr), sizeof(device->name) - 1);
|
||||||
device->name[sizeof(device->name) - 1] = '\0';
|
device->name[sizeof(device->name) - 1] = '\0';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WGDEVICE_A_PRIVATE_KEY:
|
case WGDEVICE_A_PRIVATE_KEY:
|
||||||
if (mnl_attr_get_payload_len(attr) == sizeof(device->private_key)) {
|
if (mnl_attr_get_payload_len(attr) == sizeof(device->private_key))
|
||||||
memcpy(device->private_key, mnl_attr_get_payload(attr), sizeof(device->private_key));
|
{
|
||||||
|
memcpy(
|
||||||
|
device->private_key,
|
||||||
|
mnl_attr_get_payload(attr),
|
||||||
|
sizeof(device->private_key));
|
||||||
device->flags |= WGDEVICE_HAS_PRIVATE_KEY;
|
device->flags |= WGDEVICE_HAS_PRIVATE_KEY;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WGDEVICE_A_PUBLIC_KEY:
|
case WGDEVICE_A_PUBLIC_KEY:
|
||||||
if (mnl_attr_get_payload_len(attr) == sizeof(device->public_key)) {
|
if (mnl_attr_get_payload_len(attr) == sizeof(device->public_key))
|
||||||
memcpy(device->public_key, mnl_attr_get_payload(attr), sizeof(device->public_key));
|
{
|
||||||
|
memcpy(
|
||||||
|
device->public_key,
|
||||||
|
mnl_attr_get_payload(attr),
|
||||||
|
sizeof(device->public_key));
|
||||||
device->flags |= WGDEVICE_HAS_PUBLIC_KEY;
|
device->flags |= WGDEVICE_HAS_PUBLIC_KEY;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -484,58 +585,113 @@ static int parse_device(const struct nlattr *attr, void *data)
|
||||||
case WGDEVICE_A_PEERS:
|
case WGDEVICE_A_PEERS:
|
||||||
return mnl_attr_parse_nested(attr, parse_peers, device);
|
return mnl_attr_parse_nested(attr, parse_peers, device);
|
||||||
case WGDEVICE_A_JC:
|
case WGDEVICE_A_JC:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_U16)) {
|
if (!mnl_attr_validate(attr, MNL_TYPE_U16))
|
||||||
|
{
|
||||||
device->junk_packet_count = mnl_attr_get_u16(attr);
|
device->junk_packet_count = mnl_attr_get_u16(attr);
|
||||||
device->flags |= WGDEVICE_HAS_JC;
|
device->flags |= WGDEVICE_HAS_JC;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WGDEVICE_A_JMIN:
|
case WGDEVICE_A_JMIN:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_U16)) {
|
if (!mnl_attr_validate(attr, MNL_TYPE_U16))
|
||||||
|
{
|
||||||
device->junk_packet_min_size = mnl_attr_get_u16(attr);
|
device->junk_packet_min_size = mnl_attr_get_u16(attr);
|
||||||
device->flags |= WGDEVICE_HAS_JMIN;
|
device->flags |= WGDEVICE_HAS_JMIN;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WGDEVICE_A_JMAX:
|
case WGDEVICE_A_JMAX:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_U16)) {
|
if (!mnl_attr_validate(attr, MNL_TYPE_U16))
|
||||||
|
{
|
||||||
device->junk_packet_max_size = mnl_attr_get_u16(attr);
|
device->junk_packet_max_size = mnl_attr_get_u16(attr);
|
||||||
device->flags |= WGDEVICE_HAS_JMAX;
|
device->flags |= WGDEVICE_HAS_JMAX;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WGDEVICE_A_S1:
|
case WGDEVICE_A_S1:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_U16)) {
|
if (!mnl_attr_validate(attr, MNL_TYPE_U16))
|
||||||
|
{
|
||||||
device->init_packet_junk_size = mnl_attr_get_u16(attr);
|
device->init_packet_junk_size = mnl_attr_get_u16(attr);
|
||||||
device->flags |= WGDEVICE_HAS_S1;
|
device->flags |= WGDEVICE_HAS_S1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WGDEVICE_A_S2:
|
case WGDEVICE_A_S2:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_U16)) {
|
if (!mnl_attr_validate(attr, MNL_TYPE_U16))
|
||||||
|
{
|
||||||
device->response_packet_junk_size = mnl_attr_get_u16(attr);
|
device->response_packet_junk_size = mnl_attr_get_u16(attr);
|
||||||
device->flags |= WGDEVICE_HAS_S2;
|
device->flags |= WGDEVICE_HAS_S2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WGDEVICE_A_H1:
|
case WGDEVICE_A_H1:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_U32)) {
|
if (!mnl_attr_validate(attr, MNL_TYPE_U32))
|
||||||
|
{
|
||||||
device->init_packet_magic_header = mnl_attr_get_u32(attr);
|
device->init_packet_magic_header = mnl_attr_get_u32(attr);
|
||||||
device->flags |= WGDEVICE_HAS_H1;
|
device->flags |= WGDEVICE_HAS_H1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WGDEVICE_A_H2:
|
case WGDEVICE_A_H2:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_U32)) {
|
if (!mnl_attr_validate(attr, MNL_TYPE_U32))
|
||||||
|
{
|
||||||
device->response_packet_magic_header = mnl_attr_get_u32(attr);
|
device->response_packet_magic_header = mnl_attr_get_u32(attr);
|
||||||
device->flags |= WGDEVICE_HAS_H2;
|
device->flags |= WGDEVICE_HAS_H2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WGDEVICE_A_H3:
|
case WGDEVICE_A_H3:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_U32)) {
|
if (!mnl_attr_validate(attr, MNL_TYPE_U32))
|
||||||
|
{
|
||||||
device->underload_packet_magic_header = mnl_attr_get_u32(attr);
|
device->underload_packet_magic_header = mnl_attr_get_u32(attr);
|
||||||
device->flags |= WGDEVICE_HAS_H3;
|
device->flags |= WGDEVICE_HAS_H3;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WGDEVICE_A_H4:
|
case WGDEVICE_A_H4:
|
||||||
if (!mnl_attr_validate(attr, MNL_TYPE_U32)) {
|
if (!mnl_attr_validate(attr, MNL_TYPE_U32))
|
||||||
|
{
|
||||||
device->transport_packet_magic_header = mnl_attr_get_u32(attr);
|
device->transport_packet_magic_header = mnl_attr_get_u32(attr);
|
||||||
device->flags |= WGDEVICE_HAS_H4;
|
device->flags |= WGDEVICE_HAS_H4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,15 +707,21 @@ static void coalesce_peers(struct wgdevice *device)
|
||||||
{
|
{
|
||||||
struct wgpeer *old_next_peer, *peer = device->first_peer;
|
struct wgpeer *old_next_peer, *peer = device->first_peer;
|
||||||
|
|
||||||
while (peer && peer->next_peer) {
|
while (peer && peer->next_peer)
|
||||||
if (memcmp(peer->public_key, peer->next_peer->public_key, sizeof(peer->public_key))) {
|
{
|
||||||
|
if (memcmp(
|
||||||
|
peer->public_key, peer->next_peer->public_key, sizeof(peer->public_key)))
|
||||||
|
{
|
||||||
peer = peer->next_peer;
|
peer = peer->next_peer;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!peer->first_allowedip) {
|
if (!peer->first_allowedip)
|
||||||
|
{
|
||||||
peer->first_allowedip = peer->next_peer->first_allowedip;
|
peer->first_allowedip = peer->next_peer->first_allowedip;
|
||||||
peer->last_allowedip = peer->next_peer->last_allowedip;
|
peer->last_allowedip = peer->next_peer->last_allowedip;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
peer->last_allowedip->next_allowedip = peer->next_peer->first_allowedip;
|
peer->last_allowedip->next_allowedip = peer->next_peer->first_allowedip;
|
||||||
peer->last_allowedip = peer->next_peer->last_allowedip;
|
peer->last_allowedip = peer->next_peer->last_allowedip;
|
||||||
}
|
}
|
||||||
|
@ -576,7 +738,8 @@ static int kernel_get_device(struct wgdevice **device, const char *iface)
|
||||||
struct mnlg_socket* nlg;
|
struct mnlg_socket* nlg;
|
||||||
|
|
||||||
/* libmnl doesn't check the buffer size, so enforce that before using. */
|
/* libmnl doesn't check the buffer size, so enforce that before using. */
|
||||||
if (strlen(iface) >= IFNAMSIZ) {
|
if (strlen(iface) >= IFNAMSIZ)
|
||||||
|
{
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
||||||
}
|
}
|
||||||
|
@ -588,20 +751,24 @@ try_again:
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
nlg = mnlg_socket_open(WG_GENL_NAME, WG_GENL_VERSION);
|
nlg = mnlg_socket_open(WG_GENL_NAME, WG_GENL_VERSION);
|
||||||
if (!nlg) {
|
if (!nlg)
|
||||||
|
{
|
||||||
free_wgdevice(*device);
|
free_wgdevice(*device);
|
||||||
*device = NULL;
|
*device = NULL;
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
nlh = 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);
|
mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, iface);
|
||||||
if (mnlg_socket_send(nlg, nlh) < 0) {
|
if (mnlg_socket_send(nlg, nlh) < 0)
|
||||||
|
{
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (mnlg_socket_recv_run(nlg, read_device_cb, *device) < 0) {
|
if (mnlg_socket_recv_run(nlg, read_device_cb, *device) < 0)
|
||||||
|
{
|
||||||
ret = errno ? -errno : -EINVAL;
|
ret = errno ? -errno : -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -610,7 +777,8 @@ try_again:
|
||||||
out:
|
out:
|
||||||
if (nlg)
|
if (nlg)
|
||||||
mnlg_socket_close(nlg);
|
mnlg_socket_close(nlg);
|
||||||
if (ret) {
|
if (ret)
|
||||||
|
{
|
||||||
free_wgdevice(*device);
|
free_wgdevice(*device);
|
||||||
if (ret == -EINTR)
|
if (ret == -EINTR)
|
||||||
goto try_again;
|
goto try_again;
|
||||||
|
|
|
@ -65,6 +65,25 @@ int showconf_main(int argc, const char *argv[])
|
||||||
if (device->flags & WGDEVICE_HAS_H4)
|
if (device->flags & WGDEVICE_HAS_H4)
|
||||||
printf("H4 = %u\n", device->transport_packet_magic_header);
|
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");
|
printf("\n");
|
||||||
for_each_wgpeer(device, peer) {
|
for_each_wgpeer(device, peer) {
|
||||||
key_to_base64(base64, peer->public_key);
|
key_to_base64(base64, peer->public_key);
|
||||||
|
|
|
@ -191,6 +191,15 @@ enum wgdevice_attribute {
|
||||||
WGDEVICE_A_H2,
|
WGDEVICE_A_H2,
|
||||||
WGDEVICE_A_H3,
|
WGDEVICE_A_H3,
|
||||||
WGDEVICE_A_H4,
|
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_PEER,
|
||||||
__WGDEVICE_A_LAST
|
__WGDEVICE_A_LAST
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue