[RFC PATCH v2 2/2] platform: add support for WireGuard links
- From: Javier Arteaga <jarteaga jbeta is>
- To: Thomas Haller <thaller redhat com>
- Cc: "Jason A. Donenfeld" <Jason zx2c4 com>, Maximilian Moser <e1326252 student tuwien ac at>, networkmanager-list gnome org, Javier Arteaga <jarteaga jbeta is>
- Subject: [RFC PATCH v2 2/2] platform: add support for WireGuard links
- Date: Thu, 29 Mar 2018 21:00:29 +0100
Add support for a new wireguard link type to the platform code. For now
this only covers querying existing links via Generic Netlink and parsing
them into platform objects.
[TODO: detect wireguard interface changes and invalidate nmp cache]
---
libnm-core/nm-core-types-internal.h | 31 ++++
src/nm-types.h | 2 +
src/platform/nm-linux-platform.c | 302 ++++++++++++++++++++++++++++++++++++
src/platform/nm-platform.c | 133 ++++++++++++++++
src/platform/nm-platform.h | 19 +++
src/platform/nmp-object.c | 95 ++++++++++++
src/platform/nmp-object.h | 9 ++
7 files changed, 591 insertions(+)
diff --git a/libnm-core/nm-core-types-internal.h b/libnm-core/nm-core-types-internal.h
index 4d43aaf45..1c4d74ca9 100644
--- a/libnm-core/nm-core-types-internal.h
+++ b/libnm-core/nm-core-types-internal.h
@@ -26,11 +26,42 @@
#error Cannot use this header.
#endif
+#include "nm-utils/c-list.h"
+
typedef struct {
guint32 from;
guint32 to;
} NMVlanQosMapping;
+typedef struct {
+ guint16 family;
+ union {
+ struct in_addr ip4;
+ struct in6_addr ip6;
+ } ip;
+ guint8 cidr;
+
+ CList allowedips_lst;
+} NMWireguardAllowedIP;
+
+#define NM_WG_PUBLIC_KEY_LEN 32
+#define NM_WG_SYMMETRIC_KEY_LEN 32
+
+typedef struct {
+ guint8 public_key[NM_WG_PUBLIC_KEY_LEN];
+ guint8 preshared_key[NM_WG_SYMMETRIC_KEY_LEN];
+ union {
+ struct sockaddr addr;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ } endpoint;
+ struct timespec last_handshake_time;
+ guint64 rx_bytes, tx_bytes;
+ guint16 persistent_keepalive_interval;
+
+ CList allowedips_lst_head;
+} NMWireguardPeer;
+
#define _NM_IP_TUNNEL_FLAG_ALL_IP6TNL \
( NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT \
| NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS \
diff --git a/src/nm-types.h b/src/nm-types.h
index 487b001ec..95248ab19 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -162,6 +162,7 @@ typedef enum {
NM_LINK_TYPE_VETH,
NM_LINK_TYPE_VLAN,
NM_LINK_TYPE_VXLAN,
+ NM_LINK_TYPE_WIREGUARD,
/* Software types with slaves */
NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000,
@@ -194,6 +195,7 @@ typedef enum {
NMP_OBJECT_TYPE_LNK_TUN,
NMP_OBJECT_TYPE_LNK_VLAN,
NMP_OBJECT_TYPE_LNK_VXLAN,
+ NMP_OBJECT_TYPE_LNK_WIREGUARD,
__NMP_OBJECT_TYPE_LAST,
NMP_OBJECT_TYPE_MAX = __NMP_OBJECT_TYPE_LAST - 1,
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index b8d252070..13546cbdb 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -173,6 +173,40 @@ G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1));
/*****************************************************************************/
+#define WG_CMD_GET_DEVICE 0
+#define WG_CMD_SET_DEVICE 1
+
+#define IFLA_WG_DEVICE_UNSPEC 0
+#define IFLA_WG_DEVICE_IFINDEX 1
+#define IFLA_WG_DEVICE_IFNAME 2
+#define IFLA_WG_DEVICE_PRIVATE_KEY 3
+#define IFLA_WG_DEVICE_PUBLIC_KEY 4
+#define IFLA_WG_DEVICE_FLAGS 5
+#define IFLA_WG_DEVICE_LISTEN_PORT 6
+#define IFLA_WG_DEVICE_FWMARK 7
+#define IFLA_WG_DEVICE_PEERS 8
+#define __IFLA_WG_DEVICE_MAX 9
+
+#define IFLA_WG_PEER_UNSPEC 0
+#define IFLA_WG_PEER_PUBLIC_KEY 1
+#define IFLA_WG_PEER_PRESHARED_KEY 2
+#define IFLA_WG_PEER_FLAGS 3
+#define IFLA_WG_PEER_ENDPOINT 4
+#define IFLA_WG_PEER_PERSISTENT_KEEPALIVE_INTERVAL 5
+#define IFLA_WG_PEER_LAST_HANDSHAKE_TIME 6
+#define IFLA_WG_PEER_RX_BYTES 7
+#define IFLA_WG_PEER_TX_BYTES 8
+#define IFLA_WG_PEER_ALLOWEDIPS 9
+#define __IFLA_WG_PEER_MAX 10
+
+#define IFLA_WG_ALLOWEDIP_UNSPEC 0
+#define IFLA_WG_ALLOWEDIP_FAMILY 1
+#define IFLA_WG_ALLOWEDIP_IPADDR 2
+#define IFLA_WG_ALLOWEDIP_CIDR_MASK 3
+#define __IFLA_WG_ALLOWEDIP_MAX 4
+
+/*****************************************************************************/
+
#define _NMLOG_PREFIX_NAME "platform-linux"
#define _NMLOG_DOMAIN LOGD_PLATFORM
#define _NMLOG2_DOMAIN LOGD_PLATFORM
@@ -554,6 +588,7 @@ static const LinkDesc linktypes[] = {
{ NM_LINK_TYPE_VETH, "veth", "veth", NULL },
{ NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" },
{ NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" },
+ { NM_LINK_TYPE_WIREGUARD, "wireguard", "wireguard", "wireguard" },
{ NM_LINK_TYPE_BRIDGE, "bridge", "bridge", "bridge" },
{ NM_LINK_TYPE_BOND, "bond", "bond", "bond" },
@@ -1548,6 +1583,40 @@ _parse_lnk_vlan (const char *kind, struct nlattr *info_data)
/*****************************************************************************/
+static void
+_wireguard_peer_free (gpointer data)
+{
+ NMWireguardPeer *peer = data;
+ NMWireguardAllowedIP *allowedip;
+
+ c_list_for_each_entry (allowedip, &peer->allowedips_lst_head, allowedips_lst)
+ g_free (allowedip);
+ g_free (peer);
+}
+
+static NMPObject *
+_parse_lnk_wireguard (const char *kind)
+{
+ nm_auto_nmpobj NMPObject *obj = NULL;
+ NMPObject *obj_result;
+ NMPObjectLnkWireguard *wgobj;
+
+ if (!nm_streq0 (kind, "wireguard"))
+ return NULL;
+
+ obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_WIREGUARD, NULL);
+ wgobj = &obj->_lnk_wireguard;
+
+ wgobj->peers = g_ptr_array_sized_new (1);
+ g_ptr_array_set_free_func (wgobj->peers, _wireguard_peer_free);
+
+ obj_result = obj;
+ obj = NULL;
+ return obj_result;
+}
+
+/*****************************************************************************/
+
/* The installed kernel headers might not have VXLAN stuff at all, or
* they might have the original properties, but not PORT, GROUP6, or LOCAL6.
* So until we depend on kernel >= 3.11, we just ignore the actual enum
@@ -1875,6 +1944,9 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
case NM_LINK_TYPE_VXLAN:
lnk_data = _parse_lnk_vxlan (nl_info_kind, nl_info_data);
break;
+ case NM_LINK_TYPE_WIREGUARD:
+ lnk_data = _parse_lnk_wireguard (nl_info_kind);
+ break;
default:
lnk_data_complete_from_cache = FALSE;
break;
@@ -1914,6 +1986,15 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
obj->link.tx_packets = link_cached->link.tx_packets;
obj->link.tx_bytes = link_cached->link.tx_bytes;
}
+ } else {
+ /* TODO: we have no mechanism to detect changes to cached WireGuard
+ * interfaces yet, so any changes will not be picked up. */
+ switch (obj->link.type) {
+ case NM_LINK_TYPE_WIREGUARD:
+ nm_platform_wireguard_get_link_properties (platform, &obj->link, lnk_data);
+ default:
+ break;
+ }
}
}
@@ -2982,6 +3063,8 @@ typedef struct {
GIOChannel *event_channel;
guint event_id;
+ struct nl_sock *genlh;
+
bool pruning[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM];
bool sysctl_get_warned;
@@ -3006,6 +3089,8 @@ typedef struct {
} delayed_action;
GHashTable *wifi_data;
+
+ int wireguard_family_id;
} NMLinuxPlatformPrivate;
struct _NMLinuxPlatform {
@@ -6151,6 +6236,211 @@ mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len)
/*****************************************************************************/
+static int
+_wireguard_allowedip_from_nla (struct nlattr *allowedip_attr, NMWireguardAllowedIP *allowedip)
+{
+ static const struct nla_policy allowedip_policy[__IFLA_WG_ALLOWEDIP_MAX] = {
+ [IFLA_WG_ALLOWEDIP_FAMILY] = { .type = NLA_U16 },
+ [IFLA_WG_ALLOWEDIP_IPADDR] = { .minlen = sizeof (struct in_addr) },
+ [IFLA_WG_ALLOWEDIP_CIDR_MASK] = { .type = NLA_U8 },
+ };
+ struct nlattr *tba[__IFLA_WG_ALLOWEDIP_MAX];
+ int addr_len;
+ int ret;
+
+ ret = nla_parse_nested (tba, __IFLA_WG_ALLOWEDIP_MAX, allowedip_attr, allowedip_policy);
+ if (ret)
+ goto errout;
+
+ if (tba[IFLA_WG_ALLOWEDIP_FAMILY])
+ allowedip->family = nla_get_u16 (tba[IFLA_WG_ALLOWEDIP_FAMILY]);
+
+ if (allowedip->family == AF_INET)
+ addr_len = sizeof (in_addr_t);
+ else if (allowedip->family == AF_INET6)
+ addr_len = sizeof (struct in6_addr);
+ else {
+ ret = -EAFNOSUPPORT;
+ goto errout;
+ }
+
+ ret = -EMSGSIZE;
+ _check_addr_or_errout (tba, IFLA_WG_ALLOWEDIP_IPADDR, addr_len);
+ if (tba[IFLA_WG_ALLOWEDIP_IPADDR])
+ memcpy (&allowedip->ip, nla_data (tba[IFLA_WG_ALLOWEDIP_IPADDR]), addr_len);
+
+ if (tba[IFLA_WG_ALLOWEDIP_CIDR_MASK])
+ allowedip->cidr = nla_get_u8 (tba[IFLA_WG_ALLOWEDIP_CIDR_MASK]);
+
+ ret = 0;
+errout:
+ return ret;
+}
+
+static int
+_wireguard_peer_from_nla (struct nlattr *peer_attr, NMWireguardPeer *peer)
+{
+ static const struct nla_policy peer_policy[__IFLA_WG_PEER_MAX] = {
+ [IFLA_WG_PEER_PUBLIC_KEY] = { .minlen = NM_WG_PUBLIC_KEY_LEN },
+ [IFLA_WG_PEER_PRESHARED_KEY] = { },
+ [IFLA_WG_PEER_FLAGS] = { .type = NLA_U32 },
+ [IFLA_WG_PEER_ENDPOINT] = { },
+ [IFLA_WG_PEER_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NLA_U16 },
+ [IFLA_WG_PEER_LAST_HANDSHAKE_TIME] = { },
+ [IFLA_WG_PEER_RX_BYTES] = { .type = NLA_U64 },
+ [IFLA_WG_PEER_TX_BYTES] = { .type = NLA_U64 },
+ [IFLA_WG_PEER_ALLOWEDIPS] = { .type = NLA_NESTED },
+ };
+ struct nlattr *tbp[__IFLA_WG_PEER_MAX];
+ int ret;
+
+ if (nla_parse_nested (tbp, __IFLA_WG_PEER_MAX, peer_attr, peer_policy)) {
+ ret = -EBADMSG;
+ goto errout;
+ }
+
+ if (tbp[IFLA_WG_PEER_PUBLIC_KEY])
+ memcpy (&peer->public_key, nla_data (tbp[IFLA_WG_PEER_PUBLIC_KEY]), sizeof
(peer->public_key));
+ if (tbp[IFLA_WG_PEER_PRESHARED_KEY])
+ memcpy (&peer->preshared_key, nla_data (tbp[IFLA_WG_PEER_PRESHARED_KEY]), sizeof
(peer->preshared_key));
+ if (tbp[IFLA_WG_PEER_ENDPOINT])
+ memcpy (&peer->endpoint, nla_data (tbp[IFLA_WG_PEER_ENDPOINT]), sizeof (peer->endpoint));
+ if (tbp[IFLA_WG_PEER_PERSISTENT_KEEPALIVE_INTERVAL])
+ peer->persistent_keepalive_interval = nla_get_u64
(tbp[IFLA_WG_PEER_PERSISTENT_KEEPALIVE_INTERVAL]);
+ if (tbp[IFLA_WG_PEER_LAST_HANDSHAKE_TIME])
+ memcpy (&peer->last_handshake_time, nla_data (tbp[IFLA_WG_PEER_LAST_HANDSHAKE_TIME]), sizeof
(peer->last_handshake_time));
+ if (tbp[IFLA_WG_PEER_RX_BYTES])
+ peer->rx_bytes = nla_get_u64 (tbp[IFLA_WG_PEER_RX_BYTES]);
+ if (tbp[IFLA_WG_PEER_TX_BYTES])
+ peer->tx_bytes = nla_get_u64 (tbp[IFLA_WG_PEER_TX_BYTES]);
+
+ if (tbp[IFLA_WG_PEER_ALLOWEDIPS]) {
+ struct nlattr *allowedip_attr;
+ int rem;
+
+ c_list_init (&peer->allowedips_lst_head);
+ nla_for_each_nested (allowedip_attr, tbp[IFLA_WG_PEER_ALLOWEDIPS], rem) {
+ NMWireguardAllowedIP *allowedip = g_new0(NMWireguardAllowedIP, 1);
+ ret = _wireguard_allowedip_from_nla (allowedip_attr, allowedip);
+ if (ret)
+ goto errout;
+ c_list_link_tail (&peer->allowedips_lst_head, &allowedip->allowedips_lst);
+ }
+ }
+
+ ret = 0;
+errout:
+ return ret;
+}
+
+static int
+_wireguard_read_device_cb (struct nl_msg *msg, void *arg)
+{
+ static const struct nla_policy device_policy[__IFLA_WG_DEVICE_MAX] = {
+ [IFLA_WG_DEVICE_IFINDEX] = { .type = NLA_U32 },
+ [IFLA_WG_DEVICE_IFNAME] = { .type = NLA_NUL_STRING, .maxlen = IFNAMSIZ },
+ [IFLA_WG_DEVICE_PRIVATE_KEY] = { },
+ [IFLA_WG_DEVICE_PUBLIC_KEY] = { },
+ [IFLA_WG_DEVICE_FLAGS] = { .type = NLA_U32 },
+ [IFLA_WG_DEVICE_LISTEN_PORT] = { .type = NLA_U16 },
+ [IFLA_WG_DEVICE_FWMARK] = { .type = NLA_U32 },
+ [IFLA_WG_DEVICE_PEERS] = { .type = NLA_NESTED },
+ };
+ struct nlattr *tbd[__IFLA_WG_DEVICE_MAX];
+ NMPObject *obj = arg;
+ NMPlatformLnkWireguard *props = &obj->lnk_wireguard;
+ NMPObjectLnkWireguard *wgobj = &obj->_lnk_wireguard;
+ struct nlmsghdr *nlh = nlmsg_hdr (msg);
+ int ret;
+
+ ret = genlmsg_parse (nlh, 0, tbd, __IFLA_WG_DEVICE_MAX - 1, device_policy);
+ if (ret)
+ goto errout;
+
+ if (tbd[IFLA_WG_DEVICE_PRIVATE_KEY])
+ nla_memcpy (props->private_key, tbd[IFLA_WG_DEVICE_PRIVATE_KEY], sizeof (props->private_key));
+ if (tbd[IFLA_WG_DEVICE_PUBLIC_KEY])
+ nla_memcpy (props->public_key, tbd[IFLA_WG_DEVICE_PUBLIC_KEY], sizeof (props->public_key));
+ if (tbd[IFLA_WG_DEVICE_LISTEN_PORT])
+ props->listen_port = nla_get_u16 (tbd[IFLA_WG_DEVICE_LISTEN_PORT]);
+ if (tbd[IFLA_WG_DEVICE_FWMARK])
+ props->fwmark = nla_get_u32 (tbd[IFLA_WG_DEVICE_FWMARK]);
+
+ if (tbd[IFLA_WG_DEVICE_PEERS]) {
+ struct nlattr *peer_attr;
+ int rem;
+
+ nla_for_each_nested (peer_attr, tbd[IFLA_WG_DEVICE_PEERS], rem) {
+ NMWireguardPeer *peer = g_new0(NMWireguardPeer, 1);
+ ret = _wireguard_peer_from_nla (peer_attr, peer);
+ if (ret)
+ goto errout;
+ g_ptr_array_add (wgobj->peers, peer);
+ }
+ }
+
+ return NL_OK;
+errout:
+ return NL_SKIP;
+}
+
+static void
+_wireguard_coalesce_peers (GPtrArray *peers)
+{
+ gsize i = 0;
+
+ while (i + 1 < peers->len) {
+ NMWireguardPeer *pa = g_ptr_array_index(peers, i);
+ NMWireguardPeer *pb = g_ptr_array_index(peers, i + 1);
+
+ if (memcmp(pa->public_key, pb->public_key, sizeof (pa->public_key))) {
+ i++;
+ continue;
+ }
+
+ c_list_splice (&pa->allowedips_lst_head, &pb->allowedips_lst_head);
+ g_ptr_array_remove_index_fast (peers, i + 1);
+ }
+}
+
+static gboolean
+wireguard_get_link_properties (NMPlatform *platform, const NMPlatformLink *link, NMPObject *obj)
+{
+ NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+ nm_auto_nlmsg struct nl_msg *msg = NULL;
+ struct nl_cb cb = {
+ .valid_cb = _wireguard_read_device_cb,
+ .valid_arg = obj,
+ };
+
+ g_return_val_if_fail (priv->wireguard_family_id, FALSE);
+
+ msg = nlmsg_alloc ();
+ if (!msg)
+ return FALSE;
+
+ if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, priv->wireguard_family_id,
+ 0, NLM_F_DUMP, WG_CMD_GET_DEVICE, 1))
+ return FALSE;
+
+ NLA_PUT_U32 (msg, IFLA_WG_DEVICE_IFINDEX, link->ifindex);
+
+ if (nl_send_auto (priv->genlh, msg) < 0)
+ return FALSE;
+
+ if (nl_recvmsgs (priv->genlh, &cb) < 0)
+ return FALSE;
+
+ _wireguard_coalesce_peers(obj->_lnk_wireguard.peers);
+
+ return TRUE;
+
+nla_put_failure:
+ return FALSE;
+}
+
+/*****************************************************************************/
+
static gboolean
link_get_wake_on_lan (NMPlatform *platform, int ifindex)
{
@@ -7066,6 +7356,16 @@ constructed (GObject *_object)
(EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS),
event_handler, platform);
+ priv->genlh = nl_socket_alloc ();
+ g_assert (priv->genlh);
+
+ nle = nl_connect (priv->genlh, NETLINK_GENERIC);
+ g_assert (!nle);
+ _LOGD ("Generic netlink socket established: port=%u, fd=%d", nl_socket_get_local_port (priv->genlh),
nl_socket_get_fd (priv->genlh));
+
+ priv->wireguard_family_id = genl_ctrl_resolve (priv->genlh, "wireguard");
+ _LOG2D ("kernel-support: wireguard: %s", priv->wireguard_family_id ? "detected" : "not detected");
+
/* complete construction of the GObject instance before populating the cache. */
G_OBJECT_CLASS (nm_linux_platform_parent_class)->constructed (_object);
@@ -7227,6 +7527,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->mesh_set_channel = mesh_set_channel;
platform_class->mesh_set_ssid = mesh_set_ssid;
+ platform_class->wireguard_get_link_properties = wireguard_get_link_properties;
+
platform_class->link_gre_add = link_gre_add;
platform_class->link_ip6tnl_add = link_ip6tnl_add;
platform_class->link_macsec_add = link_macsec_add;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index dac0a5ff9..f430c2600 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -27,6 +27,8 @@
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
#include <string.h>
#include <linux/ip.h>
#include <linux/if_tun.h>
@@ -1912,6 +1914,12 @@ nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformL
return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VXLAN, out_link);
}
+const NMPlatformLnkWireguard *
+nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
+{
+ return _link_get_lnk (self, ifindex, NM_LINK_TYPE_WIREGUARD, out_link);
+}
+
/*****************************************************************************/
/**
@@ -2907,6 +2915,16 @@ nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gs
return klass->mesh_set_ssid (self, ifindex, ssid, len);
}
+gboolean
+nm_platform_wireguard_get_link_properties (NMPlatform *self, const NMPlatformLink *link, NMPObject *obj)
+{
+ _CHECK_SELF (self, klass, FALSE);
+
+ g_return_val_if_fail (obj != NULL, FALSE);
+
+ return klass->wireguard_get_link_properties (self, link, obj);
+}
+
#define TO_STRING_DEV_BUF_SIZE (5+15+1)
static const char *
_to_string_dev (NMPlatform *self, int ifindex, char *buf, size_t size)
@@ -5087,6 +5105,7 @@ nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len
lnk->multi_queue ? " multi_queue" : "",
lnk->owner_valid ? nm_sprintf_buf (str_owner, " owner %u", (guint) lnk->owner) : "",
lnk->group_valid ? nm_sprintf_buf (str_group, " group %u", (guint) lnk->group) : "");
+
return buf;
}
@@ -5193,6 +5212,99 @@ nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize
return buf;
}
+const char *
+nm_platform_wireguard_peer_to_string (const NMWireguardPeer *peer, char *buf, gsize len)
+{
+ gs_free char *public_b64 = NULL;
+ char s_address[INET6_ADDRSTRLEN] = {0};
+ char s_endpoint[INET6_ADDRSTRLEN + NI_MAXSERV + sizeof("endpoint []:") + 1] = {0};
+ NMWireguardAllowedIP *allowedip;
+ guint8 nonzero_key = 0;
+ gsize i;
+
+ nm_utils_to_string_buffer_init (&buf, &len);
+
+ if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) {
+ char s_service[NI_MAXSERV];
+ socklen_t addr_len = 0;
+
+ if (peer->endpoint.addr.sa_family == AF_INET)
+ addr_len = sizeof (struct sockaddr_in);
+ else if (peer->endpoint.addr.sa_family == AF_INET6)
+ addr_len = sizeof (struct sockaddr_in6);
+ if (!getnameinfo (&peer->endpoint.addr, addr_len, s_address, sizeof(s_address), s_service,
sizeof(s_service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST)) {
+ if (peer->endpoint.addr.sa_family == AF_INET6 && strchr (s_address, ':'))
+ g_snprintf(s_endpoint, sizeof (s_endpoint), "endpoint [%s]:%s ", s_address,
s_service);
+ else
+ g_snprintf(s_endpoint, sizeof (s_endpoint), "endpoint %s:%s ", s_address,
s_service);
+ }
+ }
+
+
+ for (i = 0; i < sizeof (peer->preshared_key); i++)
+ nonzero_key |= peer->preshared_key[i];
+
+ public_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key));
+
+ nm_utils_strbuf_append (&buf, &len,
+ "{ "
+ "public_key %s "
+ "%s" /* preshared key indicator */
+ "%s" /* endpoint */
+ "rx %"G_GUINT64_FORMAT" "
+ "tx %"G_GUINT64_FORMAT" "
+ "allowedips {",
+ public_b64,
+ nonzero_key ? "preshared_key (hidden) " : "",
+ s_endpoint,
+ peer->rx_bytes,
+ peer->tx_bytes);
+
+
+ c_list_for_each_entry (allowedip, &peer->allowedips_lst_head, allowedips_lst) {
+ const char *ret;
+
+ ret = inet_ntop (allowedip->family, &allowedip->ip, s_address, sizeof(s_address));
+
+ nm_utils_strbuf_append (&buf, &len,
+ " %s/%u",
+ ret ? s_address : "<EAFNOSUPPORT>",
+ allowedip->cidr);
+ }
+
+ nm_utils_strbuf_append_str (&buf, &len, " } }");
+ return buf;
+}
+
+const char *
+nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireguard *lnk, char *buf, gsize len)
+{
+ gs_free char *public_b64 = NULL;
+ guint8 nonzero_key = 0;
+ gsize i;
+
+ if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
+ return buf;
+
+ public_b64 = g_base64_encode (lnk->public_key, sizeof (lnk->public_key));
+
+ for (i = 0; i < sizeof (lnk->private_key); i++)
+ nonzero_key |= lnk->private_key[i];
+
+ g_snprintf (buf, len,
+ "wireguard "
+ "public_key %s "
+ "%s" /* private key indicator */
+ "listen_port %u "
+ "fwmark 0x%x",
+ public_b64,
+ nonzero_key ? "private_key (hidden) " : "",
+ lnk->listen_port,
+ lnk->fwmark);
+
+ return buf;
+}
+
/**
* nm_platform_ip4_address_to_string:
* @route: pointer to NMPlatformIP4Address address structure
@@ -6019,6 +6131,27 @@ nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan
return 0;
}
+void
+nm_platform_lnk_wireguard_hash_update (const NMPlatformLnkWireguard *obj, NMHashState *h)
+{
+ nm_hash_update_vals (h,
+ obj->listen_port,
+ obj->fwmark);
+ nm_hash_update (h, obj->private_key, sizeof (obj->private_key));
+ nm_hash_update (h, obj->public_key, sizeof (obj->public_key));
+}
+
+int
+nm_platform_lnk_wireguard_cmp (const NMPlatformLnkWireguard *a, const NMPlatformLnkWireguard *b)
+{
+ NM_CMP_SELF (a, b);
+ NM_CMP_FIELD_MEMCMP (a, b, private_key);
+ NM_CMP_FIELD_MEMCMP (a, b, public_key);
+ NM_CMP_FIELD (a, b, listen_port);
+ NM_CMP_FIELD (a, b, fwmark);
+ return 0;
+}
+
void
nm_platform_ip4_address_hash_update (const NMPlatformIP4Address *obj, NMHashState *h)
{
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 824735083..0b189c3f6 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -725,6 +725,13 @@ typedef struct {
bool l3miss:1;
} NMPlatformLnkVxlan;
+typedef struct {
+ guint8 private_key[NM_WG_PUBLIC_KEY_LEN];
+ guint8 public_key[NM_WG_PUBLIC_KEY_LEN];
+ guint16 listen_port;
+ guint32 fwmark;
+} NMPlatformLnkWireguard;
+
typedef enum {
NM_PLATFORM_LINK_DUPLEX_UNKNOWN,
NM_PLATFORM_LINK_DUPLEX_HALF,
@@ -874,6 +881,8 @@ typedef struct {
gboolean (*mesh_set_channel) (NMPlatform *, int ifindex, guint32 channel);
gboolean (*mesh_set_ssid) (NMPlatform *, int ifindex, const guint8 *ssid, gsize len);
+ gboolean (*wireguard_get_link_properties) (NMPlatform *, const NMPlatformLink *, NMPObject
*obj);
+
gboolean (*object_delete) (NMPlatform *, const NMPObject *obj);
gboolean (*ip4_address_add) (NMPlatform *,
@@ -1198,6 +1207,7 @@ const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifin
const NMPlatformLnkTun *nm_platform_link_get_lnk_tun (NMPlatform *self, int ifindex, const NMPlatformLink
**out_link);
const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink
**out_link);
const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const
NMPlatformLink **out_link);
+const NMPlatformLnkWireguard *nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const
NMPlatformLink **out_link);
NMPlatformError nm_platform_link_vlan_add (NMPlatform *self,
const char *name,
@@ -1252,6 +1262,8 @@ guint32 nm_platform_mesh_get_channel (NMPlatform *self, int ifindex);
gboolean nm_platform_mesh_set_channel (NMPlatform *self, int ifindex, guint32 channel);
gboolean nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gsize len);
+gboolean nm_platform_wireguard_get_link_properties (NMPlatform *self, const NMPlatformLink *link,
NMPObject *obj);
+
void nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address,
guint8 plen);
const struct in6_addr *nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr);
@@ -1373,6 +1385,7 @@ const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *bu
const char *nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len);
const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len);
const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len);
+const char *nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireguard *lnk, char *buf, gsize len);
const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len);
const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len);
const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len);
@@ -1386,6 +1399,10 @@ const char *nm_platform_vlan_qos_mapping_to_string (const char *name,
char *buf,
gsize len);
+const char *nm_platform_wireguard_peer_to_string (const NMWireguardPeer *peer,
+ char *buf,
+ gsize len);
+
int nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b);
int nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b);
int nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b);
@@ -1397,6 +1414,7 @@ int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *
int nm_platform_lnk_tun_cmp (const NMPlatformLnkTun *a, const NMPlatformLnkTun *b);
int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b);
int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b);
+int nm_platform_lnk_wireguard_cmp (const NMPlatformLnkWireguard *a, const NMPlatformLnkWireguard *b);
int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b);
int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b);
@@ -1433,6 +1451,7 @@ void nm_platform_lnk_sit_hash_update (const NMPlatformLnkSit *obj, NMHashState *
void nm_platform_lnk_tun_hash_update (const NMPlatformLnkTun *obj, NMHashState *h);
void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h);
void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h);
+void nm_platform_lnk_wireguard_hash_update (const NMPlatformLnkWireguard *obj, NMHashState *h);
void nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h);
void nm_platform_tfilter_hash_update (const NMPlatformTfilter *obj, NMHashState *h);
diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c
index 666d334c2..91f015bcc 100644
--- a/src/platform/nmp-object.c
+++ b/src/platform/nmp-object.c
@@ -466,6 +466,12 @@ _vt_cmd_obj_dispose_lnk_vlan (NMPObject *obj)
g_free ((gpointer) obj->_lnk_vlan.egress_qos_map);
}
+static void
+_vt_cmd_obj_dispose_lnk_wireguard (NMPObject *obj)
+{
+ g_ptr_array_unref (obj->_lnk_wireguard.peers);
+}
+
static NMPObject *
_nmp_object_new_from_class (const NMPClass *klass)
{
@@ -720,6 +726,51 @@ _vt_cmd_obj_to_string_lnk_vlan (const NMPObject *obj, NMPObjectToStringMode to_s
}
}
+static const char *
+_vt_cmd_obj_to_string_lnk_wireguard (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf,
gsize buf_size)
+{
+ const NMPClass *klass;
+ char buf2[sizeof (_nm_utils_to_string_buffer)];
+ char *b;
+ gsize i, l;
+
+ klass = NMP_OBJECT_GET_CLASS (obj);
+
+ switch (to_string_mode) {
+ case NMP_OBJECT_TO_STRING_ID:
+ g_snprintf (buf, buf_size, "%p", obj);
+ return buf;
+ case NMP_OBJECT_TO_STRING_ALL:
+ b = buf;
+
+ nm_utils_strbuf_append (&b, &buf_size,
+ "[%s,%p,%u,%calive,%cvisible; %s peers (%u) {",
+ klass->obj_type_name, obj, obj->parent._ref_count,
+ nmp_object_is_alive (obj) ? '+' : '-',
+ nmp_object_is_visible (obj) ? '+' : '-',
+ nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof
(buf2)),
+ obj->_lnk_wireguard.peers->len);
+
+ for (i = 0; i < obj->_lnk_wireguard.peers->len; i++) {
+ const NMWireguardPeer *peer = g_ptr_array_index(obj->_lnk_wireguard.peers, i);
+ nm_platform_wireguard_peer_to_string (peer, b, buf_size);
+ l = strlen (b);
+ b += l;
+ buf_size -= l;
+ }
+
+ nm_utils_strbuf_append_str (&b, &buf_size, " }");
+
+ return buf;
+ case NMP_OBJECT_TO_STRING_PUBLIC:
+ NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size);
+
+ return buf;
+ default:
+ g_return_val_if_reached ("ERROR");
+ }
+}
+
#define _vt_cmd_plobj_to_string_id(type, plat_type, ...) \
static const char * \
_vt_cmd_plobj_to_string_id_##type (const NMPlatformObject *_obj, char *buf, gsize buf_len) \
@@ -787,6 +838,15 @@ _vt_cmd_obj_hash_update_lnk_vlan (const NMPObject *obj, NMHashState *h)
h);
}
+static void
+_vt_cmd_obj_hash_update_lnk_wireguard (const NMPObject *obj, NMHashState *h)
+{
+ nm_assert (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LNK_WIREGUARD);
+
+ nm_platform_lnk_wireguard_hash_update (&obj->lnk_wireguard, h);
+ nm_hash_update_val (h, obj->_lnk_wireguard.peers);
+}
+
int
nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2)
{
@@ -865,6 +925,18 @@ _vt_cmd_obj_cmp_lnk_vlan (const NMPObject *obj1, const NMPObject *obj2)
return c;
}
+static int
+_vt_cmd_obj_cmp_lnk_wireguard (const NMPObject *obj1, const NMPObject *obj2)
+{
+ int c;
+
+ c = nm_platform_lnk_wireguard_cmp (&obj1->lnk_wireguard, &obj2->lnk_wireguard);
+ if (c)
+ return c;
+
+ return obj1->_lnk_wireguard.peers < obj2->_lnk_wireguard.peers;
+}
+
/* @src is a const object, which is not entirely correct for link types, where
* we increase the ref count for src->_link.udev.device.
* Hence, nmp_object_copy() can violate the const promise of @src.
@@ -925,6 +997,13 @@ _vt_cmd_obj_copy_lnk_vlan (NMPObject *dst, const NMPObject *src)
src->_lnk_vlan.egress_qos_map);
}
+static void
+_vt_cmd_obj_copy_lnk_wireguard (NMPObject *dst, const NMPObject *src)
+{
+ dst->lnk_wireguard = src->lnk_wireguard;
+ dst->_lnk_wireguard.peers = g_ptr_array_ref (src->_lnk_wireguard.peers);
+}
+
#define _vt_cmd_plobj_id_copy(type, plat_type, cmd) \
static void \
_vt_cmd_plobj_id_copy_##type (NMPlatformObject *_dst, const NMPlatformObject *_src) \
@@ -2818,5 +2897,21 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState
*h)) nm_platform_lnk_vxlan_hash_update,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const
NMPlatformObject *obj2)) nm_platform_lnk_vxlan_cmp,
},
+ [NMP_OBJECT_TYPE_LNK_WIREGUARD - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
+ .obj_type = NMP_OBJECT_TYPE_LNK_WIREGUARD,
+ .sizeof_data = sizeof (NMPObjectLnkWireguard),
+ .sizeof_public = sizeof (NMPlatformLnkWireguard),
+ .obj_type_name = "wireguard",
+ .lnk_link_type = NM_LINK_TYPE_WIREGUARD,
+ .cmd_obj_hash_update = _vt_cmd_obj_hash_update_lnk_wireguard,
+ .cmd_obj_cmp = _vt_cmd_obj_cmp_lnk_wireguard,
+ .cmd_obj_copy = _vt_cmd_obj_copy_lnk_wireguard,
+ .cmd_obj_dispose = _vt_cmd_obj_dispose_lnk_wireguard,
+ .cmd_obj_to_string = _vt_cmd_obj_to_string_lnk_wireguard,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char
*buf, gsize len)) nm_platform_lnk_wireguard_to_string,
+ .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState
*h)) nm_platform_lnk_vlan_hash_update,
+ .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const
NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp,
+ },
};
diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h
index 0dd2687a3..e64ac6614 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -213,6 +213,12 @@ typedef struct {
NMPlatformLnkVxlan _public;
} NMPObjectLnkVxlan;
+typedef struct {
+ NMPlatformLnkWireguard _public;
+
+ GPtrArray *peers;
+} NMPObjectLnkWireguard;
+
typedef struct {
NMPlatformIP4Address _public;
} NMPObjectIP4Address;
@@ -278,6 +284,9 @@ struct _NMPObject {
NMPlatformLnkVxlan lnk_vxlan;
NMPObjectLnkVxlan _lnk_vxlan;
+ NMPlatformLnkWireguard lnk_wireguard;
+ NMPObjectLnkWireguard _lnk_wireguard;
+
NMPlatformIPAddress ip_address;
NMPlatformIPXAddress ipx_address;
NMPlatformIP4Address ip4_address;
--
2.16.2
[
Date Prev][
Date Next] [
Thread Prev][Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]