diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 6158cc917a..cd523b9dad 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -496,8 +496,8 @@ static void nm_device_set_proxy_config (NMDevice *self, const char *pac_url); static gboolean nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config, - guint32 default_route_metric, - gboolean commit); + gboolean commit, + GPtrArray *ip4_dev_route_blacklist); static gboolean ip4_config_merge_and_apply (NMDevice *self, NMIP4Config *config, gboolean commit); @@ -3885,7 +3885,7 @@ nm_device_removed (NMDevice *self, gboolean unconfigure_ip_config) if (!unconfigure_ip_config) return; - nm_device_set_ip4_config (self, NULL, 0, FALSE); + nm_device_set_ip4_config (self, NULL, FALSE, NULL); nm_device_set_ip6_config (self, NULL, FALSE); } @@ -5578,6 +5578,7 @@ ip4_config_merge_and_apply (NMDevice *self, gboolean ignore_auto_dns = FALSE; GSList *iter; NMPlatformIP4Route default_route; + gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; /* Merge all the configs into the composite config */ if (config) { @@ -5694,12 +5695,19 @@ ip4_config_merge_and_apply (NMDevice *self, } END_ADD_DEFAULT_ROUTE: + + if (commit) { + nm_ip4_config_add_device_routes (composite, + default_route_metric, + &ip4_dev_route_blacklist); + } + if (commit) { if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit) NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite); } - success = nm_device_set_ip4_config (self, composite, default_route_metric, commit); + success = nm_device_set_ip4_config (self, composite, commit, ip4_dev_route_blacklist); g_object_unref (composite); if (commit) @@ -9739,8 +9747,8 @@ nm_device_get_ip4_config (NMDevice *self) static gboolean nm_device_set_ip4_config (NMDevice *self, NMIP4Config *new_config, - guint32 default_route_metric, - gboolean commit) + gboolean commit, + GPtrArray *ip4_dev_route_blacklist) { NMDevicePrivate *priv; NMIP4Config *old_config = NULL; @@ -9766,8 +9774,10 @@ nm_device_set_ip4_config (NMDevice *self, if (commit && new_config) { _commit_mtu (self, new_config); success = nm_ip4_config_commit (new_config, - nm_device_get_platform (self), - default_route_metric); + nm_device_get_platform (self)); + nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), + nm_ip4_config_get_ifindex (new_config), + ip4_dev_route_blacklist); } if (new_config) { @@ -11986,7 +11996,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) /* Clean up IP configs; this does not actually deconfigure the * interface; the caller must flush routes and addresses explicitly. */ - nm_device_set_ip4_config (self, NULL, 0, TRUE); + nm_device_set_ip4_config (self, NULL, TRUE, NULL); nm_device_set_ip6_config (self, NULL, TRUE); nm_clear_nmp_object (&priv->default_route4); nm_clear_nmp_object (&priv->default_route6); diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index 9f6ba72407..ae76ee94ef 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -107,6 +107,7 @@ dhcp4_state_changed (NMDhcpClient *client, { static NMIP4Config *last_config = NULL; NMIP4Config *existing; + gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; g_return_if_fail (!ip4_config || NM_IS_IP4_CONFIG (ip4_config)); @@ -123,11 +124,17 @@ dhcp4_state_changed (NMDhcpClient *client, nm_ip4_config_subtract (existing, last_config); nm_ip4_config_merge (existing, ip4_config, NM_IP_CONFIG_MERGE_DEFAULT); + nm_ip4_config_add_device_routes (existing, + global_opt.priority_v4, + &ip4_dev_route_blacklist); if (!nm_ip4_config_commit (existing, - NM_PLATFORM_GET, - global_opt.priority_v4)) + NM_PLATFORM_GET)) _LOGW (LOGD_DHCP4, "failed to apply DHCPv4 config"); + nm_platform_ip4_dev_route_blacklist_set (NM_PLATFORM_GET, + gl.ifindex, + ip4_dev_route_blacklist); + if (last_config) g_object_unref (last_config); last_config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 07e2f2e080..58127dafab 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -724,23 +724,105 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i return self; } -gboolean -nm_ip4_config_commit (const NMIP4Config *self, - NMPlatform *platform, - guint32 default_route_metric) +void +nm_ip4_config_add_device_routes (NMIP4Config *self, + guint32 default_route_metric, + GPtrArray **out_ip4_dev_route_blacklist) { const NMIP4ConfigPrivate *priv; + GPtrArray *ip4_dev_route_blacklist = NULL; + const NMPlatformIP4Address *addr; + int ifindex; + NMDedupMultiIter iter; + + g_return_if_fail (NM_IS_IP4_CONFIG (self)); + + priv = NM_IP4_CONFIG_GET_PRIVATE (self); + + ifindex = nm_ip4_config_get_ifindex (self); + g_return_if_fail (ifindex > 0); + + /* For IPv6, we explicitly add the device-routes (onlink) to NMIP6Config. + * As we don't do that for IPv4, add it here shortly before syncing + * the routes. */ + + nm_ip_config_iter_ip4_address_for_each (&iter, self, &addr) { + nm_auto_nmpobj NMPObject *r = NULL; + NMPlatformIP4Route *route; + in_addr_t network; + + if (addr->plen == 0) + continue; + + nm_assert (addr->plen <= 32); + + /* The destination network depends on the peer-address. */ + network = nm_utils_ip4_address_clear_host_address (addr->peer_address, addr->plen); + + if (_ipv4_is_zeronet (network)) { + /* Kernel doesn't add device-routes for destinations that + * start with 0.x.y.z. Skip them. */ + continue; + } + + r = nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, NULL); + route = NMP_OBJECT_CAST_IP4_ROUTE (r); + + route->ifindex = ifindex; + route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL; + route->network = network; + route->plen = addr->plen; + route->pref_src = addr->address; + route->metric = default_route_metric; + route->scope_inv = nm_platform_route_scope_inv (NM_RT_SCOPE_LINK); + + nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) route); + + if (_lookup_route (self, + r, + NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) { + /* we already track this route. Don't add it again. */ + } else + _add_route (self, nmp_object_ref (r), NULL, NULL); + + if ( out_ip4_dev_route_blacklist + && default_route_metric != NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) { + nm_auto_nmpobj NMPObject *r_dev = NULL; + + r_dev = nmp_object_clone (r, FALSE); + route = NMP_OBJECT_CAST_IP4_ROUTE (r_dev); + route->metric = NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE; + + nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) route); + + if (_lookup_route (self, + r_dev, + NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) { + /* we track such a route explicitly. Don't blacklist it. */ + } else { + if (!ip4_dev_route_blacklist) + ip4_dev_route_blacklist = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref); + + g_ptr_array_add (ip4_dev_route_blacklist, + g_steal_pointer (&r_dev)); + } + } + } + + NM_SET_OUT (out_ip4_dev_route_blacklist, ip4_dev_route_blacklist); +} + +gboolean +nm_ip4_config_commit (const NMIP4Config *self, + NMPlatform *platform) +{ gs_unref_ptrarray GPtrArray *addresses = NULL; gs_unref_ptrarray GPtrArray *routes = NULL; - gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; int ifindex; - guint i; gboolean success = TRUE; g_return_val_if_fail (NM_IS_IP4_CONFIG (self), FALSE); - priv = NM_IP4_CONFIG_GET_PRIVATE (self); - ifindex = nm_ip4_config_get_ifindex (self); g_return_val_if_fail (ifindex > 0, FALSE); @@ -750,82 +832,6 @@ nm_ip4_config_commit (const NMIP4Config *self, routes = nm_dedup_multi_objs_to_ptr_array_head (nm_ip4_config_lookup_routes (self), NULL, NULL); - if (addresses) { - /* For IPv6, we explicitly add the device-routes (onlink) to NMIP6Config. - * As we don't do that for IPv4, add it here shortly before syncing - * the routes. */ - for (i = 0; i < addresses->len; i++) { - const NMPObject *o = addresses->pdata[i]; - const NMPlatformIP4Address *addr; - nm_auto_nmpobj NMPObject *r = NULL; - NMPlatformIP4Route *route; - in_addr_t network; - - if (!o) - continue; - - addr = NMP_OBJECT_CAST_IP4_ADDRESS (o); - if (addr->plen == 0) - continue; - - nm_assert (addr->plen <= 32); - - /* The destination network depends on the peer-address. */ - network = nm_utils_ip4_address_clear_host_address (addr->peer_address, addr->plen); - - if (_ipv4_is_zeronet (network)) { - /* Kernel doesn't add device-routes for destinations that - * start with 0.x.y.z. Skip them. */ - continue; - } - - r = nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, NULL); - route = NMP_OBJECT_CAST_IP4_ROUTE (r); - - route->ifindex = ifindex; - route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL; - route->network = network; - route->plen = addr->plen; - route->pref_src = addr->address; - route->metric = default_route_metric; - route->scope_inv = nm_platform_route_scope_inv (NM_RT_SCOPE_LINK); - - nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) route); - - if (_lookup_route (self, - r, - NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) { - /* we already track this route. Don't add it again. */ - } else { - if (!routes) - routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref); - g_ptr_array_add (routes, (gpointer) nmp_object_ref (r)); - } - - if (default_route_metric != NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) { - nm_auto_nmpobj NMPObject *r_dev = NULL; - - r_dev = nmp_object_clone (r, FALSE); - route = NMP_OBJECT_CAST_IP4_ROUTE (r_dev); - route->metric = NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE; - - nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) route); - - if (_lookup_route (self, - r_dev, - NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) { - /* we track such a route explicitly. Don't blacklist it. */ - } else { - if (!ip4_dev_route_blacklist) - ip4_dev_route_blacklist = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref); - - g_ptr_array_add (ip4_dev_route_blacklist, - g_steal_pointer (&r_dev)); - } - } - } - } - nm_platform_ip4_address_sync (platform, ifindex, addresses); if (!nm_platform_ip_route_sync (platform, @@ -836,10 +842,6 @@ nm_ip4_config_commit (const NMIP4Config *self, NULL)) success = FALSE; - nm_platform_ip4_dev_route_blacklist_set (platform, - ifindex, - ip4_dev_route_blacklist); - return success; } diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index a8e22c2e59..49f119c614 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -150,9 +150,14 @@ int nm_ip4_config_get_ifindex (const NMIP4Config *self); NMDedupMultiIndex *nm_ip4_config_get_multi_idx (const NMIP4Config *self); NMIP4Config *nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, gboolean capture_resolv_conf); + +void nm_ip4_config_add_device_routes (NMIP4Config *self, + guint32 default_route_metric, + GPtrArray **out_ip4_dev_route_blacklist); + gboolean nm_ip4_config_commit (const NMIP4Config *self, - NMPlatform *platform, - guint32 default_route_metric); + NMPlatform *platform); + void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, guint32 default_route_metric); NMSetting *nm_ip4_config_create_setting (const NMIP4Config *self); diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 9e4189feb7..517e7eb97a 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -121,6 +121,8 @@ typedef struct { NMNetns *netns; + GPtrArray *ip4_dev_route_blacklist; + GDBusProxy *proxy; GCancellable *cancellable; GVariant *connect_hash; @@ -1147,9 +1149,11 @@ nm_vpn_connection_apply_config (NMVpnConnection *self) if (priv->ip4_config) { nm_assert (priv->ip_ifindex == nm_ip4_config_get_ifindex (priv->ip4_config)); if (!nm_ip4_config_commit (priv->ip4_config, - nm_netns_get_platform (priv->netns), - nm_vpn_connection_get_ip4_route_metric (self))) + nm_netns_get_platform (priv->netns))) return FALSE; + nm_platform_ip4_dev_route_blacklist_set (nm_netns_get_platform (priv->netns), + priv->ip_ifindex, + priv->ip4_dev_route_blacklist); } if (priv->ip6_config) { @@ -1601,6 +1605,12 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) nm_ip4_config_add_route (config, &r, NULL); } + g_clear_pointer (&priv->ip4_dev_route_blacklist, g_ptr_array_unref); + + nm_ip4_config_add_device_routes (config, + nm_vpn_connection_get_ip4_route_metric (self), + &priv->ip4_dev_route_blacklist); + if (priv->ip4_config) { nm_ip4_config_replace (priv->ip4_config, config, NULL); g_object_unref (config); @@ -2704,6 +2714,8 @@ dispose (GObject *object) g_clear_pointer (&priv->connect_hash, g_variant_unref); + g_clear_pointer (&priv->ip4_dev_route_blacklist, g_ptr_array_unref); + nm_clear_g_source (&priv->connect_timeout); dispatcher_cleanup (self);