2021-05-05 22:39:28 +02:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2004 - 2016 Red Hat, Inc.
|
|
|
|
|
* Copyright (C) 2005 - 2008 Novell, Inc.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "src/core/nm-default-daemon.h"
|
|
|
|
|
|
|
|
|
|
#include "nm-firewall-utils.h"
|
2021-05-05 22:07:55 +02:00
|
|
|
|
|
|
|
|
#include "libnm-glib-aux/nm-str-buf.h"
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
#include "libnm-glib-aux/nm-io-utils.h"
|
2021-05-05 22:07:55 +02:00
|
|
|
#include "libnm-platform/nm-platform.h"
|
|
|
|
|
|
2021-05-06 16:50:25 +02:00
|
|
|
#include "nm-config.h"
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
#include "NetworkManagerUtils.h"
|
2021-05-06 16:50:25 +02:00
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
|
const char *name;
|
|
|
|
|
const char *path;
|
|
|
|
|
} FirewallBackends[] = {
|
2021-05-12 12:02:33 +02:00
|
|
|
[NM_FIREWALL_BACKEND_NONE - 1] =
|
|
|
|
|
{
|
|
|
|
|
.name = "none",
|
|
|
|
|
},
|
2021-05-06 16:50:25 +02:00
|
|
|
[NM_FIREWALL_BACKEND_NFTABLES - 1] =
|
|
|
|
|
{
|
|
|
|
|
.name = "nftables",
|
|
|
|
|
.path = NFT_PATH,
|
|
|
|
|
},
|
|
|
|
|
[NM_FIREWALL_BACKEND_IPTABLES - 1] =
|
|
|
|
|
{
|
|
|
|
|
.name = "iptables",
|
|
|
|
|
.path = IPTABLES_PATH,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2021-05-05 22:07:55 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2022-09-13 20:17:20 +02:00
|
|
|
static const char *
|
|
|
|
|
_nft_ifname_valid(const char *str)
|
|
|
|
|
{
|
|
|
|
|
gsize i;
|
|
|
|
|
|
|
|
|
|
/* `nft -f -` takes certain strings, like "device $IFNAME", but
|
|
|
|
|
* those strings are from a limited character set. Check that
|
|
|
|
|
* @str is valid according to those rules.
|
|
|
|
|
*
|
|
|
|
|
* src/scanner.l:
|
|
|
|
|
* digit [0-9]
|
|
|
|
|
* letter [a-zA-Z]
|
|
|
|
|
* string ({letter}|[_.])({letter}|{digit}|[/\-_\.])*
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
if (!str || !str[0])
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
for (i = 0; str[i]; i++) {
|
|
|
|
|
switch (str[i]) {
|
|
|
|
|
case 'a' ... 'z':
|
|
|
|
|
case 'A' ... 'Z':
|
|
|
|
|
case '_':
|
|
|
|
|
case '.':
|
|
|
|
|
continue;
|
|
|
|
|
case '0' ... '9':
|
|
|
|
|
case '/':
|
|
|
|
|
case '-':
|
|
|
|
|
if (i == 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
continue;
|
|
|
|
|
default:
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-05-25 15:05:29 +02:00
|
|
|
if (i >= NM_IFNAMSIZ)
|
2022-09-13 20:17:20 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
_strbuf_set_sanitized(NMStrBuf *strbuf, const char *prefix, const char *str_to_sanitize)
|
|
|
|
|
{
|
|
|
|
|
nm_str_buf_reset(strbuf);
|
|
|
|
|
|
|
|
|
|
if (prefix)
|
|
|
|
|
nm_str_buf_append(strbuf, prefix);
|
|
|
|
|
|
|
|
|
|
for (; str_to_sanitize[0] != '\0'; str_to_sanitize++) {
|
|
|
|
|
const char ch = str_to_sanitize[0];
|
|
|
|
|
|
|
|
|
|
if (g_ascii_isalpha(ch) || g_ascii_isdigit(ch)) {
|
|
|
|
|
nm_str_buf_append_c(strbuf, ch);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
nm_str_buf_append_c(strbuf, '_');
|
|
|
|
|
nm_str_buf_append_c_hex(strbuf, ch, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nm_str_buf_get_str(strbuf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-05-05 22:07:55 +02:00
|
|
|
#define _SHARE_IPTABLES_SUBNET_TO_STR_LEN (INET_ADDRSTRLEN + 1 + 2 + 1)
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
_share_iptables_subnet_to_str(char buf[static _SHARE_IPTABLES_SUBNET_TO_STR_LEN],
|
|
|
|
|
in_addr_t addr,
|
|
|
|
|
guint8 plen)
|
|
|
|
|
{
|
|
|
|
|
char buf_addr[INET_ADDRSTRLEN];
|
|
|
|
|
in_addr_t netmask;
|
|
|
|
|
int l;
|
|
|
|
|
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
netmask = nm_ip4_addr_netmask_from_prefix(plen);
|
2021-05-05 22:07:55 +02:00
|
|
|
|
|
|
|
|
l = g_snprintf(buf,
|
|
|
|
|
_SHARE_IPTABLES_SUBNET_TO_STR_LEN,
|
|
|
|
|
"%s/%u",
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
nm_inet4_ntop(addr & netmask, buf_addr),
|
2021-05-05 22:07:55 +02:00
|
|
|
plen);
|
|
|
|
|
nm_assert(l < _SHARE_IPTABLES_SUBNET_TO_STR_LEN);
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
2021-05-10 18:45:03 +02:00
|
|
|
_share_iptables_get_name(gboolean is_iptables_chain, const char *prefix, const char *ip_iface)
|
2021-05-05 22:07:55 +02:00
|
|
|
{
|
|
|
|
|
NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE);
|
|
|
|
|
gsize ip_iface_len;
|
|
|
|
|
|
|
|
|
|
nm_assert(prefix);
|
|
|
|
|
nm_assert(ip_iface);
|
|
|
|
|
|
|
|
|
|
/* This function is used to generate iptables chain names and comments.
|
|
|
|
|
* Chain names must be shorter than 29 chars. Comments don't have this
|
|
|
|
|
* limitation.
|
|
|
|
|
*
|
|
|
|
|
* Below we sanitize the ip_iface. If it's all benign, we use
|
|
|
|
|
* - either "-$IP_IFACE" (at most 16 chars)
|
|
|
|
|
* - otherwise, we base64 encode the name as "$(base64 $IP_IFACE)", at
|
|
|
|
|
* most 20 chars.
|
|
|
|
|
*
|
|
|
|
|
* Since for benign names we already add a '-', prefix probably should not
|
|
|
|
|
* contain a '-'. The '-' is necessary to distinguish between base64 encoding
|
|
|
|
|
* an plain name.
|
|
|
|
|
*
|
|
|
|
|
* That means, for chain names the prefix must be at most 8 chars long. */
|
2021-05-10 18:45:03 +02:00
|
|
|
nm_assert(!is_iptables_chain || (strlen(prefix) <= 8));
|
2021-05-05 22:07:55 +02:00
|
|
|
|
|
|
|
|
nm_str_buf_append(&strbuf, prefix);
|
|
|
|
|
|
|
|
|
|
ip_iface_len = strlen(ip_iface);
|
2023-05-25 15:05:29 +02:00
|
|
|
G_STATIC_ASSERT_EXPR(NM_IFNAMSIZ == 16);
|
|
|
|
|
if (ip_iface_len >= NM_IFNAMSIZ) {
|
2021-05-05 22:07:55 +02:00
|
|
|
nm_assert_not_reached();
|
2023-05-25 15:05:29 +02:00
|
|
|
ip_iface_len = NM_IFNAMSIZ - 1;
|
2021-05-05 22:07:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NM_STRCHAR_ALL(ip_iface,
|
|
|
|
|
ch,
|
|
|
|
|
(ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z')
|
|
|
|
|
|| (ch >= 'A' && ch <= 'Z') || NM_IN_SET(ch, '.', '_', '-', '+'))) {
|
|
|
|
|
nm_str_buf_append_c(&strbuf, '-');
|
|
|
|
|
nm_str_buf_append(&strbuf, ip_iface);
|
|
|
|
|
} else {
|
|
|
|
|
gs_free char *s = NULL;
|
|
|
|
|
|
|
|
|
|
s = g_base64_encode((const guchar *) ip_iface, ip_iface_len);
|
|
|
|
|
nm_str_buf_append(&strbuf, s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nm_str_buf_finalize(&strbuf, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-15 08:56:19 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-05-05 22:07:55 +02:00
|
|
|
static gboolean
|
|
|
|
|
_share_iptables_call_v(const char *const *argv)
|
|
|
|
|
{
|
|
|
|
|
gs_free_error GError *error = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
gs_free char *argv_str = NULL;
|
2021-05-05 22:07:55 +02:00
|
|
|
int status;
|
|
|
|
|
|
|
|
|
|
nm_log_dbg(LOGD_SHARING, "iptables: %s", (argv_str = g_strjoinv(" ", (char **) argv)));
|
|
|
|
|
|
|
|
|
|
if (!g_spawn_sync("/",
|
|
|
|
|
(char **) argv,
|
|
|
|
|
(char **) NM_PTRARRAY_EMPTY(const char *),
|
|
|
|
|
G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
&status,
|
|
|
|
|
&error)) {
|
|
|
|
|
nm_log_warn(LOGD_SHARING,
|
|
|
|
|
"iptables: error executing command %s: %s",
|
|
|
|
|
argv[0],
|
|
|
|
|
error->message);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!g_spawn_check_exit_status(status, &error)) {
|
|
|
|
|
nm_log_warn(LOGD_SHARING, "iptables: command %s failed: %s", argv[0], error->message);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-10 19:42:43 +01:00
|
|
|
#define _share_iptables_call(...) \
|
2023-01-10 19:46:01 +01:00
|
|
|
_share_iptables_call_v(NM_MAKE_STRV("" IPTABLES_PATH "", "--wait", "2", __VA_ARGS__))
|
2021-05-05 22:07:55 +02:00
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_share_iptables_chain_op(const char *table, const char *chain, const char *op)
|
|
|
|
|
{
|
2023-01-10 19:42:43 +01:00
|
|
|
return _share_iptables_call("--table", table, op, chain);
|
2021-05-05 22:07:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_share_iptables_chain_delete(const char *table, const char *chain)
|
|
|
|
|
{
|
|
|
|
|
_share_iptables_chain_op(table, chain, "--flush");
|
|
|
|
|
return _share_iptables_chain_op(table, chain, "--delete-chain");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_share_iptables_chain_add(const char *table, const char *chain)
|
|
|
|
|
{
|
|
|
|
|
if (_share_iptables_chain_op(table, chain, "--new-chain"))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
_share_iptables_chain_delete(table, chain);
|
|
|
|
|
return _share_iptables_chain_op(table, chain, "--new-chain");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2022-09-13 19:39:14 +02:00
|
|
|
_share_iptables_set_masquerade_sync(gboolean up, const char *ip_iface, in_addr_t addr, guint8 plen)
|
2021-05-05 22:07:55 +02:00
|
|
|
{
|
|
|
|
|
char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN];
|
|
|
|
|
gs_free char *comment_name = NULL;
|
|
|
|
|
|
2021-05-10 18:45:03 +02:00
|
|
|
comment_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface);
|
2021-05-05 22:07:55 +02:00
|
|
|
|
|
|
|
|
_share_iptables_subnet_to_str(str_subnet, addr, plen);
|
2023-01-10 19:42:43 +01:00
|
|
|
_share_iptables_call("--table",
|
2021-05-05 22:07:55 +02:00
|
|
|
"nat",
|
2022-09-13 19:22:58 +02:00
|
|
|
up ? "--insert" : "--delete",
|
2021-05-05 22:07:55 +02:00
|
|
|
"POSTROUTING",
|
|
|
|
|
"--source",
|
|
|
|
|
str_subnet,
|
|
|
|
|
"!",
|
|
|
|
|
"--destination",
|
|
|
|
|
str_subnet,
|
|
|
|
|
"--jump",
|
|
|
|
|
"MASQUERADE",
|
|
|
|
|
"-m",
|
|
|
|
|
"comment",
|
|
|
|
|
"--comment",
|
|
|
|
|
comment_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_share_iptables_set_shared_chains_add(const char *chain_input,
|
|
|
|
|
const char *chain_forward,
|
|
|
|
|
const char *ip_iface,
|
|
|
|
|
in_addr_t addr,
|
|
|
|
|
guint plen)
|
|
|
|
|
{
|
|
|
|
|
const char *const input_params[][2] = {
|
|
|
|
|
{
|
|
|
|
|
"tcp",
|
|
|
|
|
"67",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"udp",
|
|
|
|
|
"67",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"tcp",
|
|
|
|
|
"53",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"udp",
|
|
|
|
|
"53",
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN];
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
_share_iptables_subnet_to_str(str_subnet, addr, plen);
|
|
|
|
|
|
|
|
|
|
_share_iptables_chain_add("filter", chain_input);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < (int) G_N_ELEMENTS(input_params); i++) {
|
2023-01-10 19:42:43 +01:00
|
|
|
_share_iptables_call("--table",
|
2021-05-05 22:07:55 +02:00
|
|
|
"filter",
|
|
|
|
|
"--append",
|
|
|
|
|
chain_input,
|
|
|
|
|
"--protocol",
|
|
|
|
|
input_params[i][0],
|
|
|
|
|
"--destination-port",
|
|
|
|
|
input_params[i][1],
|
|
|
|
|
"--jump",
|
|
|
|
|
"ACCEPT");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_share_iptables_chain_add("filter", chain_forward);
|
|
|
|
|
|
2023-01-10 19:42:43 +01:00
|
|
|
_share_iptables_call("--table",
|
2021-05-05 22:07:55 +02:00
|
|
|
"filter",
|
|
|
|
|
"--append",
|
|
|
|
|
chain_forward,
|
|
|
|
|
"--destination",
|
|
|
|
|
str_subnet,
|
|
|
|
|
"--out-interface",
|
|
|
|
|
ip_iface,
|
|
|
|
|
"--match",
|
|
|
|
|
"state",
|
|
|
|
|
"--state",
|
|
|
|
|
"ESTABLISHED,RELATED",
|
|
|
|
|
"--jump",
|
|
|
|
|
"ACCEPT");
|
2023-01-10 19:42:43 +01:00
|
|
|
_share_iptables_call("--table",
|
2021-05-05 22:07:55 +02:00
|
|
|
"filter",
|
|
|
|
|
"--append",
|
|
|
|
|
chain_forward,
|
|
|
|
|
"--source",
|
|
|
|
|
str_subnet,
|
|
|
|
|
"--in-interface",
|
|
|
|
|
ip_iface,
|
|
|
|
|
"--jump",
|
|
|
|
|
"ACCEPT");
|
2023-01-10 19:42:43 +01:00
|
|
|
_share_iptables_call("--table",
|
2021-05-05 22:07:55 +02:00
|
|
|
"filter",
|
|
|
|
|
"--append",
|
|
|
|
|
chain_forward,
|
|
|
|
|
"--in-interface",
|
|
|
|
|
ip_iface,
|
|
|
|
|
"--out-interface",
|
|
|
|
|
ip_iface,
|
|
|
|
|
"--jump",
|
|
|
|
|
"ACCEPT");
|
2023-01-10 19:42:43 +01:00
|
|
|
_share_iptables_call("--table",
|
2021-05-05 22:07:55 +02:00
|
|
|
"filter",
|
|
|
|
|
"--append",
|
|
|
|
|
chain_forward,
|
|
|
|
|
"--out-interface",
|
|
|
|
|
ip_iface,
|
|
|
|
|
"--jump",
|
|
|
|
|
"REJECT");
|
2023-01-10 19:42:43 +01:00
|
|
|
_share_iptables_call("--table",
|
2021-05-05 22:07:55 +02:00
|
|
|
"filter",
|
|
|
|
|
"--append",
|
|
|
|
|
chain_forward,
|
|
|
|
|
"--in-interface",
|
|
|
|
|
ip_iface,
|
|
|
|
|
"--jump",
|
|
|
|
|
"REJECT");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_share_iptables_set_shared_chains_delete(const char *chain_input, const char *chain_forward)
|
|
|
|
|
{
|
|
|
|
|
_share_iptables_chain_delete("filter", chain_input);
|
|
|
|
|
_share_iptables_chain_delete("filter", chain_forward);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-13 19:39:14 +02:00
|
|
|
static void
|
|
|
|
|
_share_iptables_set_shared_sync(gboolean up, const char *ip_iface, in_addr_t addr, guint plen)
|
2021-05-05 22:07:55 +02:00
|
|
|
{
|
|
|
|
|
gs_free char *comment_name = NULL;
|
|
|
|
|
gs_free char *chain_input = NULL;
|
|
|
|
|
gs_free char *chain_forward = NULL;
|
|
|
|
|
|
2021-05-10 18:45:03 +02:00
|
|
|
comment_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface);
|
|
|
|
|
chain_input = _share_iptables_get_name(TRUE, "nm-sh-in", ip_iface);
|
|
|
|
|
chain_forward = _share_iptables_get_name(TRUE, "nm-sh-fw", ip_iface);
|
2021-05-05 22:07:55 +02:00
|
|
|
|
2022-09-13 19:22:58 +02:00
|
|
|
if (up)
|
2021-05-05 22:07:55 +02:00
|
|
|
_share_iptables_set_shared_chains_add(chain_input, chain_forward, ip_iface, addr, plen);
|
|
|
|
|
|
2023-01-10 19:42:43 +01:00
|
|
|
_share_iptables_call("--table",
|
2021-05-05 22:07:55 +02:00
|
|
|
"filter",
|
2022-09-13 19:22:58 +02:00
|
|
|
up ? "--insert" : "--delete",
|
2021-05-05 22:07:55 +02:00
|
|
|
"INPUT",
|
|
|
|
|
"--in-interface",
|
|
|
|
|
ip_iface,
|
|
|
|
|
"--jump",
|
|
|
|
|
chain_input,
|
|
|
|
|
"-m",
|
|
|
|
|
"comment",
|
|
|
|
|
"--comment",
|
|
|
|
|
comment_name);
|
|
|
|
|
|
2023-01-10 19:42:43 +01:00
|
|
|
_share_iptables_call("--table",
|
2021-05-05 22:07:55 +02:00
|
|
|
"filter",
|
2022-09-13 19:22:58 +02:00
|
|
|
up ? "--insert" : "--delete",
|
2021-05-05 22:07:55 +02:00
|
|
|
"FORWARD",
|
|
|
|
|
"--jump",
|
|
|
|
|
chain_forward,
|
|
|
|
|
"-m",
|
|
|
|
|
"comment",
|
|
|
|
|
"--comment",
|
|
|
|
|
comment_name);
|
|
|
|
|
|
2022-09-13 19:22:58 +02:00
|
|
|
if (!up)
|
2021-05-05 22:07:55 +02:00
|
|
|
_share_iptables_set_shared_chains_delete(chain_input, chain_forward);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 16:50:25 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
typedef struct {
|
2021-11-09 13:28:54 +01:00
|
|
|
GTask *task;
|
|
|
|
|
GSubprocess *subprocess;
|
|
|
|
|
GSource *timeout_source;
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
GCancellable *intern_cancellable;
|
2021-11-09 13:28:54 +01:00
|
|
|
char *identifier;
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
gulong cancellable_id;
|
|
|
|
|
} FwNftCallData;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_fw_nft_call_data_free(FwNftCallData *call_data, GError *error_take)
|
|
|
|
|
{
|
|
|
|
|
nm_clear_g_signal_handler(g_task_get_cancellable(call_data->task), &call_data->cancellable_id);
|
|
|
|
|
nm_clear_g_cancellable(&call_data->intern_cancellable);
|
|
|
|
|
nm_clear_g_source_inst(&call_data->timeout_source);
|
|
|
|
|
|
|
|
|
|
if (error_take)
|
2021-06-15 19:40:34 +02:00
|
|
|
g_task_return_error(call_data->task, error_take);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
else
|
|
|
|
|
g_task_return_boolean(call_data->task, TRUE);
|
|
|
|
|
|
|
|
|
|
g_object_unref(call_data->task);
|
|
|
|
|
nm_g_object_unref(call_data->subprocess);
|
|
|
|
|
g_free(call_data->identifier);
|
|
|
|
|
|
|
|
|
|
nm_g_slice_free(call_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_fw_nft_call_communicate_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
FwNftCallData *call_data = user_data;
|
|
|
|
|
gs_free_error GError *error = NULL;
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
gs_unref_bytes GBytes *stdout_buf = NULL;
|
|
|
|
|
gs_unref_bytes GBytes *stderr_buf = NULL;
|
|
|
|
|
|
|
|
|
|
nm_assert(source == (gpointer) call_data->subprocess);
|
|
|
|
|
|
|
|
|
|
if (!g_subprocess_communicate_finish(G_SUBPROCESS(source),
|
|
|
|
|
result,
|
|
|
|
|
&stdout_buf,
|
|
|
|
|
&stderr_buf,
|
|
|
|
|
&error)) {
|
|
|
|
|
/* on any error, the process might still be running. We need to abort it in
|
|
|
|
|
* the background... */
|
2021-06-15 18:11:00 +02:00
|
|
|
if (!nm_utils_error_is_cancelled(error)) {
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
nm_log_dbg(LOGD_SHARING,
|
|
|
|
|
"firewall: nft[%s]: communication failed: %s. Kill process",
|
|
|
|
|
call_data->identifier,
|
|
|
|
|
error->message);
|
2021-06-15 18:11:00 +02:00
|
|
|
} else if (!call_data->timeout_source) {
|
|
|
|
|
nm_log_dbg(LOGD_SHARING,
|
|
|
|
|
"firewall: ntf[%s]: communication timed out. Kill process",
|
|
|
|
|
call_data->identifier);
|
|
|
|
|
nm_clear_error(&error);
|
|
|
|
|
nm_utils_error_set(&error, NM_UTILS_ERROR_UNKNOWN, "timeout communicating with nft");
|
|
|
|
|
} else {
|
|
|
|
|
nm_log_dbg(LOGD_SHARING,
|
|
|
|
|
"firewall: ntf[%s]: communication cancelled. Kill process",
|
|
|
|
|
call_data->identifier);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
_nm_unused nm_auto_pop_gmaincontext GMainContext *main_context =
|
2021-06-15 18:24:11 +02:00
|
|
|
nm_g_main_context_push_thread_default_if_necessary(NULL);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
|
|
|
|
|
nm_shutdown_wait_obj_register_object(call_data->subprocess, "nft-terminate");
|
2022-02-18 13:18:47 +01:00
|
|
|
G_STATIC_ASSERT_EXPR(200 < NM_SHUTDOWN_TIMEOUT_ADDITIONAL_MSEC * 2 / 3);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
nm_g_subprocess_terminate_in_background(call_data->subprocess, 200);
|
|
|
|
|
}
|
|
|
|
|
} else if (g_subprocess_get_successful(call_data->subprocess)) {
|
|
|
|
|
nm_log_dbg(LOGD_SHARING, "firewall: nft[%s]: command successful", call_data->identifier);
|
|
|
|
|
} else {
|
2022-09-27 18:07:01 +02:00
|
|
|
char buf[NM_UTILS_GET_PROCESS_EXIT_STATUS_BUF_LEN];
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
gs_free char *ss_stdout = NULL;
|
|
|
|
|
gs_free char *ss_stderr = NULL;
|
|
|
|
|
gboolean print_stdout = (stdout_buf && g_bytes_get_size(stdout_buf) > 0);
|
|
|
|
|
gboolean print_stderr = (stderr_buf && g_bytes_get_size(stderr_buf) > 0);
|
2022-09-27 18:07:01 +02:00
|
|
|
int status;
|
|
|
|
|
|
|
|
|
|
status = g_subprocess_get_status(call_data->subprocess);
|
|
|
|
|
|
|
|
|
|
nm_utils_get_process_exit_status_desc_buf(status, buf, sizeof(buf));
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
|
|
|
|
|
nm_log_warn(LOGD_SHARING,
|
2022-09-27 18:07:01 +02:00
|
|
|
"firewall: nft[%s]: command %s:%s%s%s%s%s%s%s",
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
call_data->identifier,
|
2022-09-27 18:07:01 +02:00
|
|
|
buf,
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
print_stdout || print_stderr ? "" : " unknown reason",
|
|
|
|
|
NM_PRINT_FMT_QUOTED(
|
|
|
|
|
print_stdout,
|
|
|
|
|
" (stdout: \"",
|
|
|
|
|
nm_utils_buf_utf8safe_escape_bytes(stdout_buf,
|
|
|
|
|
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL,
|
|
|
|
|
&ss_stdout),
|
|
|
|
|
"\")",
|
|
|
|
|
""),
|
|
|
|
|
NM_PRINT_FMT_QUOTED(
|
|
|
|
|
print_stderr,
|
|
|
|
|
" (stderr: \"",
|
|
|
|
|
nm_utils_buf_utf8safe_escape_bytes(stderr_buf,
|
|
|
|
|
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL,
|
|
|
|
|
&ss_stderr),
|
|
|
|
|
"\")",
|
|
|
|
|
""));
|
2022-09-27 18:07:01 +02:00
|
|
|
|
|
|
|
|
nm_utils_error_set(&error, NM_UTILS_ERROR_COMMAND_FAILED, "nft command %s", buf);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 19:40:34 +02:00
|
|
|
_fw_nft_call_data_free(call_data, g_steal_pointer(&error));
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_fw_nft_call_cancelled_cb(GCancellable *cancellable, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
FwNftCallData *call_data = user_data;
|
|
|
|
|
|
|
|
|
|
if (call_data->cancellable_id == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
nm_log_dbg(LOGD_SHARING, "firewall: nft[%s]: operation cancelled", call_data->identifier);
|
|
|
|
|
|
|
|
|
|
nm_clear_g_signal_handler(g_task_get_cancellable(call_data->task), &call_data->cancellable_id);
|
|
|
|
|
nm_clear_g_cancellable(&call_data->intern_cancellable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_fw_nft_call_timeout_cb(gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
FwNftCallData *call_data = user_data;
|
|
|
|
|
|
|
|
|
|
nm_clear_g_source_inst(&call_data->timeout_source);
|
|
|
|
|
nm_log_dbg(LOGD_SHARING,
|
|
|
|
|
"firewall: nft[%s]: cancel operation after timeout",
|
|
|
|
|
call_data->identifier);
|
|
|
|
|
|
|
|
|
|
nm_clear_g_cancellable(&call_data->intern_cancellable);
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-15 08:56:19 +02:00
|
|
|
void
|
|
|
|
|
nm_firewall_nft_call(GBytes *stdin_buf,
|
|
|
|
|
GCancellable *cancellable,
|
|
|
|
|
GAsyncReadyCallback callback,
|
|
|
|
|
gpointer callback_user_data)
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
{
|
|
|
|
|
gs_unref_object GSubprocessLauncher *subprocess_launcher = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
gs_free_error GError *error = NULL;
|
|
|
|
|
FwNftCallData *call_data;
|
2022-09-15 09:06:58 +02:00
|
|
|
gs_free char *ss1 = NULL;
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
|
|
|
|
|
call_data = g_slice_new(FwNftCallData);
|
|
|
|
|
*call_data = (FwNftCallData){
|
2022-09-15 08:56:19 +02:00
|
|
|
.task =
|
|
|
|
|
nm_g_task_new(NULL, cancellable, nm_firewall_nft_call, callback, callback_user_data),
|
|
|
|
|
.subprocess = NULL,
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
.timeout_source = NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2022-09-15 09:06:58 +02:00
|
|
|
nm_log_trace(LOGD_SHARING,
|
|
|
|
|
"firewall: nft: call command: [ '%s' ]",
|
|
|
|
|
nm_utils_buf_utf8safe_escape_bytes(stdin_buf,
|
|
|
|
|
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL,
|
|
|
|
|
&ss1));
|
|
|
|
|
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
if (cancellable) {
|
|
|
|
|
call_data->cancellable_id = g_cancellable_connect(cancellable,
|
|
|
|
|
G_CALLBACK(_fw_nft_call_cancelled_cb),
|
|
|
|
|
call_data,
|
|
|
|
|
NULL);
|
|
|
|
|
if (call_data->cancellable_id == 0) {
|
|
|
|
|
nm_log_dbg(LOGD_SHARING, "firewall: nft: already cancelled");
|
|
|
|
|
nm_utils_error_set_cancelled(&error, FALSE, NULL);
|
|
|
|
|
_fw_nft_call_data_free(call_data, g_steal_pointer(&error));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
subprocess_launcher =
|
|
|
|
|
g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE
|
|
|
|
|
| G_SUBPROCESS_FLAGS_STDERR_PIPE);
|
|
|
|
|
g_subprocess_launcher_set_environ(subprocess_launcher, NM_STRV_EMPTY());
|
|
|
|
|
|
|
|
|
|
call_data->subprocess = g_subprocess_launcher_spawnv(subprocess_launcher,
|
|
|
|
|
NM_MAKE_STRV(NFT_PATH, "-f", "-"),
|
|
|
|
|
&error);
|
|
|
|
|
|
|
|
|
|
if (!call_data->subprocess) {
|
|
|
|
|
nm_log_dbg(LOGD_SHARING, "firewall: nft: spawning nft failed: %s", error->message);
|
|
|
|
|
_fw_nft_call_data_free(call_data, g_steal_pointer(&error));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
call_data->identifier = g_strdup(g_subprocess_get_identifier(call_data->subprocess));
|
|
|
|
|
|
|
|
|
|
nm_log_dbg(LOGD_SHARING, "firewall: nft[%s]: communicate with nft", call_data->identifier);
|
|
|
|
|
|
|
|
|
|
nm_shutdown_wait_obj_register_object(call_data->task, "nft-call");
|
|
|
|
|
|
|
|
|
|
call_data->intern_cancellable = g_cancellable_new(),
|
|
|
|
|
|
|
|
|
|
g_subprocess_communicate_async(call_data->subprocess,
|
|
|
|
|
stdin_buf,
|
|
|
|
|
call_data->intern_cancellable,
|
|
|
|
|
_fw_nft_call_communicate_cb,
|
|
|
|
|
call_data);
|
|
|
|
|
|
|
|
|
|
call_data->timeout_source =
|
2022-02-18 13:36:44 +01:00
|
|
|
nm_g_source_attach(nm_g_timeout_source_new((NM_SHUTDOWN_TIMEOUT_1500_MSEC * 2) / 3,
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
G_PRIORITY_DEFAULT,
|
|
|
|
|
_fw_nft_call_timeout_cb,
|
|
|
|
|
call_data,
|
|
|
|
|
NULL),
|
|
|
|
|
g_task_get_context(call_data->task));
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-15 08:56:19 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_firewall_nft_call_finish(GAsyncResult *result, GError **error)
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
{
|
2022-09-15 08:56:19 +02:00
|
|
|
g_return_val_if_fail(nm_g_task_is_valid(result, NULL, nm_firewall_nft_call), FALSE);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
|
|
|
|
|
return g_task_propagate_boolean(G_TASK(result), error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
GMainLoop *loop;
|
2021-11-09 13:28:54 +01:00
|
|
|
GError **error;
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
gboolean success;
|
|
|
|
|
} FwNftCallSyncData;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_fw_nft_call_sync_done(GObject *source, GAsyncResult *result, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
FwNftCallSyncData *data = user_data;
|
|
|
|
|
|
2022-09-15 08:56:19 +02:00
|
|
|
data->success = nm_firewall_nft_call_finish(result, data->error);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
g_main_loop_quit(data->loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_fw_nft_call_sync(GBytes *stdin_buf, GError **error)
|
|
|
|
|
{
|
|
|
|
|
nm_auto_pop_and_unref_gmaincontext GMainContext *main_context =
|
|
|
|
|
nm_g_main_context_push_thread_default(g_main_context_new());
|
|
|
|
|
nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new(main_context, FALSE);
|
|
|
|
|
FwNftCallSyncData data = (FwNftCallSyncData){
|
2021-11-09 13:28:54 +01:00
|
|
|
.loop = main_loop,
|
|
|
|
|
.error = error,
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
};
|
|
|
|
|
|
2022-09-15 08:56:19 +02:00
|
|
|
nm_firewall_nft_call(stdin_buf, NULL, _fw_nft_call_sync_done, &data);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
|
|
|
|
|
g_main_loop_run(main_loop);
|
|
|
|
|
return data.success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2022-09-14 12:56:29 +02:00
|
|
|
#define _append(p_strbuf, fmt, ...) nm_str_buf_append_printf((p_strbuf), "" fmt "\n", ##__VA_ARGS__)
|
|
|
|
|
|
2022-09-27 18:15:31 +02:00
|
|
|
static void
|
|
|
|
|
_fw_nft_append_cmd_table(NMStrBuf *strbuf, const char *family, const char *table_name, gboolean up)
|
|
|
|
|
{
|
|
|
|
|
/* Either delete the table, or create/flush it. */
|
|
|
|
|
_append(strbuf, "add table %s %s", family, table_name);
|
|
|
|
|
_append(strbuf, "%s table %s %s", up ? "flush" : "delete", family, table_name);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-13 19:39:14 +02:00
|
|
|
static GBytes *
|
|
|
|
|
_fw_nft_set_shared_construct(gboolean up, const char *ip_iface, in_addr_t addr, guint8 plen)
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
|
|
|
|
|
gs_free char *table_name = NULL;
|
|
|
|
|
char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN];
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
|
|
|
|
|
table_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface);
|
|
|
|
|
|
|
|
|
|
_share_iptables_subnet_to_str(str_subnet, addr, plen);
|
|
|
|
|
|
2022-09-27 18:15:31 +02:00
|
|
|
_fw_nft_append_cmd_table(&strbuf, "ip", table_name, up);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
|
2022-09-13 19:22:58 +02:00
|
|
|
if (up) {
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
_append(&strbuf,
|
2021-07-15 08:45:27 +02:00
|
|
|
"add chain ip %s nat_postrouting {"
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
" type nat hook postrouting priority 100; policy accept; "
|
|
|
|
|
"};",
|
|
|
|
|
table_name);
|
|
|
|
|
_append(&strbuf,
|
2021-07-15 08:45:27 +02:00
|
|
|
"add rule ip %s nat_postrouting ip saddr %s ip daddr != %s masquerade;",
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
table_name,
|
|
|
|
|
str_subnet,
|
|
|
|
|
str_subnet);
|
|
|
|
|
|
|
|
|
|
/* This filter_input chain serves no real purpose, because "accept" only stops
|
|
|
|
|
* evaluation of the current rule. It cannot fully accept the packet. Since
|
|
|
|
|
* this chain has no other rules, it is useless in this form.
|
2022-09-14 12:56:29 +02:00
|
|
|
*
|
|
|
|
|
* _append(&strbuf,
|
|
|
|
|
* "add chain ip %s filter_input {"
|
|
|
|
|
* " type filter hook input priority 0; policy accept; "
|
|
|
|
|
* "};",
|
|
|
|
|
* table_name);
|
|
|
|
|
* _append(&strbuf, "add rule ip %s filter_input tcp dport { 67, 53 } accept;", table_name);
|
|
|
|
|
* _append(&strbuf, "add rule ip %s filter_input udp dport { 67, 53 } accept;", table_name);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
_append(&strbuf,
|
2021-07-15 08:45:27 +02:00
|
|
|
"add chain ip %s filter_forward {"
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
" type filter hook forward priority 0; policy accept; "
|
|
|
|
|
"};",
|
|
|
|
|
table_name);
|
|
|
|
|
_append(&strbuf,
|
2021-07-15 08:45:27 +02:00
|
|
|
"add rule ip %s filter_forward ip daddr %s oifname \"%s\" "
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
" ct state { established, related } accept;",
|
|
|
|
|
table_name,
|
|
|
|
|
str_subnet,
|
|
|
|
|
ip_iface);
|
|
|
|
|
_append(&strbuf,
|
2021-07-15 08:45:27 +02:00
|
|
|
"add rule ip %s filter_forward ip saddr %s iifname \"%s\" accept;",
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
table_name,
|
|
|
|
|
str_subnet,
|
|
|
|
|
ip_iface);
|
|
|
|
|
_append(&strbuf,
|
2021-07-15 08:45:27 +02:00
|
|
|
"add rule ip %s filter_forward iifname \"%s\" oifname \"%s\" accept;",
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
table_name,
|
|
|
|
|
ip_iface,
|
|
|
|
|
ip_iface);
|
|
|
|
|
_append(&strbuf,
|
2021-07-15 08:45:27 +02:00
|
|
|
"add rule ip %s filter_forward iifname \"%s\" reject;",
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
table_name,
|
|
|
|
|
ip_iface);
|
|
|
|
|
_append(&strbuf,
|
2021-07-15 08:45:27 +02:00
|
|
|
"add rule ip %s filter_forward oifname \"%s\" reject;",
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
table_name,
|
|
|
|
|
ip_iface);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-13 19:39:14 +02:00
|
|
|
return nm_str_buf_finalize_to_gbytes(&strbuf);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2022-09-13 20:17:20 +02:00
|
|
|
GBytes *
|
|
|
|
|
nm_firewall_nft_stdio_mlag(gboolean up,
|
|
|
|
|
const char *bond_ifname,
|
|
|
|
|
const char *const *bond_ifnames_down,
|
|
|
|
|
const char *const *active_members,
|
2023-05-10 07:44:52 +02:00
|
|
|
const char *const *previous_members,
|
|
|
|
|
gboolean with_counters)
|
2022-09-13 20:17:20 +02:00
|
|
|
{
|
|
|
|
|
nm_auto_str_buf NMStrBuf strbuf_table_name =
|
|
|
|
|
NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE);
|
|
|
|
|
nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
|
|
|
|
|
const char *table_name;
|
|
|
|
|
gsize i;
|
2023-05-10 07:44:52 +02:00
|
|
|
const char *const s_counter = with_counters ? " counter" : "";
|
2022-09-13 20:17:20 +02:00
|
|
|
|
|
|
|
|
if (NM_MORE_ASSERTS > 10 && active_members) {
|
|
|
|
|
/* No duplicates. We make certain assumptions here, and we don't
|
|
|
|
|
* want to check that there are no duplicates. The caller must take
|
|
|
|
|
* care of this. */
|
|
|
|
|
for (i = 0; active_members[i]; i++)
|
|
|
|
|
nm_assert(!nm_strv_contains(&active_members[i + 1], -1, active_members[i]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If an interface gets renamed, we need to update the nft tables. Since one nft
|
|
|
|
|
* invocation is atomic, it is reasonable to drop the previous tables(s) at the
|
|
|
|
|
* same time when creating the new one. */
|
|
|
|
|
for (; bond_ifnames_down && bond_ifnames_down[0]; bond_ifnames_down++) {
|
|
|
|
|
if (nm_streq(bond_ifname, bond_ifnames_down[0]))
|
|
|
|
|
continue;
|
|
|
|
|
table_name = _strbuf_set_sanitized(&strbuf_table_name, "nm-mlag-", bond_ifnames_down[0]);
|
|
|
|
|
_fw_nft_append_cmd_table(&strbuf, "netdev", table_name, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
table_name = _strbuf_set_sanitized(&strbuf_table_name, "nm-mlag-", bond_ifname);
|
|
|
|
|
|
|
|
|
|
_fw_nft_append_cmd_table(&strbuf, "netdev", table_name, up);
|
|
|
|
|
|
|
|
|
|
if (up) {
|
|
|
|
|
nm_auto_str_buf NMStrBuf strbuf_1 =
|
|
|
|
|
NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_232, FALSE);
|
|
|
|
|
const gsize n_active_members = NM_PTRARRAY_LEN(active_members);
|
|
|
|
|
|
|
|
|
|
if (!_nft_ifname_valid(bond_ifname)) {
|
|
|
|
|
/* We cannot meaningfully express this interface name. Ignore all chains
|
|
|
|
|
* and only create an empty table. */
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (; previous_members && previous_members[0]; previous_members++) {
|
|
|
|
|
const char *previous_member = previous_members[0];
|
|
|
|
|
const char *chain_name;
|
|
|
|
|
|
|
|
|
|
/* The caller already ensures that the previous member is not part of the new
|
|
|
|
|
* active members. Avoid the overhead of checking, and assert against that. */
|
|
|
|
|
nm_assert(!nm_strv_contains(active_members, n_active_members, previous_member));
|
|
|
|
|
|
|
|
|
|
if (!_nft_ifname_valid(previous_member))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
chain_name = _strbuf_set_sanitized(&strbuf_1, "rx-drop-bc-mc-", previous_member);
|
|
|
|
|
|
|
|
|
|
/* We want atomically update our table, however, we don't want to delete
|
|
|
|
|
* and recreate it, because then the sets get lost (which we don't want).
|
|
|
|
|
*
|
|
|
|
|
* Instead, we only "add && flush" the table, which removes all rules from
|
|
|
|
|
* the chain. However, as our active-members change, we want to delete
|
|
|
|
|
* the obsolete chains too.
|
|
|
|
|
*
|
|
|
|
|
* nft has no way to delete all chains in a table, we have to name
|
|
|
|
|
* them one by one. So we keep track of active members that we had
|
|
|
|
|
* in the past, and which are now no longer in use. For those previous
|
|
|
|
|
* members we delete the chains (again, with the "add && delete" dance
|
|
|
|
|
* to avoid failure deleting a non-existing chain (in case our tracking
|
|
|
|
|
* is wrong or somebody else modified the table in the meantime).
|
|
|
|
|
*
|
|
|
|
|
* We need to track the previous members, because we don't want to first
|
|
|
|
|
* ask nft which chains exist. Doing that would be cumbersome as we would
|
|
|
|
|
* have to do one async program invocation and parse stdout. */
|
|
|
|
|
_append(&strbuf,
|
|
|
|
|
"add chain netdev %s %s {"
|
|
|
|
|
" type filter hook ingress device %s priority filter; "
|
|
|
|
|
"}",
|
|
|
|
|
table_name,
|
|
|
|
|
chain_name,
|
|
|
|
|
previous_member);
|
|
|
|
|
_append(&strbuf, "delete chain netdev %s %s", table_name, chain_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* OVS SLB rule 1
|
|
|
|
|
*
|
|
|
|
|
* "Open vSwitch avoids packet duplication by accepting multicast and broadcast
|
|
|
|
|
* packets on only the active member, and dropping multicast and broadcast
|
|
|
|
|
* packets on all other members."
|
|
|
|
|
*
|
|
|
|
|
* primary is first member, we drop on all others */
|
|
|
|
|
for (i = 0; i < n_active_members; i++) {
|
|
|
|
|
const char *active_member = active_members[i];
|
|
|
|
|
const char *chain_name;
|
|
|
|
|
|
|
|
|
|
if (!_nft_ifname_valid(active_member))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
chain_name = _strbuf_set_sanitized(&strbuf_1, "rx-drop-bc-mc-", active_member);
|
|
|
|
|
|
|
|
|
|
_append(&strbuf,
|
|
|
|
|
"add chain netdev %s %s {"
|
|
|
|
|
" type filter hook ingress device %s priority filter; "
|
|
|
|
|
"}",
|
|
|
|
|
table_name,
|
|
|
|
|
chain_name,
|
|
|
|
|
active_member);
|
|
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
_append(&strbuf, "delete chain netdev %s %s", table_name, chain_name);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_append(&strbuf,
|
|
|
|
|
"add rule netdev %s %s pkttype {"
|
|
|
|
|
" broadcast, multicast "
|
2023-05-10 07:44:52 +02:00
|
|
|
"}%s drop",
|
2022-09-13 20:17:20 +02:00
|
|
|
table_name,
|
2023-05-10 07:44:52 +02:00
|
|
|
chain_name,
|
|
|
|
|
s_counter);
|
2022-09-13 20:17:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* OVS SLB rule 2
|
|
|
|
|
*
|
|
|
|
|
* "Open vSwitch deals with this case by dropping packets received on any SLB
|
|
|
|
|
* bonded link that have a source MAC+VLAN that has been learned on any other
|
|
|
|
|
* port."
|
|
|
|
|
*/
|
|
|
|
|
_append(&strbuf,
|
|
|
|
|
"add set netdev %s macset-tagged {"
|
2023-05-02 08:54:21 +02:00
|
|
|
" typeof ether saddr . vlan id; flags dynamic,timeout; "
|
2022-09-13 20:17:20 +02:00
|
|
|
"}",
|
|
|
|
|
table_name);
|
|
|
|
|
_append(&strbuf,
|
|
|
|
|
"add set netdev %s macset-untagged {"
|
2023-05-02 08:54:21 +02:00
|
|
|
" typeof ether saddr; flags dynamic,timeout; "
|
2022-09-13 20:17:20 +02:00
|
|
|
"}",
|
|
|
|
|
table_name);
|
|
|
|
|
|
|
|
|
|
_append(&strbuf,
|
|
|
|
|
"add chain netdev %s tx-snoop-source-mac {"
|
|
|
|
|
" type filter hook egress device %s priority filter; "
|
|
|
|
|
"}",
|
|
|
|
|
table_name,
|
|
|
|
|
bond_ifname);
|
|
|
|
|
_append(&strbuf,
|
2023-05-10 07:44:52 +02:00
|
|
|
"add rule netdev %s tx-snoop-source-mac set update ether saddr . vlan id "
|
|
|
|
|
"timeout 5s @macset-tagged%s return"
|
2022-09-13 20:17:20 +02:00
|
|
|
"", /* tagged */
|
2023-05-10 07:44:52 +02:00
|
|
|
table_name,
|
|
|
|
|
s_counter);
|
2022-09-13 20:17:20 +02:00
|
|
|
_append(&strbuf,
|
2023-05-10 07:44:52 +02:00
|
|
|
"add rule netdev %s tx-snoop-source-mac set update ether saddr timeout 5s "
|
|
|
|
|
"@macset-untagged%s"
|
2022-09-13 20:17:20 +02:00
|
|
|
"", /* untagged*/
|
2023-05-10 07:44:52 +02:00
|
|
|
table_name,
|
|
|
|
|
s_counter);
|
2022-09-13 20:17:20 +02:00
|
|
|
|
|
|
|
|
_append(&strbuf,
|
|
|
|
|
"add chain netdev %s rx-drop-looped-packets {"
|
|
|
|
|
" type filter hook ingress device %s priority filter; "
|
|
|
|
|
"}",
|
|
|
|
|
table_name,
|
|
|
|
|
bond_ifname);
|
2023-05-10 07:44:52 +02:00
|
|
|
_append(
|
|
|
|
|
&strbuf,
|
|
|
|
|
"add rule netdev %s rx-drop-looped-packets ether saddr . vlan id @macset-tagged%s drop",
|
|
|
|
|
table_name,
|
|
|
|
|
s_counter);
|
2022-09-13 20:17:20 +02:00
|
|
|
_append(&strbuf,
|
2023-05-10 07:44:52 +02:00
|
|
|
"add rule netdev %s rx-drop-looped-packets ether type vlan%s return"
|
2022-09-13 20:17:20 +02:00
|
|
|
"", /* avoid looking up tagged packets in untagged table */
|
2023-05-10 07:44:52 +02:00
|
|
|
table_name,
|
|
|
|
|
s_counter);
|
2022-09-13 20:17:20 +02:00
|
|
|
_append(&strbuf,
|
2023-05-10 07:44:52 +02:00
|
|
|
"add rule netdev %s rx-drop-looped-packets ether saddr @macset-untagged%s drop",
|
|
|
|
|
table_name,
|
|
|
|
|
s_counter);
|
2022-09-13 20:17:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
return nm_str_buf_finalize_to_gbytes(&strbuf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-05-05 22:28:31 +02:00
|
|
|
struct _NMFirewallConfig {
|
2021-11-09 13:28:54 +01:00
|
|
|
char *ip_iface;
|
2021-05-05 22:07:55 +02:00
|
|
|
in_addr_t addr;
|
|
|
|
|
guint8 plen;
|
|
|
|
|
};
|
|
|
|
|
|
2021-05-05 22:28:31 +02:00
|
|
|
NMFirewallConfig *
|
2022-09-13 19:24:50 +02:00
|
|
|
nm_firewall_config_new_shared(const char *ip_iface, in_addr_t addr, guint8 plen)
|
2021-05-05 22:07:55 +02:00
|
|
|
{
|
2021-05-05 22:28:31 +02:00
|
|
|
NMFirewallConfig *self;
|
2021-05-05 22:07:55 +02:00
|
|
|
|
|
|
|
|
nm_assert(ip_iface);
|
|
|
|
|
nm_assert(addr != 0u);
|
|
|
|
|
nm_assert(plen <= 32);
|
|
|
|
|
|
2021-05-05 22:28:31 +02:00
|
|
|
self = g_slice_new(NMFirewallConfig);
|
|
|
|
|
*self = (NMFirewallConfig){
|
2021-05-05 22:07:55 +02:00
|
|
|
.ip_iface = g_strdup(ip_iface),
|
|
|
|
|
.addr = addr,
|
|
|
|
|
.plen = plen,
|
|
|
|
|
};
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2021-05-05 22:28:31 +02:00
|
|
|
nm_firewall_config_free(NMFirewallConfig *self)
|
2021-05-05 22:07:55 +02:00
|
|
|
{
|
|
|
|
|
if (!self)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
g_free(self->ip_iface);
|
|
|
|
|
nm_g_slice_free(self);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-13 20:18:35 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-05-05 22:07:55 +02:00
|
|
|
void
|
2022-09-13 20:18:35 +02:00
|
|
|
nm_firewall_config_apply_sync(NMFirewallConfig *self, gboolean up)
|
2021-05-05 22:07:55 +02:00
|
|
|
{
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
switch (nm_firewall_utils_get_backend()) {
|
|
|
|
|
case NM_FIREWALL_BACKEND_IPTABLES:
|
2022-09-13 19:39:14 +02:00
|
|
|
_share_iptables_set_masquerade_sync(up, self->ip_iface, self->addr, self->plen);
|
|
|
|
|
_share_iptables_set_shared_sync(up, self->ip_iface, self->addr, self->plen);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
break;
|
|
|
|
|
case NM_FIREWALL_BACKEND_NFTABLES:
|
2022-09-13 19:39:14 +02:00
|
|
|
{
|
|
|
|
|
gs_unref_bytes GBytes *stdin_buf = NULL;
|
|
|
|
|
|
|
|
|
|
stdin_buf = _fw_nft_set_shared_construct(up, self->ip_iface, self->addr, self->plen);
|
|
|
|
|
_fw_nft_call_sync(stdin_buf, NULL);
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
break;
|
2022-09-13 19:39:14 +02:00
|
|
|
}
|
2021-05-12 12:02:33 +02:00
|
|
|
case NM_FIREWALL_BACKEND_NONE:
|
|
|
|
|
break;
|
firewall: implement masquerading for shared mode with nftables
Add support for nftables, as a second backend beside iptables (firewalld
still missing).
Like iptables, choose to call the `nft` tool. The alternative would be
to use libnftables or talk netlink.
It's ugly to blocking wait for a process to complete. We already do that
for iptables, but we better should not because we should not treat other
processes as trusted and not allow untrusted code to block NetworkManager.
Fixing that would require a central manager that serializes all requests.
Especially with firewalld support, this will be interesting again,
because we don't want to synchronously talk D-Bus either.
For now, `nft` is still called synchronously. However, the internal
implementation uses an asynchronous function. That currently
serves no purpose except supporting a timeout. Otherwise, the only
reason why this is asynchronous is that I implemented this first, and
I think in the future we want this code to be non-blocking. So, instead
of dropping the asynchronous code, I wrap it in a synchronous function
for now.
The configured nft table is:
table inet nm-shared-eth0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.42.0/24 ip daddr != 192.168.42.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.42.0/24 oifname "eth0" ct state { established, related } accept
ip saddr 192.168.42.0/24 iifname "eth0" accept
iifname "eth0" oifname "eth0" accept
iifname "eth0" reject
oifname "eth0" reject
}
}
2021-05-12 12:01:12 +02:00
|
|
|
default:
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-05-05 22:07:55 +02:00
|
|
|
}
|
2021-05-06 16:50:25 +02:00
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static NMFirewallBackend
|
|
|
|
|
_firewall_backend_detect(void)
|
|
|
|
|
{
|
2021-06-14 11:13:57 +02:00
|
|
|
if (g_file_test(NFT_PATH, G_FILE_TEST_IS_EXECUTABLE))
|
|
|
|
|
return NM_FIREWALL_BACKEND_NFTABLES;
|
|
|
|
|
if (g_file_test(IPTABLES_PATH, G_FILE_TEST_IS_EXECUTABLE))
|
|
|
|
|
return NM_FIREWALL_BACKEND_IPTABLES;
|
|
|
|
|
|
|
|
|
|
return NM_FIREWALL_BACKEND_NFTABLES;
|
2021-05-06 16:50:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMFirewallBackend
|
|
|
|
|
nm_firewall_utils_get_backend(void)
|
|
|
|
|
{
|
|
|
|
|
static int backend = NM_FIREWALL_BACKEND_UNKNOWN;
|
|
|
|
|
int b;
|
|
|
|
|
|
|
|
|
|
again:
|
|
|
|
|
b = g_atomic_int_get(&backend);
|
|
|
|
|
if (b == NM_FIREWALL_BACKEND_UNKNOWN) {
|
|
|
|
|
gs_free char *conf_value = NULL;
|
|
|
|
|
gboolean detect;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
conf_value =
|
|
|
|
|
nm_config_data_get_value(NM_CONFIG_GET_DATA_ORIG,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_MAIN_FIREWALL_BACKEND,
|
|
|
|
|
NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
|
|
|
|
|
|
|
|
|
|
if (conf_value) {
|
|
|
|
|
for (i = 0; i < (int) G_N_ELEMENTS(FirewallBackends); i++) {
|
|
|
|
|
if (!g_ascii_strcasecmp(conf_value, FirewallBackends[i].name)) {
|
|
|
|
|
b = (i + 1);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
detect = (b == NM_FIREWALL_BACKEND_UNKNOWN);
|
|
|
|
|
if (detect)
|
|
|
|
|
b = _firewall_backend_detect();
|
|
|
|
|
|
2021-05-12 12:02:33 +02:00
|
|
|
nm_assert(NM_IN_SET(b,
|
|
|
|
|
NM_FIREWALL_BACKEND_NONE,
|
|
|
|
|
NM_FIREWALL_BACKEND_IPTABLES,
|
|
|
|
|
NM_FIREWALL_BACKEND_NFTABLES));
|
2021-05-06 16:50:25 +02:00
|
|
|
|
|
|
|
|
if (!g_atomic_int_compare_and_exchange(&backend, NM_FIREWALL_BACKEND_UNKNOWN, b))
|
|
|
|
|
goto again;
|
|
|
|
|
|
|
|
|
|
nm_log_dbg(LOGD_SHARING,
|
2021-05-12 12:02:33 +02:00
|
|
|
"firewall: use %s backend%s%s%s%s%s%s%s",
|
2021-05-06 16:50:25 +02:00
|
|
|
FirewallBackends[b - 1].name,
|
2021-05-12 12:02:33 +02:00
|
|
|
NM_PRINT_FMT_QUOTED(FirewallBackends[b - 1].path,
|
|
|
|
|
" (",
|
|
|
|
|
FirewallBackends[b - 1].path,
|
|
|
|
|
")",
|
|
|
|
|
""),
|
2021-05-06 16:50:25 +02:00
|
|
|
detect ? " (detected)" : "",
|
|
|
|
|
NM_PRINT_FMT_QUOTED(detect && conf_value,
|
|
|
|
|
" (invalid setting \"",
|
|
|
|
|
conf_value,
|
|
|
|
|
"\")",
|
|
|
|
|
""));
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-12 12:02:33 +02:00
|
|
|
nm_assert(NM_IN_SET(b,
|
|
|
|
|
NM_FIREWALL_BACKEND_NONE,
|
|
|
|
|
NM_FIREWALL_BACKEND_IPTABLES,
|
|
|
|
|
NM_FIREWALL_BACKEND_NFTABLES));
|
2021-05-06 16:50:25 +02:00
|
|
|
return b;
|
|
|
|
|
}
|