]> xenbits.xensource.com Git - libvirt.git/commitdiff
nwfilters: support for TCP flags evaluation
authorStefan Berger <stefanb@us.ibm.com>
Fri, 8 Apr 2011 00:13:38 +0000 (20:13 -0400)
committerStefan Berger <stefanb@us.ibm.com>
Fri, 8 Apr 2011 00:13:38 +0000 (20:13 -0400)
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:

<rule action='accept' direction='in'>
    <tcp state='NONE' flags='SYN/ALL' dsptportstart='80'/>
</rule>
<rule action='drop' direction='in'>
    <tcp state='NONE' flags='SYN/ALL'/>
</rule>

docs/formatnwfilter.html.in
docs/schemas/nwfilter.rng
src/conf/nwfilter_conf.c
src/conf/nwfilter_conf.h
src/libvirt_private.syms
src/nwfilter/nwfilter_ebiptables_driver.c
tests/nwfilterxml2xmlin/tcp-test.xml
tests/nwfilterxml2xmlout/tcp-test.xml

index eb3c72b7a9e309f599410efe0fe55510726b7239..1cc13352af2cdbe8d18c5f448ef14584790bf07d 100644 (file)
          <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.1)</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/>
          <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.1)</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/>
index c2625b065826ace46d3dde2768299d534b2f207c..662485e2391fef4521b38a95a8af49757e160c0e 100644 (file)
@@ -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>
                   <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>
     </optional>
   </define>
 
+  <define name="tcp-attributes">
+    <optional>
+      <attribute name="flags">
+        <ref name="tcpflags-type"/>
+      </attribute>
+    </optional>
+  </define>
+
   <!-- ################  type library ################ -->
 
   <define name="UUID">
       <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 df8e20f1a436779c8b2ba9ab29f0780b76f4f081..0732322556fd68635c14f0d7cd0f9e3347590eff 100644 (file)
@@ -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,
index 40da8c37c1f16d116ea9acd00ce59220ec73ea20..9281f567be3e055636fed1d464963b718d8c4bc5 100644 (file)
@@ -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 65a86d3de247343849e5ee309f0c4c10e16baca8..54e4482b4272f0e855b9daac562f688e9332a204 100644 (file)
@@ -678,6 +678,7 @@ virNWFilterObjRemove;
 virNWFilterObjSaveDef;
 virNWFilterObjUnlock;
 virNWFilterPrintStateMatchFlags;
+virNWFilterPrintTCPFlags;
 virNWFilterRegisterCallbackDriver;
 virNWFilterRuleActionTypeToString;
 virNWFilterRuleProtocolTypeToString;
index 75fddfbffc4dbbbbdb792fca9a21a9146d5547c8..6c9c470c41f12bdb1f9a4a87db024127e557575b 100644 (file)
@@ -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,
index 3fe5299fb4847a72ca4b5349ad349770b1cb6b57..602721c484a5206044be2161751e7bc65b95c12b 100644 (file)
           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 4037808c45d0519674bc6a6c1c06803a7a734461..253c66d9a4a191c95232e50efc58a033cdd13cda 100644 (file)
@@ -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>