diff options
author | Thomas Haller <thaller@redhat.com> | 2017-09-07 11:32:06 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-09-07 12:00:36 +0200 |
commit | 10fc74819c3646ed0c8072adbac803a3e1a8a36b (patch) | |
tree | c3677f6298d02745eb0efc063afe1e850ea334b4 /src/vpn | |
parent | f6dabee068e1ad20a6d3f5775b196d944996778c (diff) | |
download | NetworkManager-10fc74819c3646ed0c8072adbac803a3e1a8a36b.tar.gz |
vpn: only rely on `ip route get` to resolve route to external VPN gateway
Until recently, we would only consier the IP config of the parent device
to determine the route to the external VPN gateway. We changed that, to
additionally improve the guess by letting kernel resolve the route.
Now, drop checking the parent's config entirely. The only thing that
matters is the here and now runtime configuraion on the parent device.
And for that we ask kernel to resolve the route.
Diffstat (limited to 'src/vpn')
-rw-r--r-- | src/vpn/nm-vpn-connection.c | 66 |
1 files changed, 23 insertions, 43 deletions
diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index e116657e8a..bd86007ac4 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -710,8 +710,8 @@ add_ip4_vpn_gateway_route (NMIP4Config *config, in_addr_t vpn_gw, NMPlatform *platform) { - NMIP4Config *parent_config; - guint32 parent_gw; + guint32 parent_gw = 0; + gboolean has_parent_gw = FALSE; NMPlatformIP4Route route; int ifindex; guint32 route_metric; @@ -726,23 +726,8 @@ add_ip4_vpn_gateway_route (NMIP4Config *config, nm_assert (ifindex > 0); nm_assert (ifindex == nm_device_get_ip_ifindex (parent_device)); - /* Set up a route to the VPN gateway's public IP address through the default - * network device if the VPN gateway is on a different subnet. - */ - parent_config = nm_device_get_ip4_config (parent_device); - g_return_if_fail (parent_config != NULL); - - parent_gw = nm_ip4_config_get_gateway (parent_config); - - /* If the VPN gateway is in the same subnet as one of the parent device's - * IP addresses, don't add the host route to it, but a route through the - * parent device. - */ - if (nm_ip4_config_destination_is_direct (parent_config, vpn_gw, 32)) - parent_gw = 0; - - /* actually, let's ask kernel how to reach @vpn_gw. If (and only if) - * the destination is on @parent_device, then we take that @parent_gw. */ + /* Ask kernel how to reach @vpn_gw. We can only inject the route in + * @parent_device, so whatever we resolve, it can only be on @ifindex. */ if (nm_platform_ip_route_get (platform, AF_INET, &vpn_gw, @@ -756,11 +741,16 @@ add_ip4_vpn_gateway_route (NMIP4Config *config, * * So, only accept direct routes, if @vpn_gw is a private network. */ if ( r->gateway - || nm_utils_ip_is_site_local (AF_INET, &vpn_gw)) + || nm_utils_ip_is_site_local (AF_INET, &vpn_gw)) { parent_gw = r->gateway; + has_parent_gw = TRUE; + } } } + if (!has_parent_gw) + return; + route_metric = nm_device_get_ip4_route_metric (parent_device); memset (&route, 0, sizeof (route)); @@ -793,8 +783,8 @@ add_ip6_vpn_gateway_route (NMIP6Config *config, const struct in6_addr *vpn_gw, NMPlatform *platform) { - NMIP6Config *parent_config; - const struct in6_addr *parent_gw; + const struct in6_addr *parent_gw = NULL; + gboolean has_parent_gw = FALSE; NMPlatformIP6Route route; int ifindex; guint32 route_metric; @@ -809,24 +799,8 @@ add_ip6_vpn_gateway_route (NMIP6Config *config, nm_assert (ifindex > 0); nm_assert (ifindex == nm_device_get_ip_ifindex (parent_device)); - parent_config = nm_device_get_ip6_config (parent_device); - g_return_if_fail (parent_config != NULL); - - /* we add a direct route to the VPN gateway, but we only do that - * on the @parent_device. That is probably not correct in every case... */ - parent_gw = nm_ip6_config_get_gateway (parent_config); - if (!parent_gw) - return; - - /* If the VPN gateway is in the same subnet as one of the parent device's - * IP addresses, don't add the host route to it, but a route through the - * parent device. - */ - if (nm_ip6_config_destination_is_direct (parent_config, vpn_gw, 128)) - parent_gw = &in6addr_any; - - /* actually, let's ask kernel how to reach @vpn_gw. If (and only if) - * the destination is on @parent_device, then we take that @parent_gw. */ + /* Ask kernel how to reach @vpn_gw. We can only inject the route in + * @parent_device, so whatever we resolve, it can only be on @ifindex. */ if (nm_platform_ip_route_get (platform, AF_INET6, vpn_gw, @@ -840,18 +814,24 @@ add_ip6_vpn_gateway_route (NMIP6Config *config, * * So, only accept direct routes, if @vpn_gw is a private network. */ if ( !IN6_IS_ADDR_UNSPECIFIED (&r->gateway) - || nm_utils_ip_is_site_local (AF_INET6, &vpn_gw)) + || nm_utils_ip_is_site_local (AF_INET6, &vpn_gw)) { parent_gw = &r->gateway; + has_parent_gw = TRUE; + } } } + if (!has_parent_gw) + return; + route_metric = nm_device_get_ip6_route_metric (parent_device); memset (&route, 0, sizeof (route)); route.ifindex = ifindex; route.network = *vpn_gw; route.plen = 128; - route.gateway = *parent_gw; + if (parent_gw) + route.gateway = *parent_gw; route.rt_source = NM_IP_CONFIG_SOURCE_VPN; route.metric = route_metric; nm_ip6_config_add_route (config, &route); @@ -861,7 +841,7 @@ add_ip6_vpn_gateway_route (NMIP6Config *config, * routes include a subnet that matches the parent device's subnet, * the parent device's gateway would get routed through the VPN and fail. */ - if (!IN6_IS_ADDR_UNSPECIFIED (parent_gw)) { + if (parent_gw && !IN6_IS_ADDR_UNSPECIFIED (parent_gw)) { memset (&route, 0, sizeof (route)); route.network = *parent_gw; route.plen = 128; |