This patch enables chains that have a known prefix in their name. Known prefixes are: 'ipv4', 'ipv6', 'arp', 'rarp'. All prefixes are also protocols that can be evaluated on the ebtables level. Following the prefix they will be automatically connected to an interface's 'root' chain and jumped into following the protocol they evalute, i.e., a table 'arp-xyz' will be accessed from the root table using ebtables -t nat -A -p arp -j I--arp-xyz thus generating a 'root' chain like this one here: Bridge chain: libvirt-O-vnet0, entries: 5, policy: ACCEPT -p IPv4 -j O-vnet0-ipv4 -p ARP -j O-vnet0-arp -p 0x8035 -j O-vnet0-rarp -p ARP -j O-vnet0-arp-xyz -j DROP where the chain 'arp-xyz' is accessed for filtering of ARP packets. v3: - assign a priority to filters that have an allowed prefix, e.g., assign the arp chain priority to a filter arp-xyz unless user provided a priority in the XML Signed-off-by: Stefan Berger --- docs/schemas/nwfilter.rng | 16 ++++++-- src/conf/nwfilter_conf.c | 87 ++++++++++++++++++++++++++++++++++++++++++---- src/conf/nwfilter_conf.h | 3 + 3 files changed, 96 insertions(+), 10 deletions(-) Index: libvirt-acl/src/conf/nwfilter_conf.c =================================================================== --- libvirt-acl.orig/src/conf/nwfilter_conf.c +++ libvirt-acl/src/conf/nwfilter_conf.c @@ -2007,6 +2007,80 @@ err_exit: goto cleanup; } +static bool +virNWFilterIsValidChainName(const char *chainname) +{ + return chainname[strspn(chainname, VALID_CHAINNAME)] == 0; +} + +/* + * Test whether the name of the chain is supported. + * It current has to have a prefix of either one of the strings found in + * virNWFilterChainSuffixTypeToString(). + */ +static const char * +virNWFilterIsAllowedChain(const char *chainname) +{ + enum virNWFilterChainSuffixType i; + const char *name, *msg; + virBuffer buf = VIR_BUFFER_INITIALIZER; + bool printed = false; + + if (!virNWFilterIsValidChainName(chainname)) { + virNWFilterReportError(VIR_ERR_INVALID_ARG, + _("Chain name contains illegal characters")); + return NULL; + } + + if (strlen(chainname) > MAX_CHAIN_SUFFIX_SIZE) { + virNWFilterReportError(VIR_ERR_INVALID_ARG, + _("Name of chain is longer than %u characters"), + MAX_CHAIN_SUFFIX_SIZE); + return NULL; + } + + for (i = 0; i < VIR_NWFILTER_CHAINSUFFIX_LAST; i++) { + name = virNWFilterChainSuffixTypeToString(i); + if (i == VIR_NWFILTER_CHAINSUFFIX_ROOT) { + /* allow 'root' as a complete name but not as a prefix */ + if (STREQ(chainname, name)) + return name; + if (STRPREFIX(chainname, name)) + return NULL; + } + if (STRPREFIX(chainname, name)) + return name; + } + + virBufferAsprintf(&buf, + _("Illegal chain name '%s'. Please use a chain name " + "called '%s' or either one of the following prefixes: "), + virNWFilterChainSuffixTypeToString( + VIR_NWFILTER_CHAINSUFFIX_ROOT), + chainname); + for (i = 0; i < VIR_NWFILTER_CHAINSUFFIX_LAST; i++) { + if (i == VIR_NWFILTER_CHAINSUFFIX_ROOT) + continue; + if (printed) + virBufferAddLit(&buf, ", "); + virBufferAdd(&buf, virNWFilterChainSuffixTypeToString(i), -1); + printed = true; + } + + if (virBufferError(&buf)) { + virReportOOMError(); + virBufferFreeAndReset(&buf); + goto err_exit; + } + + msg = virBufferContentAndReset(&buf); + + virNWFilterReportError(VIR_ERR_INVALID_ARG, _("%s"), msg); + VIR_FREE(msg); + +err_exit: + return NULL; +} static virNWFilterDefPtr virNWFilterDefParseXML(xmlXPathContextPtr ctxt) { @@ -2017,6 +2091,7 @@ virNWFilterDefParseXML(xmlXPathContextPt char *chain_pri_s = NULL; virNWFilterEntryPtr entry; int chain_priority; + const char *name_prefix; if (VIR_ALLOC(ret) < 0) { virReportOOMError(); @@ -2052,19 +2127,19 @@ virNWFilterDefParseXML(xmlXPathContextPt chain = virXPathString("string(./@chain)", ctxt); if (chain) { - if (virNWFilterChainSuffixTypeFromString(chain) < 0) { - virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, - _("unknown chain suffix '%s'"), chain); + name_prefix = virNWFilterIsAllowedChain(chain); + if (name_prefix == NULL) goto cleanup; - } ret->chainsuffix = chain; if (chain_pri_s) { ret->chainPriority = chain_priority; } else { - /* assign an implicit priority -- support XML attribute later */ - if (intMapGetByString(chain_priorities, chain, 0, + /* assign an implicit priority */ + if (!name_prefix || + intMapGetByString(chain_priorities, name_prefix, 0, &ret->chainPriority) == false) { + /* assign default chain priority */ ret->chainPriority = (NWFILTER_MAX_FILTER_PRIORITY + NWFILTER_MIN_FILTER_PRIORITY) / 2; } Index: libvirt-acl/src/conf/nwfilter_conf.h =================================================================== --- libvirt-acl.orig/src/conf/nwfilter_conf.h +++ libvirt-acl/src/conf/nwfilter_conf.h @@ -446,6 +446,9 @@ enum virNWFilterChainSuffixType { VIR_NWFILTER_CHAINSUFFIX_LAST, }; +# define VALID_CHAINNAME \ + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.:-" + typedef int32_t virNWFilterChainPriority; typedef struct _virNWFilterDef virNWFilterDef; Index: libvirt-acl/docs/schemas/nwfilter.rng =================================================================== --- libvirt-acl.orig/docs/schemas/nwfilter.rng +++ libvirt-acl/docs/schemas/nwfilter.rng @@ -286,10 +286,18 @@ root - arp - rarp - ipv4 - ipv6 + + arp[a-zA-Z0-9_\.:-]* + + + rarp[a-zA-Z0-9_\.:-]* + + + ipv4[a-zA-Z0-9_\.:-]* + + + ipv6[a-zA-Z0-9_\.:-]* +