summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-05-06 16:50:25 +0200
committerThomas Haller <thaller@redhat.com>2021-05-14 11:41:32 +0200
commit1da1ad9c9995f6454ef39da3d8ba85b0a23e919f (patch)
tree3eceaad006fa171cc7aeaded190daf74cfd3e741
parent2a1d42e77d5b35f654198078813e35e0bd189701 (diff)
downloadNetworkManager-1da1ad9c9995f6454ef39da3d8ba85b0a23e919f.tar.gz
firewall: make firewall-backend configurable via "NetworkManager.conf"
"iptables" and "nftables" will be supported. Currently, the code is unused and only "iptables" is supported.
-rw-r--r--config.h.meson5
-rw-r--r--configure.ac23
-rw-r--r--man/NetworkManager.conf.xml11
-rw-r--r--meson.build5
-rw-r--r--meson_options.txt1
-rw-r--r--src/core/nm-firewall-utils.c97
-rw-r--r--src/core/nm-firewall-utils.h10
-rw-r--r--src/core/tests/test-core.c21
-rw-r--r--src/libnm-base/nm-config-base.h3
9 files changed, 168 insertions, 8 deletions
diff --git a/config.h.meson b/config.h.meson
index a911dbe257..432402d5b4 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -67,7 +67,10 @@
/* Define to path of iptables binary */
#mesondefine IPTABLES_PATH
-/* Define to path to the Jansson shared library */
+/* Define to path of nft binary */
+#mesondefine NFT_PATH
+
+//* Define to path to the Jansson shared library */
#mesondefine JANSSON_SONAME
/* Define to path of the kernel firmware directory */
diff --git a/configure.ac b/configure.ac
index e27ceeb7a1..d23d315cf8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -943,13 +943,12 @@ fi
AC_DEFINE_UNQUOTED(NM_CONFIG_DEFAULT_MAIN_RC_MANAGER, "$config_dns_rc_manager_default", [Default value for main.rc-manager setting (--with-config-dns-rc-manager-default)])
AC_SUBST(NM_CONFIG_DEFAULT_MAIN_RC_MANAGER, $config_dns_rc_manager_default)
-# iptables path
AC_ARG_WITH(iptables,
- AS_HELP_STRING([--with-iptables=/path/to/iptables], [path to iptables]))
+ AS_HELP_STRING([--with-iptables=/usr/sbin/iptables], [path to iptables]))
if test "x${with_iptables}" = x; then
AC_PATH_PROG(IPTABLES_PATH, iptables, [], $PATH:/sbin:/usr/sbin)
- if ! test -x "$IPTABLES_PATH"; then
- AC_MSG_ERROR(iptables was not installed.)
+ if test "x$IPTABLES_PATH" = x; then
+ IPTABLES_PATH='/usr/sbin/iptables'
fi
else
IPTABLES_PATH="$with_iptables"
@@ -957,7 +956,19 @@ fi
AC_DEFINE_UNQUOTED(IPTABLES_PATH, "$IPTABLES_PATH", [Define to path of iptables binary])
AC_SUBST(IPTABLES_PATH)
-# dnsmasq path
+AC_ARG_WITH(nft,
+ AS_HELP_STRING([--with-nft=/usr/sbin/nft], [path to nft]))
+if test "x${with_nft}" = x; then
+ AC_PATH_PROG(NFT_PATH, nft, [], $PATH:/sbin:/usr/sbin)
+ if test "x$NFT_PATH" = x; then
+ NFT_PATH='/usr/sbin/nft'
+ fi
+else
+ NFT_PATH="$with_nft"
+fi
+AC_DEFINE_UNQUOTED(NFT_PATH, "$NFT_PATH", [Define to path of nft binary])
+AC_SUBST(NFT_PATH)
+
AC_ARG_WITH(dnsmasq,
AS_HELP_STRING([--with-dnsmasq=/path/to/dnsmasq], [path to dnsmasq]))
if test "x${with_dnsmasq}" = x; then
@@ -1372,6 +1383,8 @@ echo " nmtui: $build_nmtui"
echo " nm-cloud-setup: $with_nm_cloud_setup"
echo " iwd: $ac_with_iwd"
echo " jansson: $have_jansson${JANSSON_SONAME:+ (soname: $JANSSON_SONAME)}"
+echo " iptables: $IPTABLES_PATH"
+echo " nft: $NFT_PATH"
echo
echo "Configuration plugins (main.plugins=${config_plugins_default})"
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index 4320a9facd..f88688e94b 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -476,6 +476,17 @@ no-auto-default=*
</varlistentry>
<varlistentry>
+ <term><varname>firewall-backend</varname></term>
+ <listitem>
+ <para>
+ The firewall backend for configuring masquerading.
+ Set to either <literal>iptables</literal> or <literal>nftables</literal>.
+ If unspecified, it will be auto detected.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>iwd-config-path</varname></term>
<listitem>
<para>
diff --git a/meson.build b/meson.build
index 33e840c173..de50c652a7 100644
--- a/meson.build
+++ b/meson.build
@@ -691,7 +691,8 @@ dnssec_ts_paths = ['/usr/local/libexec',
'/usr/lib/dnssec-trigger']
# 0: cmdline option, 1: paths, 2: fallback
-progs = [['iptables', default_paths, '/sbin/iptables'],
+progs = [['iptables', default_paths, '/usr/sbin/iptables'],
+ ['nft', default_paths, '/usr/sbin/nft'],
['dnsmasq', default_paths, ''],
['dnssec_trigger', dnssec_ts_paths, join_paths(nm_libexecdir, 'dnssec-trigger-script') ],
]
@@ -1044,6 +1045,8 @@ if enable_ppp
endif
output += '\n'
output += ' jansson: ' + jansson_msg + '\n'
+output += ' iptables: ' + config_h.get('IPTABLES_PATH') + '\n'
+output += ' nft: ' + config_h.get('NFT_PATH') + '\n'
output += ' modemmanager-1: ' + enable_modem_manager.to_string() + '\n'
output += ' ofono: ' + enable_ofono.to_string() + '\n'
output += ' concheck: ' + enable_concheck.to_string() + '\n'
diff --git a/meson_options.txt b/meson_options.txt
index 5100ed71f5..14ed4077a0 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -5,6 +5,7 @@ option('udev_dir', type: 'string', value: '', description: 'Absolute path of the
option('dbus_conf_dir', type: 'string', value: '', description: 'where D-Bus system.d directory is')
option('kernel_firmware_dir', type: 'string', value: '/lib/firmware', description: 'where kernel firmware directory is (default is /lib/firmware)')
option('iptables', type: 'string', value: '', description: 'path to iptables')
+option('nft', type: 'string', value: '', description: 'path to nft')
option('dnsmasq', type: 'string', value: '', description: 'path to dnsmasq')
option('dnssec_trigger', type: 'string', value: '', description: 'path to unbound dnssec-trigger-script')
diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c
index 69aa3fdfb0..fdefbf5ea1 100644
--- a/src/core/nm-firewall-utils.c
+++ b/src/core/nm-firewall-utils.c
@@ -11,6 +11,26 @@
#include "libnm-glib-aux/nm-str-buf.h"
#include "libnm-platform/nm-platform.h"
+#include "nm-config.h"
+
+/*****************************************************************************/
+
+static const struct {
+ const char *name;
+ const char *path;
+} FirewallBackends[] = {
+ [NM_FIREWALL_BACKEND_NFTABLES - 1] =
+ {
+ .name = "nftables",
+ .path = NFT_PATH,
+ },
+ [NM_FIREWALL_BACKEND_IPTABLES - 1] =
+ {
+ .name = "iptables",
+ .path = IPTABLES_PATH,
+ },
+};
+
/*****************************************************************************/
#define _SHARE_IPTABLES_SUBNET_TO_STR_LEN (INET_ADDRSTRLEN + 1 + 2 + 1)
@@ -327,6 +347,8 @@ _share_iptables_set_shared(gboolean add, const char *ip_iface, in_addr_t addr, g
_share_iptables_set_shared_chains_delete(chain_input, chain_forward);
}
+/*****************************************************************************/
+
struct _NMFirewallConfig {
char * ip_iface;
in_addr_t addr;
@@ -367,3 +389,78 @@ nm_firewall_config_apply(NMFirewallConfig *self, gboolean shared)
_share_iptables_set_masquerade(shared, self->ip_iface, self->addr, self->plen);
_share_iptables_set_shared(shared, self->ip_iface, self->addr, self->plen);
}
+
+/*****************************************************************************/
+
+static NMFirewallBackend
+_firewall_backend_detect(void)
+{
+ 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;
+}
+
+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();
+
+ nm_assert(NM_IN_SET(b, NM_FIREWALL_BACKEND_IPTABLES, NM_FIREWALL_BACKEND_NFTABLES));
+
+ if (b == NM_FIREWALL_BACKEND_NFTABLES) {
+ if (!detect)
+ nm_log_warn(LOGD_SHARING,
+ "firewall: backend \"nftables\" is not yet implemented. Fallback to "
+ "\"iptables\"");
+ nm_clear_g_free(&conf_value);
+ b = NM_FIREWALL_BACKEND_IPTABLES;
+ }
+
+ if (!g_atomic_int_compare_and_exchange(&backend, NM_FIREWALL_BACKEND_UNKNOWN, b))
+ goto again;
+
+ nm_log_dbg(LOGD_SHARING,
+ "firewall: use %s backend (%s)%s%s%s%s",
+ FirewallBackends[b - 1].name,
+ FirewallBackends[b - 1].path,
+ detect ? " (detected)" : "",
+ NM_PRINT_FMT_QUOTED(detect && conf_value,
+ " (invalid setting \"",
+ conf_value,
+ "\")",
+ ""));
+ }
+
+ nm_assert(NM_IN_SET(b, NM_FIREWALL_BACKEND_IPTABLES, NM_FIREWALL_BACKEND_NFTABLES));
+ return b;
+}
diff --git a/src/core/nm-firewall-utils.h b/src/core/nm-firewall-utils.h
index 5ba1721c2e..f261aef384 100644
--- a/src/core/nm-firewall-utils.h
+++ b/src/core/nm-firewall-utils.h
@@ -7,6 +7,16 @@
#ifndef __NM_FIREWALL_UTILS_H__
#define __NM_FIREWALL_UTILS_H__
+typedef enum {
+ NM_FIREWALL_BACKEND_UNKNOWN,
+ NM_FIREWALL_BACKEND_IPTABLES,
+ NM_FIREWALL_BACKEND_NFTABLES,
+} NMFirewallBackend;
+
+NMFirewallBackend nm_firewall_utils_get_backend(void);
+
+/*****************************************************************************/
+
typedef struct _NMFirewallConfig NMFirewallConfig;
NMFirewallConfig *nm_firewall_config_new(const char *ip_iface, in_addr_t addr, guint8 plen);
diff --git a/src/core/tests/test-core.c b/src/core/tests/test-core.c
index d7f733066a..15be7af1ed 100644
--- a/src/core/tests/test-core.c
+++ b/src/core/tests/test-core.c
@@ -22,6 +22,25 @@
#include "nm-test-utils-core.h"
+/*****************************************************************************/
+
+static void
+test_config_h(void)
+{
+#define ABSOLUTE_PATH(path) \
+ G_STMT_START \
+ { \
+ g_assert_cmpstr("" path "", !=, ""); \
+ g_assert("" path ""[0] == '/'); \
+ } \
+ G_STMT_END
+
+ ABSOLUTE_PATH(IPTABLES_PATH);
+ ABSOLUTE_PATH(NFT_PATH);
+}
+
+/*****************************************************************************/
+
/* Reference implementation for nm_utils_ip6_address_clear_host_address.
* Taken originally from set_address_masked(), src/ndisc/nm-lndp-ndisc.c
**/
@@ -2570,6 +2589,8 @@ main(int argc, char **argv)
{
nmtst_init_with_logging(&argc, &argv, NULL, "ALL");
+ g_test_add_func("/general/test_config_h", test_config_h);
+
g_test_add_func("/general/test_logging_domains", test_logging_domains);
g_test_add_func("/general/test_logging_error", test_logging_error);
diff --git a/src/libnm-base/nm-config-base.h b/src/libnm-base/nm-config-base.h
index 6a2bab1548..7a23875a43 100644
--- a/src/libnm-base/nm-config-base.h
+++ b/src/libnm-base/nm-config-base.h
@@ -26,15 +26,16 @@
#define NM_CONFIG_KEYFILE_KEY_MAIN_DEBUG "debug"
#define NM_CONFIG_KEYFILE_KEY_MAIN_DHCP "dhcp"
#define NM_CONFIG_KEYFILE_KEY_MAIN_DNS "dns"
+#define NM_CONFIG_KEYFILE_KEY_MAIN_FIREWALL_BACKEND "firewall-backend"
#define NM_CONFIG_KEYFILE_KEY_MAIN_HOSTNAME_MODE "hostname-mode"
#define NM_CONFIG_KEYFILE_KEY_MAIN_IGNORE_CARRIER "ignore-carrier"
+#define NM_CONFIG_KEYFILE_KEY_MAIN_IWD_CONFIG_PATH "iwd-config-path"
#define NM_CONFIG_KEYFILE_KEY_MAIN_MONITOR_CONNECTION_FILES "monitor-connection-files"
#define NM_CONFIG_KEYFILE_KEY_MAIN_NO_AUTO_DEFAULT "no-auto-default"
#define NM_CONFIG_KEYFILE_KEY_MAIN_PLUGINS "plugins"
#define NM_CONFIG_KEYFILE_KEY_MAIN_RC_MANAGER "rc-manager"
#define NM_CONFIG_KEYFILE_KEY_MAIN_SLAVES_ORDER "slaves-order"
#define NM_CONFIG_KEYFILE_KEY_MAIN_SYSTEMD_RESOLVED "systemd-resolved"
-#define NM_CONFIG_KEYFILE_KEY_MAIN_IWD_CONFIG_PATH "iwd-config-path"
#define NM_CONFIG_KEYFILE_KEY_LOGGING_AUDIT "audit"
#define NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND "backend"