summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog56
-rw-r--r--src/NetworkManager.c5
-rw-r--r--src/NetworkManagerPolicy.c148
-rw-r--r--src/NetworkManagerPolicy.h3
-rw-r--r--src/NetworkManagerSystem.c284
-rw-r--r--src/NetworkManagerSystem.h23
-rw-r--r--src/nm-device.c2
-rw-r--r--src/vpn-manager/nm-vpn-connection.c80
-rw-r--r--src/vpn-manager/nm-vpn-connection.h3
-rw-r--r--src/vpn-manager/nm-vpn-manager.c33
-rw-r--r--src/vpn-manager/nm-vpn-manager.h2
11 files changed, 418 insertions, 221 deletions
diff --git a/ChangeLog b/ChangeLog
index 5c580b8819..4d08a21717 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,59 @@
+2008-10-10 Dan Williams <dcbw@redhat.com>
+
+ Rework default route handling to consolidate decisions in the policy,
+ and to take active VPN connections into account when changing the default
+ route (bgo #545912)
+
+ * src/NetworkManager.c
+ - (main): pass the vpn_manager to the policy so it knows about active
+ VPN connections; clean up the named manager which wasn't done before
+
+ * src/NetworkManagerPolicy.c
+ src/NetworkManagerPolicy.h
+ - (nm_policy_new): get a clue about the vpn_manager
+ - (update_default_route): remove, fold into update_routing_and_dns()
+ - (update_routing_and_dns): handle active VPN connections too; an
+ active VPN connection becomes the default route if it does not have
+ server-specified or user-specified custom routes. Otherwise, the
+ best active device gets the default route
+ - (vpn_connection_activated, vpn_connection_deactivated, nm_policy_new,
+ nm_policy_destroy): track VPN connection activation and deactivation
+ and update the default route when appropriate
+
+ * src/NetworkManagerSystem.c
+ src/NetworkManagerSystem.h
+ - (nm_system_vpn_device_unset_from_ip4_config): remove, put functionality
+ in the VPN connection itself
+ - (nm_system_vpn_device_set_from_ip4_config,
+ nm_system_device_set_from_ip4_config): merge together to make
+ nm_system_apply_ip4_config()
+ - (add_vpn_gateway_route): add a route to the VPN's external gateway
+ via the parent device
+ - (nm_system_apply_ip4_config): simplify
+ - (add_ip4_route_to_gateway): new function; add a direct route to the
+ gateway if needed
+ - (nm_system_device_replace_default_ip4_route): simplify, break gateway
+ route stuff out into add_ip4_route_to_gateway() for clarity
+
+ * src/nm-device.c
+ - (nm_device_set_ip4_config): update for nm_system_apply_ip4_config()
+
+ * src/vpn-manager/nm-vpn-connection.c
+ src/vpn-manager/nm-vpn-connection.h
+ - (nm_vpn_connection_get_ip4_config, nm_vpn_connection_get_ip_iface,
+ nm_vpn_connection_get_parent_device): add
+ - (nm_vpn_connection_ip4_config_get): make the requirement of a tunnel
+ device explicit
+ - (connection_state_changed): update the named manager now that
+ nm_system_vpn_device_unset_from_ip4_config() is gone; do something
+ useful on errors
+
+ * src/vpn-manager/nm-vpn-manager.c
+ src/vpn-manager/nm-vpn-manager.h
+ - Add a 'connection-activated' signal
+ - (nm_vpn_manager_get_active_connections): new function; mainly for the
+ policy to find out about active VPN connections
+
2008-10-10 Tambet Ingo <tambet@gmail.com>
* src/nm-logging.c (nm_logging_setup): Don't use LOG_CONS when running as
diff --git a/src/NetworkManager.c b/src/NetworkManager.c
index e3079db489..948fb664d3 100644
--- a/src/NetworkManager.c
+++ b/src/NetworkManager.c
@@ -308,7 +308,7 @@ main (int argc, char *argv[])
goto done;
}
- policy = nm_policy_new (manager);
+ policy = nm_policy_new (manager, vpn_manager);
if (policy == NULL) {
nm_error ("Failed to initialize the policy.");
goto done;
@@ -352,6 +352,9 @@ done:
if (vpn_manager)
g_object_unref (vpn_manager);
+ if (named_mgr)
+ g_object_unref (named_mgr);
+
if (sup_mgr)
g_object_unref (sup_mgr);
diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c
index 25024c2cc4..46c51e9d0f 100644
--- a/src/NetworkManagerPolicy.c
+++ b/src/NetworkManagerPolicy.c
@@ -43,6 +43,7 @@
#include "nm-setting-connection.h"
#include "NetworkManagerSystem.h"
#include "nm-named-manager.h"
+#include "nm-vpn-manager.h"
typedef struct LookupThread LookupThread;
@@ -69,6 +70,10 @@ struct NMPolicy {
GSList *signal_ids;
GSList *dev_signal_ids;
+ NMVPNManager *vpn_manager;
+ gulong vpn_activated_id;
+ gulong vpn_deactivated_id;
+
NMDevice *default_device;
LookupThread *lookup;
@@ -462,34 +467,21 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
}
static void
-update_default_route (NMPolicy *policy, NMDevice *new)
-{
- const char *ip_iface;
-
- /* FIXME: Not sure if the following makes any sense. */
- /* If iface and ip_iface are the same, it's a regular network device and we
- treat it as such. However, if they differ, it's most likely something like
- a serial device with ppp interface, so route all the traffic to it. */
- ip_iface = nm_device_get_ip_iface (new);
- if (strcmp (ip_iface, nm_device_get_iface (new))) {
- nm_system_device_replace_default_ip4_route (ip_iface, 0, 0);
- } else {
- NMIP4Config *config;
- const NMSettingIP4Address *def_addr;
-
- config = nm_device_get_ip4_config (new);
- def_addr = nm_ip4_config_get_address (config, 0);
- nm_system_device_replace_default_ip4_route (ip_iface, def_addr->gateway, nm_ip4_config_get_mss (config));
- }
-}
-
-static void
update_routing_and_dns (NMPolicy *policy, gboolean force_update)
{
+ NMNamedIPConfigType dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
NMDevice *best = NULL;
NMActRequest *best_req = NULL;
NMNamedManager *named_mgr;
- GSList *devices = NULL, *iter;
+ GSList *devices = NULL, *iter, *vpns;
+ NMIP4Config *ip4_config = NULL;
+ const char *ip_iface = NULL;
+ const char *parent_iface = NULL;
+ NMVPNConnection *vpn = NULL;
+ NMConnection *connection = NULL;
+ NMSettingConnection *s_con = NULL;
+ guint32 parent_mss = 0;
+ guint32 gateway = 0;
best = get_best_device (policy->manager, &best_req);
if (!best)
@@ -497,8 +489,69 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
if (!force_update && (best == policy->default_device))
goto out;
- update_default_route (policy, best);
-
+ /* If a VPN connection is active, it is preferred */
+ vpns = nm_vpn_manager_get_active_connections (policy->vpn_manager);
+ for (iter = vpns; iter; iter = g_slist_next (iter)) {
+ NMVPNConnection *candidate = NM_VPN_CONNECTION (iter->data);
+
+ if (!vpn && (nm_vpn_connection_get_vpn_state (candidate) == NM_VPN_CONNECTION_STATE_ACTIVATED))
+ vpn = g_object_ref (candidate);
+ g_object_unref (candidate);
+ }
+ g_slist_free (vpns);
+
+ /* VPNs are the default route only if they don't have custom routes */
+ if (vpn) {
+ NMIP4Config *vpn_config;
+
+ vpn_config = nm_vpn_connection_get_ip4_config (vpn);
+ if (nm_ip4_config_get_num_routes (vpn_config) == 0) {
+ NMIP4Config *parent_ip4;
+ NMDevice *parent;
+
+ connection = nm_vpn_connection_get_connection (vpn);
+ ip_iface = nm_vpn_connection_get_ip_iface (vpn);
+ ip4_config = vpn_config;
+
+ parent = nm_vpn_connection_get_parent_device (vpn);
+ parent_iface = nm_device_get_ip_iface (parent);
+ parent_ip4 = nm_device_get_ip4_config (parent);
+ if (parent_ip4)
+ parent_mss = nm_ip4_config_get_mss (parent_ip4);
+
+ dns_type = NM_NAMED_IP_CONFIG_TYPE_VPN;
+ }
+ g_object_unref (vpn);
+ }
+
+ /* The best device gets the default route if a VPN connection didn't */
+ if (!ip_iface || !ip4_config) {
+ const NMSettingIP4Address *addr;
+
+ connection = nm_act_request_get_connection (best_req);
+ ip_iface = nm_device_get_ip_iface (best);
+ ip4_config = nm_device_get_ip4_config (best);
+ if (ip4_config) {
+ addr = nm_ip4_config_get_address (ip4_config, 0);
+ gateway = addr->gateway;
+ }
+
+ dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
+ }
+
+ if (!ip_iface || !ip4_config) {
+ nm_warning ("%s: couldn't determine IP interface (%p) or IPv4 config (%p)!",
+ __func__, ip_iface, ip4_config);
+ goto out;
+ }
+
+ /* Set the new default route */
+ nm_system_device_replace_default_ip4_route (ip_iface,
+ gateway,
+ nm_ip4_config_get_mss (ip4_config),
+ parent_iface,
+ parent_mss);
+
/* Update the default active connection. Only mark the new default
* active connection after setting default = FALSE on all other connections
* first. The order is important, we don't want two connections marked
@@ -515,10 +568,7 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
}
named_mgr = nm_named_manager_get ();
- nm_named_manager_add_ip4_config (named_mgr,
- nm_device_get_ip_iface (best),
- nm_device_get_ip4_config (best),
- NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE);
+ nm_named_manager_add_ip4_config (named_mgr, ip_iface, ip4_config, dns_type);
g_object_unref (named_mgr);
/* Now set new default active connection _after_ updating DNS info, so that
@@ -527,8 +577,13 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
if (best_req)
nm_act_request_set_default (best_req, TRUE);
- nm_info ("Policy set (%s) as default device for routing and DNS.",
- nm_device_get_iface (best));
+ if (connection)
+ s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+
+ if (s_con && s_con->id)
+ nm_info ("Policy set '%s' (%s) as default for routing and DNS.", s_con->id, ip_iface);
+ else
+ nm_info ("Policy set (%s) as default for routing and DNS.", ip_iface);
out:
/* Update the system hostname */
@@ -618,6 +673,24 @@ auto_activate_device (gpointer user_data)
/*****************************************************************************/
static void
+vpn_connection_activated (NMVPNManager *manager,
+ NMVPNConnection *vpn,
+ gpointer user_data)
+{
+ update_routing_and_dns ((NMPolicy *) user_data, TRUE);
+}
+
+static void
+vpn_connection_deactivated (NMVPNManager *manager,
+ NMVPNConnection *vpn,
+ NMVPNConnectionState state,
+ NMVPNConnectionStateReason reason,
+ gpointer user_data)
+{
+ update_routing_and_dns ((NMPolicy *) user_data, TRUE);
+}
+
+static void
global_state_changed (NMManager *manager, NMState state, gpointer user_data)
{
}
@@ -868,7 +941,7 @@ connection_removed (NMManager *manager,
}
NMPolicy *
-nm_policy_new (NMManager *manager)
+nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager)
{
NMPolicy *policy;
static gboolean initialized = FALSE;
@@ -881,6 +954,14 @@ nm_policy_new (NMManager *manager)
policy->manager = g_object_ref (manager);
policy->update_state_id = 0;
+ policy->vpn_manager = g_object_ref (vpn_manager);
+ id = g_signal_connect (policy->vpn_manager, "connection-activated",
+ G_CALLBACK (vpn_connection_activated), policy);
+ policy->vpn_activated_id = id;
+ id = g_signal_connect (policy->vpn_manager, "connection-deactivated",
+ G_CALLBACK (vpn_connection_deactivated), policy);
+ policy->vpn_deactivated_id = id;
+
id = g_signal_connect (manager, "state-changed",
G_CALLBACK (global_state_changed), policy);
policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);
@@ -944,6 +1025,9 @@ nm_policy_destroy (NMPolicy *policy)
}
g_slist_free (policy->pending_activation_checks);
+ g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_activated_id);
+ g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_deactivated_id);
+
for (iter = policy->signal_ids; iter; iter = g_slist_next (iter))
g_signal_handler_disconnect (policy->manager, (gulong) iter->data);
g_slist_free (policy->signal_ids);
diff --git a/src/NetworkManagerPolicy.h b/src/NetworkManagerPolicy.h
index 9f2c52323d..5ab379f89a 100644
--- a/src/NetworkManagerPolicy.h
+++ b/src/NetworkManagerPolicy.h
@@ -24,12 +24,13 @@
#include "NetworkManager.h"
#include "nm-manager.h"
+#include "nm-vpn-manager.h"
#include "nm-device.h"
#include "nm-activation-request.h"
typedef struct NMPolicy NMPolicy;
-NMPolicy *nm_policy_new (NMManager *manager);
+NMPolicy *nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager);
void nm_policy_destroy (NMPolicy *policy);
#endif /* NETWORK_MANAGER_POLICY_H */
diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c
index 8f836d98a2..653e90a712 100644
--- a/src/NetworkManagerSystem.c
+++ b/src/NetworkManagerSystem.c
@@ -273,114 +273,75 @@ add_ip4_addresses (NMIP4Config *config, const char *iface)
return TRUE;
}
-/*
- * nm_system_device_set_from_ip4_config
- *
- * Set IPv4 configuration of the device from an NMIP4Config object.
- *
- */
-gboolean
-nm_system_device_set_from_ip4_config (const char *iface,
- NMIP4Config *config,
- int priority)
+static void
+add_vpn_gateway_route (NMDevice *device, const char *iface, NMIP4Config *config)
{
- int len, i;
+ NMIP4Config *ad_config;
+ guint32 ad_gw = 0, vpn_gw = 0, i;
+ const NMSettingIP4Address *tmp;
- g_return_val_if_fail (iface != NULL, FALSE);
- g_return_val_if_fail (config != NULL, FALSE);
+ g_return_if_fail (NM_IS_DEVICE (device));
- if (!add_ip4_addresses (config, iface))
- return FALSE;
-
- sleep (1);
+ ad_config = nm_device_get_ip4_config (device);
+ g_return_if_fail (ad_config != NULL);
- len = nm_ip4_config_get_num_routes (config);
- for (i = 0; i < len; i++) {
- const NMSettingIP4Route *route = nm_ip4_config_get_route (config, i);
-
- nm_system_device_set_ip4_route (iface, config,
- route->address,
- route->prefix,
- route->next_hop,
- route->metric,
- nm_ip4_config_get_mss (config));
+ /* Set up a route to the VPN gateway's public IP address through the default
+ * network device.
+ */
+ for (i = 0; i < nm_ip4_config_get_num_addresses (ad_config); i++) {
+ tmp = nm_ip4_config_get_address (ad_config, i);
+ if (tmp->gateway) {
+ ad_gw = tmp->gateway;
+ break;
+ }
}
- if (nm_ip4_config_get_mtu (config))
- nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config));
+ if (!ad_gw)
+ return;
- if (priority > 0)
- nm_system_device_set_priority (iface, config, priority);
+ for (i = 0; i < nm_ip4_config_get_num_addresses (config); i++) {
+ tmp = nm_ip4_config_get_address (config, i);
+ if (tmp->gateway) {
+ vpn_gw = tmp->gateway;
+ break;
+ }
+ }
- return TRUE;
+ nm_system_device_set_ip4_route (nm_device_get_ip_iface (device),
+ ad_config, vpn_gw, 32, ad_gw, 0,
+ nm_ip4_config_get_mss (ad_config));
}
/*
- * nm_system_vpn_device_set_from_ip4_config
+ * nm_system_apply_ip4_config
*
- * Set IPv4 configuration of a VPN device from an NMIP4Config object.
+ * Set IPv4 configuration of the device from an NMIP4Config object.
*
*/
gboolean
-nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device,
- const char *iface,
- NMIP4Config *config)
+nm_system_apply_ip4_config (NMDevice *device,
+ const char *iface,
+ NMIP4Config *config,
+ int priority,
+ gboolean is_vpn)
{
- NMIP4Config *ad_config = NULL;
- NMNamedManager *named_mgr;
- int num;
int i;
+ g_return_val_if_fail (iface != NULL, FALSE);
g_return_val_if_fail (config != NULL, FALSE);
- /* Set up a route to the VPN gateway through the real network device */
- if (active_device && (ad_config = nm_device_get_ip4_config (active_device))) {
- guint32 ad_gw = 0, vpn_gw = 0;
- const NMSettingIP4Address *tmp;
-
- num = nm_ip4_config_get_num_addresses (ad_config);
- for (i = 0; i < num; i++) {
- tmp = nm_ip4_config_get_address (ad_config, i);
- if (tmp->gateway) {
- ad_gw = tmp->gateway;
- break;
- }
- }
-
- if (ad_gw) {
- num = nm_ip4_config_get_num_addresses (config);
- for (i = 0; i < num; i++) {
- tmp = nm_ip4_config_get_address (config, i);
- if (tmp->gateway) {
- vpn_gw = tmp->gateway;
- break;
- }
- }
-
- nm_system_device_set_ip4_route (nm_device_get_ip_iface (active_device),
- ad_config, vpn_gw, 32, ad_gw, 0,
- nm_ip4_config_get_mss (config));
- }
- }
-
- if (!iface || !strlen (iface))
- goto out;
-
- nm_system_device_set_up_down_with_iface (iface, TRUE, NULL);
-
if (!add_ip4_addresses (config, iface))
- goto out;
+ return FALSE;
- /* Set the MTU */
- if (nm_ip4_config_get_mtu (config))
- nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config));
+ if (is_vpn)
+ add_vpn_gateway_route (device, iface, config);
- /* Set routes */
- num = nm_ip4_config_get_num_routes (config);
- for (i = 0; i < num; i++) {
+ sleep (1);
+
+ for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) {
const NMSettingIP4Route *route = nm_ip4_config_get_route (config, i);
- nm_system_device_set_ip4_route (iface, config,
+ nm_system_device_set_ip4_route (iface, config,
route->address,
route->prefix,
route->next_hop,
@@ -388,39 +349,15 @@ nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device,
nm_ip4_config_get_mss (config));
}
- if (num == 0)
- nm_system_device_replace_default_ip4_route (iface, 0, 0);
-
-out:
- named_mgr = nm_named_manager_get ();
- nm_named_manager_add_ip4_config (named_mgr, iface, config, NM_NAMED_IP_CONFIG_TYPE_VPN);
- g_object_unref (named_mgr);
-
- return TRUE;
-}
-
-
-/*
- * nm_system_vpn_device_unset_from_ip4_config
- *
- * Unset an IPv4 configuration of a VPN device from an NMIP4Config object.
- *
- */
-gboolean nm_system_vpn_device_unset_from_ip4_config (NMDevice *active_device, const char *iface, NMIP4Config *config)
-{
- NMNamedManager *named_mgr;
-
- g_return_val_if_fail (active_device != NULL, FALSE);
- g_return_val_if_fail (config != NULL, FALSE);
+ if (nm_ip4_config_get_mtu (config))
+ nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config));
- named_mgr = nm_named_manager_get ();
- nm_named_manager_remove_ip4_config (named_mgr, iface, config);
- g_object_unref (named_mgr);
+ if (priority > 0)
+ nm_system_device_set_priority (iface, config, priority);
return TRUE;
}
-
/*
* nm_system_device_set_up_down
*
@@ -547,6 +484,55 @@ nm_system_device_set_mtu (const char *iface, guint32 mtu)
return success;
}
+static struct rtnl_route *
+add_ip4_route_to_gateway (const char *iface, guint32 gw, guint32 mss)
+{
+ struct nl_handle *nlh;
+ struct rtnl_route *route = NULL;
+ struct nl_addr *gw_addr = NULL;
+ int iface_idx, err;
+
+ nlh = nm_netlink_get_default_handle ();
+ g_return_val_if_fail (nlh != NULL, NULL);
+
+ iface_idx = nm_netlink_iface_to_index (iface);
+ if (iface_idx < 0)
+ return NULL;
+
+ /* Gateway might be over a bridge; try adding a route to gateway first */
+ route = rtnl_route_alloc ();
+ if (route == NULL)
+ return NULL;
+
+ rtnl_route_set_oif (route, iface_idx);
+ rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
+
+ gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw));
+ if (!gw_addr)
+ goto error;
+ rtnl_route_set_dst (route, gw_addr);
+ nl_addr_put (gw_addr);
+
+ if (mss) {
+ if (rtnl_route_set_metric (route, RTAX_ADVMSS, mss) < 0)
+ goto error;
+ }
+
+ /* Add direct route to the gateway */
+ err = rtnl_route_add (nlh, route, 0);
+ if (err) {
+ nm_warning ("Failed to add IPv4 default route on '%s': (%d) %s",
+ iface, err, nl_geterror ());
+ goto error;
+ }
+
+ return route;
+
+error:
+ rtnl_route_put (route);
+ return NULL;
+}
+
/*
* nm_system_replace_default_ip4_route
*
@@ -554,32 +540,35 @@ nm_system_device_set_mtu (const char *iface, guint32 mtu)
*
*/
void
-nm_system_device_replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss)
+nm_system_device_replace_default_ip4_route (const char *iface,
+ guint32 gw,
+ guint32 mss,
+ const char *parent_iface,
+ guint32 parent_mss)
{
- struct rtnl_route * route;
- struct rtnl_route * route2 = NULL;
- struct nl_handle * nlh;
- struct nl_addr * gw_addr;
+ struct rtnl_route *route = NULL;
+ struct rtnl_route *gw_route = NULL;
+ struct nl_handle *nlh;
+ struct nl_addr *gw_addr = NULL;
int iface_idx, err;
+ gboolean success = FALSE;
nlh = nm_netlink_get_default_handle ();
g_return_if_fail (nlh != NULL);
+ iface_idx = nm_netlink_iface_to_index (iface);
+ if (iface_idx < 0)
+ return;
+
route = rtnl_route_alloc();
g_return_if_fail (route != NULL);
rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
-
- iface_idx = nm_netlink_iface_to_index (iface);
- if (iface_idx < 0)
- goto out;
rtnl_route_set_oif (route, iface_idx);
- /* Build up gateway address; a gateway of 0 (used in e.g. PPP links) means
- * that all packets should be sent to the gateway since it's a point-to-point
- * link and has no broadcast segment really.
- */
- if (!(gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw))))
+ /* Build up the gateway address */
+ gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw));
+ if (!gw_addr)
goto out;
rtnl_route_set_gateway (route, gw_addr);
nl_addr_put (gw_addr);
@@ -589,9 +578,11 @@ nm_system_device_replace_default_ip4_route (const char *iface, guint32 gw, guint
goto out;
}
+ /* Add the new default route */
err = rtnl_route_add (nlh, route, NLM_F_REPLACE);
if (err == 0) {
/* Everything good */
+ success = TRUE;
goto out;
} else if (err != -ESRCH) {
nm_warning ("rtnl_route_add() returned error %s (%d)\n%s",
@@ -599,41 +590,26 @@ nm_system_device_replace_default_ip4_route (const char *iface, guint32 gw, guint
goto out;
}
- /* Gateway might be over a bridge; try adding a route to gateway first */
- route2 = rtnl_route_alloc ();
- if (route2 == NULL)
- goto out;
- rtnl_route_set_oif (route2, iface_idx);
- rtnl_route_set_dst (route2, gw_addr);
-
- if (mss) {
- if (rtnl_route_set_metric (route2, RTAX_ADVMSS, mss) < 0)
- goto out;
- }
-
- /* Add route to gateway over bridge */
- err = rtnl_route_add (nlh, route2, 0);
- if (err) {
- nm_warning ("Failed to add IPv4 default route on '%s': %s",
- iface,
- nl_geterror ());
+ /* Try adding a direct route to the gateway first */
+ gw_route = add_ip4_route_to_gateway (parent_iface ? parent_iface : iface,
+ gw,
+ parent_iface ? parent_mss : mss);
+ if (!gw_route)
goto out;
- }
- /* Try adding the route again */
- err = rtnl_route_add (nlh, route, 0);
- if (err) {
- rtnl_route_del (nlh, route2, 0);
- nm_warning ("Failed to set IPv4 default route on '%s': %s",
- iface,
- nl_geterror ());
+ /* Try adding the original route again */
+ err = rtnl_route_add (nlh, route, NLM_F_REPLACE);
+ if (err != 0) {
+ rtnl_route_del (nlh, gw_route, 0);
+ nm_warning ("Failed to set IPv4 default route on '%s': %s", iface, nl_geterror ());
}
out:
- if (route2)
- rtnl_route_put (route2);
+ if (gw_route)
+ rtnl_route_put (gw_route);
- rtnl_route_put (route);
+ if (route)
+ rtnl_route_put (route);
}
/*
diff --git a/src/NetworkManagerSystem.h b/src/NetworkManagerSystem.h
index 2a1503ee79..bd8df4af26 100644
--- a/src/NetworkManagerSystem.h
+++ b/src/NetworkManagerSystem.h
@@ -1,5 +1,4 @@
-/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
-
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* Dan Williams <dcbw@redhat.com>
@@ -37,7 +36,9 @@ void nm_system_device_flush_ip4_routes_with_iface (const char *iface);
void nm_system_device_replace_default_ip4_route (const char *iface,
guint32 gw,
- guint32 mss);
+ guint32 mss,
+ const char *parent_iface,
+ guint32 parent_mss);
void nm_system_device_flush_ip4_addresses (NMDevice *dev);
void nm_system_device_flush_ip4_addresses_with_iface (const char *iface);
@@ -45,17 +46,11 @@ void nm_system_device_flush_ip4_addresses_with_iface (const char *iface);
void nm_system_enable_loopback (void);
void nm_system_update_dns (void);
-gboolean nm_system_device_set_from_ip4_config (const char *iface,
- NMIP4Config *config,
- int priority);
-
-gboolean nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device,
- const char *iface,
- NMIP4Config *config);
-
-gboolean nm_system_vpn_device_unset_from_ip4_config (NMDevice *active_device,
- const char *iface,
- NMIP4Config *config);
+gboolean nm_system_apply_ip4_config (NMDevice *device,
+ const char *iface,
+ NMIP4Config *config,
+ int priority,
+ gboolean is_vpn);
gboolean nm_system_device_set_up_down (NMDevice *dev,
gboolean up,
diff --git a/src/nm-device.c b/src/nm-device.c
index a7a0fc6da3..1d5772e456 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -1919,7 +1919,7 @@ nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config, NMDeviceStateReas
if (!nm_ip4_config_get_dbus_path (config))
nm_ip4_config_export (config);
- success = nm_system_device_set_from_ip4_config (ip_iface, config, nm_device_get_priority (self));
+ success = nm_system_apply_ip4_config (self, ip_iface, config, nm_device_get_priority (self), FALSE);
if (success)
nm_device_update_ip4_address (self);
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index 6307aaa1c5..90c3691c37 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -46,6 +46,7 @@
#include "nm-properties-changed-signal.h"
#include "nm-dbus-glib-types.h"
#include "NetworkManagerUtils.h"
+#include "nm-named-manager.h"
#include "nm-vpn-connection-glue.h"
@@ -354,8 +355,8 @@ print_vpn_config (NMIP4Config *config,
static void
nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
- GHashTable *config_hash,
- gpointer user_data)
+ GHashTable *config_hash,
+ gpointer user_data)
{
NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
@@ -376,6 +377,14 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
addr = g_malloc0 (sizeof (NMSettingIP4Address));
addr->prefix = 24; /* default to class C */
+ val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV);
+ if (val)
+ priv->tundev = g_strdup (g_value_get_string (val));
+ else {
+ nm_warning ("%s: invalid or missing tunnel device received!", __func__);
+ goto error;
+ }
+
val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY);
if (val)
addr->gateway = g_value_get_uint (val);
@@ -395,8 +404,9 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
if (addr->address && addr->prefix) {
nm_ip4_config_take_address (config, addr);
} else {
- g_warning ("%s: invalid IP4 config received!", __func__);
+ nm_warning ("%s: invalid IP4 config received!", __func__);
g_free (addr);
+ goto error;
}
val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DNS);
@@ -423,10 +433,6 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
if (val)
nm_ip4_config_set_mtu (config, g_value_get_uint (val));
- val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV);
- if (val)
- priv->tundev = g_strdup (g_value_get_string (val));
-
val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN);
if (val)
nm_ip4_config_add_domain (config, g_value_get_string (val));
@@ -452,26 +458,37 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
print_vpn_config (config, priv->tundev, priv->banner);
- priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
- priv->ip4_config = config;
-
/* Merge in user overrides from the NMConnection's IPv4 setting */
s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (priv->connection, NM_TYPE_SETTING_IP4_CONFIG));
nm_utils_merge_ip4_config (config, s_ip4);
- if (nm_system_vpn_device_set_from_ip4_config (priv->parent_dev, priv->tundev, priv->ip4_config)) {
+ nm_system_device_set_up_down_with_iface (priv->tundev, TRUE, NULL);
+
+ if (nm_system_apply_ip4_config (priv->parent_dev, priv->tundev, config, 0, TRUE)) {
+ NMNamedManager *named_mgr;
+
+ /* Add the VPN to DNS */
+ named_mgr = nm_named_manager_get ();
+ nm_named_manager_add_ip4_config (named_mgr, priv->tundev, config, NM_NAMED_IP_CONFIG_TYPE_VPN);
+ g_object_unref (named_mgr);
+
+ priv->ip4_config = config;
+
nm_info ("VPN connection '%s' (IP Config Get) complete.",
nm_vpn_connection_get_name (connection));
nm_vpn_connection_set_vpn_state (connection,
NM_VPN_CONNECTION_STATE_ACTIVATED,
NM_VPN_CONNECTION_STATE_REASON_NONE);
- } else {
- nm_warning ("VPN connection '%s' did not receive valid IP config information.",
- nm_vpn_connection_get_name (connection));
- nm_vpn_connection_set_vpn_state (connection,
- NM_VPN_CONNECTION_STATE_FAILED,
- NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID);
+ return;
}
+
+error:
+ nm_warning ("VPN connection '%s' did not receive valid IP config information.",
+ nm_vpn_connection_get_name (connection));
+ nm_vpn_connection_set_vpn_state (connection,
+ NM_VPN_CONNECTION_STATE_FAILED,
+ NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID);
+ g_object_unref (config);
}
static gboolean
@@ -631,6 +648,30 @@ nm_vpn_connection_get_banner (NMVPNConnection *connection)
return NM_VPN_CONNECTION_GET_PRIVATE (connection)->banner;
}
+NMIP4Config *
+nm_vpn_connection_get_ip4_config (NMVPNConnection *connection)
+{
+ g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
+
+ return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_config;
+}
+
+const char *
+nm_vpn_connection_get_ip_iface (NMVPNConnection *connection)
+{
+ g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
+
+ return NM_VPN_CONNECTION_GET_PRIVATE (connection)->tundev;
+}
+
+NMDevice *
+nm_vpn_connection_get_parent_device (NMVPNConnection *connection)
+{
+ g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
+
+ return NM_VPN_CONNECTION_GET_PRIVATE (connection)->parent_dev;
+}
+
void
nm_vpn_connection_fail (NMVPNConnection *connection,
NMVPNConnectionStateReason reason)
@@ -870,9 +911,12 @@ connection_state_changed (NMVPNConnection *connection,
if (priv->ip4_config) {
NMIP4Config *dev_ip4_config;
+ NMNamedManager *named_mgr;
/* Remove attributes of the VPN's IP4 Config */
- nm_system_vpn_device_unset_from_ip4_config (priv->parent_dev, priv->tundev, priv->ip4_config);
+ named_mgr = nm_named_manager_get ();
+ nm_named_manager_remove_ip4_config (named_mgr, priv->tundev, priv->ip4_config);
+ g_object_unref (named_mgr);
/* Reset routes, nameservers, and domains of the currently active device */
dev_ip4_config = nm_device_get_ip4_config (priv->parent_dev);
diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h
index b642023733..7007b0bbc5 100644
--- a/src/vpn-manager/nm-vpn-connection.h
+++ b/src/vpn-manager/nm-vpn-connection.h
@@ -70,5 +70,8 @@ void nm_vpn_connection_fail (NMVPNConnection *connect
NMVPNConnectionStateReason reason);
void nm_vpn_connection_disconnect (NMVPNConnection *connection,
NMVPNConnectionStateReason reason);
+NMIP4Config * nm_vpn_connection_get_ip4_config (NMVPNConnection *connection);
+const char * nm_vpn_connection_get_ip_iface (NMVPNConnection *connection);
+NMDevice * nm_vpn_connection_get_parent_device (NMVPNConnection *connection);
#endif /* NM_VPN_CONNECTION_H */
diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c
index 26c84e402a..e8e47c3a6d 100644
--- a/src/vpn-manager/nm-vpn-manager.c
+++ b/src/vpn-manager/nm-vpn-manager.c
@@ -20,6 +20,7 @@ typedef struct {
} NMVPNManagerPrivate;
enum {
+ CONNECTION_ACTIVATED,
CONNECTION_DEACTIVATED,
LAST_SIGNAL
@@ -128,6 +129,9 @@ connection_vpn_state_changed (NMVPNConnection *connection,
NMVPNManager *manager = NM_VPN_MANAGER (user_data);
switch (state) {
+ case NM_VPN_CONNECTION_STATE_ACTIVATED:
+ g_signal_emit (manager, signals[CONNECTION_ACTIVATED], 0, connection);
+ break;
case NM_VPN_CONNECTION_STATE_FAILED:
case NM_VPN_CONNECTION_STATE_DISCONNECTED:
g_signal_emit (manager, signals[CONNECTION_DEACTIVATED], 0, connection, state, reason);
@@ -259,6 +263,27 @@ nm_vpn_manager_add_active_connections (NMVPNManager *manager,
}
}
+GSList *
+nm_vpn_manager_get_active_connections (NMVPNManager *manager)
+{
+ NMVPNManagerPrivate *priv;
+ GSList *iter;
+ GSList *list = NULL;
+
+ g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), NULL);
+
+ priv = NM_VPN_MANAGER_GET_PRIVATE (manager);
+ for (iter = priv->services; iter; iter = g_slist_next (iter)) {
+ GSList *active, *elt;
+
+ active = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (iter->data));
+ for (elt = active; elt; elt = g_slist_next (elt))
+ list = g_slist_append (list, g_object_ref (NM_VPN_CONNECTION (elt->data)));
+ }
+
+ return list;
+}
+
NMVPNManager *
nm_vpn_manager_get (void)
{
@@ -301,6 +326,14 @@ nm_vpn_manager_class_init (NMVPNManagerClass *manager_class)
object_class->finalize = finalize;
/* signals */
+ signals[CONNECTION_ACTIVATED] =
+ g_signal_new ("connection-activated",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
signals[CONNECTION_DEACTIVATED] =
g_signal_new ("connection-deactivated",
G_OBJECT_CLASS_TYPE (object_class),
diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h
index c4bb605e71..9d3bf4850a 100644
--- a/src/vpn-manager/nm-vpn-manager.h
+++ b/src/vpn-manager/nm-vpn-manager.h
@@ -61,4 +61,6 @@ void nm_vpn_manager_add_active_connections (NMVPNManager *manager,
NMConnection *filter,
GPtrArray *list);
+GSList *nm_vpn_manager_get_active_connections (NMVPNManager *manager);
+
#endif /* NM_VPN_VPN_MANAGER_H */