[PATCH v4 15/30] util: implement rollback rule autocreation for iptables commands

Laine Stump posted 30 patches 1 year, 7 months ago
There is a newer version of this series
[PATCH v4 15/30] util: implement rollback rule autocreation for iptables commands
Posted by Laine Stump 1 year, 7 months ago
If the VIR_FIREWALL_TRANSACTION_AUTO_ROLLBACK flag is set, each time
an iptables command is executed that is adding a rule or chain, a
corresponding command that will *delete* the same rule/chain is
constructed and added to the list of rollback commands. If we later
want to undo the entire firewall, we can just run those commands.

This isn't yet used anywhere, since
VIR_FIREWALL_TRANSACTION_AUTO_ROLLBACK isn't being set.

Signed-off-by: Laine Stump <laine@redhat.com>
---
 src/util/virfirewall.c | 55 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 48 insertions(+), 7 deletions(-)

diff --git a/src/util/virfirewall.c b/src/util/virfirewall.c
index 9def8999d5..b9b4140ad6 100644
--- a/src/util/virfirewall.c
+++ b/src/util/virfirewall.c
@@ -470,7 +470,7 @@ void virFirewallStartTransaction(virFirewall *firewall,
  * Returns the virFirewallTransactionFlags for the currently active
  * group (transaction) in @firewall.
  */
-static virFirewallTransactionFlags G_GNUC_UNUSED
+static virFirewallTransactionFlags
 virFirewallTransactionGetFlags(virFirewall *firewall)
 {
     return firewall->groups[firewall->currentGroup]->actionFlags;
@@ -525,16 +525,25 @@ virFirewallCmdToString(const char *cmd,
 }
 
 
+#define VIR_IPTABLES_ARG_IS_CREATE(arg) \
+    (STREQ(arg, "--insert") || STREQ(arg, "-I") || \
+     STREQ(arg, "--append") || STREQ(arg, "-A"))
+
+
 static int
-virFirewallApplyCmdDirect(virFirewallCmd *fwCmd,
-                           char **output)
+virFirewallCmdIptablesApply(virFirewall *firewall,
+                            virFirewallCmd *fwCmd,
+                            char **output)
 {
-    size_t i;
     const char *bin = virFirewallLayerCommandTypeToString(fwCmd->layer);
+    bool checkRollback = (virFirewallTransactionGetFlags(firewall) &
+                          VIR_FIREWALL_TRANSACTION_AUTO_ROLLBACK);
+    bool needRollback = false;
     g_autoptr(virCommand) cmd = NULL;
     g_autofree char *cmdStr = NULL;
-    int status;
     g_autofree char *error = NULL;
+    size_t i;
+    int status;
 
     if (!bin) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -558,8 +567,13 @@ virFirewallApplyCmdDirect(virFirewallCmd *fwCmd,
         break;
     }
 
-    for (i = 0; i < fwCmd->argsLen; i++)
+    for (i = 0; i < fwCmd->argsLen; i++) {
+        /* the -I/-A arg could be at any position in the list */
+        if (checkRollback && VIR_IPTABLES_ARG_IS_CREATE(fwCmd->args[i]))
+            needRollback = true;
+
         virCommandAddArg(cmd, fwCmd->args[i]);
+    }
 
     cmdStr = virCommandToString(cmd, false);
     VIR_INFO("Running firewall command '%s'", NULLSTR(cmdStr));
@@ -571,8 +585,10 @@ virFirewallApplyCmdDirect(virFirewallCmd *fwCmd,
         return -1;
 
     if (status != 0) {
+        /* the command failed, decide whether or not to report it */
         if (fwCmd->ignoreErrors) {
             VIR_DEBUG("Ignoring error running command");
+            return 0;
         } else {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Failed to run firewall command %1$s: %2$s"),
@@ -582,6 +598,31 @@ virFirewallApplyCmdDirect(virFirewallCmd *fwCmd,
         }
     }
 
+    /* the command was successful, see if we need to add a
+     * rollback command
+     */
+
+    if (needRollback) {
+        virFirewallCmd *rollback
+            = virFirewallAddRollbackCmd(firewall, fwCmd->layer, NULL);
+        g_autofree char *rollbackStr = NULL;
+
+        for (i = 0; i < fwCmd->argsLen; i++) {
+            /* iptables --delete wants the entire commandline that
+             * was used for --insert but with s/insert/delete/
+             */
+            if (VIR_IPTABLES_ARG_IS_CREATE(fwCmd->args[i])) {
+                virFirewallCmdAddArg(firewall, rollback, "--delete");
+            } else {
+                virFirewallCmdAddArg(firewall, rollback, fwCmd->args[i]);
+            }
+        }
+
+        rollbackStr = virFirewallCmdToString(virFirewallLayerCommandTypeToString(fwCmd->layer),
+                                             rollback);
+        VIR_DEBUG("Recording Rollback command '%s'", NULLSTR(rollbackStr));
+    }
+
     return 0;
 }
 
@@ -599,7 +640,7 @@ virFirewallApplyCmd(virFirewall *firewall,
         return -1;
     }
 
-    if (virFirewallApplyCmdDirect(fwCmd, &output) < 0)
+    if (virFirewallCmdIptablesApply(firewall, fwCmd, &output) < 0)
         return -1;
 
     if (fwCmd->queryCB && output) {
-- 
2.44.0
_______________________________________________
Devel mailing list -- devel@lists.libvirt.org
To unsubscribe send an email to devel-leave@lists.libvirt.org
Re: [PATCH v4 15/30] util: implement rollback rule autocreation for iptables commands
Posted by Daniel P. Berrangé 1 year, 7 months ago
On Tue, Apr 30, 2024 at 01:44:04PM -0400, Laine Stump wrote:
> If the VIR_FIREWALL_TRANSACTION_AUTO_ROLLBACK flag is set, each time
> an iptables command is executed that is adding a rule or chain, a
> corresponding command that will *delete* the same rule/chain is
> constructed and added to the list of rollback commands. If we later
> want to undo the entire firewall, we can just run those commands.
> 
> This isn't yet used anywhere, since
> VIR_FIREWALL_TRANSACTION_AUTO_ROLLBACK isn't being set.
> 
> Signed-off-by: Laine Stump <laine@redhat.com>
> ---
>  src/util/virfirewall.c | 55 ++++++++++++++++++++++++++++++++++++------
>  1 file changed, 48 insertions(+), 7 deletions(-)

Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
_______________________________________________
Devel mailing list -- devel@lists.libvirt.org
To unsubscribe send an email to devel-leave@lists.libvirt.org