firewall: make firewall-backend configurable via "NetworkManager.conf"

"iptables" and "nftables" will be supported. Currently, the code is
unused and only "iptables" is supported.
This commit is contained in:
Thomas Haller
2021-05-06 16:50:25 +02:00
parent 2a1d42e77d
commit 1da1ad9c99
9 changed files with 168 additions and 8 deletions

View File

@@ -67,7 +67,10 @@
/* Define to path of iptables binary */ /* Define to path of iptables binary */
#mesondefine IPTABLES_PATH #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 #mesondefine JANSSON_SONAME
/* Define to path of the kernel firmware directory */ /* Define to path of the kernel firmware directory */

View File

@@ -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_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) AC_SUBST(NM_CONFIG_DEFAULT_MAIN_RC_MANAGER, $config_dns_rc_manager_default)
# iptables path
AC_ARG_WITH(iptables, 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 if test "x${with_iptables}" = x; then
AC_PATH_PROG(IPTABLES_PATH, iptables, [], $PATH:/sbin:/usr/sbin) AC_PATH_PROG(IPTABLES_PATH, iptables, [], $PATH:/sbin:/usr/sbin)
if ! test -x "$IPTABLES_PATH"; then if test "x$IPTABLES_PATH" = x; then
AC_MSG_ERROR(iptables was not installed.) IPTABLES_PATH='/usr/sbin/iptables'
fi fi
else else
IPTABLES_PATH="$with_iptables" IPTABLES_PATH="$with_iptables"
@@ -957,7 +956,19 @@ fi
AC_DEFINE_UNQUOTED(IPTABLES_PATH, "$IPTABLES_PATH", [Define to path of iptables binary]) AC_DEFINE_UNQUOTED(IPTABLES_PATH, "$IPTABLES_PATH", [Define to path of iptables binary])
AC_SUBST(IPTABLES_PATH) 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, AC_ARG_WITH(dnsmasq,
AS_HELP_STRING([--with-dnsmasq=/path/to/dnsmasq], [path to dnsmasq])) AS_HELP_STRING([--with-dnsmasq=/path/to/dnsmasq], [path to dnsmasq]))
if test "x${with_dnsmasq}" = x; then if test "x${with_dnsmasq}" = x; then
@@ -1372,6 +1383,8 @@ echo " nmtui: $build_nmtui"
echo " nm-cloud-setup: $with_nm_cloud_setup" echo " nm-cloud-setup: $with_nm_cloud_setup"
echo " iwd: $ac_with_iwd" echo " iwd: $ac_with_iwd"
echo " jansson: $have_jansson${JANSSON_SONAME:+ (soname: $JANSSON_SONAME)}" echo " jansson: $have_jansson${JANSSON_SONAME:+ (soname: $JANSSON_SONAME)}"
echo " iptables: $IPTABLES_PATH"
echo " nft: $NFT_PATH"
echo echo
echo "Configuration plugins (main.plugins=${config_plugins_default})" echo "Configuration plugins (main.plugins=${config_plugins_default})"

View File

@@ -475,6 +475,17 @@ no-auto-default=*
</listitem> </listitem>
</varlistentry> </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> <varlistentry>
<term><varname>iwd-config-path</varname></term> <term><varname>iwd-config-path</varname></term>
<listitem> <listitem>

View File

@@ -691,7 +691,8 @@ dnssec_ts_paths = ['/usr/local/libexec',
'/usr/lib/dnssec-trigger'] '/usr/lib/dnssec-trigger']
# 0: cmdline option, 1: paths, 2: fallback # 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, ''], ['dnsmasq', default_paths, ''],
['dnssec_trigger', dnssec_ts_paths, join_paths(nm_libexecdir, 'dnssec-trigger-script') ], ['dnssec_trigger', dnssec_ts_paths, join_paths(nm_libexecdir, 'dnssec-trigger-script') ],
] ]
@@ -1044,6 +1045,8 @@ if enable_ppp
endif endif
output += '\n' output += '\n'
output += ' jansson: ' + jansson_msg + '\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 += ' modemmanager-1: ' + enable_modem_manager.to_string() + '\n'
output += ' ofono: ' + enable_ofono.to_string() + '\n' output += ' ofono: ' + enable_ofono.to_string() + '\n'
output += ' concheck: ' + enable_concheck.to_string() + '\n' output += ' concheck: ' + enable_concheck.to_string() + '\n'

View File

@@ -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('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('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('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('dnsmasq', type: 'string', value: '', description: 'path to dnsmasq')
option('dnssec_trigger', type: 'string', value: '', description: 'path to unbound dnssec-trigger-script') option('dnssec_trigger', type: 'string', value: '', description: 'path to unbound dnssec-trigger-script')

View File

@@ -11,6 +11,26 @@
#include "libnm-glib-aux/nm-str-buf.h" #include "libnm-glib-aux/nm-str-buf.h"
#include "libnm-platform/nm-platform.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) #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); _share_iptables_set_shared_chains_delete(chain_input, chain_forward);
} }
/*****************************************************************************/
struct _NMFirewallConfig { struct _NMFirewallConfig {
char * ip_iface; char * ip_iface;
in_addr_t addr; 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_masquerade(shared, self->ip_iface, self->addr, self->plen);
_share_iptables_set_shared(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;
}

View File

@@ -7,6 +7,16 @@
#ifndef __NM_FIREWALL_UTILS_H__ #ifndef __NM_FIREWALL_UTILS_H__
#define __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; typedef struct _NMFirewallConfig NMFirewallConfig;
NMFirewallConfig *nm_firewall_config_new(const char *ip_iface, in_addr_t addr, guint8 plen); NMFirewallConfig *nm_firewall_config_new(const char *ip_iface, in_addr_t addr, guint8 plen);

View File

@@ -22,6 +22,25 @@
#include "nm-test-utils-core.h" #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. /* Reference implementation for nm_utils_ip6_address_clear_host_address.
* Taken originally from set_address_masked(), src/ndisc/nm-lndp-ndisc.c * 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"); 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_domains", test_logging_domains);
g_test_add_func("/general/test_logging_error", test_logging_error); g_test_add_func("/general/test_logging_error", test_logging_error);

View File

@@ -26,15 +26,16 @@
#define NM_CONFIG_KEYFILE_KEY_MAIN_DEBUG "debug" #define NM_CONFIG_KEYFILE_KEY_MAIN_DEBUG "debug"
#define NM_CONFIG_KEYFILE_KEY_MAIN_DHCP "dhcp" #define NM_CONFIG_KEYFILE_KEY_MAIN_DHCP "dhcp"
#define NM_CONFIG_KEYFILE_KEY_MAIN_DNS "dns" #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_HOSTNAME_MODE "hostname-mode"
#define NM_CONFIG_KEYFILE_KEY_MAIN_IGNORE_CARRIER "ignore-carrier" #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_MONITOR_CONNECTION_FILES "monitor-connection-files"
#define NM_CONFIG_KEYFILE_KEY_MAIN_NO_AUTO_DEFAULT "no-auto-default" #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_PLUGINS "plugins"
#define NM_CONFIG_KEYFILE_KEY_MAIN_RC_MANAGER "rc-manager" #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_SLAVES_ORDER "slaves-order"
#define NM_CONFIG_KEYFILE_KEY_MAIN_SYSTEMD_RESOLVED "systemd-resolved" #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_AUDIT "audit"
#define NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND "backend" #define NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND "backend"