firewall: set firewall rules for WireGuard

This commit is contained in:
Thomas Haller 2022-05-03 08:16:45 +02:00
parent c9326fbb92
commit b247b5b0b9
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
3 changed files with 169 additions and 2 deletions

View file

@ -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);
@ -1479,7 +1490,8 @@ link_config(NMDeviceWireGuard *self,
}
ifindex = nm_device_get_ip_ifindex(NM_DEVICE(self));
if (ifindex <= 0) {
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;
}

View file

@ -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();

View file

@ -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);