diff --git a/ChangeLog b/ChangeLog index 1b1eb52061..006db9783e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2008-06-06 Dan Williams + + Patch from Tambet Ingo + + * src/NetworkManagerSystem.c + src/NetworkManagerSystem.h + - (nm_system_device_add_ip4_route_via_device_with_iface): remove + - (nm_system_device_set_from_ip4_config): remove unused route_to_iface + - (nm_system_device_set_ip4_route): clean up + - (nm_system_vpn_device_set_from_ip4_config): clean up, add VPN routes + + * src/nm-device.c + - (nm_device_set_ip4_config): remove unused route_to_iface bits + + * src/vpn-manager/nm-vpn-connection.c + - (ip_address_to_string): new function + - (print_vpn_config): use ip_address_to_string + - (merge_vpn_routes): add user-defined routes to the ip4 config + - (nm_vpn_connection_ip4_config_get): add routes the VPN server sent + + * include/NetworkManagerVPN.h + - Add 'routes' key + 2008-06-05 Dan Williams Patch from Markus Becker diff --git a/include/NetworkManagerVPN.h b/include/NetworkManagerVPN.h index ee81734d16..8a6d7a7d89 100644 --- a/include/NetworkManagerVPN.h +++ b/include/NetworkManagerVPN.h @@ -116,5 +116,6 @@ typedef enum NMVPNConnectionStateReason #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" #endif /* NETWORK_MANAGER_VPN_H */ diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index fccef9b674..1d61ff3e62 100644 --- a/src/NetworkManagerSystem.c +++ b/src/NetworkManagerSystem.c @@ -61,134 +61,145 @@ #include #include - -/* - * nm_system_device_set_ip4_route - * - */ static gboolean -nm_system_device_set_ip4_route (const char *iface, - NMIP4Config *iface_config, - guint32 ip4_gateway, - guint32 ip4_dest, - int prefix, - int mss) +route_in_same_subnet (NMIP4Config *config, guint32 dest, guint32 netmask) { - gboolean success = FALSE; - struct rtnl_route *route = NULL; - struct rtnl_route *route2 = NULL; - struct nl_handle *nlh = NULL; - struct nl_addr *gw_addr = NULL; - struct nl_addr *dest_addr = NULL; - int err, iface_idx, i; + int num; + int i; - /* - * Zero is not a legal gateway and the ioctl will fail. But zero is a - * way of saying "no route" so we just return here. Hopefully the - * caller flushed the routes, first. - */ - if (ip4_gateway == 0) - return TRUE; + num = nm_ip4_config_get_num_addresses (config); + for (i = 0; i < num; i++) { + const NMSettingIP4Address *cfg_addr; - /* - * Do not add the route if the destination is on the same subnet. - */ - if (iface_config) { - for (i = 0; i < nm_ip4_config_get_num_addresses (iface_config); i++) { - const NMSettingIP4Address *cfg_addr; + cfg_addr = nm_ip4_config_get_address (config, i); + if ((dest & netmask) == (cfg_addr->address & cfg_addr->netmask)) + return TRUE; + } - cfg_addr = nm_ip4_config_get_address (iface_config, i); - if ((ip4_dest & cfg_addr->netmask) == (cfg_addr->address & cfg_addr->netmask)) - return TRUE; + return FALSE; +} + +static struct rtnl_route * +create_route (int iface_idx, int mss) +{ + struct rtnl_route *route; + + route = rtnl_route_alloc (); + if (route) { + rtnl_route_set_oif (route, iface_idx); + + if (mss && rtnl_route_set_metric (route, RTAX_ADVMSS, mss) < 0) + nm_warning ("Could not set mss"); + } else + nm_warning ("Could not allocate route"); + + return route; +} + +static int +netmask_to_prefix (guint32 netmask) +{ + guchar *p; + guchar *end; + int prefix = 0; + + p = (guchar *) &netmask; + end = p + sizeof (guint32); + + while ((*p == 0xFF) && p < end) { + prefix += 8; + p++; + } + + if (p < end) { + guchar v = *p; + + while (v) { + prefix++; + v <<= 1; } } + return prefix; +} + +static void +nm_system_device_set_ip4_route (const char *iface, + NMIP4Config *iface_config, + guint32 ip4_dest, + guint32 ip4_netmask, + guint32 ip4_gateway, + int mss) +{ + struct nl_handle *nlh; + struct rtnl_route *route; + struct nl_addr *dest_addr; + struct nl_addr *gw_addr = NULL; + int err, iface_idx; + + if (iface_config && route_in_same_subnet (iface_config, ip4_dest, ip4_netmask)) + return; + nlh = nm_netlink_get_default_handle (); - g_return_val_if_fail (nlh != NULL, FALSE); + g_return_if_fail (nlh != NULL); iface_idx = nm_netlink_iface_to_index (iface); - g_return_val_if_fail (iface_idx >= 0, FALSE); + g_return_if_fail (iface_idx >= 0); - route = rtnl_route_alloc (); - g_return_val_if_fail (route != NULL, FALSE); - - rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE); - rtnl_route_set_oif (route, iface_idx); - - gw_addr = nl_addr_build (AF_INET, &ip4_gateway, sizeof (ip4_gateway)); - if (gw_addr == NULL) - goto out; - rtnl_route_set_gateway (route, gw_addr); + route = create_route (iface_idx, mss); + g_return_if_fail (route != NULL); + /* Destination */ dest_addr = nl_addr_build (AF_INET, &ip4_dest, sizeof (ip4_dest)); - if (dest_addr == NULL) - goto out; - nl_addr_set_prefixlen (dest_addr, prefix); + g_return_if_fail (dest_addr != NULL); + nl_addr_set_prefixlen (dest_addr, netmask_to_prefix (ip4_netmask)); + rtnl_route_set_dst (route, dest_addr); nl_addr_put (dest_addr); - if (mss) { - if (rtnl_route_set_metric (route, RTAX_ADVMSS, mss) < 0) - goto out; + /* Gateway */ + if (ip4_gateway) { + gw_addr = nl_addr_build (AF_INET, &ip4_gateway, sizeof (ip4_gateway)); + if (gw_addr) { + rtnl_route_set_gateway (route, gw_addr); + rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE); + } else { + nm_warning ("Invalid gateway"); + rtnl_route_put (route); + return; + } } + /* Add the route */ err = rtnl_route_add (nlh, route, 0); - if (err == 0) { - /* Everything good */ - success = TRUE; - goto out; + if (err == ESRCH && ip4_gateway) { + /* Gateway might be over a bridge; try adding a route to gateway first */ + struct rtnl_route *route2; + + route2 = create_route (iface_idx, mss); + if (route2) { + /* Add route to gateway over bridge */ + rtnl_route_set_dst (route2, gw_addr); + err = rtnl_route_add (nlh, route2, 0); + if (!err) { + /* Try adding the route again */ + err = rtnl_route_add (nlh, route, 0); + if (err) + rtnl_route_del (nlh, route2, 0); + } + + rtnl_route_put (route2); + } } - if (err != ESRCH) { - nm_warning ("Failed to set IPv4 default route on '%s': %s", - iface, - nl_geterror ()); - goto out; - } - - /* Gateway might be over a bridge; try adding a route to gateway first */ - route2 = rtnl_route_alloc (); - if (route2 == NULL) - goto out; - rtnl_route_set_oif (route2, iface_idx); - rtnl_route_set_dst (route2, gw_addr); + if (err) + nm_warning ("Failed to set IPv4 route on '%s': %s", iface, nl_geterror ()); - 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) { - success = TRUE; - } else { - rtnl_route_del (nlh, route2, 0); - nm_warning ("Failed to set IPv4 default route on '%s': %s", - iface, - nl_geterror ()); - } - -out: + rtnl_route_put (route); if (gw_addr) nl_addr_put (gw_addr); - if (route2) - rtnl_route_put (route2); - if (route) - rtnl_route_put (route); - return success; } - typedef struct { const char *iface; int ifindex; @@ -275,33 +286,6 @@ add_ip4_addresses (NMIP4Config *config, const char *iface) return TRUE; } -static int -netmask_to_prefix (guint32 netmask) -{ - guchar *p; - guchar *end; - int prefix = 0; - - p = (guchar *) &netmask; - end = p + sizeof (guint32); - - while ((*p == 0xFF) && p < end) { - prefix += 8; - p++; - } - - if (p < end) { - guchar v = *p; - - while (v) { - prefix++; - v <<= 1; - } - } - - return prefix; -} - /* * nm_system_device_set_from_ip4_config * @@ -310,8 +294,7 @@ netmask_to_prefix (guint32 netmask) */ gboolean nm_system_device_set_from_ip4_config (const char *iface, - NMIP4Config *config, - gboolean route_to_iface) + NMIP4Config *config) { int len, i; @@ -328,9 +311,9 @@ nm_system_device_set_from_ip4_config (const char *iface, const NMSettingIP4Address *route = nm_ip4_config_get_static_route (config, i); nm_system_device_set_ip4_route (iface, config, - route->gateway, route->address, - netmask_to_prefix (route->netmask), + route->netmask, + route->gateway, nm_ip4_config_get_mss (config)); } @@ -349,11 +332,11 @@ nm_system_device_set_from_ip4_config (const char *iface, gboolean nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device, const char *iface, - NMIP4Config *config, - GSList *routes) + NMIP4Config *config) { NMIP4Config *ad_config = NULL; NMNamedManager *named_mgr; + int num; int i; g_return_val_if_fail (config != NULL, FALSE); @@ -363,7 +346,8 @@ nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device, guint32 ad_gw = 0, vpn_gw = 0; const NMSettingIP4Address *tmp; - for (i = 0; i < nm_ip4_config_get_num_addresses (ad_config); i++) { + 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; @@ -371,17 +355,20 @@ nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device, } } - 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; + 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, ad_gw, vpn_gw, 32, - nm_ip4_config_get_mss (config)); + nm_system_device_set_ip4_route (nm_device_get_ip_iface (active_device), + ad_config, vpn_gw, 0xFFFFFFFF, ad_gw, + nm_ip4_config_get_mss (config)); + } } if (!iface || !strlen (iface)) @@ -396,15 +383,21 @@ nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device, if (nm_ip4_config_get_mtu (config)) nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config)); - if (g_slist_length (routes) == 0) { - nm_system_device_replace_default_ip4_route (iface, 0, 0); - } else { - GSList *iter; + /* Set routes */ + num = nm_ip4_config_get_num_static_routes (config); + for (i = 0; i < num; i++) { + const NMSettingIP4Address *route = nm_ip4_config_get_static_route (config, i); - for (iter = routes; iter; iter = iter->next) - nm_system_device_add_ip4_route_via_device_with_iface (iface, (char *) iter->data); + nm_system_device_set_ip4_route (iface, config, + route->address, + route->netmask, + route->gateway, + 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, config, NM_NAMED_IP_CONFIG_TYPE_VPN); @@ -551,45 +544,6 @@ nm_system_device_set_mtu (const char *iface, guint32 mtu) return success; } -/* - * nm_system_device_add_ip4_route_via_device_with_iface - * - * Add route to the given device - * - */ -void nm_system_device_add_ip4_route_via_device_with_iface (const char *iface, const char *addr) -{ - struct rtnl_route *route; - struct nl_handle *nlh; - struct nl_addr *dst; - int iface_idx, err; - - nlh = nm_netlink_get_default_handle (); - g_return_if_fail (nlh != NULL); - - route = rtnl_route_alloc (); - g_return_if_fail (route != NULL); - - iface_idx = nm_netlink_iface_to_index (iface); - if (iface_idx < 0) - goto out; - rtnl_route_set_oif (route, iface_idx); - - if (!(dst = nl_addr_parse (addr, AF_INET))) - goto out; - rtnl_route_set_dst (route, dst); - nl_addr_put (dst); - - err = rtnl_route_add (nlh, route, 0); - if (err) { - nm_warning ("rtnl_route_add() returned error %s (%d)\n%s", - strerror (err), err, nl_geterror()); - } - -out: - rtnl_route_put (route); -} - /* * nm_system_replace_default_ip4_route * @@ -803,4 +757,3 @@ void nm_system_device_flush_ip4_routes_with_iface (const char *iface) nl_cache_free (route_cache); } - diff --git a/src/NetworkManagerSystem.h b/src/NetworkManagerSystem.h index aab2321123..26a89768c8 100644 --- a/src/NetworkManagerSystem.h +++ b/src/NetworkManagerSystem.h @@ -41,8 +41,6 @@ void nm_system_device_replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss); -void nm_system_device_add_ip4_route_via_device_with_iface (const char *iface, const char *route); - void nm_system_device_flush_ip4_addresses (NMDevice *dev); void nm_system_device_flush_ip4_addresses_with_iface (const char *iface); @@ -51,13 +49,11 @@ void nm_system_kill_all_dhcp_daemons (void); void nm_system_update_dns (void); gboolean nm_system_device_set_from_ip4_config (const char *iface, - NMIP4Config *config, - gboolean route_to_iface); + NMIP4Config *config); gboolean nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device, const char *iface, - NMIP4Config *config, - GSList *routes); + NMIP4Config *config); gboolean nm_system_vpn_device_unset_from_ip4_config (NMDevice *active_device, const char *iface, diff --git a/src/nm-device.c b/src/nm-device.c index 977410f480..621d600087 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -1355,7 +1355,6 @@ nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config) { NMDevicePrivate *priv; const char *ip_iface; - gboolean route_to_iface; gboolean success; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); @@ -1381,16 +1380,7 @@ nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config) ip_iface = nm_device_get_ip_iface (self); - /* 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. */ - if (strcmp (ip_iface, nm_device_get_iface (self))) - route_to_iface = TRUE; - else - route_to_iface = FALSE; - - success = nm_system_device_set_from_ip4_config (ip_iface, config, route_to_iface); + success = nm_system_device_set_from_ip4_config (ip_iface, config); if (success) { nm_device_update_ip4_address (self); nm_system_set_hostname (config); diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index c6cf89bf1b..003204b7e9 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "NetworkManager.h" #include "NetworkManagerVPN.h" @@ -228,17 +230,6 @@ nm_vpn_connection_get_service (NMVPNConnection *connection) return setting->service_type; } -static GSList * -nm_vpn_connection_get_routes (NMVPNConnection *connection) -{ - NMSettingVPN *setting; - - setting = (NMSettingVPN *) nm_connection_get_setting (NM_VPN_CONNECTION_GET_PRIVATE (connection)->connection, - NM_TYPE_SETTING_VPN); - - return setting->routes; -} - static void plugin_state_changed (DBusGProxy *proxy, NMVPNServiceState state, @@ -266,13 +257,21 @@ plugin_state_changed (DBusGProxy *proxy, } } +static const char * +ip_address_to_string (guint32 numeric) +{ + struct in_addr temp_addr; + + temp_addr.s_addr = numeric; + return inet_ntoa (temp_addr); +} + static void print_vpn_config (NMIP4Config *config, const char *tundev, const char *banner) { const NMSettingIP4Address *addr; - struct in_addr temp_addr; char * dns_domain = NULL; guint32 num; guint32 i; @@ -280,23 +279,28 @@ print_vpn_config (NMIP4Config *config, g_return_if_fail (config != NULL); addr = nm_ip4_config_get_address (config, 0); - temp_addr.s_addr = addr->gateway; - nm_info ("VPN Gateway: %s", inet_ntoa (temp_addr)); + + nm_info ("VPN Gateway: %s", ip_address_to_string (addr->gateway)); nm_info ("Tunnel Device: %s", tundev); - temp_addr.s_addr = addr->address; - nm_info ("Internal IP4 Address: %s", inet_ntoa (temp_addr)); - temp_addr.s_addr = addr->netmask; - nm_info ("Internal IP4 Netmask: %s", inet_ntoa (temp_addr)); - temp_addr.s_addr = nm_ip4_config_get_ptp_address (config); - nm_info ("Internal IP4 Point-to-Point Address: %s", inet_ntoa (temp_addr)); + nm_info ("Internal IP4 Address: %s", ip_address_to_string (addr->address)); + nm_info ("Internal IP4 Netmask: %s", ip_address_to_string (addr->netmask)); + nm_info ("Internal IP4 Point-to-Point Address: %s", + ip_address_to_string (nm_ip4_config_get_ptp_address (config))); nm_info ("Maximum Segment Size (MSS): %d", nm_ip4_config_get_mss (config)); - num = nm_ip4_config_get_num_nameservers (config); + num = nm_ip4_config_get_num_static_routes (config); for (i = 0; i < num; i++) { - temp_addr.s_addr = nm_ip4_config_get_nameserver (config, i); - nm_info ("Internal IP4 DNS: %s", inet_ntoa (temp_addr)); + addr = nm_ip4_config_get_static_route (config, i); + nm_info ("Static Route: %s/%s Gateway: %s", + ip_address_to_string (addr->address), + ip_address_to_string (addr->netmask), + ip_address_to_string (addr->gateway)); } + num = nm_ip4_config_get_num_nameservers (config); + for (i = 0; i < num; i++) + nm_info ("Internal IP4 DNS: %s", ip_address_to_string (nm_ip4_config_get_nameserver (config, i))); + if (nm_ip4_config_get_num_domains (config) > 0) dns_domain = (char *) nm_ip4_config_get_domain (config, 0); nm_info ("DNS Domain: '%s'", dns_domain ? dns_domain : "(none)"); @@ -306,6 +310,57 @@ print_vpn_config (NMIP4Config *config, nm_info ("-----------------------------------------"); } +static void +merge_vpn_routes (NMVPNConnection *connection, NMIP4Config *config) +{ + NMSettingVPN *setting; + GSList *iter; + + setting = NM_SETTING_VPN (nm_connection_get_setting (NM_VPN_CONNECTION_GET_PRIVATE (connection)->connection, + NM_TYPE_SETTING_VPN)); + + /* FIXME: Shouldn't the routes from user (NMSettingVPN) be inserted in the beginning + instead of appending to the end? + */ + + for (iter = setting->routes; iter; iter = iter->next) { + struct in_addr tmp; + char *p, *route; + long int prefix = 32; + + route = g_strdup ((char *) iter->data); + p = strchr (route, '/'); + if (!p || !(*(p + 1))) { + nm_warning ("Ignoring invalid route '%s'", route); + goto next; + } + + errno = 0; + prefix = strtol (p + 1, NULL, 10); + if (errno || prefix < 0 || prefix > 32) { + nm_warning ("Ignoring invalid route '%s'", route); + goto next; + } + + /* don't pass the prefix to inet_pton() */ + *p = '\0'; + if (inet_pton (AF_INET, route, &tmp) > 0) { + NMSettingIP4Address *addr; + + addr = g_new0 (NMSettingIP4Address, 1); + addr->address = tmp.s_addr; + addr->netmask = ntohl (0xFFFFFFFF << (32 - prefix)); + addr->gateway = 0; + + nm_ip4_config_take_static_route (config, addr); + } else + nm_warning ("Ignoring invalid route '%s'", route); + +next: + g_free (route); + } +} + static void nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, GHashTable *config_hash, @@ -395,6 +450,18 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, priv->banner = g_strdup (g_value_get_string (val)); } + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES); + if (val) { + GSList *routes; + GSList *iter; + + routes = nm_utils_ip4_addresses_from_gvalue (val); + for (iter = routes; iter; iter = iter->next) + nm_ip4_config_take_static_route (config, (NMSettingIP4Address *) iter->data); + + g_slist_free (routes); + } + print_vpn_config (config, priv->tundev, priv->banner); priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); @@ -403,9 +470,9 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, /* 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); + merge_vpn_routes (connection, config); - if (nm_system_vpn_device_set_from_ip4_config (priv->parent_dev, priv->tundev, priv->ip4_config, - nm_vpn_connection_get_routes (connection))) { + if (nm_system_vpn_device_set_from_ip4_config (priv->parent_dev, priv->tundev, priv->ip4_config)) { nm_info ("VPN connection '%s' (IP Config Get) complete.", nm_vpn_connection_get_name (connection)); nm_vpn_connection_set_vpn_state (connection,