diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c index f1bb097d89..1bb8738730 100644 --- a/src/nwfilter/nwfilter_ebiptables_driver.c +++ b/src/nwfilter/nwfilter_ebiptables_driver.c @@ -3544,127 +3544,103 @@ ebtablesApplyDHCPOnlyRules(const char *ifname, virNWFilterVarValuePtr dhcpsrvrs, bool leaveTemporary) { - virBuffer buf = VIR_BUFFER_INITIALIZER; char chain_in [MAX_CHAINNAME_LENGTH], chain_out[MAX_CHAINNAME_LENGTH]; char macaddr_str[VIR_MAC_STRING_BUFLEN]; unsigned int idx = 0; unsigned int num_dhcpsrvrs; - - if (!ebtables_cmd_path) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot create rules since ebtables tool is " - "missing.")); - return -1; - } + virFirewallPtr fw = virFirewallNew(); virMacAddrFormat(macaddr, macaddr_str); - ebiptablesAllTeardown(ifname); + if (ebiptablesAllTeardown(ifname) < 0) + goto error; - NWFILTER_SET_EBTABLES_SHELLVAR(&buf); + virFirewallStartTransaction(fw, 0); - ebtablesCreateTmpRootChain(&buf, true, ifname); - ebtablesCreateTmpRootChain(&buf, false, ifname); + ebtablesCreateTmpRootChainFW(fw, true, ifname); + ebtablesCreateTmpRootChainFW(fw, false, ifname); PRINT_ROOT_CHAIN(chain_in, CHAINPREFIX_HOST_IN_TEMP, ifname); PRINT_ROOT_CHAIN(chain_out, CHAINPREFIX_HOST_OUT_TEMP, ifname); - virBufferAsprintf(&buf, - CMD_DEF("$EBT -t nat -A %s" - " -s %s" - " -p ipv4 --ip-protocol udp" - " --ip-sport 68 --ip-dport 67" - " -j ACCEPT") CMD_SEPARATOR - CMD_EXEC - "%s", + virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET, + "-t", "nat", "-A", chain_in, + "-s", macaddr_str, + "-p", "ipv4", "--ip-protocol", "udp", + "--ip-sport", "68", "--ip-dport", "67", + "-j", "ACCEPT", NULL); - chain_in, - macaddr_str, - CMD_STOPONERR(true)); - - virBufferAsprintf(&buf, - CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR - CMD_EXEC - "%s", - - chain_in, - CMD_STOPONERR(true)); + virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET, + "-t", "nat", "-A", chain_in, + "-j", "DROP", NULL); num_dhcpsrvrs = (dhcpsrvrs != NULL) ? virNWFilterVarValueGetCardinality(dhcpsrvrs) : 0; while (true) { - char *srcIPParam = NULL; + const char *dhcpserver = NULL; int ctr; - if (idx < num_dhcpsrvrs) { - const char *dhcpserver; - + if (idx < num_dhcpsrvrs) dhcpserver = virNWFilterVarValueGetNthValue(dhcpsrvrs, idx); - if (virAsprintf(&srcIPParam, "--ip-src %s", dhcpserver) < 0) - goto tear_down_tmpebchains; - } - /* * create two rules allowing response to MAC address of VM * or to broadcast MAC address */ for (ctr = 0; ctr < 2; ctr++) { - virBufferAsprintf(&buf, - CMD_DEF("$EBT -t nat -A %s" - " -d %s" - " -p ipv4 --ip-protocol udp" - " %s" - " --ip-sport 67 --ip-dport 68" - " -j ACCEPT") CMD_SEPARATOR - CMD_EXEC - "%s", - - chain_out, - (ctr == 0) ? macaddr_str : "ff:ff:ff:ff:ff:ff", - srcIPParam != NULL ? srcIPParam : "", - CMD_STOPONERR(true)); + if (dhcpserver) + virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET, + "-t", "nat", "-A", chain_out, + "-d", (ctr == 0) ? macaddr_str : "ff:ff:ff:ff:ff:ff", + "-p", "ipv4", "--ip-protocol", "udp", + "--ip-src", dhcpserver, + "--ip-sport", "67", "--ip-dport", "68", + "-j", "ACCEPT", NULL); + else + virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET, + "-t", "nat", "-A", chain_out, + "-d", (ctr == 0) ? macaddr_str : "ff:ff:ff:ff:ff:ff", + "-p", "ipv4", "--ip-protocol", "udp", + "--ip-sport", "67", "--ip-dport", "68", + "-j", "ACCEPT", NULL); } - VIR_FREE(srcIPParam); - idx++; if (idx >= num_dhcpsrvrs) break; } - virBufferAsprintf(&buf, - CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR - CMD_EXEC - "%s", + virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET, + "-t", "nat", "-A", chain_out, + "-j", "DROP", NULL); - chain_out, - CMD_STOPONERR(true)); - - ebtablesLinkTmpRootChain(&buf, true, ifname); - ebtablesLinkTmpRootChain(&buf, false, ifname); + ebtablesLinkTmpRootChainFW(fw, true, ifname); + ebtablesLinkTmpRootChainFW(fw, false, ifname); if (!leaveTemporary) { - ebtablesRenameTmpRootChain(&buf, true, ifname); - ebtablesRenameTmpRootChain(&buf, false, ifname); + ebtablesRenameTmpRootChainFW(fw, true, ifname); + ebtablesRenameTmpRootChainFW(fw, false, ifname); } - if (ebiptablesExecCLI(&buf, false, NULL) < 0) + virMutexLock(&execCLIMutex); + if (virFirewallApply(fw) < 0) { + virMutexUnlock(&execCLIMutex); goto tear_down_tmpebchains; + } + virMutexUnlock(&execCLIMutex); + + virFirewallFree(fw); return 0; tear_down_tmpebchains: ebtablesCleanAll(ifname); - - virReportError(VIR_ERR_BUILD_FIREWALL, - "%s", - _("Some rules could not be created.")); - + error: + virFirewallFree(fw); return -1; } diff --git a/tests/nwfilterebiptablestest.c b/tests/nwfilterebiptablestest.c index c03e79f092..3f9be3ecdc 100644 --- a/tests/nwfilterebiptablestest.c +++ b/tests/nwfilterebiptablestest.c @@ -348,6 +348,95 @@ testNWFilterEBIPTablesApplyBasicRules(const void *opaque ATTRIBUTE_UNUSED) } +static int +testNWFilterEBIPTablesApplyDHCPOnlyRules(const void *opaque ATTRIBUTE_UNUSED) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + const char *expected = + "iptables -D libvirt-out -m physdev --physdev-is-bridged --physdev-out vnet0 -g FO-vnet0\n" + "iptables -D libvirt-out -m physdev --physdev-out vnet0 -g FO-vnet0\n" + "iptables -D libvirt-in -m physdev --physdev-in vnet0 -g FI-vnet0\n" + "iptables -D libvirt-host-in -m physdev --physdev-in vnet0 -g HI-vnet0\n" + "iptables -D libvirt-in-post -m physdev --physdev-in vnet0 -j ACCEPT\n" + "iptables -F FO-vnet0\n" + "iptables -X FO-vnet0\n" + "iptables -F FI-vnet0\n" + "iptables -X FI-vnet0\n" + "iptables -F HI-vnet0\n" + "iptables -X HI-vnet0\n" + "ip6tables -D libvirt-out -m physdev --physdev-is-bridged --physdev-out vnet0 -g FO-vnet0\n" + "ip6tables -D libvirt-out -m physdev --physdev-out vnet0 -g FO-vnet0\n" + "ip6tables -D libvirt-in -m physdev --physdev-in vnet0 -g FI-vnet0\n" + "ip6tables -D libvirt-host-in -m physdev --physdev-in vnet0 -g HI-vnet0\n" + "ip6tables -D libvirt-in-post -m physdev --physdev-in vnet0 -j ACCEPT\n" + "ip6tables -F FO-vnet0\n" + "ip6tables -X FO-vnet0\n" + "ip6tables -F FI-vnet0\n" + "ip6tables -X FI-vnet0\n" + "ip6tables -F HI-vnet0\n" + "ip6tables -X HI-vnet0\n" + "ebtables -t nat -D PREROUTING -i vnet0 -j libvirt-I-vnet0\n" + "ebtables -t nat -D POSTROUTING -o vnet0 -j libvirt-O-vnet0\n" + "ebtables -t nat -L libvirt-I-vnet0\n" + "ebtables -t nat -L libvirt-O-vnet0\n" + "ebtables -t nat -F libvirt-I-vnet0\n" + "ebtables -t nat -X libvirt-I-vnet0\n" + "ebtables -t nat -F libvirt-O-vnet0\n" + "ebtables -t nat -X libvirt-O-vnet0\n" + "ebtables -t nat -N libvirt-J-vnet0\n" + "ebtables -t nat -N libvirt-P-vnet0\n" + "ebtables -t nat -A libvirt-J-vnet0 -s 10:20:30:40:50:60 -p ipv4 --ip-protocol udp --ip-sport 68 --ip-dport 67 -j ACCEPT\n" + "ebtables -t nat -A libvirt-J-vnet0 -j DROP\n" + "ebtables -t nat -A libvirt-P-vnet0 -d 10:20:30:40:50:60 -p ipv4 --ip-protocol udp --ip-src 192.168.122.1 --ip-sport 67 --ip-dport 68 -j ACCEPT\n" + "ebtables -t nat -A libvirt-P-vnet0 -d ff:ff:ff:ff:ff:ff -p ipv4 --ip-protocol udp --ip-src 192.168.122.1 --ip-sport 67 --ip-dport 68 -j ACCEPT\n" + "ebtables -t nat -A libvirt-P-vnet0 -d 10:20:30:40:50:60 -p ipv4 --ip-protocol udp --ip-src 10.0.0.1 --ip-sport 67 --ip-dport 68 -j ACCEPT\n" + "ebtables -t nat -A libvirt-P-vnet0 -d ff:ff:ff:ff:ff:ff -p ipv4 --ip-protocol udp --ip-src 10.0.0.1 --ip-sport 67 --ip-dport 68 -j ACCEPT\n" + "ebtables -t nat -A libvirt-P-vnet0 -d 10:20:30:40:50:60 -p ipv4 --ip-protocol udp --ip-src 10.0.0.2 --ip-sport 67 --ip-dport 68 -j ACCEPT\n" + "ebtables -t nat -A libvirt-P-vnet0 -d ff:ff:ff:ff:ff:ff -p ipv4 --ip-protocol udp --ip-src 10.0.0.2 --ip-sport 67 --ip-dport 68 -j ACCEPT\n" + "ebtables -t nat -A libvirt-P-vnet0 -j DROP\n" + "ebtables -t nat -A PREROUTING -i vnet0 -j libvirt-J-vnet0\n" + "ebtables -t nat -A POSTROUTING -o vnet0 -j libvirt-P-vnet0\n" + "ebtables -t nat -E libvirt-J-vnet0 libvirt-I-vnet0\n" + "ebtables -t nat -E libvirt-P-vnet0 libvirt-O-vnet0\n"; + char *actual = NULL; + int ret = -1; + virMacAddr mac = { .addr = { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60 } }; + const char *servers[] = { "192.168.122.1", "10.0.0.1", "10.0.0.2" }; + virNWFilterVarValue val = { + .valType = NWFILTER_VALUE_TYPE_ARRAY, + .u = { + .array = { + .values = (char **)servers, + .nValues = 3, + } + } + }; + + virCommandSetDryRun(&buf, NULL, NULL); + + if (ebiptables_driver.applyDHCPOnlyRules("vnet0", &mac, &val, false) < 0) + goto cleanup; + + if (virBufferError(&buf)) + goto cleanup; + + actual = virBufferContentAndReset(&buf); + virtTestClearCommandPath(actual); + + if (STRNEQ_NULLABLE(actual, expected)) { + virtTestDifference(stderr, actual, expected); + goto cleanup; + } + + ret = 0; + cleanup: + virCommandSetDryRun(NULL, NULL, NULL); + virBufferFreeAndReset(&buf); + VIR_FREE(actual); + return ret; +} + + static int mymain(void) { @@ -383,6 +472,11 @@ mymain(void) NULL) < 0) ret = -1; + if (virtTestRun("ebiptablesApplyDHCPOnlyRules", + testNWFilterEBIPTablesApplyDHCPOnlyRules, + NULL) < 0) + ret = -1; + cleanup: return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }