Restore iptables at once using iptables-restore instead of calling iptables numerous times

This commit is contained in:
Boris Schrijver 2016-02-01 15:58:27 +01:00
parent 0f75042566
commit b857f79fcb
5 changed files with 112 additions and 153 deletions

View File

@ -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
@ -281,7 +270,7 @@ class CsAcl(CsDataBag):
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 process(self):
for item in self.dbag:
@ -495,7 +484,7 @@ class CsSite2SiteVpn(CsDataBag):
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)])
@ -804,7 +793,7 @@ class CsForwardingRules(CsDataBag):
rule['internal_ip'],
self.portsToString(rule['internal_ports'], '-')
)
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']),

View File

@ -15,9 +15,8 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from CsDatabag import CsDataBag, CsCmdLine
from CsDatabag import CsDataBag
from CsApp import CsApache, CsDnsmasq, CsPasswdSvc
import CsHelper
import logging
from netaddr import IPAddress, IPNetwork
import CsHelper
@ -198,7 +197,7 @@ class CsInterface:
return self.get_attr("add")
def to_str(self):
pprint(self.address)
print(self.address)
class CsDevice:
@ -383,8 +382,6 @@ class CsIP:
self.fw.append(["mangle", "front",
"-A FIREWALL_%s " % self.address['public_ip'] +
"-m state --state RELATED,ESTABLISHED -j ACCEPT"])
self.fw.append(["mangle", "",
"-A FIREWALL_%s DROP" % self.address['public_ip']])
self.fw.append(["mangle", "",
"-A VPN_%s -m state --state RELATED,ESTABLISHED -j ACCEPT" % self.address['public_ip']])
self.fw.append(["mangle", "",
@ -402,8 +399,7 @@ class CsIP:
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"])
@ -446,6 +442,13 @@ class CsIP:
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"])
if self.get_type() in ["guest"]:
self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" %
(self.address['network'], self.dev, self.dev)])
@ -484,10 +487,6 @@ class CsIP:
])
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 +494,7 @@ class CsIP:
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,9 +503,11 @@ class CsIP:
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 eth0 -p tcp -m tcp --dport 3922 -m state --state NEW,ESTABLISHED -j ACCEPT"])
self.fw.append(["filter", "", "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT"])
self.fw.append(["filter", "", "-P INPUT DROP"])
self.fw.append(["filter", "", "-P FORWARD DROP"])

View File

@ -71,14 +71,16 @@ class CsLoadBalancer(CsDataBag):
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:
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)])
for rules in stat_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)])
for rules in remove_rules:
path = rules.split(':')
ip = path[0]
port = path[1]
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)])

View File

@ -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 @@ class CsNetfilters(object):
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,10 +131,7 @@ class CsNetfilters(object):
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):
@ -137,12 +140,16 @@ class CsNetfilters(object):
# 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
# 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()
# PASS 2: Create rules
for fw in list:
new_rule = CsNetfilter()
@ -151,28 +158,32 @@ class CsNetfilters(object):
if isinstance(fw[1], int):
new_rule.set_count(fw[1])
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):
cpy = cpy.replace("-A %s" % new_rule.get_chain(), '-I %s %s' % (new_rule.get_chain(), fw[1]))
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]))
CsHelper.execute("iptables -t %s %s" % (new_rule.get_table(), cpy))
self.del_standard()
self.get_unseen()
self.iptablerules.append("iptables -t %s %s" % (new_rule.get_table(), cpy))
self.apply_rules()
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())
def apply_rules(self):
s = []
for r in self.iptablerules:
if r not in s:
s.append(r)
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

View File

@ -19,14 +19,15 @@ License: GNU General Public License version 3 or later
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 sys
import logging
class ConverterError():
@ -97,8 +98,8 @@ class Chains(UserDict):
new_chain_name = liste.pop(1)
existing = self.data.keys()
if new_chain_name in existing:
msg = "Chain %s already exists" % (new_chain_name)
raise ValueError(msg)
logging.debug("Chain %s already exists" % new_chain_name)
return
self.data[new_chain_name] = [] # empty list
self.poli[new_chain_name] = "-" # empty policy, no need
return
@ -106,22 +107,18 @@ class Chains(UserDict):
chain_name = liste[1]
existing = self.data.keys()
if chain_name not in existing:
msg = "invalid chain name: %s" % (chain_name)
raise ValueError(msg)
self.data[chain_name] = []
self.poli[chain_name] = "-"
kette = self.data[chain_name]
if len(kette) > 0:
kette.insert(0, content)
else:
msg = "Empty chain %s allows append only!" % (chain_name)
raise ValueError(msg)
kette.insert(0, content.replace("-I", "-A"))
self.data[chain_name] = kette
return
if "-A" in action: # or "-I" in action:
chain_name = liste[1]
existing = self.data.keys()
if chain_name not in existing:
msg = "invalid chain name: %s" % (chain_name)
raise ValueError(msg)
self.data[chain_name] = []
self.poli[chain_name] = "-"
kette = self.data[chain_name]
kette.append(content)
self.data[chain_name] = kette
@ -147,12 +144,12 @@ class Tables(UserDict):
some chaingroups in tables are predef: filter, nat, mangle, raw
"""
def __init__(self, fname="reference-one"):
def __init__(self, rules):
"""init Tables Object is easy going"""
UserDict.__init__(self)
self.reset(fname)
self.reset(rules)
def reset(self, fname):
def reset(self, rules):
"""all predefined Chains aka lists are setup as new here"""
filter = Chains("filter", ["INPUT", "FORWARD", "OUTPUT"])
@ -168,22 +165,23 @@ class Tables(UserDict):
self.data["mangle"] = mangle
self.data["nat"] = nat
self.data["raw"] = raw
if len(fname) > 0:
self.linecounter = self.read_file(fname)
if rules is not None:
self.read_file(rules)
def table_printout(self):
"""printout nonempty tabulars in fixed sequence"""
for key in ["raw", "nat", "mangle", "filter"]:
len = self.data[key].length
if len > -1:
print("*%s" % (self.data[key].name))
for chain in self.data[key].keys():
poli = self.data[key].poli[chain]
print(":%s %s [0:0]" % (chain, poli))
for chain in self.data[key].values():
for elem in chain:
print(elem)
print("COMMIT")
with open("/tmp/rules.save", 'w') as f:
for key in ["raw", "nat", "mangle", "filter"]:
len = self.data[key].length
if len > -1:
print("*%s" % (self.data[key].name), file=f)
for chain in self.data[key].keys():
poli = self.data[key].poli[chain]
print(":%s %s [0:0]" % (chain, poli), file=f)
for chain in self.data[key].values():
for elem in chain:
print(elem, file=f)
print("COMMIT", file=f)
def put_into_tables(self, line):
"""put line into matching Chains-object"""
@ -204,64 +202,26 @@ class Tables(UserDict):
fam_dict = self.data[fam] # select the group dictionary
fam_dict.put_into_fgr(rest) # do action thers
def read_file(self, fname):
def read_file(self, rules):
"""read file into Tables-object"""
self.linecounter = 0
self.tblctr = 0
try:
fil0 = open(fname, 'r')
for zeile in fil0:
line = str(zeile.strip())
self.linecounter += 1
if line.startswith('#'):
continue
for element in ['\$', '\(', '\)', ]:
if re.search(element, line):
m1 = "Line %d:\n%s\nplain files only, " % \
(self.linecounter, line)
if element in ['\(', '\)', ]:
m2 = "unable to convert shell functions, abort"
else:
m2 = "unable to resolve shell variables, abort"
msg = m1 + m2
raise ConverterError(msg)
for muster in ["^/sbin/iptables ", "^iptables "]:
if re.search(muster, line):
self.tblctr += 1
self.put_into_tables(line)
fil0.close()
except ValueError as err:
print (fname + ": "), err
sys.exit(1)
except IOError as err:
print(fname + ": "), err.strerror
sys.exit(1)
if not fname == "reference-one":
print("# generated from: %s" % (fname))
def main():
"""
main parses options, filnames and the like
one option (-s) may be given: input-filename
if none given, it defaults to: rules
"""
usage = "usage: %prog --help | -h \n\n\t%prog: version 0.9.8"
usage = usage + "\tHave Fun!"
parser = OptionParser(usage)
parser.disable_interspersed_args()
parser.add_option("-s", "", dest="sourcefile",
help="file with iptables commands, default: rules\n")
(options, args) = parser.parse_args()
hlp = "\n\tplease use \"--help\" as argument, abort!\n"
if options.sourcefile is None:
options.sourcefile = "rules"
sourcefile = options.sourcefile
chains = Tables(sourcefile)
chains.table_printout()
if __name__ == "__main__":
main()
sys.exit(0)
for zeile in rules:
line = str(zeile.strip())
self.linecounter += 1
if line.startswith('#'):
continue
for element in ['\$', '\(', '\)', ]:
if re.search(element, line):
m1 = "Line %d:\n%s\nplain files only, " % \
(self.linecounter, line)
if element in ['\(', '\)', ]:
m2 = "unable to convert shell functions, abort"
else:
m2 = "unable to resolve shell variables, abort"
msg = m1 + m2
raise ConverterError(msg)
for muster in ["^/sbin/iptables ", "^iptables "]:
if re.search(muster, line):
self.tblctr += 1
self.put_into_tables(line)