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 @@
+
+
+
+
+
+
+
+
+
+
+
+