libnm/tests: add tests for creating wireguard connection profiles

This commit is contained in:
Thomas Haller 2019-01-03 13:38:02 +01:00
parent e148ec07d5
commit 395a78618b

View file

@ -115,6 +115,30 @@ _connection_new_from_dbus_strict (GVariant *dict,
/*****************************************************************************/ /*****************************************************************************/
static char *
_create_random_ipaddr (int addr_family, gboolean as_service)
{
char delimiter = as_service ? ':' : '/';
int num;
if (addr_family == AF_UNSPEC)
addr_family = nmtst_rand_select (AF_INET, AF_INET6);
g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
if (as_service)
num = (nmtst_get_rand_int () % 1000) + 30000;
else
num = addr_family == AF_INET ? 32 : 128;
if (addr_family == AF_INET)
return g_strdup_printf ("192.168.%u.%u%c%d", nmtst_get_rand_int () % 256, nmtst_get_rand_int () % 256, delimiter, num);
else
return g_strdup_printf ("a:b:c::%02x:%02x%c%d", nmtst_get_rand_int () % 256, nmtst_get_rand_int () % 256, delimiter, num);
}
/*****************************************************************************/
static void static void
compare_blob_data (const char *test, compare_blob_data (const char *test,
const char *key_path, const char *key_path,
@ -2013,6 +2037,235 @@ test_tc_config_dbus (void)
/*****************************************************************************/ /*****************************************************************************/
static GPtrArray *
_rndt_wg_peers_create (void)
{
GPtrArray *wg_peers;
guint i, n;
wg_peers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_wireguard_peer_unref);
n = nmtst_get_rand_int () % 10;
for (i = 0; i < n; i++) {
NMWireGuardPeer *peer;
guint8 public_key_buf[NM_WIREGUARD_PUBLIC_KEY_LEN];
guint8 preshared_key_buf[NM_WIREGUARD_SYMMETRIC_KEY_LEN];
gs_free char *public_key = NULL;
gs_free char *preshared_key = NULL;
gs_free char *s_endpoint = NULL;
guint i_aip, n_aip;
/* we don't bother to create a valid curve25519 public key. Of course, libnm cannot
* check whether the public key is bogus or not. Hence, for our purpose a random
* bogus key is good enough. */
public_key = g_base64_encode (nmtst_rand_buf (NULL, public_key_buf, sizeof (public_key_buf)), sizeof (public_key_buf));
preshared_key = g_base64_encode (nmtst_rand_buf (NULL, preshared_key_buf, sizeof (preshared_key_buf)), sizeof (preshared_key_buf));
s_endpoint = _create_random_ipaddr (AF_UNSPEC, TRUE);
peer = nm_wireguard_peer_new ();
nm_wireguard_peer_set_public_key (peer, public_key);
nm_wireguard_peer_set_preshared_key (peer, nmtst_rand_select (NULL, preshared_key));
nm_wireguard_peer_set_preshared_key_flags (peer, nmtst_rand_select (NM_SETTING_SECRET_FLAG_NONE,
NM_SETTING_SECRET_FLAG_NOT_SAVED,
NM_SETTING_SECRET_FLAG_AGENT_OWNED));
nm_wireguard_peer_set_persistent_keepalive (peer,
nmtst_rand_select ((guint32) 0, nmtst_get_rand_int ()));
nm_wireguard_peer_set_endpoint (peer, nmtst_rand_select (s_endpoint, NULL));
n_aip = nmtst_rand_select (0, nmtst_get_rand_int () % 10);
for (i_aip = 0; i_aip < n_aip; i_aip++) {
gs_free char *aip = NULL;
aip = _create_random_ipaddr (AF_UNSPEC, FALSE);
if (!nm_wireguard_peer_append_allowed_ip (peer, aip, FALSE))
g_assert_not_reached ();
}
g_assert (nm_wireguard_peer_is_valid (peer, TRUE, TRUE, NULL));
nm_wireguard_peer_seal (peer);
g_ptr_array_add (wg_peers, peer);
}
return wg_peers;
}
static const char *
_rndt_wg_peers_to_keyfile (GPtrArray *wg_peers,
gboolean strict,
char **out_str)
{
nm_auto_free_gstring GString *gstr = NULL;
nm_auto_free_gstring GString *gstr_aip = NULL;
guint i, j;
g_assert (wg_peers);
g_assert (out_str && !*out_str);
nm_gstring_prepare (&gstr);
for (i = 0; i < wg_peers->len; i++) {
const NMWireGuardPeer *peer = wg_peers->pdata[i];
gs_free char *s_endpoint = NULL;
gs_free char *s_preshared_key = NULL;
gs_free char *s_preshared_key_flags = NULL;
gs_free char *s_persistent_keepalive = NULL;
gs_free char *s_allowed_ips = NULL;
if (nm_wireguard_peer_get_endpoint (peer))
s_endpoint = g_strdup_printf ("endpoint=%s\n", nm_wireguard_peer_get_endpoint (peer));
else if (!strict)
s_endpoint = g_strdup_printf ("endpoint=\n");
if ( nm_wireguard_peer_get_preshared_key (peer)
|| !strict) {
if (nm_wireguard_peer_get_preshared_key_flags (peer) == NM_SETTING_SECRET_FLAG_NONE)
s_preshared_key = g_strdup_printf ("preshared-key=%s\n", nm_wireguard_peer_get_preshared_key (peer) ?: "");
}
if ( nm_wireguard_peer_get_preshared_key_flags (peer) != NM_SETTING_SECRET_FLAG_NOT_REQUIRED
|| !strict)
s_preshared_key_flags = g_strdup_printf ("preshared-key-flags=%d\n", (int) nm_wireguard_peer_get_preshared_key_flags (peer));
if ( nm_wireguard_peer_get_persistent_keepalive (peer) != 0
|| !strict)
s_persistent_keepalive = g_strdup_printf ("persistent-keepalive=%u\n", nm_wireguard_peer_get_persistent_keepalive (peer));
if ( nm_wireguard_peer_get_allowed_ips_len (peer) > 0
|| !strict) {
nm_gstring_prepare (&gstr_aip);
for (j = 0; j < nm_wireguard_peer_get_allowed_ips_len (peer); j++)
g_string_append_printf (gstr_aip, "%s;", nm_wireguard_peer_get_allowed_ip (peer, j, NULL));
s_allowed_ips = g_strdup_printf ("allowed-ips=%s\n", gstr_aip->str);
}
if ( !s_endpoint
&& !s_preshared_key
&& !s_preshared_key_flags
&& !s_persistent_keepalive
&& !s_allowed_ips)
s_endpoint = g_strdup_printf ("endpoint=\n");
g_string_append_printf (gstr,
"\n"
"[wireguard-peer.%s]\n"
"%s" /* endpoint */
"%s" /* preshared-key */
"%s" /* preshared-key-flags */
"%s" /* persistent-keepalive */
"%s" /* allowed-ips */
"",
nm_wireguard_peer_get_public_key (peer),
s_endpoint ?: "",
s_preshared_key ?: "",
s_preshared_key_flags ?: "",
s_persistent_keepalive ?: "",
s_allowed_ips ?: "");
}
return (*out_str = g_string_free (g_steal_pointer (&gstr), FALSE));
}
static void
_rndt_wg_peers_assert_equal (NMSettingWireGuard *s_wg,
GPtrArray *peers,
gboolean consider_persistent_secrets,
gboolean consider_all_secrets,
gboolean expect_no_secrets)
{
guint i;
g_assert (NM_IS_SETTING_WIREGUARD (s_wg));
g_assert (peers);
g_assert_cmpint (peers->len, ==, nm_setting_wireguard_get_peers_len (s_wg));
for (i = 0; i < peers->len; i++) {
const NMWireGuardPeer *a = peers->pdata[i];
const NMWireGuardPeer *b = nm_setting_wireguard_get_peer (s_wg, i);
gboolean consider_secrets;
g_assert (a);
g_assert (b);
g_assert_cmpint (nm_wireguard_peer_cmp (a, b, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS), ==, 0);
if ( consider_all_secrets
|| !nm_wireguard_peer_get_preshared_key (a))
consider_secrets = TRUE;
else if (nm_wireguard_peer_get_preshared_key (b))
consider_secrets = TRUE;
else if ( consider_persistent_secrets
&& nm_wireguard_peer_get_preshared_key_flags (b) == NM_SETTING_SECRET_FLAG_NONE)
consider_secrets = TRUE;
else
consider_secrets = FALSE;
if (consider_secrets) {
g_assert_cmpstr (nm_wireguard_peer_get_preshared_key (a), ==, nm_wireguard_peer_get_preshared_key (b));
g_assert_cmpint (nm_wireguard_peer_cmp (a, b, NM_SETTING_COMPARE_FLAG_EXACT), ==, 0);
}
if (expect_no_secrets)
g_assert_cmpstr (nm_wireguard_peer_get_preshared_key (b), ==, NULL);
}
}
static void
_rndt_wg_peers_fix_secrets (NMSettingWireGuard *s_wg,
GPtrArray *peers)
{
guint i;
g_assert (NM_IS_SETTING_WIREGUARD (s_wg));
g_assert (peers);
g_assert_cmpint (peers->len, ==, nm_setting_wireguard_get_peers_len (s_wg));
for (i = 0; i < peers->len; i++) {
const NMWireGuardPeer *a = peers->pdata[i];
const NMWireGuardPeer *b = nm_setting_wireguard_get_peer (s_wg, i);
nm_auto_unref_wgpeer NMWireGuardPeer *b_clone = NULL;
g_assert (a);
g_assert (b);
g_assert_cmpint (nm_wireguard_peer_get_preshared_key_flags (a), ==, nm_wireguard_peer_get_preshared_key_flags (b));
g_assert_cmpint (nm_wireguard_peer_cmp (a, b, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS), ==, 0);
if (!nm_streq0 (nm_wireguard_peer_get_preshared_key (a),
nm_wireguard_peer_get_preshared_key (b))) {
g_assert_cmpstr (nm_wireguard_peer_get_preshared_key (a), !=, NULL);
g_assert_cmpstr (nm_wireguard_peer_get_preshared_key (b), ==, NULL);
g_assert (NM_IN_SET (nm_wireguard_peer_get_preshared_key_flags (a), NM_SETTING_SECRET_FLAG_AGENT_OWNED,
NM_SETTING_SECRET_FLAG_NOT_SAVED));
b_clone = nm_wireguard_peer_new_clone (b, TRUE);
nm_wireguard_peer_set_preshared_key (b_clone, nm_wireguard_peer_get_preshared_key (a));
nm_setting_wireguard_set_peer (s_wg, b_clone, i);
b = nm_setting_wireguard_get_peer (s_wg, i);
g_assert (b == b_clone);
} else {
if (nm_wireguard_peer_get_preshared_key (a)) {
g_assert (NM_IN_SET (nm_wireguard_peer_get_preshared_key_flags (a), NM_SETTING_SECRET_FLAG_NONE,
NM_SETTING_SECRET_FLAG_NOT_REQUIRED));
} else {
g_assert (NM_IN_SET (nm_wireguard_peer_get_preshared_key_flags (a), NM_SETTING_SECRET_FLAG_AGENT_OWNED,
NM_SETTING_SECRET_FLAG_NONE,
NM_SETTING_SECRET_FLAG_NOT_SAVED,
NM_SETTING_SECRET_FLAG_NOT_REQUIRED));
}
}
g_assert_cmpstr (nm_wireguard_peer_get_preshared_key (a), ==, nm_wireguard_peer_get_preshared_key (b));
g_assert_cmpint (nm_wireguard_peer_cmp (a, b, NM_SETTING_COMPARE_FLAG_EXACT), ==, 0);
}
}
static void static void
test_roundtrip_conversion (gconstpointer test_data) test_roundtrip_conversion (gconstpointer test_data)
{ {
@ -2022,7 +2275,18 @@ test_roundtrip_conversion (gconstpointer test_data)
const char *INTERFACE_NAME = nm_sprintf_bufa (100, "ifname%d", MODE); const char *INTERFACE_NAME = nm_sprintf_bufa (100, "ifname%d", MODE);
guint32 ETH_MTU = nmtst_rand_select ((guint32) 0u, guint32 ETH_MTU = nmtst_rand_select ((guint32) 0u,
nmtst_get_rand_int ()); nmtst_get_rand_int ());
const char *WG_PRIVATE_KEY = nmtst_get_rand_bool ()
? "yGXGK+5bVnxSJUejH4vbpXbq+ZtaG4NB8IHRK/aVtE0="
: NULL;
const NMSettingSecretFlags WG_PRIVATE_KEY_FLAGS = nmtst_rand_select (NM_SETTING_SECRET_FLAG_NONE,
NM_SETTING_SECRET_FLAG_NOT_SAVED,
NM_SETTING_SECRET_FLAG_AGENT_OWNED);
const guint WG_LISTEN_PORT = nmtst_rand_select (0u,
nmtst_get_rand_int () % 0x10000);
const guint WG_FWMARK = nmtst_rand_select (0u,
nmtst_get_rand_int ());
gs_unref_ptrarray GPtrArray *kf_data_arr = g_ptr_array_new_with_free_func (g_free); gs_unref_ptrarray GPtrArray *kf_data_arr = g_ptr_array_new_with_free_func (g_free);
gs_unref_ptrarray GPtrArray *wg_peers = NULL;
const NMConnectionSerializationFlags dbus_serialization_flags[] = { const NMConnectionSerializationFlags dbus_serialization_flags[] = {
NM_CONNECTION_SERIALIZE_ALL, NM_CONNECTION_SERIALIZE_ALL,
NM_CONNECTION_SERIALIZE_NO_SECRETS, NM_CONNECTION_SERIALIZE_NO_SECRETS,
@ -2031,9 +2295,12 @@ test_roundtrip_conversion (gconstpointer test_data)
guint dbus_serialization_flags_idx; guint dbus_serialization_flags_idx;
gs_unref_object NMConnection *con = NULL; gs_unref_object NMConnection *con = NULL;
gs_free_error GError *error = NULL; gs_free_error GError *error = NULL;
gs_free char *tmp_str = NULL;
guint kf_data_idx; guint kf_data_idx;
NMSettingConnection *s_con = NULL; NMSettingConnection *s_con = NULL;
NMSettingWired *s_eth = NULL; NMSettingWired *s_eth = NULL;
NMSettingWireGuard *s_wg = NULL;
guint i;
switch (MODE) { switch (MODE) {
case 0: case 0:
@ -2110,6 +2377,116 @@ test_roundtrip_conversion (gconstpointer test_data)
break; break;
case 1:
con = nmtst_create_minimal_connection (ID, UUID, "wireguard", &s_con);
g_object_set (s_con,
NM_SETTING_CONNECTION_INTERFACE_NAME,
INTERFACE_NAME,
NULL);
nmtst_connection_normalize (con);
s_wg = NM_SETTING_WIREGUARD (nm_connection_get_setting (con, NM_TYPE_SETTING_WIREGUARD));
g_ptr_array_add (kf_data_arr,
g_strdup_printf ("[connection]\n"
"id=%s\n"
"uuid=%s\n"
"type=wireguard\n"
"interface-name=%s\n"
"permissions=\n"
"\n"
"[ipv4]\n"
"dns-search=\n"
"method=disabled\n"
"\n"
"[ipv6]\n"
"addr-gen-mode=stable-privacy\n"
"dns-search=\n"
"method=ignore\n"
"",
ID,
UUID,
INTERFACE_NAME));
break;
case 2:
con = nmtst_create_minimal_connection (ID, UUID, "wireguard", &s_con);
g_object_set (s_con,
NM_SETTING_CONNECTION_INTERFACE_NAME,
INTERFACE_NAME,
NULL);
nmtst_connection_normalize (con);
s_wg = NM_SETTING_WIREGUARD (nm_connection_get_setting (con, NM_TYPE_SETTING_WIREGUARD));
g_object_set (s_wg,
NM_SETTING_WIREGUARD_PRIVATE_KEY,
WG_PRIVATE_KEY,
NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS,
WG_PRIVATE_KEY_FLAGS,
NM_SETTING_WIREGUARD_LISTEN_PORT,
WG_LISTEN_PORT,
NM_SETTING_WIREGUARD_FWMARK,
WG_FWMARK,
NULL);
wg_peers = _rndt_wg_peers_create ();
for (i = 0; i < wg_peers->len; i++)
nm_setting_wireguard_append_peer (s_wg, wg_peers->pdata[i]);
nm_clear_g_free (&tmp_str);
g_ptr_array_add (kf_data_arr,
g_strdup_printf ("[connection]\n"
"id=%s\n"
"uuid=%s\n"
"type=wireguard\n"
"interface-name=%s\n"
"permissions=\n"
"%s" /* [wireguard] */
"%s" /* fwmark */
"%s" /* listen-port */
"%s" /* private-key-flags */
"%s" /* private-key */
"%s" /* [wireguard-peers*] */
"\n"
"[ipv4]\n"
"dns-search=\n"
"method=disabled\n"
"\n"
"[ipv6]\n"
"addr-gen-mode=stable-privacy\n"
"dns-search=\n"
"method=ignore\n"
"",
ID,
UUID,
INTERFACE_NAME,
( ( (WG_FWMARK != 0)
|| (WG_LISTEN_PORT != 0)
|| (WG_PRIVATE_KEY_FLAGS != NM_SETTING_SECRET_FLAG_NONE)
|| ( WG_PRIVATE_KEY
&& WG_PRIVATE_KEY_FLAGS == NM_SETTING_SECRET_FLAG_NONE))
? "\n[wireguard]\n"
: ""),
( (WG_FWMARK != 0)
? nm_sprintf_bufa (100, "fwmark=%u\n", WG_FWMARK)
: ""),
( (WG_LISTEN_PORT != 0)
? nm_sprintf_bufa (100, "listen-port=%u\n", WG_LISTEN_PORT)
: ""),
( (WG_PRIVATE_KEY_FLAGS != NM_SETTING_SECRET_FLAG_NONE)
? nm_sprintf_bufa (100, "private-key-flags=%u\n", (guint) WG_PRIVATE_KEY_FLAGS)
: ""),
( ( WG_PRIVATE_KEY
&& WG_PRIVATE_KEY_FLAGS == NM_SETTING_SECRET_FLAG_NONE)
? nm_sprintf_bufa (100, "private-key=%s\n", WG_PRIVATE_KEY)
: ""),
_rndt_wg_peers_to_keyfile (wg_peers, TRUE, &tmp_str)));
_rndt_wg_peers_assert_equal (s_wg, wg_peers, TRUE, TRUE, FALSE);
break;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
} }
@ -2131,6 +2508,7 @@ test_roundtrip_conversion (gconstpointer test_data)
/* check that reading any of kf_data_arr yields the same result that we expect. */ /* check that reading any of kf_data_arr yields the same result that we expect. */
for (kf_data_idx = 0; kf_data_idx < kf_data_arr->len; kf_data_idx++) { for (kf_data_idx = 0; kf_data_idx < kf_data_arr->len; kf_data_idx++) {
gs_unref_object NMConnection *con2 = NULL; gs_unref_object NMConnection *con2 = NULL;
NMSettingWireGuard *s_wg2 = NULL;
NMSettingWired *s_eth2 = NULL; NMSettingWired *s_eth2 = NULL;
con2 = nmtst_create_connection_from_keyfile (kf_data_arr->pdata[kf_data_idx], "/no/where/file.nmconnection"); con2 = nmtst_create_connection_from_keyfile (kf_data_arr->pdata[kf_data_idx], "/no/where/file.nmconnection");
@ -2159,6 +2537,35 @@ test_roundtrip_conversion (gconstpointer test_data)
g_assert_cmpint (nm_setting_wired_get_mtu (s_eth), ==, ETH_MTU); g_assert_cmpint (nm_setting_wired_get_mtu (s_eth), ==, ETH_MTU);
g_assert_cmpint (nm_setting_wired_get_mtu (s_eth2), ==, ETH_MTU); g_assert_cmpint (nm_setting_wired_get_mtu (s_eth2), ==, ETH_MTU);
break; break;
case 1:
s_wg2 = NM_SETTING_WIREGUARD (nm_connection_get_setting (con2, NM_TYPE_SETTING_WIREGUARD));
g_assert (NM_IS_SETTING_WIREGUARD (s_wg2));
g_assert_cmpstr (nm_setting_wireguard_get_private_key (s_wg), ==, NULL);
g_assert_cmpstr (nm_setting_wireguard_get_private_key (s_wg2), ==, NULL);
break;
case 2:
s_wg2 = NM_SETTING_WIREGUARD (nm_connection_get_setting (con2, NM_TYPE_SETTING_WIREGUARD));
g_assert (NM_IS_SETTING_WIREGUARD (s_wg2));
/* the private key was lost due to the secret-flags. Patch it. */
if (WG_PRIVATE_KEY_FLAGS != NM_SETTING_SECRET_FLAG_NONE) {
g_assert_cmpstr (nm_setting_wireguard_get_private_key (s_wg2), ==, NULL);
g_object_set (s_wg2,
NM_SETTING_WIREGUARD_PRIVATE_KEY,
WG_PRIVATE_KEY,
NULL);
}
g_assert_cmpstr (nm_setting_wireguard_get_private_key (s_wg), ==, WG_PRIVATE_KEY);
g_assert_cmpstr (nm_setting_wireguard_get_private_key (s_wg2), ==, WG_PRIVATE_KEY);
_rndt_wg_peers_assert_equal (s_wg2, wg_peers, TRUE, FALSE, FALSE);
_rndt_wg_peers_fix_secrets (s_wg2, wg_peers);
_rndt_wg_peers_assert_equal (s_wg2, wg_peers, TRUE, TRUE, FALSE);
break;
} }
nmtst_assert_connection_equals (con, nmtst_get_rand_bool (), con2, nmtst_get_rand_bool ()); nmtst_assert_connection_equals (con, nmtst_get_rand_bool (), con2, nmtst_get_rand_bool ());
@ -2168,6 +2575,7 @@ test_roundtrip_conversion (gconstpointer test_data)
NMConnectionSerializationFlags flag = dbus_serialization_flags[dbus_serialization_flags_idx]; NMConnectionSerializationFlags flag = dbus_serialization_flags[dbus_serialization_flags_idx];
gs_unref_variant GVariant *con_var = NULL; gs_unref_variant GVariant *con_var = NULL;
gs_unref_object NMConnection *con2 = NULL; gs_unref_object NMConnection *con2 = NULL;
NMSettingWireGuard *s_wg2 = NULL;
con_var = nm_connection_to_dbus (con, flag); con_var = nm_connection_to_dbus (con, flag);
g_assert (g_variant_is_of_type (con_var, NM_VARIANT_TYPE_CONNECTION)); g_assert (g_variant_is_of_type (con_var, NM_VARIANT_TYPE_CONNECTION));
@ -2186,6 +2594,21 @@ test_roundtrip_conversion (gconstpointer test_data)
nmtst_keyfile_assert_data (kf, kf_data_arr->pdata[0], -1); nmtst_keyfile_assert_data (kf, kf_data_arr->pdata[0], -1);
} }
} }
switch (MODE) {
case 2:
if (flag == NM_CONNECTION_SERIALIZE_ALL) {
s_wg2 = NM_SETTING_WIREGUARD (nm_connection_get_setting (con2, NM_TYPE_SETTING_WIREGUARD));
if (flag == NM_CONNECTION_SERIALIZE_ALL)
_rndt_wg_peers_assert_equal (s_wg2, wg_peers, TRUE, TRUE, FALSE);
else if (flag == NM_CONNECTION_SERIALIZE_NO_SECRETS)
_rndt_wg_peers_assert_equal (s_wg2, wg_peers, FALSE, FALSE, TRUE);
else
g_assert_not_reached ();
}
break;
}
} }
} }
@ -2268,6 +2691,8 @@ main (int argc, char **argv)
#endif #endif
g_test_add_data_func ("/libnm/settings/roundtrip-conversion/general/0", GINT_TO_POINTER (0), test_roundtrip_conversion); g_test_add_data_func ("/libnm/settings/roundtrip-conversion/general/0", GINT_TO_POINTER (0), test_roundtrip_conversion);
g_test_add_data_func ("/libnm/settings/roundtrip-conversion/wireguard/1", GINT_TO_POINTER (1), test_roundtrip_conversion);
g_test_add_data_func ("/libnm/settings/roundtrip-conversion/wireguard/2", GINT_TO_POINTER (2), test_roundtrip_conversion);
return g_test_run (); return g_test_run ();
} }