iptables-xml

Attached are:
1. A man page for iptables-xml

2. A fix for iptables.xslt allowing for an arbitrary depth of arguments
or modifiers.

Although iptables-xml cannot generate more than two levels deep, xml
generated by other systems may prefer to generate

<action>
  <restore-mark>
    <mask>0xff00</mask>
  </restore-mark>
</action>

than

<action>
  <restore-mark/>
   <mask>0xff00</mask>
</action>

(which is what iptables-xml generates)
even though the same iptables is re-generated on conversion.

3. A fix for iptables-xml.c so that combining of consecutive targets of
rules with the same match into one XML rule, will not combine over a
terminating action; i.e. there is no point in converting

-A table -p tcp -j DROP
-A table -p tcp -j MARK --set-mark 25
-A table -p tcp -j RETURN

into one XML rule with multiple actions as they are probably not
logically combined in the mind of the author.


Signed-off by: Sam Liddicott <azez@ufomechanic.net>
diff --git a/iptables-xml.c b/iptables-xml.c
index ce3049c..71d5288 100644
--- a/iptables-xml.c
+++ b/iptables-xml.c
@@ -359,6 +359,18 @@
 		    || strcmp((arg), "--goto") == 0));
 }
 
+// is it a terminating target like -j ACCEPT, etc
+// (or I guess -j SNAT in nat table, but we don't check for that yet
+static int
+isTerminatingTarget(char *arg)
+{
+	return ((arg)
+		&& (strcmp((arg), "ACCEPT") == 0
+		    || strcmp((arg), "DROP") == 0
+		    || strcmp((arg), "QUEUE") == 0
+		    || strcmp((arg), "RETURN") == 0));
+}
+
 // part=-1 means do conditions, part=1 means do rules, part=0 means do both
 static void
 do_rule_part(char *leveltag1, char *leveltag2, int part, int argc,
@@ -536,7 +548,19 @@
 
 	while (new < newargc && old < oldargc) {
 		if (isTarget(oldargv[old]) && isTarget(newargv[new])) {
-			compare = 1;
+			/* if oldarg was a terminating action then it makes no sense
+			 * to combine further actions into the same xml */
+			if (((strcmp((oldargv[old]), "-j") == 0 
+					|| strcmp((oldargv[old]), "--jump") == 0) 
+				&& old+1 < oldargc
+				&& isTerminatingTarget(oldargv[old+1]) )
+			    || strcmp((oldargv[old]), "-g") == 0 
+			    || strcmp((oldargv[old]), "--goto") == 0 ) {
+				/* Previous rule had terminating action */	
+				compare = 0;
+			} else {
+				compare = 1;
+			}
 			break;
 		}
 		// break when old!=new