diff --git a/ChangeLog b/ChangeLog index 4d08a2171..d16e7c6fd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2008-10-11 Dan Williams + + 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 Rework default route handling to consolidate decisions in the policy, diff --git a/include/NetworkManagerVPN.h b/include/NetworkManagerVPN.h index 84766544e..952d08aea 100644 --- a/include/NetworkManagerVPN.h +++ b/include/NetworkManagerVPN.h @@ -112,17 +112,23 @@ typedef enum { NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG } NMVPNPluginFailure; -#define NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY "gateway" -#define NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS "address" -#define NM_VPN_PLUGIN_IP4_CONFIG_PTP "ptp" -#define NM_VPN_PLUGIN_IP4_CONFIG_PREFIX "prefix" -#define NM_VPN_PLUGIN_IP4_CONFIG_DNS "dns" -#define NM_VPN_PLUGIN_IP4_CONFIG_NBNS "nbns" -#define NM_VPN_PLUGIN_IP4_CONFIG_MSS "mss" -#define NM_VPN_PLUGIN_IP4_CONFIG_MTU "mtu" -#define NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV "tundev" -#define NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN "domain" -#define NM_VPN_PLUGIN_IP4_CONFIG_BANNER "banner" -#define NM_VPN_PLUGIN_IP4_CONFIG_ROUTES "routes" + +#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_PTP "ptp" +#define NM_VPN_PLUGIN_IP4_CONFIG_PREFIX "prefix" +#define NM_VPN_PLUGIN_IP4_CONFIG_DNS "dns" +#define NM_VPN_PLUGIN_IP4_CONFIG_NBNS "nbns" +#define NM_VPN_PLUGIN_IP4_CONFIG_MSS "mss" +#define NM_VPN_PLUGIN_IP4_CONFIG_MTU "mtu" +#define NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV "tundev" +#define NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN "domain" +#define NM_VPN_PLUGIN_IP4_CONFIG_BANNER "banner" +#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 */ diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index 46c51e9d0..b4063ebb9 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -475,13 +475,11 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update) NMNamedManager *named_mgr; GSList *devices = NULL, *iter, *vpns; NMIP4Config *ip4_config = NULL; + const NMSettingIP4Address *addr; 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) @@ -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 */ if (vpn) { - NMIP4Config *vpn_config; - - vpn_config = nm_vpn_connection_get_ip4_config (vpn); - if (nm_ip4_config_get_num_routes (vpn_config) == 0) { + ip4_config = nm_vpn_connection_get_ip4_config (vpn); + if (nm_ip4_config_get_num_routes (ip4_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; + 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_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); + + 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; } @@ -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 */ 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; - } + g_assert (ip4_config); + addr = nm_ip4_config_get_address (ip4_config, 0); + + 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; } @@ -545,13 +543,6 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update) 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 diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index 653e90a71..54861db3e 100644 --- a/src/NetworkManagerSystem.c +++ b/src/NetworkManagerSystem.c @@ -533,35 +533,25 @@ error: return NULL; } -/* - * nm_system_replace_default_ip4_route - * - * 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) +static int +replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss) { 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; + int iface_idx, err = -1; + + g_return_val_if_fail (iface != NULL, -1); 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); if (iface_idx < 0) - return; + return -1; 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_oif (route, iface_idx); @@ -580,36 +570,97 @@ nm_system_device_replace_default_ip4_route (const char *iface, /* 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", - strerror (err), err, nl_geterror()); - goto out; + +out: + rtnl_route_put (route); + return err; +} + +/* + * 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 */ - gw_route = add_ip4_route_to_gateway (parent_iface ? parent_iface : iface, - gw, - parent_iface ? parent_mss : mss); + gw_route = add_ip4_route_to_gateway (parent_iface, ext_gw, parent_mss); if (!gw_route) - goto out; + return FALSE; /* 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) { 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; +} + +/* + * 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: - if (gw_route) - rtnl_route_put (gw_route); + /* Try adding a direct route to the gateway first */ + gw_route = add_ip4_route_to_gateway (iface, gw, mss); + if (!gw_route) + return FALSE; - if (route) - rtnl_route_put (route); + /* Try adding the original route again */ + 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; } /* diff --git a/src/NetworkManagerSystem.h b/src/NetworkManagerSystem.h index bd8df4af2..a9d927686 100644 --- a/src/NetworkManagerSystem.h +++ b/src/NetworkManagerSystem.h @@ -34,11 +34,16 @@ 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_replace_default_ip4_route (const char *iface, - guint32 gw, - guint32 mss, - const char *parent_iface, - guint32 parent_mss); +gboolean nm_system_replace_default_ip4_route (const char *iface, + guint32 gw, + guint32 mss); + +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); void nm_system_device_flush_ip4_addresses (NMDevice *dev); void nm_system_device_flush_ip4_addresses_with_iface (const char *iface); diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 90c3691c3..77075a587 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -71,6 +71,7 @@ typedef struct { DBusGProxy *proxy; guint ipconfig_timeout; NMIP4Config *ip4_config; + guint32 ip4_internal_gw; char *tundev; char *tapdev; char *banner; @@ -293,13 +294,13 @@ static const char * ip_address_to_string (guint32 numeric) { struct in_addr temp_addr; - char buf[INET_ADDRSTRLEN+1]; + static char buf[INET_ADDRSTRLEN + 1]; memset (&buf, '\0', sizeof (buf)); temp_addr.s_addr = numeric; if (inet_ntop (AF_INET, &temp_addr, buf, INET_ADDRSTRLEN)) { - return g_strdup (buf); + return buf; } else { nm_warning ("%s: error converting IP4 address 0x%X", __func__, ntohl (temp_addr.s_addr)); @@ -309,8 +310,9 @@ ip_address_to_string (guint32 numeric) static void print_vpn_config (NMIP4Config *config, - const char *tundev, - const char *banner) + guint32 internal_gw, + const char *tundev, + const char *banner) { const NMSettingIP4Address *addr; char * dns_domain = NULL; @@ -322,6 +324,8 @@ print_vpn_config (NMIP4Config *config, addr = nm_ip4_config_get_address (config, 0); 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 ("Internal IP4 Address: %s", ip_address_to_string (addr->address)); nm_info ("Internal IP4 Prefix: %d", addr->prefix); @@ -385,7 +389,13 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, 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) addr->gateway = g_value_get_uint (val); @@ -456,7 +466,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, 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 */ 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; } +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 nm_vpn_connection_fail (NMVPNConnection *connection, NMVPNConnectionStateReason reason) diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h index 7007b0bbc..6c54d5e68 100644 --- a/src/vpn-manager/nm-vpn-connection.h +++ b/src/vpn-manager/nm-vpn-connection.h @@ -73,5 +73,6 @@ void nm_vpn_connection_disconnect (NMVPNConnection *connect 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); +guint32 nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection); #endif /* NM_VPN_CONNECTION_H */