]> xenbits.xensource.com Git - libvirt.git/commitdiff
nwfilter: Instantiate state match in ip(6)tables rules
authorStefan Berger <stefanb@us.ibm.com>
Thu, 7 Oct 2010 10:41:37 +0000 (06:41 -0400)
committerStefan Berger <stefanb@us.ibm.com>
Thu, 7 Oct 2010 10:41:37 +0000 (06:41 -0400)
In this patch I am extending the rule instantiator to create the state
match according to the state attribute in the XML. Only one iptables
rule in the incoming or outgoing direction will be created for a rule
in direction 'in' or 'out' respectively. A rule in direction 'inout' does
get iptables rules in both directions.

src/nwfilter/nwfilter_ebiptables_driver.c

index 3fbe08b05f98d42f325fe5ad7ea9479c238db3e2..bcbefa70326aadb21263ae6d99e2e2e6dfadc9b5 100644 (file)
@@ -1129,7 +1129,7 @@ _iptablesCreateRuleInstance(int directionIn,
                             const char *ifname,
                             virNWFilterHashTablePtr vars,
                             virNWFilterRuleInstPtr res,
-                            const char *match,
+                            const char *match, bool defMatch,
                             const char *accept_target,
                             bool isIPv6,
                             bool maySkipICMP)
@@ -1488,7 +1488,7 @@ _iptablesCreateRuleInstance(int directionIn,
         target = accept_target;
     else {
         target = "DROP";
-        skipMatch = true;
+        skipMatch = defMatch;
     }
 
     if (match && !skipMatch)
@@ -1547,6 +1547,149 @@ exit_no_error:
 }
 
 
+static int
+printStateMatchFlags(int32_t flags, char **bufptr)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    virNWFilterPrintStateMatchFlags(&buf,
+                                    "-m state --state ",
+                                    flags,
+                                    false);
+    if (virBufferError(&buf)) {
+        virBufferFreeAndReset(&buf);
+        virReportOOMError();
+        return 1;
+    }
+    *bufptr = virBufferContentAndReset(&buf);
+    return 0;
+}
+
+static int
+iptablesCreateRuleInstanceStateCtrl(virNWFilterDefPtr nwfilter,
+                                    virNWFilterRuleDefPtr rule,
+                                    const char *ifname,
+                                    virNWFilterHashTablePtr vars,
+                                    virNWFilterRuleInstPtr res,
+                                    bool isIPv6)
+{
+    int rc;
+    int directionIn = 0, directionOut = 0;
+    char chainPrefix[2];
+    bool maySkipICMP, inout = false;
+    char *matchState = NULL;
+    bool create;
+
+    if ((rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN) ||
+        (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT)) {
+        directionIn = 1;
+        directionOut = inout = (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT);
+    } else
+        directionOut = 1;
+
+    chainPrefix[0] = 'F';
+
+    maySkipICMP = directionIn || inout;
+
+    create = true;
+    matchState = NULL;
+
+    if (directionIn && !inout) {
+        if ((rule->flags & IPTABLES_STATE_FLAGS))
+            create = false;
+    }
+
+    if (create && (rule->flags & IPTABLES_STATE_FLAGS)) {
+        if (printStateMatchFlags(rule->flags, &matchState))
+            return 1;
+    }
+
+    chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
+    if (create) {
+        rc = _iptablesCreateRuleInstance(directionIn,
+                                         chainPrefix,
+                                         nwfilter,
+                                         rule,
+                                         ifname,
+                                         vars,
+                                         res,
+                                         matchState, false,
+                                         "RETURN",
+                                         isIPv6,
+                                         maySkipICMP);
+
+        VIR_FREE(matchState);
+        if (rc)
+            return rc;
+    }
+
+    maySkipICMP = !directionIn || inout;
+    create = true;
+
+    if (!directionIn) {
+        if ((rule->flags & IPTABLES_STATE_FLAGS))
+            create = false;
+    }
+
+    if (create && (rule->flags & IPTABLES_STATE_FLAGS)) {
+        if (printStateMatchFlags(rule->flags, &matchState))
+            return 1;
+    }
+
+    chainPrefix[1] = CHAINPREFIX_HOST_OUT_TEMP;
+    if (create) {
+        rc = _iptablesCreateRuleInstance(!directionIn,
+                                         chainPrefix,
+                                         nwfilter,
+                                         rule,
+                                         ifname,
+                                         vars,
+                                         res,
+                                         matchState, false,
+                                         "ACCEPT",
+                                         isIPv6,
+                                         maySkipICMP);
+
+        VIR_FREE(matchState);
+
+        if (rc)
+            return rc;
+    }
+
+    maySkipICMP = directionIn;
+
+    create = true;
+
+    if (directionIn && !inout) {
+        if ((rule->flags & IPTABLES_STATE_FLAGS))
+            create = false;
+    } else {
+        if ((rule->flags & IPTABLES_STATE_FLAGS)) {
+            if (printStateMatchFlags(rule->flags, &matchState))
+                return 1;
+        }
+    }
+
+    if (create) {
+        chainPrefix[0] = 'H';
+        chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
+        rc = _iptablesCreateRuleInstance(directionIn,
+                                         chainPrefix,
+                                         nwfilter,
+                                         rule,
+                                         ifname,
+                                         vars,
+                                         res,
+                                         matchState, false,
+                                         "RETURN",
+                                         isIPv6,
+                                         maySkipICMP);
+        VIR_FREE(matchState);
+    }
+
+    return rc;
+}
+
+
 static int
 iptablesCreateRuleInstance(virNWFilterDefPtr nwfilter,
                            virNWFilterRuleDefPtr rule,
@@ -1562,6 +1705,16 @@ iptablesCreateRuleInstance(virNWFilterDefPtr nwfilter,
     bool maySkipICMP, inout = false;
     const char *matchState;
 
+    if (!(rule->flags & RULE_FLAG_NO_STATEMATCH) &&
+         (rule->flags & IPTABLES_STATE_FLAGS)) {
+        return iptablesCreateRuleInstanceStateCtrl(nwfilter,
+                                                   rule,
+                                                   ifname,
+                                                   vars,
+                                                   res,
+                                                   isIPv6);
+    }
+
     if ((rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN) ||
         (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT)) {
         directionIn = 1;
@@ -1590,7 +1743,7 @@ iptablesCreateRuleInstance(virNWFilterDefPtr nwfilter,
                                      ifname,
                                      vars,
                                      res,
-                                     matchState,
+                                     matchState, true,
                                      "RETURN",
                                      isIPv6,
                                      maySkipICMP);
@@ -1612,7 +1765,7 @@ iptablesCreateRuleInstance(virNWFilterDefPtr nwfilter,
                                      ifname,
                                      vars,
                                      res,
-                                     matchState,
+                                     matchState, true,
                                      "ACCEPT",
                                      isIPv6,
                                      maySkipICMP);
@@ -1630,7 +1783,7 @@ iptablesCreateRuleInstance(virNWFilterDefPtr nwfilter,
                                      ifname,
                                      vars,
                                      res,
-                                     NULL,
+                                     NULL, true,
                                      "ACCEPT",
                                      isIPv6,
                                      maySkipICMP);