diff --git a/systemvm/patches/debian/config/opt/cloud/bin/configure.py b/systemvm/patches/debian/config/opt/cloud/bin/configure.py index 7f0df5be0df2..38335e0322b5 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 43cd6396587a..eabd9a4f82fa 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 da9e6168ee0f..839c2c275f3d 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 d8f39dcd24a2..8c178ca00cd7 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 80b930e3fb6b..c186eecf6409 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 000000000000..54a7502018e5 --- /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 +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