summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-09-06 17:05:55 +0200
committerThomas Haller <thaller@redhat.com>2018-09-06 21:18:54 +0200
commit266629e207a3abe13506f3f63d0e3057d8d9f312 (patch)
tree11e573a3245b365c6e55ef4b682d6c5d9a5719a6
parentd257c1918efb49707d274f68f9670533294ccacb (diff)
downloadNetworkManager-th/platform-wireguard.tar.gz
platform/wireguard: rework parsing wireguard links in platformth/platform-wireguard
- previously, parsing wireguard genl data resulted in memory corruption: - _wireguard_update_from_allowedips_nla() takes pointers to allowedip = &g_array_index (buf->allowedips, NMWireGuardAllowedIP, buf->allowedips->len - 1); but resizing the GArray will invalidate this pointer. This happens when there are multiple allowed-ips to parse. - there was some confusion who owned the allowedips pointers. _wireguard_peers_cpy() and _vt_cmd_obj_dispose_lnk_wireguard() assumed each peer owned their own chunk, but _wireguard_get_link_properties() would not duplicate the memory properly. - rework memory handling for allowed_ips. Now, the NMPObjectLnkWireGuard keeps a pointer _allowed_ips_buf. This buffer contains the instances for all peers. This makes sense, because NMPObject are intended to be immutable. So, the buffers are created once (by growing a GArray) and never modified afterwards. There is no point having each peer own their own chunks, especially, because _wireguard_get_device_cb() might need to combine multiple sets of instances together. That is, within _wireguard_get_device_cb() we don't know yet how many allowed-ips we will get. - a lot of refactoring. - ensure that we nm_explicit_bzero() private data. However, that only works so far, because our netlink library does not ensure that no data is leaked.
-rw-r--r--libnm-core/nm-core-types-internal.h25
-rw-r--r--shared/nm-utils/nm-hash-utils.h5
-rw-r--r--src/platform/nm-linux-platform.c451
-rw-r--r--src/platform/nm-platform.c105
-rw-r--r--src/platform/nm-platform.h12
-rw-r--r--src/platform/nmp-object.c301
-rw-r--r--src/platform/nmp-object.h37
7 files changed, 558 insertions, 378 deletions
diff --git a/libnm-core/nm-core-types-internal.h b/libnm-core/nm-core-types-internal.h
index 7ab0f59455..4d43aaf45d 100644
--- a/libnm-core/nm-core-types-internal.h
+++ b/libnm-core/nm-core-types-internal.h
@@ -31,31 +31,6 @@ typedef struct {
guint32 to;
} NMVlanQosMapping;
-typedef struct {
- NMIPAddr ip;
- guint8 family;
- guint8 mask;
-} 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;
- guint16 persistent_keepalive_interval;
- struct timespec last_handshake_time;
- guint64 rx_bytes, tx_bytes;
-
- gsize allowedips_len;
- NMWireGuardAllowedIP *allowedips;
-} 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/shared/nm-utils/nm-hash-utils.h b/shared/nm-utils/nm-hash-utils.h
index 7d9620b96c..b797fb75af 100644
--- a/shared/nm-utils/nm-hash-utils.h
+++ b/shared/nm-utils/nm-hash-utils.h
@@ -57,6 +57,11 @@ nm_hash_update (NMHashState *state, const void *ptr, gsize n)
nm_assert (ptr);
nm_assert (n > 0);
+ /* Note: the data passed in here might be sensitive data (secrets),
+ * that we should nm_explicty_zero() afterwards. However, since
+ * we are using siphash24 with a random key, that is not really
+ * necessary. Something to keep in mind, if we ever move away from
+ * this hash implementation. */
c_siphash_append (&state->_state, ptr, n);
}
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 418186b360..47b5d7e6a5 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -44,6 +44,7 @@
#include "nm-core-internal.h"
#include "nm-setting-vlan.h"
+#include "nm-utils/nm-secret-utils.h"
#include "nm-netlink.h"
#include "nm-core-utils.h"
#include "nmp-object.h"
@@ -1912,63 +1913,60 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data)
/*****************************************************************************/
-/* Context to build a NMPObjectLnkWireGuard instance.
- * GArray wrappers are discarded after processing all netlink messages. */
-struct _wireguard_device_buf {
- NMPObject *obj;
- GArray *peers;
- GArray *allowedips;
-};
-
static gboolean
-_wireguard_update_from_allowedips_nla (struct _wireguard_device_buf *buf,
- struct nlattr *allowedip_attr)
+_wireguard_update_from_allowed_ips_nla (NMPWireGuardAllowedIP *allowed_ip,
+ struct nlattr *nlattr)
{
- static const struct nla_policy allowedip_policy[WGALLOWEDIP_A_MAX + 1] = {
+ static const struct nla_policy policy[WGALLOWEDIP_A_MAX + 1] = {
[WGALLOWEDIP_A_FAMILY] = { .type = NLA_U16 },
[WGALLOWEDIP_A_IPADDR] = { .minlen = sizeof (struct in_addr) },
[WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8 },
};
- struct nlattr *tba[WGALLOWEDIP_A_MAX + 1];
- NMWireGuardPeer *peer = &g_array_index (buf->peers, NMWireGuardPeer, buf->peers->len - 1);
- NMWireGuardAllowedIP *allowedip;
- NMWireGuardAllowedIP new_allowedip = {0};
+ struct nlattr *tb[WGALLOWEDIP_A_MAX + 1];
+ int family;
int addr_len;
- int nlerr;
- nlerr = nla_parse_nested (tba, WGALLOWEDIP_A_MAX, allowedip_attr, allowedip_policy);
- if (nlerr < 0)
+ if (nla_parse_nested (tb, WGALLOWEDIP_A_MAX, nlattr, policy) < 0)
return FALSE;
- g_array_append_val (buf->allowedips, new_allowedip);
- allowedip = &g_array_index (buf->allowedips, NMWireGuardAllowedIP, buf->allowedips->len - 1);
- peer->allowedips_len++;
-
- if (tba[WGALLOWEDIP_A_FAMILY])
- allowedip->family = nla_get_u16 (tba[WGALLOWEDIP_A_FAMILY]);
+ if (!tb[WGALLOWEDIP_A_FAMILY])
+ return FALSE;
- if (allowedip->family == AF_INET)
+ family = nla_get_u16 (tb[WGALLOWEDIP_A_FAMILY]);
+ if (family == AF_INET)
addr_len = sizeof (in_addr_t);
- else if (allowedip->family == AF_INET6)
+ else if (family == AF_INET6)
addr_len = sizeof (struct in6_addr);
else
return FALSE;
- _check_addr_or_return_val (tba, WGALLOWEDIP_A_IPADDR, addr_len, FALSE);
- if (tba[WGALLOWEDIP_A_IPADDR])
- nla_memcpy (&allowedip->ip, tba[WGALLOWEDIP_A_IPADDR], addr_len);
- if (tba[WGALLOWEDIP_A_CIDR_MASK])
- allowedip->mask = nla_get_u8 (tba[WGALLOWEDIP_A_CIDR_MASK]);
+ _check_addr_or_return_val (tb, WGALLOWEDIP_A_IPADDR, addr_len, FALSE);
+
+ memset (allowed_ip, 0, sizeof (NMPWireGuardAllowedIP));
+
+ allowed_ip->family = family;
+ nm_assert ((int) allowed_ip->family == family);
+
+ if (tb[WGALLOWEDIP_A_IPADDR])
+ nla_memcpy (&allowed_ip->addr, tb[WGALLOWEDIP_A_IPADDR], addr_len);
+ if (tb[WGALLOWEDIP_A_CIDR_MASK])
+ allowed_ip->mask = nla_get_u8 (tb[WGALLOWEDIP_A_CIDR_MASK]);
return TRUE;
}
+typedef struct {
+ CList lst;
+ NMPWireGuardPeer data;
+} WireGuardPeerConstruct;
+
static gboolean
-_wireguard_update_from_peers_nla (struct _wireguard_device_buf *buf,
+_wireguard_update_from_peers_nla (CList *peers,
+ GArray **p_allowed_ips,
struct nlattr *peer_attr)
{
static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = {
- [WGPEER_A_PUBLIC_KEY] = { .minlen = NM_WG_PUBLIC_KEY_LEN },
+ [WGPEER_A_PUBLIC_KEY] = { .minlen = NMP_WIREGUARD_PUBLIC_KEY_LEN },
[WGPEER_A_PRESHARED_KEY] = { },
[WGPEER_A_FLAGS] = { .type = NLA_U32 },
[WGPEER_A_ENDPOINT] = { },
@@ -1978,63 +1976,107 @@ _wireguard_update_from_peers_nla (struct _wireguard_device_buf *buf,
[WGPEER_A_TX_BYTES] = { .type = NLA_U64 },
[WGPEER_A_ALLOWEDIPS] = { .type = NLA_NESTED },
};
- struct nlattr *tbp[WGPEER_A_MAX + 1];
- NMWireGuardPeer *const last = buf->peers->len ? &g_array_index (buf->peers, NMWireGuardPeer, buf->peers->len - 1) : NULL;
- NMWireGuardPeer *peer;
- NMWireGuardPeer new_peer = { 0 };
+ WireGuardPeerConstruct *peer_c;
+ struct nlattr *tb[WGPEER_A_MAX + 1];
- if (nla_parse_nested (tbp, WGPEER_A_MAX, peer_attr, peer_policy) < 0)
+ if (nla_parse_nested (tb, WGPEER_A_MAX, peer_attr, peer_policy) < 0)
return FALSE;
- if (!tbp[WGPEER_A_PUBLIC_KEY])
+ if (!tb[WGPEER_A_PUBLIC_KEY])
return FALSE;
/* a peer with the same public key as last peer is just a continuation for extra AllowedIPs */
- if ( last
- && !memcmp (nla_data (tbp[WGPEER_A_PUBLIC_KEY]), last->public_key, sizeof (last->public_key)))
- peer = last;
+ peer_c = c_list_last_entry (peers, WireGuardPeerConstruct, lst);
+ if ( peer_c
+ && !memcmp (nla_data (tb[WGPEER_A_PUBLIC_KEY]), peer_c->data.public_key, NMP_WIREGUARD_PUBLIC_KEY_LEN)) {
+ G_STATIC_ASSERT_EXPR (NMP_WIREGUARD_PUBLIC_KEY_LEN == sizeof (peer_c->data.public_key));
+ /* this is a continuation. */
+ }
else {
/* otherwise, start a new peer */
- g_array_append_val (buf->peers, new_peer);
- peer = &g_array_index (buf->peers, NMWireGuardPeer, buf->peers->len - 1);
-
- nla_memcpy (&peer->public_key, tbp[WGPEER_A_PUBLIC_KEY], sizeof (peer->public_key));
-
- if (tbp[WGPEER_A_PRESHARED_KEY])
- nla_memcpy (&peer->preshared_key, tbp[WGPEER_A_PRESHARED_KEY], sizeof (peer->preshared_key));
- if (tbp[WGPEER_A_ENDPOINT]) {
- struct sockaddr *addr = nla_data (tbp[WGPEER_A_ENDPOINT]);
- if (addr->sa_family == AF_INET)
- nla_memcpy (&peer->endpoint.addr4, tbp[WGPEER_A_ENDPOINT], sizeof (peer->endpoint.addr4));
- else if (addr->sa_family == AF_INET6)
- nla_memcpy (&peer->endpoint.addr6, tbp[WGPEER_A_ENDPOINT], sizeof (peer->endpoint.addr6));
- }
- if (tbp[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL])
- peer->persistent_keepalive_interval = nla_get_u64 (tbp[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]);
- if (tbp[WGPEER_A_LAST_HANDSHAKE_TIME])
- nla_memcpy (&peer->last_handshake_time, tbp[WGPEER_A_LAST_HANDSHAKE_TIME], sizeof (peer->last_handshake_time));
- if (tbp[WGPEER_A_RX_BYTES])
- peer->rx_bytes = nla_get_u64 (tbp[WGPEER_A_RX_BYTES]);
- if (tbp[WGPEER_A_TX_BYTES])
- peer->tx_bytes = nla_get_u64 (tbp[WGPEER_A_TX_BYTES]);
+ peer_c = g_slice_new0 (WireGuardPeerConstruct);
+ c_list_link_tail (peers, &peer_c->lst);
- peer->allowedips = NULL;
- peer->allowedips_len = 0;
+ nla_memcpy (&peer_c->data.public_key, tb[WGPEER_A_PUBLIC_KEY], sizeof (peer_c->data.public_key));
+
+ if (tb[WGPEER_A_PRESHARED_KEY]) {
+ nla_memcpy (&peer_c->data.preshared_key, tb[WGPEER_A_PRESHARED_KEY], sizeof (peer_c->data.preshared_key));
+ /* FIXME(netlink-bzero-secret) */
+ nm_explicit_bzero (nla_data (tb[WGPEER_A_PRESHARED_KEY]),
+ nla_len (tb[WGPEER_A_PRESHARED_KEY]));
+ }
+ if (tb[WGPEER_A_ENDPOINT]) {
+ const struct sockaddr *addr = nla_data (tb[WGPEER_A_ENDPOINT]);
+ unsigned short family;
+
+ G_STATIC_ASSERT (sizeof (addr->sa_family) == sizeof (family));
+ memcpy (&family, &addr->sa_family, sizeof (addr->sa_family));
+
+ if ( family == AF_INET
+ && nla_len (tb[WGPEER_A_ENDPOINT]) == sizeof (struct sockaddr_in)) {
+ const struct sockaddr_in *addr4 = (const struct sockaddr_in *) addr;
+
+ peer_c->data.endpoint_family = AF_INET;
+ peer_c->data.endpoint_port = unaligned_read_be16 (&addr4->sin_port);
+ peer_c->data.endpoint_addr.addr4 = unaligned_read_ne32 (&addr4->sin_addr.s_addr);
+ memcpy (&peer_c->data.endpoint_addr.addr4, &addr4->sin_addr.s_addr, 4);
+ } else if ( family == AF_INET6
+ && nla_len (tb[WGPEER_A_ENDPOINT]) == sizeof (struct sockaddr_in6)) {
+ const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *) addr;
+
+ peer_c->data.endpoint_family = AF_INET6;
+ peer_c->data.endpoint_port = unaligned_read_be16 (&addr6->sin6_port);
+ memcpy (&peer_c->data.endpoint_addr.addr6, &addr6->sin6_addr, 16);
+ }
+ }
+ if (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL])
+ peer_c->data.persistent_keepalive_interval = nla_get_u64 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]);
+ if (tb[WGPEER_A_LAST_HANDSHAKE_TIME])
+ nla_memcpy (&peer_c->data.last_handshake_time, tb[WGPEER_A_LAST_HANDSHAKE_TIME], sizeof (peer_c->data.last_handshake_time));
+ if (tb[WGPEER_A_RX_BYTES])
+ peer_c->data.rx_bytes = nla_get_u64 (tb[WGPEER_A_RX_BYTES]);
+ if (tb[WGPEER_A_TX_BYTES])
+ peer_c->data.tx_bytes = nla_get_u64 (tb[WGPEER_A_TX_BYTES]);
}
- if (tbp[WGPEER_A_ALLOWEDIPS]) {
+ if (tb[WGPEER_A_ALLOWEDIPS]) {
struct nlattr *attr;
int rem;
+ GArray *allowed_ips = *p_allowed_ips;
+
+ nla_for_each_nested (attr, tb[WGPEER_A_ALLOWEDIPS], rem) {
+ if (!allowed_ips) {
+ allowed_ips = g_array_new (FALSE, FALSE, sizeof (NMPWireGuardAllowedIP));
+ *p_allowed_ips = allowed_ips;
+ g_array_set_size (allowed_ips, 1);
+ } else
+ g_array_set_size (allowed_ips, allowed_ips->len + 1);
+
+ if (!_wireguard_update_from_allowed_ips_nla (&g_array_index (allowed_ips,
+ NMPWireGuardAllowedIP,
+ allowed_ips->len - 1),
+ attr)) {
+ /* we ignore the error of parsing one allowed-ip. */
+ g_array_set_size (allowed_ips, allowed_ips->len - 1);
+ continue;
+ }
- nla_for_each_nested (attr, tbp[WGPEER_A_ALLOWEDIPS], rem) {
- if (!_wireguard_update_from_allowedips_nla (buf, attr))
- return FALSE;
+ if (!peer_c->data._construct_idx_end)
+ peer_c->data._construct_idx_start = allowed_ips->len - 1;
+ peer_c->data._construct_idx_end = allowed_ips->len;
}
}
return TRUE;
}
+typedef struct {
+ const int ifindex;
+ NMPObject *obj;
+ CList peers;
+ GArray *allowed_ips;
+} WireGuardParseData;
+
static int
_wireguard_get_device_cb (struct nl_msg *msg, void *arg)
{
@@ -2048,95 +2090,187 @@ _wireguard_get_device_cb (struct nl_msg *msg, void *arg)
[WGDEVICE_A_FWMARK] = { .type = NLA_U32 },
[WGDEVICE_A_PEERS] = { .type = NLA_NESTED },
};
- struct _wireguard_device_buf *buf = arg;
- struct nlattr *tbd[WGDEVICE_A_MAX + 1];
- NMPlatformLnkWireGuard *props = &buf->obj->lnk_wireguard;
- struct nlmsghdr *nlh = nlmsg_hdr (msg);
+ WireGuardParseData *parse_data = arg;
+ struct nlattr *tb[WGDEVICE_A_MAX + 1];
+ NMPObject *obj = NULL;
int nlerr;
- nlerr = genlmsg_parse (nlh, 0, tbd, WGDEVICE_A_MAX, device_policy);
+ nlerr = genlmsg_parse (nlmsg_hdr (msg), 0, tb, WGDEVICE_A_MAX, device_policy);
if (nlerr < 0)
return NL_SKIP;
- if (tbd[WGDEVICE_A_PRIVATE_KEY])
- nla_memcpy (props->private_key, tbd[WGDEVICE_A_PRIVATE_KEY], sizeof (props->private_key));
- if (tbd[WGDEVICE_A_PUBLIC_KEY])
- nla_memcpy (props->public_key, tbd[WGDEVICE_A_PUBLIC_KEY], sizeof (props->public_key));
- if (tbd[WGDEVICE_A_LISTEN_PORT])
- props->listen_port = nla_get_u16 (tbd[WGDEVICE_A_LISTEN_PORT]);
- if (tbd[WGDEVICE_A_FWMARK])
- props->fwmark = nla_get_u32 (tbd[WGDEVICE_A_FWMARK]);
+ if (tb[WGDEVICE_A_IFINDEX]) {
+ int ifindex;
+
+ ifindex = (int) nla_get_u32 (tb[WGDEVICE_A_IFINDEX]);
+ if ( ifindex <= 0
+ || parse_data->ifindex != ifindex)
+ return NL_SKIP;
+ } else {
+ if (!parse_data->obj)
+ return NL_SKIP;
+ }
+
+ if (parse_data->obj)
+ obj = parse_data->obj;
+ else {
+ NMPlatformLnkWireGuard *props;
+
+ obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_WIREGUARD, NULL);
+ props = &obj->lnk_wireguard;
+
+ if (tb[WGDEVICE_A_PRIVATE_KEY]) {
+ nla_memcpy (props->private_key, tb[WGDEVICE_A_PRIVATE_KEY], sizeof (props->private_key));
+ /* FIXME(netlink-bzero-secret): extend netlink library to wipe memory. For now,
+ * just hack it here (yes, this does not cover all places where the
+ * private key was copied). */
+ nm_explicit_bzero (nla_data (tb[WGDEVICE_A_PRIVATE_KEY]),
+ nla_len (tb[WGDEVICE_A_PRIVATE_KEY]));
+ }
+ if (tb[WGDEVICE_A_PUBLIC_KEY])
+ nla_memcpy (props->public_key, tb[WGDEVICE_A_PUBLIC_KEY], sizeof (props->public_key));
+ if (tb[WGDEVICE_A_LISTEN_PORT])
+ props->listen_port = nla_get_u16 (tb[WGDEVICE_A_LISTEN_PORT]);
+ if (tb[WGDEVICE_A_FWMARK])
+ props->fwmark = nla_get_u32 (tb[WGDEVICE_A_FWMARK]);
- if (tbd[WGDEVICE_A_PEERS]) {
+ parse_data->obj = obj;
+ }
+
+ if (tb[WGDEVICE_A_PEERS]) {
struct nlattr *attr;
int rem;
- nla_for_each_nested (attr, tbd[WGDEVICE_A_PEERS], rem) {
- if (!_wireguard_update_from_peers_nla (buf, attr))
- return NL_SKIP;
+ nla_for_each_nested (attr, tb[WGDEVICE_A_PEERS], rem) {
+ if (!_wireguard_update_from_peers_nla (&parse_data->peers, &parse_data->allowed_ips, attr)) {
+ /* we ignore the error of parsing one peer.
+ * _wireguard_update_from_peers_nla() leaves the @peers array in the
+ * desired state. */
+ }
}
}
return NL_OK;
}
-static gboolean
-_wireguard_get_link_properties (NMPlatform *platform, const NMPlatformLink *link, NMPObject *obj)
+static const NMPObject *
+_wireguard_read_info (NMPlatform *platform /* used only as logging context */,
+ struct nl_sock *genl,
+ int wireguard_family_id,
+ int ifindex)
{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
nm_auto_nlmsg struct nl_msg *msg = NULL;
- struct _wireguard_device_buf buf = {
- .obj = obj,
- .peers = g_array_new (FALSE, FALSE, sizeof (NMWireGuardPeer)),
- .allowedips = g_array_new (FALSE, FALSE, sizeof (NMWireGuardAllowedIP)),
+ NMPObject *obj = NULL;
+ WireGuardPeerConstruct *peer_c;
+ WireGuardPeerConstruct *peer_c_safe;
+ gs_unref_array GArray *allowed_ips = NULL;
+ WireGuardParseData parse_data = {
+ .ifindex = ifindex,
};
- struct nl_cb cb = {
+ const struct nl_cb cb = {
.valid_cb = _wireguard_get_device_cb,
- .valid_arg = &buf,
+ .valid_arg = (gpointer) &parse_data,
};
- guint i, j;
- int wireguard_family_id;
+ guint i;
- wireguard_family_id = genl_ctrl_resolve (priv->genl, "wireguard");
- if (wireguard_family_id < 0) {
- _LOGD ("wireguard: kernel support not available for wireguard link %s", link->name);
- goto err;
- }
+ nm_assert (genl);
+ nm_assert (wireguard_family_id >= 0);
+ nm_assert (ifindex > 0);
msg = nlmsg_alloc ();
- if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, wireguard_family_id,
- 0, NLM_F_DUMP, WG_CMD_GET_DEVICE, 1))
- goto err;
+ if (!genlmsg_put (msg,
+ NL_AUTO_PORT,
+ NL_AUTO_SEQ,
+ wireguard_family_id,
+ 0,
+ NLM_F_DUMP,
+ WG_CMD_GET_DEVICE,
+ 1))
+ return NULL;
+
+ NLA_PUT_U32 (msg, WGDEVICE_A_IFINDEX, (guint32) ifindex);
- NLA_PUT_U32 (msg, WGDEVICE_A_IFINDEX, link->ifindex);
+ if (nl_send_auto (genl, msg) < 0)
+ return NULL;
- if (nl_send_auto (priv->genl, msg) < 0)
- goto err;
+ c_list_init (&parse_data.peers);
- if (nl_recvmsgs (priv->genl, &cb) < 0)
- goto err;
+ /* we ignore errors, and return whatever we could successfully
+ * parse. */
+ nl_recvmsgs (genl, &cb);
- /* have each peer point to its own chunk of the allowedips buffer */
- for (i = 0, j = 0; i < buf.peers->len; i++) {
- NMWireGuardPeer *p = &g_array_index (buf.peers, NMWireGuardPeer, i);
+ /* unpack: transfer ownership */
+ obj = parse_data.obj;
+ allowed_ips = parse_data.allowed_ips;
- p->allowedips = &g_array_index (buf.allowedips, NMWireGuardAllowedIP, j);
- j += p->allowedips_len;
+ if (!obj) {
+ while ((peer_c = c_list_first_entry (&parse_data.peers, WireGuardPeerConstruct, lst))) {
+ c_list_unlink_stale (&peer_c->lst);
+ nm_explicit_bzero (&peer_c->data.preshared_key, sizeof (peer_c->data.preshared_key));
+ g_slice_free (WireGuardPeerConstruct, peer_c);
+ }
+ return NULL;
}
- /* drop the wrapper (but also the buffer if no peer points to it) */
- g_array_free (buf.allowedips, buf.peers->len ? FALSE : TRUE);
- obj->_lnk_wireguard.peers_len = buf.peers->len;
- obj->_lnk_wireguard.peers = (NMWireGuardPeer *) g_array_free (buf.peers, FALSE);
+ /* we receive peers/allowed-ips possibly in separate messages. Hence, while
+ * parsing the dump, we don't know how many peers/allowed-ips we will receive.
+ *
+ * We solve that, by collecting all peers with a CList. It's done this way,
+ * because a GArray would require reallocating the array, but we want to
+ * bzero() the preshared-key of each peer.
+ *
+ * For allowed-ips, we instead track one GArray, which are all appended
+ * there. The realloc/resize of the GArray is desired there. However,
+ * while we build the GArray, we don't yet have the final pointers.
+ * Hence, while constructing we track the indexes with peer->_construct_idx_*
+ * fields. These indexes must no be convered to actual pointers.
+ *
+ * This is all done during parsing. In the final NMPObjectLnkWireGuard we
+ * don't want the CList anymore. That is, because NMPObject instances are
+ * immutable and long-living. We repack the CList in a peers array. */
+ obj->_lnk_wireguard.peers_len = c_list_length (&parse_data.peers);
+ obj->_lnk_wireguard.peers = obj->_lnk_wireguard.peers_len > 0
+ ? g_new (NMPWireGuardPeer, obj->_lnk_wireguard.peers_len)
+ : NULL;
+
+ obj->_lnk_wireguard._allowed_ips_buf_len = allowed_ips ? allowed_ips->len : 0u;
+ obj->_lnk_wireguard._allowed_ips_buf = obj->_lnk_wireguard._allowed_ips_buf_len > 0
+ ? (NMPWireGuardAllowedIP *) g_array_free (g_steal_pointer (&allowed_ips), FALSE)
+ : NULL;
+
+ i = 0;
+ c_list_for_each_entry_safe (peer_c, peer_c_safe, &parse_data.peers, lst) {
+ NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &obj->_lnk_wireguard.peers[i++];
+
+ *peer = peer_c->data;
+
+ c_list_unlink_stale (&peer_c->lst);
+ nm_explicit_bzero (&peer_c->data.preshared_key, sizeof (peer_c->data.preshared_key));
+ g_slice_free (WireGuardPeerConstruct, peer_c);
+
+ if (peer->_construct_idx_end > peer->_construct_idx_start) {
+ guint len;
+
+ nm_assert (obj->_lnk_wireguard._allowed_ips_buf);
+ nm_assert (peer->_construct_idx_start < obj->_lnk_wireguard._allowed_ips_buf_len);
+ nm_assert (peer->_construct_idx_end <= obj->_lnk_wireguard._allowed_ips_buf_len);
+
+ len = peer->_construct_idx_end - peer->_construct_idx_start;
+ peer->allowed_ips = &obj->_lnk_wireguard._allowed_ips_buf[peer->_construct_idx_start];
+ peer->allowed_ips_len = len;
+ } else {
+ nm_assert (!peer->_construct_idx_start);
+ nm_assert (!peer->_construct_idx_end);
+ peer->allowed_ips = NULL;
+ peer->allowed_ips_len = 0;
+ }
+ }
- return TRUE;
+ return obj;
-err:
nla_put_failure:
- g_array_free (buf.peers, TRUE);
- g_array_free (buf.allowedips, TRUE);
- return FALSE;
+ g_return_val_if_reached (NULL);
}
/*****************************************************************************/
@@ -2197,10 +2331,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
if (!nlmsg_valid_hdr (nlh, sizeof (*ifi)))
return NULL;
- ifi = nlmsg_data(nlh);
+ ifi = nlmsg_data (nlh);
if (ifi->ifi_family != AF_UNSPEC)
return NULL;
+ if (ifi->ifi_index <= 0)
+ return NULL;
obj = nmp_object_new_link (ifi->ifi_index);
@@ -2358,6 +2494,7 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
lnk_data_complete_from_cache = FALSE;
break;
case NM_LINK_TYPE_WIREGUARD:
+ lnk_data_complete_from_cache = TRUE;
break;
default:
lnk_data_complete_from_cache = FALSE;
@@ -2410,26 +2547,6 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
}
}
- if (obj->link.type == NM_LINK_TYPE_WIREGUARD) {
- nm_auto_nmpobj NMPObject *lnk_data_now = NULL;
-
- /* The WireGuard kernel module does not yet send link update
- * notifications, so we don't actually update the cache. For
- * now, always refetch link data here. */
- lnk_data_now = nmp_object_new (NMP_OBJECT_TYPE_LNK_WIREGUARD, NULL);
- if (!_wireguard_get_link_properties (platform, &obj->link, lnk_data_now)) {
- _LOGD ("wireguard: %d %s: failed to get properties",
- obj->link.ifindex,
- obj->link.name ?: "");
- }
-
- if (lnk_data && nmp_object_cmp (lnk_data, lnk_data_now))
- nmp_object_unref (g_steal_pointer (&lnk_data));
-
- if (!lnk_data)
- lnk_data = (NMPObject *) nmp_object_ref (lnk_data_now);
- }
-
obj->_link.netlink.lnk = lnk_data;
if (need_ext_data && obj->_link.ext_data == NULL) {
@@ -2458,6 +2575,48 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
}
}
+ if (obj->link.type == NM_LINK_TYPE_WIREGUARD) {
+ const NMPObject *lnk_data_old = NULL;
+ nm_auto_nmpobj const NMPObject *lnk_data_new = NULL;
+ struct nl_sock *genl = NM_LINUX_PLATFORM_GET_PRIVATE (platform)->genl;
+
+ /* The WireGuard kernel module does not yet send link update
+ * notifications, so we don't actually update the cache. For
+ * now, always refetch link data here. */
+
+ _lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached);
+ if ( link_cached
+ && link_cached->_link.netlink.is_in_netlink
+ && link_cached->link.type == NM_LINK_TYPE_WIREGUARD) {
+ if (NMP_OBJECT_GET_TYPE (link_cached->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD)
+ lnk_data_old = link_cached->_link.netlink.lnk;
+ obj->_link.wireguard_family_id = link_cached->_link.wireguard_family_id;
+ } else
+ obj->_link.wireguard_family_id = -1;
+
+ if (obj->_link.wireguard_family_id < 0)
+ obj->_link.wireguard_family_id = genl_ctrl_resolve (genl, "wireguard");
+
+ if (obj->_link.wireguard_family_id >= 0) {
+ lnk_data_new = _wireguard_read_info (platform,
+ genl,
+ obj->_link.wireguard_family_id,
+ obj->link.ifindex);
+ }
+
+ nm_assert (!obj->_link.netlink.lnk);
+ if ( lnk_data_new
+ && ( !lnk_data_old
+ || !nmp_object_equal (lnk_data_old, lnk_data_new)))
+ obj->_link.netlink.lnk = g_steal_pointer (&lnk_data_new);
+ else {
+ /* we really want to keep the currently/old data. In particular,
+ * if we fail to fetch new information above, we stick to the
+ * stale data (instead of clearing the information). */
+ obj->_link.netlink.lnk = nmp_object_ref (lnk_data_old);
+ }
+ }
+
obj->_link.netlink.is_in_netlink = TRUE;
return g_steal_pointer (&obj);
}
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 0020acc924..7ddcf41ae5 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -5532,67 +5532,57 @@ nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize
}
const char *
-nm_platform_wireguard_peer_to_string (const NMWireGuardPeer *peer, char *buf, gsize len)
+nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *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};
- guint8 nonzero_key = 0;
- gsize i;
+ gs_free char *public_key_b64 = NULL;
+ char s_endpoint[NM_UTILS_INET_ADDRSTRLEN + 100];
+ char s_addr[NM_UTILS_INET_ADDRSTRLEN];
+ guint 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];
+ if (peer->endpoint_family == AF_INET) {
+ nm_sprintf_buf (s_endpoint,
+ " endpoint %s:%u",
+ nm_utils_inet4_ntop (peer->endpoint_addr.addr4, s_addr),
+ (guint) peer->endpoint_port);
+ } else if (peer->endpoint_family == AF_INET6) {
+ nm_sprintf_buf (s_endpoint,
+ " endpoint [%s]:%u",
+ nm_utils_inet6_ntop (&peer->endpoint_addr.addr6, s_addr),
+ (guint) peer->endpoint_port);
+ } else
+ s_endpoint[0] = '\0';
- public_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key));
+ public_key_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key));
nm_utils_strbuf_append (&buf, &len,
- "{ "
- "public_key %s "
- "%s" /* preshared key indicator */
+ "public-key %s"
+ "%s" /* preshared-key */
"%s" /* endpoint */
- "rx %"G_GUINT64_FORMAT" "
- "tx %"G_GUINT64_FORMAT" "
- "allowedips (%"G_GSIZE_FORMAT") {",
- public_b64,
- nonzero_key ? "preshared_key (hidden) " : "",
+ " rx %"G_GUINT64_FORMAT
+ " tx %"G_GUINT64_FORMAT
+ "%s", /* allowed-ips */
+ public_key_b64,
+ nm_utils_mem_all_zero (peer->preshared_key, sizeof (peer->preshared_key))
+ ? ""
+ : " preshared-key (hidden)",
s_endpoint,
peer->rx_bytes,
peer->tx_bytes,
- peer->allowedips_len);
-
-
- for (i = 0; i < peer->allowedips_len; i++) {
- NMWireGuardAllowedIP *allowedip = &peer->allowedips[i];
- const char *ret;
+ peer->allowed_ips_len > 0
+ ? " allowed-ips"
+ : "");
- ret = inet_ntop (allowedip->family, &allowedip->ip, s_address, sizeof(s_address));
+ for (i = 0; i < peer->allowed_ips_len; i++) {
+ const NMPWireGuardAllowedIP *allowed_ip = &peer->allowed_ips[i];
nm_utils_strbuf_append (&buf, &len,
" %s/%u",
- ret ? s_address : "<EAFNOSUPPORT>",
- allowedip->mask);
+ nm_utils_inet_ntop (allowed_ip->family, &allowed_ip->addr, s_addr),
+ allowed_ip->mask);
}
- nm_utils_strbuf_append_str (&buf, &len, " } }");
return buf;
}
@@ -5600,25 +5590,26 @@ 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];
+ if (!nm_utils_mem_all_zero (lnk->public_key, sizeof (lnk->public_key)))
+ public_b64 = g_base64_encode (lnk->public_key, sizeof (lnk->public_key));
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) " : "",
+ "wireguard"
+ "%s%s" /* public-key */
+ "%s" /* private-key */
+ " listen-port %u"
+ " fwmark 0x%x",
+ public_b64
+ ? " public-key "
+ : "",
+ public_b64 ?: "",
+ nm_utils_mem_all_zero (lnk->private_key, sizeof (lnk->private_key))
+ ? ""
+ : " private-key (hidden)",
lnk->listen_port,
lnk->fwmark);
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index a1171342f1..11495aff4f 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -752,11 +752,14 @@ typedef struct {
bool l3miss:1;
} NMPlatformLnkVxlan;
+#define NMP_WIREGUARD_PUBLIC_KEY_LEN 32
+#define NMP_WIREGUARD_SYMMETRIC_KEY_LEN 32
+
typedef struct {
- guint8 private_key[NM_WG_PUBLIC_KEY_LEN];
- guint8 public_key[NM_WG_PUBLIC_KEY_LEN];
- guint16 listen_port;
guint32 fwmark;
+ guint16 listen_port;
+ guint8 private_key[NMP_WIREGUARD_PUBLIC_KEY_LEN];
+ guint8 public_key[NMP_WIREGUARD_PUBLIC_KEY_LEN];
} NMPlatformLnkWireGuard;
typedef enum {
@@ -1463,7 +1466,8 @@ 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,
+struct _NMPWireGuardPeer;
+const char *nm_platform_wireguard_peer_to_string (const struct _NMPWireGuardPeer *peer,
char *buf,
gsize len);
diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c
index b0f899ce6e..058f0aee6c 100644
--- a/src/platform/nmp-object.c
+++ b/src/platform/nmp-object.c
@@ -27,6 +27,7 @@
#include <libudev.h>
#include "nm-utils.h"
+#include "nm-utils/nm-secret-utils.h"
#include "nm-core-utils.h"
#include "nm-platform-utils.h"
@@ -347,117 +348,92 @@ _vlan_xgress_qos_mappings_cpy (guint *dst_n_map,
/*****************************************************************************/
static void
-_wireguard_peers_hash_update (gsize n_peers,
- const NMWireGuardPeer *peers,
- NMHashState *h)
-{
- gsize i, j;
-
- nm_hash_update_val (h, n_peers);
- for (i = 0; i < n_peers; i++) {
- const NMWireGuardPeer *p = &peers[i];
-
- nm_hash_update (h, p->public_key, sizeof (p->public_key));
- nm_hash_update (h, p->preshared_key, sizeof (p->preshared_key));
- nm_hash_update_vals (h,
- p->persistent_keepalive_interval,
- p->allowedips_len,
- p->rx_bytes,
- p->tx_bytes,
- p->last_handshake_time.tv_sec,
- p->last_handshake_time.tv_nsec,
- p->endpoint.addr.sa_family);
-
- if (p->endpoint.addr.sa_family == AF_INET)
- nm_hash_update_val (h, p->endpoint.addr4);
- else if (p->endpoint.addr.sa_family == AF_INET6)
- nm_hash_update_val (h, p->endpoint.addr6);
- else if (p->endpoint.addr.sa_family != AF_UNSPEC)
- g_assert_not_reached ();
-
- for (j = 0; j < p->allowedips_len; j++) {
- const NMWireGuardAllowedIP *ip = &p->allowedips[j];
-
- nm_hash_update_vals (h, ip->family, ip->mask);
-
- if (ip->family == AF_INET)
- nm_hash_update_val (h, ip->ip.addr4);
- else if (ip->family == AF_INET6)
- nm_hash_update_val (h, ip->ip.addr6);
- else if (ip->family != AF_UNSPEC)
- g_assert_not_reached ();
- }
- }
+_wireguard_allowed_ip_hash_update (const NMPWireGuardAllowedIP *ip,
+ NMHashState *h)
+{
+ nm_hash_update_vals (h, ip->family,
+ ip->mask);
+
+ if (ip->family == AF_INET)
+ nm_hash_update_val (h, ip->addr.addr4);
+ else if (ip->family == AF_INET6)
+ nm_hash_update_val (h, ip->addr.addr6);
}
static int
-_wireguard_peers_cmp (gsize n_peers,
- const NMWireGuardPeer *p1,
- const NMWireGuardPeer *p2)
-{
- gsize i, j;
-
- for (i = 0; i < n_peers; i++) {
- const NMWireGuardPeer *a = &p1[i];
- const NMWireGuardPeer *b = &p2[i];
-
- NM_CMP_FIELD (a, b, last_handshake_time.tv_sec);
- NM_CMP_FIELD (a, b, last_handshake_time.tv_nsec);
- NM_CMP_FIELD (a, b, rx_bytes);
- NM_CMP_FIELD (a, b, tx_bytes);
- NM_CMP_FIELD (a, b, allowedips_len);
- NM_CMP_FIELD (a, b, persistent_keepalive_interval);
- NM_CMP_FIELD (a, b, endpoint.addr.sa_family);
- NM_CMP_FIELD_MEMCMP (a, b, public_key);
- NM_CMP_FIELD_MEMCMP (a, b, preshared_key);
-
- if (a->endpoint.addr.sa_family == AF_INET)
- NM_CMP_FIELD_MEMCMP (a, b, endpoint.addr4);
- else if (a->endpoint.addr.sa_family == AF_INET6)
- NM_CMP_FIELD_MEMCMP (a, b, endpoint.addr6);
- else if (a->endpoint.addr.sa_family != AF_UNSPEC)
- g_assert_not_reached ();
-
- for (j = 0; j < a->allowedips_len; j++) {
- const NMWireGuardAllowedIP *aip = &a->allowedips[j];
- const NMWireGuardAllowedIP *bip = &b->allowedips[j];
-
- NM_CMP_FIELD (aip, bip, family);
- NM_CMP_FIELD (aip, bip, mask);
-
- if (aip->family == AF_INET)
- NM_CMP_FIELD_MEMCMP (&aip->ip, &bip->ip, addr4);
- else if (aip->family == AF_INET6)
- NM_CMP_FIELD_MEMCMP (&aip->ip, &bip->ip, addr6);
- else if (aip->family != AF_UNSPEC)
- g_assert_not_reached ();
- }
- }
+_wireguard_allowed_ip_cmp (const NMPWireGuardAllowedIP *a,
+ const NMPWireGuardAllowedIP *b)
+{
+ NM_CMP_SELF (a, b);
+
+ NM_CMP_FIELD (a, b, family);
+ NM_CMP_FIELD (a, b, mask);
+
+ if (a->family == AF_INET)
+ NM_CMP_FIELD (a, b, addr.addr4);
+ else if (a->family == AF_INET6)
+ NM_CMP_FIELD_IN6ADDR (a, b, addr.addr6);
return 0;
}
static void
-_wireguard_peers_cpy (gsize *dst_n_peers,
- NMWireGuardPeer **dst_peers,
- gsize src_n_peers,
- const NMWireGuardPeer *src_peers)
-{
- if (src_n_peers == 0) {
- g_clear_pointer (dst_peers, g_free);
- *dst_n_peers = 0;
- } else if ( src_n_peers != *dst_n_peers
- || _wireguard_peers_cmp (src_n_peers, *dst_peers, src_peers) != 0) {
- gsize i;
- g_clear_pointer (dst_peers, g_free);
- *dst_n_peers = src_n_peers;
- if (src_n_peers > 0)
- *dst_peers = nm_memdup (src_peers, sizeof (*src_peers) * src_n_peers);
- for (i = 0; i < src_n_peers; i++) {
- dst_peers[i]->allowedips = nm_memdup (src_peers[i].allowedips, sizeof (src_peers[i].allowedips) * src_peers[i].allowedips_len);
- dst_peers[i]->allowedips_len = src_peers[i].allowedips_len;
- }
+_wireguard_peer_hash_update (const NMPWireGuardPeer *peer,
+ NMHashState *h)
+{
+ guint i;
+
+ nm_hash_update (h, peer->public_key, sizeof (peer->public_key));
+ nm_hash_update (h, peer->preshared_key, sizeof (peer->preshared_key));
+ nm_hash_update_vals (h,
+ peer->persistent_keepalive_interval,
+ peer->allowed_ips_len,
+ peer->rx_bytes,
+ peer->tx_bytes,
+ peer->last_handshake_time.tv_sec,
+ peer->last_handshake_time.tv_nsec,
+ peer->endpoint_port,
+ peer->endpoint_family);
+
+ if (peer->endpoint_family == AF_INET)
+ nm_hash_update_val (h, peer->endpoint_addr.addr4);
+ else if (peer->endpoint_family == AF_INET6)
+ nm_hash_update_val (h, peer->endpoint_addr.addr6);
+
+ for (i = 0; i < peer->allowed_ips_len; i++)
+ _wireguard_allowed_ip_hash_update (&peer->allowed_ips[i], h);
+}
+
+static int
+_wireguard_peer_cmp (const NMPWireGuardPeer *a,
+ const NMPWireGuardPeer *b)
+{
+ guint i;
+
+ NM_CMP_SELF (a, b);
+
+ NM_CMP_FIELD (a, b, last_handshake_time.tv_sec);
+ NM_CMP_FIELD (a, b, last_handshake_time.tv_nsec);
+ NM_CMP_FIELD (a, b, rx_bytes);
+ NM_CMP_FIELD (a, b, tx_bytes);
+ NM_CMP_FIELD (a, b, allowed_ips_len);
+ NM_CMP_FIELD (a, b, persistent_keepalive_interval);
+ NM_CMP_FIELD (a, b, endpoint_port);
+ NM_CMP_FIELD (a, b, endpoint_family);
+ NM_CMP_FIELD_MEMCMP (a, b, public_key);
+ NM_CMP_FIELD_MEMCMP (a, b, preshared_key);
+
+ if (a->endpoint_family == AF_INET)
+ NM_CMP_FIELD (a, b, endpoint_addr.addr4);
+ else if (a->endpoint_family == AF_INET6)
+ NM_CMP_FIELD_IN6ADDR (a, b, endpoint_addr.addr6);
+
+ for (i = 0; i < a->allowed_ips_len; i++) {
+ NM_CMP_RETURN (_wireguard_allowed_ip_cmp (&a->allowed_ips[i],
+ &b->allowed_ips[i]));
}
+
+ return 0;
}
/*****************************************************************************/
@@ -587,12 +563,25 @@ _vt_cmd_obj_dispose_lnk_vlan (NMPObject *obj)
}
static void
-_vt_cmd_obj_dispose_lnk_wireguard (NMPObject *obj)
+_wireguard_clear (NMPObjectLnkWireGuard *lnk)
{
- if (obj->_lnk_wireguard.peers_len)
- g_free (obj->_lnk_wireguard.peers[0].allowedips);
+ guint i;
+
+ nm_explicit_bzero (lnk->_public.private_key,
+ sizeof (lnk->_public.private_key));
+ for (i = 0; i < lnk->peers_len; i++) {
+ NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &lnk->peers[i];
+
+ nm_explicit_bzero (peer->preshared_key, sizeof (peer->preshared_key));
+ }
+ g_free ((gpointer) lnk->peers);
+ g_free ((gpointer) lnk->_allowed_ips_buf);
+}
- g_free (obj->_lnk_wireguard.peers);
+static void
+_vt_cmd_obj_dispose_lnk_wireguard (NMPObject *obj)
+{
+ _wireguard_clear (&obj->_lnk_wireguard);
}
static NMPObject *
@@ -859,7 +848,7 @@ _vt_cmd_obj_to_string_lnk_wireguard (const NMPObject *obj, NMPObjectToStringMode
const NMPClass *klass;
char buf2[sizeof (_nm_utils_to_string_buffer)];
char *b;
- gsize i, l;
+ guint i;
klass = NMP_OBJECT_GET_CLASS (obj);
@@ -871,23 +860,26 @@ _vt_cmd_obj_to_string_lnk_wireguard (const NMPObject *obj, NMPObjectToStringMode
b = buf;
nm_utils_strbuf_append (&b, &buf_size,
- "[%s,%p,%u,%calive,%cvisible; %s "
- "peers (%" G_GSIZE_FORMAT ") {",
+ "[%s,%p,%u,%calive,%cvisible; %s"
+ "%s",
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);
+ obj->_lnk_wireguard.peers_len > 0
+ ? " peers {"
+ : "");
for (i = 0; i < obj->_lnk_wireguard.peers_len; i++) {
- const NMWireGuardPeer *peer = &obj->_lnk_wireguard.peers[i];
+ const NMPWireGuardPeer *peer = &obj->_lnk_wireguard.peers[i];
+
+ nm_utils_strbuf_append_str (&b, &buf_size, " { ");
nm_platform_wireguard_peer_to_string (peer, b, buf_size);
- l = strlen (b);
- b += l;
- buf_size -= l;
+ nm_utils_strbuf_seek_end (&b, &buf_size);
+ nm_utils_strbuf_append_str (&b, &buf_size, " }");
}
-
- nm_utils_strbuf_append_str (&b, &buf_size, " }");
+ if (obj->_lnk_wireguard.peers_len)
+ nm_utils_strbuf_append_str (&b, &buf_size, " }");
return buf;
case NMP_OBJECT_TO_STRING_PUBLIC:
@@ -947,6 +939,7 @@ _vt_cmd_obj_hash_update_link (const NMPObject *obj, NMHashState *h)
nm_platform_link_hash_update (&obj->link, h);
nm_hash_update_vals (h,
obj->_link.netlink.is_in_netlink,
+ obj->_link.wireguard_family_id,
obj->_link.udev.device);
if (obj->_link.netlink.lnk)
nmp_object_hash_update (obj->_link.netlink.lnk, h);
@@ -969,10 +962,15 @@ _vt_cmd_obj_hash_update_lnk_vlan (const NMPObject *obj, NMHashState *h)
static void
_vt_cmd_obj_hash_update_lnk_wireguard (const NMPObject *obj, NMHashState *h)
{
+ guint i;
+
nm_assert (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LNK_WIREGUARD);
nm_platform_lnk_wireguard_hash_update (&obj->lnk_wireguard, h);
- _wireguard_peers_hash_update (obj->_lnk_wireguard.peers_len, obj->_lnk_wireguard.peers, h);
+
+ nm_hash_update_val (h, obj->_lnk_wireguard.peers_len);
+ for (i = 0; i < obj->_lnk_wireguard.peers_len; i++)
+ _wireguard_peer_hash_update (&obj->_lnk_wireguard.peers[i], h);
}
int
@@ -980,12 +978,7 @@ nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2)
{
const NMPClass *klass1, *klass2;
- if (obj1 == obj2)
- return 0;
- if (!obj1)
- return -1;
- if (!obj2)
- return 1;
+ NM_CMP_SELF (obj1, obj2);
g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj1), -1);
g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj2), 1);
@@ -1006,16 +999,11 @@ nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2)
static int
_vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2)
{
- int i;
+ NM_CMP_RETURN (nm_platform_link_cmp (&obj1->link, &obj2->link));
+ NM_CMP_DIRECT (obj1->_link.netlink.is_in_netlink, obj2->_link.netlink.is_in_netlink);
+ NM_CMP_RETURN (nmp_object_cmp (obj1->_link.netlink.lnk, obj2->_link.netlink.lnk));
+ NM_CMP_DIRECT (obj1->_link.wireguard_family_id, obj2->_link.wireguard_family_id);
- i = nm_platform_link_cmp (&obj1->link, &obj2->link);
- if (i)
- return i;
- if (obj1->_link.netlink.is_in_netlink != obj2->_link.netlink.is_in_netlink)
- return obj1->_link.netlink.is_in_netlink ? -1 : 1;
- i = nmp_object_cmp (obj1->_link.netlink.lnk, obj2->_link.netlink.lnk);
- if (i)
- return i;
if (obj1->_link.udev.device != obj2->_link.udev.device) {
if (!obj1->_link.udev.device)
return -1;
@@ -1028,6 +1016,7 @@ _vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2)
* Have this check as very last. */
return (obj1->_link.udev.device < obj2->_link.udev.device) ? -1 : 1;
}
+
return 0;
}
@@ -1056,16 +1045,16 @@ _vt_cmd_obj_cmp_lnk_vlan (const NMPObject *obj1, const NMPObject *obj2)
static int
_vt_cmd_obj_cmp_lnk_wireguard (const NMPObject *obj1, const NMPObject *obj2)
{
- int c;
+ guint i;
- c = nm_platform_lnk_wireguard_cmp (&obj1->lnk_wireguard, &obj2->lnk_wireguard);
- if (c)
- return c;
+ NM_CMP_RETURN (nm_platform_lnk_wireguard_cmp (&obj1->lnk_wireguard, &obj2->lnk_wireguard));
+
+ NM_CMP_FIELD (obj1, obj2, _lnk_wireguard.peers_len);
- if (obj1->_lnk_wireguard.peers_len != obj2->_lnk_wireguard.peers_len)
- return obj1->_lnk_wireguard.peers_len < obj2->_lnk_wireguard.peers_len ? -1 : 1;
+ for (i = 0; i < obj1->_lnk_wireguard.peers_len; i++)
+ NM_CMP_RETURN (_wireguard_peer_cmp (&obj1->_lnk_wireguard.peers[i], &obj2->_lnk_wireguard.peers[i]));
- return _wireguard_peers_cmp(obj1->_lnk_wireguard.peers_len, obj1->_lnk_wireguard.peers, obj2->_lnk_wireguard.peers);
+ return 0;
}
/* @src is a const object, which is not entirely correct for link types, where
@@ -1137,9 +1126,36 @@ _vt_cmd_obj_copy_lnk_vlan (NMPObject *dst, const NMPObject *src)
static void
_vt_cmd_obj_copy_lnk_wireguard (NMPObject *dst, const NMPObject *src)
{
- dst->lnk_wireguard = src->lnk_wireguard;
- _wireguard_peers_cpy (&dst->_lnk_wireguard.peers_len, &dst->_lnk_wireguard.peers,
- src->_lnk_wireguard.peers_len, src->_lnk_wireguard.peers);
+ guint i;
+
+ nm_assert (dst != src);
+
+ _wireguard_clear (&dst->_lnk_wireguard);
+
+ dst->_lnk_wireguard = src->_lnk_wireguard;
+
+ dst->_lnk_wireguard.peers = nm_memdup (dst->_lnk_wireguard.peers,
+ sizeof (NMPWireGuardPeer) * dst->_lnk_wireguard.peers_len);
+ dst->_lnk_wireguard._allowed_ips_buf = nm_memdup (dst->_lnk_wireguard._allowed_ips_buf,
+ sizeof (NMPWireGuardAllowedIP) * dst->_lnk_wireguard._allowed_ips_buf_len);
+
+ /* all the peers' pointers point into the buffer. They need to be readjusted. */
+ for (i = 0; i < dst->_lnk_wireguard.peers_len; i++) {
+ NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &dst->_lnk_wireguard.peers[i];
+
+ if (peer->allowed_ips_len == 0) {
+ nm_assert (!peer->allowed_ips);
+ continue;
+ }
+ nm_assert (dst->_lnk_wireguard._allowed_ips_buf_len > 0);
+ nm_assert (src->_lnk_wireguard._allowed_ips_buf);
+ nm_assert (peer->allowed_ips >= src->_lnk_wireguard._allowed_ips_buf);
+ nm_assert (&peer->allowed_ips[peer->allowed_ips_len] <= &src->_lnk_wireguard._allowed_ips_buf[src->_lnk_wireguard._allowed_ips_buf_len]);
+
+ peer->allowed_ips = &dst->_lnk_wireguard._allowed_ips_buf[peer->allowed_ips - src->_lnk_wireguard._allowed_ips_buf];
+ }
+
+ nm_assert (nmp_object_equal (src, dst));
}
#define _vt_cmd_plobj_id_copy(type, plat_type, cmd) \
@@ -3084,4 +3100,3 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.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 ba63a3a34e..67d975782e 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -27,6 +27,36 @@
struct udev_device;
+/*****************************************************************************/
+
+typedef struct {
+ NMIPAddr addr;
+ guint8 family;
+ guint8 mask;
+} NMPWireGuardAllowedIP;
+
+typedef struct _NMPWireGuardPeer {
+ NMIPAddr endpoint_addr;
+ struct timespec last_handshake_time;
+ guint64 rx_bytes;
+ guint64 tx_bytes;
+ union {
+ const NMPWireGuardAllowedIP *allowed_ips;
+ guint _construct_idx_start;
+ };
+ union {
+ guint allowed_ips_len;
+ guint _construct_idx_end;
+ };
+ guint16 persistent_keepalive_interval;
+ guint16 endpoint_port;
+ guint8 public_key[NMP_WIREGUARD_PUBLIC_KEY_LEN];
+ guint8 preshared_key[NMP_WIREGUARD_SYMMETRIC_KEY_LEN];
+ guint8 endpoint_family;
+} NMPWireGuardPeer;
+
+/*****************************************************************************/
+
typedef enum { /*< skip >*/
NMP_OBJECT_TO_STRING_ID,
NMP_OBJECT_TO_STRING_PUBLIC,
@@ -220,9 +250,10 @@ typedef struct {
typedef struct {
NMPlatformLnkWireGuard _public;
-
- gsize peers_len;
- NMWireGuardPeer *peers;
+ const NMPWireGuardPeer *peers;
+ const NMPWireGuardAllowedIP *_allowed_ips_buf;
+ guint peers_len;
+ guint _allowed_ips_buf_len;
} NMPObjectLnkWireGuard;
typedef struct {