You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by GitBox <gi...@apache.org> on 2018/04/30 09:53:31 UTC

[GitHub] DaanHoogland closed pull request #2083: Iptables speedup

DaanHoogland closed pull request #2083: Iptables speedup
URL: https://github.com/apache/cloudstack/pull/2083
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/systemvm/patches/debian/config/opt/cloud/bin/configure.py b/systemvm/patches/debian/config/opt/cloud/bin/configure.py
index 7f0df5be0df..38335e0322b 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/configure.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/configure.py
@@ -17,27 +17,16 @@
 # specific language governing permissions and limitations
 # under the License.
 import sys
-import os
 import base64
 
-from merge import DataBag
-from pprint import pprint
-import subprocess
-import logging
 import re
-import time
-import shutil
-import os.path
-import os
 from fcntl import flock, LOCK_EX, LOCK_UN
 
-from cs.CsDatabag import CsDataBag, CsCmdLine
-import cs.CsHelper
+from cs.CsDatabag import CsDataBag
 from cs.CsNetfilter import CsNetfilters
 from cs.CsDhcp import CsDhcp
 from cs.CsRedundant import *
 from cs.CsFile import CsFile
-from cs.CsApp import CsApache, CsDnsmasq
 from cs.CsMonitor import CsMonitor
 from cs.CsLoadBalancer import CsLoadBalancer
 from cs.CsConfig import CsConfig
@@ -207,7 +196,23 @@ def create(self):
 
         def process(self, direction, rule_list, base):
             count = base
-            for i in rule_list:
+            rule_list_splitted = []
+            for rule in rule_list:
+                if ',' in rule['cidr']:
+                    cidrs = rule['cidr'].split(',')
+                    for cidr in cidrs:
+                        new_rule = {
+                            'cidr': cidr,
+                            'last_port': rule['last_port'],
+                            'type': rule['type'],
+                            'first_port': rule['first_port'],
+                            'allowed': rule['allowed']
+                        }
+                        rule_list_splitted.append(new_rule)
+                else:
+                    rule_list_splitted.append(rule)
+
+            for i in rule_list_splitted:
                 r = self.AclRule(direction, self, i, self.config, count)
                 r.create()
                 count += 1
@@ -260,7 +265,7 @@ def create(self):
                     rstr = "%s -m icmp --icmp-type %s" % (rstr, self.icmp_type)
                 rstr = "%s %s -j %s" % (rstr, self.dport, self.action)
                 rstr = rstr.replace("  ", " ").lstrip()
-                self.fw.append([self.table, self.count, rstr])
+                self.fw.append([self.table, "", rstr])
 
     def flushAllowAllEgressRules(self):
         logging.debug("Flush allow 'all' egress firewall rule")
@@ -483,7 +488,7 @@ def configure_iptables(self, dev, obj):
         self.fw.append(["", "front", "-A INPUT -i %s -p udp -m udp --dport 500 -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], obj['local_public_ip'])])
         self.fw.append(["", "front", "-A INPUT -i %s -p udp -m udp --dport 4500 -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], obj['local_public_ip'])])
         self.fw.append(["", "front", "-A INPUT -i %s -p esp -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], obj['local_public_ip'])])
-        self.fw.append(["nat", "front", "-A POSTROUTING -t nat -o %s -m mark --mark 0x525 -j ACCEPT" % dev])
+        self.fw.append(["nat", "front", "-A POSTROUTING -o %s -m mark --mark 0x525 -j ACCEPT" % dev])
         for net in obj['peer_guest_cidr_list'].lstrip().rstrip().split(','):
             self.fw.append(["mangle", "front",
                             "-A FORWARD -s %s -d %s -j MARK --set-xmark 0x525/0xffffffff" % (obj['local_guest_cidr'], net)])
@@ -809,7 +814,7 @@ def forward_vr(self, rule):
                 rule['internal_ip'],
                 internal_fwports
               )
-        fw4 = "-j SNAT --to-source %s -A POSTROUTING -s %s -d %s/32 -o %s -p %s -m %s --dport %s" % \
+        fw4 = "-A POSTROUTING -j SNAT --to-source %s -s %s -d %s/32 -o %s -p %s -m %s --dport %s" % \
               (
                 self.getGuestIp(),
                 self.getNetworkByIp(rule['internal_ip']),
@@ -1011,7 +1016,7 @@ def main(argv):
             lb.process()
 
             logging.debug("Configuring iptables rules")
-            nf = CsNetfilters()
+            nf = CsNetfilters(False)
             nf.compare(config.get_fw())
 
             logging.debug("Configuring iptables rules done ...saving rules")
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py
index 43cd6396587..eabd9a4f82f 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py
@@ -401,8 +401,7 @@ def fw_router(self):
 
         self.fw.append(["filter", "", "-A INPUT -d 224.0.0.18/32 -j ACCEPT"])
         self.fw.append(["filter", "", "-A INPUT -d 225.0.0.50/32 -j ACCEPT"])
-        self.fw.append(["filter", "", "-A INPUT -i %s -m state --state RELATED,ESTABLISHED -j ACCEPT" %
-                        self.dev])
+        self.fw.append(["filter", "", "-A INPUT -i %s -m state --state RELATED,ESTABLISHED -j ACCEPT" % self.dev])
         self.fw.append(["filter", "", "-A INPUT -p icmp -j ACCEPT"])
         self.fw.append(["filter", "", "-A INPUT -i lo -j ACCEPT"])
 
@@ -436,6 +435,13 @@ def fw_router(self):
     def fw_vpcrouter(self):
         if not self.config.is_vpc():
             return
+        self.fw.append(["mangle", "front", "-A PREROUTING " +
+                        "-m state --state RELATED,ESTABLISHED " +
+                        "-j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff"])
+
+        self.fw.append(["", "front", "-A FORWARD -j NETWORK_STATS"])
+        self.fw.append(["", "front", "-A INPUT -j NETWORK_STATS"])
+        self.fw.append(["", "front", "-A OUTPUT -j NETWORK_STATS"])
 
         self.fw.append(["filter", "", "-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT"])
 
@@ -484,10 +490,6 @@ def fw_vpcrouter(self):
                             (guestNetworkCidr, self.dev, self.address['public_ip'])])
 
         if self.get_type() in ["public"]:
-            self.fw.append(["", "front",
-                            "-A FORWARD -o %s -d %s -j ACL_INBOUND_%s" % (
-                                self.dev, self.address['network'], self.dev)
-                            ])
             self.fw.append(
                 ["mangle", "", "-A FORWARD -j VPN_STATS_%s" % self.dev])
             self.fw.append(
@@ -495,11 +497,7 @@ def fw_vpcrouter(self):
             self.fw.append(
                 ["mangle", "", "-A VPN_STATS_%s -i %s -m mark --mark 0x524/0xffffffff" % (self.dev, self.dev)])
             self.fw.append(
-                ["", "front", "-A FORWARD -j NETWORK_STATS_%s" % self.dev])
-
-        self.fw.append(["", "front", "-A FORWARD -j NETWORK_STATS"])
-        self.fw.append(["", "front", "-A INPUT -j NETWORK_STATS"])
-        self.fw.append(["", "front", "-A OUTPUT -j NETWORK_STATS"])
+                ["", "front", "-A FORWARD -j NETWORK_STATS_eth1"])
 
         self.fw.append(["", "", "-A NETWORK_STATS -i eth0 -o eth2 -p tcp"])
         self.fw.append(["", "", "-A NETWORK_STATS -i eth2 -o eth0 -p tcp"])
@@ -508,7 +506,8 @@ def fw_vpcrouter(self):
 
         self.fw.append(["filter", "", "-A INPUT -d 224.0.0.18/32 -j ACCEPT"])
         self.fw.append(["filter", "", "-A INPUT -d 225.0.0.50/32 -j ACCEPT"])
-
+        self.fw.append(["filter", "", "-A INPUT -i %s -m state --state RELATED,ESTABLISHED -j ACCEPT" % self.dev])
+        self.fw.append(["filter", "", "-A INPUT -i lo -j ACCEPT"])
         self.fw.append(["filter", "", "-A INPUT -p icmp -j ACCEPT"])
         self.fw.append(["filter", "", "-A INPUT -i lo -j ACCEPT"])
 
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDhcp.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDhcp.py
index da9e6168ee0..839c2c275f3 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDhcp.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDhcp.py
@@ -60,7 +60,7 @@ def process(self):
 
         # We restart DNSMASQ every time the configure.py is called in order to avoid lease problems.
         if not self.cl.is_redundant() or self.cl.is_master():
-            CsHelper.service("dnsmasq", "restart")
+            CsHelper.execute2("service dnsmasq restart")
 
     def configure_server(self):
         # self.conf.addeq("dhcp-hostsfile=%s" % DHCP_HOSTS)
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsLoadBalancer.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsLoadBalancer.py
index d8f39dcd24a..8c178ca00cd 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsLoadBalancer.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsLoadBalancer.py
@@ -71,14 +71,15 @@ def _configure_firewall(self, add_rules, remove_rules, stat_rules):
             port = path[1]
             firewall.append(["filter", "", "-A INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)])
 
-        for rules in remove_rules:
+        for rules in stat_rules:
             path = rules.split(':')
             ip = path[0]
             port = path[1]
-            firewall.append(["filter", "", "-D INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)])
+            firewall.append(["filter", "", "-A INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)])
 
-        for rules in stat_rules:
+        for rules in remove_rules:
             path = rules.split(':')
             ip = path[0]
             port = path[1]
-            firewall.append(["filter", "", "-A INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)])
+            if ["filter", "", "-A INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)] in firewall:
+                firewall.remove(["filter", "", "-A INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)])
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsNetfilter.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsNetfilter.py
index 80b930e3fb6..c186eecf640 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsNetfilter.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsNetfilter.py
@@ -15,10 +15,12 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+from __future__ import print_function
+
 import CsHelper
-from pprint import pprint
-from CsDatabag import CsDataBag, CsCmdLine
+from CsDatabag import CsCmdLine
 import logging
+from cs_iptables_save import Tables
 
 
 class CsChain(object):
@@ -81,6 +83,7 @@ class CsNetfilters(object):
 
     def __init__(self, load=True):
         self.rules = []
+        self.iptablerules = []
         self.table = CsTable()
         self.chain = CsChain()
         if load:
@@ -91,7 +94,10 @@ def get_all_rules(self):
             if i.startswith('*'):  # Table
                 self.table.add(i[1:])
             if i.startswith(':'):  # Chain
-                self.chain.add(self.table.last(), i[1:].split(' ')[0])
+                string = i[1:].split(' ')[0]
+                cmd = "iptables -t %s -N %s" % (self.table.last(), string)
+                self.iptablerules.append(cmd)
+                self.chain.add(self.table.last(), string)
             if i.startswith('-A'):  # Rule
                 self.chain.add_rule(i.split()[1])
                 rule = CsNetfilter()
@@ -125,22 +131,25 @@ def has_rule(self, new_rule):
     def get_unseen(self):
         del_list = [x for x in self.rules if x.unseen()]
         for r in del_list:
-            cmd = "iptables -t %s %s" % (r.get_table(), r.to_str(True))
-            logging.debug("unseen cmd:  %s ", cmd)
-            CsHelper.execute(cmd)
-            # print "Delete rule %s from table %s" % (r.to_str(True), r.get_table())
+            self.delete(r)
             logging.info("Delete rule %s from table %s", r.to_str(True), r.get_table())
 
     def compare(self, list):
         """ Compare reality with what is needed """
-        # PASS 1:  Ensure all chains are present
+        for c in self.chain.get("filter"):
+            # Ensure all inbound/outbound chains have a default drop rule
+            if c.startswith("ACL_INBOUND") or c.startswith("ACL_OUTBOUND"):
+                list.append(["filter", "", "-A %s -j DROP" % c])
+        # PASS 1:  Ensure all chains are present and cleanup unused rules.
         for fw in list:
             new_rule = CsNetfilter()
             new_rule.parse(fw[2])
             new_rule.set_table(fw[0])
-            self.add_chain(new_rule)
+            self.has_rule(new_rule)
+
+        self.del_standard()
+        self.get_unseen()
 
-        ruleSet = set()
         # PASS 2: Create rules
         for fw in list:
             tupledFw = tuple(fw)
@@ -154,36 +163,33 @@ def compare(self, list):
             if isinstance(fw[1], int):
                 new_rule.set_count(fw[1])
 
-            rule_chain = new_rule.get_chain()
-
-            logging.debug("Checking if the rule already exists: rule=%s table=%s chain=%s", new_rule.get_rule(), new_rule.get_table(), new_rule.get_chain())
-            if self.has_rule(new_rule):
-                logging.debug("Exists: rule=%s table=%s", fw[2], new_rule.get_table())
-            else:
-                # print "Add rule %s in table %s" % ( fw[2], new_rule.get_table())
-                logging.info("Add: rule=%s table=%s", fw[2], new_rule.get_table())
-                # front means insert instead of append
-                cpy = fw[2]
-                if fw[1] == "front":
-                    cpy = cpy.replace('-A', '-I')
-                if isinstance(fw[1], int):
-                    # if the rule is for ACLs, we want to insert them in order, right before the DROP all
-                    if rule_chain.startswith("ACL_INBOUND") or rule_chain.startswith("ACL_OUTBOUND"):
-                        rule_count = self.chain.get_count(rule_chain)
-                        cpy = cpy.replace("-A %s" % new_rule.get_chain(), '-I %s %s' % (new_rule.get_chain(), rule_count))
-                    else:
-                        cpy = cpy.replace("-A %s" % new_rule.get_chain(), '-I %s %s' % (new_rule.get_chain(), fw[1]))
-                CsHelper.execute("iptables -t %s %s" % (new_rule.get_table(), cpy))
-                ruleSet.add(tupledFw)
-                self.chain.add_rule(rule_chain)
-        self.del_standard()
-        self.get_unseen()
+            logging.info("Add: rule=%s table=%s", fw[2], new_rule.get_table())
+            # front means insert instead of append
+            cpy = fw[2]
+            if fw[1] == "front":
+                cpy = cpy.replace('-A', '-I')
+            if isinstance(fw[1], int):
+                cpy = cpy.replace("-A %s" % new_rule.get_chain(), '-I %s %s' % (new_rule.get_chain(), fw[1]))
+
+            self.iptablerules.append("iptables -t %s %s" % (new_rule.get_table(), cpy))
+        self.apply_rules()
+
+    def apply_rules(self):
+        s = []
+        for r in self.iptablerules:
+            r.replace('  ', ' ')  # Remove duplicate spaces
+            if r not in s:
+                s.append(r)
 
-    def add_chain(self, rule):
-        """ Add the given chain if it is not already present """
-        if not self.has_chain(rule.get_table(), rule.get_chain()):
-            CsHelper.execute("iptables -t %s -N %s" % (rule.get_table(), rule.get_chain()))
-            self.chain.add(rule.get_table(), rule.get_chain())
+        chains = Tables(s)
+        chains.table_printout()
+
+        # COMMIT all rules.
+        result = CsHelper.execute("iptables-restore < /tmp/rules.save")
+        if result:
+            logging.info("iptables-restore result: %s", result)
+        else:
+            logging.info("iptables-restore result: success!")
 
     def del_standard(self):
         """ Del rules that are there but should not be deleted
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs_iptables_save.py b/systemvm/patches/debian/config/opt/cloud/bin/cs_iptables_save.py
new file mode 100644
index 00000000000..54a7502018e
--- /dev/null
+++ b/systemvm/patches/debian/config/opt/cloud/bin/cs_iptables_save.py
@@ -0,0 +1,393 @@
+#!/usr/bin/python
+#
+# -*- coding: utf-8 -*-
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""
+iptables_converter.py:
+    convert iptables commands within a script
+    into a correspondig iptables-save script
+
+    default filename to read is rules, to read some other
+        file, append: -s filename
+
+    default output is written to stdout, for writing
+        to some file, append: -d filename
+
+Author:     Johannes Hubertz <jo...@hubertz.de>
+Date:       2017-11-16
+Version:    0.9.10
+License:    GNU General Public License version 3 or later
+            Apache License Version 2.0
+
+Have Fun!
+"""
+
+from __future__ import print_function
+
+try:
+    from collections import UserDict
+except ImportError:
+    from UserDict import UserDict
+from optparse import OptionParser
+import re
+import os
+import sys
+
+
+class ConverterError(Exception):
+    pass
+
+
+class Chains(UserDict):
+    """ chains are grouped in iptables
+
+    :param str name: chain group name, 'filter', 'nat', ...
+    :param list tables: list of chains
+    :param bool sloppy: needs '-N'(default) or not
+
+    :return: object representing chain group
+    :rtype: Chains
+    :raises ConverterError: on some illegal conditions
+    """
+
+    def __init__(self, name, tables, sloppy=False):
+        """ init Chains object
+        """
+        UserDict.__init__(self)
+        self.name = name
+        self.tables = tables
+        self.predef = tables
+        self.sloppy = sloppy
+        self.reset()  # name, tables)
+
+    def put_into_fgr(self, content):
+        """ fill this line into this tabular
+
+        :param str content: one line of inputfile
+        :return: None
+        :raises ConverterError: on some illegal conditions
+        """
+        self.length += 1
+        if len(content) == 0:
+            return
+        elements = content.split()
+        action = elements[0]
+        if "-t" in action:
+            elements.pop(0)  # remove 1st: -t
+            fname = elements.pop(0)
+            legals = ["filter", "nat", "raw", "mangle"]
+            if fname not in legals:
+                msg = "Valid is one of %s, got: %s" % (legals, fname)
+                raise ConverterError(msg)
+            action = elements[0]
+            content = ""                       # rebuild content from here
+            for elem in elements:
+                content = content + elem + " "
+            if len(elements) > 1:
+                chain_name = elements[1]
+        if "-F" in action:
+            self.reset()
+            return
+        if "-P" in action:
+            elements.pop(0)
+            cha = elements.pop(0)
+            new = elements.pop(0)
+            if new not in ["ACCEPT", "DROP", "REJECT"]:
+                msg = "Illegal policy: % s" % (new)
+                raise ConverterError(msg)
+            self.poli[cha] = new
+            return
+        if "-X" in action:
+            predef = ['INPUT', 'FORWARD', 'OUTPUT',
+                      'PREROUTING', 'POSTROUTING']
+            rem_chain_name = elements.pop(1)
+            if rem_chain_name in predef:
+                msg = "Cannot remove predefined chain"
+                raise ConverterError(msg)
+            if rem_chain_name in self.data:
+                self.data[rem_chain_name] = []        # empty list
+                self.poli[rem_chain_name] = "-"       # empty policy, no need
+                self.data.pop(rem_chain_name)
+            return
+        if "-N" in action:
+            new_chain_name = elements.pop(1)
+            existing = self.data.keys()
+            if new_chain_name in existing:
+                msg = "Chain %s already exists" % (new_chain_name)
+                raise ConverterError(msg)
+            self.data[new_chain_name] = []        # empty list
+            self.poli[new_chain_name] = "-"       # empty policy, no need
+            return
+        if "-I" in action:
+            chain_name = elements[1]
+            existing = self.data.keys()
+            if chain_name not in existing:
+                msg = "invalid chain name: %s" % (chain_name)
+                if not self.sloppy:
+                    raise ConverterError(msg)
+                else:
+                    new_chain_name = elements[1]
+                    self.data[new_chain_name] = []
+                    self.poli[new_chain_name] = '-'
+            stuff = self.data[chain_name]
+            if len(stuff) > 0:
+                stuff.insert(0, content)
+            else:
+                msg = "Empty chain %s allows append only!" % (chain_name)
+                raise ConverterError(msg)
+            self.data[chain_name] = stuff
+            return
+        if "-A" in action:
+            chain_name = elements[1]
+            existing = self.data.keys()
+            if chain_name not in existing:
+                msg = "invalid chain name: %s" % (chain_name)
+                if not self.sloppy:
+                    raise ConverterError(msg)
+                else:
+                    new_chain_name = elements[1]
+                    self.data[new_chain_name] = []
+                    self.poli[new_chain_name] = '-'
+            stuff = self.data[chain_name]
+            stuff.append(content)
+            self.data[chain_name] = stuff
+            return
+        msg = "Unknown filter command in input:" + content
+        raise ConverterError(msg)
+
+    def reset(self):
+        """ action method for iptables -F
+        """
+        self.poli = {}               # empty dict
+        self.length = 0
+        self.policy = "-"
+        for tabular in self.tables:
+            self.data[tabular] = []
+            self.poli[tabular] = "ACCEPT"
+
+
+class Tables(UserDict):
+    """ some chaingroups in tables are predef: filter, nat, mangle, raw
+
+    :param str destfile: which file or pathname is to be written
+    :param str sourcefile: which file or pathname is to be read
+    :param bool sloppy: '-N' is needed(default) or not
+    :param int ipversion: 4(default) or 6
+
+    :return: Tables after read sourcefile written into destfile
+    :rtype: Tables
+
+    :raises ConverterError: on some illegal conditions
+    """
+
+    def __init__(self,
+                 destfile,
+                 sourcefile="reference-one",
+                 sloppy=False,
+                 ipversion=4
+                 ):
+        """init Tables Object is easy going"""
+        UserDict.__init__(self)
+        self.destfile = destfile
+        self.sourcefile = sourcefile
+        self.sloppy = sloppy
+        self.linecounter = 0
+        self.tblctr = 0
+        self.patterns = ""
+        self.reset(sourcefile, ipversion)
+
+    def reset(self, sourcefile, ipversion):
+        """all predefined Chains aka lists are setup as new here
+
+        :param str sourcefile: file to be read
+        :param int ipversion: 4 or 6
+
+        :return: None
+        """
+        self.patterns = ['^iptables', '^/sbin/iptables', ]
+        if ipversion == 6:
+            self.patterns = ['^ip6tables', '^/sbin/ip6tables', ]
+
+        filt = ["INPUT", "FORWARD", "OUTPUT"]
+        filters = Chains("filter", filt, self.sloppy)
+
+        mang = ["PREROUTING", "INPUT", "FORWARD", "OUTPUT", "POSTROUTING", ]
+        mangle = Chains("mangle", mang, self.sloppy)
+
+        # kernel 2.6.32 has no INPUT in NAT!
+        nats = ["PREROUTING", "OUTPUT", "POSTROUTING"]
+        nat = Chains("nat", nats, self.sloppy)
+
+        raws = ["PREROUTING", "OUTPUT", ]
+        raw = Chains("raw", raws, self.sloppy)
+
+        self.data["filter"] = filters
+        self.data["mangle"] = mangle
+        self.data["nat"] = nat
+        self.data["raw"] = raw
+        if len(sourcefile) > 0:
+            self.linecounter = self.read_file(sourcefile)
+
+    def table_printout(self):
+        """printout nonempty tabulars in fixed sequence"""
+        self.destfile.write("# generated from: %s\n" % (self.sourcefile))
+        for key in ["raw", "nat", "mangle", "filter"]:
+            count = self.data[key].length
+            if count > -1:
+                self.destfile.write("*%s\n" % (self.data[key].name))
+                for chain in self.data[key].keys():
+                    poli = self.data[key].poli[chain]
+                    self.destfile.write(":%s %s [0:0]\n" % (chain, poli))
+                for chain in self.data[key].values():
+                    for elem in chain:
+                        self.destfile.write(elem)
+                        self.destfile.write('\n')
+                self.destfile.write("COMMIT\n")
+
+    def put_into_tables(self, line):
+        """put line into matching Chains-object
+
+        :param line: one line of inputfile
+        :return: None
+        """
+        elements = line.split()
+        elements.pop(0)                     # we always know, it's iptables
+        rest = ""
+        for elem in elements:               # remove redirects and the like
+            if ">" not in elem:
+                rest = rest + elem + " "    # string again with single blanks
+        fam = "filter"
+        if "-t nat" in line:                # nat filter group
+            fam = "nat"
+        elif "-t mangle" in line:           # mangle filter group
+            fam = "mangle"
+        elif "-t raw" in line:              # raw filter group
+            fam = "raw"
+        fam_dict = self.data[fam]           # select the group dictionary
+        fam_dict.put_into_fgr(rest)         # do action thers
+
+    def read_file(self, sourcefile):
+        """ open file or error
+
+        :param sourcefile: file or pathname of file to be read
+
+        :return: file_descriptor
+        :raises ConverterError: on IOError
+        """
+        try:
+            with open(sourcefile, 'r') as file_descriptor:
+                return self.read(file_descriptor)
+        except IOError as err:
+            raise ConverterError(str(err))
+
+    def read(self, file_descriptor):
+        """read data from file like object into Tables-object
+
+        :param file_descriptor: filedescriptor of file to be read
+
+        :return: None
+        :raises ConverterError: on some illegal conditions
+        """
+        self.linecounter = 0
+        self.tblctr = 0
+        try:
+            for this_line in file_descriptor:
+                line = str(this_line.strip())
+                self.linecounter += 1
+                if line.startswith('#'):
+                    continue
+                for element in ['\$', '\(', '\)', ]:
+                    if re.search(element, line):
+                        mstart = "Line %d:\n%s\nplain files only, " % \
+                            (self.linecounter, line)
+                        if element in ['\(', '\)', ]:
+                            merr = "unable to convert shell functions, abort"
+                        else:
+                            merr = "unable to resolve shell variables, abort"
+                        msg = mstart + merr
+                        raise ConverterError(msg)
+                for pattern in self.patterns:
+                    if re.search(pattern, line):
+                        self.tblctr += 1
+                        self.put_into_tables(line)
+        except ValueError as err:
+            raise ConverterError(str(err))
+
+
+def my_options():
+    """ commandline options assembly
+
+    :returns: :class: OptionParser
+    """
+    version = "version 0.9.10"
+    usage = "usage:  %prog --help | -h \n\n\t%prog: " + version
+    usage = usage + "\tHave Fun!"
+    parser = OptionParser(usage)
+    parser.disable_interspersed_args()
+    parser.add_option("-d", "", dest="destfile",
+                      type="string",
+                      help="output filename, default: stdout\n")
+    parser.add_option("-s", "", dest="sourcefile",
+                      type="string",
+                      help="file with iptables commands, default: rules\n")
+    parser.add_option("--sloppy", "", dest="sloppy",
+                      action="store_true", default=False,
+                      help="-N name-of-userchain is inserted automatically,\n"
+                           "by default -N is neccessary in input\n")
+    (options, _) = parser.parse_args()
+    return options
+
+
+def main():
+    """ main parses options, filnames and the like
+    option -s needs input-filename to be read,
+    if it is not given, it defaults to: rules.
+    option -d needs output-filename to be written,
+    if it is not given, it defaults to: sys.stdout
+    """
+
+    options = my_options()
+
+    if options.sourcefile is None:
+        options.sourcefile = "rules"
+    sourcefile = options.sourcefile
+
+    if options.destfile is not None:
+        destfile = open(options.destfile, 'w')
+    else:
+        destfile = sys.stdout
+
+    ipversion = 4
+    if os.path.basename(sys.argv[0]).startswith("ip6"):
+        ipversion = 6
+
+    try:
+        chains = Tables(destfile,
+                        sourcefile,
+                        options.sloppy,
+                        ipversion=ipversion
+                        )
+        chains.table_printout()
+    except ConverterError as err:
+        print(str(err), file=sys.stderr)
+        return 1
+    finally:
+        if destfile != sys.stdout:
+            destfile.close()
+    return 0


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services