diff options
Diffstat (limited to 'src/vpn-manager')
| -rw-r--r-- | src/vpn-manager/nm-vpn-connection.c | 131 | ||||
| -rw-r--r-- | src/vpn-manager/nm-vpn-service.c | 17 |
2 files changed, 110 insertions, 38 deletions
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index cb07c7f9..795a8187 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -44,6 +44,8 @@ #include "nm-agent-manager.h" #include "nm-core-internal.h" #include "nm-default-route-manager.h" +#include "nm-route-manager.h" +#include "nm-firewall-manager.h" #include "nm-vpn-connection-glue.h" @@ -92,6 +94,9 @@ typedef struct { NMVpnServiceState service_state; + /* Firewall */ + NMFirewallPendingCall fw_call; + DBusGProxy *proxy; GHashTable *connect_hash; guint connect_timeout; @@ -227,19 +232,38 @@ call_plugin_disconnect (NMVpnConnection *self) } static void +fw_call_cleanup (NMVpnConnection *connection) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + + if (priv->fw_call) { + nm_firewall_manager_cancel_call (nm_firewall_manager_get (), priv->fw_call); + priv->fw_call = NULL; + } +} + +static void vpn_cleanup (NMVpnConnection *connection, NMDevice *parent_dev) { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); if (priv->ip_ifindex) { - nm_platform_link_set_down (priv->ip_ifindex); - nm_platform_route_flush (priv->ip_ifindex); - nm_platform_address_flush (priv->ip_ifindex); + nm_platform_link_set_down (NM_PLATFORM_GET, priv->ip_ifindex); + nm_route_manager_route_flush (nm_route_manager_get (), priv->ip_ifindex); + nm_platform_address_flush (NM_PLATFORM_GET, priv->ip_ifindex); } nm_device_set_vpn4_config (parent_dev, NULL); nm_device_set_vpn6_config (parent_dev, NULL); + /* Remove zone from firewall */ + if (priv->ip_iface) + nm_firewall_manager_remove_from_zone (nm_firewall_manager_get (), + priv->ip_iface, + NULL); + /* Cancel pending firewall call */ + fw_call_cleanup (connection); + g_free (priv->banner); priv->banner = NULL; @@ -252,6 +276,7 @@ vpn_cleanup (NMVpnConnection *connection, NMDevice *parent_dev) */ if (priv->connection) nm_connection_clear_secrets (priv->connection); + } static void @@ -903,10 +928,17 @@ apply_parent_device_config (NMVpnConnection *connection) * be done on the parent interface instead. */ - if (vpn4_parent_config) + /* Also clear the gateway. We don't configure the gateway as part of the + * vpn-config. Instead we tell NMDefaultRouteManager directly about the + * default route. */ + if (vpn4_parent_config) { nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config); - if (vpn6_parent_config) + nm_ip4_config_set_gateway (vpn4_parent_config, 0); + } + if (vpn6_parent_config) { nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config); + nm_ip6_config_set_gateway (vpn6_parent_config, NULL); + } } if (vpn4_parent_config) { @@ -933,16 +965,19 @@ nm_vpn_connection_apply_config (NMVpnConnection *connection) NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); if (priv->ip_ifindex > 0) { - nm_platform_link_set_up (priv->ip_ifindex); + nm_platform_link_set_up (NM_PLATFORM_GET, priv->ip_ifindex, NULL); if (priv->ip4_config) { if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex, + TRUE, nm_vpn_connection_get_ip4_route_metric (connection))) return FALSE; } if (priv->ip6_config) { - if (!nm_ip6_config_commit (priv->ip6_config, priv->ip_ifindex)) + if (!nm_ip6_config_commit (priv->ip6_config, + priv->ip_ifindex, + TRUE)) return FALSE; } } @@ -959,10 +994,47 @@ nm_vpn_connection_apply_config (NMVpnConnection *connection) } static void +_cleanup_failed_config (NMVpnConnection *connection) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + + g_clear_object (&priv->ip4_config); + g_clear_object (&priv->ip6_config); + + nm_log_warn (LOGD_VPN, "VPN connection '%s' did not receive valid IP config information.", + nm_connection_get_id (priv->connection)); + _set_vpn_state (connection, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, FALSE); +} + +static void +fw_change_zone_cb (GError *error, gpointer user_data) +{ + NMVpnConnection *connection = NM_VPN_CONNECTION (user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + priv->fw_call = NULL; + + if (error) { + nm_log_warn (LOGD_VPN, "VPN connection '%s': setting firewall zone failed: '%s'", + nm_connection_get_id (priv->connection), error->message); + // FIXME: fail the activation? + } + + if (!nm_vpn_connection_apply_config (connection)) + _cleanup_failed_config (connection); +} + +static void nm_vpn_connection_config_maybe_complete (NMVpnConnection *connection, gboolean success) { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMConnection *base_con; + NMSettingConnection *s_con; + const char *zone; if (priv->vpn_state < STATE_IP_CONFIG_GET || priv->vpn_state > STATE_ACTIVATED) return; @@ -983,16 +1055,29 @@ nm_vpn_connection_config_maybe_complete (NMVpnConnection *connection, if (success) { print_vpn_config (connection); - if (nm_vpn_connection_apply_config (connection)) + /* Add the tunnel interface to the specified firewall zone */ + if (priv->ip_iface) { + base_con = nm_vpn_connection_get_connection (connection); + g_assert (base_con); + s_con = nm_connection_get_setting_connection (base_con); + zone = nm_setting_connection_get_zone (s_con); + + nm_log_dbg (LOGD_VPN, "VPN connection '%s': setting firewall zone '%s' for '%s'", + nm_connection_get_id (base_con), zone ? zone : "default", priv->ip_iface); + fw_call_cleanup (connection); + priv->fw_call = nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (), + priv->ip_iface, + zone, + FALSE, + fw_change_zone_cb, + connection); return; + } else + if (nm_vpn_connection_apply_config (connection)) + return; } - g_clear_object (&priv->ip4_config); - g_clear_object (&priv->ip6_config); - - nm_log_warn (LOGD_VPN, "VPN connection '%s' did not receive valid IP config information.", - nm_connection_get_id (priv->connection)); - _set_vpn_state (connection, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, FALSE); + _cleanup_failed_config (connection); } #define LOG_INVALID_ARG(property) \ @@ -1027,7 +1112,7 @@ process_generic_config (NMVpnConnection *connection, if (priv->ip_iface) { /* Grab the interface index for address/routing operations */ - priv->ip_ifindex = nm_platform_link_get_ifindex (priv->ip_iface); + priv->ip_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface); if (!priv->ip_ifindex) { nm_log_err (LOGD_VPN, "(%s): failed to look up VPN interface index", priv->ip_iface); nm_vpn_connection_config_maybe_complete (connection, FALSE); @@ -1193,13 +1278,13 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, memset (&address, 0, sizeof (address)); address.plen = 24; - if (priv->ip4_external_gw) - nm_ip4_config_set_gateway (config, priv->ip4_external_gw); /* Internal address of the VPN subnet's gateway */ val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY); - if (val) + if (val) { priv->ip4_internal_gw = g_value_get_uint (val); + nm_ip4_config_set_gateway (config, priv->ip4_internal_gw); + } val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS); if (val) @@ -1338,8 +1423,6 @@ nm_vpn_connection_ip6_config_get (DBusGProxy *proxy, memset (&address, 0, sizeof (address)); address.plen = 128; - if (priv->ip6_external_gw) - nm_ip6_config_set_gateway (config, priv->ip6_external_gw); /* Internal address of the VPN subnet's gateway */ g_clear_pointer (&priv->ip6_internal_gw, g_free); @@ -1347,8 +1430,10 @@ nm_vpn_connection_ip6_config_get (DBusGProxy *proxy, if (val) { GByteArray *ba = g_value_get_boxed (val); - if (ba->len == sizeof (struct in6_addr)) + if (ba->len == sizeof (struct in6_addr)) { priv->ip6_internal_gw = g_memdup (ba->data, ba->len); + nm_ip6_config_set_gateway (config, priv->ip6_internal_gw); + } } val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS); @@ -1894,7 +1979,7 @@ get_secrets_cb (NMSettingsConnection *connection, priv->secrets_id = 0; - if (error) { + if (error && priv->secrets_idx >= SECRETS_REQ_NEW) { nm_log_err (LOGD_VPN, "Failed to request VPN secrets #%d: (%d) %s", priv->secrets_idx + 1, error->code, error->message); _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); @@ -2101,6 +2186,8 @@ dispose (GObject *object) g_clear_object (&priv->proxy); g_clear_object (&priv->connection); + fw_call_cleanup (NM_VPN_CONNECTION (object)); + G_OBJECT_CLASS (nm_vpn_connection_parent_class)->dispose (object); } diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c index b46d13ec..77220dd2 100644 --- a/src/vpn-manager/nm-vpn-service.c +++ b/src/vpn-manager/nm-vpn-service.c @@ -31,7 +31,6 @@ #include "nm-vpn-service.h" #include "nm-dbus-manager.h" #include "nm-logging.h" -#include "nm-posix-signals.h" #include "nm-vpn-manager.h" #include "nm-glib-compat.h" @@ -167,20 +166,6 @@ nm_vpn_service_stop_connections (NMVpnService *service, g_clear_pointer (&priv->pending, g_slist_free); } -static void -_daemon_setup (gpointer user_data G_GNUC_UNUSED) -{ - /* We are in the child process at this point */ - pid_t pid = getpid (); - setpgid (pid, pid); - - /* - * We blocked signals in main(). We need to restore original signal - * mask for VPN service here so that it can receive signals. - */ - nm_unblock_posix_signals (NULL); -} - static gboolean _daemon_exec_timeout (gpointer data) { @@ -207,7 +192,7 @@ nm_vpn_service_daemon_exec (NMVpnService *service, GError **error) vpn_argv[0] = priv->program; vpn_argv[1] = NULL; - success = g_spawn_async (NULL, vpn_argv, NULL, 0, _daemon_setup, NULL, &pid, &spawn_error); + success = g_spawn_async (NULL, vpn_argv, NULL, 0, nm_utils_setpgid, NULL, &pid, &spawn_error); if (success) { nm_log_info (LOGD_VPN, "VPN service '%s' started (%s), PID %ld", priv->name, priv->dbus_service, (long int) pid); |