diff options
author | Thomas Haller <thaller@redhat.com> | 2021-05-06 16:50:25 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2021-05-14 11:41:32 +0200 |
commit | 1da1ad9c9995f6454ef39da3d8ba85b0a23e919f (patch) | |
tree | 3eceaad006fa171cc7aeaded190daf74cfd3e741 | |
parent | 2a1d42e77d5b35f654198078813e35e0bd189701 (diff) | |
download | NetworkManager-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.meson | 5 | ||||
-rw-r--r-- | configure.ac | 23 | ||||
-rw-r--r-- | man/NetworkManager.conf.xml | 11 | ||||
-rw-r--r-- | meson.build | 5 | ||||
-rw-r--r-- | meson_options.txt | 1 | ||||
-rw-r--r-- | src/core/nm-firewall-utils.c | 97 | ||||
-rw-r--r-- | src/core/nm-firewall-utils.h | 10 | ||||
-rw-r--r-- | src/core/tests/test-core.c | 21 | ||||
-rw-r--r-- | src/libnm-base/nm-config-base.h | 3 |
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" |