]> xenbits.xensource.com Git - libvirt.git/commitdiff
util: new functions to support adding individual firewall rollback commands
authorLaine Stump <laine@redhat.com>
Sat, 20 Apr 2024 02:19:42 +0000 (22:19 -0400)
committerLaine Stump <laine@redhat.com>
Thu, 23 May 2024 03:19:36 +0000 (23:19 -0400)
In the past virFirewall required all rollback commands for a group
(those commands necessary to "undo" any rules that had been added in
that group in case of a later failure) to be manually added by
switching into the virFirewall object into "rollback mode" and then
re-calling the inverse of the exact virFirewallAddCmd*() APIs that had
been called to add the original rules (ie. for each
"iptables --insert" command, for rollback we would need to add a
command with all arguments identical except that "--insert" would be
replaced by "--delete").

Because nftables can't search for rules to remove by comparing all the
arguments (it instead expects *only* a handle that is provided via
stdout when the rule was originally added), we won't be able to follow
the iptables method and manually construct the command to undo any
given nft command by just duplicating all the args of the command
(except the action). Instead we will need to be able to automatically
create a rollback command at the time the rule-adding command is
executed (e.g. an "nft delete rule" command that would include the
rule handle returned in stdout by an "nft add rule" command).

In order to make this happen, we need to be able to 1) learn whether
the user of the virFirewall API desires this behavior (handled by a new
transaction flag called VIR_FIREWALL_TRANSACTION_AUTO_ROLLBACK that
can be retrieved with the new virFirewallTransactionGetFlags() API),
and 2) add a new command to the current group's rollback command list (with
the new virFirewallAddRollbackCmd()).

We will actually use this capability in an upcoming patch.

Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
src/libvirt_private.syms
src/util/virfirewall.c
src/util/virfirewall.h

index 6cb3003499d420ea5437b4b2d059a3648d0eae7b..893859caba4768f14a6651dea16d87af21bbc8ac 100644 (file)
@@ -2405,6 +2405,7 @@ virFileCacheSetPriv;
 
 # util/virfirewall.h
 virFirewallAddCmdFull;
+virFirewallAddRollbackCmd;
 virFirewallApply;
 virFirewallBackendTypeFromString;
 virFirewallBackendTypeToString;
index 77de34533df36508dcea67ad54b2328c2d2a6d7c..9def8999d589d3910ed3b0ecfeee93ed5ca2e19b 100644 (file)
@@ -198,10 +198,12 @@ void virFirewallFree(virFirewall *firewall)
         fwCmd->args[fwCmd->argsLen++] = g_strdup(str); \
     } while (0)
 
+
 static virFirewallCmd *
 virFirewallAddCmdFullV(virFirewall *firewall,
                        virFirewallLayer layer,
                        bool ignoreErrors,
+                       bool isRollback,
                        virFirewallQueryCallback cb,
                        void *opaque,
                        va_list args)
@@ -218,18 +220,16 @@ virFirewallAddCmdFullV(virFirewall *firewall,
     }
     group = firewall->groups[firewall->currentGroup];
 
-
     fwCmd = g_new0(virFirewallCmd, 1);
-
     fwCmd->layer = layer;
-    fwCmd->queryCB = cb;
-    fwCmd->queryOpaque = opaque;
 
     while ((str = va_arg(args, char *)) != NULL)
         ADD_ARG(fwCmd, str);
 
-    if (group->addingRollback) {
+    if (isRollback || group->addingRollback) {
         fwCmd->ignoreErrors = true; /* always ignore errors when rolling back */
+        fwCmd->queryCB = NULL; /* rollback commands can't have a callback */
+        fwCmd->queryOpaque = NULL;
         VIR_APPEND_ELEMENT_COPY(group->rollback, group->nrollback, fwCmd);
     } else {
         /* when not rolling back, ignore errors if this group (transaction)
@@ -237,6 +237,8 @@ virFirewallAddCmdFullV(virFirewall *firewall,
          * if this specific rule was created with ignoreErrors == true
          */
         fwCmd->ignoreErrors = ignoreErrors || (group->actionFlags & VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
+        fwCmd->queryCB = cb;
+        fwCmd->queryOpaque = opaque;
         VIR_APPEND_ELEMENT_COPY(group->action, group->naction, fwCmd);
     }
 
@@ -277,7 +279,33 @@ virFirewallCmd *virFirewallAddCmdFull(virFirewall *firewall,
     virFirewallCmd *fwCmd;
     va_list args;
     va_start(args, opaque);
-    fwCmd = virFirewallAddCmdFullV(firewall, layer, ignoreErrors, cb, opaque, args);
+    fwCmd = virFirewallAddCmdFullV(firewall, layer, ignoreErrors, false, cb, opaque, args);
+    va_end(args);
+    return fwCmd;
+}
+
+
+/**
+ * virFirewallAddRollbackCmd:
+ * @firewall: firewall commands to add to
+ * @layer: the firewall layer to change
+ * @...: NULL terminated list of strings for the command
+ *
+ * Add a command to the current firewall command group "rollback".
+ * Rollback commands always ignore errors and don't support any
+ * callbacks.
+ *
+ * Returns the new Command
+ */
+virFirewallCmd *
+virFirewallAddRollbackCmd(virFirewall *firewall,
+                          virFirewallLayer layer,
+                          ...)
+{
+    virFirewallCmd *fwCmd;
+    va_list args;
+    va_start(args, layer);
+    fwCmd = virFirewallAddCmdFullV(firewall, layer, true, true, NULL, NULL, args);
     va_end(args);
     return fwCmd;
 }
@@ -434,6 +462,21 @@ void virFirewallStartTransaction(virFirewall *firewall,
     firewall->currentGroup = firewall->ngroups - 1;
 }
 
+
+/**
+ * virFirewallTransactionGetFlags:
+ * @firewall: the firewall to look at
+ *
+ * Returns the virFirewallTransactionFlags for the currently active
+ * group (transaction) in @firewall.
+ */
+static virFirewallTransactionFlags G_GNUC_UNUSED
+virFirewallTransactionGetFlags(virFirewall *firewall)
+{
+    return firewall->groups[firewall->currentGroup]->actionFlags;
+}
+
+
 /**
  * virFirewallBeginRollback:
  * @firewall: the firewall ruleset
index 1ca1cce10a12709539e0e95578f9aae8d5394143..e6aac365f1c91c2a6439110f67808f801c6d18bd 100644 (file)
@@ -73,6 +73,11 @@ virFirewallCmd *virFirewallAddCmdFull(virFirewall *firewall,
                                       ...)
     G_GNUC_NULL_TERMINATED;
 
+virFirewallCmd *virFirewallAddRollbackCmd(virFirewall *firewall,
+                                          virFirewallLayer layer,
+                                          ...)
+    G_GNUC_NULL_TERMINATED;
+
 void virFirewallRemoveCmd(virFirewall *firewall,
                           virFirewallCmd *rule);
 
@@ -105,6 +110,8 @@ typedef enum {
     /* Ignore all errors when applying rules, so no
      * rollback block will be required */
     VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS = (1 << 0),
+    /* Set to auto-add a rollback rule for each rule that is applied */
+    VIR_FIREWALL_TRANSACTION_AUTO_ROLLBACK = (1 << 1),
 } virFirewallTransactionFlags;
 
 void virFirewallStartTransaction(virFirewall *firewall,