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



git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4167 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams
2008-10-10 23:05:45 +00:00
parent 9b82c1e92f
commit ad7a46d867
11 changed files with 420 additions and 223 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
@@ -461,35 +466,22 @@ 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,7 +489,68 @@ 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
@@ -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 */
@@ -617,6 +672,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);

View File

@@ -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 */

View File

@@ -273,18 +273,59 @@ add_ip4_addresses (NMIP4Config *config, const char *iface)
return TRUE;
}
static void
add_vpn_gateway_route (NMDevice *device, const char *iface, NMIP4Config *config)
{
NMIP4Config *ad_config;
guint32 ad_gw = 0, vpn_gw = 0, i;
const NMSettingIP4Address *tmp;
g_return_if_fail (NM_IS_DEVICE (device));
ad_config = nm_device_get_ip4_config (device);
g_return_if_fail (ad_config != NULL);
/* 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 (!ad_gw)
return;
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;
}
}
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_device_set_from_ip4_config
* nm_system_apply_ip4_config
*
* Set IPv4 configuration of the device from an NMIP4Config object.
*
*/
gboolean
nm_system_device_set_from_ip4_config (const char *iface,
nm_system_apply_ip4_config (NMDevice *device,
const char *iface,
NMIP4Config *config,
int priority)
int priority,
gboolean is_vpn)
{
int len, i;
int i;
g_return_val_if_fail (iface != NULL, FALSE);
g_return_val_if_fail (config != NULL, FALSE);
@@ -292,10 +333,12 @@ nm_system_device_set_from_ip4_config (const char *iface,
if (!add_ip4_addresses (config, iface))
return FALSE;
if (is_vpn)
add_vpn_gateway_route (device, iface, config);
sleep (1);
len = nm_ip4_config_get_num_routes (config);
for (i = 0; i < len; i++) {
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,
@@ -315,112 +358,6 @@ nm_system_device_set_from_ip4_config (const char *iface,
return TRUE;
}
/*
* nm_system_vpn_device_set_from_ip4_config
*
* Set IPv4 configuration of a VPN device from an NMIP4Config object.
*
*/
gboolean
nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device,
const char *iface,
NMIP4Config *config)
{
NMIP4Config *ad_config = NULL;
NMNamedManager *named_mgr;
int num;
int i;
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;
/* Set the MTU */
if (nm_ip4_config_get_mtu (config))
nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config));
/* Set routes */
num = nm_ip4_config_get_num_routes (config);
for (i = 0; i < num; 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));
}
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);
named_mgr = nm_named_manager_get ();
nm_named_manager_remove_ip4_config (named_mgr, iface, config);
g_object_unref (named_mgr);
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,40 +590,25 @@ 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)
/* 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;
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 ());
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);
if (route)
rtnl_route_put (route);
}

View File

@@ -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,
gboolean nm_system_apply_ip4_config (NMDevice *device,
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);
int priority,
gboolean is_vpn);
gboolean nm_system_device_set_up_down (NMDevice *dev,
gboolean up,

View File

@@ -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);

View File

@@ -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"
@@ -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 {
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);

View File

@@ -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 */

View File

@@ -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),

View File

@@ -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 */