From 626beaf83e142fcaff32dbf1662d75af1d826b2d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 4 Mar 2019 09:31:28 +0100 Subject: wireguard: implement direct "peer-routes" for WireGuard allowed-ips ranges --- src/devices/nm-device-wireguard.c | 137 ++++++++++++++++++++++++++++++++++++++ src/devices/nm-device.c | 1 - 2 files changed, 137 insertions(+), 1 deletion(-) diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c index 4e8d630e48..34fe1e1fff 100644 --- a/src/devices/nm-device-wireguard.c +++ b/src/devices/nm-device-wireguard.c @@ -1247,6 +1247,131 @@ act_stage2_config (NMDevice *device, return NM_ACT_STAGE_RETURN_FAILURE; } +static NMIPConfig * +_get_dev2_ip_config (NMDeviceWireGuard *self, + int addr_family) +{ + gs_unref_object NMIPConfig *ip_config = NULL; + NMConnection *connection; + NMSettingWireGuard *s_wg; + guint n_peers; + guint i; + int ip_ifindex; + guint32 route_metric; + guint32 route_table_coerced; + + connection = nm_device_get_applied_connection (NM_DEVICE (self)); + + s_wg = NM_SETTING_WIREGUARD (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIREGUARD)); + + /* Differences to `wg-quick`. + * + * `wg-quick` supports the "Table" setting with 3 modes: + * + * a1) "off": this is what we do with "peer-routes" disabled. + * + * a2) an explicit routing table. This is our behavior with "peer-routes" on. In this case + * we honor the "ipv4.route-table" and "ipv6.route-table" settings. One difference is that + * `wg-quick` would resolve table names from /etc/iproute2/rt_tables. Our connection profiles + * only contain table numbers, so that conversion from name to table must have happend + * before already. + * + * a3) "auto" (the default). In this case, `wg-quick` would only add the route to the + * main table, if the AllowedIP range is not yet reachable on the link. With "peer-routes" + * enabled, we don't check for that and always add the routes to the main-table + * (with 'ipv4.route-table' and 'ipv6.route-table' set to zero or RT_TABLE_MAIN (254)). + * + * Also, in "auto" mode, `wg-quick` would add special handling for /0 routes and pick + * an empty table to configure policy routing to avoid routing loops. This handling + * of routing-loops via policy routing is not yet done, and requires a separate solution + * from constructing the peer-routes here. + */ + if (!nm_setting_wireguard_get_peer_routes (s_wg)) + return NULL; + + ip_ifindex = nm_device_get_ip_ifindex (NM_DEVICE (self)); + + if (ip_ifindex <= 0) + return NULL; + + route_metric = nm_device_get_route_metric (NM_DEVICE (self), addr_family); + + route_table_coerced = nm_platform_route_table_coerce (nm_device_get_route_table (NM_DEVICE (self), addr_family, TRUE)); + + n_peers = nm_setting_wireguard_get_peers_len (s_wg); + for (i = 0; i < n_peers; i++) { + NMWireGuardPeer *peer = nm_setting_wireguard_get_peer (s_wg, i); + guint n_aips; + guint j; + + n_aips = nm_wireguard_peer_get_allowed_ips_len (peer); + for (j = 0; j < n_aips; j++) { + NMPlatformIPXRoute rt; + NMIPAddr addrbin; + const char *aip; + gboolean valid; + int prefix; + + aip = nm_wireguard_peer_get_allowed_ip (peer, j, &valid); + + if ( !valid + || !nm_utils_parse_inaddr_prefix_bin (addr_family, + aip, + NULL, + &addrbin, + &prefix)) + continue; + + if (prefix < 0) + prefix = (addr_family == AF_INET) ? 32 : 128; + + if (!ip_config) + ip_config = nm_device_ip_config_new (NM_DEVICE (self), addr_family); + + nm_utils_ipx_address_clear_host_address (addr_family, &addrbin, NULL, prefix); + + if (addr_family == AF_INET) { + rt.r4 = (NMPlatformIP4Route) { + .network = addrbin.addr4, + .plen = prefix, + .ifindex = ip_ifindex, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .table_coerced = route_table_coerced, + .metric = route_metric, + }; + } else { + rt.r6 = (NMPlatformIP6Route) { + .network = addrbin.addr6, + .plen = prefix, + .ifindex = ip_ifindex, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .table_coerced = route_table_coerced, + .metric = route_metric, + }; + } + + nm_ip_config_add_route (ip_config, &rt.rx, NULL); + } + } + + return g_steal_pointer (&ip_config); +} + +static NMActStageReturn +act_stage3_ip_config_start (NMDevice *device, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) +{ + gs_unref_object NMIPConfig *ip_config = NULL; + + ip_config = _get_dev2_ip_config (NM_DEVICE_WIREGUARD (device), addr_family); + + nm_device_set_dev2_ip_config (device, addr_family, ip_config); + + return NM_DEVICE_CLASS (nm_device_wireguard_parent_class)->act_stage3_ip_config_start (device, addr_family, out_config, out_failure_reason); +} + static guint32 get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) { @@ -1312,6 +1437,7 @@ can_reapply_change (NMDevice *device, NM_SETTING_WIREGUARD_FWMARK, NM_SETTING_WIREGUARD_LISTEN_PORT, NM_SETTING_WIREGUARD_PEERS, + NM_SETTING_WIREGUARD_PEER_ROUTES, NM_SETTING_WIREGUARD_PRIVATE_KEY, NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS); } @@ -1329,6 +1455,16 @@ reapply_connection (NMDevice *device, NMConnection *con_old, NMConnection *con_new) { + NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (device); + gs_unref_object NMIPConfig *ip4_config = NULL; + gs_unref_object NMIPConfig *ip6_config = NULL; + + ip4_config = _get_dev2_ip_config (self, AF_INET); + ip6_config = _get_dev2_ip_config (self, AF_INET6); + + nm_device_set_dev2_ip_config (device, AF_INET, ip4_config); + nm_device_set_dev2_ip_config (device, AF_INET6, ip6_config); + NM_DEVICE_CLASS (nm_device_wireguard_parent_class)->reapply_connection (device, con_old, con_new); @@ -1483,6 +1619,7 @@ nm_device_wireguard_class_init (NMDeviceWireGuardClass *klass) device_class->create_and_realize = create_and_realize; device_class->act_stage2_config = act_stage2_config; device_class->act_stage2_config_also_for_external_or_assume = TRUE; + device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; device_class->get_generic_capabilities = get_generic_capabilities; device_class->link_changed = link_changed; device_class->update_connection = update_connection; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index b24c9a7731..d5f7847f92 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -11077,7 +11077,6 @@ can_reapply_change (NMDevice *self, const char *setting_name, static void reapply_connection (NMDevice *self, NMConnection *con_old, NMConnection *con_new) { - } /* check_and_reapply_connection: -- cgit v1.2.1