2008-10-11 Dan Williams <dcbw@redhat.com>

Add support for VPN subnet gateways (bgo #549196)

	* include/NetworkManager.h
		- Add key for internal VPN subnet gateway

	* src/vpn-manager/nm-vpn-connection.c
		- (ip_address_to_string): return a const from a static buffer so we
			don't leak a lot of strings
		- (print_vpn_config): print internal VPN gateway as well
		- (nm_vpn_connection_ip4_config_get): grab internal VPN gateway from
			VPN service too
		- (nm_vpn_connection_get_ip4_internal_gateway): new function

	* src/NetworkManagerSystem.c
	  src/NetworkManagerSystem.h
		- (nm_system_device_replace_default_ip4_route): split into two, one for
			VPN connections and one for normal devices
		- (replace_default_ip4_route): break out route stuff into its own function
		- (nm_system_replace_default_ip4_route_vpn,
		   nm_system_replace_default_ip4_route): simplify by having two cases,
			one for VPNs and one for normal devices

	* src/NetworkManagerPolicy.c
		- (update_routing_and_dns): simplify, use split default route replacement
			functions



git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4169 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams
2008-10-11 14:26:41 +00:00
parent abecdae82f
commit 1c0a0ec4a8
7 changed files with 184 additions and 84 deletions

View File

@@ -1,3 +1,31 @@
2008-10-11 Dan Williams <dcbw@redhat.com>
Add support for VPN subnet gateways (bgo #549196)
* include/NetworkManager.h
- Add key for internal VPN subnet gateway
* src/vpn-manager/nm-vpn-connection.c
- (ip_address_to_string): return a const from a static buffer so we
don't leak a lot of strings
- (print_vpn_config): print internal VPN gateway as well
- (nm_vpn_connection_ip4_config_get): grab internal VPN gateway from
VPN service too
- (nm_vpn_connection_get_ip4_internal_gateway): new function
* src/NetworkManagerSystem.c
src/NetworkManagerSystem.h
- (nm_system_device_replace_default_ip4_route): split into two, one for
VPN connections and one for normal devices
- (replace_default_ip4_route): break out route stuff into its own function
- (nm_system_replace_default_ip4_route_vpn,
nm_system_replace_default_ip4_route): simplify by having two cases,
one for VPNs and one for normal devices
* src/NetworkManagerPolicy.c
- (update_routing_and_dns): simplify, use split default route replacement
functions
2008-10-10 Dan Williams <dcbw@redhat.com> 2008-10-10 Dan Williams <dcbw@redhat.com>
Rework default route handling to consolidate decisions in the policy, Rework default route handling to consolidate decisions in the policy,

View File

@@ -112,7 +112,9 @@ typedef enum {
NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG
} NMVPNPluginFailure; } NMVPNPluginFailure;
#define NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY "gateway"
#define NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY "gateway"
#define NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY "internal-gateway"
#define NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS "address" #define NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS "address"
#define NM_VPN_PLUGIN_IP4_CONFIG_PTP "ptp" #define NM_VPN_PLUGIN_IP4_CONFIG_PTP "ptp"
#define NM_VPN_PLUGIN_IP4_CONFIG_PREFIX "prefix" #define NM_VPN_PLUGIN_IP4_CONFIG_PREFIX "prefix"
@@ -125,4 +127,8 @@ typedef enum {
#define NM_VPN_PLUGIN_IP4_CONFIG_BANNER "banner" #define NM_VPN_PLUGIN_IP4_CONFIG_BANNER "banner"
#define NM_VPN_PLUGIN_IP4_CONFIG_ROUTES "routes" #define NM_VPN_PLUGIN_IP4_CONFIG_ROUTES "routes"
/* Deprecated */
#define NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY
#endif /* NETWORK_MANAGER_VPN_H */ #endif /* NETWORK_MANAGER_VPN_H */

View File

@@ -475,13 +475,11 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
NMNamedManager *named_mgr; NMNamedManager *named_mgr;
GSList *devices = NULL, *iter, *vpns; GSList *devices = NULL, *iter, *vpns;
NMIP4Config *ip4_config = NULL; NMIP4Config *ip4_config = NULL;
const NMSettingIP4Address *addr;
const char *ip_iface = NULL; const char *ip_iface = NULL;
const char *parent_iface = NULL;
NMVPNConnection *vpn = NULL; NMVPNConnection *vpn = NULL;
NMConnection *connection = NULL; NMConnection *connection = NULL;
NMSettingConnection *s_con = NULL; NMSettingConnection *s_con = NULL;
guint32 parent_mss = 0;
guint32 gateway = 0;
best = get_best_device (policy->manager, &best_req); best = get_best_device (policy->manager, &best_req);
if (!best) if (!best)
@@ -502,22 +500,24 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
/* VPNs are the default route only if they don't have custom routes */ /* VPNs are the default route only if they don't have custom routes */
if (vpn) { if (vpn) {
NMIP4Config *vpn_config; ip4_config = nm_vpn_connection_get_ip4_config (vpn);
if (nm_ip4_config_get_num_routes (ip4_config) == 0) {
vpn_config = nm_vpn_connection_get_ip4_config (vpn);
if (nm_ip4_config_get_num_routes (vpn_config) == 0) {
NMIP4Config *parent_ip4; NMIP4Config *parent_ip4;
NMDevice *parent; NMDevice *parent;
connection = nm_vpn_connection_get_connection (vpn);
ip_iface = nm_vpn_connection_get_ip_iface (vpn); ip_iface = nm_vpn_connection_get_ip_iface (vpn);
ip4_config = vpn_config; connection = nm_vpn_connection_get_connection (vpn);
addr = nm_ip4_config_get_address (ip4_config, 0);
parent = nm_vpn_connection_get_parent_device (vpn); parent = nm_vpn_connection_get_parent_device (vpn);
parent_iface = nm_device_get_ip_iface (parent);
parent_ip4 = nm_device_get_ip4_config (parent); parent_ip4 = nm_device_get_ip4_config (parent);
if (parent_ip4)
parent_mss = nm_ip4_config_get_mss (parent_ip4); nm_system_replace_default_ip4_route_vpn (ip_iface,
addr->gateway,
nm_vpn_connection_get_ip4_internal_gateway (vpn),
nm_ip4_config_get_mss (ip4_config),
nm_device_get_ip_iface (parent),
nm_ip4_config_get_mss (parent_ip4));
dns_type = NM_NAMED_IP_CONFIG_TYPE_VPN; dns_type = NM_NAMED_IP_CONFIG_TYPE_VPN;
} }
@@ -526,15 +526,13 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
/* The best device gets the default route if a VPN connection didn't */ /* The best device gets the default route if a VPN connection didn't */
if (!ip_iface || !ip4_config) { if (!ip_iface || !ip4_config) {
const NMSettingIP4Address *addr;
connection = nm_act_request_get_connection (best_req); connection = nm_act_request_get_connection (best_req);
ip_iface = nm_device_get_ip_iface (best); ip_iface = nm_device_get_ip_iface (best);
ip4_config = nm_device_get_ip4_config (best); ip4_config = nm_device_get_ip4_config (best);
if (ip4_config) { g_assert (ip4_config);
addr = nm_ip4_config_get_address (ip4_config, 0); addr = nm_ip4_config_get_address (ip4_config, 0);
gateway = addr->gateway;
} nm_system_replace_default_ip4_route (ip_iface, addr->gateway, nm_ip4_config_get_mss (ip4_config));
dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE; dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
} }
@@ -545,13 +543,6 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
goto out; 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 /* Update the default active connection. Only mark the new default
* active connection after setting default = FALSE on all other connections * active connection after setting default = FALSE on all other connections
* first. The order is important, we don't want two connections marked * first. The order is important, we don't want two connections marked

View File

@@ -533,35 +533,25 @@ error:
return NULL; return NULL;
} }
/* static int
* nm_system_replace_default_ip4_route replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss)
*
* Replace default IPv4 route with one via the current device
*
*/
void
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 = NULL; struct rtnl_route *route = NULL;
struct rtnl_route *gw_route = NULL;
struct nl_handle *nlh; struct nl_handle *nlh;
struct nl_addr *gw_addr = NULL; struct nl_addr *gw_addr = NULL;
int iface_idx, err; int iface_idx, err = -1;
gboolean success = FALSE;
g_return_val_if_fail (iface != NULL, -1);
nlh = nm_netlink_get_default_handle (); nlh = nm_netlink_get_default_handle ();
g_return_if_fail (nlh != NULL); g_return_val_if_fail (nlh != NULL, -1);
iface_idx = nm_netlink_iface_to_index (iface); iface_idx = nm_netlink_iface_to_index (iface);
if (iface_idx < 0) if (iface_idx < 0)
return; return -1;
route = rtnl_route_alloc(); route = rtnl_route_alloc();
g_return_if_fail (route != NULL); g_return_val_if_fail (route != NULL, -1);
rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE); rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
rtnl_route_set_oif (route, iface_idx); rtnl_route_set_oif (route, iface_idx);
@@ -580,36 +570,97 @@ nm_system_device_replace_default_ip4_route (const char *iface,
/* Add the new default route */ /* Add the new default route */
err = rtnl_route_add (nlh, route, NLM_F_REPLACE); err = rtnl_route_add (nlh, route, NLM_F_REPLACE);
if (err == 0) {
/* Everything good */ out:
success = TRUE; rtnl_route_put (route);
goto out; return err;
} else if (err != -ESRCH) { }
nm_warning ("rtnl_route_add() returned error %s (%d)\n%s",
strerror (err), err, nl_geterror()); /*
goto out; * nm_system_replace_default_ip4_route_vpn
*
* Replace default IPv4 route with one via the current device
*
*/
gboolean
nm_system_replace_default_ip4_route_vpn (const char *iface,
guint32 ext_gw,
guint32 int_gw,
guint32 mss,
const char *parent_iface,
guint32 parent_mss)
{
struct rtnl_route *gw_route = NULL;
struct nl_handle *nlh;
gboolean success = FALSE;
int err;
nlh = nm_netlink_get_default_handle ();
g_return_val_if_fail (nlh != NULL, FALSE);
err = replace_default_ip4_route (iface, int_gw, mss);
if (err != -ESRCH) {
nm_warning ("replace_default_ip4_route() returned error %s (%d)",
strerror (err), err);
return FALSE;
} }
/* Try adding a direct route to the gateway first */ /* Try adding a direct route to the gateway first */
gw_route = add_ip4_route_to_gateway (parent_iface ? parent_iface : iface, gw_route = add_ip4_route_to_gateway (parent_iface, ext_gw, parent_mss);
gw,
parent_iface ? parent_mss : mss);
if (!gw_route) if (!gw_route)
goto out; return FALSE;
/* Try adding the original route again */ /* Try adding the original route again */
err = rtnl_route_add (nlh, route, NLM_F_REPLACE); err = replace_default_ip4_route (iface, int_gw, mss);
if (err != 0) { if (err != 0) {
rtnl_route_del (nlh, gw_route, 0); rtnl_route_del (nlh, gw_route, 0);
nm_warning ("Failed to set IPv4 default route on '%s': %s", iface, nl_geterror ()); nm_warning ("Failed to set IPv4 default route on '%s': %s", iface, nl_geterror ());
} else
success = TRUE;
rtnl_route_put (gw_route);
return success;
}
/*
* nm_system_replace_default_ip4_route
*
* Replace default IPv4 route with one via the current device
*
*/
gboolean
nm_system_replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss)
{
struct rtnl_route *gw_route = NULL;
struct nl_handle *nlh;
gboolean success = FALSE;
int err;
nlh = nm_netlink_get_default_handle ();
g_return_val_if_fail (nlh != NULL, FALSE);
err = replace_default_ip4_route (iface, gw, mss);
if (err != -ESRCH) {
nm_warning ("replace_default_ip4_route() returned error %s (%d)",
strerror (err), err);
return FALSE;
} }
out: /* Try adding a direct route to the gateway first */
if (gw_route) gw_route = add_ip4_route_to_gateway (iface, gw, mss);
rtnl_route_put (gw_route); if (!gw_route)
return FALSE;
if (route) /* Try adding the original route again */
rtnl_route_put (route); err = replace_default_ip4_route (iface, gw, mss);
if (err != 0) {
rtnl_route_del (nlh, gw_route, 0);
nm_warning ("Failed to set IPv4 default route on '%s': %s", iface, nl_geterror ());
} else
success = TRUE;
rtnl_route_put (gw_route);
return success;
} }
/* /*

View File

@@ -34,8 +34,13 @@
void nm_system_device_flush_ip4_routes (NMDevice *dev); void nm_system_device_flush_ip4_routes (NMDevice *dev);
void nm_system_device_flush_ip4_routes_with_iface (const char *iface); void nm_system_device_flush_ip4_routes_with_iface (const char *iface);
void nm_system_device_replace_default_ip4_route (const char *iface, gboolean nm_system_replace_default_ip4_route (const char *iface,
guint32 gw, guint32 gw,
guint32 mss);
gboolean nm_system_replace_default_ip4_route_vpn (const char *iface,
guint32 ext_gw,
guint32 int_gw,
guint32 mss, guint32 mss,
const char *parent_iface, const char *parent_iface,
guint32 parent_mss); guint32 parent_mss);

View File

@@ -71,6 +71,7 @@ typedef struct {
DBusGProxy *proxy; DBusGProxy *proxy;
guint ipconfig_timeout; guint ipconfig_timeout;
NMIP4Config *ip4_config; NMIP4Config *ip4_config;
guint32 ip4_internal_gw;
char *tundev; char *tundev;
char *tapdev; char *tapdev;
char *banner; char *banner;
@@ -293,13 +294,13 @@ static const char *
ip_address_to_string (guint32 numeric) ip_address_to_string (guint32 numeric)
{ {
struct in_addr temp_addr; struct in_addr temp_addr;
char buf[INET_ADDRSTRLEN+1]; static char buf[INET_ADDRSTRLEN + 1];
memset (&buf, '\0', sizeof (buf)); memset (&buf, '\0', sizeof (buf));
temp_addr.s_addr = numeric; temp_addr.s_addr = numeric;
if (inet_ntop (AF_INET, &temp_addr, buf, INET_ADDRSTRLEN)) { if (inet_ntop (AF_INET, &temp_addr, buf, INET_ADDRSTRLEN)) {
return g_strdup (buf); return buf;
} else { } else {
nm_warning ("%s: error converting IP4 address 0x%X", nm_warning ("%s: error converting IP4 address 0x%X",
__func__, ntohl (temp_addr.s_addr)); __func__, ntohl (temp_addr.s_addr));
@@ -309,6 +310,7 @@ ip_address_to_string (guint32 numeric)
static void static void
print_vpn_config (NMIP4Config *config, print_vpn_config (NMIP4Config *config,
guint32 internal_gw,
const char *tundev, const char *tundev,
const char *banner) const char *banner)
{ {
@@ -322,6 +324,8 @@ print_vpn_config (NMIP4Config *config,
addr = nm_ip4_config_get_address (config, 0); addr = nm_ip4_config_get_address (config, 0);
nm_info ("VPN Gateway: %s", ip_address_to_string (addr->gateway)); nm_info ("VPN Gateway: %s", ip_address_to_string (addr->gateway));
if (internal_gw)
nm_info ("Internal Gateway: %s", ip_address_to_string (internal_gw));
nm_info ("Tunnel Device: %s", tundev); nm_info ("Tunnel Device: %s", tundev);
nm_info ("Internal IP4 Address: %s", ip_address_to_string (addr->address)); nm_info ("Internal IP4 Address: %s", ip_address_to_string (addr->address));
nm_info ("Internal IP4 Prefix: %d", addr->prefix); nm_info ("Internal IP4 Prefix: %d", addr->prefix);
@@ -385,7 +389,13 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
goto error; goto error;
} }
val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY); /* Internal address of the VPN subnet's gateway */
val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY);
if (val)
priv->ip4_internal_gw = g_value_get_uint (val);
/* External world-visible address of the VPN server */
val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY);
if (val) if (val)
addr->gateway = g_value_get_uint (val); addr->gateway = g_value_get_uint (val);
@@ -456,7 +466,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
g_slist_free (routes); g_slist_free (routes);
} }
print_vpn_config (config, priv->tundev, priv->banner); print_vpn_config (config, priv->ip4_internal_gw, priv->tundev, priv->banner);
/* Merge in user overrides from the NMConnection's IPv4 setting */ /* 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)); s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (priv->connection, NM_TYPE_SETTING_IP4_CONFIG));
@@ -672,6 +682,14 @@ nm_vpn_connection_get_parent_device (NMVPNConnection *connection)
return NM_VPN_CONNECTION_GET_PRIVATE (connection)->parent_dev; return NM_VPN_CONNECTION_GET_PRIVATE (connection)->parent_dev;
} }
guint32
nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection)
{
g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), 0);
return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_internal_gw;
}
void void
nm_vpn_connection_fail (NMVPNConnection *connection, nm_vpn_connection_fail (NMVPNConnection *connection,
NMVPNConnectionStateReason reason) NMVPNConnectionStateReason reason)

View File

@@ -73,5 +73,6 @@ void nm_vpn_connection_disconnect (NMVPNConnection *connect
NMIP4Config * nm_vpn_connection_get_ip4_config (NMVPNConnection *connection); NMIP4Config * nm_vpn_connection_get_ip4_config (NMVPNConnection *connection);
const char * nm_vpn_connection_get_ip_iface (NMVPNConnection *connection); const char * nm_vpn_connection_get_ip_iface (NMVPNConnection *connection);
NMDevice * nm_vpn_connection_get_parent_device (NMVPNConnection *connection); NMDevice * nm_vpn_connection_get_parent_device (NMVPNConnection *connection);
guint32 nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection);
#endif /* NM_VPN_CONNECTION_H */ #endif /* NM_VPN_CONNECTION_H */