mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-11 14:30:34 +01:00
device: allow multiple vpn IP configurations
This commit is contained in:
parent
965363a6d5
commit
9bbf5e94c2
3 changed files with 157 additions and 50 deletions
|
|
@ -272,6 +272,7 @@ typedef struct {
|
|||
NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */
|
||||
NMIP4Config * ext_ip4_config; /* Stuff added outside NM */
|
||||
NMIP4Config * wwan_ip4_config; /* WWAN configuration */
|
||||
GSList * vpn4_configs; /* VPNs which use this device */
|
||||
struct {
|
||||
gboolean v4_has;
|
||||
gboolean v4_is_assumed;
|
||||
|
|
@ -289,7 +290,6 @@ typedef struct {
|
|||
gulong dhcp4_state_sigid;
|
||||
NMDhcp4Config * dhcp4_config;
|
||||
guint dhcp4_restart_id;
|
||||
NMIP4Config * vpn4_config; /* routes added by a VPN which uses this device */
|
||||
|
||||
guint arp_round2_id;
|
||||
PingInfo gw_ping;
|
||||
|
|
@ -310,9 +310,9 @@ typedef struct {
|
|||
NMIP6Config * ip6_config;
|
||||
IpState ip6_state;
|
||||
NMIP6Config * con_ip6_config; /* config from the setting */
|
||||
NMIP6Config * vpn6_config; /* routes added by a VPN which uses this device */
|
||||
NMIP6Config * wwan_ip6_config;
|
||||
NMIP6Config * ext_ip6_config; /* Stuff added outside NM */
|
||||
GSList * vpn6_configs; /* VPNs which use this device */
|
||||
gboolean nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */
|
||||
guint32 ip6_mtu;
|
||||
|
||||
|
|
@ -3577,6 +3577,15 @@ dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_ip4_config_merge_default (gpointer value, gpointer user_data)
|
||||
{
|
||||
NMIP4Config *src = (NMIP4Config *) value;
|
||||
NMIP4Config *dst = (NMIP4Config *) user_data;
|
||||
|
||||
nm_ip4_config_merge (dst, src, NM_IP_CONFIG_MERGE_DEFAULT);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_config_merge_and_apply (NMDevice *self,
|
||||
NMIP4Config *config,
|
||||
|
|
@ -3622,8 +3631,9 @@ ip4_config_merge_and_apply (NMDevice *self,
|
|||
(ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0)
|
||||
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0));
|
||||
}
|
||||
if (priv->vpn4_config)
|
||||
nm_ip4_config_merge (composite, priv->vpn4_config, NM_IP_CONFIG_MERGE_DEFAULT);
|
||||
|
||||
g_slist_foreach (priv->vpn4_configs, _ip4_config_merge_default, composite);
|
||||
|
||||
if (priv->ext_ip4_config)
|
||||
nm_ip4_config_merge (composite, priv->ext_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT);
|
||||
|
||||
|
|
@ -4261,6 +4271,15 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_ip6_config_merge_default (gpointer value, gpointer user_data)
|
||||
{
|
||||
NMIP6Config *src = (NMIP6Config *) value;
|
||||
NMIP6Config *dst = (NMIP6Config *) user_data;
|
||||
|
||||
nm_ip6_config_merge (dst, src, NM_IP_CONFIG_MERGE_DEFAULT);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_config_merge_and_apply (NMDevice *self,
|
||||
gboolean commit,
|
||||
|
|
@ -4306,8 +4325,9 @@ ip6_config_merge_and_apply (NMDevice *self,
|
|||
(ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0)
|
||||
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0));
|
||||
}
|
||||
if (priv->vpn6_config)
|
||||
nm_ip6_config_merge (composite, priv->vpn6_config, NM_IP_CONFIG_MERGE_DEFAULT);
|
||||
|
||||
g_slist_foreach (priv->vpn6_configs, _ip6_config_merge_default, composite);
|
||||
|
||||
if (priv->ext_ip6_config)
|
||||
nm_ip6_config_merge (composite, priv->ext_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT);
|
||||
|
||||
|
|
@ -6854,18 +6874,49 @@ nm_device_set_ip4_config (NMDevice *self,
|
|||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_replace_vpn_config_in_list (GSList **plist, GObject *old, GObject *new)
|
||||
{
|
||||
GSList *old_link;
|
||||
|
||||
/* Below, assert that we have an @old instance to replace and that
|
||||
* @new is not yet tracked. But still, behave correctly in any
|
||||
* case. */
|
||||
|
||||
if ( old
|
||||
&& (old_link = g_slist_find (*plist, old))) {
|
||||
if (old != new) {
|
||||
if (new)
|
||||
old_link->data = g_object_ref (new);
|
||||
else
|
||||
*plist = g_slist_remove_link (*plist, old_link);
|
||||
g_object_unref (old);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (new) {
|
||||
if (!g_slist_find (*plist, new))
|
||||
*plist = g_slist_append (*plist, g_object_ref (new));
|
||||
else
|
||||
g_return_val_if_reached (TRUE);
|
||||
g_return_val_if_fail (!old, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* return FALSE if both @old and @new are unset. */
|
||||
g_return_val_if_fail (!old, FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
nm_device_set_vpn4_config (NMDevice *self, NMIP4Config *config)
|
||||
nm_device_replace_vpn4_config (NMDevice *self, NMIP4Config *old, NMIP4Config *config)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
if (priv->vpn4_config == config)
|
||||
if (!_replace_vpn_config_in_list (&priv->vpn4_configs, (GObject *) old, (GObject *) config))
|
||||
return;
|
||||
|
||||
g_clear_object (&priv->vpn4_config);
|
||||
if (config)
|
||||
priv->vpn4_config = g_object_ref (config);
|
||||
|
||||
/* NULL to use existing configs */
|
||||
if (!ip4_config_merge_and_apply (self, NULL, TRUE, NULL))
|
||||
_LOGW (LOGD_IP4, "failed to set VPN routes for device");
|
||||
|
|
@ -6982,17 +7033,13 @@ nm_device_set_ip6_config (NMDevice *self,
|
|||
}
|
||||
|
||||
void
|
||||
nm_device_set_vpn6_config (NMDevice *self, NMIP6Config *config)
|
||||
nm_device_replace_vpn6_config (NMDevice *self, NMIP6Config *old, NMIP6Config *config)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
if (priv->vpn6_config == config)
|
||||
if (!_replace_vpn_config_in_list (&priv->vpn6_configs, (GObject *) old, (GObject *) config))
|
||||
return;
|
||||
|
||||
g_clear_object (&priv->vpn6_config);
|
||||
if (config)
|
||||
priv->vpn6_config = g_object_ref (config);
|
||||
|
||||
/* NULL to use existing configs */
|
||||
if (!ip6_config_merge_and_apply (self, TRUE, NULL))
|
||||
_LOGW (LOGD_IP6, "failed to set VPN routes for device");
|
||||
|
|
@ -7589,6 +7636,24 @@ capture_lease_config (NMDevice *self,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_ip4_config_intersect (gpointer value, gpointer user_data)
|
||||
{
|
||||
NMIP4Config *dst = (NMIP4Config *) value;
|
||||
NMIP4Config *src = (NMIP4Config *) user_data;
|
||||
|
||||
nm_ip4_config_intersect (dst, src);
|
||||
}
|
||||
|
||||
static void
|
||||
_ip4_config_subtract (gpointer value, gpointer user_data)
|
||||
{
|
||||
NMIP4Config *dst = (NMIP4Config *) value;
|
||||
NMIP4Config *src = (NMIP4Config *) user_data;
|
||||
|
||||
nm_ip4_config_subtract (dst, src);
|
||||
}
|
||||
|
||||
static void
|
||||
update_ip4_config (NMDevice *self, gboolean initial)
|
||||
{
|
||||
|
|
@ -7626,8 +7691,9 @@ update_ip4_config (NMDevice *self, gboolean initial)
|
|||
nm_ip4_config_intersect (priv->con_ip4_config, priv->ext_ip4_config);
|
||||
if (priv->dev_ip4_config)
|
||||
nm_ip4_config_intersect (priv->dev_ip4_config, priv->ext_ip4_config);
|
||||
if (priv->vpn4_config)
|
||||
nm_ip4_config_intersect (priv->vpn4_config, priv->ext_ip4_config);
|
||||
|
||||
g_slist_foreach (priv->vpn4_configs, _ip4_config_intersect, priv->ext_ip4_config);
|
||||
|
||||
if (priv->wwan_ip4_config)
|
||||
nm_ip4_config_intersect (priv->wwan_ip4_config, priv->ext_ip4_config);
|
||||
|
||||
|
|
@ -7638,8 +7704,9 @@ update_ip4_config (NMDevice *self, gboolean initial)
|
|||
nm_ip4_config_subtract (priv->ext_ip4_config, priv->con_ip4_config);
|
||||
if (priv->dev_ip4_config)
|
||||
nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config);
|
||||
if (priv->vpn4_config)
|
||||
nm_ip4_config_subtract (priv->ext_ip4_config, priv->vpn4_config);
|
||||
|
||||
g_slist_foreach (priv->vpn4_configs, _ip4_config_subtract, priv->ext_ip4_config);
|
||||
|
||||
if (priv->wwan_ip4_config)
|
||||
nm_ip4_config_subtract (priv->ext_ip4_config, priv->wwan_ip4_config);
|
||||
|
||||
|
|
@ -7647,6 +7714,24 @@ update_ip4_config (NMDevice *self, gboolean initial)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_ip6_config_intersect (gpointer value, gpointer user_data)
|
||||
{
|
||||
NMIP6Config *dst = (NMIP6Config *) value;
|
||||
NMIP6Config *src = (NMIP6Config *) user_data;
|
||||
|
||||
nm_ip6_config_intersect (dst, src);
|
||||
}
|
||||
|
||||
static void
|
||||
_ip6_config_subtract (gpointer value, gpointer user_data)
|
||||
{
|
||||
NMIP6Config *dst = (NMIP6Config *) value;
|
||||
NMIP6Config *src = (NMIP6Config *) user_data;
|
||||
|
||||
nm_ip6_config_subtract (dst, src);
|
||||
}
|
||||
|
||||
static void
|
||||
update_ip6_config (NMDevice *self, gboolean initial)
|
||||
{
|
||||
|
|
@ -7684,8 +7769,7 @@ update_ip6_config (NMDevice *self, gboolean initial)
|
|||
nm_ip6_config_intersect (priv->dhcp6_ip6_config, priv->ext_ip6_config);
|
||||
if (priv->wwan_ip6_config)
|
||||
nm_ip6_config_intersect (priv->wwan_ip6_config, priv->ext_ip6_config);
|
||||
if (priv->vpn6_config)
|
||||
nm_ip6_config_intersect (priv->vpn6_config, priv->ext_ip6_config);
|
||||
g_slist_foreach (priv->vpn6_configs, _ip6_config_intersect, priv->ext_ip6_config);
|
||||
|
||||
/* Remove parts from ext_ip6_config to only contain the information that
|
||||
* was configured externally -- we already have the same configuration from
|
||||
|
|
@ -7698,8 +7782,7 @@ update_ip6_config (NMDevice *self, gboolean initial)
|
|||
nm_ip6_config_subtract (priv->ext_ip6_config, priv->dhcp6_ip6_config);
|
||||
if (priv->wwan_ip6_config)
|
||||
nm_ip6_config_subtract (priv->ext_ip6_config, priv->wwan_ip6_config);
|
||||
if (priv->vpn6_config)
|
||||
nm_ip6_config_subtract (priv->ext_ip6_config, priv->vpn6_config);
|
||||
g_slist_foreach (priv->vpn6_configs, _ip6_config_subtract, priv->ext_ip6_config);
|
||||
|
||||
ip6_config_merge_and_apply (self, FALSE, NULL);
|
||||
}
|
||||
|
|
@ -8540,15 +8623,18 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
|
|||
g_clear_object (&priv->dev_ip4_config);
|
||||
g_clear_object (&priv->ext_ip4_config);
|
||||
g_clear_object (&priv->wwan_ip4_config);
|
||||
g_clear_object (&priv->vpn4_config);
|
||||
g_clear_object (&priv->ip4_config);
|
||||
g_clear_object (&priv->con_ip6_config);
|
||||
g_clear_object (&priv->ac_ip6_config);
|
||||
g_clear_object (&priv->ext_ip6_config);
|
||||
g_clear_object (&priv->vpn6_config);
|
||||
g_clear_object (&priv->wwan_ip6_config);
|
||||
g_clear_object (&priv->ip6_config);
|
||||
|
||||
g_slist_free_full (priv->vpn4_configs, g_object_unref);
|
||||
priv->vpn4_configs = NULL;
|
||||
g_slist_free_full (priv->vpn6_configs, g_object_unref);
|
||||
priv->vpn6_configs = NULL;
|
||||
|
||||
clear_act_request (self);
|
||||
|
||||
/* Clear legacy IPv4 address property */
|
||||
|
|
|
|||
|
|
@ -345,10 +345,14 @@ NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *dev);
|
|||
NMDhcp6Config * nm_device_get_dhcp6_config (NMDevice *dev);
|
||||
|
||||
NMIP4Config * nm_device_get_ip4_config (NMDevice *dev);
|
||||
void nm_device_set_vpn4_config (NMDevice *dev, NMIP4Config *config);
|
||||
void nm_device_replace_vpn4_config (NMDevice *dev,
|
||||
NMIP4Config *old,
|
||||
NMIP4Config *config);
|
||||
|
||||
NMIP6Config * nm_device_get_ip6_config (NMDevice *dev);
|
||||
void nm_device_set_vpn6_config (NMDevice *dev, NMIP6Config *config);
|
||||
void nm_device_replace_vpn6_config (NMDevice *dev,
|
||||
NMIP6Config *old,
|
||||
NMIP6Config *config);
|
||||
|
||||
void nm_device_capture_initial_config (NMDevice *dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -105,6 +105,13 @@ typedef struct {
|
|||
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;
|
||||
|
|
@ -329,6 +336,22 @@ fw_call_cleanup (NMVpnConnection *self)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
remove_parent_device_config (NMVpnConnection *connection, NMDevice *device)
|
||||
{
|
||||
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_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)
|
||||
{
|
||||
|
|
@ -340,8 +363,7 @@ vpn_cleanup (NMVpnConnection *self, NMDevice *parent_dev)
|
|||
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_parent_device_config (self, parent_dev);
|
||||
|
||||
/* Remove zone from firewall */
|
||||
if (priv->ip_iface) {
|
||||
|
|
@ -1030,22 +1052,19 @@ apply_parent_device_config (NMVpnConnection *self)
|
|||
}
|
||||
}
|
||||
|
||||
if (vpn4_parent_config) {
|
||||
/* Add any explicit route to the VPN gateway through the parent device */
|
||||
if (priv->ip4_external_gw)
|
||||
add_ip4_vpn_gateway_route (vpn4_parent_config, parent_dev, priv->ip4_external_gw);
|
||||
/* 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);
|
||||
if (vpn6_parent_config && priv->ip6_external_gw)
|
||||
add_ip6_vpn_gateway_route (vpn6_parent_config, parent_dev, priv->ip6_external_gw);
|
||||
|
||||
nm_device_set_vpn4_config (parent_dev, vpn4_parent_config);
|
||||
g_object_unref (vpn4_parent_config);
|
||||
}
|
||||
if (vpn6_parent_config) {
|
||||
/* Add any explicit route to the VPN gateway through the parent device */
|
||||
if (priv->ip6_external_gw)
|
||||
add_ip6_vpn_gateway_route (vpn6_parent_config, parent_dev, priv->ip6_external_gw);
|
||||
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_set_vpn6_config (parent_dev, vpn6_parent_config);
|
||||
g_object_unref (vpn6_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
|
||||
|
|
@ -2242,10 +2261,8 @@ device_changed (NMActiveConnection *active,
|
|||
* 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 (old_device)
|
||||
remove_parent_device_config (NM_VPN_CONNECTION (active), old_device);
|
||||
|
||||
if (new_device)
|
||||
apply_parent_device_config (NM_VPN_CONNECTION (active));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue