diff options
| author | Michael Biebl <biebl@debian.org> | 2025-07-15 08:31:19 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2025-07-15 08:31:19 +0200 |
| commit | 582eb4472a0f3375042afb9026cbeb50e058a27d (patch) | |
| tree | 65f78da0c024c43e669c6a9c23402e59b28a01ef /src/core/nm-firewall-utils.c | |
| parent | 625e8ce60e826bde943487b8238884a9232e4562 (diff) | |
New upstream version 1.52.1 upstream/1.52.1
Diffstat (limited to 'src/core/nm-firewall-utils.c')
| -rw-r--r-- | src/core/nm-firewall-utils.c | 424 |
1 files changed, 299 insertions, 125 deletions
diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c index b4960612..60f40228 100644 --- a/src/core/nm-firewall-utils.c +++ b/src/core/nm-firewall-utils.c @@ -8,6 +8,7 @@ #include "nm-firewall-utils.h" +#include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "libnm-glib-aux/nm-str-buf.h" #include "libnm-glib-aux/nm-io-utils.h" #include "libnm-platform/nm-platform.h" @@ -127,7 +128,7 @@ _share_iptables_subnet_to_str(char buf[static _SHARE_IPTABLES_SUBNET_TO_STR } static char * -_share_iptables_get_name(gboolean is_iptables_chain, const char *prefix, const char *ip_iface) +_iptables_get_name(gboolean is_iptables_chain, const char *prefix, const char *ip_iface) { NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE); gsize ip_iface_len; @@ -179,13 +180,13 @@ _share_iptables_get_name(gboolean is_iptables_chain, const char *prefix, const c /*****************************************************************************/ static gboolean -_share_iptables_call_v(const char *const *argv) +_iptables_call_v(const char *const *argv) { gs_free_error GError *error = NULL; gs_free char *argv_str = NULL; int status; - nm_log_dbg(LOGD_SHARING, "iptables: %s", (argv_str = g_strjoinv(" ", (char **) argv))); + nm_log_dbg(LOGD_FIREWALL, "iptables: %s", (argv_str = g_strjoinv(" ", (char **) argv))); if (!g_spawn_sync("/", (char **) argv, @@ -197,7 +198,7 @@ _share_iptables_call_v(const char *const *argv) NULL, &status, &error)) { - nm_log_warn(LOGD_SHARING, + nm_log_warn(LOGD_FIREWALL, "iptables: error executing command %s: %s", argv[0], error->message); @@ -205,20 +206,24 @@ _share_iptables_call_v(const char *const *argv) } if (!g_spawn_check_exit_status(status, &error)) { - nm_log_warn(LOGD_SHARING, "iptables: command %s failed: %s", argv[0], error->message); + nm_log_warn(LOGD_FIREWALL, "iptables: command %s failed: %s", argv[0], error->message); return FALSE; } return TRUE; } -#define _share_iptables_call(...) \ - _share_iptables_call_v(NM_MAKE_STRV("" IPTABLES_PATH "", "--wait", "2", __VA_ARGS__)) +#define _ipxtables_call(family, ...) \ + _iptables_call_v( \ + NM_MAKE_STRV((family == AF_INET ? "" IPTABLES_PATH "" : "" IP6TABLES_PATH ""), \ + "--wait", \ + "2", \ + __VA_ARGS__)) static gboolean _share_iptables_chain_op(const char *table, const char *chain, const char *op) { - return _share_iptables_call("--table", table, op, chain); + return _ipxtables_call(AF_INET, "--table", table, op, chain); } static gboolean @@ -244,24 +249,25 @@ _share_iptables_set_masquerade_sync(gboolean up, const char *ip_iface, in_addr_t char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; gs_free char *comment_name = NULL; - comment_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface); + comment_name = _iptables_get_name(FALSE, "nm-shared", ip_iface); _share_iptables_subnet_to_str(str_subnet, addr, plen); - _share_iptables_call("--table", - "nat", - up ? "--insert" : "--delete", - "POSTROUTING", - "--source", - str_subnet, - "!", - "--destination", - str_subnet, - "--jump", - "MASQUERADE", - "-m", - "comment", - "--comment", - comment_name); + _ipxtables_call(AF_INET, + "--table", + "nat", + up ? "--insert" : "--delete", + "POSTROUTING", + "--source", + str_subnet, + "!", + "--destination", + str_subnet, + "--jump", + "MASQUERADE", + "-m", + "comment", + "--comment", + comment_name); } static void @@ -297,70 +303,76 @@ _share_iptables_set_shared_chains_add(const char *chain_input, _share_iptables_chain_add("filter", chain_input); for (i = 0; i < (int) G_N_ELEMENTS(input_params); i++) { - _share_iptables_call("--table", - "filter", - "--append", - chain_input, - "--protocol", - input_params[i][0], - "--destination-port", - input_params[i][1], - "--jump", - "ACCEPT"); + _ipxtables_call(AF_INET, + "--table", + "filter", + "--append", + chain_input, + "--protocol", + input_params[i][0], + "--destination-port", + input_params[i][1], + "--jump", + "ACCEPT"); } _share_iptables_chain_add("filter", chain_forward); - _share_iptables_call("--table", - "filter", - "--append", - chain_forward, - "--destination", - str_subnet, - "--out-interface", - ip_iface, - "--match", - "state", - "--state", - "ESTABLISHED,RELATED", - "--jump", - "ACCEPT"); - _share_iptables_call("--table", - "filter", - "--append", - chain_forward, - "--source", - str_subnet, - "--in-interface", - ip_iface, - "--jump", - "ACCEPT"); - _share_iptables_call("--table", - "filter", - "--append", - chain_forward, - "--in-interface", - ip_iface, - "--out-interface", - ip_iface, - "--jump", - "ACCEPT"); - _share_iptables_call("--table", - "filter", - "--append", - chain_forward, - "--out-interface", - ip_iface, - "--jump", - "REJECT"); - _share_iptables_call("--table", - "filter", - "--append", - chain_forward, - "--in-interface", - ip_iface, - "--jump", - "REJECT"); + _ipxtables_call(AF_INET, + "--table", + "filter", + "--append", + chain_forward, + "--destination", + str_subnet, + "--out-interface", + ip_iface, + "--match", + "state", + "--state", + "ESTABLISHED,RELATED", + "--jump", + "ACCEPT"); + _ipxtables_call(AF_INET, + "--table", + "filter", + "--append", + chain_forward, + "--source", + str_subnet, + "--in-interface", + ip_iface, + "--jump", + "ACCEPT"); + _ipxtables_call(AF_INET, + "--table", + "filter", + "--append", + chain_forward, + "--in-interface", + ip_iface, + "--out-interface", + ip_iface, + "--jump", + "ACCEPT"); + _ipxtables_call(AF_INET, + "--table", + "filter", + "--append", + chain_forward, + "--out-interface", + ip_iface, + "--jump", + "REJECT"); + _ipxtables_call(AF_INET, + "--table", + "filter", + "--append", + chain_forward, + "--in-interface", + ip_iface, + "--jump", + "REJECT"); } static void @@ -377,36 +389,38 @@ _share_iptables_set_shared_sync(gboolean up, const char *ip_iface, in_addr_t add gs_free char *chain_input = NULL; gs_free char *chain_forward = NULL; - 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); + comment_name = _iptables_get_name(FALSE, "nm-shared", ip_iface); + chain_input = _iptables_get_name(TRUE, "nm-sh-in", ip_iface); + chain_forward = _iptables_get_name(TRUE, "nm-sh-fw", ip_iface); if (up) _share_iptables_set_shared_chains_add(chain_input, chain_forward, ip_iface, addr, plen); - _share_iptables_call("--table", - "filter", - up ? "--insert" : "--delete", - "INPUT", - "--in-interface", - ip_iface, - "--jump", - chain_input, - "-m", - "comment", - "--comment", - comment_name); - - _share_iptables_call("--table", - "filter", - up ? "--insert" : "--delete", - "FORWARD", - "--jump", - chain_forward, - "-m", - "comment", - "--comment", - comment_name); + _ipxtables_call(AF_INET, + "--table", + "filter", + up ? "--insert" : "--delete", + "INPUT", + "--in-interface", + ip_iface, + "--jump", + chain_input, + "-m", + "comment", + "--comment", + comment_name); + + _ipxtables_call(AF_INET, + "--table", + "filter", + up ? "--insert" : "--delete", + "FORWARD", + "--jump", + chain_forward, + "-m", + "comment", + "--comment", + comment_name); if (!up) _share_iptables_set_shared_chains_delete(chain_input, chain_forward); @@ -460,19 +474,19 @@ _fw_nft_call_communicate_cb(GObject *source, GAsyncResult *result, gpointer user /* on any error, the process might still be running. We need to abort it in * the background... */ if (!nm_utils_error_is_cancelled(error)) { - nm_log_dbg(LOGD_SHARING, + nm_log_dbg(LOGD_FIREWALL, "firewall: nft[%s]: communication failed: %s. Kill process", call_data->identifier, error->message); } else if (!call_data->timeout_source) { - nm_log_dbg(LOGD_SHARING, - "firewall: ntf[%s]: communication timed out. Kill process", + nm_log_dbg(LOGD_FIREWALL, + "firewall: nft[%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", + nm_log_dbg(LOGD_FIREWALL, + "firewall: nft[%s]: communication cancelled. Kill process", call_data->identifier); } @@ -485,7 +499,7 @@ _fw_nft_call_communicate_cb(GObject *source, GAsyncResult *result, gpointer user 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); + nm_log_dbg(LOGD_FIREWALL, "firewall: nft[%s]: command successful", call_data->identifier); } else { char buf[NM_UTILS_GET_PROCESS_EXIT_STATUS_BUF_LEN]; gs_free char *ss_stdout = NULL; @@ -498,7 +512,7 @@ _fw_nft_call_communicate_cb(GObject *source, GAsyncResult *result, gpointer user nm_utils_get_process_exit_status_desc_buf(status, buf, sizeof(buf)); - nm_log_warn(LOGD_SHARING, + nm_log_warn(LOGD_FIREWALL, "firewall: nft[%s]: command %s:%s%s%s%s%s%s%s", call_data->identifier, buf, @@ -534,7 +548,7 @@ _fw_nft_call_cancelled_cb(GCancellable *cancellable, gpointer user_data) if (call_data->cancellable_id == 0) return; - nm_log_dbg(LOGD_SHARING, "firewall: nft[%s]: operation cancelled", call_data->identifier); + nm_log_dbg(LOGD_FIREWALL, "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); @@ -546,7 +560,7 @@ _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, + nm_log_dbg(LOGD_FIREWALL, "firewall: nft[%s]: cancel operation after timeout", call_data->identifier); @@ -573,7 +587,7 @@ nm_firewall_nft_call(GBytes *stdin_buf, .timeout_source = NULL, }; - nm_log_trace(LOGD_SHARING, + nm_log_trace(LOGD_FIREWALL, "firewall: nft: call command: [ '%s' ]", nm_utils_buf_utf8safe_escape_bytes(stdin_buf, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, @@ -585,7 +599,7 @@ nm_firewall_nft_call(GBytes *stdin_buf, call_data, NULL); if (call_data->cancellable_id == 0) { - nm_log_dbg(LOGD_SHARING, "firewall: nft: already cancelled"); + nm_log_dbg(LOGD_FIREWALL, "firewall: nft: already cancelled"); nm_utils_error_set_cancelled(&error, FALSE, NULL); _fw_nft_call_data_free(call_data, g_steal_pointer(&error)); return; @@ -602,14 +616,14 @@ nm_firewall_nft_call(GBytes *stdin_buf, &error); if (!call_data->subprocess) { - nm_log_dbg(LOGD_SHARING, "firewall: nft: spawning nft failed: %s", error->message); + nm_log_dbg(LOGD_FIREWALL, "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_log_dbg(LOGD_FIREWALL, "firewall: nft[%s]: communicate with nft", call_data->identifier); nm_shutdown_wait_obj_register_object(call_data->task, "nft-call"); @@ -691,7 +705,7 @@ _fw_nft_set_shared_construct(gboolean up, const char *ip_iface, in_addr_t addr, gs_free char *table_name = NULL; char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; - table_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface); + table_name = _iptables_get_name(FALSE, "nm-shared", ip_iface); _share_iptables_subnet_to_str(str_subnet, addr, plen); @@ -756,6 +770,141 @@ _fw_nft_set_shared_construct(gboolean up, const char *ip_iface, in_addr_t addr, return nm_str_buf_finalize_to_gbytes(&strbuf); } +static GBytes * +_fw_nft_wg_default_construct(const char *ip_iface, + NMSettingIPConfig *ip_config, + int fwmark, + gboolean up) +{ + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); + gs_free char *table_name = NULL; + const char *family_str; + + table_name = _iptables_get_name(FALSE, "nm-wg", ip_iface); + family_str = nm_setting_ip_config_get_addr_family(ip_config) == AF_INET ? "ip" : "ip6"; + + _fw_nft_append_cmd_table(&strbuf, family_str, table_name, up); + + if (up) { + guint n_addresses = nm_setting_ip_config_get_num_addresses(ip_config); + + if (n_addresses) { + _append(&strbuf, "add chain %s %s preraw {", family_str, table_name); + + for (guint i = 0; i < n_addresses; i++) { + NMIPAddress *addr = nm_setting_ip_config_get_address(ip_config, i); + + _append(&strbuf, + " iifname != \"%s\" " + " %s daddr %s " + " fib saddr type != local " + "drop;", + ip_iface, + family_str, + nm_ip_address_get_address(addr)); + } + + _append(&strbuf, "};"); + } + + _append(&strbuf, + "add chain %s %s premangle {" + " type filter hook prerouting priority mangle; policy accept; " + " meta l4proto udp meta mark set ct mark; " + "};", + family_str, + table_name); + + _append(&strbuf, + "add chain %s %s postmangle {" + " type filter hook postrouting priority mangle; policy accept; " + " meta l4proto udp mark 0x%08x ct mark set meta mark; " + "};", + family_str, + table_name, + fwmark); + } + + return nm_str_buf_finalize_to_gbytes(&strbuf); +} + +static void +_fw_iptables_wg_configure(const char *ip_iface, + NMSettingIPConfig *ip_config, + int fwmark, + gboolean up) +{ + gs_free char *comment_name = NULL; + char fwmark_str[11]; + int family = nm_setting_ip_config_get_addr_family(ip_config); + guint n_addresses = nm_setting_ip_config_get_num_addresses(ip_config); + + comment_name = _iptables_get_name(FALSE, "nm-wg", ip_iface); + g_snprintf(fwmark_str, sizeof(fwmark_str), "%" G_GUINT32_FORMAT, fwmark); + + nm_assert(strlen(fwmark_str) > 0); + + for (guint i = 0; i < n_addresses; i++) { + NMIPAddress *addr = nm_setting_ip_config_get_address(ip_config, i); + + _ipxtables_call(family, + "--table", + "raw", + up ? "--insert" : "--delete", + "PREROUTING", + "!", + "--in-interface", + ip_iface, + "--destination", + nm_ip_address_get_address(addr), + "--match", + "addrtype", + "!", + "--src-type", + "LOCAL", + "-j", + "DROP", + "-m", + "comment", + "--comment", + comment_name); + } + + _ipxtables_call(family, + "--table", + "mangle", + up ? "--insert" : "--delete", + "POSTROUTING", + "--match", + "mark", + "--mark", + fwmark_str, + "--protocol", + "udp", + "--jump", + "CONNMARK", + "--save-mark", + "-m", + "comment", + "--comment", + comment_name); + + _ipxtables_call(family, + "--table", + "mangle", + up ? "--insert" : "--delete", + "PREROUTING", + "--protocol", + "udp", + "--jump", + "CONNMARK", + "--restore-mark", + "-m", + "comment", + "--comment", + comment_name); +} + /*****************************************************************************/ GBytes * @@ -1046,6 +1195,31 @@ nm_firewall_config_free(NMFirewallConfig *self) } /*****************************************************************************/ +void +nm_firewall_config_set_wg_rule(const char *ifname, + NMSettingIPConfig *ip_config, + int fwmark, + gboolean up) +{ + switch (nm_firewall_utils_get_backend()) { + case NM_FIREWALL_BACKEND_NFTABLES: + { + gs_unref_bytes GBytes *stdin_buf = NULL; + + stdin_buf = _fw_nft_wg_default_construct(ifname, ip_config, fwmark, up); + _fw_nft_call_sync(stdin_buf, NULL); + break; + } + case NM_FIREWALL_BACKEND_IPTABLES: + _fw_iptables_wg_configure(ifname, ip_config, fwmark, up); + break; + case NM_FIREWALL_BACKEND_NONE: + break; + default: + nm_assert_not_reached(); + break; + } +} void nm_firewall_config_apply_sync(NMFirewallConfig *self, gboolean up) @@ -1124,7 +1298,7 @@ again: if (!g_atomic_int_compare_and_exchange(&backend, NM_FIREWALL_BACKEND_UNKNOWN, b)) goto again; - nm_log_dbg(LOGD_SHARING, + nm_log_dbg(LOGD_FIREWALL, "firewall: use %s backend%s%s%s%s%s%s%s", FirewallBackends[b - 1].name, NM_PRINT_FMT_QUOTED(FirewallBackends[b - 1].path, |