From 1cd167c774c6e3730deba5a1932d83135a90b1ca Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 7 Jan 2019 09:51:27 +0100 Subject: [PATCH 01/12] platform: fix hash/cmp for NMPObjectLnkWireGuard It's totally bogus. Luckily, NMPlatformLnkVlan is smaller than NMPlatformLnkWireGuard, hence there was no crash, just wrong results. Fixes: 0827d4c2e402b8c82d58e053e922d9d22679b960 --- src/platform/nmp-object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 683d5cdcfc..c0711c7927 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -3108,7 +3108,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_obj_dispose = _vt_cmd_obj_dispose_lnk_wireguard, .cmd_obj_to_string = _vt_cmd_obj_to_string_lnk_wireguard, .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_wireguard_to_string, - .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_vlan_hash_update, - .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_wireguard_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_wireguard_cmp, }, }; From 6ae04654f79643d758145df34b1011b051b1b329 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 6 Jan 2019 21:52:20 +0100 Subject: [PATCH 02/12] shared: avoid compiler warning in nm_strndup_a() Using strncpy() in the macro directly can result in a compiler warning. We don't want to replace this with memcpy(), because strncpy() aborts on the first NUL and fills the rest with NUL. Since nm_strndup_a() is a replacement for g_strndup(), we want to do that here as well. In file included from ../shared/nm-default.h:294, from ../libnm-core/nm-utils.c:22: ../libnm-core/nm-utils.c: In function nm_sock_addr_endpoint_new: ../shared/nm-utils/nm-shared-utils.h:281:4: error: strncpy output truncated before terminating nul copying as many bytes from a string as its length [-Werror=stringop-truncation] strncpy (_s, _str, _len); \ ^~~~~~~~~~~~~~~~~~~~~~~~ ../libnm-core/nm-utils.c:154:26: note: in expansion of macro nm_strndup_a host = _parse_endpoint (nm_strndup_a (200, endpoint, l_endpoint - 1, &host_clone), ^~~~~~~~~~~~ ../libnm-core/nm-utils.c:152:15: note: length computed here l_endpoint = strlen (endpoint) + 1; ^~~~~~~~~~~~~~~~~ --- shared/nm-utils/nm-shared-utils.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index e560697b1a..f3f3831e49 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -264,6 +264,15 @@ nm_memdup (gconstpointer data, gsize size) return p; } +static inline char * +_nm_strndup_a_step (char *s, const char *str, gsize len) +{ + if (len > 0) + strncpy (s, str, len); + s[len] = '\0'; + return s; +} + /* Similar to g_strndup(), however, if the string (including the terminating * NUL char) fits into alloca_maxlen, this will alloca() the memory. * @@ -289,10 +298,7 @@ nm_memdup (gconstpointer data, gsize size) g_assert (_len < _alloca_maxlen); \ _s = g_alloca (_len + 1); \ } \ - if (_len > 0) \ - strncpy (_s, _str, _len); \ - _s[_len] = '\0'; \ - _s; \ + _nm_strndup_a_step (_s, _str, _len); \ }) /*****************************************************************************/ From aab3e14883cf27d24ca64ee6cae68485f97e404c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 23 Dec 2018 13:51:21 +0100 Subject: [PATCH 03/12] shared: add nm_utils_getpagesize() and use it in netlink code Since we already cached the result of getpagesize() in a static variable (at two places), move the code to nm-shared-utils, so it is reusable. Also, use sysconf() instead of getpagesize(), like suggested by `man getpagesize`. --- shared/nm-utils/nm-shared-utils.c | 32 +++++++++++++++++++++++++++++++ shared/nm-utils/nm-shared-utils.h | 4 ++++ src/platform/nm-netlink.c | 23 +++------------------- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c index 6131d3e809..9daa7783da 100644 --- a/shared/nm-utils/nm-shared-utils.c +++ b/shared/nm-utils/nm-shared-utils.c @@ -2285,3 +2285,35 @@ nm_utils_invoke_on_idle (NMUtilsInvokeOnIdleCallback callback, data->cancelled_id = 0; data->idle_id = g_idle_add (_nm_utils_invoke_on_idle_cb_idle, data); } + +/*****************************************************************************/ + +int +nm_utils_getpagesize (void) +{ + static volatile int val = 0; + long l; + int v; + + v = g_atomic_int_get (&val); + + if (G_UNLIKELY (v == 0)) { + l = sysconf (_SC_PAGESIZE); + + g_return_val_if_fail (l > 0 && l < G_MAXINT, 4*1024); + + v = (int) l; + if (!g_atomic_int_compare_and_exchange (&val, 0, v)) { + v = g_atomic_int_get (&val); + g_return_val_if_fail (v > 0, 4*1024); + } + } + + nm_assert (v > 0); +#if NM_MORE_ASSERTS > 5 + nm_assert (v == getpagesize ()); + nm_assert (v == sysconf (_SC_PAGESIZE)); +#endif + + return v; +} diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index f3f3831e49..37d65e877c 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -1086,4 +1086,8 @@ nm_strv_ptrarray_take_gstring (GPtrArray *cmd, FALSE)); } +/*****************************************************************************/ + +int nm_utils_getpagesize (void); + #endif /* __NM_SHARED_UTILS_H__ */ diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c index ccd2ff9bfc..806f05b95b 100644 --- a/src/platform/nm-netlink.c +++ b/src/platform/nm-netlink.c @@ -255,20 +255,6 @@ nla_reserve (struct nl_msg *msg, int attrtype, int attrlen) /*****************************************************************************/ -static int -get_default_page_size (void) -{ - static int val = 0; - int v; - - if (G_UNLIKELY (val == 0)) { - v = getpagesize (); - g_assert (v > 0); - val = v; - } - return val; -} - struct nl_msg * nlmsg_alloc_size (size_t len) { @@ -298,7 +284,7 @@ nlmsg_alloc_size (size_t len) struct nl_msg * nlmsg_alloc (void) { - return nlmsg_alloc_size (get_default_page_size ()); + return nlmsg_alloc_size (nm_utils_getpagesize ()); } struct nl_msg * @@ -1334,7 +1320,6 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, { ssize_t n; int flags = 0; - static int page_size = 0; struct iovec iov; struct msghdr msg = { .msg_name = (void *) nla, @@ -1354,10 +1339,8 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, && sk->s_bufsize == 0)) flags |= MSG_PEEK | MSG_TRUNC; - if (page_size == 0) - page_size = getpagesize () * 4; - - iov.iov_len = sk->s_bufsize ?: page_size; + iov.iov_len = sk->s_bufsize + ?: (((size_t) nm_utils_getpagesize ()) * 4u); iov.iov_base = g_malloc (iov.iov_len); if ( creds From af67b4520f58c0afef0f951bebd17f5b928753aa Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 27 Dec 2018 14:22:59 +0100 Subject: [PATCH 04/12] shared: refactor nm_utils_mem_all_zero() to use memcmp() --- shared/nm-utils/nm-shared-utils.c | 23 +++++++++++++++++++++++ shared/nm-utils/nm-shared-utils.h | 14 +------------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c index 9daa7783da..bdd0b077fe 100644 --- a/shared/nm-utils/nm-shared-utils.c +++ b/shared/nm-utils/nm-shared-utils.c @@ -2317,3 +2317,26 @@ nm_utils_getpagesize (void) return v; } + +gboolean +nm_utils_mem_all_zero (gconstpointer data, gsize length) +{ + const unsigned char *p = data; + int len; + + /* Taken from https://github.com/rustyrussell/ccan/blob/9d2d2c49f053018724bcc6e37029da10b7c3d60d/ccan/mem/mem.c#L92, + * CC-0 licensed. */ + + /* Check first 16 bytes manually */ + for (len = 0; len < 16; len++) { + if (!length) + return TRUE; + if (*p) + return FALSE; + p++; + length--; + } + + /* Now we know that's zero, memcmp with self. */ + return memcmp (data, p, length) == 0; +} diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index 37d65e877c..de57418979 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -219,19 +219,7 @@ nm_ip_addr_set (int addr_family, gpointer dst, gconstpointer src) /*****************************************************************************/ -static inline gboolean -nm_utils_mem_all_zero (gconstpointer mem, gsize len) -{ - const guint8 *p; - - for (p = mem; len-- > 0; p++) { - if (*p != 0) - return FALSE; - } - - /* incidentally, a buffer with len==0, is also *all-zero*. */ - return TRUE; -} +gboolean nm_utils_mem_all_zero (gconstpointer data, gsize length); /*****************************************************************************/ From fce3243f12e3dd1714f6c207dd37967936bf5485 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 27 Dec 2018 14:37:21 +0100 Subject: [PATCH 05/12] shared/trivial: rename nm_utils_mem_all_zero() to nm_utils_memeqzero() in systemd/systemd, systemd/casync, and rustyrussel/ccan (github) this function is called "memeqzero()". Rename, to use a more popular name. --- shared/nm-utils/nm-shared-utils.c | 2 +- shared/nm-utils/nm-shared-utils.h | 2 +- src/platform/nm-platform.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c index bdd0b077fe..93b476d645 100644 --- a/shared/nm-utils/nm-shared-utils.c +++ b/shared/nm-utils/nm-shared-utils.c @@ -2319,7 +2319,7 @@ nm_utils_getpagesize (void) } gboolean -nm_utils_mem_all_zero (gconstpointer data, gsize length) +nm_utils_memeqzero (gconstpointer data, gsize length) { const unsigned char *p = data; int len; diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index de57418979..76049804f4 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -219,7 +219,7 @@ nm_ip_addr_set (int addr_family, gpointer dst, gconstpointer src) /*****************************************************************************/ -gboolean nm_utils_mem_all_zero (gconstpointer data, gsize length); +gboolean nm_utils_memeqzero (gconstpointer data, gsize length); /*****************************************************************************/ diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index af5548ecdc..f64015c70e 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -5577,7 +5577,7 @@ nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, g " tx %"G_GUINT64_FORMAT "%s", /* allowed-ips */ public_key_b64, - nm_utils_mem_all_zero (peer->preshared_key, sizeof (peer->preshared_key)) + nm_utils_memeqzero (peer->preshared_key, sizeof (peer->preshared_key)) ? "" : " preshared-key (hidden)", s_endpoint, @@ -5607,7 +5607,7 @@ nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireGuard *lnk, char *bu if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) return buf; - if (!nm_utils_mem_all_zero (lnk->public_key, sizeof (lnk->public_key))) + if (!nm_utils_memeqzero (lnk->public_key, sizeof (lnk->public_key))) public_b64 = g_base64_encode (lnk->public_key, sizeof (lnk->public_key)); g_snprintf (buf, len, @@ -5620,7 +5620,7 @@ nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireGuard *lnk, char *bu ? " public-key " : "", public_b64 ?: "", - nm_utils_mem_all_zero (lnk->private_key, sizeof (lnk->private_key)) + nm_utils_memeqzero (lnk->private_key, sizeof (lnk->private_key)) ? "" : " private-key (hidden)", lnk->listen_port, From e5fb1dd6e7fff3827eca0ec79e890b21ed96284d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 23 Dec 2018 14:25:56 +0100 Subject: [PATCH 06/12] netlink: track ucred via a boolean field in struct nl_msg Also, accept NULL in nlmsg_set_creds() to clear the set credentials. --- src/platform/nm-linux-platform.c | 3 +-- src/platform/nm-netlink.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 979e6a6eaa..d9af54c2c3 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -7422,8 +7422,7 @@ continue_reading: _LOGt ("netlink: recvmsg: new message %s", nl_nlmsghdr_to_str (hdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); - if (creds) - nlmsg_set_creds (msg, creds); + nlmsg_set_creds (msg, creds); if (hdr->nlmsg_flags & NLM_F_MULTI) multipart = TRUE; diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c index 806f05b95b..a4feee0564 100644 --- a/src/platform/nm-netlink.c +++ b/src/platform/nm-netlink.c @@ -44,16 +44,14 @@ #define NETLINK_EXT_ACK 11 #endif -#define NL_MSG_CRED_PRESENT 1 - struct nl_msg { int nm_protocol; - int nm_flags; struct sockaddr_nl nm_src; struct sockaddr_nl nm_dst; struct ucred nm_creds; struct nlmsghdr * nm_nlh; size_t nm_size; + bool nm_creds_has:1; }; struct nl_sock { @@ -610,7 +608,7 @@ nlmsg_set_src (struct nl_msg *msg, struct sockaddr_nl *addr) struct ucred * nlmsg_get_creds (struct nl_msg *msg) { - if (msg->nm_flags & NL_MSG_CRED_PRESENT) + if (msg->nm_creds_has) return &msg->nm_creds; return NULL; } @@ -618,8 +616,11 @@ nlmsg_get_creds (struct nl_msg *msg) void nlmsg_set_creds (struct nl_msg *msg, struct ucred *creds) { - memcpy (&msg->nm_creds, creds, sizeof (*creds)); - msg->nm_flags |= NL_MSG_CRED_PRESENT; + if (creds) { + memcpy (&msg->nm_creds, creds, sizeof (*creds)); + msg->nm_creds_has = TRUE; + } else + msg->nm_creds_has = FALSE; } /*****************************************************************************/ @@ -1098,8 +1099,7 @@ continue_reading: nlmsg_set_proto (msg, sk->s_proto); nlmsg_set_src (msg, &nla); - if (creds) - nlmsg_set_creds (msg, creds); + nlmsg_set_creds (msg, creds); nrecv++; From 2e48f6419ffaff960548f40e0a54303e35b9a7bb Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 23 Dec 2018 14:39:22 +0100 Subject: [PATCH 07/12] netlink: don't heap allocate struct ucred during nla_recv() Instead, fill a preallocated output buffer provided by the caller. --- src/platform/nm-linux-platform.c | 16 ++++++++-------- src/platform/nm-netlink.c | 31 +++++++++++++++++++------------ src/platform/nm-netlink.h | 7 +++++-- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index d9af54c2c3..45016ea50b 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -7367,13 +7367,13 @@ event_handler_recvmsgs (NMPlatform *platform, gboolean handle_events) struct nlmsghdr *hdr; WaitForNlResponseResult seq_result; struct sockaddr_nl nla = {0}; - nm_auto_free struct ucred *creds = NULL; + struct ucred creds; + gboolean creds_has; nm_auto_free unsigned char *buf = NULL; continue_reading: g_clear_pointer (&buf, free); - g_clear_pointer (&creds, free); - n = nl_recv (sk, &nla, &buf, &creds); + n = nl_recv (sk, &nla, &buf, &creds, &creds_has); if (n <= 0) { @@ -7410,11 +7410,11 @@ continue_reading: nlmsg_set_proto (msg, NETLINK_ROUTE); nlmsg_set_src (msg, &nla); - if (!creds || creds->pid) { - if (creds) - _LOGT ("netlink: recvmsg: received non-kernel message (pid %d)", creds->pid); - else + if (!creds_has || creds.pid) { + if (!creds_has) _LOGT ("netlink: recvmsg: received message without credentials"); + else + _LOGT ("netlink: recvmsg: received non-kernel message (pid %d)", creds.pid); err = 0; goto stop; } @@ -7422,7 +7422,7 @@ continue_reading: _LOGt ("netlink: recvmsg: new message %s", nl_nlmsghdr_to_str (hdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); - nlmsg_set_creds (msg, creds); + nlmsg_set_creds (msg, &creds); if (hdr->nlmsg_flags & NLM_F_MULTI) multipart = TRUE; diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c index a4feee0564..72f7c73495 100644 --- a/src/platform/nm-netlink.c +++ b/src/platform/nm-netlink.c @@ -1084,10 +1084,11 @@ nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb) gs_free unsigned char *buf = NULL; struct nlmsghdr *hdr; struct sockaddr_nl nla = { 0 }; - gs_free struct ucred *creds = NULL; + struct ucred creds; + gboolean creds_has; continue_reading: - n = nl_recv (sk, &nla, &buf, &creds); + n = nl_recv (sk, &nla, &buf, &creds, &creds_has); if (n <= 0) return n; @@ -1099,7 +1100,7 @@ continue_reading: nlmsg_set_proto (msg, sk->s_proto); nlmsg_set_src (msg, &nla); - nlmsg_set_creds (msg, creds); + nlmsg_set_creds (msg, creds_has ? &creds : NULL); nrecv++; @@ -1203,7 +1204,6 @@ skip: if (multipart) { /* Multipart message not yet complete, continue reading */ - nm_clear_g_free (&creds); nm_clear_g_free (&buf); goto continue_reading; @@ -1315,8 +1315,11 @@ int nl_send_auto (struct nl_sock *sk, struct nl_msg *msg) } int -nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, - unsigned char **buf, struct ucred **creds) +nl_recv (struct nl_sock *sk, + struct sockaddr_nl *nla, + unsigned char **buf, + struct ucred *out_creds, + gboolean *out_creds_has) { ssize_t n; int flags = 0; @@ -1327,12 +1330,13 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, .msg_iov = &iov, .msg_iovlen = 1, }; - gs_free struct ucred* tmpcreds = NULL; + struct ucred tmpcreds; + gboolean tmpcreds_has = FALSE; int retval; nm_assert (nla); nm_assert (buf && !*buf); - nm_assert (!creds || !*creds); + nm_assert (!out_creds_has == !out_creds); if ( (sk->s_flags & NL_MSG_PEEK) || ( !(sk->s_flags & NL_MSG_PEEK_EXPLICIT) @@ -1343,7 +1347,7 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, ?: (((size_t) nm_utils_getpagesize ()) * 4u); iov.iov_base = g_malloc (iov.iov_len); - if ( creds + if ( out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) { msg.msg_controllen = CMSG_SPACE (sizeof (struct ucred)); msg.msg_control = g_malloc (msg.msg_controllen); @@ -1403,7 +1407,7 @@ retry: goto abort; } - if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) { + if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) { struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) { @@ -1411,7 +1415,8 @@ retry: continue; if (cmsg->cmsg_type != SCM_CREDENTIALS) continue; - tmpcreds = nm_memdup (CMSG_DATA (cmsg), sizeof (*tmpcreds)); + memcpy (&tmpcreds, CMSG_DATA (cmsg), sizeof (tmpcreds)); + tmpcreds_has = TRUE; break; } } @@ -1427,6 +1432,8 @@ abort: } *buf = iov.iov_base; - NM_SET_OUT (creds, g_steal_pointer (&tmpcreds)); + if (out_creds && tmpcreds_has) + *out_creds = tmpcreds; + NM_SET_OUT (out_creds_has, tmpcreds_has); return retval; } diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h index 2fbddff4cf..f1f8394052 100644 --- a/src/platform/nm-netlink.h +++ b/src/platform/nm-netlink.h @@ -416,8 +416,11 @@ int nl_socket_add_memberships (struct nl_sock *sk, int group, ...); int nl_connect (struct nl_sock *sk, int protocol); -int nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, - unsigned char **buf, struct ucred **creds); +int nl_recv (struct nl_sock *sk, + struct sockaddr_nl *nla, + unsigned char **buf, + struct ucred *out_creds, + gboolean *out_creds_has); int nl_send (struct nl_sock *sk, struct nl_msg *msg); From 0713a6996c19d4d02ef048ab93278bc1f5e33c09 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Dec 2018 00:41:01 +0100 Subject: [PATCH 08/12] platform: track wireguard endpoint as sockaddr struct We need to track the IPv6 endpoint as struct sockaddr_in6, so that we have access to the scope-id. --- src/platform/nm-linux-platform.c | 49 ++++++++++++++++++-------------- src/platform/nm-platform.c | 20 ++++++++----- src/platform/nmp-object.c | 22 +++++++------- src/platform/nmp-object.h | 12 ++++++-- 4 files changed, 59 insertions(+), 44 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 45016ea50b..2979ee5d38 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -475,6 +475,30 @@ static struct nl_sock *_genl_sock (NMLinuxPlatform *platform); /*****************************************************************************/ +static int +_sock_addr_set_unaligned (NMSockAddrUnion *dst, + gconstpointer src, + gsize src_len) +{ + int f_expected; + struct sockaddr sa; + + if (src_len == sizeof (struct sockaddr_in)) + f_expected = AF_INET; + else if (src_len == sizeof (struct sockaddr_in6)) + f_expected = AF_INET6; + else + return AF_UNSPEC; + + memcpy (&sa.sa_family, &((struct sockaddr *) src)->sa_family, sizeof (sa.sa_family)); + if (sa.sa_family != f_expected) + return AF_UNSPEC; + memcpy (dst, src, src_len); + return f_expected; +} + +/*****************************************************************************/ + static int wait_for_nl_response_to_nmerr (WaitForNlResponseResult seq_result) { @@ -2009,28 +2033,9 @@ _wireguard_update_from_peers_nla (CList *peers, 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); - } + _sock_addr_set_unaligned (&peer_c->data.endpoint, + nla_data (tb[WGPEER_A_ENDPOINT]), + nla_len (tb[WGPEER_A_ENDPOINT])); } if (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]) peer_c->data.persistent_keepalive_interval = nla_get_u64 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index f64015c70e..c750caf567 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -5550,20 +5550,26 @@ nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, g gs_free char *public_key_b64 = NULL; char s_endpoint[NM_UTILS_INET_ADDRSTRLEN + 100]; char s_addr[NM_UTILS_INET_ADDRSTRLEN]; + char s_scope_id[40]; guint i; nm_utils_to_string_buffer_init (&buf, &len); - if (peer->endpoint_family == AF_INET) { + if (peer->endpoint.sa.sa_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_utils_inet4_ntop (peer->endpoint.in.sin_addr.s_addr, s_addr), + (guint) htons (peer->endpoint.in.sin_port)); + } else if (peer->endpoint.sa.sa_family == AF_INET6) { + if (peer->endpoint.in6.sin6_scope_id != 0) + nm_sprintf_buf (s_scope_id, "@%u", peer->endpoint.in6.sin6_scope_id); + else + s_scope_id[0] = '\0'; nm_sprintf_buf (s_endpoint, - " endpoint [%s]:%u", - nm_utils_inet6_ntop (&peer->endpoint_addr.addr6, s_addr), - (guint) peer->endpoint_port); + " endpoint [%s]%s:%u", + nm_utils_inet6_ntop (&peer->endpoint.in6.sin6_addr, s_addr), + s_scope_id, + (guint) htons (peer->endpoint.in6.sin6_port)); } else s_endpoint[0] = '\0'; diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index c0711c7927..03ddaaa7b3 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -393,13 +393,12 @@ _wireguard_peer_hash_update (const NMPWireGuardPeer *peer, peer->tx_bytes, peer->last_handshake_time.tv_sec, peer->last_handshake_time.tv_nsec, - peer->endpoint_port, - peer->endpoint_family); + peer->endpoint.sa.sa_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); + if (peer->endpoint.sa.sa_family == AF_INET) + nm_hash_update_val (h, peer->endpoint.in); + else if (peer->endpoint.sa.sa_family == AF_INET6) + nm_hash_update_val (h, peer->endpoint.in6); for (i = 0; i < peer->allowed_ips_len; i++) _wireguard_allowed_ip_hash_update (&peer->allowed_ips[i], h); @@ -419,15 +418,14 @@ _wireguard_peer_cmp (const NMPWireGuardPeer *a, 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 (a, b, endpoint.sa.sa_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); + if (a->endpoint.sa.sa_family == AF_INET) + NM_CMP_FIELD_MEMCMP (a, b, endpoint.in); + else if (a->endpoint.sa.sa_family == AF_INET6) + NM_CMP_FIELD_MEMCMP (a, b, endpoint.in6); for (i = 0; i < a->allowed_ips_len; i++) { NM_CMP_RETURN (_wireguard_allowed_ip_cmp (&a->allowed_ips[i], diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 66c0eebef4..efba5f1b8d 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -21,6 +21,8 @@ #ifndef __NMP_OBJECT_H__ #define __NMP_OBJECT_H__ +#include + #include "nm-utils/nm-obj.h" #include "nm-utils/nm-dedup-multi.h" #include "nm-platform.h" @@ -29,6 +31,12 @@ struct udev_device; /*****************************************************************************/ +typedef union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; +} NMSockAddrUnion; + typedef struct { NMIPAddr addr; guint8 family; @@ -36,7 +44,7 @@ typedef struct { } NMPWireGuardAllowedIP; typedef struct _NMPWireGuardPeer { - NMIPAddr endpoint_addr; + NMSockAddrUnion endpoint; struct timespec last_handshake_time; guint64 rx_bytes; guint64 tx_bytes; @@ -49,10 +57,8 @@ typedef struct _NMPWireGuardPeer { 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; /*****************************************************************************/ From 7a105c2191a00f077539b4948453d032b9018097 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 27 Dec 2018 14:27:51 +0100 Subject: [PATCH 09/12] netlink: don't require a callback argument in nl_recvmsgs() --- src/platform/nm-netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c index 72f7c73495..6abc1c3a34 100644 --- a/src/platform/nm-netlink.c +++ b/src/platform/nm-netlink.c @@ -1055,7 +1055,7 @@ nl_wait_for_ack (struct nl_sock *sk, do { \ const struct nl_cb *_cb = (cb); \ \ - if (_cb->type##_cb) { \ + if (_cb && _cb->type##_cb) { \ /* the returned value here must be either a negative * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ \ nmerr = _cb->type##_cb ((msg), _cb->type##_arg); \ @@ -1171,7 +1171,7 @@ continue_reading: } if (e->error) { /* Error message reported back from kernel. */ - if (cb->err_cb) { + if (cb && cb->err_cb) { /* the returned value here must be either a negative * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ nmerr = cb->err_cb (&nla, e, From fb79c79d872f941bae5603cf0832b1af7d456cce Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 27 Dec 2018 14:28:23 +0100 Subject: [PATCH 10/12] netlink: add nla_put() helpers to set integers --- src/platform/nm-netlink.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h index f1f8394052..84bbe27b22 100644 --- a/src/platform/nm-netlink.h +++ b/src/platform/nm-netlink.h @@ -187,6 +187,24 @@ nla_put_string (struct nl_msg *msg, int attrtype, const char *str) return nla_put(msg, attrtype, strlen(str) + 1, str); } +static inline int +nla_put_uint8 (struct nl_msg *msg, int attrtype, uint8_t val) +{ + return nla_put (msg, attrtype, sizeof (val), &val); +} + +static inline int +nla_put_uint16 (struct nl_msg *msg, int attrtype, uint16_t val) +{ + return nla_put (msg, attrtype, sizeof (val), &val); +} + +static inline int +nla_put_uint32 (struct nl_msg *msg, int attrtype, uint32_t val) +{ + return nla_put (msg, attrtype, sizeof (val), &val); +} + #define NLA_PUT(msg, attrtype, attrlen, data) \ do { \ if (nla_put(msg, attrtype, attrlen, data) < 0) \ From 7b935c8940bec2dae19972c35011cfeb75e6f6e3 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 29 Dec 2018 00:22:58 +0100 Subject: [PATCH 11/12] device: use NM_IN_STRSET() in nm_connection_is_virtual() --- libnm-core/nm-connection.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 9e5de7b267..eca9c1dfdd 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -2305,23 +2305,23 @@ nm_connection_is_virtual (NMConnection *connection) if (!type) return FALSE; - if ( !strcmp (type, NM_SETTING_6LOWPAN_SETTING_NAME) - || !strcmp (type, NM_SETTING_BOND_SETTING_NAME) - || !strcmp (type, NM_SETTING_DUMMY_SETTING_NAME) - || !strcmp (type, NM_SETTING_TEAM_SETTING_NAME) - || !strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME) - || !strcmp (type, NM_SETTING_VLAN_SETTING_NAME) - || !strcmp (type, NM_SETTING_TUN_SETTING_NAME) - || !strcmp (type, NM_SETTING_IP_TUNNEL_SETTING_NAME) - || !strcmp (type, NM_SETTING_MACSEC_SETTING_NAME) - || !strcmp (type, NM_SETTING_MACVLAN_SETTING_NAME) - || !strcmp (type, NM_SETTING_OVS_BRIDGE_SETTING_NAME) - || !strcmp (type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) - || !strcmp (type, NM_SETTING_OVS_PORT_SETTING_NAME) - || !strcmp (type, NM_SETTING_VXLAN_SETTING_NAME)) + if (NM_IN_STRSET (type, NM_SETTING_6LOWPAN_SETTING_NAME, + NM_SETTING_BOND_SETTING_NAME, + NM_SETTING_BRIDGE_SETTING_NAME, + NM_SETTING_DUMMY_SETTING_NAME, + NM_SETTING_IP_TUNNEL_SETTING_NAME, + NM_SETTING_MACSEC_SETTING_NAME, + NM_SETTING_MACVLAN_SETTING_NAME, + NM_SETTING_OVS_BRIDGE_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME, + NM_SETTING_OVS_PORT_SETTING_NAME, + NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TUN_SETTING_NAME, + NM_SETTING_VLAN_SETTING_NAME, + NM_SETTING_VXLAN_SETTING_NAME)) return TRUE; - if (!strcmp (type, NM_SETTING_INFINIBAND_SETTING_NAME)) { + if (nm_streq (type, NM_SETTING_INFINIBAND_SETTING_NAME)) { NMSettingInfiniband *s_ib; s_ib = nm_connection_get_setting_infiniband (connection); From a5c894c35f5621e2bcf2c1d177e70aeabac451dd Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 25 Dec 2018 18:41:28 +0100 Subject: [PATCH 12/12] platform: create wireguard netdev interface 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 --- src/platform/nm-linux-platform.c | 339 ++++++++++++++++++++++++++++++- src/platform/nm-platform.c | 55 +++++ src/platform/nm-platform.h | 19 +- src/platform/nmp-object.h | 4 + src/platform/tests/test-link.c | 273 ++++++++++++++++++++++++- 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);