summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-05-03 08:16:45 +0200
committerThomas Haller <thaller@redhat.com>2022-05-03 09:06:53 +0200
commitb247b5b0b9893bcf7e45af6cd08ae8fa07c70216 (patch)
tree1719cdeccf360ed6c549607d8607546b9785ab34
parentc9326fbb92f360cbfd05ece8c7d1e81ff1e1499f (diff)
downloadNetworkManager-th/wireguard-firewall.tar.gz
firewall: set firewall rules for WireGuardth/wireguard-firewall
-rw-r--r--src/core/devices/nm-device-wireguard.c27
-rw-r--r--src/core/nm-firewall-utils.c138
-rw-r--r--src/core/nm-firewall-utils.h6
3 files changed, 169 insertions, 2 deletions
diff --git a/src/core/devices/nm-device-wireguard.c b/src/core/devices/nm-device-wireguard.c
index bdb96cb298..c51cee0b99 100644
--- a/src/core/devices/nm-device-wireguard.c
+++ b/src/core/devices/nm-device-wireguard.c
@@ -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"
@@ -120,6 +121,14 @@ typedef struct {
CList lst_peers_head;
GHashTable *peers;
+ union {
+ struct {
+ NMFirewallConfig *fw_config_6;
+ NMFirewallConfig *fw_config_4;
+ };
+ NMFirewallConfig *fw_config_x[2];
+ };
+
/* counts the numbers of peers that are currently resolving. */
guint peers_resolving_cnt;
@@ -1423,6 +1432,7 @@ link_config(NMDeviceWireGuard *self,
{
NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self);
nm_auto_bzero_secret_ptr NMSecretPtr wg_lnk_clear_private_key = NM_SECRET_PTR_INIT();
+ const char *ip_iface;
NMSettingWireGuard *s_wg;
NMConnection *connection;
NMActStageReturn ret;
@@ -1436,6 +1446,7 @@ link_config(NMDeviceWireGuard *self,
NMPlatformWireGuardChangeFlags wg_change_flags;
int ifindex;
int r;
+ int IS_IPv4;
NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_NONE);
@@ -1478,8 +1489,9 @@ link_config(NMDeviceWireGuard *self,
}
}
- ifindex = nm_device_get_ip_ifindex(NM_DEVICE(self));
- if (ifindex <= 0) {
+ ifindex = nm_device_get_ip_ifindex(NM_DEVICE(self));
+ ip_iface = nm_device_get_ip_iface(NM_DEVICE(self));
+ if (ifindex <= 0 || !ip_iface) {
NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
return NM_ACT_STAGE_RETURN_FAILURE;
}
@@ -1537,6 +1549,17 @@ link_config(NMDeviceWireGuard *self,
return NM_ACT_STAGE_RETURN_FAILURE;
}
+ for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
+ //XXX
+ nm_firewall_config_apply(priv->fw_config_x[IS_IPv4], FALSE);
+ nm_clear_pointer(&priv->fw_config_x[IS_IPv4], nm_firewall_config_free);
+ priv->fw_config_x[IS_IPv4] = nm_firewall_config_new_wireguard(ip_iface,
+ IS_IPv4 ? AF_INET : AF_INET6,
+ wg_lnk.fwmark,
+ NULL,
+ 0);
+ }
+
return NM_ACT_STAGE_RETURN_SUCCESS;
}
diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c
index 4d0117ab7e..116c4cf3d9 100644
--- a/src/core/nm-firewall-utils.c
+++ b/src/core/nm-firewall-utils.c
@@ -17,6 +17,7 @@
typedef enum _nm_packed {
FIREWALL_TOPIC_IP4_SHARED,
+ FIREWALL_TOPIC_WIREGUARD,
} FirewallTopic;
/*****************************************************************************/
@@ -689,6 +690,86 @@ _fw_nft_set_ip4_shared(gboolean up, const char *ip_iface, in_addr_t addr, guint8
/*****************************************************************************/
+static void
+_fw_nft_set_wireguard(gboolean up,
+ const char *ip_iface,
+ int addr_family,
+ guint32 fwmark,
+ const NMIPAddr *addrs,
+ gsize addrs_len)
+{
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
+ nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
+ gs_unref_bytes GBytes *stdin_buf = NULL;
+ gs_free char *table_name = NULL;
+ gs_free char *ss1 = NULL;
+ const char *pf = IS_IPv4 ? "ip" : "ip6";
+ gsize i;
+
+ table_name = _share_iptables_get_name(FALSE, "nm-wg", ip_iface);
+
+ /* Taken from wg-quick:
+ * https://git.zx2c4.com/wireguard-tools/tree/src/wg-quick/linux.bash?id=1fd95708391088742c139010cc6b821add941dec#n228 */
+
+#define _append(p_strbuf, fmt, ...) nm_str_buf_append_printf((p_strbuf), "" fmt "\n", ##__VA_ARGS__)
+
+ _append(&strbuf, "add table %s %s", pf, table_name);
+ _append(&strbuf, "%s table %s %s", up ? "flush" : "delete", pf, table_name);
+
+ if (up) {
+ _append(&strbuf,
+ "add chain %s %s preraw {"
+ " type filter hook prerouting priority -300; "
+ "};",
+ pf,
+ table_name);
+ _append(&strbuf,
+ "add chain %s %s premangle {"
+ " type filter hook prerouting priority -150; "
+ "};",
+ pf,
+ table_name);
+ _append(&strbuf,
+ "add chain %s %s postmangle {"
+ " type filter hook postrouting priority -150; "
+ "};",
+ pf,
+ table_name);
+ for (i = 0; i < addrs_len; i++) {
+ char addr_buf[NM_UTILS_INET_ADDRSTRLEN];
+
+ _append(
+ &strbuf,
+ "add rule %s %s preraw iifname != \"%s\" %s daddr %s fib saddr type != local drop",
+ pf,
+ table_name,
+ ip_iface,
+ pf,
+ nm_utils_inet_ntop(addr_family, &addrs[i], addr_buf));
+ }
+ _append(&strbuf,
+ "add rule %s %s postmangle meta l4proto udp mark %u ct mark set mark",
+ pf,
+ table_name,
+ fwmark);
+ _append(&strbuf,
+ "add rule %s %s premangle meta l4proto udp meta mark set ct mark",
+ pf,
+ table_name);
+ }
+
+ nm_log_trace(LOGD_SHARING,
+ "firewall: nft command: [ %s ]",
+ nm_utils_str_utf8safe_escape(nm_str_buf_get_str(&strbuf),
+ NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL,
+ &ss1));
+
+ stdin_buf = nm_str_buf_finalize_to_gbytes(&strbuf);
+ _fw_nft_call_sync(stdin_buf, NULL);
+}
+
+/*****************************************************************************/
+
struct _NMFirewallConfig {
FirewallTopic topic;
char *ip_iface;
@@ -697,6 +778,12 @@ struct _NMFirewallConfig {
in_addr_t addr;
guint8 plen;
} ip4_shared;
+ struct {
+ int addr_family;
+ guint32 fwmark;
+ NMIPAddr *addrs;
+ gsize addrs_len;
+ } wireguard;
};
};
@@ -722,6 +809,35 @@ nm_firewall_config_new_ip4_shared(const char *ip_iface, in_addr_t addr, guint8 p
return self;
}
+NMFirewallConfig *
+nm_firewall_config_new_wireguard(const char *ip_iface,
+ int addr_family,
+ guint32 fwmark,
+ const NMIPAddr *addrs,
+ gsize addrs_len)
+{
+ NMFirewallConfig *self;
+
+ nm_assert(ip_iface);
+ nm_assert_addr_family(addr_family);
+ nm_assert(addrs_len > 0);
+ nm_assert(addrs);
+
+ self = g_slice_new(NMFirewallConfig);
+ *self = (NMFirewallConfig){
+ .topic = FIREWALL_TOPIC_WIREGUARD,
+ .ip_iface = g_strdup(ip_iface),
+ .wireguard =
+ {
+ .addr_family = addr_family,
+ .fwmark = fwmark,
+ .addrs = nm_memdup(addrs, addrs_len * sizeof(addrs[0])),
+ .addrs_len = addrs_len,
+ },
+ };
+ return self;
+}
+
void
nm_firewall_config_free(NMFirewallConfig *self)
{
@@ -731,6 +847,9 @@ nm_firewall_config_free(NMFirewallConfig *self)
switch (self->topic) {
case FIREWALL_TOPIC_IP4_SHARED:
goto out;
+ case FIREWALL_TOPIC_WIREGUARD:
+ g_free(self->wireguard.addrs);
+ goto out;
}
nm_assert_not_reached();
@@ -769,6 +888,25 @@ nm_firewall_config_apply(NMFirewallConfig *self, gboolean up)
goto out_bug;
}
goto out_bug;
+ case FIREWALL_TOPIC_WIREGUARD:
+ switch (nm_firewall_utils_get_backend()) {
+ case NM_FIREWALL_BACKEND_IPTABLES:
+ /* XXX: Not implemented. */
+ return;
+ case NM_FIREWALL_BACKEND_NFTABLES:
+ _fw_nft_set_wireguard(up,
+ self->ip_iface,
+ self->wireguard.addr_family,
+ self->wireguard.fwmark,
+ self->wireguard.addrs,
+ self->wireguard.addrs_len);
+ return;
+ case NM_FIREWALL_BACKEND_NONE:
+ return;
+ case NM_FIREWALL_BACKEND_UNKNOWN:
+ goto out_bug;
+ }
+ goto out_bug;
}
out_bug:
nm_assert_not_reached();
diff --git a/src/core/nm-firewall-utils.h b/src/core/nm-firewall-utils.h
index 12a65b77e0..3417baa652 100644
--- a/src/core/nm-firewall-utils.h
+++ b/src/core/nm-firewall-utils.h
@@ -23,6 +23,12 @@ typedef struct _NMFirewallConfig NMFirewallConfig;
NMFirewallConfig *
nm_firewall_config_new_ip4_shared(const char *ip_iface, in_addr_t addr, guint8 plen);
+NMFirewallConfig *nm_firewall_config_new_wireguard(const char *ip_iface,
+ int addr_family,
+ guint32 fwmark,
+ const NMIPAddr *addrs,
+ gsize addrs_len);
+
void nm_firewall_config_free(NMFirewallConfig *self);
void nm_firewall_config_apply(NMFirewallConfig *self, gboolean up);