summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-12-25 18:41:28 +0100
committerThomas Haller <thaller@redhat.com>2019-01-08 10:48:52 +0100
commit2fab3da78b9ff4ad273cb54834ad584408260770 (patch)
tree8cf8143594932bd4ee06c12826b0928878123e3f
parent756aec8d9259a371915f46935f978cfef923f030 (diff)
downloadNetworkManager-th/wireguard-pt2.tar.gz
platform: create wireguard netdev interfaceth/wireguard-pt2
The netlink code for WG_CMD_SET_DEVICE is strongly inspired by WireGuard ([1]) and systemd ([2]). Currently, nm_platform_link_wireguard_change() always aims to reset all peers and allowed-ips settings. I think that should be improved in the future, to support only partial updates. [1] https://git.zx2c4.com/WireGuard/tree/contrib/examples/embeddable-wg-library/wireguard.c?id=5e99a6d43fe2351adf36c786f5ea2086a8fe7ab8#n1073 [2] https://github.com/systemd/systemd/blob/04ca4d191b13e79e5701ed22dc972f08628d7bcc/src/network/netdev/wireguard.c#L48
-rw-r--r--src/platform/nm-linux-platform.c339
-rw-r--r--src/platform/nm-platform.c55
-rw-r--r--src/platform/nm-platform.h19
-rw-r--r--src/platform/nmp-object.h4
-rw-r--r--src/platform/tests/test-link.c273
5 files changed, 679 insertions, 11 deletions
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 2979ee5d38..7db6a9261e 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -187,6 +187,12 @@ G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1));
#define WG_CMD_GET_DEVICE 0
#define WG_CMD_SET_DEVICE 1
+#define WGDEVICE_F_REPLACE_PEERS ((guint32) (1U << 0))
+
+#define WGPEER_F_REMOVE_ME ((guint32) (1U << 0))
+#define WGPEER_F_REPLACE_ALLOWEDIPS ((guint32) (1U << 1))
+
+
#define WGDEVICE_A_UNSPEC 0
#define WGDEVICE_A_IFINDEX 1
#define WGDEVICE_A_IFNAME 2
@@ -2164,9 +2170,9 @@ _wireguard_get_device_cb (struct nl_msg *msg, void *arg)
static const NMPObject *
_wireguard_read_info (NMPlatform *platform /* used only as logging context */,
- struct nl_sock *genl,
- int wireguard_family_id,
- int ifindex)
+ struct nl_sock *genl,
+ int wireguard_family_id,
+ int ifindex)
{
nm_auto_nlmsg struct nl_msg *msg = NULL;
NMPObject *obj = NULL;
@@ -2182,6 +2188,8 @@ _wireguard_read_info (NMPlatform *platform /* used only as logging context */,
nm_assert (wireguard_family_id >= 0);
nm_assert (ifindex > 0);
+ _LOGT ("wireguard: fetching infomation for ifindex %d (genl-id %d)...", ifindex, wireguard_family_id);
+
msg = nlmsg_alloc ();
if (!genlmsg_put (msg,
@@ -2290,6 +2298,330 @@ nla_put_failure:
g_return_val_if_reached (NULL);
}
+static int
+_wireguard_get_family_id (NMPlatform *platform, int ifindex_try)
+{
+ NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+ int wireguard_family_id = -1;
+
+ if (ifindex_try > 0) {
+ const NMPlatformLink *plink;
+
+ if (nm_platform_link_get_lnk_wireguard (platform, ifindex_try, &plink))
+ wireguard_family_id = NMP_OBJECT_UP_CAST (plink)->_link.wireguard_family_id;
+ }
+ if (wireguard_family_id < 0)
+ wireguard_family_id = genl_ctrl_resolve (priv->genl, "wireguard");
+ return wireguard_family_id;
+}
+
+static const NMPObject *
+_wireguard_refresh_link (NMPlatform *platform,
+ int wireguard_family_id,
+ int ifindex)
+{
+ NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ nm_auto_nmpobj const NMPObject *obj_new = NULL;
+ nm_auto_nmpobj const NMPObject *lnk_new = NULL;
+ NMPCacheOpsType cache_op;
+ const NMPObject *plink = NULL;
+ nm_auto_nmpobj NMPObject *obj = NULL;
+
+ nm_assert (wireguard_family_id >= 0);
+ nm_assert (ifindex > 0);
+
+ nm_platform_process_events (platform);
+
+ plink = nm_platform_link_get_obj (platform, ifindex, TRUE);
+
+ if ( !plink
+ || plink->link.type != NM_LINK_TYPE_WIREGUARD) {
+ nm_platform_link_refresh (platform, ifindex);
+ plink = nm_platform_link_get_obj (platform, ifindex, TRUE);
+ if ( !plink
+ || plink->link.type != NM_LINK_TYPE_WIREGUARD)
+ return NULL;
+ if (NMP_OBJECT_GET_TYPE (plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD)
+ lnk_new = nmp_object_ref (plink->_link.netlink.lnk);
+ } else {
+ lnk_new = _wireguard_read_info (platform,
+ priv->genl,
+ wireguard_family_id,
+ ifindex);
+ if (!lnk_new) {
+ if (NMP_OBJECT_GET_TYPE (plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD)
+ lnk_new = nmp_object_ref (plink->_link.netlink.lnk);
+ } else if (nmp_object_equal (plink->_link.netlink.lnk, lnk_new)) {
+ nmp_object_unref (lnk_new);
+ lnk_new = nmp_object_ref (plink->_link.netlink.lnk);
+ }
+ }
+
+ if ( plink->_link.wireguard_family_id == wireguard_family_id
+ && plink->_link.netlink.lnk == lnk_new)
+ return plink;
+
+ /* we use nmp_cache_update_netlink() to re-inject the new object into the cache.
+ * For that, we need to clone it, and tweak it so that it's suitable. It's a bit
+ * of a hack, in particular that we need to clear driver and udev-device. */
+ obj = nmp_object_clone (plink, FALSE);
+ obj->_link.wireguard_family_id = wireguard_family_id;
+ nmp_object_unref (obj->_link.netlink.lnk);
+ obj->_link.netlink.lnk = g_steal_pointer (&lnk_new);
+ obj->link.driver = NULL;
+ nm_clear_pointer (&obj->_link.udev.device, udev_device_unref);
+
+ cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform),
+ obj,
+ FALSE,
+ &obj_old,
+ &obj_new);
+ nm_assert (NM_IN_SET (cache_op, NMP_CACHE_OPS_UPDATED));
+ if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
+ cache_on_change (platform, cache_op, obj_old, obj_new);
+ nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
+ }
+
+ nm_assert ( !obj_new
+ || ( NMP_OBJECT_GET_TYPE (obj_new) == NMP_OBJECT_TYPE_LINK
+ && obj_new->link.type == NM_LINK_TYPE_WIREGUARD
+ && ( !obj_new->_link.netlink.lnk
+ || NMP_OBJECT_GET_TYPE (obj_new->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD)));
+ return obj_new;
+}
+
+static int
+_wireguard_create_change_nlmsgs (NMPlatform *platform,
+ int ifindex,
+ int wireguard_family_id,
+ const NMPlatformLnkWireGuard *lnk_wireguard,
+ const NMPWireGuardPeer *peers,
+ guint peers_len,
+ GPtrArray **out_msgs)
+{
+ gs_unref_ptrarray GPtrArray *msgs = NULL;
+ nm_auto_nlmsg struct nl_msg *msg = NULL;
+ const guint IDX_NIL = G_MAXUINT;
+ guint idx_peer_curr;
+ guint idx_allowed_ips_curr;
+ struct nlattr *nest_peers;
+ struct nlattr *nest_curr_peer;
+ struct nlattr *nest_allowed_ips;
+ struct nlattr *nest_curr_allowed_ip;
+
+#define _nla_nest_end(msg, nest_start) \
+ G_STMT_START { \
+ if (nla_nest_end ((msg), (nest_start)) < 0) \
+ g_return_val_if_reached (-NME_BUG); \
+ } G_STMT_END
+
+ /* Adapted from LGPL-2.1+ code [1].
+ *
+ * [1] https://git.zx2c4.com/WireGuard/tree/contrib/examples/embeddable-wg-library/wireguard.c?id=5e99a6d43fe2351adf36c786f5ea2086a8fe7ab8#n1073 */
+
+ idx_peer_curr = IDX_NIL;
+ idx_allowed_ips_curr = IDX_NIL;
+
+ /* TODO: for the moment, we always reset all peers and allowed-ips (WGDEVICE_F_REPLACE_PEERS, WGPEER_F_REPLACE_ALLOWEDIPS).
+ * The platform API should be extended to also support partial updates. In particular, configuring the same configuration
+ * multiple times, should not clear and re-add all settings, but rather sync the existing settings with the desired configuration. */
+
+again:
+
+ msg = nlmsg_alloc ();
+ if (!genlmsg_put (msg,
+ NL_AUTO_PORT,
+ NL_AUTO_SEQ,
+ wireguard_family_id,
+ 0,
+ NLM_F_REQUEST,
+ WG_CMD_SET_DEVICE,
+ 1))
+ g_return_val_if_reached (-NME_BUG);
+
+ NLA_PUT_U32 (msg, WGDEVICE_A_IFINDEX, (guint32) ifindex);
+
+ if (idx_peer_curr == IDX_NIL) {
+ NLA_PUT (msg, WGDEVICE_A_PRIVATE_KEY, sizeof (lnk_wireguard->private_key), lnk_wireguard->private_key);
+ NLA_PUT_U16 (msg, WGDEVICE_A_LISTEN_PORT, lnk_wireguard->listen_port);
+ NLA_PUT_U32 (msg, WGDEVICE_A_FWMARK, lnk_wireguard->fwmark);
+ NLA_PUT_U32 (msg, WGDEVICE_A_FLAGS, WGDEVICE_F_REPLACE_PEERS);
+ }
+
+ if (peers_len == 0)
+ goto send;
+
+ nest_curr_peer = NULL;
+ nest_allowed_ips = NULL;
+ nest_curr_allowed_ip = NULL;
+
+ nest_peers = nla_nest_start (msg, WGDEVICE_A_PEERS);
+ if (!nest_peers)
+ g_return_val_if_reached (-NME_BUG);
+
+ if (idx_peer_curr == IDX_NIL)
+ idx_peer_curr = 0;
+ for (; idx_peer_curr < peers_len; idx_peer_curr++) {
+ const NMPWireGuardPeer *p = &peers[idx_peer_curr];
+
+ nest_curr_peer = nla_nest_start (msg, 0);
+ if (!nest_curr_peer)
+ goto toobig_peers;
+
+ if (nla_put (msg, WGPEER_A_PUBLIC_KEY, NMP_WIREGUARD_PUBLIC_KEY_LEN, p->public_key) < 0)
+ goto toobig_peers;
+
+ if (idx_allowed_ips_curr == IDX_NIL) {
+
+ if (nla_put (msg, WGPEER_A_PRESHARED_KEY, sizeof (p->preshared_key), p->preshared_key) < 0)
+ goto toobig_peers;
+
+ if (nla_put_uint16 (msg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, p->persistent_keepalive_interval) < 0)
+ goto toobig_peers;
+
+ if (nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS) < 0)
+ goto toobig_peers;
+
+ g_return_val_if_fail (NM_IN_SET (p->endpoint.sa.sa_family, AF_INET, AF_INET6), -NME_BUG);
+
+ if (nla_put (msg,
+ WGPEER_A_ENDPOINT,
+ p->endpoint.sa.sa_family == AF_INET
+ ? sizeof (p->endpoint.in)
+ : sizeof (p->endpoint.in6),
+ &p->endpoint) < 0)
+ goto toobig_peers;
+ }
+
+ if (p->allowed_ips_len > 0) {
+ if (idx_allowed_ips_curr == IDX_NIL)
+ idx_allowed_ips_curr = 0;
+
+ nest_allowed_ips = nla_nest_start (msg, WGPEER_A_ALLOWEDIPS);
+ if (!nest_allowed_ips)
+ goto toobig_allowedips;
+
+ for (; idx_allowed_ips_curr < p->allowed_ips_len; idx_allowed_ips_curr++) {
+ const NMPWireGuardAllowedIP *aip = &p->allowed_ips[idx_allowed_ips_curr];
+
+ nest_curr_allowed_ip = nla_nest_start (msg, 0);
+ if (!nest_curr_allowed_ip)
+ goto toobig_allowedips;
+
+ g_return_val_if_fail (NM_IN_SET (aip->family, AF_INET, AF_INET6), -NME_BUG);
+
+ if (nla_put_uint16 (msg, WGALLOWEDIP_A_FAMILY, aip->family) < 0)
+ goto toobig_allowedips;
+ if (nla_put (msg,
+ WGALLOWEDIP_A_IPADDR,
+ nm_utils_addr_family_to_size (aip->family),
+ &aip->addr) < 0)
+ goto toobig_allowedips;
+ if (nla_put_uint8 (msg, WGALLOWEDIP_A_CIDR_MASK, aip->mask) < 0)
+ goto toobig_allowedips;
+
+ _nla_nest_end (msg, nest_curr_allowed_ip);
+ nest_curr_allowed_ip = NULL;
+ }
+ idx_allowed_ips_curr = IDX_NIL;
+
+ _nla_nest_end (msg, nest_allowed_ips);
+ nest_allowed_ips = NULL;
+ }
+
+ _nla_nest_end (msg, nest_curr_peer);
+ nest_curr_peer = NULL;
+ }
+
+ _nla_nest_end (msg, nest_peers);
+ goto send;
+
+toobig_allowedips:
+ if (nest_curr_allowed_ip)
+ nla_nest_cancel (msg, nest_curr_allowed_ip);
+ if (nest_allowed_ips)
+ nla_nest_cancel (msg, nest_allowed_ips);
+ _nla_nest_end (msg, nest_curr_peer);
+ _nla_nest_end (msg, nest_peers);
+ goto send;
+
+toobig_peers:
+ if (nest_curr_peer)
+ nla_nest_cancel (msg, nest_curr_peer);
+ _nla_nest_end (msg, nest_peers);
+ goto send;
+
+send:
+ if (!msgs)
+ msgs = g_ptr_array_new_with_free_func ((GDestroyNotify) nlmsg_free);
+ g_ptr_array_add (msgs, g_steal_pointer (&msg));
+
+ if ( idx_peer_curr != IDX_NIL
+ && idx_peer_curr < peers_len)
+ goto again;
+
+ NM_SET_OUT (out_msgs, g_steal_pointer (&msgs));
+ return 0;
+
+nla_put_failure:
+ g_return_val_if_reached (-NME_BUG);
+
+#undef _nla_nest_end
+}
+
+static int
+link_wireguard_change (NMPlatform *platform,
+ int ifindex,
+ const NMPlatformLnkWireGuard *lnk_wireguard,
+ const NMPWireGuardPeer *peers,
+ guint peers_len)
+{
+ NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+ gs_unref_ptrarray GPtrArray *msgs = NULL;
+ int wireguard_family_id;
+ guint i;
+ int r;
+
+ wireguard_family_id = _wireguard_get_family_id (platform, ifindex);
+ if (wireguard_family_id < 0)
+ return -NME_PL_NO_FIRMWARE;
+
+ r = _wireguard_create_change_nlmsgs (platform,
+ ifindex,
+ wireguard_family_id,
+ lnk_wireguard,
+ peers,
+ peers_len,
+ &msgs);
+ if (r < 0) {
+ _LOGW ("wireguard: set-device, cannot construct netlink message: %s", nm_strerror (r));
+ return r;
+ }
+
+ for (i = 0; i < msgs->len; i++) {
+ r = nl_send_auto (priv->genl, msgs->pdata[i]);
+ if (r < 0) {
+ _LOGW ("wireguard: set-device, send netlink message #%u failed: %s", i, nm_strerror (r));
+ return r;
+ }
+
+ do {
+ r = nl_recvmsgs (priv->genl, NULL);
+ } while (r == -EAGAIN);
+ if (r < 0) {
+ _LOGW ("wireguard: set-device, message #%u was rejected: %s", i, nm_strerror (r));
+ return r;
+ }
+
+ _LOGT ("wireguard: set-device, message #%u sent and confirmed", i);
+ }
+
+ _wireguard_refresh_link (platform, wireguard_family_id, ifindex);
+
+ return 0;
+}
+
/*****************************************************************************/
/* Copied and heavily modified from libnl3's link_msg_parser(). */
@@ -8055,6 +8387,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->vlan_add = vlan_add;
platform_class->link_vlan_change = link_vlan_change;
+ platform_class->link_wireguard_change = link_wireguard_change;
platform_class->link_vxlan_add = link_vxlan_add;
platform_class->infiniband_partition_add = infiniband_partition_add;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index c750caf567..d097186ef7 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -1985,6 +1985,61 @@ nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatf
/*****************************************************************************/
+int
+nm_platform_link_wireguard_add (NMPlatform *self,
+ const char *name,
+ const NMPlatformLink **out_link)
+{
+ return nm_platform_link_add (self, name, NM_LINK_TYPE_WIREGUARD, NULL, NULL, 0, out_link);
+}
+
+int
+nm_platform_link_wireguard_change (NMPlatform *self,
+ int ifindex,
+ const NMPlatformLnkWireGuard *lnk_wireguard,
+ const struct _NMPWireGuardPeer *peers,
+ guint peers_len)
+{
+ _CHECK_SELF (self, klass, -NME_BUG);
+
+ nm_assert (klass->link_wireguard_change);
+
+ if (_LOGD_ENABLED ()) {
+ char buf_lnk[256];
+ char buf_peers[512];
+
+ buf_peers[0] = '\0';
+ if (peers_len > 0) {
+ char *b = buf_peers;
+ gsize len = sizeof (buf_peers);
+ guint i;
+
+ nm_utils_strbuf_append_str (&b, &len, " { ");
+ for (i = 0; i < peers_len; i++) {
+ nm_utils_strbuf_append_str (&b, &len, " { ");
+ nm_platform_wireguard_peer_to_string (&peers[i], b, len);
+ nm_utils_strbuf_seek_end (&b, &len);
+ nm_utils_strbuf_append_str (&b, &len, " } ");
+ }
+ nm_utils_strbuf_append_str (&b, &len, "}");
+ }
+
+ _LOG3D ("link: change wireguard ifindex %d, %s, %u peers%s",
+ ifindex,
+ nm_platform_lnk_wireguard_to_string (lnk_wireguard, buf_lnk, sizeof (buf_lnk)),
+ peers_len,
+ buf_peers);
+ }
+
+ return klass->link_wireguard_change (self,
+ ifindex,
+ lnk_wireguard,
+ peers,
+ peers_len);
+}
+
+/*****************************************************************************/
+
/**
* nm_platform_link_bridge_add:
* @self: platform instance
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 13e8fc4d60..9bfc4bc398 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -54,6 +54,8 @@
/*****************************************************************************/
+struct _NMPWireGuardPeer;
+
struct udev_device;
typedef gboolean (*NMPObjectPredicateFunc) (const NMPObject *obj,
@@ -825,6 +827,12 @@ typedef struct {
gboolean (*link_can_assume) (NMPlatform *, int ifindex);
+ int (*link_wireguard_change) (NMPlatform *self,
+ int ifindex,
+ const NMPlatformLnkWireGuard *lnk_wireguard,
+ const struct _NMPWireGuardPeer *peers,
+ guint peers_len);
+
gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, const NMPlatformLink **out_link);
gboolean (*link_vlan_change) (NMPlatform *self,
int ifindex,
@@ -1377,6 +1385,16 @@ gboolean nm_platform_link_6lowpan_get_properties (NMPlatform *self,
int ifindex,
int *out_parent);
+int nm_platform_link_wireguard_add (NMPlatform *self,
+ const char *name,
+ const NMPlatformLink **out_link);
+
+int nm_platform_link_wireguard_change (NMPlatform *self,
+ int ifindex,
+ const NMPlatformLnkWireGuard *lnk_wireguard,
+ const struct _NMPWireGuardPeer *peers,
+ guint peers_len);
+
const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address);
gboolean nm_platform_object_delete (NMPlatform *self, const NMPObject *route);
@@ -1477,7 +1495,6 @@ const char *nm_platform_vlan_qos_mapping_to_string (const char *name,
char *buf,
gsize len);
-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.h b/src/platform/nmp-object.h
index efba5f1b8d..e46b16c8f0 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -45,9 +45,11 @@ typedef struct {
typedef struct _NMPWireGuardPeer {
NMSockAddrUnion endpoint;
+
struct timespec last_handshake_time;
guint64 rx_bytes;
guint64 tx_bytes;
+
union {
const NMPWireGuardAllowedIP *allowed_ips;
guint _construct_idx_start;
@@ -56,7 +58,9 @@ typedef struct _NMPWireGuardPeer {
guint allowed_ips_len;
guint _construct_idx_end;
};
+
guint16 persistent_keepalive_interval;
+
guint8 public_key[NMP_WIREGUARD_PUBLIC_KEY_LEN];
guint8 preshared_key[NMP_WIREGUARD_SYMMETRIC_KEY_LEN];
} NMPWireGuardPeer;
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index b3fd2bc0ae..031bb79a25 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -466,12 +466,20 @@ test_bridge (void)
test_software (NM_LINK_TYPE_BRIDGE, "bridge");
}
+static int
+_system (const char *cmd)
+{
+ /* some gcc version really want to warn on -Werror=unused-result. Add a bogus wrapper
+ * function. */
+ return system (cmd);
+}
+
static void
test_bond (void)
{
if (nmtstp_is_root_test () &&
!g_file_test ("/proc/1/net/bonding", G_FILE_TEST_IS_DIR) &&
- system("modprobe --show bonding") != 0) {
+ _system("modprobe --show bonding") != 0) {
g_test_skip ("Skipping test for bonding: bonding module not available");
return;
}
@@ -684,6 +692,232 @@ test_external (void)
/*****************************************************************************/
+static guint8 *
+_copy_base64 (guint8 *dst, gsize dst_len, const char *base64_src)
+{
+ g_assert (dst);
+ g_assert (dst_len > 0);
+
+ if (!base64_src)
+ memset (dst, 0, dst_len);
+ else {
+ gs_free guint8 *b = NULL;
+ gsize l;
+
+ b = g_base64_decode (base64_src, &l);
+ g_assert (b);
+ g_assert (l == dst_len);
+
+ memcpy (dst, b, dst_len);
+ }
+ return dst;
+}
+
+typedef struct {
+ const char *pri;
+ const char *pub;
+ const char *pre;
+} KeyPair;
+
+static void
+_test_wireguard_change (NMPlatform *platform,
+ int ifindex,
+ int test_mode)
+{
+ const KeyPair self_key =
+ { "yOWEsaXFxX9/DOkQPzqB9RufZOpfSP4LZZCErP0N0Xo=", "s6pVT2xPwktor9O5bVOSzcPqBu9uzQOUzPQHXLU2jmk=" };
+ const KeyPair keys[100] = {
+ { "+BDHMh11bkheGfvlQpqt8P/H7N1sPXtVi05XraZS0E8=", "QItu7PJadBVXFXGv55CMtVnbRHdrI6E2CGlu2N5oGx4=", "2IvZnKTzbF1UlChznWSsEYtGbPjhYSTT41GXO6zLxvk=" },
+ { "qGZyV2BO1nyY/FGYd6elBPirwJC9QyZwqbm2OJAgLkY=", "v8L1FEitO0xo+wW/CVVUnALlw0zGveApSFdlITi/5lI=", "/R2c0JmBNGJzT594NQ0mBJ2XJjxt2QUSo+ZiqeY0EQA=" },
+ { "YDgsIb0oe+9NcxIx2r0HEEPQpRMxmRN0ALoLm9Sh40Q=", "nFPs1HaU7uFBvE9xZCMF8oOAjzLpZ49AzDHOluY1O2E=", "zsYED2Ef7zIHJoRBPcen+w4ktrRsLPEfYwZhWIuXfds=" },
+ { "kHkosM503LWu43tdYXbNwVOpRrtPgd9XFqcN7k4t6G4=", "b8e092WT+eNmnxCr5WE2QC/MXAjDagfG1g03cs2mBC0=", "VXz0ShGWT7H0CBCg2awfatmOJF15ZtaSMPhMsp+hc3A=" },
+ { "4C2w5CEnxH59Y2aa6CJXgLdDtWoNMS2UJounRCM1Jkk=", "gC/R9umlnEQL+Qsz/Y64AlsdMge4ECe5/u/JHZCMWSs=", "2bmL5ISr+V5a7l7xFJ695BLIJyBgx8xnxzybkxiRHOg=" },
+ { "KHJSzFGkXcZf/wbH2rr99SYtGKWbL680wA2AcDE94lo=", "BsN23h4aOi458Q3EgMQsodsWQxd9h/RxqskAUpsXfgg=", "nK4Zv34YKEhjuexhq1SgK4oTd4MZJT5gcpYvEuPjc7Q=" },
+ { "QGMulXJ9e3AVxtpi8+UUVqPOr/YBWvCNFVsWS9IUnUA=", "kjVclP5Ifi6og2BBCEHKS/aa/WktArB4+ig06lYaVlg=", "0+mmceDPcSRK3vFnYqHd9iAfY+Nyjzf/1KgDeYGlRkQ=" },
+ { "AOJiDD4y6GA7P7gugjjQG9Cctvc5Y27fajHz6aU3gU4=", "gEnHn6euHtcMEwZBlX6HANPeN9Of+voBDtltS38xDUw=", "wIH1OxgX6GLxx/bnR+t3fbmjGZDTU3WMxp7t1XGezqM=" },
+ { "COsls2BlCltaIrrq1+FU51cWddlmoPPppSeIDunOxGA=", "+n6WuV8Tb1/iZArTrHsyNqkRHABbavBQt9Me72K2KEc=", "t4baiprSO9ZbKD2/RutOY9cr+yCajQWZGCTnQdrFQj0=" },
+ { "uHawQq2BRyJlsTPoCa+MfBVnv4MwtRoS+S9FEpFOEVg=", "8lcmr27afeb6iI3BQCaDtvalF2Cl7gxRZgs+nyJ/fEg=", "Eh9o/6W60iujBLIHuRfNrPhOWAn7PambT2JRln9iwA0=" },
+ { "yL7hmoE/JfRGAotRzx9xOpjfrDA3BFlPEemFiQw40Wk=", "BHK0PHi5kp7rOfQ46oc9xlVpB+pZeZYXTtH7EXr5TwU=", "BS2h2ZZyW0BlYMmLR29xyHEcZ4jtO7rgj1jkz/EEaxU=" },
+ { "ON8YrTHQgoC5e0mAR9FakZ8hZ/9I7ysuE21sG546J1Y=", "Bm3l5I6iH1tDrv6EgdZU9PzHqp0H26Z6ggmmIypwxy8=", "qKVfbCnK1EI3eC28SsL+jyBnEnIF/nRJQJzDevBFdNQ=" },
+ { "KGLO0RI0VlQFCG+ETUqk25HdaKUnUPXKOKkTh/w8BXU=", "sBDBwQFC7k8UMdMzuavKBkBjYYKigzvYmGF5rm6muQc=", "BNfZF9d7540pUGGOQCh3iDxAZcPBqX4qqM00GSLPBek=" },
+ { "KGdWyEodIn7KKI2e4EFK9tT6Bt3bNMFBRFVTKjjJm2E=", "lrbjU/Xn9wDCZQiU8E5fY6igTSozghvo47QeVIIWaUk=", "LczqW48MW8qDQIZYRELsz/VCzVDc5niROvk7OqrTxR0=" },
+ { "wO3xinUGABgEmX+RJZbBbOtAmBuPPFG6oVdimvoo90w=", "dCIvTzR6EerOOsRKnWly1a9WGzbJ4qc+6t3SSzLgWFk=", "wFj0zpr5PadBoBy0couLuZ1qudZbXLbV/j3UT+AyKeo=" },
+ { "+JNOBlO4tp9vvQk6UO4r3sILyEgjl+BBoWketZufyn0=", "Q6LSv9y7YQkJEzQ/1mpjJEgOrO8GYPUTgcizjh7Cm34=", "kg7AG9MuN04xPJ5Z0IcNZ4a8d1b/n4GsGIeyA4FaaSE=" },
+ { "+EJcThLRwjZ+h1CNNFu15HWzznf4u/lPVw8hifTm2Ec=", "Kkn2jFqwBzyIFQfD0OpmePFSmBYmhKagv4pGgkqsWgE=", "jYpxojj8WKYe/XIXMP+uv1Fv0+TKrs83tqfzP0AGdcI=" },
+ { "+DKFqSMNFmxriEFj3qatuzYeTJ9+xWYspZ4ydL3eC0Q=", "3o37bsg6HhRg/M9+fTlLcFYc2w/Bz9rLQySvvYCKbRE=", "Jb9qoDIBat1EexlgfpRbXa7OflptME8/zt93bldkiVE=" },
+ { "EH3MjFOMqRoDFQz+hSlJpntWBeH3lTk6WPjTIQjr42o=", "PbPewED/nxSBLdM7AXMj7uS3bCgAAg8M6F4iPLd0b1U=", "pj4+UgOGkpJwlRvX5BRXZzmzAUnDtUtJsS7LzbcJWzw=" },
+ { "kL6M2KvO+vPBLEc/a0DpEHTibQ1bwaMRT9b9SkzeP0Y=", "pS3G2bHHlkOE6UHP0qVitDuxXgjEaZTviTjNc55RbVs=", "ZVZpWOtYqhX3CpF1kATg/38J6pvUJo8AS1sVYjs3rUE=" },
+ { "sFlcRLDn36fnew2Ld92IHJwnKifdS3aF1MWRPs6K3Wg=", "OpjUOTiWExaDYULTINB4yQFqc3mnU3RjQzGRV+KtdFY=", "of0V/uoFRNljv/XTt/tXgoquLRH93Ty0KNiaPUpEi2w=" },
+ { "UJ8hjDsg3jfsnnfPH8Gw9FnCb6taTuviurAfZu+kEFg=", "3byjHksUOv8CNjGGKvHvvrJDURBhCIL5UtfZbgyVWCE=", "9f7dbWif51gGrE7R9LeuewQSrvGFGTOB3ceJC67jSkI=" },
+ { "iFFPKGIfqeUKY/w72KAZSjd/PGTqCakHYBV10xMDfnI=", "ehneHATNSXtsJTOiPjVSc0QARkihgcfcvoXKFWKfQnI=", "yKdqDBcRwA7RCg4GiY/b5IsWcExPleOBde/hjxc36a4=" },
+ { "GDGocdPJTPUAllxQo7SpXZKqMPn7lpxQELQUX9ETHmE=", "n0ScNEou4ekfrXRRXvcADLu2Afj8g5D3TuDP/I4KrnY=", "8QhswqAhi/ehhcmCwQF5aSh80TvIGC/gRL5jBn5wOH8=" },
+ { "UCcrlN8fX2ZdNdhaEBNwktwL+H0ZO7fhaj7rgdUutmw=", "LF8J728ilXs4TphnrgR6r0p7W3912DYnsXkGMEPQnRE=", "cYfMjxl2REYir7frGeB0u+NHAaFYF02ysgpBhOL5ygc=" },
+ { "SH0657XuIiHidVmViXZF30RUWtkuWXcWWHmKZHTiOG8=", "7k6j49W1u5qgLE5MQUc1osPVW1oPPhzjrGvJ7o9YamY=", "dV2+7rNk/3LR2IcwYg/c+Wvzep1yjY7/u1I+nnlTQ00=" },
+ { "qFQWs6jzrscV42pGISQyA7JDvFFAvEQCWJi584VHD2g=", "AT63nHKLC17yUvkR4lOVPxCr4DD3QhXmcmecOTn+Amc=", "2Qe2fwJbFcu1CmKpktElOFkSQMqlyvlV3ZUIAd/Dcts=" },
+ { "6J+yLxgPwWtUbk9I3zbeD8RuK6XkQjJ0wTJ1zSVhflQ=", "NJzMBYyPZjk3eLmgdKaOeWyNER5YZF1mR8Umeiu9f28=", "pp+4+XHw5ZmHGJ7WbZ1xLYRsnTI17QIbb0bzHzYZrBs=" },
+ { "KJGoWYNVDUWcEMg+E4tljv1LiWAbdRw2QVapYqdFa1Y=", "M2SGk9WVnzYNGnT777G/JE8uUsY2f7mszTwlue73UDE=", "Jg8N7GbhbYB400foFP+OH0v+hCaL1jW61bajSA6EZqc=" },
+ { "uAgrgppPyIvk8S1CHUmaCaORsgFFfBreB8pxXmbSdXw=", "dJ22bER4fD3qF2/yIGWQ7SgmZ990sy/SbANjmUMkzws=", "mKkd0OoAR9sClmD+k3fL9weBsoCy5GQGz9BP0kAQIjc=" },
+ { "EI3Q8gePNPrtFyoMcv7hOihQgroF/dfjzPn8yvpGPWQ=", "Y9QhJFeiyuuIZNPU56B6U//ZK+XTTe4EP7h/p3Q+dE8=", "qBVUYw9rTWaxn55nUd55NpCWtxOUSWLt4WJGusiDS8Q=" },
+ { "oEQvdRm/yHkx+JvlhHGT5RUFrFEUleKb9DCT55EqZ30=", "8hsh/UHwWADTHntOJq4dy0o7ahcNAAlo2rDpjzzrVXk=", "/GF2inW2mPtA26IgFdgOEBbBEerT740wWuP/8NyANdc=" },
+ { "6OWrGKZKNsgfRezSUw29EnHymcgKyEKvX5/pZQlLmWs=", "oaJeO6YSS2dodNEf97DvgWrYnFFelG5daEdN84jVVGw=", "T5wvTdyVxK0LY96kouLjs06oUfhGChfty8OUL1Mddro=" },
+ { "mPmzQbh2R+r1DC5hSquzKM1SDrxUdfnBPRPJrpqrgkE=", "BtUHAnYWjDjBI42qBf9dJqezTUikYsF96o6PKEWPrVo=", "MxU8EMmq+vVHpuK/AkFZrZDF2b+VbSqukZLPbNsCcgo=" },
+ { "8GVxuoo1Veyr+nqxr5Q4vmsMf5qfiXwSlQ4q3+BU60g=", "uSOLe/E9/OjIgUOk0NMBHB45E0+q4Rd+IUO2UOxmKlM=", "+30F+56OE0Sr3wY2clKw4kgE+2XiucMg7xjK6EemXuk=" },
+ { "qORPKb+qFuU/9TpFbRUupHsqm9iyk9pa6cpik+EVDkg=", "bMZxxd+Z9I0XA1h9U8JEY+/mRxWGnvbXDZ5Dxz7YzS0=", "SmkkqOz4OhHuSL6cxuRm9+Mlt50Sfd0sMDFTC78gqOE=" },
+ { "2Ko3IYhXKcdOMIJGNpASk9saNSZsI64lyJPOoxpQ2kI=", "xVOc9PxY1VFaZfemmKi+Ei2liHhmeTu+JMa+rS00gnA=", "+398DlW8kWeI2aRaC4QfcrEjwqPKCohyDeWdaI1wvv0=" },
+ { "CPioGCVpxnym62nH/QoCt1RiiaaxUcuFjvh5kRhjqHA=", "W0XxlBLrZgFKhggMvvv6oFf/RJbfs92qv8JK9e+5i2o=", "bsK2U6CRAUv1uVgYQ7NpqjWWswFIDiDPDEtU1XQygSA=" },
+ { "AF17siKaeiO85hikYN0IWCMGWqPm1UOoCkXMltJGUVk=", "B+PFos9aN2S5bLxzGZHljRZj41j3rIx8RWu0vDUzq1w=", "Qb8d6iDYv3m1h7PE8j0Exl2cSwpHkim/fJ1S4P7MYvY=" },
+ { "wMFDBTJzx5tDCBhMkrptYJ8w9EeURjc4xeDQpevxAWo=", "4ec439EXE5WQzvtV9reSX+aMmdq5k7o9Ayt8oQp+RhQ=", "jwQlvdNH5WtSSU10H+fh/JisOlaBaohDPEp/BYnTt1Q=" },
+ { "4GaJpIFigNDwd31O84pLIMM/o2qhp0ydlI/ydD/2a2Q=", "r/LdkCoK5/BPGdq2+XJO8sCRhI+8ULFmg0887V43PAI=", "Da+3ZZvEJdx4TYFMIDUlbkmytILnSTNxTKX+sQdjMd4=" },
+ { "gMnojGqCLmMfGp2m31xlKZ/rIV2b8ockw9DPahRyu0c=", "H6tKCTosnM4BXKqflXrkTdJyNlCIZhQ3ZRxfrvSdrDk=", "4Z6K3LKIMV89plcjMb9CzSzJl03SWRe/++geBMZcOtY=" },
+ { "wKCg22aNNoHnDJ0oAKE46FcSSsREW4AaGn5WxCSeXUs=", "9NDTFC0iPt4HbbWepLHhN5poNTN2fdxJKNadsNT7qzY=", "GSVTOCnfLpJ1VCOLHaKSjCMv7/OlcnQiP5+5woqkud8=" },
+ { "oCoykq7pcJcg2X2V5TBRzGwn8hzzHC05WUreuotdznY=", "DxfwnbMqr5Wn5SAyFolfEmNQT6l84Oq69ngpg6H6Iio=", "p1RHBuqhuDa1MAQ2lbqmUQFu0CTwYlf73fWZSj9tQhA=" },
+ { "UO7YVyRUVkcKr7c63VWWV2zj36XD3HyDfLZCqvrZmFc=", "360lzYtIyHq5lv/QXSCe4bL4G2J1jBXFJ8yS+Ycr7Bc=", "RRPQ1XWF1HN8Us4dtfn2eemdjgtWm7U8r7mM3y00NOk=" },
+ { "eCGFYV/NuGP4H552E8Of1xU+3IvZxGyX+p5UFGW8iHI=", "LqhZ4AS9dQ/MhsQnE5Oy7Q8INXY+P+mrfGY5dtg9SlE=", "SICfqs8T5wP6IzATDCT4ovamBKPdkZ7JP4Cfsb3izec=" },
+ { "oI3HBZknoIMMZw1BuYMkTBylt25reX7AbCqtWQv8cno=", "B7dUgLgvQhi0RGmvaMrmf26WdjEVrhaiBclVkCKd4AA=", "5O9K9pLXwxFAt5lfMWh4qGbwX1BM7sz0QGYxAnR77dk=" },
+ { "sBfYn14EFVIS2M/E1aahP7mOmRNbNtyDChDMS1s6aGs=", "FLYv0ZvzxMkc9A7OzhC4P1ZRu1aKIQd7u6gqfdekC3c=", "kaYLcNCXnCLgiB8fleMQuboUJsj5u3YAmXL9x3ywV0M=" },
+ { "qFwZESU/XYZXUtxwrGsFU9qPAFTzjm7EhTS1Q6ajGlM=", "hraQQaqJCkS2yQXv+ccMOVh9V9a/qgSZJgdMAhrt8ms=", "72oDfnWOn39gdk/ncw8Lv267I0I+m73SwxrpYojpWYk=" },
+ { "YHhp6Zf/miuc2QXeI2lTezy0lL0pTv2b+nWNkmjYQWI=", "UhNO5arLzF0WlZSgNOx7+IjWN+GSxDdQxZRp8uIwsyI=", "1Q39Nzv2NGI9zWKWMpYLURAMZUg+FP+OboHHzFU8Anc=" },
+ { "mLBBXKaCJ+7qeBZpS3wxGi/SQ4kLzun+K+QwwdwfJVQ=", "gIq/nh7NwCJ36MvRnyrWHaRWu8lTmwfN2NvsjVl6SXQ=", "AahcNR91GDyJBIP+vC8ZuIV8ukqjSGtd8s+cmjVC2Ao=" },
+ { "OJG4LZlNNngFtAEQdbVVWVm6QAjOOauGcMZGbQrb40M=", "pFHAC6HaWAOtvTRRVfSHvzG05mp4SJZXKsN/tkSF0kM=", "IoXT3wIqWNxQhYuHWl12ODq/P7RM9LwaqglhmjKg+0g=" },
+ { "OOwBFOQNhepiqDf04DehQLh1gpBNOluDF1ia752Yfng=", "u715uJ/XhdjXjThCTJ9w6zzXnIhp3VCxhtso1wk+oBQ=", "5x1Ip3Ym0KzDjGhiYjmpeWWr+dgrZlYwfr02GngPOTM=" },
+ { "eNPFnwkQy1qw+IjFAlrDA6+sIsxbWDlzbNSsBW8R1UA=", "OaOXaAfPb1MRpWadawFje8YZ0oxJgdCIDIP8c5X+r1U=", "NtfaRRD0GqujnaQQoNoBbtovgO4dfVwEmEQx/YgnDpw=" },
+ { "OLdaZItbtxH3mGqItkibIJp7KV27FrQavjhd5zq6s3Q=", "SLSmAYxkMCGj0DO35cMLkC3NVAqK2VmVFndbOZEdA24=", "SnBO68XQTDjxYbmYaAeEHgLwD2u4D+BPT86raRuUQZM=" },
+ { "UBQOEz08izwr4eEK/SnQUpkt+TxCjo6Sya/XOGMLOE0=", "wQwrwezI9LzKevGsJJCBHDG8noR0yIEtOK5Rig97SSo=", "DpyS+0d7lrlFWkztsniG2v/j44vcuvWz3sPeghRyb5A=" },
+ { "mN98iuqUKh67ggUdq9ZIQNZCZM90fgycTVqYKEo+DkY=", "GYdXVW1jpS0dN1q9zMehubP7LfYqs34kszN0bXQqxxA=", "AJPIHffB4uvvJJki4xCG0VORVBbF6bc2mZQqUx+idPc=" },
+ { "OEd/1it8C3o+NOWxDI3DfLMXVBHJQg15N3E8F8d99l8=", "QL1NcuUkoXxDy7M9VjGslCejcUlnUDHRghFVnr+8fmA=", "nven9Dicl8U6QXuDO8rRNtjd4NYaa90SU+Gmv435XKY=" },
+ { "AFMCGDu2oAP68miucsi4fmYX2KeRZnsEGv8tQm8JEng=", "1sNxvk8uZhFsBUgxOXmuCMjDAgBbjVeWe9oaFk5Osy0=", "t5iI5XXd56S5q0Y9HC91gzgF9uGjL9FIy6NUaKqkydo=" },
+ { "CIAwfJghQHHr4YlztN9at6/iWkrEVCGFAxNVuQCuT3I=", "zpUOF1h17g7RpBzrVlN7oTRz6e+dxcDL8OsAtHwgLC8=", "kOSwC1p6Uoti9E9Eg7ViPZwCytuvp5Fr5Buw677aogU=" },
+ { "sC8vrAVBU0zvhWDRfzfySjvopXm2/cTMkTLmioyO3Es=", "p6H7GWm8NfgyO5OCX/COjvVT4MAnTs9ZUj4uZMK8XHA=", "9Tzqo57V/h7+6nSNAHSBKdmU7ultlvZbAnNKSRlrLi4=" },
+ { "eI63gjxCZGnzqZxPEi/ifYphXhxIRI2ZxK8jzqo3mmU=", "XyNzEuU9x37fxFCnrZH89Krs5/UqGVx5wNkGfQCAYz0=", "vZ2fTlRPnJQ+q33YdS5p1aweqPGj/kTMc4Uq80FtFjI=" },
+ { "aNJlGtm79/RS4SQ/PC4YM6LFo9zAqDr2/RjLqk/z/1A=", "lgZ9akPrABmfHQMlfNFnnpAJzGtcsaU9mUjEYKfzZHc=", "d0Xt1Bcgphd1HMI0RneA4VdBbMZL1qNGJAvFhb080eA=" },
+ { "oONSnHirNh3cuH93Ty0C9AXKebGY+cdF3R0DtPzIQlo=", "TuREKfA8EVQiYWsPx8veUzjN2cz/b72limSLWlrCWxw=", "vEqqKbpZf0EM6EApMUaUH65r3Zr81Y/DSODhE4H7U3Y=" },
+ { "+D6RyLEaHJ9YF9WDyOlwh87KaNJcc6lqX8Arp6yqHF0=", "EpecjfIo1/EEbmsgUtzEDqLu2ut+SMmzqaBL9Z/MlCA=", "oYfO6/7XQgEYT9zmr4sqFrk0muK/fEv3FfD8MzZzjkE=" },
+ { "OCmW5KQql2PRMJnsMYQjXlr6TSYUbxJBknqZtXJPSHM=", "ZZR2ghHlCwAJu/XlsEZuNS6XiGPwuXzyMPPywYFapVM=", "fqSCXq+pKJJ6yNvlOi+tyQ9E4Y6kc4kblGrVqN2WuXA=" },
+ { "APWXDAe8d2ia1CUbf/IzSPXOUjR8TVuJgmISiWw0/EY=", "jrT5P5YCkG+U7cfNTvCKy0GSEgsjwmJtHg+8HBP6ZCA=", "t75aUjZXMPir8Ao0yhVClh9/BdWxSL+11CjK3iELNWk=" },
+ { "8Nw4sRis7M/6Om+3w5YHXthyMzLGuP48teqdzbHNPlA=", "lj3q3ZYij3ZJ/QunK8n9I00cv/Z+O1TU1kFFl8x3DTE=", "adqB79P7gbXEYYnSd1/UPCwFffTAPXa9kHWynRBYcGo=" },
+ { "yOupps5XbjV0fIZKnGhrpcxB7yDQzbBILC0UMJyVS1c=", "+MDV/t9UCIdgm3IkH3BZlxaRPJ3lejRmrm4UPApq4mk=", "AOJPmQxsU6hjOd+9mHnF0VL7Afih3P1Fr625xFT4FtY=" },
+ { "cD2DEl4MBwONuTV0db5XreoVjQAUZFNXqIeFEU3KFkE=", "2CeHrjN7tBX48k4Sgv5fIHG06e57q/ucCL+8DIRmfXw=", "3EUo6MRzs6rSoY/7AFs8wiBiTXPcHzerLh6Xp3aMGKo=" },
+ { "EA+S3a9ZeOLiRbhTxaT2wkpyDheAmai+UJa6SFGzSm8=", "GGByUKZx/FPa2OkJoqVTHXx+6jrIpIw5rf0rp43MHko=", "BXoDA3yn0JcMV7hHVzEqhlwAORvhToFO1qG00nas92A=" },
+ { "eBeJi/imBiV52WEqrwAprUQggqdQmvTTmWtLq8pDDkM=", "zCX26ZTOZHLpq5x5aIUL1XhIVoXJLp/zcXwnmFA3jBo=", "Dm/DCxXWYXEsmQgxAD3KREK2PF0bUSnV5WRAaya8s1I=" },
+ { "8C7p+EQO+CnWUSjHVu3PpeWpUIbLy48zpftZu021plM=", "DxpnF/IbKAh6kmWC5Jpj8iw387EDkrvjsjOb9fbTSng=", "bGrk0OshJB+0oQOK0QGKU8+lotnIDz3oeUnMZGienyM=" },
+ { "COIez7YcBJiOJCLxxWV5UGLW5/o009YI0aszlD/PiUc=", "eD9USWV37LFIOxlDSHyOmfFqNJFpORRlzEI+HoF/czI=", "n+/ra86gUSF2pNZS51nt2JgrzXnQJl+dWswOq/Ahs94=" },
+ { "iBBSTG9VLC+T9+ahNaQ4umZoig8o7w1DaeOw+cD2BGc=", "XnAxqDlvGnQ6aakv8ABGHVj07qVQfk4NChZbstTMBxg=", "7KKSwu/4yWr1UzFmNMGtiaSwdYMhP/HKbrQLlABL4UE=" },
+ { "eNmwattflehr9+KsVqTuwt1YaAc5ONkaIaTQt9Gkhn8=", "1NNVvm++YTTGMKyAXfGOCZ4aDDdFFH5Um3vAg4XimDo=", "bXNrnDTP0pBay9ytZe7xpiKoSi12F7WUXqoIeI++Xvo=" },
+ { "QJotpmZINx9eptKpkh9j3JlEDcHdWnjEbicdBS7gPXM=", "3gLYKeoruVZ/AYjym0gciDvRHj45UIWyHhNjWj2Wj28=", "NwuUkkE5yOWT7wed7bltgAk71miz3cSooiIDAdv6kKw=" },
+ { "OAYGuxH70OPQvhVIX4BhSCWUyzAI5H2IkYxKgC/AO0M=", "Rj9iNF/FagkXfdLPqc9LHfaoGR8GlvY3gun2FilE508=", "hkNXLVMlBRsMEaQKkSzevcEK2sMu0AShGKQJMNqdzWM=" },
+ { "uBrgZ7wLHrOV/0dNiEqo7FjY9VnJqL5eUDHJWAc9QXg=", "3Hnln8ZHfSaK4OzESJe5U6NcLaW56wzfZICzvzefnSo=", "DhXsehe5FAmbUidXT5ZpZIAuu1eF9rkU6cF3FBoKwOE=" },
+ { "sJknn3CHvx/812EWU3ddLdLLZFBKsc+wx35GXyiRsHY=", "qqa2dNSt0jWozGyqpokP392H5/DOAUUZmUpyZDaUEEE=", "1Dyz8CvmF17oKT/wG2fu3vRzPzgQv8/OY9GJYew4FG8=" },
+ { "yOumS9HN68ZwIm+5hZol3jFQ0DB4SKuW/ld3y8wioGk=", "6PowsbKj/fKSzXZMAfaSkP3fE+4AThL9xm6ysQzMDxg=", "vF8cKu9X9FxgCjyVZ5RG7nuue8RelF5Qsb8Efme4M4A=" },
+ { "mISm5vQfPdK72SsaHh6O1/ARvaWCtm+KZNcpTsyt500=", "YCORDQDpb1U8vADdstBgXkg0N7QaAc5VoXJ4QFuA/UY=", "JlrBmfaCgbfEVD9YQq3c03WwwsHWc1nBwp1JkFORC3A=" },
+ { "cPyu3Qry6qbsiOJKFGRziZ9LJWJ47k3ZSXiGkQXuQm0=", "/cmBZTbqEp8sababPAxGb3OvDAEE7MlwPOwEFHE+7yM=", "lp0Hhc/rVtpT5FtLLccChqDl3El48XtP6Wm6JwjI7jo=" },
+ { "YKsMYU0SINbPwWw4RDCJV6GnzDlSp1ZNwUw2euGWi0A=", "/KmBReATQbFnLg8YKV0jwhqKeishRoWvlVtMX3550Vk=", "7fXpPSMo1Fw2sOXtjTtvFU+DbZvS/FWB9wAsywWx6R4=" },
+ { "WD0YI3y71eIp/GXw9i+7scEiQKSBkGihZWE+s6fGmWo=", "RdthAL/qPnAZFb3xBgRMiAtGHNjgokzoKX9iO2K5qhc=", "4dk4HGkT9dBmomGNorDE/hLr/HEFhljtl4zz3M4sG58=" },
+ { "oD8KWhJYZVhutJRb0kZlZnB22QUXzi2FfPRD0ll65UM=", "MYTBGHh4Ukj97pKj6qcfWmxGNQzmU3/aBOX2f1tfhG0=", "VT1gC+a9nRJzYMi/TPvRVnn3IQlaop/jKmmxZePEME0=" },
+ { "0Ns/1SOiqR2CpHRG03QNzJJd5gxTm1XJmSkFlugjQ3k=", "KvQAI+ekNOa2xfEvfyc9JGcS+CTUrnnhsKrlyJGJixg=", "J8LmSX6zElX3S9q4PNvh2NKUtAiQ3oHiYjSJ7yErPlY=" },
+ { "mD6TeF4ezSPXN/csN1OhoAREFSXllI+zl4DUOInVq2Q=", "WmLJ9ep2EqFcSftnYFJsmWyUxqL0zzuSzVEv94PcISM=", "U2+ILy2NDmmfgSW78C8dl8GyHESUc1lXPHPpg5F+gr8=" },
+ { "SMJoXOYgHz8HSzY+ByeWLcSP5qFwv7YjRe0bcKesRnM=", "DEsNSOY3TEs9J2YgqroQ4xKq8T8xNJQjvvE4UrTItQw=", "Bws1Hk2+lO+JQ7ME16EbwAdsBkWsGvti0Gb6LY2Lrms=" },
+ { "iGhXF0Hg0tqZmpwAMiolxvbvTPClQ7LlBAspSSyFEHE=", "7Xxzpwl7yRWehHNWTYVtFkdChJdXhtY4Mtw1fA9QcCg=", "Swjfv0PjuaE8Oq3a17BVno5I+q49dZlPwKK1bPUoKNI=" },
+ { "MIazjx3qTi6Qz3WzhtCPw3i4Q2uZBHcuMoh++ZGFYUk=", "oni8pbFqk9Ya+Fx+911Nl1SN0FD/hR1jwb2RH3t/pRk=", "ZYAFcj67LkbNURYbSnCCWGxAG8QLDGWwbl968mA6ZA4=" },
+ { "MAadYdiFM2cPuJF19q20Yoo5KJabuR9TUQ9jG5nvA1w=", "5OcE8XV+UPoBVbgqBQdVF62GZCW9DOQEdxrQsktPPBA=", "FCZsEFXouy+xtxv8X7VroXtvPG1Z1HFHL724tz1jcUI=" },
+ { "+GwxMmD2dee5+QmvXNI0NdP+rNWoSXTN42otbp0aZ24=", "Y0N44baz9ihclCUnv6rRbDqCYu4BxQlBfNnTz3NNe2A=", "/LqSgkVQNkQ/oBiZSgpM9Rw7BJv0RvRpEQpvlizvHy0=" },
+ { "8FREpCtncOcT7+W2nW4aYSjmSbADtVSH9rIliQZZUH4=", "fTNSd0JeREhXmPfjrmrAu6Lu/yHkB9GyxR3SyO4kZ28=", "262KN/iG/iJEaZeerFm1yVtvhFVGgQFwSvtxTcjZzeg=" },
+ { "EDhaRQGtscjoSE9wJOnSXoQVtVruIqyzknty+x/vDWo=", "eMmMgws6ZxDIxZ6QSwGjZO1Mx/r5T+fJjSTKGMBk/BU=", "0CyaJV6AG9bZ0C4yeZ/RDsOs9BdNqZpUxAsD30WmJO4=" },
+ { "CJV0UB2YdvVDG1cs4oiJgHAS+f1FocGr/vGCfiovsWQ=", "9/O9GWZEOXVm7On8lftL27PffRORju8OKl6gZd/74CA=", "A+kXRVNOwIrA5DUa+3v7dpRC+Gbxm23LTiYmOUAXUyY=" },
+ { "gCjDsJUwZGA7BjYVoCQsvdIgN9Q4lBHlSyKwUrl751A=", "HRwS8T9y2qPYk7JVU/8Y+6cS+Bk8XCLCXxwN/ttbQiI=", "iFotjA6rhUfkDv4S/wspJgEWunEmrlGSGsXcJ0+8laQ=" },
+ { "6N5pL4gsuK+shHpDxirTnAGdyKXIlYHyfIhtB0njJGA=", "CVZvW7NaN2XMEEKHodghBA9hLCwee/jrmttiWh/CmEg=", "OpPEd3Sp8r6KdjNDTN4bVHETlGJ92BCK74FCdEaDe9g=" },
+ { "UIPPTUdvhlg8qEDv6JRxM4/8F5ORjJz4ud82QZrgeEY=", "7Nd13z5EpB3ChytvQC1CxvDY7n0H8r2Y7lzLEY8hdEk=", "b22PvgU0M2QfNC7ZGN+RXNe5fjOzMsY32IcHTwLNIqw=" },
+ { "oBn53Q5fmxKX02PgI6F47Rb+XoLeFQO07ok2tYhk0lE=", "e0gtPDKXCZSoNW1uHqBPQXLfiYgyeqPMU2zZJgPXACI=", "wmjW2wDT2EzFkyaGui7YWNLTRu8Q4eD/GVKM2utZkEs=" },
+ };
+ gs_unref_ptrarray GPtrArray *allowed_ips_keep_alive = NULL;
+ gs_unref_array GArray *peers = NULL;
+ NMPlatformLnkWireGuard lnk_wireguard;
+ int r;
+ guint i;
+
+ allowed_ips_keep_alive = g_ptr_array_new_with_free_func (g_free);
+
+ peers = g_array_new (FALSE, TRUE, sizeof (NMPWireGuardPeer));
+
+ lnk_wireguard = (NMPlatformLnkWireGuard) {
+ .listen_port = 50754,
+ .fwmark = 0x1102,
+ };
+ _copy_base64 (lnk_wireguard.private_key, sizeof (lnk_wireguard.private_key), self_key.pri);
+ _copy_base64 (lnk_wireguard.public_key, sizeof (lnk_wireguard.public_key), self_key.pub);
+
+ if (test_mode == 0) {
+ /* no peers. */
+ } else if (NM_IN_SET (test_mode, 1, 2)) {
+ guint num_peers = (test_mode == 1) ? 1 : G_N_ELEMENTS (keys);
+
+ for (i = 0; i < num_peers; i++) {
+ NMPWireGuardPeer peer;
+ char s_addr[NM_UTILS_INET_ADDRSTRLEN];
+ NMSockAddrUnion endpoint;
+ guint i_allowed_ips, n_allowed_ips;
+ NMPWireGuardAllowedIP *allowed_ips;
+
+ if ((i % 2) == 1) {
+ endpoint = (NMSockAddrUnion) {
+ .in = {
+ .sin_family = AF_INET,
+ .sin_addr = nmtst_inet4_from_string (nm_sprintf_buf (s_addr, "192.168.7.%d", i)),
+ .sin_port = htons (14000 + i),
+ },
+ };
+ } else {
+ endpoint = (NMSockAddrUnion) {
+ .in6 = {
+ .sin6_family = AF_INET6,
+ .sin6_addr = *nmtst_inet6_from_string (nm_sprintf_buf (s_addr, "a:b:c:e::1:%d", i)),
+ .sin6_port = htons (16000 + i),
+ },
+ };
+ }
+
+ if (test_mode == 1)
+ n_allowed_ips = 1;
+ else
+ n_allowed_ips = i % 10;
+ allowed_ips = g_new0 (NMPWireGuardAllowedIP, n_allowed_ips);
+ g_ptr_array_add (allowed_ips_keep_alive, allowed_ips);
+ for (i_allowed_ips = 0; i_allowed_ips < n_allowed_ips; i_allowed_ips++) {
+ NMPWireGuardAllowedIP *aip = &allowed_ips[i_allowed_ips];
+
+ aip->family = (i_allowed_ips % 2) ? AF_INET : AF_INET6;
+ if (aip->family == AF_INET) {
+ aip->addr.addr4 = nmtst_inet4_from_string (nm_sprintf_buf (s_addr, "10.%u.%u.0", i, i_allowed_ips));
+ aip->mask = 32 - (i_allowed_ips % 8);
+ } else {
+ aip->addr.addr6 = *nmtst_inet6_from_string (nm_sprintf_buf (s_addr, "a:d:f:%02x:%02x::", i, i_allowed_ips));
+ aip->mask = 128 - (i_allowed_ips % 10);
+ }
+ }
+
+ peer = (NMPWireGuardPeer) {
+ .persistent_keepalive_interval = 60+i,
+ .endpoint = endpoint,
+ .allowed_ips = n_allowed_ips > 0 ? allowed_ips : NULL,
+ .allowed_ips_len = n_allowed_ips,
+ };
+ _copy_base64 (peer.public_key, sizeof (peer.public_key), keys[i].pub);
+ _copy_base64 (peer.preshared_key, sizeof (peer.preshared_key), (i % 3) ? NULL : keys[i].pre);
+
+ g_array_append_val (peers, peer);
+ }
+ } else
+ g_assert_not_reached ();
+
+ r = nm_platform_link_wireguard_change (platform,
+ ifindex,
+ &lnk_wireguard,
+ (const NMPWireGuardPeer *) peers->data,
+ peers->len);
+ g_assert (NMTST_NM_ERR_SUCCESS (r));
+}
+
+/*****************************************************************************/
+
typedef struct {
NMLinkType link_type;
int test_mode;
@@ -697,6 +931,7 @@ test_software_detect (gconstpointer user_data)
int ifindex, ifindex_parent;
const NMPlatformLink *plink;
const NMPObject *lnk;
+ int r;
guint i_step;
const gboolean ext = test_data->external_command;
NMPlatformLnkTun lnk_tun;
@@ -1005,6 +1240,19 @@ test_software_detect (gconstpointer user_data)
: NULL));
break;
}
+ case NM_LINK_TYPE_WIREGUARD: {
+ const NMPlatformLink *link;
+
+ r = nm_platform_link_wireguard_add (NM_PLATFORM_GET, DEVICE_NAME, &link);
+ if (r == -EOPNOTSUPP) {
+ g_test_skip ("wireguard not supported (modprobe wireguard?)");
+ goto out_delete_parent;
+ }
+
+ g_assert (NMTST_NM_ERR_SUCCESS (r));
+ g_assert (NMP_OBJECT_GET_TYPE (NMP_OBJECT_UP_CAST (link)) == NMP_OBJECT_TYPE_LINK);
+ break;
+ }
default:
g_assert_not_reached ();
}
@@ -1238,6 +1486,18 @@ test_software_detect (gconstpointer user_data)
}
break;
}
+ case NM_LINK_TYPE_WIREGUARD: {
+ const NMPlatformLnkWireGuard *plnk = &lnk->lnk_wireguard;
+
+ g_assert (plnk == nm_platform_link_get_lnk_wireguard (NM_PLATFORM_GET, ifindex, NULL));
+
+ if (plink->n_ifi_flags & IFF_UP) {
+ _test_wireguard_change (NM_PLATFORM_GET, plink->ifindex, test_data->test_mode);
+ if (_LOGD_ENABLED ())
+ _system ("WG_HIDE_KEYS=never wg show all");
+ }
+ break;
+ }
default:
g_assert_not_reached ();
}
@@ -2800,12 +3060,8 @@ test_ethtool_features_get (void)
ethtool_features_dump (features);
- if (_LOGT_ENABLED ()) {
- int ignore;
-
- ignore = system ("ethtool -k lo");
- (void) ignore;
- }
+ if (_LOGT_ENABLED ())
+ _system ("ethtool -k lo");
if (!do_set) {
requested = gfree_keeper->pdata[i_run * 2 - 2];
@@ -2862,6 +3118,9 @@ _nmtstp_setup_tests (void)
test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0);
test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0);
test_software_detect_add ("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1);
+ test_software_detect_add ("/link/software/detect/wireguard/0", NM_LINK_TYPE_WIREGUARD, 0);
+ test_software_detect_add ("/link/software/detect/wireguard/1", NM_LINK_TYPE_WIREGUARD, 1);
+ test_software_detect_add ("/link/software/detect/wireguard/2", NM_LINK_TYPE_WIREGUARD, 2);
g_test_add_func ("/link/software/vlan/set-xgress", test_vlan_set_xgress);