[libvirt] [PATCH] nwfilters: support for TCP flags evaluation

Stefan Berger stefanb at linux.vnet.ibm.com
Fri Apr 1 16:17:21 UTC 2011


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.

Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>

---
  docs/formatnwfilter.html.in               |   10 ++
  docs/schemas/nwfilter.rng                 |   16 ++++
  src/conf/nwfilter_conf.c                  |  115 
+++++++++++++++++++++++++++---
  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, 174 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
@@ -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
                   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;
+            if (!flags)
+                break;
          }
-        last_attr = int_map[i].attr;
+        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 tcpAttrib
          .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,
Index: libvirt-acl/src/conf/nwfilter_conf.h
===================================================================
--- libvirt-acl.orig/src/conf/nwfilter_conf.h
+++ libvirt-acl/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);
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
@@ -1204,6 +1204,15 @@ _iptablesCreateRuleInstance(int directio
&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,
Index: libvirt-acl/docs/schemas/nwfilter.rng
===================================================================
--- libvirt-acl.orig/docs/schemas/nwfilter.rng
+++ libvirt-acl/docs/schemas/nwfilter.rng
@@ -81,6 +81,7 @@
<ref name="common-port-attributes"/>
<ref name="common-ip-attributes-p1"/>
<ref name="common-ip-attributes-p2"/>
+ <ref name="tcp-attributes"/>
<ref name="comment-attribute"/>
</element>
</zeroOrMore>
@@ -184,6 +185,7 @@
<ref name="common-port-attributes"/>
<ref name="common-ipv6-attributes-p1"/>
<ref name="common-ipv6-attributes-p2"/>
+ <ref name="tcp-attributes"/>
<ref name="comment-attribute"/>
</element>
</zeroOrMore>
@@ -606,6 +608,14 @@
</optional>
</define>

+ <define name="tcp-attributes">
+ <optional>
+ <attribute name="flags">
+ <ref name="tcpflags-type"/>
+ </attribute>
+ </optional>
+ </define>
+
<!-- ################  type library ################ -->

<define name="UUID">
@@ -872,4 +882,10 @@
<param 
name="pattern">((NEW|ESTABLISHED|RELATED|INVALID)(,(NEW|ESTABLISHED|RELATED|INVALID))*|NONE)</param>
</data>
</define>
+
+ <define name='tcpflags-type'>
+ <data type="string">
+ <param 
name="pattern">((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)</param>
+ </data>
+ </define>
</grammar>
Index: libvirt-acl/docs/formatnwfilter.html.in
===================================================================
--- libvirt-acl.orig/docs/formatnwfilter.html.in
+++ libvirt-acl/docs/formatnwfilter.html.in
@@ -755,6 +755,11 @@
<td>STRING</td>
<td>comma separated list of NEW,ESTABLISHED,RELATED,INVALID or NONE</td>
</tr>
+ <tr>
+ <td>flags <span class="since">(Since 0.9.0)</span></td>
+ <td>STRING</td>
+ <td>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</td>
+ </tr>
</table>
<p>
<br><br>
@@ -1040,6 +1045,11 @@
<td>STRING</td>
<td>comma separated list of NEW,ESTABLISHED,RELATED,INVALID or NONE</td>
</tr>
+ <tr>
+ <td>flags <span class="since">(Since 0.8.5)</span></td>
+ <td>STRING</td>
+ <td>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</td>
+ </tr>
</table>
<p>
<br><br>
Index: libvirt-acl/src/libvirt_private.syms
===================================================================
--- libvirt-acl.orig/src/libvirt_private.syms
+++ libvirt-acl/src/libvirt_private.syms
@@ -683,6 +683,7 @@ virNWFilterObjRemove;
  virNWFilterObjSaveDef;
  virNWFilterObjUnlock;
  virNWFilterPrintStateMatchFlags;
+virNWFilterPrintTCPFlags;
  virNWFilterRegisterCallbackDriver;
  virNWFilterRuleActionTypeToString;
  virNWFilterRuleProtocolTypeToString;
Index: libvirt-acl/tests/nwfilterxml2xmlin/tcp-test.xml
===================================================================
--- libvirt-acl.orig/tests/nwfilterxml2xmlin/tcp-test.xml
+++ libvirt-acl/tests/nwfilterxml2xmlin/tcp-test.xml
@@ -19,4 +19,16 @@
            srcportstart='255' srcportend='256'
            dstportstart='65535' dstportend='65536'/>
</rule>
+ <rule action='accept' direction='in'>
+ <tcp state='NONE' flags='SYN/ALL'/>
+ </rule>
+ <rule action='accept' direction='in'>
+ <tcp state='NONE' flags='SYN/SYN,ACK'/>
+ </rule>
+ <rule action='accept' direction='in'>
+ <tcp state='NONE' flags='RST/NONE'/>
+ </rule>
+ <rule action='accept' direction='in'>
+ <tcp state='NONE' flags='PSH/'/>
+ </rule>
</filter>
Index: libvirt-acl/tests/nwfilterxml2xmlout/tcp-test.xml
===================================================================
--- libvirt-acl.orig/tests/nwfilterxml2xmlout/tcp-test.xml
+++ libvirt-acl/tests/nwfilterxml2xmlout/tcp-test.xml
@@ -9,4 +9,16 @@
<rule action='accept' direction='in' priority='500' statematch='false'>
<tcp srcmacaddr='01:02:03:04:05:06' srcipaddr='10.1.2.3' srcipmask='32' 
dscp='63' srcportstart='255' srcportend='256' dstportstart='65535'/>
</rule>
+ <rule action='accept' direction='in' priority='500'>
+ <tcp state='NONE' flags='SYN/ALL'/>
+ </rule>
+ <rule action='accept' direction='in' priority='500'>
+ <tcp state='NONE' flags='SYN/SYN,ACK'/>
+ </rule>
+ <rule action='accept' direction='in' priority='500'>
+ <tcp state='NONE' flags='RST/NONE'/>
+ </rule>
+ <rule action='accept' direction='in' priority='500'>
+ <tcp state='NONE' flags='PSH/NONE'/>
+ </rule>
</filter>




More information about the libvir-list mailing list