This patch adds support for L3/L4 filtering using iptables. This adds support for 'tcp', 'udp', 'icmp', 'igmp', 'sctp' etc. filtering. As mentioned in the introduction, a .c file provided by this patch is #include'd into a .c file. This will need work, but should be alright for review. Signed-off-by: Stefan Berger --- configure.ac | 7 src/conf/nwfilter_conf.c | 278 ++++++ src/conf/nwfilter_conf.h | 73 + src/libvirt_private.syms | 1 src/nwfilter/nwfilter_ebiptables_driver.c | 1231 ++++++++++++++++++++++++++++-- src/nwfilter/nwfilter_ebiptables_driver.h | 7 6 files changed, 1529 insertions(+), 68 deletions(-) Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c =================================================================== --- libvirt-acl.orig/src/nwfilter/nwfilter_ebiptables_driver.c +++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c @@ -63,7 +63,10 @@ #define EBTABLES_CMD EBTABLES_PATH +#define IPTABLES_CMD IPTABLES_PATH #define BASH_CMD BASH_PATH +#define GREP_CMD GREP_PATH +#define GAWK_CMD GAWK_PATH #define PRINT_ROOT_CHAIN(buf, prefix, ifname) \ snprintf(buf, sizeof(buf), "libvirt-%c-%s", prefix, ifname) @@ -71,6 +74,28 @@ snprintf(buf, sizeof(buf), "%c-%s-%s", prefix, ifname, suffix) +#define VIRT_IN_CHAIN "libvirt-in" +#define VIRT_OUT_CHAIN "libvirt-out" +#define VIRT_IN_POST_CHAIN "libvirt-in-post" +#define HOST_IN_CHAIN "libvirt-host-in" + +#define PRINT_IPT_ROOT_CHAIN(buf, prefix, ifname) \ + snprintf(buf, sizeof(buf), "%c%c-%s", prefix[0], prefix[1], ifname) + +#define PHYSDEV_IN "--physdev-in" +#define PHYSDEV_OUT "--physdev-out" + +static const char *m_state_out_str = "-m state --state NEW,ESTABLISHED"; +static const char *m_state_in_str = "-m state --state ESTABLISHED"; +static const char *m_physdev_in_str = "-m physdev " PHYSDEV_IN; +static const char *m_physdev_out_str = "-m physdev " PHYSDEV_OUT; + +#define MATCH_STATE_OUT m_state_out_str +#define MATCH_STATE_IN m_state_in_str +#define MATCH_PHYSDEV_IN m_physdev_in_str +#define MATCH_PHYSDEV_OUT m_physdev_out_str + + static const char *supported_protocols[] = { "ipv4", "ipv6", @@ -195,108 +220,1087 @@ printDataType(virConnectPtr conn, } -static void -ebiptablesRuleInstFree(ebiptablesRuleInstPtr inst) -{ - if (!inst) - return; +static void +ebiptablesRuleInstFree(ebiptablesRuleInstPtr inst) +{ + if (!inst) + return; + + VIR_FREE(inst->commandTemplate); + VIR_FREE(inst); +} + + +static int +ebiptablesAddRuleInst(virConnectPtr conn, + virNWFilterRuleInstPtr res, + char *commandTemplate, + enum virNWFilterChainSuffixType neededChain, + char chainprefix, + unsigned int priority, + enum RuleType ruleType) +{ + ebiptablesRuleInstPtr inst; + + if (VIR_ALLOC(inst) < 0) { + virReportOOMError(); + return 1; + } + + inst->commandTemplate = commandTemplate; + inst->neededProtocolChain = neededChain; + inst->chainprefix = chainprefix; + inst->priority = priority; + inst->ruleType = ruleType; + + return virNWFilterRuleInstAddData(conn, res, inst); +} + + +static int +ebtablesHandleEthHdr(virConnectPtr conn, + virBufferPtr buf, + virNWFilterHashTablePtr vars, + ethHdrDataDefPtr ethHdr) +{ + char macaddr[VIR_MAC_STRING_BUFLEN]; + + if (HAS_ENTRY_ITEM(ðHdr->dataSrcMACAddr)) { + if (printDataType(conn, + vars, + macaddr, sizeof(macaddr), + ðHdr->dataSrcMACAddr)) + goto err_exit; + + virBufferVSprintf(buf, + " -s %s %s", + ENTRY_GET_NEG_SIGN(ðHdr->dataSrcMACAddr), + macaddr); + + if (HAS_ENTRY_ITEM(ðHdr->dataSrcMACMask)) { + if (printDataType(conn, + vars, + macaddr, sizeof(macaddr), + ðHdr->dataSrcMACMask)) + goto err_exit; + + virBufferVSprintf(buf, + "/%s", + macaddr); + } + } + + if (HAS_ENTRY_ITEM(ðHdr->dataDstMACAddr)) { + if (printDataType(conn, + vars, + macaddr, sizeof(macaddr), + ðHdr->dataDstMACAddr)) + goto err_exit; + + virBufferVSprintf(buf, + " -d %s %s", + ENTRY_GET_NEG_SIGN(ðHdr->dataDstMACAddr), + macaddr); + + if (HAS_ENTRY_ITEM(ðHdr->dataDstMACMask)) { + if (printDataType(conn, + vars, + macaddr, sizeof(macaddr), + ðHdr->dataDstMACMask)) + goto err_exit; + + virBufferVSprintf(buf, + "/%s", + macaddr); + } + } + + return 0; + + err_exit: + virBufferFreeAndReset(buf); + + return 1; +} + + +/************************ iptables support ************************/ + +static int iptablesLinkIPTablesBaseChain(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + const char *udchain, + const char *syschain, + unsigned int pos, + int stopOnError) +{ + virBufferVSprintf(buf, + "res=$(" + IPTABLES_CMD " -L %s -n --line-number | " + GREP_CMD " \" %s \")\n" + "if [ $? -ne 0 ]; then\n" + " " IPTABLES_CMD " -I %s %d -j %s\n" + "else\n" + " r=$(echo $res | " GAWK_CMD " '{print $1}')\n" + " if [ \"${r}\" != \"%d\" ]; then\n" + " " CMD_DEF(IPTABLES_CMD " -I %s %d -j %s") CMD_SEPARATOR + " " CMD_EXEC + " %s" + " let r=r+1\n" + " " CMD_DEF(IPTABLES_CMD " -D %s ${r}") CMD_SEPARATOR + " " CMD_EXEC + " %s" + " fi\n" + "fi\n", + + syschain, udchain, + + syschain, pos, udchain, + + pos, + + syschain, pos, udchain, + CMD_STOPONERR(stopOnError), + + syschain, + CMD_STOPONERR(stopOnError)); + return 0; +} + + +static int iptablesCreateBaseChains(virConnectPtr conn, + virBufferPtr buf) +{ + virBufferAddLit(buf, IPTABLES_CMD " -N " VIRT_IN_CHAIN CMD_SEPARATOR + IPTABLES_CMD " -N " VIRT_OUT_CHAIN CMD_SEPARATOR + IPTABLES_CMD " -N " VIRT_IN_POST_CHAIN CMD_SEPARATOR + IPTABLES_CMD " -N " HOST_IN_CHAIN CMD_SEPARATOR); + iptablesLinkIPTablesBaseChain(conn, buf, + VIRT_IN_CHAIN , "FORWARD", 1, 1); + iptablesLinkIPTablesBaseChain(conn, buf, + VIRT_OUT_CHAIN , "FORWARD", 2, 1); + iptablesLinkIPTablesBaseChain(conn, buf, + VIRT_IN_POST_CHAIN, "FORWARD", 3, 1); + iptablesLinkIPTablesBaseChain(conn, buf, + HOST_IN_CHAIN , "INPUT" , 1, 1); + + return 0; +} + + +static int +iptablesCreateTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + char prefix, + int incoming, const char *ifname, + int stopOnError) +{ + char chain[MAX_CHAINNAME_LENGTH]; + char chainPrefix[2] = { + prefix, + (incoming) ? CHAINPREFIX_HOST_IN_TEMP + : CHAINPREFIX_HOST_OUT_TEMP + }; + + PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname); + + virBufferVSprintf(buf, + CMD_DEF(IPTABLES_CMD " -N %s") CMD_SEPARATOR + CMD_EXEC + "%s", + chain, + CMD_STOPONERR(stopOnError)); + + return 0; +} + + +static int +iptablesCreateTmpRootChains(virConnectPtr conn, + virBufferPtr buf, + const char *ifname) +{ + iptablesCreateTmpRootChain(conn, buf, 'F', 0, ifname, 1); + iptablesCreateTmpRootChain(conn, buf, 'F', 1, ifname, 1); + iptablesCreateTmpRootChain(conn, buf, 'H', 1, ifname, 1); + return 0; +} + + +static int +_iptablesRemoveRootChain(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + char prefix, + int incoming, const char *ifname, + int isTempChain) +{ + char chain[MAX_CHAINNAME_LENGTH]; + char chainPrefix[2] = { + prefix, + }; + + if (isTempChain) + chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN_TEMP + : CHAINPREFIX_HOST_OUT_TEMP; + else + chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN + : CHAINPREFIX_HOST_OUT; + + PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname); + + virBufferVSprintf(buf, + IPTABLES_CMD " -F %s" CMD_SEPARATOR + IPTABLES_CMD " -X %s" CMD_SEPARATOR, + chain, + chain); + + return 0; +} + + +static int +iptablesRemoveRootChain(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + char prefix, + int incoming, + const char *ifname) +{ + return _iptablesRemoveRootChain(conn, buf, prefix, incoming, ifname, 0); +} + + +static int +iptablesRemoveTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + char prefix, + int incoming, + const char *ifname) +{ + return _iptablesRemoveRootChain(conn, buf, prefix, incoming, ifname, 1); +} + + +static int +iptablesRemoveTmpRootChains(virConnectPtr conn, + virBufferPtr buf, + const char *ifname) +{ + iptablesRemoveTmpRootChain(conn, buf, 'F', 0, ifname); + iptablesRemoveTmpRootChain(conn, buf, 'F', 1, ifname); + iptablesRemoveTmpRootChain(conn, buf, 'H', 1, ifname); + return 0; +} + + +static int +iptablesRemoveRootChains(virConnectPtr conn, + virBufferPtr buf, + const char *ifname) +{ + iptablesRemoveRootChain(conn, buf, 'F', 0, ifname); + iptablesRemoveRootChain(conn, buf, 'F', 1, ifname); + iptablesRemoveRootChain(conn, buf, 'H', 1, ifname); + return 0; +} + + +static int +iptablesLinkTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + const char *basechain, + char prefix, + int incoming, const char *ifname, + int stopOnError) +{ + char chain[MAX_CHAINNAME_LENGTH]; + char chainPrefix[2] = { + prefix, + (incoming) ? CHAINPREFIX_HOST_IN_TEMP + : CHAINPREFIX_HOST_OUT_TEMP + }; + const char *match = (incoming) ? MATCH_PHYSDEV_IN + : MATCH_PHYSDEV_OUT; + + PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname); + + virBufferVSprintf(buf, + CMD_DEF(IPTABLES_CMD " -A %s " + "%s %s -g %s") CMD_SEPARATOR + CMD_EXEC + "%s", + basechain, + match, ifname, chain, + + CMD_STOPONERR(stopOnError)); + + return 0; +} + + +static int +iptablesLinkTmpRootChains(virConnectPtr conn, + virBufferPtr buf, + const char *ifname) +{ + iptablesLinkTmpRootChain(conn, buf, VIRT_OUT_CHAIN, 'F', 0, ifname, 1); + iptablesLinkTmpRootChain(conn, buf, VIRT_IN_CHAIN , 'F', 1, ifname, 1); + iptablesLinkTmpRootChain(conn, buf, HOST_IN_CHAIN , 'H', 1, ifname, 1); + + return 0; +} + + +static int +iptablesSetupVirtInPost(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + const char *ifname) +{ + const char *match = MATCH_PHYSDEV_IN; + virBufferVSprintf(buf, + "res=$(" IPTABLES_CMD " -L " VIRT_IN_POST_CHAIN + " | grep \"\\%s %s\")\n" + "if [ \"${res}\" == \"\" ]; then " + CMD_DEF(IPTABLES_CMD + " -A " VIRT_IN_POST_CHAIN + " %s %s -j ACCEPT") CMD_SEPARATOR + CMD_EXEC + "%s" + "fi\n", + PHYSDEV_IN, ifname, + match, ifname, + CMD_STOPONERR(1)); + return 0; +} + + +static int +iptablesClearVirtInPost(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + const char *ifname) +{ + const char *match = MATCH_PHYSDEV_IN; + virBufferVSprintf(buf, + IPTABLES_CMD + " -D " VIRT_IN_POST_CHAIN + " %s %s -j ACCEPT" CMD_SEPARATOR, + match, ifname); + return 0; +} + +static int +_iptablesUnlinkRootChain(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + const char *basechain, + char prefix, + int incoming, const char *ifname, + int isTempChain) +{ + char chain[MAX_CHAINNAME_LENGTH]; + char chainPrefix[2] = { + prefix, + }; + if (isTempChain) + chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN_TEMP + : CHAINPREFIX_HOST_OUT_TEMP; + else + chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN + : CHAINPREFIX_HOST_OUT; + const char *match = (incoming) ? MATCH_PHYSDEV_IN + : MATCH_PHYSDEV_OUT; + + PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname); + + virBufferVSprintf(buf, + IPTABLES_CMD " -D %s " + "%s %s -g %s" CMD_SEPARATOR, + basechain, + match, ifname, chain); + + return 0; +} + + +static int +iptablesUnlinkRootChain(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + const char *basechain, + char prefix, + int incoming, const char *ifname) +{ + return _iptablesUnlinkRootChain(conn, buf, + basechain, prefix, incoming, ifname, 0); +} + + +static int +iptablesUnlinkTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + const char *basechain, + char prefix, + int incoming, const char *ifname) +{ + return _iptablesUnlinkRootChain(conn, buf, + basechain, prefix, incoming, ifname, 1); +} + + +static int +iptablesUnlinkRootChains(virConnectPtr conn, + virBufferPtr buf, + const char *ifname) +{ + iptablesUnlinkRootChain(conn, buf, VIRT_OUT_CHAIN, 'F', 0, ifname); + iptablesUnlinkRootChain(conn, buf, VIRT_IN_CHAIN , 'F', 1, ifname); + iptablesUnlinkRootChain(conn, buf, HOST_IN_CHAIN , 'H', 1, ifname); + + return 0; +} + + +static int +iptablesUnlinkTmpRootChains(virConnectPtr conn, + virBufferPtr buf, + const char *ifname) +{ + iptablesUnlinkTmpRootChain(conn, buf, VIRT_OUT_CHAIN, 'F', 0, ifname); + iptablesUnlinkTmpRootChain(conn, buf, VIRT_IN_CHAIN , 'F', 1, ifname); + iptablesUnlinkTmpRootChain(conn, buf, HOST_IN_CHAIN , 'H', 1, ifname); + return 0; +} + + +static int +iptablesRenameTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + char prefix, + int incoming, + const char *ifname) +{ + char tmpchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH]; + char tmpChainPrefix[2] = { + prefix, + (incoming) ? CHAINPREFIX_HOST_IN_TEMP + : CHAINPREFIX_HOST_OUT_TEMP + }; + char chainPrefix[2] = { + prefix, + (incoming) ? CHAINPREFIX_HOST_IN + : CHAINPREFIX_HOST_OUT + }; + + PRINT_IPT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname); + PRINT_IPT_ROOT_CHAIN( chain, chainPrefix, ifname); + + virBufferVSprintf(buf, + IPTABLES_CMD " -E %s %s" CMD_SEPARATOR, + tmpchain, + chain); + return 0; +} + + +static int +iptablesRenameTmpRootChains(virConnectPtr conn, + virBufferPtr buf, + const char *ifname) +{ + iptablesRenameTmpRootChain(conn, buf, 'F', 0, ifname); + iptablesRenameTmpRootChain(conn, buf, 'F', 1, ifname); + iptablesRenameTmpRootChain(conn, buf, 'H', 1, ifname); + return 0; +} + + +static void +iptablesInstCommand(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + const char *templ, char cmd, int pos, + int stopOnError) +{ + char position[10] = { 0 }; + if (pos >= 0) + snprintf(position, sizeof(position), "%d", pos); + virBufferVSprintf(buf, templ, cmd, position); + virBufferVSprintf(buf, CMD_SEPARATOR "%s", + CMD_STOPONERR(stopOnError)); +} + + +static int +iptablesHandleSrcMacAddr(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + virNWFilterHashTablePtr vars, + nwItemDescPtr srcMacAddr, + int directionIn ATTRIBUTE_UNUSED) +{ + char macaddr[VIR_MAC_STRING_BUFLEN]; + + if (HAS_ENTRY_ITEM(srcMacAddr)) { + if (printDataType(conn, + vars, + macaddr, sizeof(macaddr), + srcMacAddr)) + goto err_exit; + + virBufferVSprintf(buf, + " -m mac %s --mac-source %s", + ENTRY_GET_NEG_SIGN(srcMacAddr), + macaddr); + } + + return 0; + +err_exit: + virBufferFreeAndReset(buf); + + return 1; +} + + +static int +iptablesHandleIpHdr(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + virNWFilterHashTablePtr vars, + ipHdrDataDefPtr ipHdr, + int directionIn) +{ + char ipaddr[INET_ADDRSTRLEN], + number[20]; + const char *src = "--source"; + const char *dst = "--destination"; + const char *srcrange = "--src-range"; + const char *dstrange = "--dst-range"; + if (directionIn) { + src = "--destination"; + dst = "--source"; + srcrange = "--dst-range"; + dstrange = "--src-range"; + } + + if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPAddr)) { + + if (printDataType(conn, + vars, + ipaddr, sizeof(ipaddr), + &ipHdr->dataSrcIPAddr)) + goto err_exit; + + virBufferVSprintf(buf, + " %s %s %s", + ENTRY_GET_NEG_SIGN(&ipHdr->dataSrcIPAddr), + src, + ipaddr); + + if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPMask)) { + + if (printDataType(conn, + vars, + number, sizeof(number), + &ipHdr->dataSrcIPMask)) + goto err_exit; + + virBufferVSprintf(buf, + "/%s", + number); + } + } else if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPFrom)) { + + if (printDataType(conn, + vars, + ipaddr, sizeof(ipaddr), + &ipHdr->dataSrcIPFrom)) + goto err_exit; + + virBufferVSprintf(buf, + " -m iprange %s %s %s", + ENTRY_GET_NEG_SIGN(&ipHdr->dataSrcIPFrom), + srcrange, + ipaddr); + + if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPTo)) { + + if (printDataType(conn, + vars, + ipaddr, sizeof(ipaddr), + &ipHdr->dataSrcIPTo)) + goto err_exit; + + virBufferVSprintf(buf, + "-%s", + ipaddr); + } + } + + if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPAddr)) { + + if (printDataType(conn, + vars, + ipaddr, sizeof(ipaddr), + &ipHdr->dataDstIPAddr)) + goto err_exit; + + virBufferVSprintf(buf, + " %s %s %s", + ENTRY_GET_NEG_SIGN(&ipHdr->dataDstIPAddr), + dst, + ipaddr); + + if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPMask)) { + + if (printDataType(conn, + vars, + number, sizeof(number), + &ipHdr->dataDstIPMask)) + goto err_exit; + + virBufferVSprintf(buf, + "/%s", + number); + + } + } else if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPFrom)) { + + if (printDataType(conn, + vars, + ipaddr, sizeof(ipaddr), + &ipHdr->dataDstIPFrom)) + goto err_exit; + + virBufferVSprintf(buf, + " -m iprange %s %s %s", + ENTRY_GET_NEG_SIGN(&ipHdr->dataDstIPFrom), + dstrange, + ipaddr); + + if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPTo)) { + + if (printDataType(conn, + vars, + ipaddr, sizeof(ipaddr), + &ipHdr->dataDstIPTo)) + goto err_exit; - VIR_FREE(inst->commandTemplate); - VIR_FREE(inst); -} + virBufferVSprintf(buf, + "-%s", + ipaddr); + } + } + if (HAS_ENTRY_ITEM(&ipHdr->dataDSCP)) { -static int -ebiptablesAddRuleInst(virConnectPtr conn, - virNWFilterRuleInstPtr res, - char *commandTemplate, - enum virNWFilterChainSuffixType neededChain, - char chainprefix, - unsigned int priority) -{ - ebiptablesRuleInstPtr inst; + if (printDataType(conn, + vars, + number, sizeof(number), + &ipHdr->dataDSCP)) + goto err_exit; - if (VIR_ALLOC(inst) < 0) { - virReportOOMError(); - return 1; + virBufferVSprintf(buf, + " -m dscp %s --dscp %s", + ENTRY_GET_NEG_SIGN(&ipHdr->dataDSCP), + number); } - inst->commandTemplate = commandTemplate; - inst->neededProtocolChain = neededChain; - inst->chainprefix = chainprefix; - inst->priority = priority; + return 0; - return virNWFilterRuleInstAddData(conn, res, inst); +err_exit: + virBufferFreeAndReset(buf); + + return 1; } static int -ebtablesHandleEthHdr(virConnectPtr conn, - virBufferPtr buf, - virNWFilterHashTablePtr vars, - ethHdrDataDefPtr ethHdr) -{ - char macaddr[VIR_MAC_STRING_BUFLEN]; +iptablesHandlePortData(virConnectPtr conn ATTRIBUTE_UNUSED, + virBufferPtr buf, + virNWFilterHashTablePtr vars, + portDataDefPtr portData, + int directionIn) +{ + char portstr[20]; + const char *sport = "--sport"; + const char *dport = "--dport"; + if (directionIn) { + sport = "--dport"; + dport = "--sport"; + } - if (HAS_ENTRY_ITEM(ðHdr->dataSrcMACAddr)) { + if (HAS_ENTRY_ITEM(&portData->dataSrcPortStart)) { if (printDataType(conn, vars, - macaddr, sizeof(macaddr), - ðHdr->dataSrcMACAddr)) + portstr, sizeof(portstr), + &portData->dataSrcPortStart)) goto err_exit; virBufferVSprintf(buf, - " -s %s %s", - ENTRY_GET_NEG_SIGN(ðHdr->dataSrcMACAddr), - macaddr); + " %s %s %s", + ENTRY_GET_NEG_SIGN(&portData->dataSrcPortStart), + sport, + portstr); - if (HAS_ENTRY_ITEM(ðHdr->dataSrcMACMask)) { + if (HAS_ENTRY_ITEM(&portData->dataSrcPortEnd)) { if (printDataType(conn, vars, - macaddr, sizeof(macaddr), - ðHdr->dataSrcMACMask)) + portstr, sizeof(portstr), + &portData->dataSrcPortEnd)) goto err_exit; - virBufferVSprintf(buf, - "/%s", - macaddr); + virBufferVSprintf(buf, + ":%s", + portstr); } } - if (HAS_ENTRY_ITEM(ðHdr->dataDstMACAddr)) { + if (HAS_ENTRY_ITEM(&portData->dataDstPortStart)) { if (printDataType(conn, vars, - macaddr, sizeof(macaddr), - ðHdr->dataDstMACAddr)) + portstr, sizeof(portstr), + &portData->dataDstPortStart)) goto err_exit; virBufferVSprintf(buf, - " -d %s %s", - ENTRY_GET_NEG_SIGN(ðHdr->dataDstMACAddr), - macaddr); + " %s %s %s", + ENTRY_GET_NEG_SIGN(&portData->dataDstPortStart), + dport, + portstr); - if (HAS_ENTRY_ITEM(ðHdr->dataDstMACMask)) { + if (HAS_ENTRY_ITEM(&portData->dataDstPortEnd)) { if (printDataType(conn, vars, - macaddr, sizeof(macaddr), - ðHdr->dataDstMACMask)) + portstr, sizeof(portstr), + &portData->dataDstPortEnd)) goto err_exit; - virBufferVSprintf(buf, - "/%s", - macaddr); + virBufferVSprintf(buf, + ":%s", + portstr); } } return 0; - err_exit: - virBufferFreeAndReset(buf); - +err_exit: return 1; } /* + * _iptablesCreateRuleInstance: + * @conn : Pointer to a virConnect object + * @chainPrefix : The prefix to put in front of the name of the chain + * @nwfilter : The filter + * @rule: The rule of the filter to convert + * @ifname : The name of the interface to apply the rule to + * @vars : A map containing the variables to resolve + * @res : The data structure to store the result(s) into + * + * Convert a single rule into its representation for later instantiation + * + * Returns 0 in case of success with the result stored in the data structure + * pointed to by res, != 0 otherwise with the error message stored in the + * virConnect object. + */ +static int +_iptablesCreateRuleInstance(virConnectPtr conn, + int directionIn, + const char *chainPrefix, + virNWFilterDefPtr nwfilter, + virNWFilterRuleDefPtr rule, + const char *ifname, + virNWFilterHashTablePtr vars, + virNWFilterRuleInstPtr res, + const char *match, + const char *accept_target) +{ + char chain[MAX_CHAINNAME_LENGTH]; + char number[20]; + virBuffer buf = VIR_BUFFER_INITIALIZER; + const char *target; + + PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname); + + switch (rule->prtclType) { + case VIR_NWFILTER_RULE_PROTOCOL_TCP: + virBufferVSprintf(&buf, + CMD_DEF_PRE IPTABLES_CMD " -%%c %s %%s", + chain); + + virBufferAddLit(&buf, " -p tcp"); + + if (iptablesHandleSrcMacAddr(conn, + &buf, + vars, + &rule->p.tcpHdrFilter.dataSrcMACAddr, + directionIn)) + goto err_exit; + + if (iptablesHandleIpHdr(conn, + &buf, + vars, + &rule->p.tcpHdrFilter.ipHdr, + directionIn)) + goto err_exit; + + if (iptablesHandlePortData(conn, + &buf, + vars, + &rule->p.tcpHdrFilter.portData, + directionIn)) + goto err_exit; + + if (HAS_ENTRY_ITEM(&rule->p.tcpHdrFilter.dataTCPOption)) { + if (printDataType(conn, + vars, + number, sizeof(number), + &rule->p.tcpHdrFilter.dataTCPOption)) + goto err_exit; + + virBufferVSprintf(&buf, + " %s --tcp-option %s", + ENTRY_GET_NEG_SIGN(&rule->p.tcpHdrFilter.dataTCPOption), + number); + } + + break; + + case VIR_NWFILTER_RULE_PROTOCOL_UDP: + virBufferVSprintf(&buf, + CMD_DEF_PRE IPTABLES_CMD " -%%c %s %%s", + chain); + + virBufferAddLit(&buf, " -p udp"); + + if (iptablesHandleSrcMacAddr(conn, + &buf, + vars, + &rule->p.udpHdrFilter.dataSrcMACAddr, + directionIn)) + goto err_exit; + + if (iptablesHandleIpHdr(conn, + &buf, + vars, + &rule->p.udpHdrFilter.ipHdr, + directionIn)) + goto err_exit; + + if (iptablesHandlePortData(conn, + &buf, + vars, + &rule->p.udpHdrFilter.portData, + directionIn)) + goto err_exit; + break; + + case VIR_NWFILTER_RULE_PROTOCOL_SCTP: + virBufferVSprintf(&buf, + CMD_DEF_PRE IPTABLES_CMD " -%%c %s %%s", + chain); + + virBufferAddLit(&buf, " -p sctp"); + + if (iptablesHandleSrcMacAddr(conn, + &buf, + vars, + &rule->p.sctpHdrFilter.dataSrcMACAddr, + directionIn)) + goto err_exit; + + if (iptablesHandleIpHdr(conn, + &buf, + vars, + &rule->p.sctpHdrFilter.ipHdr, + directionIn)) + goto err_exit; + + if (iptablesHandlePortData(conn, + &buf, + vars, + &rule->p.sctpHdrFilter.portData, + directionIn)) + goto err_exit; + break; + + case VIR_NWFILTER_RULE_PROTOCOL_ICMP: + virBufferVSprintf(&buf, + CMD_DEF_PRE IPTABLES_CMD " -%%c %s %%s", + chain); + + virBufferAddLit(&buf, " -p icmp"); + + if (iptablesHandleSrcMacAddr(conn, + &buf, + vars, + &rule->p.icmpHdrFilter.dataSrcMACAddr, + directionIn)) + goto err_exit; + + if (iptablesHandleIpHdr(conn, + &buf, + vars, + &rule->p.icmpHdrFilter.ipHdr, + directionIn)) + goto err_exit; + + if (HAS_ENTRY_ITEM(&rule->p.icmpHdrFilter.dataICMPType)) { + if (printDataType(conn, + vars, + number, sizeof(number), + &rule->p.icmpHdrFilter.dataICMPType)) + goto err_exit; + + virBufferVSprintf(&buf, + " %s --icmp-type %s", + ENTRY_GET_NEG_SIGN(&rule->p.icmpHdrFilter.dataICMPType), + number); + + if (HAS_ENTRY_ITEM(&rule->p.icmpHdrFilter.dataICMPCode)) { + if (printDataType(conn, + vars, + number, sizeof(number), + &rule->p.icmpHdrFilter.dataICMPCode)) + goto err_exit; + + virBufferVSprintf(&buf, + "/%s", + number); + } + } + break; + + case VIR_NWFILTER_RULE_PROTOCOL_ALL: + virBufferVSprintf(&buf, + CMD_DEF_PRE IPTABLES_CMD " -%%c %s %%s", + chain); + + virBufferAddLit(&buf, " -p all"); + + if (iptablesHandleSrcMacAddr(conn, + &buf, + vars, + &rule->p.allHdrFilter.dataSrcMACAddr, + directionIn)) + goto err_exit; + + if (iptablesHandleIpHdr(conn, + &buf, + vars, + &rule->p.allHdrFilter.ipHdr, + directionIn)) + goto err_exit; + + break; + + default: + return -1; + } + + if (match) + virBufferVSprintf(&buf, " %s", match); + + if (rule->action == VIR_NWFILTER_RULE_ACTION_ACCEPT) + target = accept_target; + else + target = "DROP"; + + virBufferVSprintf(&buf, + " -j %s" CMD_DEF_POST CMD_SEPARATOR + CMD_EXEC, + target); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + + return ebiptablesAddRuleInst(conn, + res, + virBufferContentAndReset(&buf), + nwfilter->chainsuffix, + '\0', + rule->priority, + 1); + + +err_exit: + virBufferFreeAndReset(&buf); + + return -1; + +} + + +static int +iptablesCreateRuleInstance(virConnectPtr conn, + virNWFilterDefPtr nwfilter, + virNWFilterRuleDefPtr rule, + const char *ifname, + virNWFilterHashTablePtr vars, + virNWFilterRuleInstPtr res) +{ + int rc; + int directionIn = 0; + char chainPrefix[2]; + int needState = 1; + + if ((rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN) || + (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT)) { + directionIn = 1; + needState = 0; + } + + chainPrefix[0] = 'F'; + + chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP; + rc = _iptablesCreateRuleInstance(conn, + directionIn, + chainPrefix, + nwfilter, + rule, + ifname, + vars, + res, + needState ? MATCH_STATE_OUT + : NULL, + "RETURN"); + if (rc) + return rc; + + chainPrefix[1] = CHAINPREFIX_HOST_OUT_TEMP; + rc = _iptablesCreateRuleInstance(conn, + !directionIn, + chainPrefix, + nwfilter, + rule, + ifname, + vars, + res, + needState ? MATCH_STATE_IN + : NULL, + "ACCEPT"); + if (rc) + return rc; + + chainPrefix[0] = 'H'; + chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP; + rc = _iptablesCreateRuleInstance(conn, + directionIn, + chainPrefix, + nwfilter, + rule, + ifname, + vars, + res, + NULL, + "ACCEPT"); + if (rc) + return rc; + + return rc; +} + + + + +/* * ebtablesCreateRuleInstance: * @conn : Pointer to a virConnect object * @chainPrefix : The prefix to put in front of the name of the chain @@ -741,6 +1745,9 @@ ebtablesCreateRuleInstance(virConnectPtr CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s", EBTABLES_DEFAULT_TABLE, chain); break; + + default: + return -1; } virBufferVSprintf(&buf, @@ -759,7 +1766,8 @@ ebtablesCreateRuleInstance(virConnectPtr virBufferContentAndReset(&buf), nwfilter->chainsuffix, chainPrefix, - rule->priority); + rule->priority, + RT_EBTABLES); err_exit: virBufferFreeAndReset(&buf); @@ -785,7 +1793,7 @@ err_exit: */ static int ebiptablesCreateRuleInstance(virConnectPtr conn, - enum virDomainNetType nettype ATTRIBUTE_UNUSED, + enum virDomainNetType nettype, virNWFilterDefPtr nwfilter, virNWFilterRuleDefPtr rule, const char *ifname, @@ -825,6 +1833,33 @@ ebiptablesCreateRuleInstance(virConnectP res); } break; + + case VIR_NWFILTER_RULE_PROTOCOL_TCP: + case VIR_NWFILTER_RULE_PROTOCOL_UDP: + case VIR_NWFILTER_RULE_PROTOCOL_SCTP: + case VIR_NWFILTER_RULE_PROTOCOL_ICMP: + case VIR_NWFILTER_RULE_PROTOCOL_IGMP: + case VIR_NWFILTER_RULE_PROTOCOL_ALL: + if (nettype == VIR_DOMAIN_NET_TYPE_DIRECT) { + virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER, + _("'%s' protocol not support for net type '%s'"), + virNWFilterRuleProtocolTypeToString(rule->prtclType), + virDomainNetTypeToString(nettype)); + return 1; + } + rc = iptablesCreateRuleInstance(conn, + nwfilter, + rule, + ifname, + vars, + res); + break; + + case VIR_NWFILTER_RULE_PROTOCOL_LAST: + virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER, + "%s", _("illegal protocol type")); + rc = 1; + break; } return rc; @@ -1352,16 +2387,19 @@ ebiptablesApplyNewRules(virConnectPtr co ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst; int chains_in = 0, chains_out = 0; virBuffer buf = VIR_BUFFER_INITIALIZER; + int haveIptables = 0; if (inst) qsort(inst, nruleInstances, sizeof(inst[0]), ebiptablesRuleOrderSort); for (i = 0; i < nruleInstances; i++) { - if (inst[i]->chainprefix == CHAINPREFIX_HOST_IN_TEMP) - chains_in |= (1 << inst[i]->neededProtocolChain); - else - chains_out |= (1 << inst[i]->neededProtocolChain); + if (inst[i]->ruleType == RT_EBTABLES) { + if (inst[i]->chainprefix == CHAINPREFIX_HOST_IN_TEMP) + chains_in |= (1 << inst[i]->neededProtocolChain); + else + chains_out |= (1 << inst[i]->neededProtocolChain); + } } ebtablesUnlinkTmpRootChain(conn, &buf, 1, ifname); @@ -1369,6 +2407,7 @@ ebiptablesApplyNewRules(virConnectPtr co ebtablesRemoveTmpSubChains(conn, &buf, ifname); ebtablesRemoveTmpRootChain(conn, &buf, 1, ifname); ebtablesRemoveTmpRootChain(conn, &buf, 0, ifname); + ebiptablesExecCLI(conn, &buf, &cli_status); if (chains_in != 0) ebtablesCreateTmpRootChain(conn, &buf, 1, ifname, 1); @@ -1395,15 +2434,53 @@ ebiptablesApplyNewRules(virConnectPtr co goto tear_down_tmpebchains; for (i = 0; i < nruleInstances; i++) - ebiptablesInstCommand(conn, &buf, - inst[i]->commandTemplate, - 'A', -1, 1); + switch (inst[i]->ruleType) { + case RT_EBTABLES: + ebiptablesInstCommand(conn, &buf, + inst[i]->commandTemplate, + 'A', -1, 1); + break; + case RT_IPTABLES: + haveIptables = 1; + break; + } if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0) goto tear_down_tmpebchains; // FIXME: establishment of iptables user define table tree goes here + if (haveIptables) { + iptablesUnlinkTmpRootChains(conn, &buf, ifname); + iptablesRemoveTmpRootChains(conn, &buf, ifname); + + iptablesCreateBaseChains(conn, &buf); + + if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0) + goto tear_down_tmpebchains; + + iptablesCreateTmpRootChains(conn, &buf, ifname); + + if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0) + goto tear_down_tmpiptchains; + + iptablesLinkTmpRootChains(conn, &buf, ifname); + iptablesSetupVirtInPost(conn, &buf, ifname); + if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0) + goto tear_down_tmpiptchains; + + for (i = 0; i < nruleInstances; i++) { + if (inst[i]->ruleType == RT_IPTABLES) + iptablesInstCommand(conn, &buf, + inst[i]->commandTemplate, + 'A', -1, 1); + } + + if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0) + goto tear_down_tmpiptchains; + } + + // END IPTABLES stuff if (chains_in != 0) @@ -1420,6 +2497,12 @@ tear_down_ebsubchains_and_unlink: ebtablesUnlinkTmpRootChain(conn, &buf, 1, ifname); ebtablesUnlinkTmpRootChain(conn, &buf, 0, ifname); +tear_down_tmpiptchains: + if (haveIptables) { + iptablesUnlinkTmpRootChains(conn, &buf, ifname); + iptablesRemoveTmpRootChains(conn, &buf, ifname); + } + tear_down_tmpebchains: ebtablesRemoveTmpSubChains(conn, &buf, ifname); ebtablesRemoveTmpRootChain(conn, &buf, 1, ifname); @@ -1442,6 +2525,9 @@ ebiptablesTearNewRules(virConnectPtr con int cli_status; virBuffer buf = VIR_BUFFER_INITIALIZER; + iptablesUnlinkTmpRootChains(conn, &buf, ifname); + iptablesRemoveTmpRootChains(conn, &buf, ifname); + ebtablesUnlinkTmpRootChain(conn, &buf, 1, ifname); ebtablesUnlinkTmpRootChain(conn, &buf, 0, ifname); @@ -1462,6 +2548,13 @@ ebiptablesTearOldRules(virConnectPtr con int cli_status; virBuffer buf = VIR_BUFFER_INITIALIZER; + // switch to new iptables user defined chains + iptablesUnlinkRootChains(conn, &buf, ifname); + iptablesRemoveRootChains(conn, &buf, ifname); + + iptablesRenameTmpRootChains(conn, &buf, ifname); + ebiptablesExecCLI(conn, &buf, &cli_status); + ebtablesUnlinkRootChain(conn, &buf, 1, ifname); ebtablesUnlinkRootChain(conn, &buf, 0, ifname); @@ -1541,6 +2634,10 @@ ebiptablesAllTeardown(const char *ifname int cli_status; virConnectPtr conn = NULL; + iptablesUnlinkRootChains(conn, &buf, ifname); + iptablesClearVirtInPost(conn, &buf, ifname); + iptablesRemoveRootChains(conn, &buf, ifname); + ebtablesUnlinkRootChain(conn, &buf, 1, ifname); ebtablesUnlinkRootChain(conn, &buf, 0, ifname); Index: libvirt-acl/src/conf/nwfilter_conf.h =================================================================== --- libvirt-acl.orig/src/conf/nwfilter_conf.h +++ libvirt-acl/src/conf/nwfilter_conf.h @@ -150,6 +150,10 @@ struct _ipHdrDataDef { nwItemDesc dataDstIPAddr; nwItemDesc dataDstIPMask; nwItemDesc dataProtocolID; + nwItemDesc dataSrcIPFrom; + nwItemDesc dataSrcIPTo; + nwItemDesc dataDstIPFrom; + nwItemDesc dataDstIPTo; nwItemDesc dataDSCP; }; @@ -182,6 +186,61 @@ struct _ipv6HdrFilterDef { }; +typedef struct _icmpHdrFilterDef icmpHdrFilterDef; +typedef icmpHdrFilterDef *icmpHdrFilterDefPtr; +struct _icmpHdrFilterDef { + nwItemDesc dataSrcMACAddr; + ipHdrDataDef ipHdr; + nwItemDesc dataICMPType; + nwItemDesc dataICMPCode; + nwItemDesc dataStateFlags; +}; + + +typedef struct _allHdrFilterDef allHdrFilterDef; +typedef allHdrFilterDef *allHdrFilterDefPtr; +struct _allHdrFilterDef { + nwItemDesc dataSrcMACAddr; + ipHdrDataDef ipHdr; +}; + + +typedef struct _igmpHdrFilterDef igmpHdrFilterDef; +typedef igmpHdrFilterDef *igmpHdrFilterDefPtr; +struct _igmpHdrFilterDef { + nwItemDesc dataSrcMACAddr; + ipHdrDataDef ipHdr; +}; + + +typedef struct _tcpHdrFilterDef tcpHdrFilterDef; +typedef tcpHdrFilterDef *tcpHdrFilterDefPtr; +struct _tcpHdrFilterDef { + nwItemDesc dataSrcMACAddr; + ipHdrDataDef ipHdr; + portDataDef portData; + nwItemDesc dataTCPOption; +}; + + +typedef struct _udpHdrFilterDef udpHdrFilterDef; +typedef udpHdrFilterDef *udpHdrFilterDefPtr; +struct _udpHdrFilterDef { + nwItemDesc dataSrcMACAddr; + ipHdrDataDef ipHdr; + portDataDef portData; +}; + + +typedef struct _sctpHdrFilterDef sctpHdrFilterDef; +typedef sctpHdrFilterDef *sctpHdrFilterDefPtr; +struct _sctpHdrFilterDef { + nwItemDesc dataSrcMACAddr; + ipHdrDataDef ipHdr; + portDataDef portData; +}; + + enum virNWFilterRuleActionType { VIR_NWFILTER_RULE_ACTION_DROP = 0, VIR_NWFILTER_RULE_ACTION_ACCEPT, @@ -210,6 +269,14 @@ enum virNWFilterRuleProtocolType { VIR_NWFILTER_RULE_PROTOCOL_ARP, VIR_NWFILTER_RULE_PROTOCOL_IP, VIR_NWFILTER_RULE_PROTOCOL_IPV6, + VIR_NWFILTER_RULE_PROTOCOL_TCP, + VIR_NWFILTER_RULE_PROTOCOL_ICMP, + VIR_NWFILTER_RULE_PROTOCOL_IGMP, + VIR_NWFILTER_RULE_PROTOCOL_UDP, + VIR_NWFILTER_RULE_PROTOCOL_SCTP, + VIR_NWFILTER_RULE_PROTOCOL_ALL, + + VIR_NWFILTER_RULE_PROTOCOL_LAST }; enum virNWFilterEbtablesTableType { @@ -236,6 +303,12 @@ struct _virNWFilterRuleDef { arpHdrFilterDef arpHdrFilter; ipHdrFilterDef ipHdrFilter; ipv6HdrFilterDef ipv6HdrFilter; + tcpHdrFilterDef tcpHdrFilter; + icmpHdrFilterDef icmpHdrFilter; + udpHdrFilterDef udpHdrFilter; + allHdrFilterDef allHdrFilter; + igmpHdrFilterDef igmpHdrFilter; + sctpHdrFilterDef sctpHdrFilter; } p; int nvars; Index: libvirt-acl/src/conf/nwfilter_conf.c =================================================================== --- libvirt-acl.orig/src/conf/nwfilter_conf.c +++ libvirt-acl/src/conf/nwfilter_conf.c @@ -76,6 +76,19 @@ VIR_ENUM_IMPL(virNWFilterChainSuffix, VI "ipv4", "ipv6"); +VIR_ENUM_IMPL(virNWFilterRuleProtocol, VIR_NWFILTER_RULE_PROTOCOL_LAST, + "none", + "mac", + "arp", + "ip", + "ipv6", + "tcp", + "icmp", + "igmp", + "udp", + "sctp", + "all"); + /* * a map entry for a simple static int-to-string map @@ -117,6 +130,10 @@ static const char srcipaddr_str[] = " static const char srcipmask_str[] = "srcipmask"; static const char dstipaddr_str[] = "dstipaddr"; static const char dstipmask_str[] = "dstipmask"; +static const char srcipfrom_str[] = "srcipfrom"; +static const char srcipto_str[] = "srcipto"; +static const char dstipfrom_str[] = "dstipfrom"; +static const char dstipto_str[] = "dstipto"; static const char srcportstart_str[] = "srcportstart"; static const char srcportend_str[] = "srcportend"; static const char dstportstart_str[] = "dstportstart"; @@ -135,6 +152,10 @@ static const char dscp_str[] = " #define SRCIPMASK srcipmask_str #define DSTIPADDR dstipaddr_str #define DSTIPMASK dstipmask_str +#define SRCIPFROM srcipfrom_str +#define SRCIPTO srcipto_str +#define DSTIPFROM dstipfrom_str +#define DSTIPTO dstipto_str #define SRCPORTSTART srcportstart_str #define SRCPORTEND srcportend_str #define DSTPORTSTART dstportstart_str @@ -831,6 +852,149 @@ static const virXMLAttr2Struct ipv6Attri }; +#define COMMON_L3_MAC_PROPS(STRUCT) \ + {\ + .name = SRCMACADDR,\ + .datatype = DATATYPE_MACADDR,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.dataSrcMACAddr),\ + } + +#define COMMON_IP_PROPS(STRUCT) \ + COMMON_L3_MAC_PROPS(STRUCT),\ + {\ + .name = SRCIPADDR,\ + .datatype = DATATYPE_IPADDR,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataSrcIPAddr),\ + },\ + {\ + .name = DSTIPADDR,\ + .datatype = DATATYPE_IPADDR,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDstIPAddr),\ + },\ + {\ + .name = SRCIPMASK,\ + .datatype = DATATYPE_IPMASK,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataSrcIPMask),\ + },\ + {\ + .name = DSTIPMASK,\ + .datatype = DATATYPE_IPMASK,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDstIPMask),\ + },\ + {\ + .name = SRCIPFROM,\ + .datatype = DATATYPE_IPADDR,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataSrcIPFrom),\ + },\ + {\ + .name = SRCIPTO,\ + .datatype = DATATYPE_IPADDR,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataSrcIPTo),\ + },\ + {\ + .name = DSTIPFROM,\ + .datatype = DATATYPE_IPADDR,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDstIPFrom),\ + },\ + {\ + .name = DSTIPTO,\ + .datatype = DATATYPE_IPADDR,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDstIPTo),\ + },\ + {\ + .name = DSCP,\ + .datatype = DATATYPE_UINT8,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDSCP),\ + .validator = dscpValidator,\ + } + +#define COMMON_PORT_PROPS(STRUCT) \ + {\ + .name = SRCPORTSTART,\ + .datatype = DATATYPE_UINT16,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataSrcPortStart),\ + },\ + {\ + .name = SRCPORTEND,\ + .datatype = DATATYPE_UINT16,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataSrcPortEnd),\ + },\ + {\ + .name = DSTPORTSTART,\ + .datatype = DATATYPE_UINT16,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataDstPortStart),\ + },\ + {\ + .name = DSTPORTEND,\ + .datatype = DATATYPE_UINT16,\ + .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataDstPortEnd),\ + } + +static const virXMLAttr2Struct tcpAttributes[] = { + COMMON_IP_PROPS(tcpHdrFilter), + COMMON_PORT_PROPS(tcpHdrFilter), + { + .name = "option", + .datatype = DATATYPE_UINT8, + .dataIdx = offsetof(virNWFilterRuleDef, p.tcpHdrFilter.dataTCPOption), + }, + { + .name = NULL, + } +}; + +static const virXMLAttr2Struct udpAttributes[] = { + COMMON_IP_PROPS(udpHdrFilter), + COMMON_PORT_PROPS(udpHdrFilter), + { + .name = NULL, + } +}; + + +static const virXMLAttr2Struct sctpAttributes[] = { + COMMON_IP_PROPS(sctpHdrFilter), + COMMON_PORT_PROPS(sctpHdrFilter), + { + .name = NULL, + } +}; + + +static const virXMLAttr2Struct icmpAttributes[] = { + COMMON_IP_PROPS(icmpHdrFilter), + { + .name = "type", + .datatype = DATATYPE_UINT8, + .dataIdx = offsetof(virNWFilterRuleDef, p.icmpHdrFilter.dataICMPType), + }, + { + .name = "code", + .datatype = DATATYPE_UINT8, + .dataIdx = offsetof(virNWFilterRuleDef, p.icmpHdrFilter.dataICMPCode), + }, + { + .name = NULL, + } +}; + + +static const virXMLAttr2Struct allAttributes[] = { + COMMON_IP_PROPS(allHdrFilter), + { + .name = NULL, + } +}; + + +static const virXMLAttr2Struct igmpAttributes[] = { + COMMON_IP_PROPS(igmpHdrFilter), + { + .name = NULL, + } +}; + + typedef struct _virAttributes virAttributes; struct _virAttributes { const char *id; @@ -857,6 +1021,30 @@ static const virAttributes virAttr[] = { .att = ipv6Attributes, .prtclType = VIR_NWFILTER_RULE_PROTOCOL_IPV6, }, { + .id = "tcp", + .att = tcpAttributes, + .prtclType = VIR_NWFILTER_RULE_PROTOCOL_TCP, + }, { + .id = "udp", + .att = udpAttributes, + .prtclType = VIR_NWFILTER_RULE_PROTOCOL_UDP, + }, { + .id = "sctp", + .att = sctpAttributes, + .prtclType = VIR_NWFILTER_RULE_PROTOCOL_SCTP, + }, { + .id = "icmp", + .att = icmpAttributes, + .prtclType = VIR_NWFILTER_RULE_PROTOCOL_ICMP, + }, { + .id = "all", // = 'any' + .att = allAttributes, + .prtclType = VIR_NWFILTER_RULE_PROTOCOL_ALL, + }, { + .id = "igmp", + .att = igmpAttributes, + .prtclType = VIR_NWFILTER_RULE_PROTOCOL_IGMP, + }, { .id = NULL, } }; @@ -1274,8 +1462,96 @@ virNWFilterRuleDefFixup(virNWFilterRuleD case VIR_NWFILTER_RULE_PROTOCOL_ARP: case VIR_NWFILTER_RULE_PROTOCOL_NONE: break; - } + case VIR_NWFILTER_RULE_PROTOCOL_TCP: + COPY_NEG_SIGN(rule->p.tcpHdrFilter.ipHdr.dataSrcIPMask, + rule->p.tcpHdrFilter.ipHdr.dataSrcIPAddr); + COPY_NEG_SIGN(rule->p.tcpHdrFilter.ipHdr.dataDstIPMask, + rule->p.tcpHdrFilter.ipHdr.dataDstIPAddr); + COPY_NEG_SIGN(rule->p.tcpHdrFilter.ipHdr.dataSrcIPTo, + rule->p.tcpHdrFilter.ipHdr.dataSrcIPFrom); + COPY_NEG_SIGN(rule->p.tcpHdrFilter.ipHdr.dataDstIPTo, + rule->p.tcpHdrFilter.ipHdr.dataDstIPFrom); + COPY_NEG_SIGN(rule->p.tcpHdrFilter.portData.dataSrcPortEnd, + rule->p.tcpHdrFilter.portData.dataSrcPortStart); + COPY_NEG_SIGN(rule->p.tcpHdrFilter.portData.dataDstPortStart, + rule->p.tcpHdrFilter.portData.dataSrcPortStart); + COPY_NEG_SIGN(rule->p.tcpHdrFilter.portData.dataDstPortEnd, + rule->p.tcpHdrFilter.portData.dataSrcPortStart); + break; + + case VIR_NWFILTER_RULE_PROTOCOL_UDP: + COPY_NEG_SIGN(rule->p.udpHdrFilter.ipHdr.dataSrcIPMask, + rule->p.udpHdrFilter.ipHdr.dataSrcIPAddr); + COPY_NEG_SIGN(rule->p.udpHdrFilter.ipHdr.dataDstIPMask, + rule->p.udpHdrFilter.ipHdr.dataDstIPAddr); + COPY_NEG_SIGN(rule->p.udpHdrFilter.ipHdr.dataSrcIPTo, + rule->p.udpHdrFilter.ipHdr.dataSrcIPFrom); + COPY_NEG_SIGN(rule->p.udpHdrFilter.ipHdr.dataDstIPTo, + rule->p.udpHdrFilter.ipHdr.dataDstIPFrom); + COPY_NEG_SIGN(rule->p.udpHdrFilter.portData.dataSrcPortEnd, + rule->p.udpHdrFilter.portData.dataSrcPortStart); + COPY_NEG_SIGN(rule->p.udpHdrFilter.portData.dataDstPortStart, + rule->p.udpHdrFilter.portData.dataSrcPortStart); + COPY_NEG_SIGN(rule->p.udpHdrFilter.portData.dataDstPortEnd, + rule->p.udpHdrFilter.portData.dataSrcPortStart); + break; + + case VIR_NWFILTER_RULE_PROTOCOL_SCTP: + COPY_NEG_SIGN(rule->p.sctpHdrFilter.ipHdr.dataSrcIPMask, + rule->p.sctpHdrFilter.ipHdr.dataSrcIPAddr); + COPY_NEG_SIGN(rule->p.sctpHdrFilter.ipHdr.dataDstIPMask, + rule->p.sctpHdrFilter.ipHdr.dataDstIPAddr); + COPY_NEG_SIGN(rule->p.sctpHdrFilter.ipHdr.dataSrcIPTo, + rule->p.sctpHdrFilter.ipHdr.dataSrcIPFrom); + COPY_NEG_SIGN(rule->p.sctpHdrFilter.ipHdr.dataDstIPTo, + rule->p.sctpHdrFilter.ipHdr.dataDstIPFrom); + COPY_NEG_SIGN(rule->p.sctpHdrFilter.portData.dataSrcPortEnd, + rule->p.sctpHdrFilter.portData.dataSrcPortStart); + COPY_NEG_SIGN(rule->p.sctpHdrFilter.portData.dataDstPortStart, + rule->p.sctpHdrFilter.portData.dataSrcPortStart); + COPY_NEG_SIGN(rule->p.sctpHdrFilter.portData.dataDstPortEnd, + rule->p.sctpHdrFilter.portData.dataSrcPortStart); + break; + + case VIR_NWFILTER_RULE_PROTOCOL_ICMP: + COPY_NEG_SIGN(rule->p.icmpHdrFilter.ipHdr.dataSrcIPMask, + rule->p.icmpHdrFilter.ipHdr.dataSrcIPAddr); + COPY_NEG_SIGN(rule->p.icmpHdrFilter.ipHdr.dataDstIPMask, + rule->p.icmpHdrFilter.ipHdr.dataDstIPAddr); + COPY_NEG_SIGN(rule->p.icmpHdrFilter.ipHdr.dataSrcIPTo, + rule->p.icmpHdrFilter.ipHdr.dataSrcIPFrom); + COPY_NEG_SIGN(rule->p.icmpHdrFilter.ipHdr.dataDstIPTo, + rule->p.icmpHdrFilter.ipHdr.dataDstIPFrom); + COPY_NEG_SIGN(rule->p.icmpHdrFilter.dataICMPCode, + rule->p.icmpHdrFilter.dataICMPType); + break; + + case VIR_NWFILTER_RULE_PROTOCOL_ALL: + COPY_NEG_SIGN(rule->p.allHdrFilter.ipHdr.dataSrcIPMask, + rule->p.allHdrFilter.ipHdr.dataSrcIPAddr); + COPY_NEG_SIGN(rule->p.allHdrFilter.ipHdr.dataDstIPMask, + rule->p.allHdrFilter.ipHdr.dataDstIPAddr); + COPY_NEG_SIGN(rule->p.allHdrFilter.ipHdr.dataSrcIPTo, + rule->p.allHdrFilter.ipHdr.dataSrcIPFrom); + COPY_NEG_SIGN(rule->p.allHdrFilter.ipHdr.dataDstIPTo, + rule->p.allHdrFilter.ipHdr.dataDstIPFrom); + break; + + case VIR_NWFILTER_RULE_PROTOCOL_IGMP: + COPY_NEG_SIGN(rule->p.igmpHdrFilter.ipHdr.dataSrcIPMask, + rule->p.igmpHdrFilter.ipHdr.dataSrcIPAddr); + COPY_NEG_SIGN(rule->p.igmpHdrFilter.ipHdr.dataDstIPMask, + rule->p.igmpHdrFilter.ipHdr.dataDstIPAddr); + COPY_NEG_SIGN(rule->p.igmpHdrFilter.ipHdr.dataSrcIPTo, + rule->p.igmpHdrFilter.ipHdr.dataSrcIPFrom); + COPY_NEG_SIGN(rule->p.igmpHdrFilter.ipHdr.dataDstIPTo, + rule->p.igmpHdrFilter.ipHdr.dataDstIPFrom); + break; + + case VIR_NWFILTER_RULE_PROTOCOL_LAST: + break; + } #undef COPY_NEG_SIGN } Index: libvirt-acl/src/libvirt_private.syms =================================================================== --- libvirt-acl.orig/src/libvirt_private.syms +++ libvirt-acl/src/libvirt_private.syms @@ -448,6 +448,7 @@ virNWFilterPoolObjListFree; virNWFilterDefFormat; virNWFilterChainSuffixTypeToString; virNWFilterRuleActionTypeToString; +virNWFilterRuleProtocolTypeToString; virNWFilterJumpTargetTypeToString; virNWFilterRegisterCallbackDriver; virNWFilterTestUnassignDef; Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.h =================================================================== --- libvirt-acl.orig/src/nwfilter/nwfilter_ebiptables_driver.h +++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.h @@ -25,6 +25,12 @@ #define MAX_CHAINNAME_LENGTH 32 /* see linux/netfilter_bridge/ebtables.h */ +enum RuleType { + RT_EBTABLES, + RT_IPTABLES, +/* RT_IP6TABLES, for future use */ +}; + typedef struct _ebiptablesRuleInst ebiptablesRuleInst; typedef ebiptablesRuleInst *ebiptablesRuleInstPtr; struct _ebiptablesRuleInst { @@ -32,6 +38,7 @@ struct _ebiptablesRuleInst { enum virNWFilterChainSuffixType neededProtocolChain; char chainprefix; // I for incoming, O for outgoing unsigned int priority; + enum RuleType ruleType; }; extern virNWFilterTechDriver ebiptables_driver; Index: libvirt-acl/configure.ac =================================================================== --- libvirt-acl.orig/configure.ac +++ libvirt-acl/configure.ac @@ -303,6 +303,13 @@ AC_DEFINE_UNQUOTED([IPTABLES_PATH], "$IP AC_PATH_PROG([EBTABLES_PATH], [ebtables], /sbin/ebtables, [/usr/sbin:$PATH]) AC_DEFINE_UNQUOTED([EBTABLES_PATH], "$EBTABLES_PATH", [path to ebtables binary]) +AC_PATH_PROG([GREP_PATH], [grep], /bin/grep, [/bin:$PATH]) +AC_DEFINE_UNQUOTED([GREP_PATH], "$GREP_PATH", [path to grep binary]) + +AC_PATH_PROG([GAWK_PATH], [gawk], /bin/gawk, [/bin:$PATH]) +AC_DEFINE_UNQUOTED([GAWK_PATH], "$GAWK_PATH", [path to gawk binary]) + + if test "$with_openvz" = "yes"; then AC_DEFINE_UNQUOTED([WITH_OPENVZ], 1, [whether OpenVZ driver is enabled]) fi