vpn/core: move VPN gateway route between devices when routing changes
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
#include "nm-types.h"
|
#include "nm-types.h"
|
||||||
#include "nm-active-connection.h"
|
#include "nm-active-connection.h"
|
||||||
#include "nm-dbus-interface.h"
|
#include "nm-dbus-interface.h"
|
||||||
@@ -30,7 +31,7 @@
|
|||||||
#include "nm-auth-utils.h"
|
#include "nm-auth-utils.h"
|
||||||
#include "nm-auth-subject.h"
|
#include "nm-auth-subject.h"
|
||||||
#include "NetworkManagerUtils.h"
|
#include "NetworkManagerUtils.h"
|
||||||
|
#include "gsystem-local-alloc.h"
|
||||||
#include "nm-active-connection-glue.h"
|
#include "nm-active-connection-glue.h"
|
||||||
|
|
||||||
/* Base class for anything implementing the Connection.Active D-Bus interface */
|
/* Base class for anything implementing the Connection.Active D-Bus interface */
|
||||||
@@ -94,6 +95,12 @@ enum {
|
|||||||
LAST_PROP
|
LAST_PROP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DEVICE_CHANGED,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
static guint signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
static void check_master_ready (NMActiveConnection *self);
|
static void check_master_ready (NMActiveConnection *self);
|
||||||
static void _device_cleanup (NMActiveConnection *self);
|
static void _device_cleanup (NMActiveConnection *self);
|
||||||
|
|
||||||
@@ -395,20 +402,23 @@ gboolean
|
|||||||
nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
|
nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
|
||||||
{
|
{
|
||||||
NMActiveConnectionPrivate *priv;
|
NMActiveConnectionPrivate *priv;
|
||||||
|
gs_unref_object NMDevice *old_device = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
|
||||||
g_return_val_if_fail (!device || NM_IS_DEVICE (device), FALSE);
|
g_return_val_if_fail (!device || NM_IS_DEVICE (device), FALSE);
|
||||||
|
|
||||||
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
||||||
|
if (device == priv->device)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
old_device = priv->device ? g_object_ref (priv->device) : NULL;
|
||||||
|
_device_cleanup (self);
|
||||||
|
|
||||||
if (device) {
|
if (device) {
|
||||||
g_return_val_if_fail (priv->device == NULL, FALSE);
|
|
||||||
|
|
||||||
/* Device obviously can't be its own master */
|
/* Device obviously can't be its own master */
|
||||||
g_return_val_if_fail (!priv->master || device != nm_active_connection_get_device (priv->master), FALSE);
|
g_return_val_if_fail (!priv->master || device != nm_active_connection_get_device (priv->master), FALSE);
|
||||||
|
|
||||||
priv->device = g_object_ref (device);
|
priv->device = g_object_ref (device);
|
||||||
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_DEVICE);
|
|
||||||
|
|
||||||
g_signal_connect (device, "state-changed",
|
g_signal_connect (device, "state-changed",
|
||||||
G_CALLBACK (device_state_changed), self);
|
G_CALLBACK (device_state_changed), self);
|
||||||
@@ -419,7 +429,14 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
|
|||||||
priv->pending_activation_id = g_strdup_printf ("activation::%p", (void *)self);
|
priv->pending_activation_id = g_strdup_printf ("activation::%p", (void *)self);
|
||||||
nm_device_add_pending_action (device, priv->pending_activation_id, TRUE);
|
nm_device_add_pending_action (device, priv->pending_activation_id, TRUE);
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
|
priv->device = NULL;
|
||||||
|
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_DEVICE);
|
||||||
|
|
||||||
|
g_signal_emit (self, signals[DEVICE_CHANGED], 0, priv->device, old_device);
|
||||||
|
|
||||||
|
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEVICES);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1014,6 +1031,14 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
|
|||||||
FALSE, G_PARAM_READABLE |
|
FALSE, G_PARAM_READABLE |
|
||||||
G_PARAM_STATIC_STRINGS));
|
G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
signals[DEVICE_CHANGED] =
|
||||||
|
g_signal_new (NM_ACTIVE_CONNECTION_DEVICE_CHANGED,
|
||||||
|
G_OBJECT_CLASS_TYPE (object_class),
|
||||||
|
G_SIGNAL_RUN_FIRST,
|
||||||
|
G_STRUCT_OFFSET (NMActiveConnectionClass, device_changed),
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
G_TYPE_NONE, 2, NM_TYPE_DEVICE, NM_TYPE_DEVICE);
|
||||||
|
|
||||||
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
|
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
|
||||||
G_TYPE_FROM_CLASS (ac_class),
|
G_TYPE_FROM_CLASS (ac_class),
|
||||||
&dbus_glib_nm_active_connection_object_info);
|
&dbus_glib_nm_active_connection_object_info);
|
||||||
|
@@ -56,6 +56,9 @@
|
|||||||
#define NM_ACTIVE_CONNECTION_INT_MASTER "int-master"
|
#define NM_ACTIVE_CONNECTION_INT_MASTER "int-master"
|
||||||
#define NM_ACTIVE_CONNECTION_INT_MASTER_READY "int-master-ready"
|
#define NM_ACTIVE_CONNECTION_INT_MASTER_READY "int-master-ready"
|
||||||
|
|
||||||
|
/* Internal signals*/
|
||||||
|
#define NM_ACTIVE_CONNECTION_DEVICE_CHANGED "device-changed"
|
||||||
|
|
||||||
struct _NMActiveConnection {
|
struct _NMActiveConnection {
|
||||||
GObject parent;
|
GObject parent;
|
||||||
};
|
};
|
||||||
@@ -71,6 +74,10 @@ typedef struct {
|
|||||||
NMDeviceState new_state,
|
NMDeviceState new_state,
|
||||||
NMDeviceState old_state);
|
NMDeviceState old_state);
|
||||||
void (*master_failed) (NMActiveConnection *connection);
|
void (*master_failed) (NMActiveConnection *connection);
|
||||||
|
|
||||||
|
void (*device_changed) (NMActiveConnection *connection,
|
||||||
|
NMDevice *new_device,
|
||||||
|
NMDevice *old_device);
|
||||||
} NMActiveConnectionClass;
|
} NMActiveConnectionClass;
|
||||||
|
|
||||||
GType nm_active_connection_get_type (void);
|
GType nm_active_connection_get_type (void);
|
||||||
|
@@ -658,6 +658,20 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update)
|
|||||||
|
|
||||||
gw_addr = nm_ip4_config_get_gateway (ip4_config);
|
gw_addr = nm_ip4_config_get_gateway (ip4_config);
|
||||||
|
|
||||||
|
if (best) {
|
||||||
|
const GSList *connections, *iter;
|
||||||
|
|
||||||
|
connections = nm_manager_get_active_connections (priv->manager);
|
||||||
|
for (iter = connections; iter; iter = g_slist_next (iter)) {
|
||||||
|
NMActiveConnection *active = iter->data;
|
||||||
|
|
||||||
|
if ( NM_IS_VPN_CONNECTION (active)
|
||||||
|
&& nm_vpn_connection_get_ip4_config (NM_VPN_CONNECTION (active))
|
||||||
|
&& !nm_active_connection_get_device (active))
|
||||||
|
nm_active_connection_set_device (active, best);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (vpn) {
|
if (vpn) {
|
||||||
NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
|
NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
|
||||||
int parent_ifindex = nm_device_get_ip_ifindex (parent);
|
int parent_ifindex = nm_device_get_ip_ifindex (parent);
|
||||||
@@ -861,6 +875,20 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update)
|
|||||||
if (!gw_addr)
|
if (!gw_addr)
|
||||||
gw_addr = &in6addr_any;
|
gw_addr = &in6addr_any;
|
||||||
|
|
||||||
|
if (best) {
|
||||||
|
const GSList *connections, *iter;
|
||||||
|
|
||||||
|
connections = nm_manager_get_active_connections (priv->manager);
|
||||||
|
for (iter = connections; iter; iter = g_slist_next (iter)) {
|
||||||
|
NMActiveConnection *active = iter->data;
|
||||||
|
|
||||||
|
if ( NM_IS_VPN_CONNECTION (active)
|
||||||
|
&& nm_vpn_connection_get_ip6_config (NM_VPN_CONNECTION (active))
|
||||||
|
&& !nm_active_connection_get_device (active))
|
||||||
|
nm_active_connection_set_device (active, best);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (vpn) {
|
if (vpn) {
|
||||||
NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
|
NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
|
||||||
int parent_ifindex = nm_device_get_ip_ifindex (parent);
|
int parent_ifindex = nm_device_get_ip_ifindex (parent);
|
||||||
|
@@ -435,12 +435,27 @@ _set_vpn_state (NMVpnConnection *connection,
|
|||||||
g_object_unref (parent_dev);
|
g_object_unref (parent_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_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;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
device_state_changed (NMActiveConnection *active,
|
device_state_changed (NMActiveConnection *active,
|
||||||
NMDevice *device,
|
NMDevice *device,
|
||||||
NMDeviceState new_state,
|
NMDeviceState new_state,
|
||||||
NMDeviceState old_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) {
|
if (new_state <= NM_DEVICE_STATE_DISCONNECTED) {
|
||||||
_set_vpn_state (NM_VPN_CONNECTION (active),
|
_set_vpn_state (NM_VPN_CONNECTION (active),
|
||||||
STATE_DISCONNECTED,
|
STATE_DISCONNECTED,
|
||||||
@@ -839,41 +854,29 @@ print_vpn_config (NMVpnConnection *connection)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
nm_vpn_connection_apply_config (NMVpnConnection *connection)
|
apply_parent_device_config (NMVpnConnection *connection)
|
||||||
{
|
{
|
||||||
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
|
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
|
||||||
NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (connection));
|
NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (connection));
|
||||||
NMIP4Config *vpn4_parent_config = NULL;
|
NMIP4Config *vpn4_parent_config = NULL;
|
||||||
NMIP6Config *vpn6_parent_config = NULL;
|
NMIP6Config *vpn6_parent_config = NULL;
|
||||||
|
|
||||||
if (priv->ip_ifindex > 0) {
|
|
||||||
nm_platform_link_set_up (priv->ip_ifindex);
|
|
||||||
|
|
||||||
if (priv->ip4_config) {
|
|
||||||
if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex))
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->ip6_config) {
|
|
||||||
if (!nm_ip6_config_commit (priv->ip6_config, priv->ip_ifindex))
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->ip4_config)
|
if (priv->ip4_config)
|
||||||
vpn4_parent_config = nm_ip4_config_new ();
|
vpn4_parent_config = nm_ip4_config_new ();
|
||||||
if (priv->ip6_config)
|
if (priv->ip6_config)
|
||||||
vpn6_parent_config = nm_ip6_config_new ();
|
vpn6_parent_config = nm_ip6_config_new ();
|
||||||
} else {
|
|
||||||
|
if (priv->ip_ifindex <= 0) {
|
||||||
/* If the VPN didn't return a network interface, it is a route-based
|
/* 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
|
* VPN (like kernel IPSec) and all IP addressing and routing should
|
||||||
* be done on the parent interface instead.
|
* be done on the parent interface instead.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (priv->ip4_config)
|
if (vpn4_parent_config)
|
||||||
vpn4_parent_config = g_object_ref (priv->ip4_config);
|
nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config);
|
||||||
if (priv->ip6_config)
|
if (vpn6_parent_config)
|
||||||
vpn6_parent_config = g_object_ref (priv->ip6_config);
|
nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vpn4_parent_config) {
|
if (vpn4_parent_config) {
|
||||||
@@ -892,6 +895,28 @@ nm_vpn_connection_apply_config (NMVpnConnection *connection)
|
|||||||
nm_device_set_vpn6_config (parent_dev, vpn6_parent_config);
|
nm_device_set_vpn6_config (parent_dev, vpn6_parent_config);
|
||||||
g_object_unref (vpn6_parent_config);
|
g_object_unref (vpn6_parent_config);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (priv->ip4_config) {
|
||||||
|
if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->ip6_config) {
|
||||||
|
if (!nm_ip6_config_commit (priv->ip6_config, priv->ip_ifindex))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_parent_device_config (connection);
|
||||||
|
|
||||||
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.",
|
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.",
|
||||||
nm_connection_get_id (priv->connection));
|
nm_connection_get_id (priv->connection));
|
||||||
@@ -1928,6 +1953,39 @@ plugin_interactive_secrets_required (DBusGProxy *proxy,
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
static void
|
||||||
|
device_changed (NMActiveConnection *active,
|
||||||
|
NMDevice *new_device,
|
||||||
|
NMDevice *old_device)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
nm_device_set_vpn4_config (old_device, NULL);
|
||||||
|
nm_device_set_vpn6_config (old_device, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_device)
|
||||||
|
apply_parent_device_config (NM_VPN_CONNECTION (active));
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nm_vpn_connection_init (NMVpnConnection *self)
|
nm_vpn_connection_init (NMVpnConnection *self)
|
||||||
{
|
{
|
||||||
@@ -2049,6 +2107,7 @@ nm_vpn_connection_class_init (NMVpnConnectionClass *connection_class)
|
|||||||
object_class->dispose = dispose;
|
object_class->dispose = dispose;
|
||||||
object_class->finalize = finalize;
|
object_class->finalize = finalize;
|
||||||
active_class->device_state_changed = device_state_changed;
|
active_class->device_state_changed = device_state_changed;
|
||||||
|
active_class->device_changed = device_changed;
|
||||||
|
|
||||||
g_object_class_override_property (object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER);
|
g_object_class_override_property (object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user