mirror of https://github.com/apache/cloudstack.git
First part of some serious refactoring
The problem is that teh convergence model does not works as it currently is Firewall rules will get added but not deleted This builds a table of firewall rules that need to be present The new CsNetfilter class will then do: 1. Add rules that are not present 2. Delete any that were not explicitly in the add list WIP
This commit is contained in:
parent
e323d63867
commit
c6d99a45a2
|
|
@ -1,4 +1,77 @@
|
|||
import CsHelper
|
||||
from pprint import pprint
|
||||
|
||||
class Netfilter(object):
|
||||
class CsChain(object):
|
||||
|
||||
def __init__(self):
|
||||
self.chain = {}
|
||||
|
||||
def add(self, table, chain):
|
||||
if not table in self.chain.keys():
|
||||
self.chain.setdefault(table, []).append( chain )
|
||||
else:
|
||||
self.chain[table].append(chain)
|
||||
|
||||
def get(self, table):
|
||||
return self.chain[table]
|
||||
|
||||
class CsTable(object):
|
||||
|
||||
def __init__(self):
|
||||
self.table = []
|
||||
self.last_added = ''
|
||||
|
||||
def add(self, name):
|
||||
if not name in self.table:
|
||||
self.table.append(name)
|
||||
self.last_added = name
|
||||
|
||||
def get(self):
|
||||
return self.table
|
||||
|
||||
def last(self):
|
||||
return self.last_added
|
||||
|
||||
class CsNetfilters(object):
|
||||
|
||||
def __init__(self):
|
||||
self.rules = []
|
||||
self.table = CsTable()
|
||||
self.chain = CsChain()
|
||||
self.get_all_rules()
|
||||
|
||||
def get_all_rules(self):
|
||||
for i in CsHelper.execute("iptables-save"):
|
||||
if i.startswith('*'): # Table
|
||||
self.table.add(i[1:])
|
||||
if i.startswith(':'): # Chain
|
||||
self.chain.add(self.table.last(), i[1:].split(' ')[0])
|
||||
if i.startswith('-A'): # Rule
|
||||
rule = CsNetfilter()
|
||||
rule.parse(i)
|
||||
self.save(rule)
|
||||
|
||||
def save(self,rule):
|
||||
self.rules.append(rule)
|
||||
|
||||
def get(self):
|
||||
return self.rules
|
||||
|
||||
def hasTable(self, table):
|
||||
return table in self.table.get()
|
||||
|
||||
def hasChain(self, table, chain):
|
||||
return chain in self.chain.get(table)
|
||||
|
||||
class CsNetfilter(object):
|
||||
|
||||
def parse(self, rule):
|
||||
rule.replace('! -', '!_-')
|
||||
bits = rule.split(' ')
|
||||
self.rule = dict(zip(bits[0::2], bits[1::2])).iteritems()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
t = CsNetfilters()
|
||||
print t.hasTable('mangle');
|
||||
print t.hasChain('mangle', 'PREROUTING');
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ import shutil
|
|||
import os.path
|
||||
from cs_ip import merge
|
||||
import CsHelper
|
||||
import CsNetfilter
|
||||
|
||||
fw = []
|
||||
|
||||
class CsFile:
|
||||
""" File editors """
|
||||
|
|
@ -230,11 +233,7 @@ class CsApp:
|
|||
if self.type == "guest":
|
||||
gn = CsGuestNetwork(self.dev)
|
||||
self.domain = gn.get_domain()
|
||||
|
||||
class CsAcl(CsApp):
|
||||
"""
|
||||
Manage network acls
|
||||
"""
|
||||
global fw
|
||||
|
||||
class CsPasswdSvc(CsApp):
|
||||
"""
|
||||
|
|
@ -242,11 +241,9 @@ class CsPasswdSvc(CsApp):
|
|||
"""
|
||||
|
||||
def setup(self):
|
||||
cmds = "-A INPUT -i %s -d %s -p %s -m %s --state %s --dport %s -j %s"
|
||||
slist = [ self.dev, self.ip, "tcp", "state", "NEW", "8080", "ACCEPT" ]
|
||||
|
||||
firewall = CsIpTables(self.dev)
|
||||
firewall.change_rule("", slist, cmds)
|
||||
fw.append(["", "front",
|
||||
"-A INPUT -i %s -d %s -p tcp -m tcp --state NEW --dport 8080 -j ACCEPT" % (self.dev, self.ip)
|
||||
])
|
||||
|
||||
proc = CsProcess(['/opt/cloud/bin/vpc_passwd_server', self.ip])
|
||||
if not proc.find():
|
||||
|
|
@ -277,36 +274,27 @@ class CsApache(CsApp):
|
|||
if file.is_changed():
|
||||
CsHelper.service("apache2", "restart")
|
||||
|
||||
cmds = "-A INPUT -i %s -d %s -p %s -m %s --state %s --dport %s -j %s"
|
||||
slist = [ self.dev, self.ip, "tcp", "state", "NEW", "80", "ACCEPT" ]
|
||||
|
||||
firewall = CsIpTables(self.dev)
|
||||
firewall.change_rule("", slist, cmds)
|
||||
|
||||
fw.append(["", "front",
|
||||
"-A INPUT -i %s -d %s -p tcp -m state --state NEW --dport 80 -j ACCEPT" % (self.dev, self.ip)
|
||||
])
|
||||
|
||||
class CsDnsmasq(CsApp):
|
||||
""" Set up dnsmasq """
|
||||
|
||||
def add_firewall_rules(self, method):
|
||||
def add_firewall_rules(self):
|
||||
""" Add the necessary firewall rules
|
||||
This is problamatic because the current logic cannot delete them
|
||||
(In a convergence model)
|
||||
|
||||
We will need to store some state about what "used" to be there
|
||||
"""
|
||||
firewall = CsIpTables(self.dev)
|
||||
fw.append(["", "front"
|
||||
"-A INPUT -i %s -p udp -m udp --dport 67 -j ACCEPT" % self.dev
|
||||
])
|
||||
|
||||
cmds = "-A INPUT -i %s -p %s -m %s --dport %s -j %s"
|
||||
slist = [ self.dev, "udp", "udp", "67", "ACCEPT" ]
|
||||
firewall.change_rule("", slist, cmds)
|
||||
fw.append(["", "front"
|
||||
"-A INPUT -i %s -d %s -p udp -m udp --dport 53 -j ACCEPT" % (self.dev, self.ip)
|
||||
])
|
||||
|
||||
cmds = "-A INPUT -i %s -d %s -p %s -m %s --dport %s -j %s"
|
||||
slist = [ self.dev, self.ip, "udp", "udp", "53", "ACCEPT" ]
|
||||
firewall.change_rule("", slist, cmds)
|
||||
|
||||
cmds = "-A INPUT -i %s -d %s -p %s -m %s --dport %s -j %s"
|
||||
slist = [ self.dev, self.ip, "tcp", "tcp", "53", "ACCEPT" ]
|
||||
firewall.change_rule("", slist, cmds)
|
||||
fw.append(["", "front"
|
||||
"-A INPUT -i %s -d %s -p tcp -m tcp --dport 53 -j ACCEPT" % ( self.dev, self.ip )
|
||||
])
|
||||
|
||||
def configure_server(self, method = "add"):
|
||||
file = CsFile("/etc/dnsmasq.d/cloud.conf")
|
||||
|
|
@ -352,6 +340,7 @@ class CsDevice:
|
|||
if dev != '':
|
||||
self.tableNo = dev[3]
|
||||
self.table = "Table_%s" % dev
|
||||
global fw
|
||||
|
||||
def configure_rp(self):
|
||||
"""
|
||||
|
|
@ -394,108 +383,11 @@ class CsDevice:
|
|||
if " DOWN " in i:
|
||||
cmd2 = "ip link set %s up" % self.dev
|
||||
CsHelper.execute(cmd2)
|
||||
CsIpTables(self.dev).set_connmark()
|
||||
cmd = "-A PREROUTING -i %s -m state --state NEW -j CONNMARK --set-mark 0x%s" % \
|
||||
(self.dev, "Table_%s" % self.tableNo)
|
||||
fw.append(["mangle", "", cmd])
|
||||
|
||||
|
||||
class CsIpTables:
|
||||
|
||||
""" Utility class
|
||||
All the bits and pieces needed for iptables operations
|
||||
"""
|
||||
def __init__(self, dev):
|
||||
self.dev = dev
|
||||
self.tableNo = dev[3]
|
||||
self.table = "Table_%s" % (dev)
|
||||
self.devChain = "ACL_INBOUND_%s" % (dev)
|
||||
|
||||
def set_connmark(self, method = "add"):
|
||||
""" Set connmark for device """
|
||||
slist = ["PREROUTING", self.dev, "state", "NEW", "CONNMARK", self.tableNo]
|
||||
if method == "add":
|
||||
cmds="-A %s -i %s -m %s --state %s -j %s --set-mark 0x%s"
|
||||
else:
|
||||
cmds="-D %s -i %s -m %s --state %s -j %s --set-mark 0x%s"
|
||||
self.change_rule("mangle", slist, cmds)
|
||||
|
||||
def set_accept(self, table, method = "add"):
|
||||
""" Add an accept rule
|
||||
First version - very simple - once I find out what the patterns
|
||||
are this will be refactored
|
||||
"""
|
||||
slist = [ self.devChain, "ACCEPT" ]
|
||||
if method == "add":
|
||||
cmds = "-A %s -j %s"
|
||||
else:
|
||||
cmds = "-D %s -j %s"
|
||||
self.change_rule( table, slist, cmds)
|
||||
|
||||
def set_forward(self, ip, method = "add"):
|
||||
""" set a forward to the device chain
|
||||
takes a CsIP object """
|
||||
slist = [ "FORWARD", self.dev, ip['network'], self.devChain ]
|
||||
if method == "add":
|
||||
cmds = "-A %s -o %s -d %s -j %s"
|
||||
else:
|
||||
cmds = "-D %s -o %s -d %s -j %s"
|
||||
self.change_rule('', slist, cmds)
|
||||
|
||||
def set_drop(self, method = "add"):
|
||||
""" Ensure the last rule is drop """
|
||||
slist = [ self.devChain, "DROP" ]
|
||||
if method == "add":
|
||||
cmds="-A %s -j %s"
|
||||
else:
|
||||
cmds="-D %s -j %s"
|
||||
self.change_rule('', slist, cmds)
|
||||
|
||||
def set_static_nat(self, ip, method = "add"):
|
||||
""" Add static nat to a device/ip combination
|
||||
Takes a CsIp object as its parameter
|
||||
"""
|
||||
slist = ["POSTROUTING", ip['network'], self.dev, "SNAT", ip['public_ip']]
|
||||
if method == "add":
|
||||
cmds ="-A %s -s %s -o %s -j %s --to-source %s"
|
||||
else:
|
||||
cmds ="-D %s -s %s -o %s -j %s --to-source %s"
|
||||
self.change_rule('nat', slist, cmds)
|
||||
|
||||
def set_preroute(self, ip, method):
|
||||
slist = [ "PREROUTING", "NEW", self.dev, ip['network'], ip['public_ip'], self.devChain ]
|
||||
cmds = "-A %s -m state --state %s -i %s -s %s ! -d %s -j %s"
|
||||
if method == "add":
|
||||
self.change_rule('mangle', slist, cmds)
|
||||
|
||||
def change_rule(self, table, slist, cmds):
|
||||
cmd = ''
|
||||
if not self.has_rule(table, slist):
|
||||
if table != '':
|
||||
cmd = "-t %s " % table
|
||||
cmd += cmds % tuple(slist)
|
||||
CsHelper.execute("iptables %s" % (cmd))
|
||||
logging.info("iptables %s", cmd)
|
||||
|
||||
def set_chain(self, table, method):
|
||||
""" Create a chain if it does not already exist """
|
||||
slist = [ self.devChain ]
|
||||
cmd = ''
|
||||
if not self.has_rule(table, slist):
|
||||
if table != '':
|
||||
cmd = "-t %s " % table
|
||||
cmd += "-N %s" % tuple(slist)
|
||||
CsHelper.execute("iptables %s" % (cmd))
|
||||
logging.info("iptables %s", cmd)
|
||||
|
||||
def has_rule(self, table, list):
|
||||
""" Check if a particular rule exists """
|
||||
cmd = "iptables-save "
|
||||
if table != "":
|
||||
cmd += "-t %s" % table
|
||||
for line in CsHelper.execute(cmd):
|
||||
matches = len([i for i in list if i in line])
|
||||
if matches == len(list):
|
||||
return True
|
||||
return False
|
||||
|
||||
class CsIP:
|
||||
|
||||
def __init__(self, dev):
|
||||
|
|
@ -552,16 +444,27 @@ class CsIP:
|
|||
route.add(self.address, method)
|
||||
# On deletion nw_type will no longer be known
|
||||
if self.get_type() in [ "guest" ]:
|
||||
devChain = "ACL_INBOUND_%s" % (self.dev)
|
||||
CsDevice(self.dev).configure_rp()
|
||||
CsIpTables(self.dev).set_static_nat(self.address, method)
|
||||
CsIpTables(self.dev).set_chain('', method)
|
||||
CsIpTables(self.dev).set_chain('mangle', method)
|
||||
CsIpTables(self.dev).set_accept('mangle', method)
|
||||
CsIpTables(self.dev).set_forward(self.address, method)
|
||||
CsIpTables(self.dev).set_drop(method)
|
||||
CsIpTables(self.dev).set_preroute(self.address, method)
|
||||
|
||||
fw.append(["nat", "",
|
||||
"-A POSTROUTING -s %s -o %s -j SNAT --to-source %s" % \
|
||||
(self.address['network'], self.dev, self.address['public_ip'])
|
||||
])
|
||||
fw.append(["", "", "-N %s" % devChain ])
|
||||
fw.append(["mangle", "", "-N %s" % devChain ])
|
||||
fw.append(["mangle", "", "-A %s -j ACCEPT" % devChain])
|
||||
|
||||
fw.append(["", "",
|
||||
"-A FORWARD -o %s -d %s -j %s" % (self.dev, self.address['network'], devChain)
|
||||
])
|
||||
fw.append(["", "", "-A DROP -j %s" % devChain])
|
||||
fw.append(["mangle", "",
|
||||
"-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s -j %s" % \
|
||||
(self.dev, self.address['network'], self.address['public_ip'], devChain)
|
||||
])
|
||||
dns = CsDnsmasq(self)
|
||||
dns.add_firewall_rules("add")
|
||||
dns.add_firewall_rules()
|
||||
dns.configure_server()
|
||||
app = CsApache(self)
|
||||
app.setup()
|
||||
|
|
@ -802,7 +705,7 @@ def main(argv):
|
|||
logging.basicConfig(filename='/var/log/cloud.log',
|
||||
level=logging.DEBUG,
|
||||
format='%(asctime)s %(message)s')
|
||||
|
||||
|
||||
db = dataBag()
|
||||
db.setKey("ips")
|
||||
db.load()
|
||||
|
|
@ -828,6 +731,7 @@ def main(argv):
|
|||
if CsDevice(dev).waitfordevice():
|
||||
ip.configure()
|
||||
CsPassword()
|
||||
pprint(fw)
|
||||
|
||||
metadata = CsVmMetadata()
|
||||
metadata.process()
|
||||
|
|
|
|||
Loading…
Reference in New Issue