summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-03-04 09:31:28 +0100
committerThomas Haller <thaller@redhat.com>2019-03-04 15:59:02 +0100
commitcc801cb2fc014e66fed633945e94a321a4f39761 (patch)
tree624357001b6354ba78f3fd4c50a919b5aa544254
parent49cbd6d1f38dcae484c6a1c9545bf174be0cfd8e (diff)
downloadNetworkManager-th/wireguard-routes.tar.gz
wireguard: implement direct "peer-routes" for WireGuard allowed-ips rangesth/wireguard-routes
-rw-r--r--src/devices/nm-device-wireguard.c137
-rw-r--r--src/devices/nm-device.c1
2 files changed, 137 insertions, 1 deletions
diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c
index 51eabbd94a..145dbe8cd0 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)
{
@@ -1313,6 +1438,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);
}
@@ -1330,6 +1456,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);
@@ -1484,6 +1620,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: