From 23f45d0e180c110c4b2e6fe21f053014332cee79 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Tue, 16 Jan 2024 17:30:48 +0100 Subject: [PATCH 1/2] vpn: simplify routes parsing code Split the IPv4 and IPv6 cases to make the following commit simpler. --- src/core/vpn/nm-vpn-connection.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c index 3dba9ff6c..dddc6e0b3 100644 --- a/src/core/vpn/nm-vpn-connection.c +++ b/src/core/vpn/nm-vpn-connection.c @@ -2099,20 +2099,12 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) nm_l3_config_data_add_route(l3cd, addr_family, route, NULL); } - } else if (IS_IPv4 ? g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, "aau", &var_iter) - : g_variant_lookup(dict, - NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, - "a(ayuayu)", - &var_iter)) { - _nm_unused nm_auto_free_variant_iter GVariantIter *var_iter_ref_owner = var_iter; - NMPlatformIPXRoute route = {}; - guint32 plen; - GVariant *next_hop; - GVariant *dest; - guint32 prefix; - guint32 metric; + } else if (IS_IPv4) { + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, "aau", &var_iter)) { + _nm_unused nm_auto_free_variant_iter GVariantIter *var_iter_ref_owner = var_iter; + NMPlatformIPXRoute route = {}; + guint32 plen; - if (IS_IPv4) { while (g_variant_iter_next(var_iter, "@au", &v)) { _nm_unused gs_unref_variant GVariant *v_ref_owner = v; @@ -2151,7 +2143,19 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict break; } } - } else { + } + } else { + _nm_unused nm_auto_free_variant_iter GVariantIter *var_iter_ref_owner = NULL; + NMPlatformIPXRoute route = {}; + GVariant *next_hop; + GVariant *dest; + guint32 prefix; + guint32 metric; + + /* IPv6 and no "preserve-routes" */ + + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayu)", &var_iter)) { + var_iter_ref_owner = var_iter; while ( g_variant_iter_next(var_iter, "(@ayu@ayu)", &dest, &prefix, &next_hop, &metric)) { _nm_unused gs_unref_variant GVariant *next_hop_ref_owner = next_hop; From c415eaca762867d948cc7d582988a791a8732736 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Tue, 16 Jan 2024 17:49:57 +0100 Subject: [PATCH 2/2] vpn: accept pref-src for IPv6 routes returned by plugins As done for IPv4 in commit 3b145a33b748 ('vpn-connections: allow the plugin to specify route preferred src'), allow VPN plugins to return a preferred source address for routes. Still accept the old format. --- src/core/vpn/nm-vpn-connection.c | 100 ++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 35 deletions(-) diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c index dddc6e0b3..de0c9f710 100644 --- a/src/core/vpn/nm-vpn-connection.c +++ b/src/core/vpn/nm-vpn-connection.c @@ -2147,50 +2147,80 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict } else { _nm_unused nm_auto_free_variant_iter GVariantIter *var_iter_ref_owner = NULL; NMPlatformIPXRoute route = {}; - GVariant *next_hop; - GVariant *dest; guint32 prefix; guint32 metric; + NMOptionBool new_signature = NM_OPTION_BOOL_DEFAULT; /* IPv6 and no "preserve-routes" */ - if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayu)", &var_iter)) { - var_iter_ref_owner = var_iter; - while ( - g_variant_iter_next(var_iter, "(@ayu@ayu)", &dest, &prefix, &next_hop, &metric)) { - _nm_unused gs_unref_variant GVariant *next_hop_ref_owner = next_hop; - _nm_unused gs_unref_variant GVariant *dest_ref_owner = dest; + if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayu)", &var_iter)) + new_signature = FALSE; + else if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayuay)", &var_iter)) + new_signature = TRUE; + else + var_iter = NULL; - if (prefix > 128) - continue; + var_iter_ref_owner = var_iter; - route.r6 = (NMPlatformIP6Route){ - .plen = prefix, - .table_any = TRUE, - .metric_any = TRUE, - .rt_source = NM_IP_CONFIG_SOURCE_VPN, - }; + while (TRUE) { + gs_unref_variant GVariant *next_hop = NULL; + gs_unref_variant GVariant *dest = NULL; + gs_unref_variant GVariant *pref_src = NULL; - if (!nm_ip_addr_set_from_variant(AF_INET6, &route.r6.network, dest, NULL)) - continue; - - nm_ip_addr_set_from_variant(AF_INET6, &route.r6.gateway, next_hop, NULL); - - nm_ip6_addr_clear_host_address(&route.r6.network, &route.r6.network, route.r6.plen); - - if (!IN6_IS_ADDR_UNSPECIFIED(&priv->ip_data_6.gw_external.addr6) - && IN6_ARE_ADDR_EQUAL(&route.r6.network, &priv->ip_data_6.gw_external.addr6) - && route.r6.plen == 128) { - /* Ignore host routes to the VPN gateway since NM adds one itself. - * Since NM knows more about the routing situation than the VPN - * server, we want to use the NM created route instead of whatever - * the server provides. - */ - continue; - } - - nm_l3_config_data_add_route_6(l3cd, &route.r6); + if (new_signature == NM_OPTION_BOOL_DEFAULT) { + break; + } else if (new_signature) { + if (!g_variant_iter_next(var_iter, + "(@ayu@ayu@ay)", + &dest, + &prefix, + &next_hop, + &metric, + &pref_src)) + break; + } else { + if (!g_variant_iter_next(var_iter, + "(@ayu@ayu)", + &dest, + &prefix, + &next_hop, + &metric)) + break; } + + if (prefix > 128) + continue; + + route.r6 = (NMPlatformIP6Route){ + .plen = prefix, + .table_any = TRUE, + .metric_any = TRUE, + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + }; + + if (!nm_ip_addr_set_from_variant(AF_INET6, &route.r6.network, dest, NULL)) + continue; + + if (pref_src + && !nm_ip_addr_set_from_variant(AF_INET6, &route.r6.pref_src, pref_src, NULL)) + continue; + + nm_ip_addr_set_from_variant(AF_INET6, &route.r6.gateway, next_hop, NULL); + + nm_ip6_addr_clear_host_address(&route.r6.network, &route.r6.network, route.r6.plen); + + if (!IN6_IS_ADDR_UNSPECIFIED(&priv->ip_data_6.gw_external.addr6) + && IN6_ARE_ADDR_EQUAL(&route.r6.network, &priv->ip_data_6.gw_external.addr6) + && route.r6.plen == 128) { + /* Ignore host routes to the VPN gateway since NM adds one itself. + * Since NM knows more about the routing situation than the VPN + * server, we want to use the NM created route instead of whatever + * the server provides. + */ + continue; + } + + nm_l3_config_data_add_route_6(l3cd, &route.r6); } }