]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
virfirewalltest: Introduce testIPtablesSetupPrivateChains()
authorMichal Privoznik <mprivozn@redhat.com>
Wed, 26 Nov 2025 20:40:06 +0000 (21:40 +0100)
committerMichal Privoznik <mprivozn@redhat.com>
Tue, 2 Dec 2025 11:35:51 +0000 (12:35 +0100)
When the network driver starts up it may inject some firewall
rules (e.g. for a network with NAT). So far, this scenario wasn't
covered in our test suite. The reason for adding this test is
twofold: the first, check we add correct rules, the second is to
cover iptablesPrivateChainCreate() as its implementation is soon
to be changed.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Tested-by: Jaroslav Suchanek <jsuchane@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
src/network/meson.build
tests/meson.build
tests/virfirewalltest.c

index 51bbf7063d80a2bd7e6201daa9dcc4d751ace691..7a9897485251917271b349682bedb780b8e39cd2 100644 (file)
@@ -10,6 +10,7 @@ if host_machine.system() == 'freebsd'
   network_driver_sources += 'network_pf.c'
 endif
 
+network_inc_dir = include_directories('.')
 driver_source_files += files(network_driver_sources)
 stateful_driver_source_files += files(network_driver_sources)
 
index bb6ee6b4eee12c6983159518767ec58375825410..1f73d6c029d46eae52142b7a9238aef5f58c5289 100644 (file)
@@ -259,6 +259,13 @@ if conf.has('WITH_QEMU')
   domaincapstest_link_whole += [ test_utils_qemu_lib ]
 endif
 
+virfirewalltest_include = []
+virfirewalltest_link_with = []
+if conf.has('WITH_NETWORK')
+  virfirewalltest_include += [ network_inc_dir ]
+  virfirewalltest_link_with += [ network_driver_impl ]
+endif
+
 tests += [
   { 'name': 'commandtest' },
   { 'name': 'cputest', 'link_with': cputest_link_with, 'link_whole': cputest_link_whole },
@@ -286,7 +293,7 @@ tests += [
   { 'name': 'virerrortest' },
   { 'name': 'virfilecachetest' },
   { 'name': 'virfiletest' },
-  { 'name': 'virfirewalltest' },
+  { 'name': 'virfirewalltest', 'include': virfirewalltest_include, 'link_with': virfirewalltest_link_with },
   { 'name': 'virhostcputest', 'link_whole': [ test_file_wrapper_lib ] },
   { 'name': 'virhostdevtest' },
   { 'name': 'viridentitytest' },
index 38726dcc7a919d2175d793e10b52d2ef7888690b..942eba90d76913e6349fbf156fb174cd3404e95e 100644 (file)
@@ -26,6 +26,9 @@
 
 # include "virbuffer.h"
 # include "virfirewall.h"
+# if WITH_NETWORK
+#  include "network_iptables.h"
+# endif
 
 # define LIBVIRT_VIRCOMMANDPRIV_H_ALLOW
 # include "vircommandpriv.h"
@@ -763,6 +766,113 @@ testFirewallQuery(const void *opaque G_GNUC_UNUSED)
 }
 
 
+static void G_GNUC_UNUSED
+testIPtablesSetupPrivateChainsHook(const char *const *args,
+                                   const char *const *env G_GNUC_UNUSED,
+                                   const char *input G_GNUC_UNUSED,
+                                   char **output,
+                                   char **error,
+                                   int *status,
+                                   void *opaque G_GNUC_UNUSED)
+{
+    if (STREQ_NULLABLE(*args, "iptables") &&
+        STREQ_NULLABLE(*(args + 1), "-w") &&
+        STREQ_NULLABLE(*(args + 2), "--table") &&
+        STREQ_NULLABLE(*(args + 3), "filter") &&
+        STREQ_NULLABLE(*(args + 4), "--list-rules")) {
+        *output = g_strdup("-P INPUT ACCEPT\n"
+                           "-P FORWARD ACCEPT\n"
+                           "-P OUTPUT ACCEPT\n"
+                          );
+        *error = NULL;
+        *status = EXIT_SUCCESS;
+        return;
+    }
+
+    if (STREQ_NULLABLE(*args, "iptables") &&
+        STREQ_NULLABLE(*(args + 1), "-w") &&
+        STREQ_NULLABLE(*(args + 2), "--table") &&
+        STREQ_NULLABLE(*(args + 3), "nat") &&
+        STREQ_NULLABLE(*(args + 4), "--list-rules")) {
+        *output = g_strdup("-P PREROUTING ACCEPT\n"
+                           "-P INPUT ACCEPT\n"
+                           "-P OUTPUT ACCEPT\n"
+                           "-P POSTROUTING ACCEPT\n");
+        *error = NULL;
+        *status = EXIT_SUCCESS;
+        return;
+    }
+
+    /* Intentionally steering away from empty rules above. This is how the
+     * table looks AFTER we've injected our rules. The idea is to cover more
+     * lines, esp. in iptablesPrivateChainCreate(). */
+    if (STREQ_NULLABLE(*args, "iptables") &&
+        STREQ_NULLABLE(*(args + 1), "-w") &&
+        STREQ_NULLABLE(*(args + 2), "--table") &&
+        STREQ_NULLABLE(*(args + 3), "mangle") &&
+        STREQ_NULLABLE(*(args + 4), "--list-rules")) {
+        *output = g_strdup("-P PREROUTING ACCEPT\n"
+                           "-P INPUT ACCEPT\n"
+                           "-P FORWARD ACCEPT\n"
+                           "-P OUTPUT ACCEPT\n"
+                           "-P POSTROUTING ACCEPT\n"
+                           "-N LIBVIRT_PRT\n"
+                           "-A POSTROUTING -j LIBVIRT_PRT\n"
+                           "-A LIBVIRT_PRT -o virbr0 -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill\n");
+        *error = NULL;
+        *status = EXIT_SUCCESS;
+        return;
+    }
+
+    *output = NULL;
+    *error = NULL;
+    *status = EXIT_SUCCESS;
+}
+
+
+static int
+testIPtablesSetupPrivateChains(const void *opaque G_GNUC_UNUSED)
+{
+# if WITH_NETWORK
+    g_auto(virBuffer) cmdbuf = VIR_BUFFER_INITIALIZER;
+    g_autoptr(virCommandDryRunToken) dryRunToken = virCommandDryRunTokenNew();
+    const char *actual;
+    const char *expected =
+        IPTABLES " -w --table filter --list-rules\n"
+        IPTABLES " -w --table nat --list-rules\n"
+        IPTABLES " -w --table mangle --list-rules\n"
+        IPTABLES " -w --table filter --new-chain LIBVIRT_INP\n"
+        IPTABLES " -w --table filter --insert INPUT --jump LIBVIRT_INP\n"
+        IPTABLES " -w --table filter --new-chain LIBVIRT_OUT\n"
+        IPTABLES " -w --table filter --insert OUTPUT --jump LIBVIRT_OUT\n"
+        IPTABLES " -w --table filter --new-chain LIBVIRT_FWO\n"
+        IPTABLES " -w --table filter --insert FORWARD --jump LIBVIRT_FWO\n"
+        IPTABLES " -w --table filter --new-chain LIBVIRT_FWI\n"
+        IPTABLES " -w --table filter --insert FORWARD --jump LIBVIRT_FWI\n"
+        IPTABLES " -w --table filter --new-chain LIBVIRT_FWX\n"
+        IPTABLES " -w --table filter --insert FORWARD --jump LIBVIRT_FWX\n"
+        IPTABLES " -w --table nat --new-chain LIBVIRT_PRT\n"
+        IPTABLES " -w --table nat --insert POSTROUTING --jump LIBVIRT_PRT\n";
+
+    virCommandSetDryRun(dryRunToken, &cmdbuf, false, false, testIPtablesSetupPrivateChainsHook, NULL);
+
+    if (iptablesSetupPrivateChains(VIR_FIREWALL_LAYER_IPV4) < 0)
+        return -1;
+
+    actual = virBufferCurrentContent(&cmdbuf);
+
+    if (virTestCompareToString(expected, actual) < 0) {
+        fprintf(stderr, "Unexpected command execution\n");
+        return -1;
+    }
+
+    return 0;
+# else
+    return EXIT_AM_SKIP;
+# endif
+}
+
+
 static int
 mymain(void)
 {
@@ -784,6 +894,7 @@ mymain(void)
     RUN_TEST("many rollback", testFirewallManyRollback);
     RUN_TEST("chained rollback", testFirewallChainedRollback);
     RUN_TEST("query transaction", testFirewallQuery);
+    RUN_TEST("setup private chains", testIPtablesSetupPrivateChains);
 
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }