platform/wireguard: rework parsing wireguard links in platform

- 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.
  The parsing of the netlink message is the complicated part, because
  we don't know upfront how many peers/allowed-ips we receive. During
  construction, the tracking of peers/allowed-ips is complicated,
  via a CList/GArray. At the end of that, we prettify the data
  representation and put everything into two buffers. That is more
  efficient and simpler for user afterwards. This moves complexity
  to the way how the object is created, vs. how it is used later.

- ensure that we nm_explicit_bzero() private-key and preshared-key. However,
  that only works to a certain point, because our netlink library does not
  ensure that no data is leaked.

- don't use a "struct sockaddr" union for the peer's endpoint. Instead,
  use a combintation of endpoint_family, endpoint_port, and
  endpoint_addr.

- a lot of refactoring.
This commit is contained in:
Thomas Haller
2018-09-07 09:54:07 +02:00
parent cb23779e0a
commit 62d14e1884
7 changed files with 550 additions and 362 deletions

View File

@@ -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 \

View File

@@ -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);
}

View File

@@ -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 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, 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 (!tb[WGALLOWEDIP_A_FAMILY])
return FALSE;
if (tba[WGALLOWEDIP_A_FAMILY])
allowedip->family = nla_get_u16 (tba[WGALLOWEDIP_A_FAMILY]);
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 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,10 +1976,8 @@ _wireguard_update_from_peers_nla (struct _wireguard_device_buf *buf,
[WGPEER_A_TX_BYTES] = { .type = NLA_U64 },
[WGPEER_A_ALLOWEDIPS] = { .type = NLA_NESTED },
};
WireGuardPeerConstruct *peer_c;
struct nlattr *tb[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 };
if (nla_parse_nested (tb, WGPEER_A_MAX, peer_attr, policy) < 0)
return FALSE;
@@ -1990,51 +1986,98 @@ _wireguard_update_from_peers_nla (struct _wireguard_device_buf *buf,
return FALSE;
/* a peer with the same public key as last peer is just a continuation for extra AllowedIPs */
if ( last
&& !memcmp (nla_data (tb[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 message is a continuation of the previous peer.
* Only parse WGPEER_A_ALLOWEDIPS below. */
}
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);
peer_c = g_slice_new0 (WireGuardPeerConstruct);
c_list_link_tail (peers, &peer_c->lst);
nla_memcpy (&peer->public_key, tb[WGPEER_A_PUBLIC_KEY], sizeof (peer->public_key));
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->preshared_key, tb[WGPEER_A_PRESHARED_KEY], sizeof (peer->preshared_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]) {
struct sockaddr *addr = nla_data (tb[WGPEER_A_ENDPOINT]);
if (addr->sa_family == AF_INET)
nla_memcpy (&peer->endpoint.addr4, tb[WGPEER_A_ENDPOINT], sizeof (peer->endpoint.addr4));
else if (addr->sa_family == AF_INET6)
nla_memcpy (&peer->endpoint.addr6, tb[WGPEER_A_ENDPOINT], sizeof (peer->endpoint.addr6));
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->persistent_keepalive_interval = nla_get_u64 (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->last_handshake_time, tb[WGPEER_A_LAST_HANDSHAKE_TIME], sizeof (peer->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->rx_bytes = nla_get_u64 (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->tx_bytes = nla_get_u64 (tb[WGPEER_A_TX_BYTES]);
peer->allowedips = NULL;
peer->allowedips_len = 0;
peer_c->data.tx_bytes = nla_get_u64 (tb[WGPEER_A_TX_BYTES]);
}
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 (!_wireguard_update_from_allowedips_nla (buf, attr))
return FALSE;
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;
}
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 +2091,196 @@ _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;
WireGuardParseData *parse_data = arg;
struct nlattr *tb[WGDEVICE_A_MAX + 1];
NMPlatformLnkWireGuard *props = &buf->obj->lnk_wireguard;
struct nlmsghdr *nlh = nlmsg_hdr (msg);
int nlerr;
nlerr = genlmsg_parse (nlh, 0, tb, WGDEVICE_A_MAX, policy);
nlerr = genlmsg_parse (nlmsg_hdr (msg), 0, tb, WGDEVICE_A_MAX, policy);
if (nlerr < 0)
return NL_SKIP;
if (tb[WGDEVICE_A_PRIVATE_KEY])
nla_memcpy (props->private_key, tb[WGDEVICE_A_PRIVATE_KEY], sizeof (props->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 (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) {
/* we already have an object instance. This means the netlink message
* is a continuation, only providing more WGDEVICE_A_PEERS data below. */
} else {
NMPObject *obj;
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]);
parse_data->obj = obj;
}
if (tb[WGDEVICE_A_PEERS]) {
struct nlattr *attr;
int rem;
nla_for_each_nested (attr, tb[WGDEVICE_A_PEERS], rem) {
if (!_wireguard_update_from_peers_nla (buf, attr))
return NL_SKIP;
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 = {
.valid_cb = _wireguard_get_device_cb,
.valid_arg = &buf,
};
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, link->ifindex);
NLA_PUT_U32 (msg, WGDEVICE_A_IFINDEX, (guint32) ifindex);
if (nl_send_auto (priv->genl, msg) < 0)
goto err;
if (nl_send_auto (genl, msg) < 0)
return NULL;
if (nl_recvmsgs (priv->genl, &cb) < 0)
goto err;
c_list_init (&parse_data.peers);
/* 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);
/* we ignore errors, and return whatever we could successfully
* parse. */
nl_recvmsgs (genl,
&((const struct nl_cb) {
.valid_cb = _wireguard_get_device_cb,
.valid_arg = (gpointer) &parse_data,
}));
p->allowedips = &g_array_index (buf.allowedips, NMWireGuardAllowedIP, j);
j += p->allowedips_len;
/* unpack: transfer ownership */
obj = parse_data.obj;
allowed_ips = parse_data.allowed_ips;
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 netlink messages. Hence, while
* parsing the dump, we don't know upfront 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 growing the array, but we want to bzero()
* the preshared-key of each peer while reallocating. The CList apprach avoids
* that.
*
* For allowed-ips, we instead track one GArray, which are all appended
* there. The realloc/resize of the GArray is fine 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 be convered to actual pointers blow.
*
* This is all done during parsing. In the final NMPObjectLnkWireGuard we
* don't want the CList anymore and repackage the NMPObject tightly. The
* reason is, that NMPObject instances are immutable and long-living. Spend
* a bit effort below during construction to obtain a most suitable representation
* in this regard. */
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;
return TRUE;
/* duplicate allowed_ips instead of using the pointer. The GArray possibly has more
* space allocated then we need, and we want to get rid of this excess buffer.
* Note that NMPObject instance is possibly put into the cache and long-living. */
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 *) nm_memdup (allowed_ips->data,
sizeof (NMPWireGuardAllowedIP) * allowed_ips->len)
: 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 != 0) {
guint len;
nm_assert (obj->_lnk_wireguard._allowed_ips_buf);
nm_assert (peer->_construct_idx_end > peer->_construct_idx_start);
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 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);
}
/*****************************************************************************/
@@ -2188,7 +2332,7 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
gboolean completed_from_cache_val = FALSE;
gboolean *completed_from_cache = cache ? &completed_from_cache_val : NULL;
const NMPObject *link_cached = NULL;
NMPObject *lnk_data = NULL;
const NMPObject *lnk_data = NULL;
gboolean address_complete_from_cache = TRUE;
gboolean lnk_data_complete_from_cache = TRUE;
gboolean need_ext_data = FALSE;
@@ -2197,10 +2341,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 +2504,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;
@@ -2386,7 +2533,7 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
* Also, sometimes the info-data is missing for updates. In this case
* we want to keep the previously received lnk_data. */
nmp_object_unref (lnk_data);
lnk_data = (NMPObject *) nmp_object_ref (link_cached->_link.netlink.lnk);
lnk_data = nmp_object_ref (link_cached->_link.netlink.lnk);
}
if ( need_ext_data
@@ -2411,29 +2558,10 @@ _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) {
if ( need_ext_data
&& obj->_link.ext_data == NULL) {
switch (obj->link.type) {
case NM_LINK_TYPE_WIFI:
obj->_link.ext_data = (GObject *) nm_wifi_utils_new (ifi->ifi_index,
@@ -2459,6 +2587,42 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
}
}
if (obj->link.type == NM_LINK_TYPE_WIREGUARD) {
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)
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);
}
if ( lnk_data_new
&& obj->_link.netlink.lnk
&& nmp_object_equal (obj->_link.netlink.lnk, lnk_data_new))
nmp_object_unref (lnk_data_new);
else {
nmp_object_unref (obj->_link.netlink.lnk);
obj->_link.netlink.lnk = lnk_data_new;
}
}
obj->_link.netlink.is_in_netlink = TRUE;
return g_steal_pointer (&obj);
}

View File

@@ -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_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';
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));
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);
peer->allowed_ips_len > 0
? " allowed-ips"
: "");
for (i = 0; i < peer->allowedips_len; i++) {
NMWireGuardAllowedIP *allowedip = &peer->allowedips[i];
const char *ret;
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);

View File

@@ -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);

View File

@@ -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)
_wireguard_allowed_ip_hash_update (const NMPWireGuardAllowedIP *ip,
NMHashState *h)
{
gsize i, j;
nm_hash_update_vals (h, ip->family,
ip->mask);
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 ();
}
}
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)
_wireguard_allowed_ip_cmp (const NMPWireGuardAllowedIP *a,
const NMPWireGuardAllowedIP *b)
{
gsize i, j;
NM_CMP_SELF (a, b);
for (i = 0; i < n_peers; i++) {
const NMWireGuardPeer *a = &p1[i];
const NMWireGuardPeer *b = &p2[i];
NM_CMP_FIELD (a, b, family);
NM_CMP_FIELD (a, b, mask);
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 ();
}
}
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)
_wireguard_peer_hash_update (const NMPWireGuardPeer *peer,
NMHashState *h)
{
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;
}
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;
}
/*****************************************************************************/
@@ -586,13 +562,26 @@ _vt_cmd_obj_dispose_lnk_vlan (NMPObject *obj)
g_free ((gpointer) obj->_lnk_vlan.egress_qos_map);
}
static void
_wireguard_clear (NMPObjectLnkWireGuard *lnk)
{
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);
}
static void
_vt_cmd_obj_dispose_lnk_wireguard (NMPObject *obj)
{
if (obj->_lnk_wireguard.peers_len)
g_free (obj->_lnk_wireguard.peers[0].allowedips);
g_free (obj->_lnk_wireguard.peers);
_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];
nm_platform_wireguard_peer_to_string (peer, b, buf_size);
l = strlen (b);
b += l;
buf_size -= l;
}
const NMPWireGuardPeer *peer = &obj->_lnk_wireguard.peers[i];
nm_utils_strbuf_append_str (&b, &buf_size, " }");
nm_utils_strbuf_append_str (&b, &buf_size, " { ");
nm_platform_wireguard_peer_to_string (peer, b, buf_size);
nm_utils_strbuf_seek_end (&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));
if (obj1->_lnk_wireguard.peers_len != obj2->_lnk_wireguard.peers_len)
return obj1->_lnk_wireguard.peers_len < obj2->_lnk_wireguard.peers_len ? -1 : 1;
NM_CMP_FIELD (obj1, obj2, _lnk_wireguard.peers_len);
return _wireguard_peers_cmp(obj1->_lnk_wireguard.peers_len, obj1->_lnk_wireguard.peers, obj2->_lnk_wireguard.peers);
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 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,
},
};

View File

@@ -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,
@@ -168,6 +198,9 @@ typedef struct {
/* Auxiliary data object for Wi-Fi and WPAN */
GObject *ext_data;
/* FIXME: not every NMPObjectLink should pay the price for tracking
* the wireguard family id. This should be tracked via ext_data, which
* would be exactly the right place. */
int wireguard_family_id;
} NMPObjectLink;
@@ -220,9 +253,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 {