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:
56
ChangeLog
56
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
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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 */
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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 */
|
||||
|
@@ -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),
|
||||
|
@@ -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 */
|
||||
|
Reference in New Issue
Block a user