On Sun, Apr 30, 2023 at 11:19:23PM -0400, Laine Stump wrote:
This is the only iptables-specific function in all of
virfirewall.c. By moving it to viriptables.c (with appropriate
renaming), and calling it indirectly through a similarly named wrapper
function in virnetfilter.c, we have made virfirewall.c backend
agnostic (the new wrapper function will soon be calling either
virIptablesApplyFirewallRule() or (to-be-created)
virNftablesApplyFirewallRule() depending on the backend chosen when
creating the virFirewall object).
Signed-off-by: Laine Stump <laine(a)redhat.com>
---
src/libvirt_private.syms | 2 ++
src/util/virfirewall.c | 72 ++-----------------------------------
src/util/viriptables.c | 78 ++++++++++++++++++++++++++++++++++++++++
src/util/viriptables.h | 6 ++++
src/util/virnetfilter.c | 19 ++++++++++
src/util/virnetfilter.h | 3 ++
I don't much like this split of responsibilities.
With the current codebase
* virfirewall.c is the low level transactional interface for
interacting with firewalls.
* viriptables.c is a medium level interface providing helpers
needed by the network bridge driver
The viriptables.c file probably ought not to even be located
in the src/util directory. Its API is inherantly tied to the
bridge driver, so ought to be moved to src/network/bridge_iptables.c
I think.
IOW, we have a clean flow from high level to low level of
bridge_driver.c -> viriptables.c -> virfirewall.c
and
nwfilter_driver.c -> nwfilter_ebiptables_driver.c -> virfirewall.c
After this change, AFAICT we have dependancy loops
* virfirewall.c is the low level transactional interface for
interacting with firwalls
* viriptables.c is a medium level interface providing helpers
needed by the netfilter APIs, and also helpers needed by
virfirewall.c
* virnetfilter.c is a slightly higher level inteface
providing helpers needed by the bridge interface
IOW, AFAICT we now have
bridge-driver.c -> virnetfilter.c -> viriptables.c -> virfirewall.c
^ |
| |
\-----------------/
and
nwfilter_driver.c -> nwfilter_ebiptables_driver.c -> virfirewall.c ->
viriptables.c
6 files changed, 110 insertions(+), 70 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 11b84a866a..cf68e4c942 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2550,6 +2550,7 @@ virInitctlSetRunLevel;
iptablesAddOutputFixUdpChecksum;
iptablesRemoveOutputFixUdpChecksum;
iptablesSetupPrivateChains;
+virIptablesApplyFirewallRule;
# util/viriscsi.h
@@ -2949,6 +2950,7 @@ virNetfilterAddTcpInput;
virNetfilterAddTcpOutput;
virNetfilterAddUdpInput;
virNetfilterAddUdpOutput;
+virNetfilterApplyFirewallRule;
virNetfilterRemoveDontMasquerade;
virNetfilterRemoveForwardAllowCross;
virNetfilterRemoveForwardAllowIn;
diff --git a/src/util/virfirewall.c b/src/util/virfirewall.c
index e3ba8f7846..6603fd6341 100644
--- a/src/util/virfirewall.c
+++ b/src/util/virfirewall.c
@@ -24,6 +24,7 @@
#include "virfirewall.h"
#include "virfirewalld.h"
+#include "virnetfilter.h"
#include "viralloc.h"
#include "virerror.h"
#include "vircommand.h"
@@ -37,14 +38,6 @@ VIR_LOG_INIT("util.firewall");
typedef struct _virFirewallGroup virFirewallGroup;
-VIR_ENUM_DECL(virFirewallLayerCommand);
-VIR_ENUM_IMPL(virFirewallLayerCommand,
- VIR_FIREWALL_LAYER_LAST,
- EBTABLES,
- IPTABLES,
- IP6TABLES,
-);
-
struct _virFirewallRule {
virFirewallLayer layer;
@@ -500,67 +493,6 @@ virFirewallRuleToString(const char *cmd,
}
-static int
-virFirewallApplyRuleDirect(virFirewallRule *rule,
- char **output)
-{
- size_t i;
- const char *bin = virFirewallLayerCommandTypeToString(rule->layer);
- g_autoptr(virCommand) cmd = NULL;
- g_autofree char *cmdStr = NULL;
- int status;
- g_autofree char *error = NULL;
-
- if (!bin) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unknown firewall layer %1$d"),
- rule->layer);
- return -1;
- }
-
- cmd = virCommandNewArgList(bin, NULL);
-
- /* lock to assure nobody else is messing with the tables while we are */
- switch (rule->layer) {
- case VIR_FIREWALL_LAYER_ETHERNET:
- virCommandAddArg(cmd, "--concurrent");
- break;
- case VIR_FIREWALL_LAYER_IPV4:
- case VIR_FIREWALL_LAYER_IPV6:
- virCommandAddArg(cmd, "-w");
- break;
- case VIR_FIREWALL_LAYER_LAST:
- break;
- }
-
- for (i = 0; i < rule->argsLen; i++)
- virCommandAddArg(cmd, rule->args[i]);
-
- cmdStr = virCommandToString(cmd, false);
- VIR_INFO("Applying rule '%s'", NULLSTR(cmdStr));
-
- virCommandSetOutputBuffer(cmd, output);
- virCommandSetErrorBuffer(cmd, &error);
-
- if (virCommandRun(cmd, &status) < 0)
- return -1;
-
- if (status != 0) {
- if (virFirewallRuleGetIgnoreErrors(rule)) {
- VIR_DEBUG("Ignoring error running command");
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Failed to apply firewall rules %1$s: %2$s"),
- NULLSTR(cmdStr), NULLSTR(error));
- VIR_FREE(*output);
- return -1;
- }
- }
-
- return 0;
-}
-
-
static int
virFirewallApplyRule(virFirewall *firewall,
virFirewallRule *rule)
@@ -568,7 +500,7 @@ virFirewallApplyRule(virFirewall *firewall,
g_autofree char *output = NULL;
g_auto(GStrv) lines = NULL;
- if (virFirewallApplyRuleDirect(rule, &output) < 0)
+ if (virNetfilterApplyFirewallRule(firewall, rule, &output) < 0)
return -1;
if (rule->queryCB && output) {
diff --git a/src/util/viriptables.c b/src/util/viriptables.c
index a0c35887c5..9c7f7790c4 100644
--- a/src/util/viriptables.c
+++ b/src/util/viriptables.c
@@ -31,6 +31,8 @@
#include "viriptables.h"
#include "virfirewalld.h"
#include "virerror.h"
+#include "viralloc.h"
+#include "vircommand.h"
#include "virlog.h"
#include "virhash.h"
#include "virenum.h"
@@ -40,6 +42,19 @@ VIR_LOG_INIT("util.iptables");
#define VIR_FROM_THIS VIR_FROM_NONE
+/* iptables backend uses a different program for each layer. This
+ * gives us a convenient function for converting VIR_FIREWALL_LAYER_*
+ * enum from a virFirewallRule into a binary name.
+ */
+VIR_ENUM_DECL(virIptablesLayerCommand);
+VIR_ENUM_IMPL(virIptablesLayerCommand,
+ VIR_FIREWALL_LAYER_LAST,
+ EBTABLES,
+ IPTABLES,
+ IP6TABLES,
+);
+
+
VIR_ENUM_DECL(virIptablesAction);
VIR_ENUM_IMPL(virIptablesAction,
VIR_FIREWALL_ACTION_LAST,
@@ -49,6 +64,69 @@ VIR_ENUM_IMPL(virIptablesAction,
);
+int
+virIptablesApplyFirewallRule(virFirewall *firewall G_GNUC_UNUSED,
+ virFirewallRule *rule,
+ char **output)
+{
+ virFirewallLayer layer = virFirewallRuleGetLayer(rule);
+ const char *bin = virIptablesLayerCommandTypeToString(layer);
+ g_autoptr(virCommand) cmd = NULL;
+ g_autofree char *cmdStr = NULL;
+ g_autofree char *error = NULL;
+ size_t i, count;
+ int status;
+
+ if (!bin) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown firewall layer %1$d"), layer);
+ return -1;
+ }
+
+ cmd = virCommandNewArgList(bin, NULL);
+
+ /* lock to assure nobody else is messing with the tables while we are */
+ switch (layer) {
+ case VIR_FIREWALL_LAYER_ETHERNET:
+ virCommandAddArg(cmd, "--concurrent");
+ break;
+ case VIR_FIREWALL_LAYER_IPV4:
+ case VIR_FIREWALL_LAYER_IPV6:
+ virCommandAddArg(cmd, "-w");
+ break;
+ case VIR_FIREWALL_LAYER_LAST:
+ break;
+ }
+
+ count = virFirewallRuleGetArgCount(rule);
+ for (i = 0; i < count; i++)
+ virCommandAddArg(cmd, virFirewallRuleGetArg(rule, i));
+
+ cmdStr = virCommandToString(cmd, false);
+ VIR_INFO("Applying rule '%s'", NULLSTR(cmdStr));
+
+ virCommandSetOutputBuffer(cmd, output);
+ virCommandSetErrorBuffer(cmd, &error);
+
+ if (virCommandRun(cmd, &status) < 0)
+ return -1;
+
+ if (status != 0) {
+ if (virFirewallRuleGetIgnoreErrors(rule)) {
+ VIR_DEBUG("Ignoring error running command");
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to apply firewall rules %1$s: %2$s"),
+ NULLSTR(cmdStr), NULLSTR(error));
+ VIR_FREE(*output);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
typedef struct {
const char *parent;
const char *child;
diff --git a/src/util/viriptables.h b/src/util/viriptables.h
index 17f43a8fa8..990cb2e25d 100644
--- a/src/util/viriptables.h
+++ b/src/util/viriptables.h
@@ -24,6 +24,12 @@
#include "virfirewall.h"
#include "virnetfilter.h"
+/* virIptablesApplyFirewallRule should be called only from virnetfilter.c */
+int
+virIptablesApplyFirewallRule(virFirewall *firewall,
+ virFirewallRule *rule,
+ char **output);
+
/* These functions are (currently) called directly from the consumer
* (e.g. the network driver), and only when the iptables backend is
* selected. (Possibly/probably functions should be added to the
diff --git a/src/util/virnetfilter.c b/src/util/virnetfilter.c
index 10c1a54e26..ba0f292ea9 100644
--- a/src/util/virnetfilter.c
+++ b/src/util/virnetfilter.c
@@ -44,6 +44,25 @@ VIR_LOG_INIT("util.netfilter");
#define VIR_FROM_THIS VIR_FROM_NONE
+/**
+ * virNetfilterApplyFirewallRule:
+ * @fw: the virFirewall this rule is part of (currently unused)
+ * @rule: this particular rule
+ * @ignoreErrors: true if errors should be ignored
+ * @output: everything that appears on stdout as a result of applying the rule
+ *
+ * Applies @rule to the host's network filtering. returns 0 on success
+ * -1 on failure.
+ */
+int
+virNetfilterApplyFirewallRule(virFirewall *fw,
+ virFirewallRule *rule,
+ char **output)
+{
+ return virIptablesApplyFirewallRule(fw, rule, output);
+}
+
+
/**
* virNetfilterAddTcpInput:
* @ctx: pointer to the IP table context
diff --git a/src/util/virnetfilter.h b/src/util/virnetfilter.h
index b515512ad7..eff047cde0 100644
--- a/src/util/virnetfilter.h
+++ b/src/util/virnetfilter.h
@@ -30,6 +30,9 @@
#define VIR_NETFILTER_FWD_X_CHAIN "LIBVIRT_FWX"
#define VIR_NETFILTER_NAT_POSTROUTE_CHAIN "LIBVIRT_PRT"
+int virNetfilterApplyFirewallRule (virFirewall *fw,
+ virFirewallRule *rule,
+ char **output);
void virNetfilterAddTcpInput (virFirewall *fw,
virFirewallLayer layer,
const char *iface,
--
2.39.2
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 :|