diff options
| author | Michael Biebl <biebl@debian.org> | 2020-10-05 22:27:18 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2020-10-05 22:27:18 +0200 |
| commit | aafc1dbe4712c86189bbc1d4d54ad8cb4c69be7e (patch) | |
| tree | a2a9bb4d007339a0b1304540388230ccedac32bd /src/vpn | |
| parent | e7b44ef4c80907346ec7492a09c45277459924fc (diff) | |
New upstream version 1.27.90 upstream/1.27.90
Diffstat (limited to 'src/vpn')
| -rw-r--r-- | src/vpn/nm-vpn-connection.c | 4898 | ||||
| -rw-r--r-- | src/vpn/nm-vpn-connection.h | 72 | ||||
| -rw-r--r-- | src/vpn/nm-vpn-manager.c | 428 | ||||
| -rw-r--r-- | src/vpn/nm-vpn-manager.h | 27 |
4 files changed, 2739 insertions, 2686 deletions
diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index ff6b8e00..68c66af7 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2005 - 2013 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. @@ -35,136 +35,133 @@ #include "dns/nm-dns-manager.h" typedef enum { - /* Only system secrets */ - SECRETS_REQ_SYSTEM = 0, - /* All existing secrets including agent secrets */ - SECRETS_REQ_EXISTING = 1, - /* New secrets required; ask an agent */ - SECRETS_REQ_NEW = 2, - /* Plugin requests secrets interactively */ - SECRETS_REQ_INTERACTIVE = 3, - /* Placeholder for bounds checking */ - SECRETS_REQ_LAST + /* Only system secrets */ + SECRETS_REQ_SYSTEM = 0, + /* All existing secrets including agent secrets */ + SECRETS_REQ_EXISTING = 1, + /* New secrets required; ask an agent */ + SECRETS_REQ_NEW = 2, + /* Plugin requests secrets interactively */ + SECRETS_REQ_INTERACTIVE = 3, + /* Placeholder for bounds checking */ + SECRETS_REQ_LAST } SecretsReq; /* Internal VPN states, private to NMVpnConnection */ typedef enum { - STATE_UNKNOWN = 0, - STATE_WAITING, - STATE_PREPARE, - STATE_NEED_AUTH, - STATE_CONNECT, - STATE_IP_CONFIG_GET, - STATE_PRE_UP, - STATE_ACTIVATED, - STATE_DEACTIVATING, - STATE_DISCONNECTED, - STATE_FAILED, + STATE_UNKNOWN = 0, + STATE_WAITING, + STATE_PREPARE, + STATE_NEED_AUTH, + STATE_CONNECT, + STATE_IP_CONFIG_GET, + STATE_PRE_UP, + STATE_ACTIVATED, + STATE_DEACTIVATING, + STATE_DISCONNECTED, + STATE_FAILED, } VpnState; enum { - INTERNAL_STATE_CHANGED, - INTERNAL_RETRY_AFTER_FAILURE, + INTERNAL_STATE_CHANGED, + INTERNAL_RETRY_AFTER_FAILURE, - LAST_SIGNAL + LAST_SIGNAL }; -static guint signals[LAST_SIGNAL] = { 0 }; +static guint signals[LAST_SIGNAL] = {0}; -NM_GOBJECT_PROPERTIES_DEFINE (NMVpnConnection, - PROP_VPN_STATE, - PROP_BANNER, +NM_GOBJECT_PROPERTIES_DEFINE(NMVpnConnection, PROP_VPN_STATE, PROP_BANNER, #define PROP_IP4_CONFIG 2000 #define PROP_IP6_CONFIG 2001 #define PROP_MASTER 2002 ); typedef struct { - gboolean service_can_persist; - gboolean connection_can_persist; - - NMSettingsConnectionCallId *secrets_id; - SecretsReq secrets_idx; - char *username; - - VpnState vpn_state; - NMDispatcherCallId *dispatcher_id; - NMActiveConnectionStateReason failure_reason; - - NMVpnServiceState service_state; - guint start_timeout; - gboolean service_running; - NMVpnPluginInfo *plugin_info; - char *bus_name; - - NMFirewallManagerCallId *fw_call; - - NMNetns *netns; - - GPtrArray *ip4_dev_route_blacklist; - - GDBusProxy *proxy; - GCancellable *cancellable; - GVariant *connect_hash; - guint connect_timeout; - NMProxyConfig *proxy_config; - NMPacrunnerConfId *pacrunner_conf_id; - gboolean has_ip4; - NMIP4Config *ip4_config; - guint32 ip4_internal_gw; - guint32 ip4_external_gw; - gboolean has_ip6; - NMIP6Config *ip6_config; - - /* These config instances are passed on to NMDevice and modified by NMDevice. - * This pointer is only useful for nm_device_replace_vpn4_config() to clear the - * previous configuration. Consider these instances to be owned by NMDevice. */ - NMIP4Config *last_device_ip4_config; - NMIP6Config *last_device_ip6_config; - - struct in6_addr *ip6_internal_gw; - struct in6_addr *ip6_external_gw; - char *ip_iface; - int ip_ifindex; - char *banner; - guint32 mtu; + gboolean service_can_persist; + gboolean connection_can_persist; + + NMSettingsConnectionCallId *secrets_id; + SecretsReq secrets_idx; + char * username; + + VpnState vpn_state; + NMDispatcherCallId * dispatcher_id; + NMActiveConnectionStateReason failure_reason; + + NMVpnServiceState service_state; + guint start_timeout; + gboolean service_running; + NMVpnPluginInfo * plugin_info; + char * bus_name; + + NMFirewallManagerCallId *fw_call; + + NMNetns *netns; + + GPtrArray *ip4_dev_route_blacklist; + + GDBusProxy * proxy; + GCancellable * cancellable; + GVariant * connect_hash; + guint connect_timeout; + NMProxyConfig * proxy_config; + NMPacrunnerConfId *pacrunner_conf_id; + gboolean has_ip4; + NMIP4Config * ip4_config; + guint32 ip4_internal_gw; + guint32 ip4_external_gw; + gboolean has_ip6; + NMIP6Config * ip6_config; + + /* These config instances are passed on to NMDevice and modified by NMDevice. + * This pointer is only useful for nm_device_replace_vpn4_config() to clear the + * previous configuration. Consider these instances to be owned by NMDevice. */ + NMIP4Config *last_device_ip4_config; + NMIP6Config *last_device_ip6_config; + + struct in6_addr *ip6_internal_gw; + struct in6_addr *ip6_external_gw; + char * ip_iface; + int ip_ifindex; + char * banner; + guint32 mtu; } NMVpnConnectionPrivate; struct _NMVpnConnection { - NMActiveConnection parent; - NMVpnConnectionPrivate _priv; + NMActiveConnection parent; + NMVpnConnectionPrivate _priv; }; struct _NMVpnConnectionClass { - NMActiveConnectionClass parent; + NMActiveConnectionClass parent; }; -G_DEFINE_TYPE (NMVpnConnection, nm_vpn_connection, NM_TYPE_ACTIVE_CONNECTION) +G_DEFINE_TYPE(NMVpnConnection, nm_vpn_connection, NM_TYPE_ACTIVE_CONNECTION) -#define NM_VPN_CONNECTION_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMVpnConnection, NM_IS_VPN_CONNECTION, NMActiveConnection) +#define NM_VPN_CONNECTION_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMVpnConnection, NM_IS_VPN_CONNECTION, NMActiveConnection) /*****************************************************************************/ static const NMDBusInterfaceInfoExtended interface_info_vpn_connection; -static const GDBusSignalInfo signal_info_vpn_state_changed; +static const GDBusSignalInfo signal_info_vpn_state_changed; -static NMSettingsConnection *_get_settings_connection (NMVpnConnection *self, - gboolean allow_missing); +static NMSettingsConnection *_get_settings_connection(NMVpnConnection *self, + gboolean allow_missing); -static void get_secrets (NMVpnConnection *self, - SecretsReq secrets_idx, - const char *const*hints); +static void get_secrets(NMVpnConnection *self, SecretsReq secrets_idx, const char *const *hints); -static guint32 get_route_table (NMVpnConnection *self, int addr_family, gboolean fallback_main); +static guint32 get_route_table(NMVpnConnection *self, int addr_family, gboolean fallback_main); -static void plugin_interactive_secrets_required (NMVpnConnection *self, - const char *message, - const char *const*secrets); +static void plugin_interactive_secrets_required(NMVpnConnection * self, + const char * message, + const char *const *secrets); -static void _set_vpn_state (NMVpnConnection *self, - VpnState vpn_state, - NMActiveConnectionStateReason reason, - gboolean quitting); +static void _set_vpn_state(NMVpnConnection * self, + VpnState vpn_state, + NMActiveConnectionStateReason reason, + gboolean quitting); /*****************************************************************************/ @@ -174,2771 +171,2820 @@ static void _set_vpn_state (NMVpnConnection *self, #define __NMLOG_prefix_buf_len 128 static const char * -__LOG_create_prefix (char *buf, NMVpnConnection *self, NMSettingsConnection *con) -{ - NMVpnConnectionPrivate *priv; - const char *id; - - if (!self) - return _NMLOG_PREFIX_NAME; - - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - id = con ? nm_settings_connection_get_id (con) : NULL; - - g_snprintf (buf, __NMLOG_prefix_buf_len, - "%s[" - "%p" /*self*/ - "%s%s" /*con-uuid*/ - "%s%s%s%s" /*con-id*/ - ",%d" /*ifindex*/ - "%s%s%s" /*iface*/ - "]", - _NMLOG_PREFIX_NAME, - self, - con ? "," : "--", con ? (nm_settings_connection_get_uuid (con) ?: "??") : "", - con ? "," : "", NM_PRINT_FMT_QUOTED (id, "\"", id, "\"", con ? "??" : ""), - priv->ip_ifindex, - NM_PRINT_FMT_QUOTED (priv->ip_iface, ":(", priv->ip_iface, ")", "") - ); - - return buf; -} - -#define _NMLOG(level, ...) \ - G_STMT_START { \ - const NMLogLevel _level = (level); \ - NMSettingsConnection *_con = (self) ? _get_settings_connection (self, TRUE) : NULL; \ - \ - if (nm_logging_enabled (_level, _NMLOG_DOMAIN)) { \ - char __prefix[__NMLOG_prefix_buf_len]; \ - \ - _nm_log (_level, _NMLOG_DOMAIN, 0, \ - (self) ? NM_VPN_CONNECTION_GET_PRIVATE (self)->ip_iface : NULL, \ - (_con) ? nm_settings_connection_get_uuid (_con) : NULL, \ - "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - __LOG_create_prefix (__prefix, (self), _con) \ - _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ - } \ - } G_STMT_END +__LOG_create_prefix(char *buf, NMVpnConnection *self, NMSettingsConnection *con) +{ + NMVpnConnectionPrivate *priv; + const char * id; + + if (!self) + return _NMLOG_PREFIX_NAME; + + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + id = con ? nm_settings_connection_get_id(con) : NULL; + + g_snprintf(buf, + __NMLOG_prefix_buf_len, + "%s[" + "%p" /*self*/ + "%s%s" /*con-uuid*/ + "%s%s%s%s" /*con-id*/ + ",%d" /*ifindex*/ + "%s%s%s" /*iface*/ + "]", + _NMLOG_PREFIX_NAME, + self, + con ? "," : "--", + con ? (nm_settings_connection_get_uuid(con) ?: "??") : "", + con ? "," : "", + NM_PRINT_FMT_QUOTED(id, "\"", id, "\"", con ? "??" : ""), + priv->ip_ifindex, + NM_PRINT_FMT_QUOTED(priv->ip_iface, ":(", priv->ip_iface, ")", "")); + + return buf; +} + +#define _NMLOG(level, ...) \ + G_STMT_START \ + { \ + const NMLogLevel _level = (level); \ + NMSettingsConnection *_con = (self) ? _get_settings_connection(self, TRUE) : NULL; \ + \ + if (nm_logging_enabled(_level, _NMLOG_DOMAIN)) { \ + char __prefix[__NMLOG_prefix_buf_len]; \ + \ + _nm_log(_level, \ + _NMLOG_DOMAIN, \ + 0, \ + (self) ? NM_VPN_CONNECTION_GET_PRIVATE(self)->ip_iface : NULL, \ + (_con) ? nm_settings_connection_get_uuid(_con) : NULL, \ + "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + __LOG_create_prefix(__prefix, (self), _con) \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ + G_STMT_END /*****************************************************************************/ static void -cancel_get_secrets (NMVpnConnection *self) +cancel_get_secrets(NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - if (priv->secrets_id) { - nm_settings_connection_cancel_secrets (_get_settings_connection (self, FALSE), - priv->secrets_id); - g_warn_if_fail (!priv->secrets_id); - priv->secrets_id = NULL; - } + if (priv->secrets_id) { + nm_settings_connection_cancel_secrets(_get_settings_connection(self, FALSE), + priv->secrets_id); + g_warn_if_fail(!priv->secrets_id); + priv->secrets_id = NULL; + } } static NMVpnConnectionState -_state_to_nm_vpn_state (VpnState state) -{ - switch (state) { - case STATE_WAITING: - case STATE_PREPARE: - return NM_VPN_CONNECTION_STATE_PREPARE; - case STATE_NEED_AUTH: - return NM_VPN_CONNECTION_STATE_NEED_AUTH; - case STATE_CONNECT: - return NM_VPN_CONNECTION_STATE_CONNECT; - case STATE_IP_CONFIG_GET: - case STATE_PRE_UP: - return NM_VPN_CONNECTION_STATE_IP_CONFIG_GET; - case STATE_ACTIVATED: - return NM_VPN_CONNECTION_STATE_ACTIVATED; - case STATE_DEACTIVATING: { - /* Map DEACTIVATING to ACTIVATED to preserve external API behavior, - * since our API has no DEACTIVATING state of its own. Since this can - * take some time, and the VPN isn't actually disconnected until it - * hits the DISCONNECTED state, to clients it should still appear - * connected. - */ - return NM_VPN_CONNECTION_STATE_ACTIVATED; - } - case STATE_DISCONNECTED: - return NM_VPN_CONNECTION_STATE_DISCONNECTED; - case STATE_FAILED: - return NM_VPN_CONNECTION_STATE_FAILED; - default: - return NM_VPN_CONNECTION_STATE_UNKNOWN; - } +_state_to_nm_vpn_state(VpnState state) +{ + switch (state) { + case STATE_WAITING: + case STATE_PREPARE: + return NM_VPN_CONNECTION_STATE_PREPARE; + case STATE_NEED_AUTH: + return NM_VPN_CONNECTION_STATE_NEED_AUTH; + case STATE_CONNECT: + return NM_VPN_CONNECTION_STATE_CONNECT; + case STATE_IP_CONFIG_GET: + case STATE_PRE_UP: + return NM_VPN_CONNECTION_STATE_IP_CONFIG_GET; + case STATE_ACTIVATED: + return NM_VPN_CONNECTION_STATE_ACTIVATED; + case STATE_DEACTIVATING: + { + /* Map DEACTIVATING to ACTIVATED to preserve external API behavior, + * since our API has no DEACTIVATING state of its own. Since this can + * take some time, and the VPN isn't actually disconnected until it + * hits the DISCONNECTED state, to clients it should still appear + * connected. + */ + return NM_VPN_CONNECTION_STATE_ACTIVATED; + } + case STATE_DISCONNECTED: + return NM_VPN_CONNECTION_STATE_DISCONNECTED; + case STATE_FAILED: + return NM_VPN_CONNECTION_STATE_FAILED; + default: + return NM_VPN_CONNECTION_STATE_UNKNOWN; + } } static NMActiveConnectionState -_state_to_ac_state (VpnState vpn_state) -{ - /* Set the NMActiveConnection state based on VPN state */ - switch (vpn_state) { - case STATE_WAITING: - case STATE_PREPARE: - case STATE_NEED_AUTH: - case STATE_CONNECT: - case STATE_IP_CONFIG_GET: - case STATE_PRE_UP: - return NM_ACTIVE_CONNECTION_STATE_ACTIVATING; - case STATE_ACTIVATED: - return NM_ACTIVE_CONNECTION_STATE_ACTIVATED; - case STATE_DEACTIVATING: - return NM_ACTIVE_CONNECTION_STATE_DEACTIVATING; - case STATE_DISCONNECTED: - case STATE_FAILED: - return NM_ACTIVE_CONNECTION_STATE_DEACTIVATED; - default: - break; - } - return NM_ACTIVE_CONNECTION_STATE_UNKNOWN; +_state_to_ac_state(VpnState vpn_state) +{ + /* Set the NMActiveConnection state based on VPN state */ + switch (vpn_state) { + case STATE_WAITING: + case STATE_PREPARE: + case STATE_NEED_AUTH: + case STATE_CONNECT: + case STATE_IP_CONFIG_GET: + case STATE_PRE_UP: + return NM_ACTIVE_CONNECTION_STATE_ACTIVATING; + case STATE_ACTIVATED: + return NM_ACTIVE_CONNECTION_STATE_ACTIVATED; + case STATE_DEACTIVATING: + return NM_ACTIVE_CONNECTION_STATE_DEACTIVATING; + case STATE_DISCONNECTED: + case STATE_FAILED: + return NM_ACTIVE_CONNECTION_STATE_DEACTIVATED; + default: + break; + } + return NM_ACTIVE_CONNECTION_STATE_UNKNOWN; } static NMSettingsConnection * -_get_settings_connection (NMVpnConnection *self, gboolean allow_missing) +_get_settings_connection(NMVpnConnection *self, gboolean allow_missing) { - NMSettingsConnection *con; + NMSettingsConnection *con; - /* Currently we operate on the assumption, that the settings-connection - * never changes after it is set (though initially, it might be unset). - * Later we might want to change that, but then we need fixes here too. */ + /* Currently, we operate on the assumption, that the settings-connection + * never changes after it is set (though initially, it might be unset). + * Later we might want to change that, but then we need fixes here too. */ - con = _nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (self)); - if (!con && !allow_missing) - g_return_val_if_reached (NULL); - return con; + con = _nm_active_connection_get_settings_connection(NM_ACTIVE_CONNECTION(self)); + if (!con && !allow_missing) + g_return_val_if_reached(NULL); + return con; } static NMConnection * -_get_applied_connection (NMVpnConnection *connection) +_get_applied_connection(NMVpnConnection *connection) { - NMConnection *con; + NMConnection *con; - con = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (connection)); - g_return_val_if_fail (con, NULL); - return con; + con = nm_active_connection_get_applied_connection(NM_ACTIVE_CONNECTION(connection)); + g_return_val_if_fail(con, NULL); + return con; } static void -disconnect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +disconnect_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { - GVariant *variant; + GVariant *variant; - variant = g_dbus_proxy_call_finish (proxy, result, NULL); - if (variant) - g_variant_unref (variant); - g_object_unref (user_data); + variant = g_dbus_proxy_call_finish(proxy, result, NULL); + if (variant) + g_variant_unref(variant); + g_object_unref(user_data); } static void -fw_call_cleanup (NMVpnConnection *self) +fw_call_cleanup(NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - if (priv->fw_call) { - nm_firewall_manager_cancel_call (priv->fw_call); - g_warn_if_fail (!priv->fw_call); - priv->fw_call = NULL; - } + if (priv->fw_call) { + nm_firewall_manager_cancel_call(priv->fw_call); + g_warn_if_fail(!priv->fw_call); + priv->fw_call = NULL; + } } static void -remove_parent_device_config (NMVpnConnection *connection, NMDevice *device) +remove_parent_device_config(NMVpnConnection *connection, NMDevice *device) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(connection); - if (priv->last_device_ip4_config) { - nm_device_replace_vpn4_config (device, priv->last_device_ip4_config, NULL); - g_clear_object (&priv->last_device_ip4_config); - } + if (priv->last_device_ip4_config) { + nm_device_replace_vpn4_config(device, priv->last_device_ip4_config, NULL); + g_clear_object(&priv->last_device_ip4_config); + } - if (priv->last_device_ip6_config) { - nm_device_replace_vpn6_config (device, priv->last_device_ip6_config, NULL); - g_clear_object (&priv->last_device_ip6_config); - } + if (priv->last_device_ip6_config) { + nm_device_replace_vpn6_config(device, priv->last_device_ip6_config, NULL); + g_clear_object(&priv->last_device_ip6_config); + } } static void -vpn_cleanup (NMVpnConnection *self, NMDevice *parent_dev) +vpn_cleanup(NMVpnConnection *self, NMDevice *parent_dev) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - if (priv->ip_ifindex) { - NMPlatform *platform = nm_netns_get_platform (priv->netns); + if (priv->ip_ifindex) { + NMPlatform *platform = nm_netns_get_platform(priv->netns); - nm_platform_link_set_down (platform, priv->ip_ifindex); - nm_platform_ip_route_flush (platform, AF_UNSPEC, priv->ip_ifindex); - nm_platform_ip_address_flush (platform, AF_UNSPEC, priv->ip_ifindex); - } + nm_platform_link_set_down(platform, priv->ip_ifindex); + nm_platform_ip_route_flush(platform, AF_UNSPEC, priv->ip_ifindex); + nm_platform_ip_address_flush(platform, AF_UNSPEC, priv->ip_ifindex); + } - remove_parent_device_config (self, parent_dev); + remove_parent_device_config(self, parent_dev); - /* Remove zone from firewall */ - if (priv->ip_iface) { - nm_firewall_manager_remove_from_zone (nm_firewall_manager_get (), - priv->ip_iface, - NULL, - NULL, - NULL); - } - /* Cancel pending firewall call */ - fw_call_cleanup (self); + /* Remove zone from firewall */ + if (priv->ip_iface) { + nm_firewall_manager_remove_from_zone(nm_firewall_manager_get(), + priv->ip_iface, + NULL, + NULL, + NULL); + } + /* Cancel pending firewall call */ + fw_call_cleanup(self); - g_free (priv->banner); - priv->banner = NULL; + g_free(priv->banner); + priv->banner = NULL; - g_free (priv->ip_iface); - priv->ip_iface = NULL; - priv->ip_ifindex = 0; + g_free(priv->ip_iface); + priv->ip_iface = NULL; + priv->ip_ifindex = 0; - g_free (priv->bus_name); - priv->bus_name = NULL; + g_free(priv->bus_name); + priv->bus_name = NULL; - /* Clear out connection secrets to ensure that the settings service - * gets asked for them next time the connection is activated. - */ - nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (self)); + /* Clear out connection secrets to ensure that the settings service + * gets asked for them next time the connection is activated. + */ + nm_active_connection_clear_secrets(NM_ACTIVE_CONNECTION(self)); } static void -dispatcher_pre_down_done (NMDispatcherCallId *call_id, gpointer user_data) +dispatcher_pre_down_done(NMDispatcherCallId *call_id, gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnection * self = NM_VPN_CONNECTION(user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - nm_assert (call_id); - nm_assert (priv->dispatcher_id == call_id); + nm_assert(call_id); + nm_assert(priv->dispatcher_id == call_id); - priv->dispatcher_id = NULL; - _set_vpn_state (self, STATE_DISCONNECTED, NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED, FALSE); + priv->dispatcher_id = NULL; + _set_vpn_state(self, + STATE_DISCONNECTED, + NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED, + FALSE); } static void -dispatcher_pre_up_done (NMDispatcherCallId *call_id, gpointer user_data) +dispatcher_pre_up_done(NMDispatcherCallId *call_id, gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnection * self = NM_VPN_CONNECTION(user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - nm_assert (call_id); - nm_assert (priv->dispatcher_id == call_id); + nm_assert(call_id); + nm_assert(priv->dispatcher_id == call_id); - priv->dispatcher_id = NULL; - _set_vpn_state (self, STATE_ACTIVATED, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); + priv->dispatcher_id = NULL; + _set_vpn_state(self, STATE_ACTIVATED, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); } static void -dispatcher_cleanup (NMVpnConnection *self) +dispatcher_cleanup(NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - if (priv->dispatcher_id) - nm_dispatcher_call_cancel (g_steal_pointer (&priv->dispatcher_id)); + if (priv->dispatcher_id) + nm_dispatcher_call_cancel(g_steal_pointer(&priv->dispatcher_id)); } static void -_set_vpn_state (NMVpnConnection *self, - VpnState vpn_state, - NMActiveConnectionStateReason reason, - gboolean quitting) -{ - NMVpnConnectionPrivate *priv; - VpnState old_vpn_state; - NMVpnConnectionState new_external_state, old_external_state; - NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self)); - NMConnection *applied; - - g_return_if_fail (NM_IS_VPN_CONNECTION (self)); - - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - - if (vpn_state == priv->vpn_state) - return; - - old_vpn_state = priv->vpn_state; - priv->vpn_state = vpn_state; - - /* The device gets destroyed by active connection when it enters - * the deactivated state, so we need to ref it for usage below. - */ - if (parent_dev) - g_object_ref (parent_dev); - - /* Update active connection base class state */ - nm_active_connection_set_state (NM_ACTIVE_CONNECTION (self), - _state_to_ac_state (vpn_state), - reason); - - /* Clear any in-progress secrets request */ - cancel_get_secrets (self); - - dispatcher_cleanup (self); - - /* The connection gets destroyed by the VPN manager when it enters the - * disconnected/failed state, but we need to keep it around for a bit - * to send out signals and handle the dispatcher. So ref it. - */ - g_object_ref (self); - - old_external_state = _state_to_nm_vpn_state (old_vpn_state); - new_external_state = _state_to_nm_vpn_state (priv->vpn_state); - if (new_external_state != old_external_state) { - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_vpn_connection, - &signal_info_vpn_state_changed, - "(uu)", - (guint32) new_external_state, - (guint32) reason); - g_signal_emit (self, signals[INTERNAL_STATE_CHANGED], 0, - new_external_state, - old_external_state, - reason); - _notify (self, PROP_VPN_STATE); - } - - switch (vpn_state) { - case STATE_NEED_AUTH: - /* Do nothing; not part of 'default' because we don't want to touch - * priv->secrets_req as NEED_AUTH is re-entered during interactive - * secrets. - */ - break; - case STATE_PRE_UP: - if (!nm_dispatcher_call_vpn (NM_DISPATCHER_ACTION_VPN_PRE_UP, - _get_settings_connection (self, FALSE), - _get_applied_connection (self), - parent_dev, - priv->ip_iface, - priv->proxy_config, - priv->ip4_config, - priv->ip6_config, - dispatcher_pre_up_done, - self, - &priv->dispatcher_id)) { - /* Just proceed on errors */ - dispatcher_pre_up_done (0, self); - } - break; - case STATE_ACTIVATED: - applied = _get_applied_connection (self); - - /* Secrets no longer needed now that we're connected */ - nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (self)); - - /* Let dispatcher scripts know we're up and running */ - nm_dispatcher_call_vpn (NM_DISPATCHER_ACTION_VPN_UP, - _get_settings_connection (self, FALSE), - applied, - parent_dev, - priv->ip_iface, - priv->proxy_config, - priv->ip4_config, - priv->ip6_config, - NULL, - NULL, - NULL); - - if (priv->proxy_config) { - nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id); - priv->pacrunner_conf_id = nm_pacrunner_manager_add (nm_pacrunner_manager_get (), - priv->proxy_config, - priv->ip_iface, - priv->ip4_config, - priv->ip6_config); - } - break; - case STATE_DEACTIVATING: - applied = _get_applied_connection (self); - if (quitting) { - nm_dispatcher_call_vpn_sync (NM_DISPATCHER_ACTION_VPN_PRE_DOWN, - _get_settings_connection (self, FALSE), - applied, - parent_dev, - priv->ip_iface, - priv->proxy_config, - priv->ip4_config, - priv->ip6_config); - } else { - if (!nm_dispatcher_call_vpn (NM_DISPATCHER_ACTION_VPN_PRE_DOWN, - _get_settings_connection (self, FALSE), - applied, - parent_dev, - priv->ip_iface, - priv->proxy_config, - priv->ip4_config, - priv->ip6_config, - dispatcher_pre_down_done, - self, - &priv->dispatcher_id)) { - /* Just proceed on errors */ - dispatcher_pre_down_done (0, self); - } - } - - nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id); - break; - case STATE_FAILED: - case STATE_DISCONNECTED: - if ( old_vpn_state >= STATE_ACTIVATED - && old_vpn_state <= STATE_DEACTIVATING) { - /* Let dispatcher scripts know we're about to go down */ - if (quitting) { - nm_dispatcher_call_vpn_sync (NM_DISPATCHER_ACTION_VPN_DOWN, - _get_settings_connection (self, FALSE), - _get_applied_connection (self), - parent_dev, - priv->ip_iface, - NULL, - NULL, - NULL); - } else { - nm_dispatcher_call_vpn (NM_DISPATCHER_ACTION_VPN_DOWN, - _get_settings_connection (self, FALSE), - _get_applied_connection (self), - parent_dev, - priv->ip_iface, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - } - } - - /* Tear down and clean up the connection */ - if (priv->proxy) { - g_dbus_proxy_call (priv->proxy, - "Disconnect", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->cancellable, - (GAsyncReadyCallback) disconnect_cb, - g_object_ref (self)); - } - - vpn_cleanup (self, parent_dev); - /* fall-through */ - default: - priv->secrets_idx = SECRETS_REQ_SYSTEM; - break; - } - - g_object_unref (self); - if (parent_dev) - g_object_unref (parent_dev); +_set_vpn_state(NMVpnConnection * self, + VpnState vpn_state, + NMActiveConnectionStateReason reason, + gboolean quitting) +{ + NMVpnConnectionPrivate *priv; + VpnState old_vpn_state; + NMVpnConnectionState new_external_state, old_external_state; + NMDevice * parent_dev = nm_active_connection_get_device(NM_ACTIVE_CONNECTION(self)); + NMConnection *applied; + + g_return_if_fail(NM_IS_VPN_CONNECTION(self)); + + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + + if (vpn_state == priv->vpn_state) + return; + + old_vpn_state = priv->vpn_state; + priv->vpn_state = vpn_state; + + /* The device gets destroyed by active connection when it enters + * the deactivated state, so we need to ref it for usage below. + */ + if (parent_dev) + g_object_ref(parent_dev); + + /* Update active connection base class state */ + nm_active_connection_set_state(NM_ACTIVE_CONNECTION(self), + _state_to_ac_state(vpn_state), + reason); + + /* Clear any in-progress secrets request */ + cancel_get_secrets(self); + + dispatcher_cleanup(self); + + /* The connection gets destroyed by the VPN manager when it enters the + * disconnected/failed state, but we need to keep it around for a bit + * to send out signals and handle the dispatcher. So ref it. + */ + g_object_ref(self); + + old_external_state = _state_to_nm_vpn_state(old_vpn_state); + new_external_state = _state_to_nm_vpn_state(priv->vpn_state); + if (new_external_state != old_external_state) { + nm_dbus_object_emit_signal(NM_DBUS_OBJECT(self), + &interface_info_vpn_connection, + &signal_info_vpn_state_changed, + "(uu)", + (guint32) new_external_state, + (guint32) reason); + g_signal_emit(self, + signals[INTERNAL_STATE_CHANGED], + 0, + new_external_state, + old_external_state, + reason); + _notify(self, PROP_VPN_STATE); + } + + switch (vpn_state) { + case STATE_NEED_AUTH: + /* Do nothing; not part of 'default' because we don't want to touch + * priv->secrets_req as NEED_AUTH is re-entered during interactive + * secrets. + */ + break; + case STATE_PRE_UP: + if (!nm_dispatcher_call_vpn(NM_DISPATCHER_ACTION_VPN_PRE_UP, + _get_settings_connection(self, FALSE), + _get_applied_connection(self), + parent_dev, + priv->ip_iface, + priv->proxy_config, + priv->ip4_config, + priv->ip6_config, + dispatcher_pre_up_done, + self, + &priv->dispatcher_id)) { + /* Just proceed on errors */ + dispatcher_pre_up_done(0, self); + } + break; + case STATE_ACTIVATED: + applied = _get_applied_connection(self); + + /* Secrets no longer needed now that we're connected */ + nm_active_connection_clear_secrets(NM_ACTIVE_CONNECTION(self)); + + /* Let dispatcher scripts know we're up and running */ + nm_dispatcher_call_vpn(NM_DISPATCHER_ACTION_VPN_UP, + _get_settings_connection(self, FALSE), + applied, + parent_dev, + priv->ip_iface, + priv->proxy_config, + priv->ip4_config, + priv->ip6_config, + NULL, + NULL, + NULL); + + if (priv->proxy_config) { + nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); + priv->pacrunner_conf_id = nm_pacrunner_manager_add(nm_pacrunner_manager_get(), + priv->proxy_config, + priv->ip_iface, + priv->ip4_config, + priv->ip6_config); + } + break; + case STATE_DEACTIVATING: + applied = _get_applied_connection(self); + if (quitting) { + nm_dispatcher_call_vpn_sync(NM_DISPATCHER_ACTION_VPN_PRE_DOWN, + _get_settings_connection(self, FALSE), + applied, + parent_dev, + priv->ip_iface, + priv->proxy_config, + priv->ip4_config, + priv->ip6_config); + } else { + if (!nm_dispatcher_call_vpn(NM_DISPATCHER_ACTION_VPN_PRE_DOWN, + _get_settings_connection(self, FALSE), + applied, + parent_dev, + priv->ip_iface, + priv->proxy_config, + priv->ip4_config, + priv->ip6_config, + dispatcher_pre_down_done, + self, + &priv->dispatcher_id)) { + /* Just proceed on errors */ + dispatcher_pre_down_done(0, self); + } + } + + nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); + break; + case STATE_FAILED: + case STATE_DISCONNECTED: + if (old_vpn_state >= STATE_ACTIVATED && old_vpn_state <= STATE_DEACTIVATING) { + /* Let dispatcher scripts know we're about to go down */ + if (quitting) { + nm_dispatcher_call_vpn_sync(NM_DISPATCHER_ACTION_VPN_DOWN, + _get_settings_connection(self, FALSE), + _get_applied_connection(self), + parent_dev, + priv->ip_iface, + NULL, + NULL, + NULL); + } else { + nm_dispatcher_call_vpn(NM_DISPATCHER_ACTION_VPN_DOWN, + _get_settings_connection(self, FALSE), + _get_applied_connection(self), + parent_dev, + priv->ip_iface, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + } + } + + /* Tear down and clean up the connection */ + if (priv->proxy) { + g_dbus_proxy_call(priv->proxy, + "Disconnect", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + (GAsyncReadyCallback) disconnect_cb, + g_object_ref(self)); + } + + vpn_cleanup(self, parent_dev); + /* fall-through */ + default: + priv->secrets_idx = SECRETS_REQ_SYSTEM; + break; + } + + g_object_unref(self); + if (parent_dev) + g_object_unref(parent_dev); } static gboolean -_service_and_connection_can_persist (NMVpnConnection *self) +_service_and_connection_can_persist(NMVpnConnection *self) { - return NM_VPN_CONNECTION_GET_PRIVATE (self)->connection_can_persist && - NM_VPN_CONNECTION_GET_PRIVATE (self)->service_can_persist; + return NM_VPN_CONNECTION_GET_PRIVATE(self)->connection_can_persist + && NM_VPN_CONNECTION_GET_PRIVATE(self)->service_can_persist; } static gboolean -_connection_only_can_persist (NMVpnConnection *self) +_connection_only_can_persist(NMVpnConnection *self) { - return NM_VPN_CONNECTION_GET_PRIVATE (self)->connection_can_persist && - !NM_VPN_CONNECTION_GET_PRIVATE (self)->service_can_persist; + return NM_VPN_CONNECTION_GET_PRIVATE(self)->connection_can_persist + && !NM_VPN_CONNECTION_GET_PRIVATE(self)->service_can_persist; } static void -device_state_changed (NMActiveConnection *active, - NMDevice *device, - NMDeviceState new_state, - NMDeviceState old_state) -{ - if (_service_and_connection_can_persist (NM_VPN_CONNECTION (active))) { - if (new_state <= NM_DEVICE_STATE_DISCONNECTED || - new_state == NM_DEVICE_STATE_FAILED) { - nm_active_connection_set_device (active, NULL); - } - return; - } - - if (new_state <= NM_DEVICE_STATE_DISCONNECTED) { - _set_vpn_state (NM_VPN_CONNECTION (active), - STATE_DISCONNECTED, - NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED, - FALSE); - } else if (new_state == NM_DEVICE_STATE_FAILED) { - _set_vpn_state (NM_VPN_CONNECTION (active), - STATE_FAILED, - NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED, - FALSE); - } - - /* FIXME: map device DEACTIVATING state to VPN DEACTIVATING state and - * block device deactivation on VPN deactivation. - */ +device_state_changed(NMActiveConnection *active, + NMDevice * device, + NMDeviceState new_state, + NMDeviceState old_state) +{ + if (_service_and_connection_can_persist(NM_VPN_CONNECTION(active))) { + if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state == NM_DEVICE_STATE_FAILED) { + nm_active_connection_set_device(active, NULL); + } + return; + } + + if (new_state <= NM_DEVICE_STATE_DISCONNECTED) { + _set_vpn_state(NM_VPN_CONNECTION(active), + STATE_DISCONNECTED, + NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED, + FALSE); + } else if (new_state == NM_DEVICE_STATE_FAILED) { + _set_vpn_state(NM_VPN_CONNECTION(active), + STATE_FAILED, + NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED, + FALSE); + } + + /* FIXME: map device DEACTIVATING state to VPN DEACTIVATING state and + * block device deactivation on VPN deactivation. + */ } static void -add_ip4_vpn_gateway_route (NMIP4Config *config, - NMDevice *parent_device, - in_addr_t vpn_gw, - NMPlatform *platform) -{ - guint32 parent_gw = 0; - gboolean has_parent_gw = FALSE; - NMPlatformIP4Route route; - int ifindex; - guint32 route_metric; - nm_auto_nmpobj const NMPObject *route_resolved = NULL; - - g_return_if_fail (NM_IS_IP4_CONFIG (config)); - g_return_if_fail (NM_IS_DEVICE (parent_device)); - g_return_if_fail (vpn_gw != 0); - - ifindex = nm_ip4_config_get_ifindex (config); - - nm_assert (ifindex > 0); - nm_assert (ifindex == nm_device_get_ip_ifindex (parent_device)); - - /* Ask kernel how to reach @vpn_gw. We can only inject the route in - * @parent_device, so whatever we resolve, it can only be on @ifindex. */ - if (nm_platform_ip_route_get (platform, - AF_INET, - &vpn_gw, - ifindex, - (NMPObject **) &route_resolved) >= 0) { - const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (route_resolved); - - if (r->ifindex == ifindex) { - const NMPObject *obj; - - /* `ip route get` always resolves the route, even if the destination is unreachable. - * In which case, it pretends the destination is directly reachable. - * - * So, only accept direct routes if @vpn_gw is a private network - * or if the parent device also has a direct default route */ - if (nm_platform_route_table_is_main (r->table_coerced)) { - if (r->gateway) { - parent_gw = r->gateway; - has_parent_gw = TRUE; - } else if (nm_utils_ip_is_site_local (AF_INET, &vpn_gw)) { - has_parent_gw = TRUE; - } else if ( (obj = nm_device_get_best_default_route (parent_device, AF_INET)) - && !NMP_OBJECT_CAST_IP4_ROUTE (obj)->gateway) { - has_parent_gw = TRUE; - } - } - } - } - - if (!has_parent_gw) - return; - - route_metric = nm_device_get_route_metric (parent_device, AF_INET); - - memset (&route, 0, sizeof (route)); - route.ifindex = ifindex; - route.network = vpn_gw; - route.plen = 32; - route.gateway = parent_gw; - route.rt_source = NM_IP_CONFIG_SOURCE_VPN; - route.metric = route_metric; - nm_ip4_config_add_route (config, &route, NULL); - - if (parent_gw) { - /* Ensure there's a route to the parent device's gateway through the - * parent device, since if the VPN claims the default route and the VPN - * routes include a subnet that matches the parent device's subnet, - * the parent device's gateway would get routed through the VPN and fail. - */ - memset (&route, 0, sizeof (route)); - route.network = parent_gw; - route.plen = 32; - route.rt_source = NM_IP_CONFIG_SOURCE_VPN; - route.metric = route_metric; - nm_ip4_config_add_route (config, &route, NULL); - } +add_ip4_vpn_gateway_route(NMIP4Config *config, + NMDevice * parent_device, + in_addr_t vpn_gw, + NMPlatform * platform) +{ + guint32 parent_gw = 0; + gboolean has_parent_gw = FALSE; + NMPlatformIP4Route route; + int ifindex; + guint32 route_metric; + nm_auto_nmpobj const NMPObject *route_resolved = NULL; + + g_return_if_fail(NM_IS_IP4_CONFIG(config)); + g_return_if_fail(NM_IS_DEVICE(parent_device)); + g_return_if_fail(vpn_gw != 0); + + ifindex = nm_ip4_config_get_ifindex(config); + + nm_assert(ifindex > 0); + nm_assert(ifindex == nm_device_get_ip_ifindex(parent_device)); + + /* Ask kernel how to reach @vpn_gw. We can only inject the route in + * @parent_device, so whatever we resolve, it can only be on @ifindex. */ + if (nm_platform_ip_route_get(platform, + AF_INET, + &vpn_gw, + ifindex, + (NMPObject **) &route_resolved) + >= 0) { + const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE(route_resolved); + + if (r->ifindex == ifindex) { + const NMPObject *obj; + + /* `ip route get` always resolves the route, even if the destination is unreachable. + * In which case, it pretends the destination is directly reachable. + * + * So, only accept direct routes if @vpn_gw is a private network + * or if the parent device also has a direct default route */ + if (nm_platform_route_table_is_main(r->table_coerced)) { + if (r->gateway) { + parent_gw = r->gateway; + has_parent_gw = TRUE; + } else if (nm_utils_ip_is_site_local(AF_INET, &vpn_gw)) { + has_parent_gw = TRUE; + } else if ((obj = nm_device_get_best_default_route(parent_device, AF_INET)) + && !NMP_OBJECT_CAST_IP4_ROUTE(obj)->gateway) { + has_parent_gw = TRUE; + } + } + } + } + + if (!has_parent_gw) + return; + + route_metric = nm_device_get_route_metric(parent_device, AF_INET); + + memset(&route, 0, sizeof(route)); + route.ifindex = ifindex; + route.network = vpn_gw; + route.plen = 32; + route.gateway = parent_gw; + route.rt_source = NM_IP_CONFIG_SOURCE_VPN; + route.metric = route_metric; + nm_ip4_config_add_route(config, &route, NULL); + + if (parent_gw) { + /* Ensure there's a route to the parent device's gateway through the + * parent device, since if the VPN claims the default route and the VPN + * routes include a subnet that matches the parent device's subnet, + * the parent device's gateway would get routed through the VPN and fail. + */ + memset(&route, 0, sizeof(route)); + route.network = parent_gw; + route.plen = 32; + route.rt_source = NM_IP_CONFIG_SOURCE_VPN; + route.metric = route_metric; + nm_ip4_config_add_route(config, &route, NULL); + } } static void -add_ip6_vpn_gateway_route (NMIP6Config *config, - NMDevice *parent_device, - const struct in6_addr *vpn_gw, - NMPlatform *platform) -{ - const struct in6_addr *parent_gw = NULL; - gboolean has_parent_gw = FALSE; - NMPlatformIP6Route route; - int ifindex; - guint32 route_metric; - nm_auto_nmpobj const NMPObject *route_resolved = NULL; - - g_return_if_fail (NM_IS_IP6_CONFIG (config)); - g_return_if_fail (NM_IS_DEVICE (parent_device)); - g_return_if_fail (vpn_gw != NULL); - - ifindex = nm_ip6_config_get_ifindex (config); - - nm_assert (ifindex > 0); - nm_assert (ifindex == nm_device_get_ip_ifindex (parent_device)); - - /* Ask kernel how to reach @vpn_gw. We can only inject the route in - * @parent_device, so whatever we resolve, it can only be on @ifindex. */ - if (nm_platform_ip_route_get (platform, - AF_INET6, - vpn_gw, - ifindex, - (NMPObject **) &route_resolved) >= 0) { - const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (route_resolved); - - if (r->ifindex == ifindex) { - const NMPObject *obj; - - /* `ip route get` always resolves the route, even if the destination is unreachable. - * In which case, it pretends the destination is directly reachable. - * - * So, only accept direct routes if @vpn_gw is a private network - * or if the parent device also has a direct default route */ - if (nm_platform_route_table_is_main (r->table_coerced)) { - if (!IN6_IS_ADDR_UNSPECIFIED (&r->gateway)) { - parent_gw = &r->gateway; - has_parent_gw = TRUE; - } else if (nm_utils_ip_is_site_local (AF_INET6, &vpn_gw)) { - has_parent_gw = TRUE; - } else if ( (obj = nm_device_get_best_default_route (parent_device, AF_INET6)) - && IN6_IS_ADDR_UNSPECIFIED (&NMP_OBJECT_CAST_IP6_ROUTE (obj)->gateway)) { - has_parent_gw = TRUE; - } - } - } - } - - if (!has_parent_gw) - return; - - route_metric = nm_device_get_route_metric (parent_device, AF_INET6); - - memset (&route, 0, sizeof (route)); - route.ifindex = ifindex; - route.network = *vpn_gw; - route.plen = 128; - if (parent_gw) - route.gateway = *parent_gw; - route.rt_source = NM_IP_CONFIG_SOURCE_VPN; - route.metric = route_metric; - nm_ip6_config_add_route (config, &route, NULL); - - /* Ensure there's a route to the parent device's gateway through the - * parent device, since if the VPN claims the default route and the VPN - * routes include a subnet that matches the parent device's subnet, - * the parent device's gateway would get routed through the VPN and fail. - */ - if (parent_gw && !IN6_IS_ADDR_UNSPECIFIED (parent_gw)) { - memset (&route, 0, sizeof (route)); - route.network = *parent_gw; - route.plen = 128; - route.rt_source = NM_IP_CONFIG_SOURCE_VPN; - route.metric = route_metric; - nm_ip6_config_add_route (config, &route, NULL); - } +add_ip6_vpn_gateway_route(NMIP6Config * config, + NMDevice * parent_device, + const struct in6_addr *vpn_gw, + NMPlatform * platform) +{ + const struct in6_addr *parent_gw = NULL; + gboolean has_parent_gw = FALSE; + NMPlatformIP6Route route; + int ifindex; + guint32 route_metric; + nm_auto_nmpobj const NMPObject *route_resolved = NULL; + + g_return_if_fail(NM_IS_IP6_CONFIG(config)); + g_return_if_fail(NM_IS_DEVICE(parent_device)); + g_return_if_fail(vpn_gw != NULL); + + ifindex = nm_ip6_config_get_ifindex(config); + + nm_assert(ifindex > 0); + nm_assert(ifindex == nm_device_get_ip_ifindex(parent_device)); + + /* Ask kernel how to reach @vpn_gw. We can only inject the route in + * @parent_device, so whatever we resolve, it can only be on @ifindex. */ + if (nm_platform_ip_route_get(platform, + AF_INET6, + vpn_gw, + ifindex, + (NMPObject **) &route_resolved) + >= 0) { + const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE(route_resolved); + + if (r->ifindex == ifindex) { + const NMPObject *obj; + + /* `ip route get` always resolves the route, even if the destination is unreachable. + * In which case, it pretends the destination is directly reachable. + * + * So, only accept direct routes if @vpn_gw is a private network + * or if the parent device also has a direct default route */ + if (nm_platform_route_table_is_main(r->table_coerced)) { + if (!IN6_IS_ADDR_UNSPECIFIED(&r->gateway)) { + parent_gw = &r->gateway; + has_parent_gw = TRUE; + } else if (nm_utils_ip_is_site_local(AF_INET6, &vpn_gw)) { + has_parent_gw = TRUE; + } else if ((obj = nm_device_get_best_default_route(parent_device, AF_INET6)) + && IN6_IS_ADDR_UNSPECIFIED(&NMP_OBJECT_CAST_IP6_ROUTE(obj)->gateway)) { + has_parent_gw = TRUE; + } + } + } + } + + if (!has_parent_gw) + return; + + route_metric = nm_device_get_route_metric(parent_device, AF_INET6); + + memset(&route, 0, sizeof(route)); + route.ifindex = ifindex; + route.network = *vpn_gw; + route.plen = 128; + if (parent_gw) + route.gateway = *parent_gw; + route.rt_source = NM_IP_CONFIG_SOURCE_VPN; + route.metric = route_metric; + nm_ip6_config_add_route(config, &route, NULL); + + /* Ensure there's a route to the parent device's gateway through the + * parent device, since if the VPN claims the default route and the VPN + * routes include a subnet that matches the parent device's subnet, + * the parent device's gateway would get routed through the VPN and fail. + */ + if (parent_gw && !IN6_IS_ADDR_UNSPECIFIED(parent_gw)) { + memset(&route, 0, sizeof(route)); + route.network = *parent_gw; + route.plen = 128; + route.rt_source = NM_IP_CONFIG_SOURCE_VPN; + route.metric = route_metric; + nm_ip6_config_add_route(config, &route, NULL); + } } NMVpnConnection * -nm_vpn_connection_new (NMSettingsConnection *settings_connection, - NMDevice *parent_device, - const char *specific_object, - NMActivationReason activation_reason, - NMActivationStateFlags initial_state_flags, - NMAuthSubject *subject) -{ - g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); - g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL); - g_return_val_if_fail (specific_object, NULL); - - return (NMVpnConnection *) g_object_new (NM_TYPE_VPN_CONNECTION, - NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, settings_connection, - NM_ACTIVE_CONNECTION_INT_DEVICE, parent_device, - NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object, - NM_ACTIVE_CONNECTION_INT_SUBJECT, subject, - NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, activation_reason, - NM_ACTIVE_CONNECTION_VPN, TRUE, - NM_ACTIVE_CONNECTION_STATE_FLAGS, (guint) initial_state_flags, - NULL); +nm_vpn_connection_new(NMSettingsConnection * settings_connection, + NMDevice * parent_device, + const char * specific_object, + NMActivationReason activation_reason, + NMActivationStateFlags initial_state_flags, + NMAuthSubject * subject) +{ + g_return_val_if_fail(!settings_connection || NM_IS_SETTINGS_CONNECTION(settings_connection), + NULL); + g_return_val_if_fail(NM_IS_DEVICE(parent_device), NULL); + g_return_val_if_fail(specific_object, NULL); + + return (NMVpnConnection *) g_object_new(NM_TYPE_VPN_CONNECTION, + NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, + settings_connection, + NM_ACTIVE_CONNECTION_INT_DEVICE, + parent_device, + NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, + specific_object, + NM_ACTIVE_CONNECTION_INT_SUBJECT, + subject, + NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, + activation_reason, + NM_ACTIVE_CONNECTION_VPN, + TRUE, + NM_ACTIVE_CONNECTION_STATE_FLAGS, + (guint) initial_state_flags, + NULL); } const char * -nm_vpn_connection_get_service (NMVpnConnection *self) +nm_vpn_connection_get_service(NMVpnConnection *self) { - NMSettingVpn *s_vpn; + NMSettingVpn *s_vpn; - s_vpn = nm_connection_get_setting_vpn (_get_applied_connection (self)); - return nm_setting_vpn_get_service_type (s_vpn); + s_vpn = nm_connection_get_setting_vpn(_get_applied_connection(self)); + return nm_setting_vpn_get_service_type(s_vpn); } -static -NM_UTILS_LOOKUP_STR_DEFINE (_vpn_plugin_failure_to_string, NMVpnPluginFailure, - NM_UTILS_LOOKUP_DEFAULT (NULL), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED, "login-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED, "connect-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG, "bad-ip-config"), -); +static NM_UTILS_LOOKUP_STR_DEFINE( + _vpn_plugin_failure_to_string, + NMVpnPluginFailure, + NM_UTILS_LOOKUP_DEFAULT(NULL), + NM_UTILS_LOOKUP_STR_ITEM(NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED, "login-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED, "connect-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG, "bad-ip-config"), ); -#define vpn_plugin_failure_to_string_a(failure) NM_UTILS_LOOKUP_STR_A (_vpn_plugin_failure_to_string, failure) +#define vpn_plugin_failure_to_string_a(failure) \ + NM_UTILS_LOOKUP_STR_A(_vpn_plugin_failure_to_string, failure) static void -plugin_failed (NMVpnConnection *self, guint reason) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - - _LOGW ("VPN plugin: failed: %s (%d)", vpn_plugin_failure_to_string_a (reason), reason); - - switch (reason) { - case NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED: - priv->failure_reason = NM_ACTIVE_CONNECTION_STATE_REASON_LOGIN_FAILED; - break; - case NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG: - priv->failure_reason = NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID; - break; - default: - priv->failure_reason = NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN; - break; - } -} - -static -NM_UTILS_LOOKUP_STR_DEFINE (_vpn_service_state_to_string, NMVpnServiceState, - NM_UTILS_LOOKUP_DEFAULT (NULL), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_SERVICE_STATE_UNKNOWN, "unknown"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_SERVICE_STATE_INIT, "init"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_SERVICE_STATE_SHUTDOWN, "shutdown"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_SERVICE_STATE_STARTING, "starting"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_SERVICE_STATE_STARTED, "started"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_SERVICE_STATE_STOPPING, "stopping"), - NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_SERVICE_STATE_STOPPED, "stopped"), -); - -#define vpn_service_state_to_string_a(state) NM_UTILS_LOOKUP_STR_A (_vpn_service_state_to_string, state) - -static -NM_UTILS_LOOKUP_STR_DEFINE (_vpn_state_to_string, VpnState, - NM_UTILS_LOOKUP_DEFAULT (NULL), - NM_UTILS_LOOKUP_STR_ITEM (STATE_UNKNOWN, "unknown"), - NM_UTILS_LOOKUP_STR_ITEM (STATE_WAITING, "waiting"), - NM_UTILS_LOOKUP_STR_ITEM (STATE_PREPARE, "prepare"), - NM_UTILS_LOOKUP_STR_ITEM (STATE_NEED_AUTH, "need-auth"), - NM_UTILS_LOOKUP_STR_ITEM (STATE_CONNECT, "connect"), - NM_UTILS_LOOKUP_STR_ITEM (STATE_IP_CONFIG_GET, "ip-config-get"), - NM_UTILS_LOOKUP_STR_ITEM (STATE_PRE_UP, "pre-up"), - NM_UTILS_LOOKUP_STR_ITEM (STATE_ACTIVATED, "activated"), - NM_UTILS_LOOKUP_STR_ITEM (STATE_DEACTIVATING, "deactivating"), - NM_UTILS_LOOKUP_STR_ITEM (STATE_DISCONNECTED, "disconnected"), - NM_UTILS_LOOKUP_STR_ITEM (STATE_FAILED, "failed"), -); - -#define vpn_state_to_string_a(state) NM_UTILS_LOOKUP_STR_A (_vpn_state_to_string, state) +plugin_failed(NMVpnConnection *self, guint reason) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + + _LOGW("VPN plugin: failed: %s (%d)", vpn_plugin_failure_to_string_a(reason), reason); + + switch (reason) { + case NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED: + priv->failure_reason = NM_ACTIVE_CONNECTION_STATE_REASON_LOGIN_FAILED; + break; + case NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG: + priv->failure_reason = NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID; + break; + default: + priv->failure_reason = NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN; + break; + } +} + +static NM_UTILS_LOOKUP_STR_DEFINE( + _vpn_service_state_to_string, + NMVpnServiceState, + NM_UTILS_LOOKUP_DEFAULT(NULL), + NM_UTILS_LOOKUP_STR_ITEM(NM_VPN_SERVICE_STATE_UNKNOWN, "unknown"), + NM_UTILS_LOOKUP_STR_ITEM(NM_VPN_SERVICE_STATE_INIT, "init"), + NM_UTILS_LOOKUP_STR_ITEM(NM_VPN_SERVICE_STATE_SHUTDOWN, "shutdown"), + NM_UTILS_LOOKUP_STR_ITEM(NM_VPN_SERVICE_STATE_STARTING, "starting"), + NM_UTILS_LOOKUP_STR_ITEM(NM_VPN_SERVICE_STATE_STARTED, "started"), + NM_UTILS_LOOKUP_STR_ITEM(NM_VPN_SERVICE_STATE_STOPPING, "stopping"), + NM_UTILS_LOOKUP_STR_ITEM(NM_VPN_SERVICE_STATE_STOPPED, "stopped"), ); + +#define vpn_service_state_to_string_a(state) \ + NM_UTILS_LOOKUP_STR_A(_vpn_service_state_to_string, state) + +static NM_UTILS_LOOKUP_STR_DEFINE(_vpn_state_to_string, + VpnState, + NM_UTILS_LOOKUP_DEFAULT(NULL), + NM_UTILS_LOOKUP_STR_ITEM(STATE_UNKNOWN, "unknown"), + NM_UTILS_LOOKUP_STR_ITEM(STATE_WAITING, "waiting"), + NM_UTILS_LOOKUP_STR_ITEM(STATE_PREPARE, "prepare"), + NM_UTILS_LOOKUP_STR_ITEM(STATE_NEED_AUTH, "need-auth"), + NM_UTILS_LOOKUP_STR_ITEM(STATE_CONNECT, "connect"), + NM_UTILS_LOOKUP_STR_ITEM(STATE_IP_CONFIG_GET, "ip-config-get"), + NM_UTILS_LOOKUP_STR_ITEM(STATE_PRE_UP, "pre-up"), + NM_UTILS_LOOKUP_STR_ITEM(STATE_ACTIVATED, "activated"), + NM_UTILS_LOOKUP_STR_ITEM(STATE_DEACTIVATING, "deactivating"), + NM_UTILS_LOOKUP_STR_ITEM(STATE_DISCONNECTED, "disconnected"), + NM_UTILS_LOOKUP_STR_ITEM(STATE_FAILED, "failed"), ); + +#define vpn_state_to_string_a(state) NM_UTILS_LOOKUP_STR_A(_vpn_state_to_string, state) static void -plugin_state_changed (NMVpnConnection *self, NMVpnServiceState new_service_state) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - NMVpnServiceState old_service_state = priv->service_state; - - _LOGI ("VPN plugin: state changed: %s (%d)", - vpn_service_state_to_string_a (new_service_state), new_service_state); - priv->service_state = new_service_state; - - if (new_service_state == NM_VPN_SERVICE_STATE_STOPPED) { - /* Clear connection secrets to ensure secrets get requested each time the - * connection is activated. - */ - nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (self)); - - if ((priv->vpn_state >= STATE_WAITING) && (priv->vpn_state <= STATE_ACTIVATED)) { - VpnState old_state = priv->vpn_state; - - _set_vpn_state (self, STATE_FAILED, priv->failure_reason, FALSE); - - /* Reset the failure reason */ - priv->failure_reason = NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN; - - /* If the connection failed, the service cannot persist, but the - * connection can persist, ask listeners to re-activate the connection. - */ - if ( old_state == STATE_ACTIVATED - && priv->vpn_state == STATE_FAILED - && _connection_only_can_persist (self)) - g_signal_emit (self, signals[INTERNAL_RETRY_AFTER_FAILURE], 0); - } - } else if (new_service_state == NM_VPN_SERVICE_STATE_STARTING && - old_service_state == NM_VPN_SERVICE_STATE_STARTED) { - /* The VPN service got disconnected and is attempting to reconnect */ - _set_vpn_state (self, STATE_CONNECT, NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, FALSE); - } +plugin_state_changed(NMVpnConnection *self, NMVpnServiceState new_service_state) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + NMVpnServiceState old_service_state = priv->service_state; + + _LOGI("VPN plugin: state changed: %s (%d)", + vpn_service_state_to_string_a(new_service_state), + new_service_state); + priv->service_state = new_service_state; + + if (new_service_state == NM_VPN_SERVICE_STATE_STOPPED) { + /* Clear connection secrets to ensure secrets get requested each time the + * connection is activated. + */ + nm_active_connection_clear_secrets(NM_ACTIVE_CONNECTION(self)); + + if ((priv->vpn_state >= STATE_WAITING) && (priv->vpn_state <= STATE_ACTIVATED)) { + VpnState old_state = priv->vpn_state; + + _set_vpn_state(self, STATE_FAILED, priv->failure_reason, FALSE); + + /* Reset the failure reason */ + priv->failure_reason = NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN; + + /* If the connection failed, the service cannot persist, but the + * connection can persist, ask listeners to re-activate the connection. + */ + if (old_state == STATE_ACTIVATED && priv->vpn_state == STATE_FAILED + && _connection_only_can_persist(self)) + g_signal_emit(self, signals[INTERNAL_RETRY_AFTER_FAILURE], 0); + } + } else if (new_service_state == NM_VPN_SERVICE_STATE_STARTING + && old_service_state == NM_VPN_SERVICE_STATE_STARTED) { + /* The VPN service got disconnected and is attempting to reconnect */ + _set_vpn_state(self, + STATE_CONNECT, + NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, + FALSE); + } } static void -print_vpn_config (NMVpnConnection *self) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - const NMPlatformIP4Address *address4; - const NMPlatformIP6Address *address6; - char *dns_domain = NULL; - guint32 num, i; - char b1[NM_UTILS_INET_ADDRSTRLEN]; - char b2[NM_UTILS_INET_ADDRSTRLEN]; - NMDedupMultiIter ipconf_iter; - - if (priv->ip4_external_gw) { - _LOGI ("Data: VPN Gateway: %s", - _nm_utils_inet4_ntop (priv->ip4_external_gw, b1)); - } else if (priv->ip6_external_gw) { - _LOGI ("Data: VPN Gateway: %s", - _nm_utils_inet6_ntop (priv->ip6_external_gw, b1)); - } - - _LOGI ("Data: Tunnel Device: %s%s%s", NM_PRINT_FMT_QUOTE_STRING (priv->ip_iface)); - - if (priv->ip4_config) { - const NMPlatformIP4Route *route; - - _LOGI ("Data: IPv4 configuration:"); - - address4 = nm_ip4_config_get_first_address (priv->ip4_config); - nm_assert (address4); - - if (priv->ip4_internal_gw) - _LOGI ("Data: Internal Gateway: %s", _nm_utils_inet4_ntop (priv->ip4_internal_gw, b1)); - _LOGI ("Data: Internal Address: %s", address4 ? _nm_utils_inet4_ntop (address4->address, b1) : "??"); - _LOGI ("Data: Internal Prefix: %d", address4 ? (int) address4->plen : -1); - _LOGI ("Data: Internal Point-to-Point Address: %s", _nm_utils_inet4_ntop (address4->peer_address, b1)); - - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->ip4_config, &route) { - _LOGI ("Data: Static Route: %s/%d Next Hop: %s", - _nm_utils_inet4_ntop (route->network, b1), - route->plen, - _nm_utils_inet4_ntop (route->gateway, b2)); - } - - num = nm_ip4_config_get_num_nameservers (priv->ip4_config); - for (i = 0; i < num; i++) { - _LOGI ("Data: Internal DNS: %s", - _nm_utils_inet4_ntop (nm_ip4_config_get_nameserver (priv->ip4_config, i), b1)); - } - - if (nm_ip4_config_get_num_domains (priv->ip4_config) > 0) - dns_domain = (char *) nm_ip4_config_get_domain (priv->ip4_config, 0); - - _LOGI ("Data: DNS Domain: '%s'", dns_domain ?: "(none)"); - } else - _LOGI ("Data: No IPv4 configuration"); - - if (priv->ip6_config) { - const NMPlatformIP6Route *route; - - _LOGI ("Data: IPv6 configuration:"); - - address6 = nm_ip6_config_get_first_address (priv->ip6_config); - nm_assert (address6); - - if (priv->ip6_internal_gw) - _LOGI ("Data: Internal Gateway: %s", _nm_utils_inet6_ntop (priv->ip6_internal_gw, b1)); - _LOGI ("Data: Internal Address: %s", _nm_utils_inet6_ntop (&address6->address, b1)); - _LOGI ("Data: Internal Prefix: %d", address6->plen); - _LOGI ("Data: Internal Point-to-Point Address: %s", _nm_utils_inet6_ntop (&address6->peer_address, b1)); - - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) { - _LOGI ("Data: Static Route: %s/%d Next Hop: %s", - _nm_utils_inet6_ntop (&route->network, b1), - route->plen, - _nm_utils_inet6_ntop (&route->gateway, b2)); - } - - num = nm_ip6_config_get_num_nameservers (priv->ip6_config); - for (i = 0; i < num; i++) { - _LOGI ("Data: Internal DNS: %s", - _nm_utils_inet6_ntop (nm_ip6_config_get_nameserver (priv->ip6_config, i), b1)); - } - - if (nm_ip6_config_get_num_domains (priv->ip6_config) > 0) - dns_domain = (char *) nm_ip6_config_get_domain (priv->ip6_config, 0); - - _LOGI ("Data: DNS Domain: '%s'", dns_domain ?: "(none)"); - } else - _LOGI ("Data: No IPv6 configuration"); - - if (priv->banner && strlen (priv->banner)) { - _LOGI ("Data: Login Banner:"); - _LOGI ("Data: -----------------------------------------"); - _LOGI ("Data: %s", priv->banner); - _LOGI ("Data: -----------------------------------------"); - } +print_vpn_config(NMVpnConnection *self) +{ + NMVpnConnectionPrivate * priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + const NMPlatformIP4Address *address4; + const NMPlatformIP6Address *address6; + char * dns_domain = NULL; + guint32 num, i; + char b1[NM_UTILS_INET_ADDRSTRLEN]; + char b2[NM_UTILS_INET_ADDRSTRLEN]; + NMDedupMultiIter ipconf_iter; + + if (priv->ip4_external_gw) { + _LOGI("Data: VPN Gateway: %s", _nm_utils_inet4_ntop(priv->ip4_external_gw, b1)); + } else if (priv->ip6_external_gw) { + _LOGI("Data: VPN Gateway: %s", _nm_utils_inet6_ntop(priv->ip6_external_gw, b1)); + } + + _LOGI("Data: Tunnel Device: %s%s%s", NM_PRINT_FMT_QUOTE_STRING(priv->ip_iface)); + + if (priv->ip4_config) { + const NMPlatformIP4Route *route; + + _LOGI("Data: IPv4 configuration:"); + + address4 = nm_ip4_config_get_first_address(priv->ip4_config); + nm_assert(address4); + + if (priv->ip4_internal_gw) + _LOGI("Data: Internal Gateway: %s", _nm_utils_inet4_ntop(priv->ip4_internal_gw, b1)); + _LOGI("Data: Internal Address: %s", + address4 ? _nm_utils_inet4_ntop(address4->address, b1) : "??"); + _LOGI("Data: Internal Prefix: %d", address4 ? (int) address4->plen : -1); + _LOGI("Data: Internal Point-to-Point Address: %s", + _nm_utils_inet4_ntop(address4->peer_address, b1)); + + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->ip4_config, &route) { + _LOGI("Data: Static Route: %s/%d Next Hop: %s", + _nm_utils_inet4_ntop(route->network, b1), + route->plen, + _nm_utils_inet4_ntop(route->gateway, b2)); + } + + num = nm_ip4_config_get_num_nameservers(priv->ip4_config); + for (i = 0; i < num; i++) { + _LOGI("Data: Internal DNS: %s", + _nm_utils_inet4_ntop(nm_ip4_config_get_nameserver(priv->ip4_config, i), b1)); + } + + if (nm_ip4_config_get_num_domains(priv->ip4_config) > 0) + dns_domain = (char *) nm_ip4_config_get_domain(priv->ip4_config, 0); + + _LOGI("Data: DNS Domain: '%s'", dns_domain ?: "(none)"); + } else + _LOGI("Data: No IPv4 configuration"); + + if (priv->ip6_config) { + const NMPlatformIP6Route *route; + + _LOGI("Data: IPv6 configuration:"); + + address6 = nm_ip6_config_get_first_address(priv->ip6_config); + nm_assert(address6); + + if (priv->ip6_internal_gw) + _LOGI("Data: Internal Gateway: %s", _nm_utils_inet6_ntop(priv->ip6_internal_gw, b1)); + _LOGI("Data: Internal Address: %s", _nm_utils_inet6_ntop(&address6->address, b1)); + _LOGI("Data: Internal Prefix: %d", address6->plen); + _LOGI("Data: Internal Point-to-Point Address: %s", + _nm_utils_inet6_ntop(&address6->peer_address, b1)); + + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) { + _LOGI("Data: Static Route: %s/%d Next Hop: %s", + _nm_utils_inet6_ntop(&route->network, b1), + route->plen, + _nm_utils_inet6_ntop(&route->gateway, b2)); + } + + num = nm_ip6_config_get_num_nameservers(priv->ip6_config); + for (i = 0; i < num; i++) { + _LOGI("Data: Internal DNS: %s", + _nm_utils_inet6_ntop(nm_ip6_config_get_nameserver(priv->ip6_config, i), b1)); + } + + if (nm_ip6_config_get_num_domains(priv->ip6_config) > 0) + dns_domain = (char *) nm_ip6_config_get_domain(priv->ip6_config, 0); + + _LOGI("Data: DNS Domain: '%s'", dns_domain ?: "(none)"); + } else + _LOGI("Data: No IPv6 configuration"); + + if (priv->banner && strlen(priv->banner)) { + _LOGI("Data: Login Banner:"); + _LOGI("Data: -----------------------------------------"); + _LOGI("Data: %s", priv->banner); + _LOGI("Data: -----------------------------------------"); + } } static void -apply_parent_device_config (NMVpnConnection *self) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self)); - int ifindex; - NMIP4Config *vpn4_parent_config = NULL; - NMIP6Config *vpn6_parent_config = NULL; - - ifindex = nm_device_get_ip_ifindex (parent_dev); - if (ifindex > 0) { - /* If the VPN didn't return a network interface, it is a route-based - * VPN (like kernel IPSec) and all IP addressing and routing should - * be done on the parent interface instead. - */ - if (priv->ip4_config) { - vpn4_parent_config = nm_ip4_config_new (nm_netns_get_multi_idx (priv->netns), - ifindex); - if (priv->ip_ifindex <= 0) - nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config, NM_IP_CONFIG_MERGE_NO_DNS, 0); - } - if (priv->ip6_config) { - vpn6_parent_config = nm_ip6_config_new (nm_netns_get_multi_idx (priv->netns), - ifindex); - if (priv->ip_ifindex <= 0) - nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config, NM_IP_CONFIG_MERGE_NO_DNS, 0); - } - } - - /* Add any explicit route to the VPN gateway through the parent device */ - if ( vpn4_parent_config - && priv->ip4_external_gw) { - add_ip4_vpn_gateway_route (vpn4_parent_config, - parent_dev, - priv->ip4_external_gw, - nm_netns_get_platform (priv->netns)); - } - if ( vpn6_parent_config - && priv->ip6_external_gw) { - add_ip6_vpn_gateway_route (vpn6_parent_config, - parent_dev, - priv->ip6_external_gw, - nm_netns_get_platform (priv->netns)); - } - - nm_device_replace_vpn4_config (parent_dev, priv->last_device_ip4_config, vpn4_parent_config); - g_clear_object (&priv->last_device_ip4_config); - priv->last_device_ip4_config = vpn4_parent_config; - - nm_device_replace_vpn6_config (parent_dev, priv->last_device_ip6_config, vpn6_parent_config); - g_clear_object (&priv->last_device_ip6_config); - priv->last_device_ip6_config = vpn6_parent_config; +apply_parent_device_config(NMVpnConnection *self) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + NMDevice * parent_dev = nm_active_connection_get_device(NM_ACTIVE_CONNECTION(self)); + int ifindex; + NMIP4Config *vpn4_parent_config = NULL; + NMIP6Config *vpn6_parent_config = NULL; + + ifindex = nm_device_get_ip_ifindex(parent_dev); + if (ifindex > 0) { + /* If the VPN didn't return a network interface, it is a route-based + * VPN (like kernel IPSec) and all IP addressing and routing should + * be done on the parent interface instead. + */ + if (priv->ip4_config) { + vpn4_parent_config = nm_ip4_config_new(nm_netns_get_multi_idx(priv->netns), ifindex); + if (priv->ip_ifindex <= 0) + nm_ip4_config_merge(vpn4_parent_config, + priv->ip4_config, + NM_IP_CONFIG_MERGE_NO_DNS, + 0); + } + if (priv->ip6_config) { + vpn6_parent_config = nm_ip6_config_new(nm_netns_get_multi_idx(priv->netns), ifindex); + if (priv->ip_ifindex <= 0) + nm_ip6_config_merge(vpn6_parent_config, + priv->ip6_config, + NM_IP_CONFIG_MERGE_NO_DNS, + 0); + } + } + + /* Add any explicit route to the VPN gateway through the parent device */ + if (vpn4_parent_config && priv->ip4_external_gw) { + add_ip4_vpn_gateway_route(vpn4_parent_config, + parent_dev, + priv->ip4_external_gw, + nm_netns_get_platform(priv->netns)); + } + if (vpn6_parent_config && priv->ip6_external_gw) { + add_ip6_vpn_gateway_route(vpn6_parent_config, + parent_dev, + priv->ip6_external_gw, + nm_netns_get_platform(priv->netns)); + } + + nm_device_replace_vpn4_config(parent_dev, priv->last_device_ip4_config, vpn4_parent_config); + g_clear_object(&priv->last_device_ip4_config); + priv->last_device_ip4_config = vpn4_parent_config; + + nm_device_replace_vpn6_config(parent_dev, priv->last_device_ip6_config, vpn6_parent_config); + g_clear_object(&priv->last_device_ip6_config); + priv->last_device_ip6_config = vpn6_parent_config; } static gboolean -nm_vpn_connection_apply_config (NMVpnConnection *self) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - - apply_parent_device_config (self); - - if (priv->ip_ifindex > 0) { - nm_platform_link_set_up (nm_netns_get_platform (priv->netns), priv->ip_ifindex, NULL); - - if (priv->ip4_config) { - nm_assert (priv->ip_ifindex == nm_ip4_config_get_ifindex (priv->ip4_config)); - if (!nm_ip4_config_commit (priv->ip4_config, - nm_netns_get_platform (priv->netns), - get_route_table (self, AF_INET, FALSE) - ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL - : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN)) - return FALSE; - nm_platform_ip4_dev_route_blacklist_set (nm_netns_get_platform (priv->netns), - priv->ip_ifindex, - priv->ip4_dev_route_blacklist); - } - - if (priv->ip6_config) { - nm_assert (priv->ip_ifindex == nm_ip6_config_get_ifindex (priv->ip6_config)); - if (!nm_ip6_config_commit (priv->ip6_config, - nm_netns_get_platform (priv->netns), - get_route_table (self, AF_INET6, FALSE) - ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL - : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, - NULL)) - return FALSE; - } - - if (priv->mtu && priv->mtu != nm_platform_link_get_mtu (nm_netns_get_platform (priv->netns), priv->ip_ifindex)) - nm_platform_link_set_mtu (nm_netns_get_platform (priv->netns), priv->ip_ifindex, priv->mtu); - } - - _LOGI ("VPN connection: (IP Config Get) complete"); - if (priv->vpn_state < STATE_PRE_UP) - _set_vpn_state (self, STATE_PRE_UP, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); - return TRUE; +nm_vpn_connection_apply_config(NMVpnConnection *self) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + + apply_parent_device_config(self); + + if (priv->ip_ifindex > 0) { + nm_platform_link_set_up(nm_netns_get_platform(priv->netns), priv->ip_ifindex, NULL); + + if (priv->ip4_config) { + nm_assert(priv->ip_ifindex == nm_ip4_config_get_ifindex(priv->ip4_config)); + if (!nm_ip4_config_commit(priv->ip4_config, + nm_netns_get_platform(priv->netns), + get_route_table(self, AF_INET, FALSE) + ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL + : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN)) + return FALSE; + nm_platform_ip4_dev_route_blacklist_set(nm_netns_get_platform(priv->netns), + priv->ip_ifindex, + priv->ip4_dev_route_blacklist); + } + + if (priv->ip6_config) { + nm_assert(priv->ip_ifindex == nm_ip6_config_get_ifindex(priv->ip6_config)); + if (!nm_ip6_config_commit(priv->ip6_config, + nm_netns_get_platform(priv->netns), + get_route_table(self, AF_INET6, FALSE) + ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL + : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, + NULL)) + return FALSE; + } + + if (priv->mtu + && priv->mtu + != nm_platform_link_get_mtu(nm_netns_get_platform(priv->netns), + priv->ip_ifindex)) + nm_platform_link_set_mtu(nm_netns_get_platform(priv->netns), + priv->ip_ifindex, + priv->mtu); + } + + _LOGI("VPN connection: (IP Config Get) complete"); + if (priv->vpn_state < STATE_PRE_UP) + _set_vpn_state(self, STATE_PRE_UP, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); + return TRUE; } static void -_cleanup_failed_config (NMVpnConnection *self) +_cleanup_failed_config(NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - nm_dbus_object_clear_and_unexport (&priv->ip4_config); - nm_dbus_object_clear_and_unexport (&priv->ip6_config); + nm_dbus_object_clear_and_unexport(&priv->ip4_config); + nm_dbus_object_clear_and_unexport(&priv->ip6_config); - _LOGW ("VPN connection: did not receive valid IP config information"); - _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, FALSE); + _LOGW("VPN connection: did not receive valid IP config information"); + _set_vpn_state(self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, FALSE); } static void -fw_change_zone_cb (NMFirewallManager *firewall_manager, - NMFirewallManagerCallId *call_id, - GError *error, - gpointer user_data) +fw_change_zone_cb(NMFirewallManager * firewall_manager, + NMFirewallManagerCallId *call_id, + GError * error, + gpointer user_data) { - NMVpnConnection *self = user_data; - NMVpnConnectionPrivate *priv; + NMVpnConnection * self = user_data; + NMVpnConnectionPrivate *priv; - g_return_if_fail (NM_IS_VPN_CONNECTION (self)); + g_return_if_fail(NM_IS_VPN_CONNECTION(self)); - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - g_return_if_fail (priv->fw_call == call_id); + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + g_return_if_fail(priv->fw_call == call_id); - priv->fw_call = NULL; + priv->fw_call = NULL; - if (nm_utils_error_is_cancelled (error)) - return; + if (nm_utils_error_is_cancelled(error)) + return; - if (error) { - // FIXME: fail the activation? - } + if (error) { + // FIXME: fail the activation? + } - if (!nm_vpn_connection_apply_config (self)) - _cleanup_failed_config (self); + if (!nm_vpn_connection_apply_config(self)) + _cleanup_failed_config(self); } static void -nm_vpn_connection_config_maybe_complete (NMVpnConnection *self, - gboolean success) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - NMConnection *base_con; - NMSettingConnection *s_con; - const char *zone; - - if (priv->vpn_state < STATE_IP_CONFIG_GET || priv->vpn_state > STATE_ACTIVATED) - return; - - if (success) { - if ( (priv->has_ip4 && !priv->ip4_config) - || (priv->has_ip6 && !priv->ip6_config)) { - /* Need to wait for other config */ - return; - } - } - - nm_clear_g_source (&priv->connect_timeout); - - if (success) { - print_vpn_config (self); - - /* Add the tunnel interface to the specified firewall zone */ - if (priv->ip_iface) { - base_con = _get_applied_connection (self); - s_con = nm_connection_get_setting_connection (base_con); - zone = nm_setting_connection_get_zone (s_con); - - _LOGD ("setting firewall zone %s%s%s for '%s'", - NM_PRINT_FMT_QUOTED (zone, "'", zone, "'", "(default)"), - priv->ip_iface); - fw_call_cleanup (self); - priv->fw_call = nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (), - priv->ip_iface, - zone, - FALSE, - fw_change_zone_cb, - self); - return; - } else - if (nm_vpn_connection_apply_config (self)) - return; - } - - _cleanup_failed_config (self); +nm_vpn_connection_config_maybe_complete(NMVpnConnection *self, gboolean success) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + NMConnection * base_con; + NMSettingConnection * s_con; + const char * zone; + + if (priv->vpn_state < STATE_IP_CONFIG_GET || priv->vpn_state > STATE_ACTIVATED) + return; + + if (success) { + if ((priv->has_ip4 && !priv->ip4_config) || (priv->has_ip6 && !priv->ip6_config)) { + /* Need to wait for other config */ + return; + } + } + + nm_clear_g_source(&priv->connect_timeout); + + if (success) { + print_vpn_config(self); + + /* Add the tunnel interface to the specified firewall zone */ + if (priv->ip_iface) { + base_con = _get_applied_connection(self); + s_con = nm_connection_get_setting_connection(base_con); + zone = nm_setting_connection_get_zone(s_con); + + _LOGD("setting firewall zone %s%s%s for '%s'", + NM_PRINT_FMT_QUOTED(zone, "'", zone, "'", "(default)"), + priv->ip_iface); + fw_call_cleanup(self); + priv->fw_call = nm_firewall_manager_add_or_change_zone(nm_firewall_manager_get(), + priv->ip_iface, + zone, + FALSE, + fw_change_zone_cb, + self); + return; + } else if (nm_vpn_connection_apply_config(self)) + return; + } + + _cleanup_failed_config(self); } static gboolean -ip6_addr_from_variant (GVariant *v, struct in6_addr *addr) +ip6_addr_from_variant(GVariant *v, struct in6_addr *addr) { - const guint8 *bytes; - gsize len; + const guint8 *bytes; + gsize len; - g_return_val_if_fail (v, FALSE); - g_return_val_if_fail (addr, FALSE); + g_return_val_if_fail(v, FALSE); + g_return_val_if_fail(addr, FALSE); - if (g_variant_is_of_type (v, G_VARIANT_TYPE ("ay"))) { - bytes = g_variant_get_fixed_array (v, &len, sizeof (guint8)); - if (len == sizeof (struct in6_addr) && !IN6_IS_ADDR_UNSPECIFIED (bytes)) { - memcpy (addr, bytes, len); - return TRUE; - } - } - return FALSE; + if (g_variant_is_of_type(v, G_VARIANT_TYPE("ay"))) { + bytes = g_variant_get_fixed_array(v, &len, sizeof(guint8)); + if (len == sizeof(struct in6_addr) && !IN6_IS_ADDR_UNSPECIFIED(bytes)) { + memcpy(addr, bytes, len); + return TRUE; + } + } + return FALSE; } static struct in6_addr * -ip6_addr_dup_from_variant (GVariant *v) +ip6_addr_dup_from_variant(GVariant *v) { - struct in6_addr *addr; + struct in6_addr *addr; - addr = g_malloc0 (sizeof (*addr)); - if (ip6_addr_from_variant (v, addr)) - return addr; - g_free (addr); - return NULL; + addr = g_malloc0(sizeof(*addr)); + if (ip6_addr_from_variant(v, addr)) + return addr; + g_free(addr); + return NULL; } static gboolean -process_generic_config (NMVpnConnection *self, GVariant *dict) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - const char *str; - GVariant *v; - guint32 u32; - gboolean b; - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_CAN_PERSIST, "b", &b) && b) { - /* Defaults to FALSE, so only let service indicate TRUE */ - priv->service_can_persist = TRUE; - } - - nm_clear_g_free (&priv->ip_iface); - priv->ip_ifindex = 0; - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_TUNDEV, "&s", &str)) { - /* Backwards compat with NM-openswan */ - if (g_strcmp0 (str, "_none_") != 0) - priv->ip_iface = g_strdup (str); - } - - if (priv->ip_iface) { - /* Grab the interface index for address/routing operations */ - priv->ip_ifindex = nm_platform_link_get_ifindex (nm_netns_get_platform (priv->netns), priv->ip_iface); - if (priv->ip_ifindex <= 0) { - nm_platform_process_events (nm_netns_get_platform (priv->netns)); - priv->ip_ifindex = nm_platform_link_get_ifindex (nm_netns_get_platform (priv->netns), priv->ip_iface); - } - if (priv->ip_ifindex <= 0) { - _LOGE ("failed to look up VPN interface index for \"%s\"", priv->ip_iface); - nm_clear_g_free (&priv->ip_iface); - priv->ip_ifindex = 0; - nm_vpn_connection_config_maybe_complete (self, FALSE); - return FALSE; - } - } - - nm_clear_g_free (&priv->banner); - if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_BANNER, "&s", &str)) { - priv->banner = g_strdup (str); - _notify (self, PROP_BANNER); - } - - /* Proxy Config */ - g_clear_object (&priv->proxy_config); - priv->proxy_config = nm_proxy_config_new (); - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_PROXY_PAC, "&s", &str)) { - nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); - nm_proxy_config_set_pac_url (priv->proxy_config, str); - } else - nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); - - /* User overrides if any from the NMConnection's Proxy settings */ - nm_proxy_config_merge_setting (priv->proxy_config, - nm_connection_get_setting_proxy (_get_applied_connection (self))); - - /* External world-visible address of the VPN server */ - priv->ip4_external_gw = 0; - nm_clear_g_free (&priv->ip6_external_gw); - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, "u", &u32)) { - priv->ip4_external_gw = u32; - } else if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, "@ay", &v)) { - priv->ip6_external_gw = ip6_addr_dup_from_variant (v); - g_variant_unref (v); - - if (!priv->ip6_external_gw) { - _LOGE ("Invalid IPv6 VPN gateway address received"); - nm_vpn_connection_config_maybe_complete (self, FALSE); - return FALSE; - } - } - - priv->mtu = 0; - if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_MTU, "u", &u32)) - priv->mtu = u32; - - return TRUE; +process_generic_config(NMVpnConnection *self, GVariant *dict) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + const char * str; + GVariant * v; + guint32 u32; + gboolean b; + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_CAN_PERSIST, "b", &b) && b) { + /* Defaults to FALSE, so only let service indicate TRUE */ + priv->service_can_persist = TRUE; + } + + nm_clear_g_free(&priv->ip_iface); + priv->ip_ifindex = 0; + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_TUNDEV, "&s", &str)) { + /* Backwards compat with NM-openswan */ + if (g_strcmp0(str, "_none_") != 0) + priv->ip_iface = g_strdup(str); + } + + if (priv->ip_iface) { + /* Grab the interface index for address/routing operations */ + priv->ip_ifindex = + nm_platform_link_get_ifindex(nm_netns_get_platform(priv->netns), priv->ip_iface); + if (priv->ip_ifindex <= 0) { + nm_platform_process_events(nm_netns_get_platform(priv->netns)); + priv->ip_ifindex = + nm_platform_link_get_ifindex(nm_netns_get_platform(priv->netns), priv->ip_iface); + } + if (priv->ip_ifindex <= 0) { + _LOGE("failed to look up VPN interface index for \"%s\"", priv->ip_iface); + nm_clear_g_free(&priv->ip_iface); + priv->ip_ifindex = 0; + nm_vpn_connection_config_maybe_complete(self, FALSE); + return FALSE; + } + } + + nm_clear_g_free(&priv->banner); + if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_BANNER, "&s", &str)) { + priv->banner = g_strdup(str); + _notify(self, PROP_BANNER); + } + + /* Proxy Config */ + g_clear_object(&priv->proxy_config); + priv->proxy_config = nm_proxy_config_new(); + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_PROXY_PAC, "&s", &str)) { + nm_proxy_config_set_method(priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); + nm_proxy_config_set_pac_url(priv->proxy_config, str); + } else + nm_proxy_config_set_method(priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); + + /* User overrides if any from the NMConnection's Proxy settings */ + nm_proxy_config_merge_setting(priv->proxy_config, + nm_connection_get_setting_proxy(_get_applied_connection(self))); + + /* External world-visible address of the VPN server */ + priv->ip4_external_gw = 0; + nm_clear_g_free(&priv->ip6_external_gw); + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, "u", &u32)) { + priv->ip4_external_gw = u32; + } else if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, "@ay", &v)) { + priv->ip6_external_gw = ip6_addr_dup_from_variant(v); + g_variant_unref(v); + + if (!priv->ip6_external_gw) { + _LOGE("Invalid IPv6 VPN gateway address received"); + nm_vpn_connection_config_maybe_complete(self, FALSE); + return FALSE; + } + } + + priv->mtu = 0; + if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_MTU, "u", &u32)) + priv->mtu = u32; + + return TRUE; } static void -nm_vpn_connection_config_get (NMVpnConnection *self, GVariant *dict) +nm_vpn_connection_config_get(NMVpnConnection *self, GVariant *dict) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - gboolean b; + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + gboolean b; - g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT)); + g_return_if_fail(dict && g_variant_is_of_type(dict, G_VARIANT_TYPE_VARDICT)); - _LOGI ("VPN connection: (IP Config Get) reply received."); + _LOGI("VPN connection: (IP Config Get) reply received."); - if (priv->vpn_state == STATE_CONNECT) - _set_vpn_state (self, STATE_IP_CONFIG_GET, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); + if (priv->vpn_state == STATE_CONNECT) + _set_vpn_state(self, STATE_IP_CONFIG_GET, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); - if (!process_generic_config (self, dict)) - return; + if (!process_generic_config(self, dict)) + return; - /* Note whether to expect IPv4 and IPv6 configs */ - priv->has_ip4 = FALSE; - if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_HAS_IP4, "b", &b)) - priv->has_ip4 = b; - nm_dbus_object_clear_and_unexport (&priv->ip4_config); + /* Note whether to expect IPv4 and IPv6 configs */ + priv->has_ip4 = FALSE; + if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_HAS_IP4, "b", &b)) + priv->has_ip4 = b; + nm_dbus_object_clear_and_unexport(&priv->ip4_config); - priv->has_ip6 = FALSE; - if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_HAS_IP6, "b", &b)) - priv->has_ip6 = b; - nm_dbus_object_clear_and_unexport (&priv->ip6_config); + priv->has_ip6 = FALSE; + if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_HAS_IP6, "b", &b)) + priv->has_ip6 = b; + nm_dbus_object_clear_and_unexport(&priv->ip6_config); - nm_vpn_connection_config_maybe_complete (self, TRUE); + nm_vpn_connection_config_maybe_complete(self, TRUE); } guint32 -nm_vpn_connection_get_ip4_route_metric (NMVpnConnection *self) +nm_vpn_connection_get_ip4_route_metric(NMVpnConnection *self) { - gint64 route_metric; - NMConnection *applied; + gint64 route_metric; + NMConnection *applied; - applied = _get_applied_connection (self); - route_metric = nm_setting_ip_config_get_route_metric (nm_connection_get_setting_ip4_config (applied)); + applied = _get_applied_connection(self); + route_metric = + nm_setting_ip_config_get_route_metric(nm_connection_get_setting_ip4_config(applied)); - return (route_metric >= 0) ? route_metric : NM_VPN_ROUTE_METRIC_DEFAULT; + return (route_metric >= 0) ? route_metric : NM_VPN_ROUTE_METRIC_DEFAULT; } guint32 -nm_vpn_connection_get_ip6_route_metric (NMVpnConnection *self) +nm_vpn_connection_get_ip6_route_metric(NMVpnConnection *self) { - gint64 route_metric; - NMConnection *applied; + gint64 route_metric; + NMConnection *applied; - applied = _get_applied_connection (self); - route_metric = nm_setting_ip_config_get_route_metric (nm_connection_get_setting_ip6_config (applied)); + applied = _get_applied_connection(self); + route_metric = + nm_setting_ip_config_get_route_metric(nm_connection_get_setting_ip6_config(applied)); - return (route_metric >= 0) ? route_metric : NM_VPN_ROUTE_METRIC_DEFAULT; + return (route_metric >= 0) ? route_metric : NM_VPN_ROUTE_METRIC_DEFAULT; } static guint32 -get_route_table (NMVpnConnection *self, - int addr_family, - gboolean fallback_main) +get_route_table(NMVpnConnection *self, int addr_family, gboolean fallback_main) { - NMConnection *connection; - NMSettingIPConfig *s_ip; - guint32 route_table = 0; + NMConnection * connection; + NMSettingIPConfig *s_ip; + guint32 route_table = 0; - nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); - connection = _get_applied_connection (self); - if (connection) { - s_ip = nm_connection_get_setting_ip_config (connection, addr_family); - if (s_ip) - route_table = nm_setting_ip_config_get_route_table (s_ip); - } + connection = _get_applied_connection(self); + if (connection) { + s_ip = nm_connection_get_setting_ip_config(connection, addr_family); + if (s_ip) + route_table = nm_setting_ip_config_get_route_table(s_ip); + } - return route_table ?: (fallback_main ? RT_TABLE_MAIN : 0); + return route_table ?: (fallback_main ? RT_TABLE_MAIN : 0); } static gboolean -_is_device_vrf (NMVpnConnection *self) +_is_device_vrf(NMVpnConnection *self) { - NMDevice *parent; - NMDevice *master; + NMDevice *parent; + NMDevice *master; - parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self)); - if (!parent) - return FALSE; + parent = nm_active_connection_get_device(NM_ACTIVE_CONNECTION(self)); + if (!parent) + return FALSE; - master = nm_device_get_master (parent); - return master && nm_device_get_link_type (master) == NM_LINK_TYPE_VRF; + master = nm_device_get_master(parent); + return master && nm_device_get_link_type(master) == NM_LINK_TYPE_VRF; } static void -nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - NMPlatformIP4Address address; - guint32 u32, route_metric; - NMSettingIPConfig *s_ip; - NMSettingConnection *s_con; - guint32 route_table; - NMIP4Config *config; - GVariantIter *iter; - const char *str; - GVariant *v; - gboolean b; - int ip_ifindex; - guint32 mss = 0; - gboolean never_default = FALSE; - - g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT)); - - if (priv->vpn_state == STATE_CONNECT) - _set_vpn_state (self, STATE_IP_CONFIG_GET, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); - - if (priv->vpn_state > STATE_ACTIVATED) { - _LOGI ("VPN connection: (IP4 Config Get) ignoring, the connection is no longer active"); - return; - } - - if (priv->has_ip4) { - _LOGI ("VPN connection: (IP4 Config Get) reply received"); - - if (g_variant_n_children (dict) == 0) { - priv->has_ip4 = FALSE; - nm_vpn_connection_config_maybe_complete (self, TRUE); - return; - } - } else { - _LOGI ("VPN connection: (IP4 Config Get) reply received from old-style plugin"); - - /* In the old API, the generic and IPv4 configuration items - * were mixed together. - */ - if (!process_generic_config (self, dict)) - return; - - priv->has_ip4 = TRUE; - priv->has_ip6 = FALSE; - } - - ip_ifindex = nm_vpn_connection_get_ip_ifindex (self, TRUE); - if (ip_ifindex <= 0) - g_return_if_reached (); - - config = nm_ip4_config_new (nm_netns_get_multi_idx (priv->netns), - ip_ifindex); - nm_ip4_config_set_dns_priority (config, NM_DNS_PRIORITY_DEFAULT_VPN); - - memset (&address, 0, sizeof (address)); - address.plen = 24; - - /* Internal address of the VPN subnet's gateway */ - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY, "u", &u32)) - priv->ip4_internal_gw = u32; - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, "u", &u32)) - address.address = u32; - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PTP, "u", &u32)) - address.peer_address = u32; - else - address.peer_address = address.address; - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, "u", &u32)) - address.plen = u32; - - if (address.address && address.plen && address.plen <= 32) { - address.addr_source = NM_IP_CONFIG_SOURCE_VPN; - nm_ip4_config_add_address (config, &address); - } else { - _LOGW ("invalid IP4 config received!"); - g_object_unref (config); - nm_vpn_connection_config_maybe_complete (self, FALSE); - return; - } - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_DNS, "au", &iter)) { - while (g_variant_iter_next (iter, "u", &u32)) - nm_ip4_config_add_nameserver (config, u32); - g_variant_iter_free (iter); - } - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_NBNS, "au", &iter)) { - while (g_variant_iter_next (iter, "u", &u32)) - nm_ip4_config_add_wins (config, u32); - g_variant_iter_free (iter); - } - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_MSS, "u", &u32)) - mss = u32; - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN, "&s", &str)) - nm_ip4_config_add_domain (config, str); - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_DOMAINS, "as", &iter)) { - while (g_variant_iter_next (iter, "&s", &str)) - nm_ip4_config_add_domain (config, str); - g_variant_iter_free (iter); - } - - route_table = get_route_table (self, AF_INET, TRUE); - route_metric = nm_vpn_connection_get_ip4_route_metric (self); - s_ip = nm_connection_get_setting_ip4_config (_get_applied_connection (self)); - s_con = nm_connection_get_setting_connection (_get_applied_connection (self)); - - if (nm_setting_ip_config_get_ignore_auto_routes (s_ip)) { - /* ignore VPN routes */ - } else if ( g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES, "b", &b) - && b) { - if (priv->ip4_config) { - NMDedupMultiIter ipconf_iter; - const NMPlatformIP4Route *route; - - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->ip4_config, &route) - nm_ip4_config_add_route (config, route, NULL); - } - } else if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, "aau", &iter)) { - while (g_variant_iter_next (iter, "@au", &v)) { - NMPlatformIP4Route route = { 0, }; - guint32 plen; - - switch (g_variant_n_children (v)) { - case 5: - g_variant_get_child (v, 4, "u", &route.pref_src); - /* fall-through */ - case 4: - g_variant_get_child (v, 0, "u", &route.network); - g_variant_get_child (v, 1, "u", &plen); - g_variant_get_child (v, 2, "u", &route.gateway); - /* 4th item is unused route metric */ - route.table_coerced = nm_platform_route_table_coerce (route_table); - route.metric = route_metric; - route.rt_source = NM_IP_CONFIG_SOURCE_VPN; - - if (plen > 32 || plen == 0) - break; - route.plen = plen; - route.network = nm_utils_ip4_address_clear_host_address (route.network, plen); - - if ( priv->ip4_external_gw - && route.network == priv->ip4_external_gw - && route.plen == 32) { - /* Ignore host routes to the VPN gateway since NM adds one itself - * below. Since NM knows more about the routing situation than - * the VPN server, we want to use the NM created route instead of - * whatever the server provides. - */ - break; - } - - nm_ip4_config_add_route (config, &route, NULL); - break; - default: - break; - } - g_variant_unref (v); - } - g_variant_iter_free (iter); - } - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT, "b", &b)) - never_default = b; - - /* Merge in user overrides from the NMConnection's IPv4 setting */ - nm_ip4_config_merge_setting (config, - s_ip, - nm_setting_connection_get_mdns (s_con), - nm_setting_connection_get_llmnr (s_con), - route_table, - route_metric); - - if ( !never_default - && !nm_setting_ip_config_get_never_default (s_ip)) { - const NMPlatformIP4Route r = { - .ifindex = ip_ifindex, - .rt_source = NM_IP_CONFIG_SOURCE_VPN, - .gateway = priv->ip4_internal_gw, - .table_coerced = nm_platform_route_table_coerce (route_table), - .metric = route_metric, - .mss = mss, - }; - - nm_ip4_config_add_route (config, &r, NULL); - } - - nm_clear_pointer (&priv->ip4_dev_route_blacklist, g_ptr_array_unref); - - nm_ip4_config_add_dependent_routes (config, - route_table, - nm_vpn_connection_get_ip4_route_metric (self), - _is_device_vrf (self), - &priv->ip4_dev_route_blacklist); - - if (priv->ip4_config) { - nm_ip4_config_replace (priv->ip4_config, config, NULL); - g_object_unref (config); - } else { - priv->ip4_config = config; - nm_dbus_object_export (NM_DBUS_OBJECT (config)); - g_object_notify ((GObject *) self, NM_ACTIVE_CONNECTION_IP4_CONFIG); - } - - nm_vpn_connection_config_maybe_complete (self, TRUE); +nm_vpn_connection_ip4_config_get(NMVpnConnection *self, GVariant *dict) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + NMPlatformIP4Address address; + guint32 u32, route_metric; + NMSettingIPConfig * s_ip; + NMSettingConnection * s_con; + guint32 route_table; + NMIP4Config * config; + GVariantIter * iter; + const char * str; + GVariant * v; + gboolean b; + int ip_ifindex; + guint32 mss = 0; + gboolean never_default = FALSE; + + g_return_if_fail(dict && g_variant_is_of_type(dict, G_VARIANT_TYPE_VARDICT)); + + if (priv->vpn_state == STATE_CONNECT) + _set_vpn_state(self, STATE_IP_CONFIG_GET, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); + + if (priv->vpn_state > STATE_ACTIVATED) { + _LOGI("VPN connection: (IP4 Config Get) ignoring, the connection is no longer active"); + return; + } + + if (priv->has_ip4) { + _LOGI("VPN connection: (IP4 Config Get) reply received"); + + if (g_variant_n_children(dict) == 0) { + priv->has_ip4 = FALSE; + nm_vpn_connection_config_maybe_complete(self, TRUE); + return; + } + } else { + _LOGI("VPN connection: (IP4 Config Get) reply received from old-style plugin"); + + /* In the old API, the generic and IPv4 configuration items + * were mixed together. + */ + if (!process_generic_config(self, dict)) + return; + + priv->has_ip4 = TRUE; + priv->has_ip6 = FALSE; + } + + ip_ifindex = nm_vpn_connection_get_ip_ifindex(self, TRUE); + if (ip_ifindex <= 0) + g_return_if_reached(); + + config = nm_ip4_config_new(nm_netns_get_multi_idx(priv->netns), ip_ifindex); + nm_ip4_config_set_dns_priority(config, NM_DNS_PRIORITY_DEFAULT_VPN); + + memset(&address, 0, sizeof(address)); + address.plen = 24; + + /* Internal address of the VPN subnet's gateway */ + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY, "u", &u32)) + priv->ip4_internal_gw = u32; + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, "u", &u32)) + address.address = u32; + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_PTP, "u", &u32)) + address.peer_address = u32; + else + address.peer_address = address.address; + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, "u", &u32)) + address.plen = u32; + + if (address.address && address.plen && address.plen <= 32) { + address.addr_source = NM_IP_CONFIG_SOURCE_VPN; + nm_ip4_config_add_address(config, &address); + } else { + _LOGW("invalid IP4 config received!"); + g_object_unref(config); + nm_vpn_connection_config_maybe_complete(self, FALSE); + return; + } + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_DNS, "au", &iter)) { + while (g_variant_iter_next(iter, "u", &u32)) + nm_ip4_config_add_nameserver(config, u32); + g_variant_iter_free(iter); + } + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_NBNS, "au", &iter)) { + while (g_variant_iter_next(iter, "u", &u32)) + nm_ip4_config_add_wins(config, u32); + g_variant_iter_free(iter); + } + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_MSS, "u", &u32)) + mss = u32; + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN, "&s", &str)) + nm_ip4_config_add_domain(config, str); + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_DOMAINS, "as", &iter)) { + while (g_variant_iter_next(iter, "&s", &str)) + nm_ip4_config_add_domain(config, str); + g_variant_iter_free(iter); + } + + route_table = get_route_table(self, AF_INET, TRUE); + route_metric = nm_vpn_connection_get_ip4_route_metric(self); + s_ip = nm_connection_get_setting_ip4_config(_get_applied_connection(self)); + s_con = nm_connection_get_setting_connection(_get_applied_connection(self)); + + if (nm_setting_ip_config_get_ignore_auto_routes(s_ip)) { + /* ignore VPN routes */ + } else if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES, "b", &b) && b) { + if (priv->ip4_config) { + NMDedupMultiIter ipconf_iter; + const NMPlatformIP4Route *route; + + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->ip4_config, &route) + nm_ip4_config_add_route(config, route, NULL); + } + } else if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, "aau", &iter)) { + while (g_variant_iter_next(iter, "@au", &v)) { + NMPlatformIP4Route route = { + 0, + }; + guint32 plen; + + switch (g_variant_n_children(v)) { + case 5: + g_variant_get_child(v, 4, "u", &route.pref_src); + /* fall-through */ + case 4: + g_variant_get_child(v, 0, "u", &route.network); + g_variant_get_child(v, 1, "u", &plen); + g_variant_get_child(v, 2, "u", &route.gateway); + /* 4th item is unused route metric */ + route.table_coerced = nm_platform_route_table_coerce(route_table); + route.metric = route_metric; + route.rt_source = NM_IP_CONFIG_SOURCE_VPN; + + if (plen > 32 || plen == 0) + break; + route.plen = plen; + route.network = nm_utils_ip4_address_clear_host_address(route.network, plen); + + if (priv->ip4_external_gw && route.network == priv->ip4_external_gw + && route.plen == 32) { + /* Ignore host routes to the VPN gateway since NM adds one itself + * below. Since NM knows more about the routing situation than + * the VPN server, we want to use the NM created route instead of + * whatever the server provides. + */ + break; + } + + nm_ip4_config_add_route(config, &route, NULL); + break; + default: + break; + } + g_variant_unref(v); + } + g_variant_iter_free(iter); + } + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT, "b", &b)) + never_default = b; + + /* Merge in user overrides from the NMConnection's IPv4 setting */ + nm_ip4_config_merge_setting(config, + s_ip, + nm_setting_connection_get_mdns(s_con), + nm_setting_connection_get_llmnr(s_con), + route_table, + route_metric); + + if (!never_default && !nm_setting_ip_config_get_never_default(s_ip)) { + const NMPlatformIP4Route r = { + .ifindex = ip_ifindex, + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + .gateway = priv->ip4_internal_gw, + .table_coerced = nm_platform_route_table_coerce(route_table), + .metric = route_metric, + .mss = mss, + }; + + nm_ip4_config_add_route(config, &r, NULL); + } + + nm_clear_pointer(&priv->ip4_dev_route_blacklist, g_ptr_array_unref); + + nm_ip4_config_add_dependent_routes(config, + route_table, + nm_vpn_connection_get_ip4_route_metric(self), + _is_device_vrf(self), + &priv->ip4_dev_route_blacklist); + + if (priv->ip4_config) { + nm_ip4_config_replace(priv->ip4_config, config, NULL); + g_object_unref(config); + } else { + priv->ip4_config = config; + nm_dbus_object_export(NM_DBUS_OBJECT(config)); + g_object_notify((GObject *) self, NM_ACTIVE_CONNECTION_IP4_CONFIG); + } + + nm_vpn_connection_config_maybe_complete(self, TRUE); } static void -nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - NMPlatformIP6Address address; - guint32 u32, route_metric; - NMSettingIPConfig *s_ip; - guint32 route_table; - NMIP6Config *config; - GVariantIter *iter; - const char *str; - GVariant *v; - gboolean b; - int ip_ifindex; - guint32 mss = 0; - gboolean never_default = FALSE; - - g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT)); - - _LOGI ("VPN connection: (IP6 Config Get) reply received"); - - if (priv->vpn_state == STATE_CONNECT) - _set_vpn_state (self, STATE_IP_CONFIG_GET, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); - - if (priv->vpn_state > STATE_ACTIVATED) { - _LOGI ("VPN connection: (IP6 Config Get) ignoring, the connection is no longer active"); - return; - } - - if (g_variant_n_children (dict) == 0) { - priv->has_ip6 = FALSE; - nm_vpn_connection_config_maybe_complete (self, TRUE); - return; - } - - ip_ifindex = nm_vpn_connection_get_ip_ifindex (self, TRUE); - if (ip_ifindex <= 0) - g_return_if_reached (); - - config = nm_ip6_config_new (nm_netns_get_multi_idx (priv->netns), - ip_ifindex); - nm_ip6_config_set_dns_priority (config, NM_DNS_PRIORITY_DEFAULT_VPN); - - memset (&address, 0, sizeof (address)); - address.plen = 128; - - /* Internal address of the VPN subnet's gateway */ - nm_clear_g_free (&priv->ip6_internal_gw); - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY, "@ay", &v)) { - priv->ip6_internal_gw = ip6_addr_dup_from_variant (v); - g_variant_unref (v); - } - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS, "@ay", &v)) { - ip6_addr_from_variant (v, &address.address); - g_variant_unref (v); - } - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_PTP, "@ay", &v)) { - ip6_addr_from_variant (v, &address.peer_address); - g_variant_unref (v); - } - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_PREFIX, "u", &u32)) - address.plen = u32; - - if (!IN6_IS_ADDR_UNSPECIFIED (&address.address) && address.plen && address.plen <= 128) { - address.addr_source = NM_IP_CONFIG_SOURCE_VPN; - nm_ip6_config_add_address (config, &address); - } else { - _LOGW ("invalid IP6 config received!"); - g_object_unref (config); - nm_vpn_connection_config_maybe_complete (self, FALSE); - return; - } - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_DNS, "aay", &iter)) { - while (g_variant_iter_next (iter, "@ay", &v)) { - struct in6_addr dns; - - if (ip6_addr_from_variant (v, &dns)) - nm_ip6_config_add_nameserver (config, &dns); - g_variant_unref (v); - } - g_variant_iter_free (iter); - } - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_MSS, "u", &u32)) - mss = u32; - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_DOMAIN, "&s", &str)) - nm_ip6_config_add_domain (config, str); - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_DOMAINS, "as", &iter)) { - while (g_variant_iter_next (iter, "&s", &str)) - nm_ip6_config_add_domain (config, str); - g_variant_iter_free (iter); - } - - route_table = get_route_table (self, AF_INET6, TRUE); - route_metric = nm_vpn_connection_get_ip6_route_metric (self); - s_ip = nm_connection_get_setting_ip6_config (_get_applied_connection (self)); - - if (nm_setting_ip_config_get_ignore_auto_routes (s_ip)) { - /* Ignore VPN routes */ - } else if ( g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES, "b", &b) - && b) { - if (priv->ip6_config) { - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Route *route; - - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) - nm_ip6_config_add_route (config, route, NULL); - } - } else if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayu)", &iter)) { - GVariant *dest, *next_hop; - guint32 prefix, metric; - - while (g_variant_iter_next (iter, "(@ayu@ayu)", &dest, &prefix, &next_hop, &metric)) { - NMPlatformIP6Route route; - - memset (&route, 0, sizeof (route)); - - if (!ip6_addr_from_variant (dest, &route.network)) - goto next; - - if (prefix > 128 || prefix == 0) - goto next; - - route.plen = prefix; - ip6_addr_from_variant (next_hop, &route.gateway); - route.table_coerced = nm_platform_route_table_coerce (route_table); - route.metric = route_metric; - route.rt_source = NM_IP_CONFIG_SOURCE_VPN; - - nm_utils_ip6_address_clear_host_address (&route.network, &route.network, route.plen); - - if ( priv->ip6_external_gw - && IN6_ARE_ADDR_EQUAL (&route.network, priv->ip6_external_gw) - && route.plen == 128) { - /* Ignore host routes to the VPN gateway since NM adds one itself. - * Since NM knows more about the routing situation than the VPN - * server, we want to use the NM created route instead of whatever - * the server provides. - */ - goto next; - } - - nm_ip6_config_add_route (config, &route, NULL); +nm_vpn_connection_ip6_config_get(NMVpnConnection *self, GVariant *dict) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + NMPlatformIP6Address address; + guint32 u32, route_metric; + NMSettingIPConfig * s_ip; + guint32 route_table; + NMIP6Config * config; + GVariantIter * iter; + const char * str; + GVariant * v; + gboolean b; + int ip_ifindex; + guint32 mss = 0; + gboolean never_default = FALSE; + + g_return_if_fail(dict && g_variant_is_of_type(dict, G_VARIANT_TYPE_VARDICT)); + + _LOGI("VPN connection: (IP6 Config Get) reply received"); + + if (priv->vpn_state == STATE_CONNECT) + _set_vpn_state(self, STATE_IP_CONFIG_GET, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); + + if (priv->vpn_state > STATE_ACTIVATED) { + _LOGI("VPN connection: (IP6 Config Get) ignoring, the connection is no longer active"); + return; + } + + if (g_variant_n_children(dict) == 0) { + priv->has_ip6 = FALSE; + nm_vpn_connection_config_maybe_complete(self, TRUE); + return; + } + + ip_ifindex = nm_vpn_connection_get_ip_ifindex(self, TRUE); + if (ip_ifindex <= 0) + g_return_if_reached(); + + config = nm_ip6_config_new(nm_netns_get_multi_idx(priv->netns), ip_ifindex); + nm_ip6_config_set_dns_priority(config, NM_DNS_PRIORITY_DEFAULT_VPN); + + memset(&address, 0, sizeof(address)); + address.plen = 128; + + /* Internal address of the VPN subnet's gateway */ + nm_clear_g_free(&priv->ip6_internal_gw); + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY, "@ay", &v)) { + priv->ip6_internal_gw = ip6_addr_dup_from_variant(v); + g_variant_unref(v); + } + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS, "@ay", &v)) { + ip6_addr_from_variant(v, &address.address); + g_variant_unref(v); + } + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_PTP, "@ay", &v)) { + ip6_addr_from_variant(v, &address.peer_address); + g_variant_unref(v); + } + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_PREFIX, "u", &u32)) + address.plen = u32; + + if (!IN6_IS_ADDR_UNSPECIFIED(&address.address) && address.plen && address.plen <= 128) { + address.addr_source = NM_IP_CONFIG_SOURCE_VPN; + nm_ip6_config_add_address(config, &address); + } else { + _LOGW("invalid IP6 config received!"); + g_object_unref(config); + nm_vpn_connection_config_maybe_complete(self, FALSE); + return; + } + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_DNS, "aay", &iter)) { + while (g_variant_iter_next(iter, "@ay", &v)) { + struct in6_addr dns; + + if (ip6_addr_from_variant(v, &dns)) + nm_ip6_config_add_nameserver(config, &dns); + g_variant_unref(v); + } + g_variant_iter_free(iter); + } + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_MSS, "u", &u32)) + mss = u32; + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_DOMAIN, "&s", &str)) + nm_ip6_config_add_domain(config, str); + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_DOMAINS, "as", &iter)) { + while (g_variant_iter_next(iter, "&s", &str)) + nm_ip6_config_add_domain(config, str); + g_variant_iter_free(iter); + } + + route_table = get_route_table(self, AF_INET6, TRUE); + route_metric = nm_vpn_connection_get_ip6_route_metric(self); + s_ip = nm_connection_get_setting_ip6_config(_get_applied_connection(self)); + + if (nm_setting_ip_config_get_ignore_auto_routes(s_ip)) { + /* Ignore VPN routes */ + } else if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES, "b", &b) && b) { + if (priv->ip6_config) { + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Route *route; + + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) + nm_ip6_config_add_route(config, route, NULL); + } + } else if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayu)", &iter)) { + GVariant *dest, *next_hop; + guint32 prefix, metric; + + while (g_variant_iter_next(iter, "(@ayu@ayu)", &dest, &prefix, &next_hop, &metric)) { + NMPlatformIP6Route route; + + memset(&route, 0, sizeof(route)); + + if (!ip6_addr_from_variant(dest, &route.network)) + goto next; + + if (prefix > 128 || prefix == 0) + goto next; + + route.plen = prefix; + ip6_addr_from_variant(next_hop, &route.gateway); + route.table_coerced = nm_platform_route_table_coerce(route_table); + route.metric = route_metric; + route.rt_source = NM_IP_CONFIG_SOURCE_VPN; + + nm_utils_ip6_address_clear_host_address(&route.network, &route.network, route.plen); + + if (priv->ip6_external_gw && IN6_ARE_ADDR_EQUAL(&route.network, priv->ip6_external_gw) + && route.plen == 128) { + /* Ignore host routes to the VPN gateway since NM adds one itself. + * Since NM knows more about the routing situation than the VPN + * server, we want to use the NM created route instead of whatever + * the server provides. + */ + goto next; + } + + nm_ip6_config_add_route(config, &route, NULL); next: - g_variant_unref (dest); - g_variant_unref (next_hop); - } - g_variant_iter_free (iter); - } - - if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT, "b", &b)) - never_default = b; - - /* Merge in user overrides from the NMConnection's IPv6 setting */ - nm_ip6_config_merge_setting (config, - s_ip, - route_table, - route_metric); - - if ( !never_default - && !nm_setting_ip_config_get_never_default (s_ip)) { - const NMPlatformIP6Route r = { - .ifindex = ip_ifindex, - .rt_source = NM_IP_CONFIG_SOURCE_VPN, - .gateway = *(priv->ip6_internal_gw ?: &in6addr_any), - .table_coerced = nm_platform_route_table_coerce (route_table), - .metric = route_metric, - .mss = mss, - }; - - nm_ip6_config_add_route (config, &r, NULL); - } - - nm_ip6_config_add_dependent_routes (config, route_table, route_metric, _is_device_vrf (self)); - - if (priv->ip6_config) { - nm_ip6_config_replace (priv->ip6_config, config, NULL); - g_object_unref (config); - } else { - priv->ip6_config = config; - nm_dbus_object_export (NM_DBUS_OBJECT (config)); - g_object_notify ((GObject *) self, NM_ACTIVE_CONNECTION_IP6_CONFIG); - } - - nm_vpn_connection_config_maybe_complete (self, TRUE); + g_variant_unref(dest); + g_variant_unref(next_hop); + } + g_variant_iter_free(iter); + } + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT, "b", &b)) + never_default = b; + + /* Merge in user overrides from the NMConnection's IPv6 setting */ + nm_ip6_config_merge_setting(config, s_ip, route_table, route_metric); + + if (!never_default && !nm_setting_ip_config_get_never_default(s_ip)) { + const NMPlatformIP6Route r = { + .ifindex = ip_ifindex, + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + .gateway = *(priv->ip6_internal_gw ?: &in6addr_any), + .table_coerced = nm_platform_route_table_coerce(route_table), + .metric = route_metric, + .mss = mss, + }; + + nm_ip6_config_add_route(config, &r, NULL); + } + + nm_ip6_config_add_dependent_routes(config, route_table, route_metric, _is_device_vrf(self)); + + if (priv->ip6_config) { + nm_ip6_config_replace(priv->ip6_config, config, NULL); + g_object_unref(config); + } else { + priv->ip6_config = config; + nm_dbus_object_export(NM_DBUS_OBJECT(config)); + g_object_notify((GObject *) self, NM_ACTIVE_CONNECTION_IP6_CONFIG); + } + + nm_vpn_connection_config_maybe_complete(self, TRUE); } static gboolean -connect_timeout_cb (gpointer user_data) +connect_timeout_cb(gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnection * self = NM_VPN_CONNECTION(user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - priv->connect_timeout = 0; + priv->connect_timeout = 0; - /* Cancel activation if it's taken too long */ - if (priv->vpn_state == STATE_CONNECT || - priv->vpn_state == STATE_IP_CONFIG_GET) { - _LOGW ("VPN connection: connect timeout exceeded."); - _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, FALSE); - } + /* Cancel activation if it's taken too long */ + if (priv->vpn_state == STATE_CONNECT || priv->vpn_state == STATE_IP_CONFIG_GET) { + _LOGW("VPN connection: connect timeout exceeded."); + _set_vpn_state(self, + STATE_FAILED, + NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, + FALSE); + } - return FALSE; + return FALSE; } static void -connect_success (NMVpnConnection *self) +connect_success(NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - NMSettingVpn *s_vpn; - guint32 timeout; + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + NMSettingVpn * s_vpn; + guint32 timeout; - s_vpn = nm_connection_get_setting_vpn (_get_applied_connection (self)); - g_assert (s_vpn); + s_vpn = nm_connection_get_setting_vpn(_get_applied_connection(self)); + g_assert(s_vpn); - /* Timeout waiting for IP config signal from VPN service - * It is a configured value or 60 seconds */ - timeout = nm_setting_vpn_get_timeout (s_vpn); - if (timeout == 0) { - timeout = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("vpn.timeout"), - NULL, - 1, G_MAXUINT32, 60); - } - priv->connect_timeout = g_timeout_add_seconds (timeout, connect_timeout_cb, self); + /* Timeout waiting for IP config signal from VPN service + * It is a configured value or 60 seconds */ + timeout = nm_setting_vpn_get_timeout(s_vpn); + if (timeout == 0) { + timeout = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("vpn.timeout"), + NULL, + 1, + G_MAXUINT32, + 60); + } + priv->connect_timeout = g_timeout_add_seconds(timeout, connect_timeout_cb, self); - nm_clear_pointer (&priv->connect_hash, g_variant_unref); + nm_clear_pointer(&priv->connect_hash, g_variant_unref); } static void -connect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +connect_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { - NMVpnConnection *self; - gs_unref_variant GVariant *reply = NULL; - gs_free_error GError *error = NULL; + NMVpnConnection *self; + gs_unref_variant GVariant *reply = NULL; + gs_free_error GError *error = NULL; - reply = g_dbus_proxy_call_finish (proxy, result, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; + reply = g_dbus_proxy_call_finish(proxy, result, &error); + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; - self = NM_VPN_CONNECTION (user_data); + self = NM_VPN_CONNECTION(user_data); - if (error) { - g_dbus_error_strip_remote_error (error); - _LOGW ("VPN connection: failed to connect: '%s'", - error->message); - _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); - } else - connect_success (self); + if (error) { + g_dbus_error_strip_remote_error(error); + _LOGW("VPN connection: failed to connect: '%s'", error->message); + _set_vpn_state(self, + STATE_FAILED, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, + FALSE); + } else + connect_success(self); } static void -connect_interactive_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) -{ - NMVpnConnection *self; - NMVpnConnectionPrivate *priv; - gs_unref_variant GVariant *reply = NULL; - gs_free_error GError *error = NULL; - - reply = g_dbus_proxy_call_finish (proxy, result, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_VPN_CONNECTION (user_data); - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - - _LOGI ("VPN connection: (ConnectInteractive) reply received"); - - if (g_error_matches (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED)) { - _LOGD ("VPN connection: falling back to non-interactive connect"); - - /* Fall back to Connect() */ - g_dbus_proxy_call (priv->proxy, - "Connect", - g_variant_new ("(@a{sa{sv}})", priv->connect_hash), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->cancellable, - (GAsyncReadyCallback) connect_cb, - self); - } else if (error) { - g_dbus_error_strip_remote_error (error); - _LOGW ("VPN connection: failed to connect interactively: '%s'", - error->message); - _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); - } else - connect_success (self); +connect_interactive_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +{ + NMVpnConnection * self; + NMVpnConnectionPrivate *priv; + gs_unref_variant GVariant *reply = NULL; + gs_free_error GError *error = NULL; + + reply = g_dbus_proxy_call_finish(proxy, result, &error); + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_VPN_CONNECTION(user_data); + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + + _LOGI("VPN connection: (ConnectInteractive) reply received"); + + if (g_error_matches(error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED)) { + _LOGD("VPN connection: falling back to non-interactive connect"); + + /* Fall back to Connect() */ + g_dbus_proxy_call(priv->proxy, + "Connect", + g_variant_new("(@a{sa{sv}})", priv->connect_hash), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + (GAsyncReadyCallback) connect_cb, + self); + } else if (error) { + g_dbus_error_strip_remote_error(error); + _LOGW("VPN connection: failed to connect interactively: '%s'", error->message); + _set_vpn_state(self, + STATE_FAILED, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, + FALSE); + } else + connect_success(self); } /* Add a username to a hashed connection */ static GVariant * -_hash_with_username (NMConnection *connection, const char *username) +_hash_with_username(NMConnection *connection, const char *username) { - gs_unref_object NMConnection *dup = NULL; - NMSettingVpn *s_vpn; + gs_unref_object NMConnection *dup = NULL; + NMSettingVpn * s_vpn; - /* Shortcut if we weren't given a username or if there already was one in - * the VPN setting; don't bother duplicating the connection and everything. - */ - s_vpn = nm_connection_get_setting_vpn (connection); - g_assert (s_vpn); - if (username == NULL || nm_setting_vpn_get_user_name (s_vpn)) - return nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL); + /* Shortcut if we weren't given a username or if there already was one in + * the VPN setting; don't bother duplicating the connection and everything. + */ + s_vpn = nm_connection_get_setting_vpn(connection); + g_assert(s_vpn); + if (username == NULL || nm_setting_vpn_get_user_name(s_vpn)) + return nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_ALL); - dup = nm_simple_connection_new_clone (connection); - g_assert (dup); - s_vpn = nm_connection_get_setting_vpn (dup); - g_assert (s_vpn); - g_object_set (s_vpn, NM_SETTING_VPN_USER_NAME, username, NULL); - return nm_connection_to_dbus (dup, NM_CONNECTION_SERIALIZE_ALL); + dup = nm_simple_connection_new_clone(connection); + g_assert(dup); + s_vpn = nm_connection_get_setting_vpn(dup); + g_assert(s_vpn); + g_object_set(s_vpn, NM_SETTING_VPN_USER_NAME, username, NULL); + return nm_connection_to_dbus(dup, NM_CONNECTION_SERIALIZE_ALL); } static void -really_activate (NMVpnConnection *self, const char *username) -{ - NMVpnConnectionPrivate *priv; - GVariantBuilder details; - - g_return_if_fail (NM_IS_VPN_CONNECTION (self)); - - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - g_return_if_fail (priv->vpn_state == STATE_NEED_AUTH); - - nm_clear_pointer (&priv->connect_hash, g_variant_unref); - priv->connect_hash = _hash_with_username (_get_applied_connection (self), username); - g_variant_ref_sink (priv->connect_hash); - - /* If at least one agent doesn't support VPN hints, then we can't use - * ConnectInteractive(), because that agent won't be able to pass hints - * from the VPN plugin's interactive secrets requests to the VPN authentication - * dialog and we won't get the secrets we need. In this case fall back to - * the old Connect() call. - */ - if (nm_agent_manager_all_agents_have_capability (nm_agent_manager_get (), - nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (self)), - NM_SECRET_AGENT_CAPABILITY_VPN_HINTS)) { - _LOGD ("Allowing interactive secrets as all agents have that capability"); - - g_variant_builder_init (&details, G_VARIANT_TYPE_VARDICT); - g_dbus_proxy_call (priv->proxy, - "ConnectInteractive", - g_variant_new ("(@a{sa{sv}}a{sv})", priv->connect_hash, &details), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->cancellable, - (GAsyncReadyCallback) connect_interactive_cb, - self); - } else { - _LOGD ("Calling old Connect function as not all agents support interactive secrets"); - g_dbus_proxy_call (priv->proxy, - "Connect", - g_variant_new ("(@a{sa{sv}})", priv->connect_hash), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->cancellable, - (GAsyncReadyCallback) connect_cb, - self); - } - - _set_vpn_state (self, STATE_CONNECT, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); +really_activate(NMVpnConnection *self, const char *username) +{ + NMVpnConnectionPrivate *priv; + GVariantBuilder details; + + g_return_if_fail(NM_IS_VPN_CONNECTION(self)); + + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + g_return_if_fail(priv->vpn_state == STATE_NEED_AUTH); + + nm_clear_pointer(&priv->connect_hash, g_variant_unref); + priv->connect_hash = _hash_with_username(_get_applied_connection(self), username); + g_variant_ref_sink(priv->connect_hash); + + /* If at least one agent doesn't support VPN hints, then we can't use + * ConnectInteractive(), because that agent won't be able to pass hints + * from the VPN plugin's interactive secrets requests to the VPN authentication + * dialog and we won't get the secrets we need. In this case fall back to + * the old Connect() call. + */ + if (nm_agent_manager_all_agents_have_capability( + nm_agent_manager_get(), + nm_active_connection_get_subject(NM_ACTIVE_CONNECTION(self)), + NM_SECRET_AGENT_CAPABILITY_VPN_HINTS)) { + _LOGD("Allowing interactive secrets as all agents have that capability"); + + g_variant_builder_init(&details, G_VARIANT_TYPE_VARDICT); + g_dbus_proxy_call(priv->proxy, + "ConnectInteractive", + g_variant_new("(@a{sa{sv}}a{sv})", priv->connect_hash, &details), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + (GAsyncReadyCallback) connect_interactive_cb, + self); + } else { + _LOGD("Calling old Connect function as not all agents support interactive secrets"); + g_dbus_proxy_call(priv->proxy, + "Connect", + g_variant_new("(@a{sa{sv}})", priv->connect_hash), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + (GAsyncReadyCallback) connect_cb, + self); + } + + _set_vpn_state(self, STATE_CONNECT, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); } static void -failure_cb (GDBusProxy *proxy, - guint32 reason, - gpointer user_data) +failure_cb(GDBusProxy *proxy, guint32 reason, gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); + NMVpnConnection *self = NM_VPN_CONNECTION(user_data); - plugin_failed (self, reason); + plugin_failed(self, reason); } static void -state_changed_cb (GDBusProxy *proxy, - guint32 new_service_state, - gpointer user_data) +state_changed_cb(GDBusProxy *proxy, guint32 new_service_state, gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); + NMVpnConnection *self = NM_VPN_CONNECTION(user_data); - plugin_state_changed (self, new_service_state); + plugin_state_changed(self, new_service_state); } static void -secrets_required_cb (GDBusProxy *proxy, - const char *message, - const char *const*secrets, - gpointer user_data) +secrets_required_cb(GDBusProxy * proxy, + const char * message, + const char *const *secrets, + gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); + NMVpnConnection *self = NM_VPN_CONNECTION(user_data); - plugin_interactive_secrets_required (self, message, secrets); + plugin_interactive_secrets_required(self, message, secrets); } static void -config_cb (GDBusProxy *proxy, - GVariant *dict, - gpointer user_data) +config_cb(GDBusProxy *proxy, GVariant *dict, gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnection * self = NM_VPN_CONNECTION(user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - /* Only list to this signals during and after connection */ - if (priv->vpn_state >= STATE_NEED_AUTH) - nm_vpn_connection_config_get (self, dict); + /* Only list to this signals during and after connection */ + if (priv->vpn_state >= STATE_NEED_AUTH) + nm_vpn_connection_config_get(self, dict); } static void -ip4_config_cb (GDBusProxy *proxy, - GVariant *dict, - gpointer user_data) +ip4_config_cb(GDBusProxy *proxy, GVariant *dict, gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnection * self = NM_VPN_CONNECTION(user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - /* Only list to this signals during and after connection */ - if (priv->vpn_state >= STATE_NEED_AUTH) - nm_vpn_connection_ip4_config_get (self, dict); + /* Only list to this signals during and after connection */ + if (priv->vpn_state >= STATE_NEED_AUTH) + nm_vpn_connection_ip4_config_get(self, dict); } static void -ip6_config_cb (GDBusProxy *proxy, - GVariant *dict, - gpointer user_data) +ip6_config_cb(GDBusProxy *proxy, GVariant *dict, gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnection * self = NM_VPN_CONNECTION(user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - /* Only list to this signals during and after connection */ - if (priv->vpn_state >= STATE_NEED_AUTH) - nm_vpn_connection_ip6_config_get (self, dict); + /* Only list to this signals during and after connection */ + if (priv->vpn_state >= STATE_NEED_AUTH) + nm_vpn_connection_ip6_config_get(self, dict); } static void -_name_owner_changed (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - char *owner; - - owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object)); - - if (owner && !priv->service_running) { - /* service appeared */ - priv->service_running = TRUE; - _LOGI ("Saw the service appear; activating connection"); - - /* No need to wait for the timeout any longer */ - nm_clear_g_source (&priv->start_timeout); - - /* Expect success because the VPN service has already appeared */ - _nm_dbus_signal_connect (priv->proxy, "Failure", G_VARIANT_TYPE ("(u)"), - G_CALLBACK (failure_cb), self); - _nm_dbus_signal_connect (priv->proxy, "StateChanged", G_VARIANT_TYPE ("(u)"), - G_CALLBACK (state_changed_cb), self); - _nm_dbus_signal_connect (priv->proxy, "SecretsRequired", G_VARIANT_TYPE ("(sas)"), - G_CALLBACK (secrets_required_cb), self); - _nm_dbus_signal_connect (priv->proxy, "Config", G_VARIANT_TYPE ("(a{sv})"), - G_CALLBACK (config_cb), self); - _nm_dbus_signal_connect (priv->proxy, "Ip4Config", G_VARIANT_TYPE ("(a{sv})"), - G_CALLBACK (ip4_config_cb), self); - _nm_dbus_signal_connect (priv->proxy, "Ip6Config", G_VARIANT_TYPE ("(a{sv})"), - G_CALLBACK (ip6_config_cb), self); - - _set_vpn_state (self, STATE_NEED_AUTH, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); - - /* Kick off the secrets requests; first we get existing system secrets - * and ask the plugin if these are sufficient, next we get all existing - * secrets from system and from user agents and ask the plugin again, - * and last we ask the user for new secrets if required. - */ - get_secrets (self, SECRETS_REQ_SYSTEM, NULL); - } else if (!owner && priv->service_running) { - /* service went away */ - priv->service_running = FALSE; - _LOGI ("VPN service disappeared"); - nm_vpn_connection_disconnect (self, NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_STOPPED, FALSE); - } - - g_free (owner); +_name_owner_changed(GObject *object, GParamSpec *pspec, gpointer user_data) +{ + NMVpnConnection * self = NM_VPN_CONNECTION(user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + char * owner; + + owner = g_dbus_proxy_get_name_owner(G_DBUS_PROXY(object)); + + if (owner && !priv->service_running) { + /* service appeared */ + priv->service_running = TRUE; + _LOGI("Saw the service appear; activating connection"); + + /* No need to wait for the timeout any longer */ + nm_clear_g_source(&priv->start_timeout); + + /* Expect success because the VPN service has already appeared */ + _nm_dbus_signal_connect(priv->proxy, + "Failure", + G_VARIANT_TYPE("(u)"), + G_CALLBACK(failure_cb), + self); + _nm_dbus_signal_connect(priv->proxy, + "StateChanged", + G_VARIANT_TYPE("(u)"), + G_CALLBACK(state_changed_cb), + self); + _nm_dbus_signal_connect(priv->proxy, + "SecretsRequired", + G_VARIANT_TYPE("(sas)"), + G_CALLBACK(secrets_required_cb), + self); + _nm_dbus_signal_connect(priv->proxy, + "Config", + G_VARIANT_TYPE("(a{sv})"), + G_CALLBACK(config_cb), + self); + _nm_dbus_signal_connect(priv->proxy, + "Ip4Config", + G_VARIANT_TYPE("(a{sv})"), + G_CALLBACK(ip4_config_cb), + self); + _nm_dbus_signal_connect(priv->proxy, + "Ip6Config", + G_VARIANT_TYPE("(a{sv})"), + G_CALLBACK(ip6_config_cb), + self); + + _set_vpn_state(self, STATE_NEED_AUTH, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); + + /* Kick off the secrets requests; first we get existing system secrets + * and ask the plugin if these are sufficient, next we get all existing + * secrets from system and from user agents and ask the plugin again, + * and last we ask the user for new secrets if required. + */ + get_secrets(self, SECRETS_REQ_SYSTEM, NULL); + } else if (!owner && priv->service_running) { + /* service went away */ + priv->service_running = FALSE; + _LOGI("VPN service disappeared"); + nm_vpn_connection_disconnect(self, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_STOPPED, + FALSE); + } + + g_free(owner); } static gboolean -_daemon_exec_timeout (gpointer data) +_daemon_exec_timeout(gpointer data) { - NMVpnConnection *self = NM_VPN_CONNECTION (data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnection * self = NM_VPN_CONNECTION(data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - _LOGW ("Timed out waiting for the service to start"); - priv->start_timeout = 0; - nm_vpn_connection_disconnect (self, NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT, FALSE); - return G_SOURCE_REMOVE; + _LOGW("Timed out waiting for the service to start"); + priv->start_timeout = 0; + nm_vpn_connection_disconnect(self, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT, + FALSE); + return G_SOURCE_REMOVE; } static int -_get_log_level (void) -{ - NMLogLevel level; - - /* curiously enough, nm-logging also uses syslog. But it - * maps NMLogLevel differently to the syslog levels then we - * do here. - * - * The reason is, that LOG_NOTICE is already something worth - * highlighting in the journal, but we have 3 levels that are - * lower then LOG_NOTICE (LOGL_TRACE, LOGL_DEBUG, LOGL_INFO), - * On the other hand, syslog only defines LOG_DEBUG and LOG_INFO. - * Thus, we must map them differently. - * - * Inside the VPN plugin, you might want to treat LOG_NOTICE as - * as low severity, not worthy to be highlighted (like NM does). */ - - level = nm_logging_get_level (LOGD_VPN_PLUGIN); - if (level != _LOGL_OFF) { - if (level <= LOGL_TRACE) - return LOG_DEBUG; - if (level <= LOGL_DEBUG) - return LOG_INFO; - if (level <= LOGL_INFO) - return LOG_NOTICE; - if (level <= LOGL_WARN) - return LOG_WARNING; - if (level <= LOGL_ERR) - return LOG_ERR; - } - - return LOG_EMERG; +_get_log_level(void) +{ + NMLogLevel level; + + /* curiously enough, nm-logging also uses syslog. But it + * maps NMLogLevel differently to the syslog levels then we + * do here. + * + * The reason is, that LOG_NOTICE is already something worth + * highlighting in the journal, but we have 3 levels that are + * lower then LOG_NOTICE (LOGL_TRACE, LOGL_DEBUG, LOGL_INFO), + * On the other hand, syslog only defines LOG_DEBUG and LOG_INFO. + * Thus, we must map them differently. + * + * Inside the VPN plugin, you might want to treat LOG_NOTICE as + * as low severity, not worthy to be highlighted (like NM does). */ + + level = nm_logging_get_level(LOGD_VPN_PLUGIN); + if (level != _LOGL_OFF) { + if (level <= LOGL_TRACE) + return LOG_DEBUG; + if (level <= LOGL_DEBUG) + return LOG_INFO; + if (level <= LOGL_INFO) + return LOG_NOTICE; + if (level <= LOGL_WARN) + return LOG_WARNING; + if (level <= LOGL_ERR) + return LOG_ERR; + } + + return LOG_EMERG; } static gboolean -nm_vpn_service_daemon_exec (NMVpnConnection *self, GError **error) -{ - NMVpnConnectionPrivate *priv; - GPid pid; - char *vpn_argv[4]; - gboolean success = FALSE; - GError *spawn_error = NULL; - guint i, j, n_environ; - gs_free char **envp = NULL; - char env_log_level[NM_STRLEN ("NM_VPN_LOG_LEVEL=") + 100]; - char env_log_syslog[NM_STRLEN ("NM_VPN_LOG_SYSLOG=") + 10]; - const int N_ENVIRON_EXTRA = 3; - char **p_environ; - - g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), FALSE); - - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - - i = 0; - vpn_argv[i++] = (char *) nm_vpn_plugin_info_get_program (priv->plugin_info); - g_return_val_if_fail (vpn_argv[0], FALSE); - if (nm_vpn_plugin_info_supports_multiple (priv->plugin_info)) { - vpn_argv[i++] = "--bus-name"; - vpn_argv[i++] = priv->bus_name; - } - vpn_argv[i++] = NULL; - - /* we include <unistd.h> and "config.h" defines _GNU_SOURCE for us. So, we have @environ. */ - p_environ = environ; - n_environ = p_environ ? g_strv_length (p_environ) : 0; - envp = g_new (char *, n_environ + N_ENVIRON_EXTRA); - for (i = 0, j = 0; j < n_environ; j++) { - if ( g_str_has_prefix (p_environ[j], "NM_VPN_LOG_LEVEL=") - || g_str_has_prefix (p_environ[j], "NM_VPN_LOG_SYSLOG=")) - continue; - envp[i++] = p_environ[j]; - } - - /* NM_VPN_LOG_LEVEL: the syslog logging level for the plugin. */ - envp[i++] = nm_sprintf_buf (env_log_level, "NM_VPN_LOG_LEVEL=%d", _get_log_level ()); - - /* NM_VPN_LOG_SYSLOG: whether to log to stdout or syslog. If NetworkManager itself runs in - * foreground, we also want the plugin to log to stdout. - * If the plugin runs in background, the plugin should prefer logging to syslog. Otherwise - * logging messages will be lost (unless using journald, in which case it wouldn't matter). */ - envp[i++] = nm_sprintf_buf (env_log_syslog, "NM_VPN_LOG_SYSLOG=%c", nm_logging_syslog_enabled () ? '1' : '0'); - - envp[i++] = NULL; - nm_assert (i <= n_environ + N_ENVIRON_EXTRA); - - success = g_spawn_async (NULL, vpn_argv, envp, 0, nm_utils_setpgid, NULL, &pid, &spawn_error); - - if (success) { - _LOGI ("Started the VPN service, PID %ld", (long int) pid); - priv->start_timeout = g_timeout_add_seconds (5, _daemon_exec_timeout, self); - } else { - g_set_error (error, - NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "%s", spawn_error ? spawn_error->message : "unknown g_spawn_async() error"); - - if (spawn_error) - g_error_free (spawn_error); - } - - return success; +nm_vpn_service_daemon_exec(NMVpnConnection *self, GError **error) +{ + NMVpnConnectionPrivate *priv; + GPid pid; + char * vpn_argv[4]; + gboolean success = FALSE; + GError * spawn_error = NULL; + guint i, j, n_environ; + gs_free char ** envp = NULL; + char env_log_level[NM_STRLEN("NM_VPN_LOG_LEVEL=") + 100]; + char env_log_syslog[NM_STRLEN("NM_VPN_LOG_SYSLOG=") + 10]; + const int N_ENVIRON_EXTRA = 3; + char ** p_environ; + + g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), FALSE); + + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + + i = 0; + vpn_argv[i++] = (char *) nm_vpn_plugin_info_get_program(priv->plugin_info); + g_return_val_if_fail(vpn_argv[0], FALSE); + if (nm_vpn_plugin_info_supports_multiple(priv->plugin_info)) { + vpn_argv[i++] = "--bus-name"; + vpn_argv[i++] = priv->bus_name; + } + vpn_argv[i++] = NULL; + + /* we include <unistd.h> and "config.h" defines _GNU_SOURCE for us. So, we have @environ. */ + p_environ = environ; + n_environ = p_environ ? g_strv_length(p_environ) : 0; + envp = g_new(char *, n_environ + N_ENVIRON_EXTRA); + for (i = 0, j = 0; j < n_environ; j++) { + if (g_str_has_prefix(p_environ[j], "NM_VPN_LOG_LEVEL=") + || g_str_has_prefix(p_environ[j], "NM_VPN_LOG_SYSLOG=")) + continue; + envp[i++] = p_environ[j]; + } + + /* NM_VPN_LOG_LEVEL: the syslog logging level for the plugin. */ + envp[i++] = nm_sprintf_buf(env_log_level, "NM_VPN_LOG_LEVEL=%d", _get_log_level()); + + /* NM_VPN_LOG_SYSLOG: whether to log to stdout or syslog. If NetworkManager itself runs in + * foreground, we also want the plugin to log to stdout. + * If the plugin runs in background, the plugin should prefer logging to syslog. Otherwise + * logging messages will be lost (unless using journald, in which case it wouldn't matter). */ + envp[i++] = nm_sprintf_buf(env_log_syslog, + "NM_VPN_LOG_SYSLOG=%c", + nm_logging_syslog_enabled() ? '1' : '0'); + + envp[i++] = NULL; + nm_assert(i <= n_environ + N_ENVIRON_EXTRA); + + success = g_spawn_async(NULL, vpn_argv, envp, 0, nm_utils_setpgid, NULL, &pid, &spawn_error); + + if (success) { + _LOGI("Started the VPN service, PID %ld", (long int) pid); + priv->start_timeout = g_timeout_add_seconds(5, _daemon_exec_timeout, self); + } else { + g_set_error(error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "%s", + spawn_error ? spawn_error->message : "unknown g_spawn_async() error"); + + if (spawn_error) + g_error_free(spawn_error); + } + + return success; } static void -on_proxy_acquired (GObject *object, GAsyncResult *result, gpointer user_data) +on_proxy_acquired(GObject *object, GAsyncResult *result, gpointer user_data) { - NMVpnConnection *self; - NMVpnConnectionPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy *proxy; + NMVpnConnection * self; + NMVpnConnectionPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy * proxy; - proxy = g_dbus_proxy_new_for_bus_finish (result, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; + proxy = g_dbus_proxy_new_for_bus_finish(result, &error); + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; - self = NM_VPN_CONNECTION (user_data); - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + self = NM_VPN_CONNECTION(user_data); + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - if (error) { - _LOGE ("failed to acquire dbus proxy for VPN service: %s", - error->message); - _set_vpn_state (self, - STATE_FAILED, - NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, - FALSE); - return; - } + if (error) { + _LOGE("failed to acquire dbus proxy for VPN service: %s", error->message); + _set_vpn_state(self, + STATE_FAILED, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, + FALSE); + return; + } - priv->proxy = proxy; + priv->proxy = proxy; - g_signal_connect (priv->proxy, "notify::g-name-owner", - G_CALLBACK (_name_owner_changed), self); - _name_owner_changed (G_OBJECT (priv->proxy), NULL, self); + g_signal_connect(priv->proxy, "notify::g-name-owner", G_CALLBACK(_name_owner_changed), self); + _name_owner_changed(G_OBJECT(priv->proxy), NULL, self); - if (priv->service_running) - return; + if (priv->service_running) + return; - if (!nm_vpn_service_daemon_exec (self, &error)) { - _LOGW ("Could not launch the VPN service. error: %s.", - error->message); + if (!nm_vpn_service_daemon_exec(self, &error)) { + _LOGW("Could not launch the VPN service. error: %s.", error->message); - nm_vpn_connection_disconnect (self, NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); - } + nm_vpn_connection_disconnect(self, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, + FALSE); + } } void -nm_vpn_connection_activate (NMVpnConnection *self, - NMVpnPluginInfo *plugin_info) +nm_vpn_connection_activate(NMVpnConnection *self, NMVpnPluginInfo *plugin_info) { - NMVpnConnectionPrivate *priv; - NMSettingVpn *s_vpn; - const char *service; + NMVpnConnectionPrivate *priv; + NMSettingVpn * s_vpn; + const char * service; - g_return_if_fail (NM_IS_VPN_CONNECTION (self)); - g_return_if_fail (NM_IS_VPN_PLUGIN_INFO (plugin_info)); + g_return_if_fail(NM_IS_VPN_CONNECTION(self)); + g_return_if_fail(NM_IS_VPN_PLUGIN_INFO(plugin_info)); - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - g_return_if_fail (!priv->plugin_info); + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + g_return_if_fail(!priv->plugin_info); - s_vpn = nm_connection_get_setting_vpn (_get_applied_connection (self)); - g_return_if_fail (s_vpn); + s_vpn = nm_connection_get_setting_vpn(_get_applied_connection(self)); + g_return_if_fail(s_vpn); - service = nm_vpn_plugin_info_get_service (plugin_info); - nm_assert (service); + service = nm_vpn_plugin_info_get_service(plugin_info); + nm_assert(service); - if (nm_vpn_plugin_info_supports_multiple (plugin_info)) { - const char *path; + if (nm_vpn_plugin_info_supports_multiple(plugin_info)) { + const char *path; - path = nm_dbus_object_get_path (NM_DBUS_OBJECT (self)); - if (path) - path = strrchr (path, '/'); - g_return_if_fail (path); + path = nm_dbus_object_get_path(NM_DBUS_OBJECT(self)); + if (path) + path = strrchr(path, '/'); + g_return_if_fail(path); - priv->bus_name = g_strdup_printf ("%s.Connection_%s", service, &path[1]); - } else - priv->bus_name = g_strdup (service); + priv->bus_name = g_strdup_printf("%s.Connection_%s", service, &path[1]); + } else + priv->bus_name = g_strdup(service); - priv->connection_can_persist = nm_setting_vpn_get_persistent (s_vpn); - priv->plugin_info = g_object_ref (plugin_info); - priv->cancellable = g_cancellable_new (); + priv->connection_can_persist = nm_setting_vpn_get_persistent(s_vpn); + priv->plugin_info = g_object_ref(plugin_info); + priv->cancellable = g_cancellable_new(); - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, - priv->bus_name, - NM_VPN_DBUS_PLUGIN_PATH, - NM_VPN_DBUS_PLUGIN_INTERFACE, - priv->cancellable, - (GAsyncReadyCallback) on_proxy_acquired, - self); + g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + priv->bus_name, + NM_VPN_DBUS_PLUGIN_PATH, + NM_VPN_DBUS_PLUGIN_INTERFACE, + priv->cancellable, + (GAsyncReadyCallback) on_proxy_acquired, + self); - _set_vpn_state (self, STATE_PREPARE, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state(self, STATE_PREPARE, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); } NMVpnConnectionState -nm_vpn_connection_get_vpn_state (NMVpnConnection *self) +nm_vpn_connection_get_vpn_state(NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NM_VPN_CONNECTION_STATE_UNKNOWN); + g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), NM_VPN_CONNECTION_STATE_UNKNOWN); - return _state_to_nm_vpn_state (NM_VPN_CONNECTION_GET_PRIVATE (self)->vpn_state); + return _state_to_nm_vpn_state(NM_VPN_CONNECTION_GET_PRIVATE(self)->vpn_state); } const char * -nm_vpn_connection_get_banner (NMVpnConnection *self) +nm_vpn_connection_get_banner(NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NULL); + g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), NULL); - return NM_VPN_CONNECTION_GET_PRIVATE (self)->banner; + return NM_VPN_CONNECTION_GET_PRIVATE(self)->banner; } NMProxyConfig * -nm_vpn_connection_get_proxy_config (NMVpnConnection *self) +nm_vpn_connection_get_proxy_config(NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NULL); + g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), NULL); - return NM_VPN_CONNECTION_GET_PRIVATE (self)->proxy_config; + return NM_VPN_CONNECTION_GET_PRIVATE(self)->proxy_config; } NMIP4Config * -nm_vpn_connection_get_ip4_config (NMVpnConnection *self) +nm_vpn_connection_get_ip4_config(NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NULL); + g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), NULL); - return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip4_config; + return NM_VPN_CONNECTION_GET_PRIVATE(self)->ip4_config; } NMIP6Config * -nm_vpn_connection_get_ip6_config (NMVpnConnection *self) +nm_vpn_connection_get_ip6_config(NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NULL); + g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), NULL); - return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip6_config; + return NM_VPN_CONNECTION_GET_PRIVATE(self)->ip6_config; } static int -_get_ip_iface_for_device (NMVpnConnection *self, const char **out_iface) +_get_ip_iface_for_device(NMVpnConnection *self, const char **out_iface) { - NMDevice *parent_dev; - int ifindex; - const char *iface; + NMDevice * parent_dev; + int ifindex; + const char *iface; - nm_assert (NM_IS_VPN_CONNECTION (self)); + nm_assert(NM_IS_VPN_CONNECTION(self)); - /* the ifindex and the ifname in this case should come together. - * They either must be both set, or none. */ + /* the ifindex and the ifname in this case should come together. + * They either must be both set, or none. */ - parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self)); - if (!parent_dev) - goto none; - ifindex = nm_device_get_ip_ifindex (parent_dev); - if (ifindex <= 0) - goto none; - iface = nm_device_get_ip_iface (parent_dev); - if (!iface) - goto none; + parent_dev = nm_active_connection_get_device(NM_ACTIVE_CONNECTION(self)); + if (!parent_dev) + goto none; + ifindex = nm_device_get_ip_ifindex(parent_dev); + if (ifindex <= 0) + goto none; + iface = nm_device_get_ip_iface(parent_dev); + if (!iface) + goto none; - NM_SET_OUT (out_iface, iface); - return ifindex; + NM_SET_OUT(out_iface, iface); + return ifindex; none: - NM_SET_OUT (out_iface, NULL); - return 0; + NM_SET_OUT(out_iface, NULL); + return 0; } const char * -nm_vpn_connection_get_ip_iface (NMVpnConnection *self, gboolean fallback_device) +nm_vpn_connection_get_ip_iface(NMVpnConnection *self, gboolean fallback_device) { - NMVpnConnectionPrivate *priv; - const char *iface; + NMVpnConnectionPrivate *priv; + const char * iface; - g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NULL); + g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), NULL); - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - if (priv->ip_iface || !fallback_device) - return priv->ip_iface; + if (priv->ip_iface || !fallback_device) + return priv->ip_iface; - _get_ip_iface_for_device (self, &iface); - return iface; + _get_ip_iface_for_device(self, &iface); + return iface; } int -nm_vpn_connection_get_ip_ifindex (NMVpnConnection *self, gboolean fallback_device) +nm_vpn_connection_get_ip_ifindex(NMVpnConnection *self, gboolean fallback_device) { - NMVpnConnectionPrivate *priv; + NMVpnConnectionPrivate *priv; - g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), 0); + g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), 0); - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - if (priv->ip_ifindex > 0) - return priv->ip_ifindex; - if (!fallback_device) - return 0; + if (priv->ip_ifindex > 0) + return priv->ip_ifindex; + if (!fallback_device) + return 0; - return _get_ip_iface_for_device (self, NULL); + return _get_ip_iface_for_device(self, NULL); } guint32 -nm_vpn_connection_get_ip4_internal_gateway (NMVpnConnection *self) +nm_vpn_connection_get_ip4_internal_gateway(NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), 0); + g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), 0); - return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip4_internal_gw; + return NM_VPN_CONNECTION_GET_PRIVATE(self)->ip4_internal_gw; } struct in6_addr * -nm_vpn_connection_get_ip6_internal_gateway (NMVpnConnection *self) +nm_vpn_connection_get_ip6_internal_gateway(NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), 0); + g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), 0); - return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip6_internal_gw; + return NM_VPN_CONNECTION_GET_PRIVATE(self)->ip6_internal_gw; } void -nm_vpn_connection_disconnect (NMVpnConnection *self, - NMActiveConnectionStateReason reason, - gboolean quitting) +nm_vpn_connection_disconnect(NMVpnConnection * self, + NMActiveConnectionStateReason reason, + gboolean quitting) { - g_return_if_fail (NM_IS_VPN_CONNECTION (self)); + g_return_if_fail(NM_IS_VPN_CONNECTION(self)); - _set_vpn_state (self, STATE_DISCONNECTED, reason, quitting); + _set_vpn_state(self, STATE_DISCONNECTED, reason, quitting); } gboolean -nm_vpn_connection_deactivate (NMVpnConnection *self, - NMActiveConnectionStateReason reason, - gboolean quitting) +nm_vpn_connection_deactivate(NMVpnConnection * self, + NMActiveConnectionStateReason reason, + gboolean quitting) { - NMVpnConnectionPrivate *priv; - gboolean success = FALSE; + NMVpnConnectionPrivate *priv; + gboolean success = FALSE; - g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), FALSE); + g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), FALSE); - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - if (priv->vpn_state > STATE_UNKNOWN && priv->vpn_state <= STATE_DEACTIVATING) { - _set_vpn_state (self, STATE_DEACTIVATING, reason, quitting); - success = TRUE; - } - return success; + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + if (priv->vpn_state > STATE_UNKNOWN && priv->vpn_state <= STATE_DEACTIVATING) { + _set_vpn_state(self, STATE_DEACTIVATING, reason, quitting); + success = TRUE; + } + return success; } /*****************************************************************************/ static void -plugin_need_secrets_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) -{ - NMVpnConnection *self; - NMVpnConnectionPrivate *priv; - gs_unref_variant GVariant *reply = NULL; - gs_free_error GError *error = NULL; - const char *setting_name; - - reply = _nm_dbus_proxy_call_finish (proxy, result, G_VARIANT_TYPE ("(s)"), &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_VPN_CONNECTION (user_data); - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - - if (error) { - g_dbus_error_strip_remote_error (error); - _LOGE ("plugin NeedSecrets request #%d failed: %s", - priv->secrets_idx + 1, - error->message); - _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); - return; - } - - g_variant_get (reply, "(&s)", &setting_name); - if (!strlen (setting_name)) { - _LOGD ("service indicated no additional secrets required"); - - /* No secrets required; we can start the VPN */ - really_activate (self, priv->username); - return; - } - - /* More secrets required */ - if (priv->secrets_idx == SECRETS_REQ_NEW) { - _LOGE ("final secrets request failed to provide sufficient secrets"); - _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); - } else { - _LOGD ("service indicated additional secrets required"); - get_secrets (self, priv->secrets_idx + 1, NULL); - } +plugin_need_secrets_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +{ + NMVpnConnection * self; + NMVpnConnectionPrivate *priv; + gs_unref_variant GVariant *reply = NULL; + gs_free_error GError *error = NULL; + const char * setting_name; + + reply = _nm_dbus_proxy_call_finish(proxy, result, G_VARIANT_TYPE("(s)"), &error); + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_VPN_CONNECTION(user_data); + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + + if (error) { + g_dbus_error_strip_remote_error(error); + _LOGE("plugin NeedSecrets request #%d failed: %s", priv->secrets_idx + 1, error->message); + _set_vpn_state(self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); + return; + } + + g_variant_get(reply, "(&s)", &setting_name); + if (!strlen(setting_name)) { + _LOGD("service indicated no additional secrets required"); + + /* No secrets required; we can start the VPN */ + really_activate(self, priv->username); + return; + } + + /* More secrets required */ + if (priv->secrets_idx == SECRETS_REQ_NEW) { + _LOGE("final secrets request failed to provide sufficient secrets"); + _set_vpn_state(self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); + } else { + _LOGD("service indicated additional secrets required"); + get_secrets(self, priv->secrets_idx + 1, NULL); + } } static void -plugin_new_secrets_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +plugin_new_secrets_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { - NMVpnConnection *self; - gs_unref_variant GVariant *reply = NULL; - gs_free_error GError *error = NULL; + NMVpnConnection *self; + gs_unref_variant GVariant *reply = NULL; + gs_free_error GError *error = NULL; - reply = g_dbus_proxy_call_finish (proxy, result, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; + reply = g_dbus_proxy_call_finish(proxy, result, &error); + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; - self = NM_VPN_CONNECTION (user_data); + self = NM_VPN_CONNECTION(user_data); - if (error) { - g_dbus_error_strip_remote_error (error); - _LOGE ("sending new secrets to the plugin failed: %s", - error->message); - _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); - } else - _set_vpn_state (self, STATE_CONNECT, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); + if (error) { + g_dbus_error_strip_remote_error(error); + _LOGE("sending new secrets to the plugin failed: %s", error->message); + _set_vpn_state(self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); + } else + _set_vpn_state(self, STATE_CONNECT, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); } static void -get_secrets_cb (NMSettingsConnection *connection, - NMSettingsConnectionCallId *call_id, - const char *agent_username, - const char *setting_name, - GError *error, - gpointer user_data) -{ - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv; - GVariant *dict; - - g_return_if_fail (NM_IS_VPN_CONNECTION (self)); - - priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - - g_return_if_fail (connection && connection == _get_settings_connection (self, FALSE)); - g_return_if_fail (call_id == priv->secrets_id); - - priv->secrets_id = NULL; - - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - if (error && priv->secrets_idx >= SECRETS_REQ_NEW) { - _LOGE ("Failed to request VPN secrets #%d: %s", - priv->secrets_idx + 1, error->message); - _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); - return; - } - - /* Cache the username for later */ - if (agent_username) { - g_free (priv->username); - priv->username = g_strdup (agent_username); - } - - dict = _hash_with_username (_get_applied_connection (self), priv->username); - - if (priv->secrets_idx == SECRETS_REQ_INTERACTIVE) { - _LOGD ("sending secrets to the plugin"); - - /* Send the secrets back to the plugin */ - g_dbus_proxy_call (priv->proxy, - "NewSecrets", - g_variant_new ("(@a{sa{sv}})", dict), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->cancellable, - (GAsyncReadyCallback) plugin_new_secrets_cb, - self); - } else { - _LOGD ("asking service if additional secrets are required"); - - /* Ask the VPN service if more secrets are required */ - g_dbus_proxy_call (priv->proxy, - "NeedSecrets", - g_variant_new ("(@a{sa{sv}})", dict), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->cancellable, - (GAsyncReadyCallback) plugin_need_secrets_cb, - self); - } +get_secrets_cb(NMSettingsConnection * connection, + NMSettingsConnectionCallId *call_id, + const char * agent_username, + const char * setting_name, + GError * error, + gpointer user_data) +{ + NMVpnConnection * self = NM_VPN_CONNECTION(user_data); + NMVpnConnectionPrivate *priv; + GVariant * dict; + + g_return_if_fail(NM_IS_VPN_CONNECTION(self)); + + priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + + g_return_if_fail(connection && connection == _get_settings_connection(self, FALSE)); + g_return_if_fail(call_id == priv->secrets_id); + + priv->secrets_id = NULL; + + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + if (error && priv->secrets_idx >= SECRETS_REQ_NEW) { + _LOGE("Failed to request VPN secrets #%d: %s", priv->secrets_idx + 1, error->message); + _set_vpn_state(self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); + return; + } + + /* Cache the username for later */ + if (agent_username) { + g_free(priv->username); + priv->username = g_strdup(agent_username); + } + + dict = _hash_with_username(_get_applied_connection(self), priv->username); + + if (priv->secrets_idx == SECRETS_REQ_INTERACTIVE) { + _LOGD("sending secrets to the plugin"); + + /* Send the secrets back to the plugin */ + g_dbus_proxy_call(priv->proxy, + "NewSecrets", + g_variant_new("(@a{sa{sv}})", dict), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + (GAsyncReadyCallback) plugin_new_secrets_cb, + self); + } else { + _LOGD("asking service if additional secrets are required"); + + /* Ask the VPN service if more secrets are required */ + g_dbus_proxy_call(priv->proxy, + "NeedSecrets", + g_variant_new("(@a{sa{sv}})", dict), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + (GAsyncReadyCallback) plugin_need_secrets_cb, + self); + } } static void -get_secrets (NMVpnConnection *self, - SecretsReq secrets_idx, - const char *const*hints) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE; - - g_return_if_fail (secrets_idx < SECRETS_REQ_LAST); - priv->secrets_idx = secrets_idx; - - cancel_get_secrets (self); - - _LOGD ("requesting VPN secrets pass #%d", - priv->secrets_idx + 1); - - switch (priv->secrets_idx) { - case SECRETS_REQ_SYSTEM: - flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM; - break; - case SECRETS_REQ_EXISTING: - flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE; - break; - case SECRETS_REQ_NEW: - case SECRETS_REQ_INTERACTIVE: - flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; - break; - default: - g_assert_not_reached (); - } - - if (nm_active_connection_get_user_requested (NM_ACTIVE_CONNECTION (self))) - flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED; - - priv->secrets_id = nm_settings_connection_get_secrets (_get_settings_connection (self, FALSE), - _get_applied_connection (self), - nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (self)), - NM_SETTING_VPN_SETTING_NAME, - flags, - hints, - get_secrets_cb, - self); - g_return_if_fail (priv->secrets_id); +get_secrets(NMVpnConnection *self, SecretsReq secrets_idx, const char *const *hints) +{ + NMVpnConnectionPrivate * priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE; + + g_return_if_fail(secrets_idx < SECRETS_REQ_LAST); + priv->secrets_idx = secrets_idx; + + cancel_get_secrets(self); + + _LOGD("requesting VPN secrets pass #%d", priv->secrets_idx + 1); + + switch (priv->secrets_idx) { + case SECRETS_REQ_SYSTEM: + flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM; + break; + case SECRETS_REQ_EXISTING: + flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE; + break; + case SECRETS_REQ_NEW: + case SECRETS_REQ_INTERACTIVE: + flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; + break; + default: + g_assert_not_reached(); + } + + if (nm_active_connection_get_user_requested(NM_ACTIVE_CONNECTION(self))) + flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED; + + priv->secrets_id = nm_settings_connection_get_secrets( + _get_settings_connection(self, FALSE), + _get_applied_connection(self), + nm_active_connection_get_subject(NM_ACTIVE_CONNECTION(self)), + NM_SETTING_VPN_SETTING_NAME, + flags, + hints, + get_secrets_cb, + self); + g_return_if_fail(priv->secrets_id); } static void -plugin_interactive_secrets_required (NMVpnConnection *self, - const char *message, - const char *const*secrets) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - const gsize secrets_len = NM_PTRARRAY_LEN (secrets); - gsize i; - gs_free const char **hints = NULL; - gs_free char *message_hint = NULL; - - if (!NM_IN_SET (priv->vpn_state, STATE_CONNECT, - STATE_NEED_AUTH)) { - _LOGD ("VPN plugin: requested secrets; state %s (%d); ignore request in current state", - vpn_state_to_string_a (priv->vpn_state), priv->vpn_state); - return; - } - - _LOGI ("VPN plugin: requested secrets; state %s (%d)", - vpn_state_to_string_a (priv->vpn_state), priv->vpn_state); - - priv->secrets_idx = SECRETS_REQ_INTERACTIVE; - _set_vpn_state (self, STATE_NEED_AUTH, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); - - /* Copy hints and add message to the end */ - hints = g_new (const char *, secrets_len + 2); - for (i = 0; i < secrets_len; i++) - hints[i] = secrets[i]; - if (message) { - message_hint = g_strdup_printf ("x-vpn-message:%s", message); - hints[i++] = message_hint; - } - hints[i] = NULL; - nm_assert (i < secrets_len + 2); - - get_secrets (self, SECRETS_REQ_INTERACTIVE, hints); +plugin_interactive_secrets_required(NMVpnConnection * self, + const char * message, + const char *const *secrets) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + const gsize secrets_len = NM_PTRARRAY_LEN(secrets); + gsize i; + gs_free const char ** hints = NULL; + gs_free char * message_hint = NULL; + + if (!NM_IN_SET(priv->vpn_state, STATE_CONNECT, STATE_NEED_AUTH)) { + _LOGD("VPN plugin: requested secrets; state %s (%d); ignore request in current state", + vpn_state_to_string_a(priv->vpn_state), + priv->vpn_state); + return; + } + + _LOGI("VPN plugin: requested secrets; state %s (%d)", + vpn_state_to_string_a(priv->vpn_state), + priv->vpn_state); + + priv->secrets_idx = SECRETS_REQ_INTERACTIVE; + _set_vpn_state(self, STATE_NEED_AUTH, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); + + /* Copy hints and add message to the end */ + hints = g_new(const char *, secrets_len + 2); + for (i = 0; i < secrets_len; i++) + hints[i] = secrets[i]; + if (message) { + message_hint = g_strdup_printf("x-vpn-message:%s", message); + hints[i++] = message_hint; + } + hints[i] = NULL; + nm_assert(i < secrets_len + 2); + + get_secrets(self, SECRETS_REQ_INTERACTIVE, hints); } /*****************************************************************************/ static void -device_changed (NMActiveConnection *active, - NMDevice *new_device, - NMDevice *old_device) +device_changed(NMActiveConnection *active, NMDevice *new_device, NMDevice *old_device) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (active); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(active); - if (!_service_and_connection_can_persist (NM_VPN_CONNECTION (active))) - return; - if (priv->vpn_state < STATE_CONNECT || priv->vpn_state > STATE_ACTIVATED) - return; + if (!_service_and_connection_can_persist(NM_VPN_CONNECTION(active))) + return; + if (priv->vpn_state < STATE_CONNECT || priv->vpn_state > STATE_ACTIVATED) + return; - /* Route-based VPNs must update their routing and send a new IP config - * since all their routes need to be adjusted for new_device. - */ - if (priv->ip_ifindex <= 0) - return; + /* Route-based VPNs must update their routing and send a new IP config + * since all their routes need to be adjusted for new_device. + */ + if (priv->ip_ifindex <= 0) + return; - /* Device changed underneath the VPN connection. Let the plugin figure - * out that connectivity is down and start its reconnect attempt if it - * needs to. - */ - if (old_device) - remove_parent_device_config (NM_VPN_CONNECTION (active), old_device); + /* Device changed underneath the VPN connection. Let the plugin figure + * out that connectivity is down and start its reconnect attempt if it + * needs to. + */ + if (old_device) + remove_parent_device_config(NM_VPN_CONNECTION(active), old_device); - if (new_device) - apply_parent_device_config (NM_VPN_CONNECTION (active)); + if (new_device) + apply_parent_device_config(NM_VPN_CONNECTION(active)); } /*****************************************************************************/ static void -nm_vpn_connection_init (NMVpnConnection *self) +nm_vpn_connection_init(NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - priv->vpn_state = STATE_WAITING; - priv->secrets_idx = SECRETS_REQ_SYSTEM; - priv->netns = g_object_ref (nm_netns_get ()); + priv->vpn_state = STATE_WAITING; + priv->secrets_idx = SECRETS_REQ_SYSTEM; + priv->netns = g_object_ref(nm_netns_get()); } static void -dispose (GObject *object) +dispose(GObject *object) { - NMVpnConnection *self = NM_VPN_CONNECTION (object); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMVpnConnection * self = NM_VPN_CONNECTION(object); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - if (priv->proxy) - g_signal_handlers_disconnect_by_data (priv->proxy, self); + if (priv->proxy) + g_signal_handlers_disconnect_by_data(priv->proxy, self); - nm_clear_g_source (&priv->start_timeout); + nm_clear_g_source(&priv->start_timeout); - nm_clear_pointer (&priv->connect_hash, g_variant_unref); + nm_clear_pointer(&priv->connect_hash, g_variant_unref); - nm_clear_pointer (&priv->ip4_dev_route_blacklist, g_ptr_array_unref); + nm_clear_pointer(&priv->ip4_dev_route_blacklist, g_ptr_array_unref); - nm_clear_g_source (&priv->connect_timeout); + nm_clear_g_source(&priv->connect_timeout); - dispatcher_cleanup (self); + dispatcher_cleanup(self); - cancel_get_secrets (self); + cancel_get_secrets(self); - nm_clear_g_cancellable (&priv->cancellable); + nm_clear_g_cancellable(&priv->cancellable); - g_clear_object (&priv->proxy_config); - nm_dbus_object_clear_and_unexport (&priv->ip4_config); - nm_dbus_object_clear_and_unexport (&priv->ip6_config); - g_clear_object (&priv->proxy); - g_clear_object (&priv->plugin_info); + g_clear_object(&priv->proxy_config); + nm_dbus_object_clear_and_unexport(&priv->ip4_config); + nm_dbus_object_clear_and_unexport(&priv->ip6_config); + g_clear_object(&priv->proxy); + g_clear_object(&priv->plugin_info); - fw_call_cleanup (self); + fw_call_cleanup(self); - nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id); + nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); - G_OBJECT_CLASS (nm_vpn_connection_parent_class)->dispose (object); + G_OBJECT_CLASS(nm_vpn_connection_parent_class)->dispose(object); } static void -finalize (GObject *object) +finalize(GObject *object) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(object); - g_free (priv->banner); - g_free (priv->ip_iface); - g_free (priv->username); - g_free (priv->ip6_internal_gw); - g_free (priv->ip6_external_gw); + g_free(priv->banner); + g_free(priv->ip_iface); + g_free(priv->username); + g_free(priv->ip6_internal_gw); + g_free(priv->ip6_external_gw); - G_OBJECT_CLASS (nm_vpn_connection_parent_class)->finalize (object); + G_OBJECT_CLASS(nm_vpn_connection_parent_class)->finalize(object); - g_clear_object (&priv->netns); + g_clear_object(&priv->netns); } static gboolean -ip_config_valid (VpnState state) +ip_config_valid(VpnState state) { - return (state == STATE_PRE_UP || state == STATE_ACTIVATED); + return (state == STATE_PRE_UP || state == STATE_ACTIVATED); } static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object); - NMDevice *parent_dev; - - switch (prop_id) { - case PROP_VPN_STATE: - g_value_set_uint (value, _state_to_nm_vpn_state (priv->vpn_state)); - break; - case PROP_BANNER: - g_value_set_string (value, priv->banner ?: ""); - break; - case PROP_IP4_CONFIG: - nm_dbus_utils_g_value_set_object_path (value, ip_config_valid (priv->vpn_state) ? priv->ip4_config : NULL); - break; - case PROP_IP6_CONFIG: - nm_dbus_utils_g_value_set_object_path (value, ip_config_valid (priv->vpn_state) ? priv->ip6_config : NULL); - break; - case PROP_MASTER: - parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object)); - nm_dbus_utils_g_value_set_object_path (value, parent_dev); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static const GDBusSignalInfo signal_info_vpn_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "VpnStateChanged", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("state", "u"), - NM_DEFINE_GDBUS_ARG_INFO ("reason", "u"), - ), -); +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(object); + NMDevice * parent_dev; + + switch (prop_id) { + case PROP_VPN_STATE: + g_value_set_uint(value, _state_to_nm_vpn_state(priv->vpn_state)); + break; + case PROP_BANNER: + g_value_set_string(value, priv->banner ?: ""); + break; + case PROP_IP4_CONFIG: + nm_dbus_utils_g_value_set_object_path(value, + ip_config_valid(priv->vpn_state) ? priv->ip4_config + : NULL); + break; + case PROP_IP6_CONFIG: + nm_dbus_utils_g_value_set_object_path(value, + ip_config_valid(priv->vpn_state) ? priv->ip6_config + : NULL); + break; + case PROP_MASTER: + parent_dev = nm_active_connection_get_device(NM_ACTIVE_CONNECTION(object)); + nm_dbus_utils_g_value_set_object_path(value, parent_dev); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static const GDBusSignalInfo signal_info_vpn_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT( + "VpnStateChanged", + .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("state", "u"), + NM_DEFINE_GDBUS_ARG_INFO("reason", "u"), ), ); static const NMDBusInterfaceInfoExtended interface_info_vpn_connection = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_VPN_CONNECTION, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - &signal_info_vpn_state_changed, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("VpnState", "u", NM_VPN_CONNECTION_VPN_STATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Banner", "s", NM_VPN_CONNECTION_BANNER), - ), - ), - .legacy_property_changed = TRUE, + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + NM_DBUS_INTERFACE_VPN_CONNECTION, + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, + &signal_info_vpn_state_changed, ), + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("VpnState", + "u", + NM_VPN_CONNECTION_VPN_STATE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Banner", + "s", + NM_VPN_CONNECTION_BANNER), ), ), + .legacy_property_changed = TRUE, }; static void -nm_vpn_connection_class_init (NMVpnConnectionClass *connection_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (connection_class); - NMActiveConnectionClass *active_class = NM_ACTIVE_CONNECTION_CLASS (connection_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (connection_class); - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_vpn_connection); - - object_class->get_property = get_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - active_class->device_state_changed = device_state_changed; - active_class->device_changed = device_changed; - - obj_properties[PROP_VPN_STATE] = - g_param_spec_uint (NM_VPN_CONNECTION_VPN_STATE, "", "", - NM_VPN_CONNECTION_STATE_UNKNOWN, - NM_VPN_CONNECTION_STATE_DISCONNECTED, - NM_VPN_CONNECTION_STATE_UNKNOWN, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_BANNER] = - g_param_spec_string (NM_VPN_CONNECTION_BANNER, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - g_object_class_override_property (object_class, PROP_MASTER, - NM_ACTIVE_CONNECTION_MASTER); - g_object_class_override_property (object_class, PROP_IP4_CONFIG, - NM_ACTIVE_CONNECTION_IP4_CONFIG); - g_object_class_override_property (object_class, PROP_IP6_CONFIG, - NM_ACTIVE_CONNECTION_IP6_CONFIG); - - signals[INTERNAL_STATE_CHANGED] = - g_signal_new (NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT); - - signals[INTERNAL_RETRY_AFTER_FAILURE] = - g_signal_new (NM_VPN_CONNECTION_INTERNAL_RETRY_AFTER_FAILURE, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); +nm_vpn_connection_class_init(NMVpnConnectionClass *connection_class) +{ + GObjectClass * object_class = G_OBJECT_CLASS(connection_class); + NMActiveConnectionClass *active_class = NM_ACTIVE_CONNECTION_CLASS(connection_class); + NMDBusObjectClass * dbus_object_class = NM_DBUS_OBJECT_CLASS(connection_class); + + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_vpn_connection); + + object_class->get_property = get_property; + object_class->dispose = dispose; + object_class->finalize = finalize; + + active_class->device_state_changed = device_state_changed; + active_class->device_changed = device_changed; + + obj_properties[PROP_VPN_STATE] = g_param_spec_uint(NM_VPN_CONNECTION_VPN_STATE, + "", + "", + NM_VPN_CONNECTION_STATE_UNKNOWN, + NM_VPN_CONNECTION_STATE_DISCONNECTED, + NM_VPN_CONNECTION_STATE_UNKNOWN, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_BANNER] = g_param_spec_string(NM_VPN_CONNECTION_BANNER, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + g_object_class_override_property(object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER); + g_object_class_override_property(object_class, + PROP_IP4_CONFIG, + NM_ACTIVE_CONNECTION_IP4_CONFIG); + g_object_class_override_property(object_class, + PROP_IP6_CONFIG, + NM_ACTIVE_CONNECTION_IP6_CONFIG); + + signals[INTERNAL_STATE_CHANGED] = g_signal_new(NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 3, + G_TYPE_UINT, + G_TYPE_UINT, + G_TYPE_UINT); + + signals[INTERNAL_RETRY_AFTER_FAILURE] = + g_signal_new(NM_VPN_CONNECTION_INTERNAL_RETRY_AFTER_FAILURE, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); } diff --git a/src/vpn/nm-vpn-connection.h b/src/vpn/nm-vpn-connection.h index b2d3e370..9cf80a1e 100644 --- a/src/vpn/nm-vpn-connection.h +++ b/src/vpn/nm-vpn-connection.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2005 - 2011 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. @@ -13,16 +13,19 @@ #include "nm-active-connection.h" #include "nm-vpn-plugin-info.h" -#define NM_TYPE_VPN_CONNECTION (nm_vpn_connection_get_type ()) -#define NM_VPN_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_CONNECTION, NMVpnConnection)) -#define NM_VPN_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_VPN_CONNECTION, NMVpnConnectionClass)) -#define NM_IS_VPN_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_VPN_CONNECTION)) -#define NM_IS_VPN_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_VPN_CONNECTION)) -#define NM_VPN_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_CONNECTION, NMVpnConnectionClass)) +#define NM_TYPE_VPN_CONNECTION (nm_vpn_connection_get_type()) +#define NM_VPN_CONNECTION(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VPN_CONNECTION, NMVpnConnection)) +#define NM_VPN_CONNECTION_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_VPN_CONNECTION, NMVpnConnectionClass)) +#define NM_IS_VPN_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_VPN_CONNECTION)) +#define NM_IS_VPN_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_VPN_CONNECTION)) +#define NM_VPN_CONNECTION_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_VPN_CONNECTION, NMVpnConnectionClass)) /* Properties */ #define NM_VPN_CONNECTION_VPN_STATE "vpn-state" -#define NM_VPN_CONNECTION_BANNER "banner" +#define NM_VPN_CONNECTION_BANNER "banner" /* Signals */ #define NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED "internal-state-changed" @@ -30,38 +33,37 @@ typedef struct _NMVpnConnectionClass NMVpnConnectionClass; -GType nm_vpn_connection_get_type (void); +GType nm_vpn_connection_get_type(void); -NMVpnConnection * nm_vpn_connection_new (NMSettingsConnection *settings_connection, - NMDevice *parent_device, - const char *specific_object, - NMActivationReason activation_reason, - NMActivationStateFlags initial_state_flags, - NMAuthSubject *subject); +NMVpnConnection *nm_vpn_connection_new(NMSettingsConnection * settings_connection, + NMDevice * parent_device, + const char * specific_object, + NMActivationReason activation_reason, + NMActivationStateFlags initial_state_flags, + NMAuthSubject * subject); -void nm_vpn_connection_activate (NMVpnConnection *self, - NMVpnPluginInfo *plugin_info); -NMVpnConnectionState nm_vpn_connection_get_vpn_state (NMVpnConnection *self); -const char * nm_vpn_connection_get_banner (NMVpnConnection *self); -const char * nm_vpn_connection_get_service (NMVpnConnection *self); +void nm_vpn_connection_activate(NMVpnConnection *self, NMVpnPluginInfo *plugin_info); +NMVpnConnectionState nm_vpn_connection_get_vpn_state(NMVpnConnection *self); +const char * nm_vpn_connection_get_banner(NMVpnConnection *self); +const char * nm_vpn_connection_get_service(NMVpnConnection *self); -gboolean nm_vpn_connection_deactivate (NMVpnConnection *self, - NMActiveConnectionStateReason reason, - gboolean quitting); -void nm_vpn_connection_disconnect (NMVpnConnection *self, - NMActiveConnectionStateReason reason, - gboolean quitting); +gboolean nm_vpn_connection_deactivate(NMVpnConnection * self, + NMActiveConnectionStateReason reason, + gboolean quitting); +void nm_vpn_connection_disconnect(NMVpnConnection * self, + NMActiveConnectionStateReason reason, + gboolean quitting); -NMProxyConfig * nm_vpn_connection_get_proxy_config (NMVpnConnection *self); +NMProxyConfig *nm_vpn_connection_get_proxy_config(NMVpnConnection *self); -NMIP4Config * nm_vpn_connection_get_ip4_config (NMVpnConnection *self); -NMIP6Config * nm_vpn_connection_get_ip6_config (NMVpnConnection *self); -const char * nm_vpn_connection_get_ip_iface (NMVpnConnection *self, gboolean fallback_device); -int nm_vpn_connection_get_ip_ifindex (NMVpnConnection *self, gboolean fallback_device); -guint32 nm_vpn_connection_get_ip4_internal_gateway (NMVpnConnection *self); -struct in6_addr * nm_vpn_connection_get_ip6_internal_gateway (NMVpnConnection *self); +NMIP4Config * nm_vpn_connection_get_ip4_config(NMVpnConnection *self); +NMIP6Config * nm_vpn_connection_get_ip6_config(NMVpnConnection *self); +const char * nm_vpn_connection_get_ip_iface(NMVpnConnection *self, gboolean fallback_device); +int nm_vpn_connection_get_ip_ifindex(NMVpnConnection *self, gboolean fallback_device); +guint32 nm_vpn_connection_get_ip4_internal_gateway(NMVpnConnection *self); +struct in6_addr *nm_vpn_connection_get_ip6_internal_gateway(NMVpnConnection *self); -guint32 nm_vpn_connection_get_ip4_route_metric (NMVpnConnection *self); -guint32 nm_vpn_connection_get_ip6_route_metric (NMVpnConnection *self); +guint32 nm_vpn_connection_get_ip4_route_metric(NMVpnConnection *self); +guint32 nm_vpn_connection_get_ip6_route_metric(NMVpnConnection *self); #endif /* __NM_VPN_CONNECTION_H__ */ diff --git a/src/vpn/nm-vpn-manager.c b/src/vpn/nm-vpn-manager.c index a80ab71e..607ad7f3 100644 --- a/src/vpn/nm-vpn-manager.c +++ b/src/vpn/nm-vpn-manager.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2005 - 2012 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. @@ -15,264 +15,268 @@ #include "nm-core-internal.h" typedef struct { - GSList *plugins; - GFileMonitor *monitor_etc; - GFileMonitor *monitor_lib; - gulong monitor_id_etc; - gulong monitor_id_lib; - - /* This is only used for services that don't support multiple - * connections, to guard access to them. */ - GHashTable *active_services; + GSList * plugins; + GFileMonitor *monitor_etc; + GFileMonitor *monitor_lib; + gulong monitor_id_etc; + gulong monitor_id_lib; + + /* This is only used for services that don't support multiple + * connections, to guard access to them. */ + GHashTable *active_services; } NMVpnManagerPrivate; struct _NMVpnManager { - GObject parent; - NMVpnManagerPrivate _priv; + GObject parent; + NMVpnManagerPrivate _priv; }; struct _NMVpnManagerClass { - GObjectClass parent; + GObjectClass parent; }; -G_DEFINE_TYPE (NMVpnManager, nm_vpn_manager, G_TYPE_OBJECT) +G_DEFINE_TYPE(NMVpnManager, nm_vpn_manager, G_TYPE_OBJECT) -#define NM_VPN_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMVpnManager, NM_IS_VPN_MANAGER) +#define NM_VPN_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMVpnManager, NM_IS_VPN_MANAGER) /*****************************************************************************/ static void -vpn_state_changed (NMVpnConnection *vpn, - GParamSpec *pspec, - NMVpnManager *manager) +vpn_state_changed(NMVpnConnection *vpn, GParamSpec *pspec, NMVpnManager *manager) { - NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (manager); - NMActiveConnectionState state = nm_active_connection_get_state (NM_ACTIVE_CONNECTION (vpn)); - const char *service_name = nm_vpn_connection_get_service (vpn); - - if (state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) { - g_hash_table_remove (priv->active_services, service_name); - g_signal_handlers_disconnect_by_func (vpn, vpn_state_changed, manager); - g_object_unref (manager); - } + NMVpnManagerPrivate * priv = NM_VPN_MANAGER_GET_PRIVATE(manager); + NMActiveConnectionState state = nm_active_connection_get_state(NM_ACTIVE_CONNECTION(vpn)); + const char * service_name = nm_vpn_connection_get_service(vpn); + + if (state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) { + g_hash_table_remove(priv->active_services, service_name); + g_signal_handlers_disconnect_by_func(vpn, vpn_state_changed, manager); + g_object_unref(manager); + } } gboolean -nm_vpn_manager_activate_connection (NMVpnManager *manager, - NMVpnConnection *vpn, - GError **error) +nm_vpn_manager_activate_connection(NMVpnManager *manager, NMVpnConnection *vpn, GError **error) { - NMVpnManagerPrivate *priv; - NMVpnPluginInfo *plugin_info; - const char *service_name; - NMDevice *device; - - g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), FALSE); - g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - priv = NM_VPN_MANAGER_GET_PRIVATE (manager); - device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); - g_assert (device); - if ( nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED - && nm_device_get_state (device) != NM_DEVICE_STATE_SECONDARIES) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, - "The base device for the VPN connection was not active."); - return FALSE; - } - - service_name = nm_vpn_connection_get_service (vpn); - - plugin_info = nm_vpn_plugin_info_list_find_by_service (priv->plugins, service_name); - if (!plugin_info) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE, - "The VPN service '%s' was not installed.", - service_name); - return FALSE; - } - - if ( !nm_vpn_plugin_info_supports_multiple (plugin_info) - && g_hash_table_contains (priv->active_services, service_name)) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE, - "The '%s' plugin only supports a single active connection.", - nm_vpn_plugin_info_get_name (plugin_info)); - return FALSE; - } - - nm_vpn_connection_activate (vpn, plugin_info); - - if (!nm_vpn_plugin_info_supports_multiple (plugin_info)) { - /* Block activations of the connections of the same service type. */ - g_hash_table_add (priv->active_services, g_strdup (service_name)); - g_signal_connect (vpn, "notify::" NM_ACTIVE_CONNECTION_STATE, - G_CALLBACK (vpn_state_changed), - g_object_ref (manager)); - } - - return TRUE; + NMVpnManagerPrivate *priv; + NMVpnPluginInfo * plugin_info; + const char * service_name; + NMDevice * device; + + g_return_val_if_fail(NM_IS_VPN_MANAGER(manager), FALSE); + g_return_val_if_fail(NM_IS_VPN_CONNECTION(vpn), FALSE); + g_return_val_if_fail(!error || !*error, FALSE); + + priv = NM_VPN_MANAGER_GET_PRIVATE(manager); + device = nm_active_connection_get_device(NM_ACTIVE_CONNECTION(vpn)); + g_assert(device); + if (nm_device_get_state(device) != NM_DEVICE_STATE_ACTIVATED + && nm_device_get_state(device) != NM_DEVICE_STATE_SECONDARIES) { + g_set_error_literal(error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_DEPENDENCY_FAILED, + "The base device for the VPN connection was not active."); + return FALSE; + } + + service_name = nm_vpn_connection_get_service(vpn); + + plugin_info = nm_vpn_plugin_info_list_find_by_service(priv->plugins, service_name); + if (!plugin_info) { + g_set_error(error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE, + "The VPN service '%s' was not installed.", + service_name); + return FALSE; + } + + if (!nm_vpn_plugin_info_supports_multiple(plugin_info) + && g_hash_table_contains(priv->active_services, service_name)) { + g_set_error(error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE, + "The '%s' plugin only supports a single active connection.", + nm_vpn_plugin_info_get_name(plugin_info)); + return FALSE; + } + + nm_vpn_connection_activate(vpn, plugin_info); + + if (!nm_vpn_plugin_info_supports_multiple(plugin_info)) { + /* Block activations of the connections of the same service type. */ + g_hash_table_add(priv->active_services, g_strdup(service_name)); + g_signal_connect(vpn, + "notify::" NM_ACTIVE_CONNECTION_STATE, + G_CALLBACK(vpn_state_changed), + g_object_ref(manager)); + } + + return TRUE; } /*****************************************************************************/ static void -try_add_plugin (NMVpnManager *self, NMVpnPluginInfo *plugin_info) +try_add_plugin(NMVpnManager *self, NMVpnPluginInfo *plugin_info) { - NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); - const char *program; - - program = nm_vpn_plugin_info_get_program (plugin_info); - if (!program || !*program) - return; - - /* Make sure we don't add dupes. - * We don't really allow reload of the same file. What we do allow is however to - * delete a file and re-add it. */ - if (nm_vpn_plugin_info_list_find_by_filename (priv->plugins, - nm_vpn_plugin_info_get_filename (plugin_info))) - return; - if (!nm_vpn_plugin_info_list_add (&priv->plugins, plugin_info, NULL)) - return; + NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE(self); + const char * program; + + program = nm_vpn_plugin_info_get_program(plugin_info); + if (!program || !*program) + return; + + /* Make sure we don't add dupes. + * We don't really allow reload of the same file. What we do allow is however to + * delete a file and re-add it. */ + if (nm_vpn_plugin_info_list_find_by_filename(priv->plugins, + nm_vpn_plugin_info_get_filename(plugin_info))) + return; + if (!nm_vpn_plugin_info_list_add(&priv->plugins, plugin_info, NULL)) + return; } static void -vpn_dir_changed (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) +vpn_dir_changed(GFileMonitor * monitor, + GFile * file, + GFile * other_file, + GFileMonitorEvent event_type, + gpointer user_data) { - NMVpnManager *self = NM_VPN_MANAGER (user_data); - NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); - NMVpnPluginInfo *plugin_info; - gs_free char *path = NULL; - GError *error = NULL; - - path = g_file_get_path (file); - if (!nm_vpn_plugin_info_validate_filename (path)) - return; - - switch (event_type) { - case G_FILE_MONITOR_EVENT_DELETED: - plugin_info = nm_vpn_plugin_info_list_find_by_filename (priv->plugins, path); - if (!plugin_info) - break; - - nm_log_dbg (LOGD_VPN, "vpn: service file %s deleted", path); - nm_vpn_plugin_info_list_remove (&priv->plugins, plugin_info); - break; - case G_FILE_MONITOR_EVENT_CREATED: - case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - plugin_info = nm_vpn_plugin_info_list_find_by_filename (priv->plugins, path); - if (plugin_info) { - /* we don't support reloading an existing plugin. You can only remove the file - * and re-add it. By reloading we want to support the use case of installing - * a VPN plugin after NM started. No need to burden ourself with a complete - * reload. */ - break; - } - - if (!_nm_vpn_plugin_info_check_file (path, TRUE, TRUE, 0, - NULL, NULL, &error)) { - nm_log_dbg (LOGD_VPN, "vpn: ignore changed service file %s (%s)", path, error->message); - g_clear_error (&error); - break; - } - plugin_info = nm_vpn_plugin_info_new_from_file (path, &error); - if (!plugin_info) { - nm_log_dbg (LOGD_VPN, "vpn: ignore changed service file %s due to invalid content (%s)", path, error->message); - g_clear_error (&error); - break; - } - - nm_log_dbg (LOGD_VPN, "vpn: service file %s created or modified", path); - try_add_plugin (self, plugin_info); - g_object_unref (plugin_info); - break; - default: - nm_log_dbg (LOGD_VPN, "vpn: service file %s change event %d", path, event_type); - break; - } + NMVpnManager * self = NM_VPN_MANAGER(user_data); + NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE(self); + NMVpnPluginInfo * plugin_info; + gs_free char * path = NULL; + GError * error = NULL; + + path = g_file_get_path(file); + if (!nm_vpn_plugin_info_validate_filename(path)) + return; + + switch (event_type) { + case G_FILE_MONITOR_EVENT_DELETED: + plugin_info = nm_vpn_plugin_info_list_find_by_filename(priv->plugins, path); + if (!plugin_info) + break; + + nm_log_dbg(LOGD_VPN, "vpn: service file %s deleted", path); + nm_vpn_plugin_info_list_remove(&priv->plugins, plugin_info); + break; + case G_FILE_MONITOR_EVENT_CREATED: + case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: + plugin_info = nm_vpn_plugin_info_list_find_by_filename(priv->plugins, path); + if (plugin_info) { + /* we don't support reloading an existing plugin. You can only remove the file + * and re-add it. By reloading we want to support the use case of installing + * a VPN plugin after NM started. No need to burden ourself with a complete + * reload. */ + break; + } + + if (!_nm_vpn_plugin_info_check_file(path, TRUE, TRUE, 0, NULL, NULL, &error)) { + nm_log_dbg(LOGD_VPN, "vpn: ignore changed service file %s (%s)", path, error->message); + g_clear_error(&error); + break; + } + plugin_info = nm_vpn_plugin_info_new_from_file(path, &error); + if (!plugin_info) { + nm_log_dbg(LOGD_VPN, + "vpn: ignore changed service file %s due to invalid content (%s)", + path, + error->message); + g_clear_error(&error); + break; + } + + nm_log_dbg(LOGD_VPN, "vpn: service file %s created or modified", path); + try_add_plugin(self, plugin_info); + g_object_unref(plugin_info); + break; + default: + nm_log_dbg(LOGD_VPN, "vpn: service file %s change event %d", path, event_type); + break; + } } /*****************************************************************************/ -NM_DEFINE_SINGLETON_GETTER (NMVpnManager, nm_vpn_manager_get, NM_TYPE_VPN_MANAGER); +NM_DEFINE_SINGLETON_GETTER(NMVpnManager, nm_vpn_manager_get, NM_TYPE_VPN_MANAGER); static void -nm_vpn_manager_init (NMVpnManager *self) +nm_vpn_manager_init(NMVpnManager *self) { - NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); - GFile *file; - GSList *infos, *info; - const char *conf_dir_etc = _nm_vpn_plugin_info_get_default_dir_etc (); - const char *conf_dir_lib = _nm_vpn_plugin_info_get_default_dir_lib (); - - /* Watch the VPN directory for changes */ - file = g_file_new_for_path (conf_dir_lib); - priv->monitor_lib = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); - g_object_unref (file); - if (priv->monitor_lib) { - priv->monitor_id_lib = g_signal_connect (priv->monitor_lib, "changed", - G_CALLBACK (vpn_dir_changed), self); - } - - file = g_file_new_for_path (conf_dir_etc); - priv->monitor_etc = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); - g_object_unref (file); - if (priv->monitor_etc) { - priv->monitor_id_etc = g_signal_connect (priv->monitor_etc, "changed", - G_CALLBACK (vpn_dir_changed), self); - } - - /* first read conf_dir_lib. The name files are not really user configuration, but - * plugin configuration. Hence we expect ~newer~ plugins to install their files - * in /usr/lib/NetworkManager. We want to prefer those files. - * In case of no-conflict, the order doesn't matter. */ - infos = _nm_vpn_plugin_info_list_load_dir (conf_dir_lib, TRUE, 0, NULL, NULL); - for (info = infos; info; info = info->next) - try_add_plugin (self, info->data); - g_slist_free_full (infos, g_object_unref); - - infos = _nm_vpn_plugin_info_list_load_dir (conf_dir_etc, TRUE, 0, NULL, NULL); - for (info = infos; info; info = info->next) - try_add_plugin (self, info->data); - g_slist_free_full (infos, g_object_unref); - - priv->active_services = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL); + NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE(self); + GFile * file; + GSList * infos, *info; + const char * conf_dir_etc = _nm_vpn_plugin_info_get_default_dir_etc(); + const char * conf_dir_lib = _nm_vpn_plugin_info_get_default_dir_lib(); + + /* Watch the VPN directory for changes */ + file = g_file_new_for_path(conf_dir_lib); + priv->monitor_lib = g_file_monitor_directory(file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref(file); + if (priv->monitor_lib) { + priv->monitor_id_lib = + g_signal_connect(priv->monitor_lib, "changed", G_CALLBACK(vpn_dir_changed), self); + } + + file = g_file_new_for_path(conf_dir_etc); + priv->monitor_etc = g_file_monitor_directory(file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref(file); + if (priv->monitor_etc) { + priv->monitor_id_etc = + g_signal_connect(priv->monitor_etc, "changed", G_CALLBACK(vpn_dir_changed), self); + } + + /* first read conf_dir_lib. The name files are not really user configuration, but + * plugin configuration. Hence we expect ~newer~ plugins to install their files + * in /usr/lib/NetworkManager. We want to prefer those files. + * In case of no-conflict, the order doesn't matter. */ + infos = _nm_vpn_plugin_info_list_load_dir(conf_dir_lib, TRUE, 0, NULL, NULL); + for (info = infos; info; info = info->next) + try_add_plugin(self, info->data); + g_slist_free_full(infos, g_object_unref); + + infos = _nm_vpn_plugin_info_list_load_dir(conf_dir_etc, TRUE, 0, NULL, NULL); + for (info = infos; info; info = info->next) + try_add_plugin(self, info->data); + g_slist_free_full(infos, g_object_unref); + + priv->active_services = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, NULL); } static void -dispose (GObject *object) +dispose(GObject *object) { - NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (object); + NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE(object); - if (priv->monitor_etc) { - if (priv->monitor_id_etc) - g_signal_handler_disconnect (priv->monitor_etc, priv->monitor_id_etc); - g_file_monitor_cancel (priv->monitor_etc); - g_clear_object (&priv->monitor_etc); - } + if (priv->monitor_etc) { + if (priv->monitor_id_etc) + g_signal_handler_disconnect(priv->monitor_etc, priv->monitor_id_etc); + g_file_monitor_cancel(priv->monitor_etc); + g_clear_object(&priv->monitor_etc); + } - if (priv->monitor_lib) { - if (priv->monitor_id_lib) - g_signal_handler_disconnect (priv->monitor_lib, priv->monitor_id_lib); - g_file_monitor_cancel (priv->monitor_lib); - g_clear_object (&priv->monitor_lib); - } + if (priv->monitor_lib) { + if (priv->monitor_id_lib) + g_signal_handler_disconnect(priv->monitor_lib, priv->monitor_id_lib); + g_file_monitor_cancel(priv->monitor_lib); + g_clear_object(&priv->monitor_lib); + } - while (priv->plugins) - nm_vpn_plugin_info_list_remove (&priv->plugins, priv->plugins->data); + while (priv->plugins) + nm_vpn_plugin_info_list_remove(&priv->plugins, priv->plugins->data); - g_hash_table_unref (priv->active_services); + g_hash_table_unref(priv->active_services); - G_OBJECT_CLASS (nm_vpn_manager_parent_class)->dispose (object); + G_OBJECT_CLASS(nm_vpn_manager_parent_class)->dispose(object); } static void -nm_vpn_manager_class_init (NMVpnManagerClass *manager_class) +nm_vpn_manager_class_init(NMVpnManagerClass *manager_class) { - GObjectClass *object_class = G_OBJECT_CLASS (manager_class); + GObjectClass *object_class = G_OBJECT_CLASS(manager_class); - object_class->dispose = dispose; + object_class->dispose = dispose; } - diff --git a/src/vpn/nm-vpn-manager.h b/src/vpn/nm-vpn-manager.h index 6a78acd2..5f24df25 100644 --- a/src/vpn/nm-vpn-manager.h +++ b/src/vpn/nm-vpn-manager.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2005 - 2011 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. @@ -9,22 +9,23 @@ #include "nm-vpn-connection.h" -#define NM_TYPE_VPN_MANAGER (nm_vpn_manager_get_type ()) -#define NM_VPN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_MANAGER, NMVpnManager)) -#define NM_VPN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_VPN_MANAGER, NMVpnManagerClass)) -#define NM_IS_VPN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_VPN_MANAGER)) -#define NM_IS_VPN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_VPN_MANAGER)) -#define NM_VPN_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_MANAGER, NMVpnManagerClass)) +#define NM_TYPE_VPN_MANAGER (nm_vpn_manager_get_type()) +#define NM_VPN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VPN_MANAGER, NMVpnManager)) +#define NM_VPN_MANAGER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_VPN_MANAGER, NMVpnManagerClass)) +#define NM_IS_VPN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_VPN_MANAGER)) +#define NM_IS_VPN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_VPN_MANAGER)) +#define NM_VPN_MANAGER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_VPN_MANAGER, NMVpnManagerClass)) -typedef struct _NMVpnManager NMVpnManager; +typedef struct _NMVpnManager NMVpnManager; typedef struct _NMVpnManagerClass NMVpnManagerClass; -GType nm_vpn_manager_get_type (void); +GType nm_vpn_manager_get_type(void); -NMVpnManager *nm_vpn_manager_get (void); +NMVpnManager *nm_vpn_manager_get(void); -gboolean nm_vpn_manager_activate_connection (NMVpnManager *manager, - NMVpnConnection *vpn, - GError **error); +gboolean +nm_vpn_manager_activate_connection(NMVpnManager *manager, NMVpnConnection *vpn, GError **error); #endif /* __NM_VPN_MANAGER_H__ */ |