From a769c17af710ca10c0f4e66d798cc67296ba04da Mon Sep 17 00:00:00 2001 From: Jan Vaclav Date: Tue, 25 Mar 2025 14:00:53 +0100 Subject: [PATCH] firewall/wireguard: drop packets received to wrong interface If we receive a packet sent to the WG interface's address, but it does not come from the WG tunnel, let's assume something is broken and drop the packet. This is also inspired by wg-quick firewall rules: https://git.zx2c4.com/wireguard-tools/tree/src/wg-quick/linux.bash?id=17c78d31c27a3c311a2ff42a881057753c6ef2a4#n221 --- src/core/devices/nm-device-wireguard.c | 29 +++++++--- src/core/nm-firewall-utils.c | 74 +++++++++++++++++++++++--- src/core/nm-firewall-utils.h | 5 +- 3 files changed, 92 insertions(+), 16 deletions(-) diff --git a/src/core/devices/nm-device-wireguard.c b/src/core/devices/nm-device-wireguard.c index 52a35655c0..299e3b30e8 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -1213,18 +1213,33 @@ _configure_firewall(NMDeviceWireGuard *self, NMConnection *connection, int addr_ { 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; + NMSettingIPConfig *ip_config; 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); + switch (addr_family) { + case AF_INET: + if (!priv->auto_default_route_enabled_4) + return; + + ip_config = nm_connection_get_setting_ip4_config(connection); + break; + case AF_INET6: + if (!priv->auto_default_route_enabled_6) + return; + + ip_config = nm_connection_get_setting_ip6_config(connection); + break; + default: + nm_assert_not_reached(); + } + + nm_assert(ip_config); + nm_assert(priv->auto_default_route_fwmark); + + nm_firewall_config_set_wg_rule(ip_iface, ip_config, priv->auto_default_route_fwmark, up); } /*****************************************************************************/ diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c index 7b3b4a1032..03d246593f 100644 --- a/src/core/nm-firewall-utils.c +++ b/src/core/nm-firewall-utils.c @@ -8,6 +8,7 @@ #include "nm-firewall-utils.h" +#include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "libnm-glib-aux/nm-str-buf.h" #include "libnm-glib-aux/nm-io-utils.h" #include "libnm-platform/nm-platform.h" @@ -764,17 +765,42 @@ _fw_nft_set_shared_construct(gboolean up, const char *ip_iface, in_addr_t addr, } static GBytes * -_fw_nft_wg_default_construct(const char *ip_iface, int family, int fwmark, gboolean up) +_fw_nft_wg_default_construct(const char *ip_iface, + NMSettingIPConfig *ip_config, + 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"; + const char *family_str; table_name = _share_iptables_get_name(FALSE, "nm-wg", ip_iface); + family_str = nm_setting_ip_config_get_addr_family(ip_config) == AF_INET ? "ip" : "ip6"; _fw_nft_append_cmd_table(&strbuf, family_str, table_name, up); if (up) { + guint n_addresses = nm_setting_ip_config_get_num_addresses(ip_config); + + if (n_addresses) { + _append(&strbuf, "add chain %s %s preraw {", family_str, table_name); + + for (guint i = 0; i < n_addresses; i++) { + NMIPAddress *addr = nm_setting_ip_config_get_address(ip_config, i); + + _append(&strbuf, + " iifname != \"%s\" " + " %s daddr %s " + " fib saddr type != local " + "drop;", + ip_iface, + family_str, + nm_ip_address_get_address(addr)); + } + + _append(&strbuf, "};"); + } + _append(&strbuf, "add chain %s %s premangle {" " type filter hook prerouting priority mangle; policy accept; " @@ -797,16 +823,47 @@ _fw_nft_wg_default_construct(const char *ip_iface, int family, int fwmark, gbool } static void -_fw_iptables_wg_configure(const char *ip_iface, int family, int fwmark, gboolean up) +_fw_iptables_wg_configure(const char *ip_iface, + NMSettingIPConfig *ip_config, + int fwmark, + gboolean up) { gs_free char *comment_name = NULL; char fwmark_str[11]; + int family = nm_setting_ip_config_get_addr_family(ip_config); + guint n_addresses = nm_setting_ip_config_get_num_addresses(ip_config); 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); + for (guint i = 0; i < n_addresses; i++) { + NMIPAddress *addr = nm_setting_ip_config_get_address(ip_config, i); + + _ipxtables_call(family, + "--table", + "raw", + up ? "--insert" : "--delete", + "PREROUTING", + "!", + "--in-interface", + ip_iface, + "--destination", + nm_ip_address_get_address(addr), + "--match", + "addrtype", + "!", + "--src-type", + "LOCAL", + "-j", + "DROP", + "-m", + "comment", + "--comment", + comment_name); + } + _ipxtables_call(family, "--table", "mangle", @@ -1133,21 +1190,22 @@ nm_firewall_config_free(NMFirewallConfig *self) /*****************************************************************************/ void -nm_firewall_config_set_wg_rule(const char *ifname, int family, int fwmark, gboolean up) +nm_firewall_config_set_wg_rule(const char *ifname, + NMSettingIPConfig *ip_config, + 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); + stdin_buf = _fw_nft_wg_default_construct(ifname, ip_config, fwmark, up); _fw_nft_call_sync(stdin_buf, NULL); break; } case NM_FIREWALL_BACKEND_IPTABLES: - _fw_iptables_wg_configure(ifname, family, fwmark, up); + _fw_iptables_wg_configure(ifname, ip_config, fwmark, up); break; case NM_FIREWALL_BACKEND_NONE: break; diff --git a/src/core/nm-firewall-utils.h b/src/core/nm-firewall-utils.h index f46b3666fa..4df33d11db 100644 --- a/src/core/nm-firewall-utils.h +++ b/src/core/nm-firewall-utils.h @@ -24,7 +24,10 @@ 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_set_wg_rule(const char *ifname, + NMSettingIPConfig *ip_config, + int fwmark, + gboolean up); void nm_firewall_config_apply_sync(NMFirewallConfig *self, gboolean up);