mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-27 05:50:08 +01:00
wireguard: add firewall rules to copy mark
When a WG connection is connecting to an IPv6 endpoint, configures a
default route, and firewalld is active with IPv6_rpfilter=yes, it never
handshakes and doesn't pass traffic. This is because firewalld has a
IPv6 reverse path filter which is discarding these packets.
Thus, we add some firewall rules whenever a WG connection is brought up
that ensure the conntrack mark and packet mark are copied over.
These rules are largely inspired by wg-quick:
https://git.zx2c4.com/wireguard-tools/tree/src/wg-quick/linux.bash?id=17c78d31c27a3c311a2ff42a881057753c6ef2a4#n221
(cherry picked from commit db557908a2)
This commit is contained in:
parent
57321f78c9
commit
2afcebe0c7
3 changed files with 155 additions and 2 deletions
|
|
@ -23,6 +23,7 @@
|
|||
#include "nm-active-connection.h"
|
||||
#include "nm-act-request.h"
|
||||
#include "dns/nm-dns-manager.h"
|
||||
#include "nm-firewall-utils.h"
|
||||
|
||||
#define _NMLOG_DEVICE_TYPE NMDeviceWireGuard
|
||||
#include "nm-device-logging.h"
|
||||
|
|
@ -1207,6 +1208,25 @@ skip:
|
|||
*out_allowed_ips_data = g_steal_pointer(&allowed_ips);
|
||||
}
|
||||
|
||||
static void
|
||||
_configure_firewall(NMDeviceWireGuard *self, NMConnection *connection, int addr_family, gboolean up)
|
||||
{
|
||||
NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self);
|
||||
const char *ip_iface;
|
||||
|
||||
if (addr_family == AF_INET && !priv->auto_default_route_enabled_4)
|
||||
return;
|
||||
else if (addr_family == AF_INET6 && !priv->auto_default_route_enabled_6)
|
||||
return;
|
||||
|
||||
ip_iface = nm_device_get_ip_iface(NM_DEVICE(self));
|
||||
|
||||
nm_assert(priv->auto_default_route_fwmark);
|
||||
nm_assert(ip_iface);
|
||||
|
||||
nm_firewall_config_set_wg_rule(ip_iface, addr_family, priv->auto_default_route_fwmark, up);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
|
|
@ -1300,6 +1320,18 @@ create_and_realize(NMDevice *device,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
deactivate(NMDevice *device)
|
||||
{
|
||||
NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD(device);
|
||||
NMConnection *connection = nm_device_get_applied_connection(NM_DEVICE(self));
|
||||
|
||||
if (connection) {
|
||||
_configure_firewall(self, connection, AF_INET, FALSE);
|
||||
_configure_firewall(self, connection, AF_INET6, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
|
|
@ -1768,6 +1800,10 @@ act_stage3_ip_config(NMDevice *device, int addr_family)
|
|||
nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL;
|
||||
|
||||
l3cd = _get_dev2_ip_config(NM_DEVICE_WIREGUARD(device), addr_family);
|
||||
_configure_firewall(NM_DEVICE_WIREGUARD(device),
|
||||
nm_device_get_applied_connection(device),
|
||||
addr_family,
|
||||
TRUE);
|
||||
nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, l3cd);
|
||||
}
|
||||
|
||||
|
|
@ -1866,6 +1902,10 @@ reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_ne
|
|||
|
||||
if (state >= NM_DEVICE_STATE_CONFIG) {
|
||||
priv->auto_default_route_refresh = TRUE;
|
||||
|
||||
_configure_firewall(self, con_old, AF_INET, FALSE);
|
||||
_configure_firewall(self, con_old, AF_INET6, FALSE);
|
||||
|
||||
link_config(NM_DEVICE_WIREGUARD(device), "reapply", LINK_CONFIG_MODE_REAPPLY, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -2018,6 +2058,7 @@ nm_device_wireguard_class_init(NMDeviceWireGuardClass *klass)
|
|||
|
||||
device_class->state_changed = device_state_changed;
|
||||
device_class->create_and_realize = create_and_realize;
|
||||
device_class->deactivate = deactivate;
|
||||
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 = act_stage3_ip_config;
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ _share_iptables_get_name(gboolean is_iptables_chain, const char *prefix, const c
|
|||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
_share_iptables_call_v(const char *const *argv)
|
||||
_iptables_call_v(const char *const *argv)
|
||||
{
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_free char *argv_str = NULL;
|
||||
|
|
@ -213,7 +213,14 @@ _share_iptables_call_v(const char *const *argv)
|
|||
}
|
||||
|
||||
#define _share_iptables_call(...) \
|
||||
_share_iptables_call_v(NM_MAKE_STRV("" IPTABLES_PATH "", "--wait", "2", __VA_ARGS__))
|
||||
_iptables_call_v(NM_MAKE_STRV("" IPTABLES_PATH "", "--wait", "2", __VA_ARGS__))
|
||||
|
||||
#define _ipxtables_call(family, ...) \
|
||||
_iptables_call_v( \
|
||||
NM_MAKE_STRV((family == AF_INET ? "" IPTABLES_PATH "" : "" IP6TABLES_PATH ""), \
|
||||
"--wait", \
|
||||
"2", \
|
||||
__VA_ARGS__))
|
||||
|
||||
static gboolean
|
||||
_share_iptables_chain_op(const char *table, const char *chain, const char *op)
|
||||
|
|
@ -756,6 +763,85 @@ _fw_nft_set_shared_construct(gboolean up, const char *ip_iface, in_addr_t addr,
|
|||
return nm_str_buf_finalize_to_gbytes(&strbuf);
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
_fw_nft_wg_default_construct(const char *ip_iface, int family, int fwmark, gboolean up)
|
||||
{
|
||||
nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
|
||||
gs_free char *table_name = NULL;
|
||||
const char *family_str = family == AF_INET ? "ip" : "ip6";
|
||||
|
||||
table_name = _share_iptables_get_name(FALSE, "nm-wg", ip_iface);
|
||||
|
||||
_fw_nft_append_cmd_table(&strbuf, family_str, table_name, up);
|
||||
|
||||
if (up) {
|
||||
_append(&strbuf,
|
||||
"add chain %s %s premangle {"
|
||||
" type filter hook prerouting priority mangle; policy accept; "
|
||||
" meta l4proto udp meta mark set ct mark; "
|
||||
"};",
|
||||
family_str,
|
||||
table_name);
|
||||
|
||||
_append(&strbuf,
|
||||
"add chain %s %s postmangle {"
|
||||
" type filter hook postrouting priority mangle; policy accept; "
|
||||
" meta l4proto udp mark 0x%08x ct mark set meta mark; "
|
||||
"};",
|
||||
family_str,
|
||||
table_name,
|
||||
fwmark);
|
||||
}
|
||||
|
||||
return nm_str_buf_finalize_to_gbytes(&strbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
_fw_iptables_wg_configure(const char *ip_iface, int family, int fwmark, gboolean up)
|
||||
{
|
||||
gs_free char *comment_name = NULL;
|
||||
char fwmark_str[11];
|
||||
|
||||
comment_name = _share_iptables_get_name(FALSE, "nm-wg", ip_iface);
|
||||
g_snprintf(fwmark_str, sizeof(fwmark_str), "%" G_GUINT32_FORMAT, fwmark);
|
||||
|
||||
nm_assert(strlen(fwmark_str) > 0);
|
||||
|
||||
_ipxtables_call(family,
|
||||
"--table",
|
||||
"mangle",
|
||||
up ? "--insert" : "--delete",
|
||||
"POSTROUTING",
|
||||
"--match",
|
||||
"mark",
|
||||
"--mark",
|
||||
fwmark_str,
|
||||
"--protocol",
|
||||
"udp",
|
||||
"--jump",
|
||||
"CONNMARK",
|
||||
"--save-mark",
|
||||
"-m",
|
||||
"comment",
|
||||
"--comment",
|
||||
comment_name);
|
||||
|
||||
_ipxtables_call(family,
|
||||
"--table",
|
||||
"mangle",
|
||||
up ? "--insert" : "--delete",
|
||||
"PREROUTING",
|
||||
"--protocol",
|
||||
"udp",
|
||||
"--jump",
|
||||
"CONNMARK",
|
||||
"--restore-mark",
|
||||
"-m",
|
||||
"comment",
|
||||
"--comment",
|
||||
comment_name);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
GBytes *
|
||||
|
|
@ -1046,6 +1132,30 @@ nm_firewall_config_free(NMFirewallConfig *self)
|
|||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void
|
||||
nm_firewall_config_set_wg_rule(const char *ifname, int family, int fwmark, gboolean up)
|
||||
{
|
||||
nm_assert(NM_IN_SET(family, AF_INET, AF_INET6));
|
||||
|
||||
switch (nm_firewall_utils_get_backend()) {
|
||||
case NM_FIREWALL_BACKEND_NFTABLES:
|
||||
{
|
||||
gs_unref_bytes GBytes *stdin_buf = NULL;
|
||||
|
||||
stdin_buf = _fw_nft_wg_default_construct(ifname, family, fwmark, up);
|
||||
_fw_nft_call_sync(stdin_buf, NULL);
|
||||
break;
|
||||
}
|
||||
case NM_FIREWALL_BACKEND_IPTABLES:
|
||||
_fw_iptables_wg_configure(ifname, family, fwmark, up);
|
||||
break;
|
||||
case NM_FIREWALL_BACKEND_NONE:
|
||||
break;
|
||||
default:
|
||||
nm_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nm_firewall_config_apply_sync(NMFirewallConfig *self, gboolean up)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ NMFirewallConfig *nm_firewall_config_new_shared(const char *ip_iface, in_addr_t
|
|||
|
||||
void nm_firewall_config_free(NMFirewallConfig *self);
|
||||
|
||||
void nm_firewall_config_set_wg_rule(const char *ifname, int family, int fwmark, gboolean up);
|
||||
|
||||
void nm_firewall_config_apply_sync(NMFirewallConfig *self, gboolean up);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue