summary refs log tree commit diff
path: root/src/core/nm-firewall-utils.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2022-10-18 11:56:48 +0200
committerMichael Biebl <biebl@debian.org>2022-10-18 11:56:48 +0200
commit9f101839d9e64df832e9e43c5181887369c46a7e (patch)
tree3e23589a9d4e9e7c32ce41b634ccf26af3f0d45e /src/core/nm-firewall-utils.c
parentab0efddcdb48d800e2f938da54cfe3074640792e (diff)
New upstream version 1.40.2 upstream/1.40.2
Diffstat (limited to 'src/core/nm-firewall-utils.c')
-rw-r--r--src/core/nm-firewall-utils.c125
1 files changed, 74 insertions, 51 deletions
diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c
index 1311f503..e482ab96 100644
--- a/src/core/nm-firewall-utils.c
+++ b/src/core/nm-firewall-utils.c
@@ -111,6 +111,8 @@ _share_iptables_get_name(gboolean is_iptables_chain, const char *prefix, const c
     return nm_str_buf_finalize(&strbuf, NULL);
 }
 
+/*****************************************************************************/
+
 static gboolean
 _share_iptables_call_v(const char *const *argv)
 {
@@ -171,7 +173,7 @@ _share_iptables_chain_add(const char *table, const char *chain)
 }
 
 static void
-_share_iptables_set_masquerade(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen)
+_share_iptables_set_masquerade_sync(gboolean up, const char *ip_iface, in_addr_t addr, guint8 plen)
 {
     char          str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN];
     gs_free char *comment_name = NULL;
@@ -182,7 +184,7 @@ _share_iptables_set_masquerade(gboolean add, const char *ip_iface, in_addr_t add
     _share_iptables_call("" IPTABLES_PATH "",
                          "--table",
                          "nat",
-                         add ? "--insert" : "--delete",
+                         up ? "--insert" : "--delete",
                          "POSTROUTING",
                          "--source",
                          str_subnet,
@@ -309,8 +311,8 @@ _share_iptables_set_shared_chains_delete(const char *chain_input, const char *ch
     _share_iptables_chain_delete("filter", chain_forward);
 }
 
-_nm_unused static void
-_share_iptables_set_shared(gboolean add, const char *ip_iface, in_addr_t addr, guint plen)
+static void
+_share_iptables_set_shared_sync(gboolean up, const char *ip_iface, in_addr_t addr, guint plen)
 {
     gs_free char *comment_name  = NULL;
     gs_free char *chain_input   = NULL;
@@ -320,13 +322,13 @@ _share_iptables_set_shared(gboolean add, const char *ip_iface, in_addr_t addr, g
     chain_input   = _share_iptables_get_name(TRUE, "nm-sh-in", ip_iface);
     chain_forward = _share_iptables_get_name(TRUE, "nm-sh-fw", ip_iface);
 
-    if (add)
+    if (up)
         _share_iptables_set_shared_chains_add(chain_input, chain_forward, ip_iface, addr, plen);
 
     _share_iptables_call("" IPTABLES_PATH "",
                          "--table",
                          "filter",
-                         add ? "--insert" : "--delete",
+                         up ? "--insert" : "--delete",
                          "INPUT",
                          "--in-interface",
                          ip_iface,
@@ -340,7 +342,7 @@ _share_iptables_set_shared(gboolean add, const char *ip_iface, in_addr_t addr, g
     _share_iptables_call("" IPTABLES_PATH "",
                          "--table",
                          "filter",
-                         add ? "--insert" : "--delete",
+                         up ? "--insert" : "--delete",
                          "FORWARD",
                          "--jump",
                          chain_forward,
@@ -349,7 +351,7 @@ _share_iptables_set_shared(gboolean add, const char *ip_iface, in_addr_t addr, g
                          "--comment",
                          comment_name);
 
-    if (!add)
+    if (!up)
         _share_iptables_set_shared_chains_delete(chain_input, chain_forward);
 }
 
@@ -428,14 +430,21 @@ _fw_nft_call_communicate_cb(GObject *source, GAsyncResult *result, gpointer user
     } else if (g_subprocess_get_successful(call_data->subprocess)) {
         nm_log_dbg(LOGD_SHARING, "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;
         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);
+        int           status;
+
+        status = g_subprocess_get_status(call_data->subprocess);
+
+        nm_utils_get_process_exit_status_desc_buf(status, buf, sizeof(buf));
 
         nm_log_warn(LOGD_SHARING,
-                    "firewall: nft[%s]: command failed:%s%s%s%s%s%s%s",
+                    "firewall: nft[%s]: command %s:%s%s%s%s%s%s%s",
                     call_data->identifier,
+                    buf,
                     print_stdout || print_stderr ? "" : " unknown reason",
                     NM_PRINT_FMT_QUOTED(
                         print_stdout,
@@ -453,6 +462,8 @@ _fw_nft_call_communicate_cb(GObject *source, GAsyncResult *result, gpointer user
                                                            &ss_stderr),
                         "\")",
                         ""));
+
+        nm_utils_error_set(&error, NM_UTILS_ERROR_COMMAND_FAILED, "nft command %s", buf);
     }
 
     _fw_nft_call_data_free(call_data, g_steal_pointer(&error));
@@ -486,23 +497,31 @@ _fw_nft_call_timeout_cb(gpointer user_data)
     return G_SOURCE_CONTINUE;
 }
 
-static void
-_fw_nft_call(GBytes             *stdin_buf,
-             GCancellable       *cancellable,
-             GAsyncReadyCallback callback,
-             gpointer            callback_user_data)
+void
+nm_firewall_nft_call(GBytes             *stdin_buf,
+                     GCancellable       *cancellable,
+                     GAsyncReadyCallback callback,
+                     gpointer            callback_user_data)
 {
     gs_unref_object GSubprocessLauncher *subprocess_launcher = NULL;
     gs_free_error GError                *error               = NULL;
     FwNftCallData                       *call_data;
+    gs_free char                        *ss1 = NULL;
 
     call_data  = g_slice_new(FwNftCallData);
     *call_data = (FwNftCallData){
-        .task       = nm_g_task_new(NULL, cancellable, _fw_nft_call, callback, callback_user_data),
-        .subprocess = NULL,
+        .task =
+            nm_g_task_new(NULL, cancellable, nm_firewall_nft_call, callback, callback_user_data),
+        .subprocess     = NULL,
         .timeout_source = NULL,
     };
 
+    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));
+
     if (cancellable) {
         call_data->cancellable_id = g_cancellable_connect(cancellable,
                                                           G_CALLBACK(_fw_nft_call_cancelled_cb),
@@ -554,10 +573,10 @@ _fw_nft_call(GBytes             *stdin_buf,
                            g_task_get_context(call_data->task));
 }
 
-static gboolean
-_fw_nft_call_finish(GAsyncResult *result, GError **error)
+gboolean
+nm_firewall_nft_call_finish(GAsyncResult *result, GError **error)
 {
-    g_return_val_if_fail(nm_g_task_is_valid(result, NULL, _fw_nft_call), FALSE);
+    g_return_val_if_fail(nm_g_task_is_valid(result, NULL, nm_firewall_nft_call), FALSE);
 
     return g_task_propagate_boolean(G_TASK(result), error);
 }
@@ -575,7 +594,7 @@ _fw_nft_call_sync_done(GObject *source, GAsyncResult *result, gpointer user_data
 {
     FwNftCallSyncData *data = user_data;
 
-    data->success = _fw_nft_call_finish(result, data->error);
+    data->success = nm_firewall_nft_call_finish(result, data->error);
     g_main_loop_quit(data->loop);
 }
 
@@ -590,7 +609,7 @@ _fw_nft_call_sync(GBytes *stdin_buf, GError **error)
                               .error = error,
     };
 
-    _fw_nft_call(stdin_buf, NULL, _fw_nft_call_sync_done, &data);
+    nm_firewall_nft_call(stdin_buf, NULL, _fw_nft_call_sync_done, &data);
 
     g_main_loop_run(main_loop);
     return data.success;
@@ -598,25 +617,30 @@ _fw_nft_call_sync(GBytes *stdin_buf, GError **error)
 
 /*****************************************************************************/
 
+#define _append(p_strbuf, fmt, ...) nm_str_buf_append_printf((p_strbuf), "" fmt "\n", ##__VA_ARGS__)
+
 static void
-_fw_nft_set(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen)
+_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);
+}
+
+static GBytes *
+_fw_nft_set_shared_construct(gboolean up, const char *ip_iface, in_addr_t addr, guint8 plen)
 {
     nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
-    gs_unref_bytes GBytes   *stdin_buf  = NULL;
     gs_free char            *table_name = NULL;
-    gs_free char            *ss1        = NULL;
     char                     str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN];
 
     table_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface);
 
     _share_iptables_subnet_to_str(str_subnet, addr, plen);
 
-#define _append(p_strbuf, fmt, ...) nm_str_buf_append_printf((p_strbuf), "" fmt "\n", ##__VA_ARGS__)
-
-    _append(&strbuf, "add table ip %s", table_name);
-    _append(&strbuf, "%s table ip %s", add ? "flush" : "delete", table_name);
+    _fw_nft_append_cmd_table(&strbuf, "ip", table_name, up);
 
-    if (add) {
+    if (up) {
         _append(&strbuf,
                 "add chain ip %s nat_postrouting {"
                 " type nat hook postrouting priority 100; policy accept; "
@@ -631,16 +655,15 @@ _fw_nft_set(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen)
         /* 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.
+         *
+         * _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);
          */
-        /*
-        _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);
-        */
 
         _append(&strbuf,
                 "add chain ip %s filter_forward {"
@@ -673,14 +696,7 @@ _fw_nft_set(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen)
                 ip_iface);
     }
 
-    nm_log_trace(LOGD_SHARING,
-                 "firewall: nft command: [ %s ]",
-                 nm_utils_str_utf8safe_escape(nm_str_buf_get_str(&strbuf),
-                                              NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL,
-                                              &ss1));
-
-    stdin_buf = nm_str_buf_finalize_to_gbytes(&strbuf);
-    _fw_nft_call_sync(stdin_buf, NULL);
+    return nm_str_buf_finalize_to_gbytes(&strbuf);
 }
 
 /*****************************************************************************/
@@ -692,7 +708,7 @@ struct _NMFirewallConfig {
 };
 
 NMFirewallConfig *
-nm_firewall_config_new(const char *ip_iface, in_addr_t addr, guint8 plen)
+nm_firewall_config_new_shared(const char *ip_iface, in_addr_t addr, guint8 plen)
 {
     NMFirewallConfig *self;
 
@@ -719,17 +735,24 @@ nm_firewall_config_free(NMFirewallConfig *self)
     nm_g_slice_free(self);
 }
 
+/*****************************************************************************/
+
 void
-nm_firewall_config_apply(NMFirewallConfig *self, gboolean shared)
+nm_firewall_config_apply_sync(NMFirewallConfig *self, gboolean up)
 {
     switch (nm_firewall_utils_get_backend()) {
     case NM_FIREWALL_BACKEND_IPTABLES:
-        _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_masquerade_sync(up, self->ip_iface, self->addr, self->plen);
+        _share_iptables_set_shared_sync(up, self->ip_iface, self->addr, self->plen);
         break;
     case NM_FIREWALL_BACKEND_NFTABLES:
-        _fw_nft_set(shared, self->ip_iface, self->addr, self->plen);
+    {
+        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);
         break;
+    }
     case NM_FIREWALL_BACKEND_NONE:
         break;
     default: