summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-12-27 16:48:30 +0100
committerThomas Haller <thaller@redhat.com>2019-02-22 11:00:10 +0100
commitb521f426ab228b003e1e87348e116291d23dc88b (patch)
treeb4e1d229a747e42dc441935838ad2dc16b2acfec
parent1d47643d954d69aa6be86a0f308111da9f926389 (diff)
downloadNetworkManager-b521f426ab228b003e1e87348e116291d23dc88b.tar.gz
libnm,cli: add NMSettingWireGuard
For now only add the core settings, no peers' data. To support peers and the allowed-ips of the peers is more complicated and will be done later. It's more complicated because these are nested lists (allowed-ips) inside a list (peers). That is quite unusual and to conveniently support that in D-Bus API, in keyfile format, in libnm, and nmcli, is a effort. Also, it's further complicated by the fact that each peer has a secret (the preshared-key). Thus we probably need secret flags for each peer, which is a novelty as well (until now we require a fixed set of secrets per profile that is well known).
-rw-r--r--Makefile.am2
-rw-r--r--clients/cli/connections.c1
-rw-r--r--clients/common/nm-meta-setting-desc.c29
-rw-r--r--clients/common/nm-secret-agent-simple.c58
-rw-r--r--clients/common/settings-docs.h.in4
-rw-r--r--docs/libnm/libnm-docs.xml1
-rw-r--r--libnm-core/meson.build2
-rw-r--r--libnm-core/nm-connection.c27
-rw-r--r--libnm-core/nm-core-enum-types.c.template1
-rw-r--r--libnm-core/nm-core-internal.h11
-rw-r--r--libnm-core/nm-core-types.h1
-rw-r--r--libnm-core/nm-setting-wireguard.c404
-rw-r--r--libnm-core/nm-setting-wireguard.h80
-rw-r--r--libnm-core/nm-utils.c75
-rw-r--r--libnm/NetworkManager.h1
-rw-r--r--libnm/libnm.ver6
-rw-r--r--libnm/nm-autoptr.h1
-rw-r--r--po/POTFILES.in1
-rw-r--r--shared/nm-meta-setting.c7
-rw-r--r--shared/nm-meta-setting.h1
-rw-r--r--src/devices/nm-device-wireguard.c7
21 files changed, 710 insertions, 10 deletions
diff --git a/Makefile.am b/Makefile.am
index bbbb37de87..005dbace18 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -670,6 +670,7 @@ libnm_core_lib_h_pub_real = \
libnm-core/nm-setting-wifi-p2p.h \
libnm-core/nm-setting-wimax.h \
libnm-core/nm-setting-wired.h \
+ libnm-core/nm-setting-wireguard.h \
libnm-core/nm-setting-wireless-security.h \
libnm-core/nm-setting-wireless.h \
libnm-core/nm-setting-wpan.h \
@@ -739,6 +740,7 @@ libnm_core_lib_c_settings_real = \
libnm-core/nm-setting-wifi-p2p.c \
libnm-core/nm-setting-wimax.c \
libnm-core/nm-setting-wired.c \
+ libnm-core/nm-setting-wireguard.c \
libnm-core/nm-setting-wireless-security.c \
libnm-core/nm-setting-wireless.c \
libnm-core/nm-setting-wpan.c
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index ff7d020303..63cb0bb90c 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -822,6 +822,7 @@ const NmcMetaGenericInfo *const metagen_con_active_vpn[_NMC_GENERIC_INFO_TYPE_CO
NM_SETTING_VXLAN_SETTING_NAME"," \
NM_SETTING_WPAN_SETTING_NAME","\
NM_SETTING_6LOWPAN_SETTING_NAME","\
+ NM_SETTING_WIREGUARD_SETTING_NAME","\
NM_SETTING_PROXY_SETTING_NAME"," \
NM_SETTING_TC_CONFIG_SETTING_NAME"," \
NM_SETTING_SRIOV_SETTING_NAME"," \
diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c
index e33070dc06..03be32f645 100644
--- a/clients/common/nm-meta-setting-desc.c
+++ b/clients/common/nm-meta-setting-desc.c
@@ -7505,6 +7505,28 @@ static const NMMetaPropertyInfo *const property_infos_WIRED[] = {
};
#undef _CURRENT_NM_META_SETTING_TYPE
+#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_WIREGUARD
+static const NMMetaPropertyInfo *const property_infos_WIREGUARD[] = {
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_PRIVATE_KEY,
+ .is_secret = TRUE,
+ .property_type = &_pt_gobject_string,
+ ),
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS,
+ .property_type = &_pt_gobject_secret_flags,
+ ),
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_LISTEN_PORT,
+ .property_type = &_pt_gobject_int,
+ ),
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_FWMARK,
+ .property_type = &_pt_gobject_int,
+ .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, \
+ .base = 16,
+ ),
+ ),
+ NULL
+};
+
+#undef _CURRENT_NM_META_SETTING_TYPE
#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_WIRELESS
static const NMMetaPropertyInfo *const property_infos_WIRELESS[] = {
PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SSID,
@@ -8001,6 +8023,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN)
#define SETTING_PRETTY_NAME_WIFI_P2P N_("Wi-Fi P2P connection")
#define SETTING_PRETTY_NAME_WIMAX N_("WiMAX connection")
#define SETTING_PRETTY_NAME_WIRED N_("Wired Ethernet")
+#define SETTING_PRETTY_NAME_WIREGUARD N_("WireGuard VPN settings")
#define SETTING_PRETTY_NAME_WIRELESS N_("Wi-Fi connection")
#define SETTING_PRETTY_NAME_WIRELESS_SECURITY N_("Wi-Fi security settings")
#define SETTING_PRETTY_NAME_WPAN N_("WPAN settings")
@@ -8264,6 +8287,12 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
+ SETTING_INFO (WIREGUARD,
+ .valid_parts = NM_META_SETTING_VALID_PARTS (
+ NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
+ NM_META_SETTING_VALID_PART_ITEM (WIREGUARD, TRUE),
+ ),
+ ),
SETTING_INFO (WIRELESS,
.alias = "wifi",
.valid_parts = NM_META_SETTING_VALID_PARTS (
diff --git a/clients/common/nm-secret-agent-simple.c b/clients/common/nm-secret-agent-simple.c
index ffcb7c8978..6b72d2aa00 100644
--- a/clients/common/nm-secret-agent-simple.c
+++ b/clients/common/nm-secret-agent-simple.c
@@ -405,8 +405,8 @@ add_vpn_secret_helper (GPtrArray *secrets, NMSettingVpn *s_vpn, const char *name
static gboolean
add_vpn_secrets (RequestData *request,
- GPtrArray *secrets,
- char **msg)
+ GPtrArray *secrets,
+ char **msg)
{
NMSettingVpn *s_vpn = nm_connection_get_setting_vpn (request->connection);
const VpnPasswordName *secret_names, *p;
@@ -435,6 +435,56 @@ add_vpn_secrets (RequestData *request,
return TRUE;
}
+static gboolean
+add_wireguard_secrets (RequestData *request,
+ GPtrArray *secrets,
+ char **msg,
+ GError **error)
+{
+ NMSettingWireGuard *s_wg;
+ NMSecretAgentSimpleSecret *secret;
+ guint i;
+
+ s_wg = NM_SETTING_WIREGUARD (nm_connection_get_setting (request->connection, NM_TYPE_SETTING_WIREGUARD));
+ if (!s_wg) {
+ g_set_error (error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED,
+ "Cannot service a WireGuard secrets request %s for a connection without WireGuard settings",
+ request->request_id);
+ return FALSE;
+ }
+
+ if ( !request->hints
+ || !request->hints[0]
+ || g_strv_contains (NM_CAST_STRV_CC (request->hints), NM_SETTING_WIREGUARD_PRIVATE_KEY)) {
+ secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET,
+ _("WireGuard private-key"),
+ NM_SETTING (s_wg),
+ NM_SETTING_WIREGUARD_PRIVATE_KEY);
+ g_ptr_array_add (secrets, secret);
+ }
+
+ if (request->hints) {
+ for (i = 0; request->hints[i]; i++) {
+ const char *name = request->hints[i];
+ gs_free char *peer_name = NULL;
+
+ if (nm_streq (name, NM_SETTING_WIREGUARD_PRIVATE_KEY))
+ continue;
+
+ /* TODO: add support for WireGuard peers and their preshared-key. */
+ g_set_error (error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED,
+ _("Cannot service unknown WireGuard hint '%s' for secrets request %s"),
+ name,
+ request->request_id);
+ return FALSE;
+ }
+ }
+
+ *msg = g_strdup_printf (_("Secrets are required to connect WireGuard VPN '%s'"),
+ nm_connection_get_id (request->connection));
+ return TRUE;
+}
+
typedef struct {
GPid auth_dialog_pid;
GString *auth_dialog_response;
@@ -820,6 +870,10 @@ request_secrets_from_ui (RequestData *request)
if (!add_8021x_secrets (request, secrets))
goto out_fail;
}
+ } else if (nm_connection_is_type (request->connection, NM_SETTING_WIREGUARD_SETTING_NAME)) {
+ title = _("WireGuard VPN secret");
+ if (!add_wireguard_secrets (request, secrets, &msg, &error))
+ goto out_fail_error;
} else if (nm_connection_is_type (request->connection, NM_SETTING_CDMA_SETTING_NAME)) {
NMSettingCdma *s_cdma = nm_connection_get_setting_cdma (request->connection);
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
index 6a0586e30e..235a9c7f30 100644
--- a/clients/common/settings-docs.h.in
+++ b/clients/common/settings-docs.h.in
@@ -362,6 +362,10 @@
#define DESCRIBE_DOC_NM_SETTING_WIFI_P2P_WPS_METHOD N_("Flags indicating which mode of WPS is to be used. There's little point in changing the default setting as NetworkManager will automatically determine the best method to use.")
#define DESCRIBE_DOC_NM_SETTING_WIMAX_MAC_ADDRESS N_("If specified, this connection will only apply to the WiMAX device whose MAC address matches. This property does not change the MAC address of the device (known as MAC spoofing). Deprecated: 1")
#define DESCRIBE_DOC_NM_SETTING_WIMAX_NETWORK_NAME N_("Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1")
+#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_FWMARK N_("The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise it is a 32-bit fwmark for outgoing packets.")
+#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_LISTEN_PORT N_("The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up.")
+#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PRIVATE_KEY N_("The 256 bit private-key in base64 encoding.")
+#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS N_("Flags indicating how to handle the \"private-key\" property.")
#define DESCRIBE_DOC_NM_SETTING_WPAN_CHANNEL N_("IEEE 802.15.4 channel. A positive integer or -1, meaning \"do not set, use whatever the device is already set to\".")
#define DESCRIBE_DOC_NM_SETTING_WPAN_MAC_ADDRESS N_("If specified, this connection will only apply to the IEEE 802.15.4 (WPAN) MAC layer device whose permanent MAC address matches.")
#define DESCRIBE_DOC_NM_SETTING_WPAN_PAGE N_("IEEE 802.15.4 channel page. A positive integer or -1, meaning \"do not set, use whatever the device is already set to\".")
diff --git a/docs/libnm/libnm-docs.xml b/docs/libnm/libnm-docs.xml
index 2a7b76bf34..74866acebd 100644
--- a/docs/libnm/libnm-docs.xml
+++ b/docs/libnm/libnm-docs.xml
@@ -234,6 +234,7 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in
<xi:include href="xml/nm-setting-wifi-p2p.xml"/>
<xi:include href="xml/nm-setting-wimax.xml"/>
<xi:include href="xml/nm-setting-wired.xml"/>
+ <xi:include href="xml/nm-setting-wireguard.xml"/>
<xi:include href="xml/nm-setting-wireless-security.xml"/>
<xi:include href="xml/nm-setting-wireless.xml"/>
<xi:include href="xml/nm-setting-wpan.xml"/>
diff --git a/libnm-core/meson.build b/libnm-core/meson.build
index a2610fe46f..d10dd1c551 100644
--- a/libnm-core/meson.build
+++ b/libnm-core/meson.build
@@ -48,6 +48,7 @@ libnm_core_headers = files(
'nm-setting-wifi-p2p.h',
'nm-setting-wimax.h',
'nm-setting-wired.h',
+ 'nm-setting-wireguard.h',
'nm-setting-wireless-security.h',
'nm-setting-wireless.h',
'nm-setting-wpan.h',
@@ -104,6 +105,7 @@ libnm_core_settings_sources = files(
'nm-setting-wifi-p2p.c',
'nm-setting-wimax.c',
'nm-setting-wired.c',
+ 'nm-setting-wireguard.c',
'nm-setting-wireless-security.c',
'nm-setting-wireless.c',
'nm-setting-wpan.c',
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c
index 5e84cf45b6..e958aff06d 100644
--- a/libnm-core/nm-connection.c
+++ b/libnm-core/nm-connection.c
@@ -905,25 +905,24 @@ _supports_addr_family (NMConnection *self, int family)
static gboolean
_normalize_ip_config (NMConnection *self, GHashTable *parameters)
{
- const char *default_ip4_method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
- const char *default_ip6_method = NULL;
NMSettingIPConfig *s_ip4, *s_ip6;
NMSettingProxy *s_proxy;
NMSetting *setting;
gboolean changed = FALSE;
guint num, i;
- if (parameters)
- default_ip6_method = g_hash_table_lookup (parameters, NM_CONNECTION_NORMALIZE_PARAM_IP6_CONFIG_METHOD);
- if (!default_ip6_method)
- default_ip6_method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
-
s_ip4 = nm_connection_get_setting_ip4_config (self);
s_ip6 = nm_connection_get_setting_ip6_config (self);
s_proxy = nm_connection_get_setting_proxy (self);
if (_supports_addr_family (self, AF_INET)) {
+
if (!s_ip4) {
+ const char *default_ip4_method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
+
+ if (nm_connection_is_type (self, NM_SETTING_WIREGUARD_SETTING_NAME))
+ default_ip4_method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
+
/* But if no IP4 setting was specified, assume the caller was just
* being lazy and use the default method.
*/
@@ -966,6 +965,17 @@ _normalize_ip_config (NMConnection *self, GHashTable *parameters)
if (_supports_addr_family (self, AF_INET6)) {
if (!s_ip6) {
+ const char *default_ip6_method = NULL;
+
+ if (parameters)
+ default_ip6_method = g_hash_table_lookup (parameters, NM_CONNECTION_NORMALIZE_PARAM_IP6_CONFIG_METHOD);
+ if (!default_ip6_method) {
+ if (nm_connection_is_type (self, NM_SETTING_WIREGUARD_SETTING_NAME))
+ default_ip6_method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE;
+ else
+ default_ip6_method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
+ }
+
/* If no IP6 setting was specified, then assume that means IP6 config is
* allowed to fail.
*/
@@ -2419,7 +2429,8 @@ nm_connection_is_virtual (NMConnection *connection)
NM_SETTING_TEAM_SETTING_NAME,
NM_SETTING_TUN_SETTING_NAME,
NM_SETTING_VLAN_SETTING_NAME,
- NM_SETTING_VXLAN_SETTING_NAME))
+ NM_SETTING_VXLAN_SETTING_NAME,
+ NM_SETTING_WIREGUARD_SETTING_NAME))
return TRUE;
if (nm_streq (type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
diff --git a/libnm-core/nm-core-enum-types.c.template b/libnm-core/nm-core-enum-types.c.template
index 2cef0307a1..94744827ba 100644
--- a/libnm-core/nm-core-enum-types.c.template
+++ b/libnm-core/nm-core-enum-types.c.template
@@ -46,6 +46,7 @@
#include "nm-setting-wifi-p2p.h"
#include "nm-setting-wimax.h"
#include "nm-setting-wired.h"
+#include "nm-setting-wireguard.h"
#include "nm-setting-wireless-security.h"
#include "nm-setting-wireless.h"
#include "nm-setting-wpan.h"
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index 19a914956e..54d852a7fd 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -79,6 +79,7 @@
#include "nm-setting-wifi-p2p.h"
#include "nm-setting-wimax.h"
#include "nm-setting-wired.h"
+#include "nm-setting-wireguard.h"
#include "nm-setting-wireless-security.h"
#include "nm-setting-wireless.h"
#include "nm-setting-wpan.h"
@@ -768,4 +769,14 @@ gboolean _nm_connection_find_secret (NMConnection *self,
/*****************************************************************************/
+gboolean _nm_utils_wireguard_decode_key (const char *base64_key,
+ gsize required_key_len,
+ guint8 *out_key);
+
+gboolean _nm_utils_wireguard_normalize_key (const char *base64_key,
+ gsize required_key_len,
+ char **out_base64_key_norm);
+
+/*****************************************************************************/
+
#endif
diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h
index e8aa67a93f..f20ffc09da 100644
--- a/libnm-core/nm-core-types.h
+++ b/libnm-core/nm-core-types.h
@@ -72,6 +72,7 @@ typedef struct _NMSettingVxlan NMSettingVxlan;
typedef struct _NMSettingWifiP2P NMSettingWifiP2P;
typedef struct _NMSettingWimax NMSettingWimax;
typedef struct _NMSettingWired NMSettingWired;
+typedef struct _NMSettingWireGuard NMSettingWireGuard;
typedef struct _NMSettingWireless NMSettingWireless;
typedef struct _NMSettingWirelessSecurity NMSettingWirelessSecurity;
typedef struct _NMSettingWpan NMSettingWpan;
diff --git a/libnm-core/nm-setting-wireguard.c b/libnm-core/nm-setting-wireguard.c
new file mode 100644
index 0000000000..724dda55d1
--- /dev/null
+++ b/libnm-core/nm-setting-wireguard.c
@@ -0,0 +1,404 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2018 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-setting-wireguard.h"
+
+#include "nm-setting-private.h"
+#include "nm-utils-private.h"
+#include "nm-connection-private.h"
+#include "nm-utils/nm-secret-utils.h"
+
+/*****************************************************************************/
+
+/**
+ * SECTION:nm-setting-wireguard
+ * @short_description: Describes connection properties for wireguard related options
+ *
+ * The #NMSettingWireGuard object is a #NMSetting subclass that contains settings
+ * for configuring WireGuard.
+ **/
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+ PROP_PRIVATE_KEY,
+ PROP_PRIVATE_KEY_FLAGS,
+ PROP_LISTEN_PORT,
+ PROP_FWMARK,
+);
+
+typedef struct {
+ char *private_key;
+ NMSettingSecretFlags private_key_flags;
+ guint32 fwmark;
+ guint16 listen_port;
+ bool private_key_valid:1;
+} NMSettingWireGuardPrivate;
+
+/**
+ * NMSettingWireGuard:
+ *
+ * WireGuard Ethernet Settings
+ *
+ * Since: 1.16
+ */
+struct _NMSettingWireGuard {
+ NMSetting parent;
+ NMSettingWireGuardPrivate _priv;
+};
+
+struct _NMSettingWireGuardClass {
+ NMSettingClass parent;
+};
+
+G_DEFINE_TYPE (NMSettingWireGuard, nm_setting_wireguard, NM_TYPE_SETTING)
+
+#define NM_SETTING_WIREGUARD_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSettingWireGuard, NM_IS_SETTING_WIREGUARD, NMSetting)
+
+/*****************************************************************************/
+
+/**
+ * nm_setting_wireguard_get_private_key:
+ * @self: the #NMSettingWireGuard instance
+ *
+ * Returns: (transfer none): the set private-key or %NULL.
+ *
+ * Since: 1.16
+ */
+const char *
+nm_setting_wireguard_get_private_key (NMSettingWireGuard *self)
+{
+ g_return_val_if_fail (NM_IS_SETTING_WIREGUARD (self), NULL);
+
+ return NM_SETTING_WIREGUARD_GET_PRIVATE (self)->private_key;
+}
+
+/**
+ * nm_setting_wireguard_get_private_key_flags:
+ * @self: the #NMSettingWireGuard instance
+ *
+ * Returns: the secret-flags for #NMSettingWireGuard:private-key.
+ *
+ * Since: 1.16
+ */
+NMSettingSecretFlags
+nm_setting_wireguard_get_private_key_flags (NMSettingWireGuard *self)
+{
+ g_return_val_if_fail (NM_IS_SETTING_WIREGUARD (self), 0);
+
+ return NM_SETTING_WIREGUARD_GET_PRIVATE (self)->private_key_flags;
+}
+
+/**
+ * nm_setting_wireguard_get_fwmark:
+ * @self: the #NMSettingWireGuard instance
+ *
+ * Returns: the set firewall mark.
+ *
+ * Since: 1.16
+ */
+guint32
+nm_setting_wireguard_get_fwmark (NMSettingWireGuard *self)
+{
+ g_return_val_if_fail (NM_IS_SETTING_WIREGUARD (self), 0);
+
+ return NM_SETTING_WIREGUARD_GET_PRIVATE (self)->fwmark;
+}
+
+/**
+ * nm_setting_wireguard_get_listen_port:
+ * @self: the #NMSettingWireGuard instance
+ *
+ * Returns: the set UDP listen port.
+ *
+ * Since: 1.16
+ */
+guint16
+nm_setting_wireguard_get_listen_port (NMSettingWireGuard *self)
+{
+ g_return_val_if_fail (NM_IS_SETTING_WIREGUARD (self), 0);
+
+ return NM_SETTING_WIREGUARD_GET_PRIVATE (self)->listen_port;
+}
+
+/*****************************************************************************/
+
+static gboolean
+verify (NMSetting *setting, NMConnection *connection, GError **error)
+{
+ NMSettingWireGuard *s_wg = NM_SETTING_WIREGUARD (setting);
+
+ if (!_nm_connection_verify_required_interface_name (connection, error))
+ return FALSE;
+
+ if (!_nm_utils_secret_flags_validate (nm_setting_wireguard_get_private_key_flags (s_wg),
+ NM_SETTING_WIREGUARD_SETTING_NAME,
+ NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS,
+ NM_SETTING_SECRET_FLAG_NOT_REQUIRED,
+ error))
+ return FALSE;
+
+ if (connection) {
+ NMSettingIPConfig *s_ip4;
+ NMSettingIPConfig *s_ip6;
+ const char *method;
+
+ /* WireGuard is Layer 3 only. For the moment, we only support a restricted set of
+ * IP methods. We may relax that later, once we fix the implementations so they
+ * actually work. */
+
+ if ( (s_ip4 = nm_connection_get_setting_ip4_config (connection))
+ && (method = nm_setting_ip_config_get_method (s_ip4))
+ && !NM_IN_STRSET (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+ NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("method \"%s\" is not supported for WireGuard"),
+ method);
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_METHOD);
+ return FALSE;
+ }
+
+ if ( (s_ip6 = nm_connection_get_setting_ip6_config (connection))
+ && (method = nm_setting_ip_config_get_method (s_ip6))
+ && !NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
+ NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL,
+ NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("method \"%s\" is not supported for WireGuard"),
+ method);
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_METHOD);
+ return FALSE;
+ }
+ }
+
+ /* private-key is a secret, hence we cannot verify it like a regular property. */
+ return TRUE;
+}
+
+static gboolean
+verify_secrets (NMSetting *setting, NMConnection *connection, GError **error)
+{
+ NMSettingWireGuardPrivate *priv = NM_SETTING_WIREGUARD_GET_PRIVATE (setting);
+
+ if ( priv->private_key
+ && !priv->private_key_valid) {
+ g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("key must be 32 bytes base64 encoded"));
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_WIREGUARD_SETTING_NAME, NM_SETTING_WIREGUARD_PRIVATE_KEY);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GPtrArray *
+need_secrets (NMSetting *setting)
+{
+ NMSettingWireGuardPrivate *priv = NM_SETTING_WIREGUARD_GET_PRIVATE (setting);
+ GPtrArray *secrets = NULL;
+
+ if ( !priv->private_key
+ || !priv->private_key_valid) {
+ secrets = g_ptr_array_new_full (1, NULL);
+ g_ptr_array_add (secrets, NM_SETTING_WIREGUARD_PRIVATE_KEY);
+ }
+
+ return secrets;
+}
+
+/*****************************************************************************/
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ NMSettingWireGuard *setting = NM_SETTING_WIREGUARD (object);
+ NMSettingWireGuardPrivate *priv = NM_SETTING_WIREGUARD_GET_PRIVATE (setting);
+
+ switch (prop_id) {
+ case PROP_PRIVATE_KEY:
+ g_value_set_string (value, priv->private_key);
+ break;
+ case PROP_PRIVATE_KEY_FLAGS:
+ g_value_set_flags (value, priv->private_key_flags);
+ break;
+ case PROP_LISTEN_PORT:
+ g_value_set_uint (value, priv->listen_port);
+ break;
+ case PROP_FWMARK:
+ g_value_set_uint (value, priv->fwmark);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ NMSettingWireGuardPrivate *priv = NM_SETTING_WIREGUARD_GET_PRIVATE (object);
+ const char *str;
+
+ switch (prop_id) {
+ case PROP_PRIVATE_KEY:
+ nm_clear_pointer (&priv->private_key, nm_free_secret);
+ str = g_value_get_string (value);
+ if (str) {
+ if (_nm_utils_wireguard_normalize_key (str,
+ NM_WIREGUARD_PUBLIC_KEY_LEN,
+ &priv->private_key))
+ priv->private_key_valid = TRUE;
+ else {
+ priv->private_key = g_strdup (str);
+ priv->private_key_valid = FALSE;
+ }
+ }
+ break;
+ case PROP_PRIVATE_KEY_FLAGS:
+ priv->private_key_flags = g_value_get_flags (value);
+ break;
+ case PROP_LISTEN_PORT:
+ priv->listen_port = g_value_get_uint (value);
+ break;
+ case PROP_FWMARK:
+ priv->fwmark = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/*****************************************************************************/
+
+static void
+nm_setting_wireguard_init (NMSettingWireGuard *setting)
+{
+}
+
+/**
+ * nm_setting_wireguard_new:
+ *
+ * Creates a new #NMSettingWireGuard object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingWireGuard object
+ *
+ * Since: 1.16
+ **/
+NMSetting *
+nm_setting_wireguard_new (void)
+{
+ return g_object_new (NM_TYPE_SETTING_WIREGUARD, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+ NMSettingWireGuardPrivate *priv = NM_SETTING_WIREGUARD_GET_PRIVATE (object);
+
+ nm_free_secret (priv->private_key);
+
+ G_OBJECT_CLASS (nm_setting_wireguard_parent_class)->finalize (object);
+}
+
+static void
+nm_setting_wireguard_class_init (NMSettingWireGuardClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ NMSettingClass *setting_class = NM_SETTING_CLASS (klass);
+
+ object_class->get_property = get_property;
+ object_class->set_property = set_property;
+ object_class->finalize = finalize;
+
+ setting_class->verify = verify;
+ setting_class->verify_secrets = verify_secrets;
+ setting_class->need_secrets = need_secrets;
+
+ /**
+ * NMSettingWireGuard:private-key:
+ *
+ * The 256 bit private-key in base64 encoding.
+ *
+ * Since: 1.16
+ **/
+ obj_properties[PROP_PRIVATE_KEY] =
+ g_param_spec_string (NM_SETTING_WIREGUARD_PRIVATE_KEY, "", "",
+ NULL,
+ G_PARAM_READWRITE
+ | NM_SETTING_PARAM_SECRET
+ | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * NMSettingWireGuard:private-key-flags:
+ *
+ * Flags indicating how to handle the #NMSettingWirelessSecurity:private-key
+ * property.
+ *
+ * Since: 1.16
+ **/
+ obj_properties[PROP_PRIVATE_KEY_FLAGS] =
+ g_param_spec_flags (NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS, "", "",
+ NM_TYPE_SETTING_SECRET_FLAGS,
+ NM_SETTING_SECRET_FLAG_NONE,
+ G_PARAM_READWRITE
+ | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * NMSettingWireGuard:fwmark:
+ *
+ * The use of fwmark is optional and is by default off. Setting it to 0
+ * disables it. Otherwise it is a 32-bit fwmark for outgoing packets.
+ *
+ * Since: 1.16
+ **/
+ obj_properties[PROP_FWMARK] =
+ g_param_spec_uint (NM_SETTING_WIREGUARD_FWMARK, "", "",
+ 0, G_MAXUINT32, 0,
+ G_PARAM_READWRITE
+ | NM_SETTING_PARAM_INFERRABLE
+ | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * NMSettingWireGuard:listen-port:
+ *
+ * The listen-port. If listen-port is not specified, the port will be chosen
+ * randomly when the interface comes up.
+ *
+ * Since: 1.16
+ **/
+ obj_properties[PROP_LISTEN_PORT] =
+ g_param_spec_uint (NM_SETTING_WIREGUARD_LISTEN_PORT, "", "",
+ 0, 65535, 0,
+ G_PARAM_READWRITE
+ | NM_SETTING_PARAM_INFERRABLE
+ | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
+ _nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_WIREGUARD);
+}
diff --git a/libnm-core/nm-setting-wireguard.h b/libnm-core/nm-setting-wireguard.h
new file mode 100644
index 0000000000..1127b11382
--- /dev/null
+++ b/libnm-core/nm-setting-wireguard.h
@@ -0,0 +1,80 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2018 - 2019 Red Hat, Inc.
+ */
+
+#ifndef __NM_SETTING_WIREGUARD_H__
+#define __NM_SETTING_WIREGUARD_H__
+
+#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION)
+#error "Only <NetworkManager.h> can be included directly."
+#endif
+
+#include "nm-setting.h"
+
+G_BEGIN_DECLS
+
+/*****************************************************************************/
+
+#define NM_WIREGUARD_PUBLIC_KEY_LEN 32
+#define NM_WIREGUARD_SYMMETRIC_KEY_LEN 32
+
+/*****************************************************************************/
+
+#define NM_TYPE_SETTING_WIREGUARD (nm_setting_wireguard_get_type ())
+#define NM_SETTING_WIREGUARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_WIREGUARD, NMSettingWireGuard))
+#define NM_SETTING_WIREGUARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_WIREGUARD, NMSettingWireGuardClass))
+#define NM_IS_SETTING_WIREGUARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_WIREGUARD))
+#define NM_IS_SETTING_WIREGUARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_WIREGUARD))
+#define NM_SETTING_WIREGUARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_WIREGUARD, NMSettingWireGuardClass))
+
+#define NM_SETTING_WIREGUARD_SETTING_NAME "wireguard"
+
+#define NM_SETTING_WIREGUARD_PRIVATE_KEY "private-key"
+#define NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS "private-key-flags"
+#define NM_SETTING_WIREGUARD_LISTEN_PORT "listen-port"
+#define NM_SETTING_WIREGUARD_FWMARK "fwmark"
+
+/*****************************************************************************/
+
+typedef struct _NMSettingWireGuardClass NMSettingWireGuardClass;
+
+NM_AVAILABLE_IN_1_16
+GType nm_setting_wireguard_get_type (void);
+
+NM_AVAILABLE_IN_1_16
+NMSetting *nm_setting_wireguard_new (void);
+
+/*****************************************************************************/
+
+NM_AVAILABLE_IN_1_16
+const char *nm_setting_wireguard_get_private_key (NMSettingWireGuard *self);
+
+NM_AVAILABLE_IN_1_16
+NMSettingSecretFlags nm_setting_wireguard_get_private_key_flags (NMSettingWireGuard *self);
+
+NM_AVAILABLE_IN_1_16
+guint16 nm_setting_wireguard_get_listen_port (NMSettingWireGuard *self);
+
+NM_AVAILABLE_IN_1_16
+guint32 nm_setting_wireguard_get_fwmark (NMSettingWireGuard *self);
+
+/*****************************************************************************/
+
+G_END_DECLS
+
+#endif /* __NM_SETTING_WIREGUARD_H__ */
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index cd354d036e..fd9f87f879 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -38,6 +38,8 @@
#endif
#include "nm-utils/nm-enum-utils.h"
+#include "nm-utils/nm-secret-utils.h"
+#include "systemd/nm-sd-utils-shared.h"
#include "nm-common-macros.h"
#include "nm-utils-private.h"
#include "nm-setting-private.h"
@@ -6809,3 +6811,76 @@ nm_utils_version (void)
return NM_VERSION;
}
+/*****************************************************************************/
+
+/**
+ * _nm_utils_wireguard_decode_key:
+ * @base64_key: the (possibly invalid) base64 encode key.
+ * @required_key_len: the expected (binary) length of the key after
+ * decoding. If the length does not match, the validation fails.
+ * @out_key: (allow-none): an optional output buffer for the binary
+ * key. If given, it will be filled with exactly @required_key_len
+ * bytes.
+ *
+ * Returns: %TRUE if the input key is a valid base64 encoded key
+ * with @required_key_len bytes.
+ */
+gboolean
+_nm_utils_wireguard_decode_key (const char *base64_key,
+ gsize required_key_len,
+ guint8 *out_key)
+{
+ gs_free guint8 *bin_arr = NULL;
+ gsize base64_key_len;
+ gsize bin_len;
+ int r;
+
+ if (!base64_key)
+ return FALSE;
+
+ base64_key_len = strlen (base64_key);
+
+ r = nm_sd_utils_unbase64mem (base64_key, base64_key_len, &bin_arr, &bin_len);
+ if (r < 0)
+ return FALSE;
+ if (bin_len != required_key_len) {
+ nm_explicit_bzero (bin_arr, bin_len);
+ return FALSE;
+ }
+
+ if (nm_utils_memeqzero (bin_arr, required_key_len)) {
+ /* an all zero key is not valid either. That is used to represet an unset key */
+ return FALSE;
+ }
+
+ if (out_key)
+ memcpy (out_key, bin_arr, required_key_len);
+
+ nm_explicit_bzero (bin_arr, bin_len);
+ return TRUE;
+}
+
+gboolean
+_nm_utils_wireguard_normalize_key (const char *base64_key,
+ gsize required_key_len,
+ char **out_base64_key_norm)
+{
+ gs_free guint8 *buf_free = NULL;
+ guint8 buf_static[200];
+ guint8 *buf;
+
+ if (required_key_len > sizeof (buf_static)) {
+ buf_free = g_new (guint8, required_key_len);
+ buf = buf_free;
+ } else
+ buf = buf_static;
+
+ if (!_nm_utils_wireguard_decode_key (base64_key, required_key_len, buf)) {
+ NM_SET_OUT (out_base64_key_norm, NULL);
+ return FALSE;
+ }
+
+ NM_SET_OUT (out_base64_key_norm, g_base64_encode (buf, required_key_len));
+ nm_explicit_bzero (buf, required_key_len);
+ return TRUE;
+}
diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h
index 1e59d11758..7c70a226fd 100644
--- a/libnm/NetworkManager.h
+++ b/libnm/NetworkManager.h
@@ -105,6 +105,7 @@
#include "nm-setting-vxlan.h"
#include "nm-setting-wimax.h"
#include "nm-setting-wired.h"
+#include "nm-setting-wireguard.h"
#include "nm-setting-wireless.h"
#include "nm-setting-wireless-security.h"
#include "nm-setting-wpan.h"
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index cc8b211b8c..7689072eeb 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -1462,6 +1462,12 @@ global:
nm_setting_wifi_p2p_get_wfd_ies;
nm_setting_wifi_p2p_get_wps_method;
nm_setting_wifi_p2p_new;
+ nm_setting_wireguard_get_fwmark;
+ nm_setting_wireguard_get_listen_port;
+ nm_setting_wireguard_get_private_key;
+ nm_setting_wireguard_get_private_key_flags;
+ nm_setting_wireguard_get_type;
+ nm_setting_wireguard_new;
nm_team_link_watcher_get_vlanid;
nm_team_link_watcher_new_arp_ping2;
nm_wifi_p2p_peer_connection_valid;
diff --git a/libnm/nm-autoptr.h b/libnm/nm-autoptr.h
index 8abd792e22..40248dcd3e 100644
--- a/libnm/nm-autoptr.h
+++ b/libnm/nm-autoptr.h
@@ -80,6 +80,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingVxlan, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingWifiP2P, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingWimax, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingWired, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingWireGuard, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingWireless, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingWirelessSecurity, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingWpan, g_object_unref)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 393f84e8ca..148fd546f9 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -97,6 +97,7 @@ libnm-core/nm-setting-vxlan.c
libnm-core/nm-setting-wifi-p2p.c
libnm-core/nm-setting-wimax.c
libnm-core/nm-setting-wired.c
+libnm-core/nm-setting-wireguard.c
libnm-core/nm-setting-wireless-security.c
libnm-core/nm-setting-wireless.c
libnm-core/nm-setting-wpan.c
diff --git a/shared/nm-meta-setting.c b/shared/nm-meta-setting.c
index e7e73bd88e..e666e0b2a2 100644
--- a/shared/nm-meta-setting.c
+++ b/shared/nm-meta-setting.c
@@ -65,6 +65,7 @@
#include "nm-setting-wifi-p2p.h"
#include "nm-setting-wimax.h"
#include "nm-setting-wired.h"
+#include "nm-setting-wireguard.h"
#include "nm-setting-wireless-security.h"
#include "nm-setting-wireless.h"
#include "nm-setting-wpan.h"
@@ -402,6 +403,12 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = {
.setting_name = NM_SETTING_WIRED_SETTING_NAME,
.get_setting_gtype = nm_setting_wired_get_type,
},
+ [NM_META_SETTING_TYPE_WIREGUARD] = {
+ .meta_type = NM_META_SETTING_TYPE_WIREGUARD,
+ .setting_priority = NM_SETTING_PRIORITY_HW_BASE,
+ .setting_name = NM_SETTING_WIREGUARD_SETTING_NAME,
+ .get_setting_gtype = nm_setting_wireguard_get_type,
+ },
[NM_META_SETTING_TYPE_WIRELESS] = {
.meta_type = NM_META_SETTING_TYPE_WIRELESS,
.setting_priority = NM_SETTING_PRIORITY_HW_BASE,
diff --git a/shared/nm-meta-setting.h b/shared/nm-meta-setting.h
index 883d8ca195..18727a1638 100644
--- a/shared/nm-meta-setting.h
+++ b/shared/nm-meta-setting.h
@@ -147,6 +147,7 @@ typedef enum {
NM_META_SETTING_TYPE_VXLAN,
NM_META_SETTING_TYPE_WIFI_P2P,
NM_META_SETTING_TYPE_WIMAX,
+ NM_META_SETTING_TYPE_WIREGUARD,
NM_META_SETTING_TYPE_WPAN,
NM_META_SETTING_TYPE_UNKNOWN,
diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c
index 62ec027494..0ca8cf3a5a 100644
--- a/src/devices/nm-device-wireguard.c
+++ b/src/devices/nm-device-wireguard.c
@@ -21,6 +21,8 @@
#include "nm-device-wireguard.h"
+#include "nm-setting-wireguard.h"
+
#include "nm-device-private.h"
#include "platform/nm-platform.h"
#include "nm-device-factory.h"
@@ -30,6 +32,11 @@ _LOG_DECLARE_SELF(NMDeviceWireGuard);
/*****************************************************************************/
+G_STATIC_ASSERT (NM_WIREGUARD_PUBLIC_KEY_LEN == NMP_WIREGUARD_PUBLIC_KEY_LEN);
+G_STATIC_ASSERT (NM_WIREGUARD_SYMMETRIC_KEY_LEN == NMP_WIREGUARD_SYMMETRIC_KEY_LEN);
+
+/*****************************************************************************/
+
NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceWireGuard,
PROP_PUBLIC_KEY,
PROP_LISTEN_PORT,