From 6ab24feb44a0cb3a7de5ad89619c14cfd4be44ce Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 7 Apr 2011 20:13:38 -0400 Subject: [PATCH] nwfilters: support for TCP flags evaluation This patch adds support for the evaluation of TCP flags in nwfilters. It adds documentation to the web page and extends the tests as well. Also, the nwfilter schema is extended. The following are some example for rules using the tcp flags: --- docs/formatnwfilter.html.in | 10 ++ docs/schemas/nwfilter.rng | 16 +++ src/conf/nwfilter_conf.c | 117 ++++++++++++++++++++-- src/conf/nwfilter_conf.h | 9 ++ src/libvirt_private.syms | 1 + src/nwfilter/nwfilter_ebiptables_driver.c | 9 ++ tests/nwfilterxml2xmlin/tcp-test.xml | 12 +++ tests/nwfilterxml2xmlout/tcp-test.xml | 12 +++ 8 files changed, 175 insertions(+), 11 deletions(-) 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; - - 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++; + int32_t mask = 0x1; + + 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 @@ + + + + + + + + + + + + -- GitLab