Search code examples
cxmllinuxxsltiptables

iptables-restore v1.4.12: iptables.xslt creates wrong output: Couldn't load match `ptcp'


I am trying to load data from xml to iptables. I am using the following command:

xsltproc /usr/share/iptables/iptables.xslt myiptable.xml | iptables-restore

But I get this error

iptables-restore v1.4.12: Couldn't load match `ptcp':No such file or directory

I compared the outputs of ip-tables-save and xsltproc /usr/share/iptables/iptables.xslt myiptable.xml and I got this

output of xsltproc /usr/share/iptables/iptables.xslt myiptable.xml:

-A INPUT -m ptcp -m tcp --dport 22 -j ACCEPT

output of ip-tables-save:

-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT

Can someone please explain what's happening. Also, is there a standard iptables.xslt file that I could download?


Solution

  • Well, the output of your XSLT seems to be syntactically incorrect.

    So -m ptcp -m tcp should probably be -p tcp -m tcp. IIRC -m is match and -p is protocol.

    I investigated this further

    It seems that this is a bug in /usr/share/iptables/iptables.xslt. The actual XSLT is out of sync with the XML format and therefore the output is unusable.

    In the original iptables.xslt(2011-07-22) the output for match-extensions is checked with

    <xsl:if test="name() != 'match'">
    

    but there are no <match> elements in the generated XML file and so this evaluates to always true - creating the -m ptcp output (next to many other wrong strings).

    Solution:

    I rewrote the iptables.xslt replacing the first template matching the conditions with

    <!-- output conditions of a rule but not an action -->
    <xsl:template match="iptables-rules/table/chain/rule/conditions/*">
      <!-- <match> is the psuedo module when a match module doesn't need to be loaded and when -m does not need to be inserted -->
      <xsl:choose>
        <xsl:when test="document('ipt-ext.xml')//@name = name()">
          <xsl:text> -m </xsl:text><xsl:value-of select="name()"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="concat(' -',name(),' ')"/>
        </xsl:otherwise>
      </xsl:choose>     
      <xsl:apply-templates select="node()"/>
    </xsl:template>
    

    This template needs a secondary XML helper file in the same directory for identifying the match-extensions, which are listed in this file I named ipt-ext.xml. Create a new file with this name and the following content in /usr/share/iptables/

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <IPTablesMatchExtensions>
        <IPText name="addrtype" />
        <IPText name="ah" />
        <IPText name="ah" />
        <IPText name="bpf" />
        <IPText name="cluster" />
        <IPText name="comment" />
        <IPText name="connbytes" />
        <IPText name="connlimit" />
        <IPText name="connmark" />
        <IPText name="conntrack" />
        <IPText name="cpu" />
        <IPText name="dccp" />
        <IPText name="devgroup" />
        <IPText name="dscp" />
        <IPText name="dst" />
        <IPText name="ecn" />
        <IPText name="esp" />
        <IPText name="eui64" />
        <IPText name="frag" />
        <IPText name="hashlimit" />
        <IPText name="hbh" />
        <IPText name="helper" />
        <IPText name="hl" />
        <IPText name="icmp" />
        <IPText name="icmp6" />
        <IPText name="iprange" />
        <IPText name="ipv6header" />
        <IPText name="ipvs" />
        <IPText name="length" />
        <IPText name="limit" />
        <IPText name="mac" />
        <IPText name="mark" />
        <IPText name="mh" />
        <IPText name="multiport" />
        <IPText name="nfacct" />
        <IPText name="osf" />
        <IPText name="owner" />
        <IPText name="physdev" />
        <IPText name="pkttype" />
        <IPText name="policy" />
        <IPText name="quota" />
        <IPText name="rateest" />
        <IPText name="realm" />
        <IPText name="recent" />
        <IPText name="rpfilter" />
        <IPText name="rt" />
        <IPText name="sctp" />
        <IPText name="set" />
        <IPText name="socket" />
        <IPText name="state" />
        <IPText name="statistic" />
        <IPText name="string" />
        <IPText name="tcp" />
        <IPText name="tcpmss" />
        <IPText name="time" />
        <IPText name="tos" />
        <IPText name="ttl" />
        <IPText name="u32" />
        <IPText name="udp" />
        <IPText name="unclean" />
    </IPTablesMatchExtensions>
    

    Application:

    From IPTables-rules to XML file:

    sudo iptables-save | iptables-xml -c > myiptable.xml

    From XML file back to IPTables-rules:

    xsltproc /usr/share/iptables/iptables.xslt myiptable.xml | sudo iptables-restore


    Test case: I tested the new stylesheet with these iptables rules:

    $ sudo iptables-save
    # Generated by iptables-save v1.4.12 on Thu May 19 12:00:00 2016
    *nat
    :PREROUTING ACCEPT [11:568]
    :INPUT ACCEPT [1:248]
    :OUTPUT ACCEPT [35:2284]
    :POSTROUTING ACCEPT [35:2284]
    -A PREROUTING -s 192.168.69.9/32 -i eth1 -p tcp -m tcp --dport 80 --tcp-flags FIN,SYN,RST,ACK SYN -j ACCEPT
    -A PREROUTING -d 192.168.70.124/32 -i eth1 -p tcp -m tcp --dport 80 --tcp-flags FIN,SYN,RST,ACK SYN -j ACCEPT
    COMMIT
    # Completed on Thu May 19 12:00:00 2016
    # Generated by iptables-save v1.4.12 on Thu May 19 12:00:00 2016
    *filter
    :INPUT ACCEPT [138:40810]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [135:24836]
    -A INPUT -p tcp -m tcp --dport 65002 -j ACCEPT
    -A INPUT -s 10.0.0.0/32 -p tcp -m tcp --dport 65003 -j ACCEPT
    -A INPUT -d 10.0.0.1/32 -m connbytes --connbytes 1:4 --connbytes-mode bytes --connbytes-dir both -j ACCEPT
    COMMIT
    # Completed on Thu May 19 12:00:00 2016
    

    Then I converted this output to XML with the command from above

    sudo iptables-save | iptables-xml -c > myiptable.xml

    The resulting XML file looks like this:

    <iptables-rules version="1.0">
    <!-- # Generated by iptables*-save v1.4.12 on Thu May 19 12:00:00 2016 -->
      <table name="nat" >
        <chain name="PREROUTING" policy="ACCEPT" packet-count="3" byte-count="96" >
          <rule >
           <conditions>
    PREROUTING          <s >192.168.69.9/32</s>
              <i >eth1</i>
              <p >tcp</p>
            <tcp >
              <dport >80</dport>
              <tcp-flags >FIN,SYN,RST,ACK SYN</tcp-flags>
            </tcp>
           </conditions>
           <actions>
            <ACCEPT  />
           </actions>
    
          </rule>
    
          <rule >
           <conditions>
    PREROUTING          <d >192.168.70.124/32</d>
              <i >eth1</i>
              <p >tcp</p>
            <tcp >
              <dport >80</dport>
              <tcp-flags >FIN,SYN,RST,ACK SYN</tcp-flags>
            </tcp>
           </conditions>
           <actions>
            <ACCEPT  />
           </actions>
    
          </rule>
    
        </chain>
        <chain name="INPUT" policy="ACCEPT" packet-count="0" byte-count="0" />
        <chain name="OUTPUT" policy="ACCEPT" packet-count="8" byte-count="541" />
        <chain name="POSTROUTING" policy="ACCEPT" packet-count="8" byte-count="541" />
      </table>
    <!-- # Completed on Thu May 19 12:00:00 2016 -->
    <!-- # Generated by iptables*-save v1.4.12 on Thu May 19 12:00:00 2016 -->
      <table name="filter" >
        <chain name="INPUT" policy="ACCEPT" packet-count="127" byte-count="27749" >
          <rule >
           <conditions>
    INPUT          <p >tcp</p>
            <tcp >
              <dport >65002</dport>
            </tcp>
           </conditions>
           <actions>
            <ACCEPT  />
           </actions>
    
          </rule>
    
          <rule >
           <conditions>
    INPUT          <s >10.0.0.0/32</s>
              <p >tcp</p>
            <tcp >
              <dport >65003</dport>
            </tcp>
           </conditions>
           <actions>
            <ACCEPT  />
           </actions>
    
          </rule>
    
          <rule >
           <conditions>
    INPUT          <d >10.0.0.1/32</d>
            <connbytes >
              <connbytes >1:4</connbytes>
              <connbytes-mode >bytes</connbytes-mode>
              <connbytes-dir >both</connbytes-dir>
            </connbytes>
           </conditions>
           <actions>
            <ACCEPT  />
           </actions>
    
          </rule>
    
        </chain>
        <chain name="FORWARD" policy="ACCEPT" packet-count="0" byte-count="0" />
        <chain name="OUTPUT" policy="ACCEPT" packet-count="78" byte-count="6909" />
      </table>
    <!-- # Completed on Thu May 19 12:00:00 2016 -->
    </iptables-rules>
    

    And then back again from XML to iptables

    xsltproc /usr/share/iptables/iptables.xslt myiptable.xml | sudo iptables-restore

    It all works seamlessly as expected.