diff --git a/docs/formatnwfilter.html.in b/docs/formatnwfilter.html.in index eb3c72b7a9..1cc13352af 100644 --- a/docs/formatnwfilter.html.in +++ b/docs/formatnwfilter.html.in @@ -755,6 +755,11 @@ STRING comma separated list of NEW,ESTABLISHED,RELATED,INVALID or NONE + + flags (Since 0.9.1) + STRING + TCP-only: format of mask/flags with mask and flags each being a comma separated list of SYN,ACK,URG,PSH,FIN,RST or NONE or ALL +



@@ -1040,6 +1045,11 @@ STRING comma separated list of NEW,ESTABLISHED,RELATED,INVALID or NONE + + flags (Since 0.9.1) + STRING + TCP-only: format of mask/flags with mask and flags each being a comma separated list of SYN,ACK,URG,PSH,FIN,RST or NONE or ALL +



diff --git a/docs/schemas/nwfilter.rng b/docs/schemas/nwfilter.rng index c2625b0658..662485e239 100644 --- a/docs/schemas/nwfilter.rng +++ b/docs/schemas/nwfilter.rng @@ -81,6 +81,7 @@ + @@ -184,6 +185,7 @@ + @@ -606,6 +608,14 @@ + + + + + + + + @@ -872,4 +882,10 @@ ((NEW|ESTABLISHED|RELATED|INVALID)(,(NEW|ESTABLISHED|RELATED|INVALID))*|NONE) + + + + ((SYN|ACK|URG|PSH|FIN|RST)(,(SYN|ACK|URG|PSH|FIN|RST))*|ALL|NONE)/((SYN|ACK|URG|PSH|FIN|RST)(,(SYN|ACK|URG|PSH|FIN|RST))*|ALL|NONE) + + diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c index df8e20f1a4..0732322556 100644 --- a/src/conf/nwfilter_conf.c +++ b/src/conf/nwfilter_conf.c @@ -5,7 +5,8 @@ * Copyright (C) 2006-2011 Red Hat, Inc. * Copyright (C) 2006-2008 Daniel P. Berrange * - * Copyright (C) 2010 IBM Corporation + * Copyright (C) 2010-2011 IBM Corporation + * Copyright (C) 2010-2011 Stefan Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -726,17 +727,23 @@ printStringItems(virBufferPtr buf, const struct int_map *int_map, int32_t flags, const char *sep) { unsigned int i, c = 0; - int32_t last_attr = 0; + int32_t mask = 0x1; - for (i = 0; int_map[i].val; i++) { - if (last_attr != int_map[i].attr && - flags & int_map[i].attr) { - if (c >= 1) - virBufferVSprintf(buf, "%s", sep); - virBufferVSprintf(buf, "%s", int_map[i].val); - c++; + while (mask) { + if ((mask & flags)) { + for (i = 0; int_map[i].val; i++) { + if (mask == int_map[i].attr) { + if (c >= 1) + virBufferVSprintf(buf, "%s", sep); + virBufferVSprintf(buf, "%s", int_map[i].val); + c++; + } + } + flags ^= mask; } - last_attr = int_map[i].attr; + if (!flags) + break; + mask <<= 1; } return 0; @@ -799,6 +806,87 @@ stateFormatter(virBufferPtr buf, } + +static const struct int_map tcpFlags[] = { + INTMAP_ENTRY(0x1 , "FIN"), + INTMAP_ENTRY(0x2 , "SYN"), + INTMAP_ENTRY(0x4 , "RST"), + INTMAP_ENTRY(0x8 , "PSH"), + INTMAP_ENTRY(0x10, "ACK"), + INTMAP_ENTRY(0x20, "URG"), + INTMAP_ENTRY(0x3F, "ALL"), + INTMAP_ENTRY(0x0 , "NONE"), + INTMAP_ENTRY_LAST +}; + + +static bool +tcpFlagsValidator(enum attrDatatype datatype ATTRIBUTE_UNUSED, union data *val, + virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED, + nwItemDesc *item) +{ + bool rc = false; + char *s_mask = val->c; + char *sep = strchr(val->c, '/'); + char *s_flags; + int32_t mask = 0, flags = 0; + + if (!sep) + return false; + + s_flags = sep + 1; + + *sep = '\0'; + + if (!parseStringItems(tcpFlags, s_mask , &mask , ',') && + !parseStringItems(tcpFlags, s_flags, &flags, ',')) { + item->u.tcpFlags.mask = mask & 0x3f; + item->u.tcpFlags.flags = flags & 0x3f; + rc = true; + } + + *sep = '/'; + + return rc; +} + + +static void +printTCPFlags(virBufferPtr buf, uint8_t flags) +{ + if (flags == 0) + virBufferAddLit(buf, "NONE"); + else if (flags == 0x3f) + virBufferAddLit(buf, "ALL"); + else + printStringItems(buf, tcpFlags, flags, ","); +} + + +void +virNWFilterPrintTCPFlags(virBufferPtr buf, + uint8_t mask, char sep, uint8_t flags) +{ + printTCPFlags(buf, mask); + virBufferAddChar(buf, sep); + printTCPFlags(buf, flags); +} + + +static bool +tcpFlagsFormatter(virBufferPtr buf, + virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED, + nwItemDesc *item) +{ + virNWFilterPrintTCPFlags(buf, + item->u.tcpFlags.mask, + '/', + item->u.tcpFlags.flags); + + return true; +} + + #define COMMON_MAC_PROPS(STRUCT) \ {\ .name = SRCMACADDR,\ @@ -1104,6 +1192,13 @@ static const virXMLAttr2Struct tcpAttributes[] = { .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX, .dataIdx = offsetof(virNWFilterRuleDef, p.tcpHdrFilter.dataTCPOption), }, + { + .name = "flags", + .datatype = DATATYPE_STRING, + .dataIdx = offsetof(virNWFilterRuleDef, p.tcpHdrFilter.dataTCPFlags), + .validator = tcpFlagsValidator, + .formatter = tcpFlagsFormatter, + }, COMMENT_PROP_IPHDR(tcpHdrFilter), { .name = NULL, diff --git a/src/conf/nwfilter_conf.h b/src/conf/nwfilter_conf.h index 40da8c37c1..9281f567be 100644 --- a/src/conf/nwfilter_conf.h +++ b/src/conf/nwfilter_conf.h @@ -122,6 +122,10 @@ struct _nwItemDesc { uint16_t u16; char protocolID[10]; char *string; + struct { + uint8_t mask; + uint8_t flags; + } tcpFlags; } u; }; @@ -242,6 +246,7 @@ struct _tcpHdrFilterDef { ipHdrDataDef ipHdr; portDataDef portData; nwItemDesc dataTCPOption; + nwItemDesc dataTCPFlags; }; @@ -667,6 +672,10 @@ void virNWFilterCallbackDriversLock(void); void virNWFilterCallbackDriversUnlock(void); +void virNWFilterPrintTCPFlags(virBufferPtr buf, uint8_t mask, + char sep, uint8_t flags); + + VIR_ENUM_DECL(virNWFilterRuleAction); VIR_ENUM_DECL(virNWFilterRuleDirection); VIR_ENUM_DECL(virNWFilterRuleProtocol); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 65a86d3de2..54e4482b42 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -678,6 +678,7 @@ virNWFilterObjRemove; virNWFilterObjSaveDef; virNWFilterObjUnlock; virNWFilterPrintStateMatchFlags; +virNWFilterPrintTCPFlags; virNWFilterRegisterCallbackDriver; virNWFilterRuleActionTypeToString; virNWFilterRuleProtocolTypeToString; diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c index 75fddfbffc..6c9c470c41 100644 --- a/src/nwfilter/nwfilter_ebiptables_driver.c +++ b/src/nwfilter/nwfilter_ebiptables_driver.c @@ -1204,6 +1204,15 @@ _iptablesCreateRuleInstance(int directionIn, &prefix)) goto err_exit; + if (HAS_ENTRY_ITEM(&rule->p.tcpHdrFilter.dataTCPFlags)) { + virBufferVSprintf(&buf, " %s --tcp-flags ", + ENTRY_GET_NEG_SIGN(&rule->p.tcpHdrFilter.dataTCPFlags)); + virNWFilterPrintTCPFlags(&buf, + rule->p.tcpHdrFilter.dataTCPFlags.u.tcpFlags.mask, + ' ', + rule->p.tcpHdrFilter.dataTCPFlags.u.tcpFlags.flags); + } + if (iptablesHandlePortData(&buf, vars, &rule->p.tcpHdrFilter.portData, diff --git a/tests/nwfilterxml2xmlin/tcp-test.xml b/tests/nwfilterxml2xmlin/tcp-test.xml index 3fe5299fb4..602721c484 100644 --- a/tests/nwfilterxml2xmlin/tcp-test.xml +++ b/tests/nwfilterxml2xmlin/tcp-test.xml @@ -19,4 +19,16 @@ srcportstart='255' srcportend='256' dstportstart='65535' dstportend='65536'/> + + + + + + + + + + + + diff --git a/tests/nwfilterxml2xmlout/tcp-test.xml b/tests/nwfilterxml2xmlout/tcp-test.xml index 4037808c45..253c66d9a4 100644 --- a/tests/nwfilterxml2xmlout/tcp-test.xml +++ b/tests/nwfilterxml2xmlout/tcp-test.xml @@ -9,4 +9,16 @@ + + + + + + + + + + + +