From: Nicolas Emiliani Date: Sat, 10 Nov 2007 19:56:14 +0000 (-0300) Subject: Merge baryon.com.ar:workspace/pymin X-Git-Url: https://git.llucax.com/software/pymin.git/commitdiff_plain/6ed640af531e717da24d1dd423ce4f2df0fdec71?hp=3c717546f26524f438aeadc7776b57579400f7cb Merge baryon.com.ar:workspace/pymin Conflicts: config.py --- diff --git a/config.py b/config.py index 57d0f5a..b4c454d 100644 --- a/config.py +++ b/config.py @@ -10,31 +10,46 @@ pickle_path = join(base_path, 'pickle') config_path = join(base_path, 'config') class Root(Handler): - ip = IpHandler( - pickle_dir = join(pickle_path, 'ip'), - config_dir = join(config_path, 'ip')) + firewall = FirewallHandler( pickle_dir = join(pickle_path, 'firewall'), - config_dir = join(config_path, 'firewall')) + config_dir = '/tmp') + nat = NatHandler(pickle_dir = join(pickle_path, 'nat')) + + ppp = PppHandler( + pickle_dir = join(pickle_path, 'ppp'), + config_dir = { + 'pap-secrets': '/etc/ppp', + 'chap-secrets': '/etc/ppp', + 'options.X': '/etc/ppp', + 'nameX': '/etc/ppp/peers', + }) + + ip = IpHandler( + pickle_dir = join(pickle_path, 'ip'), + config_dir = join(config_path, 'ip')) + dns = DnsHandler( pickle_dir = join(pickle_path, 'dns'), config_dir = { - 'named.conf': join(config_path, 'dns'), - 'zoneX.zone': join(config_path, 'dns', 'zones'), + 'named.conf': '/etc', + 'zoneX.zone': '/var/lib/named', }) + dhcp = DhcpHandler( pickle_dir = join(pickle_path, 'dhcp'), - config_dir = join(config_path, 'dhcp')) - ppp = PppHandler( - pickle_dir = join(pickle_path, 'ppp'), - config_dir = join(config_path, 'ppp')) - vrrp = VrrpHandler( - pickle_dir = join(pickle_path, 'vrrp'), - config_dir = join(config_path, 'vrrp')) + config_dir = '/etc') + proxy = ProxyHandler( pickle_dir = join(pickle_path, 'proxy'), config_dir = join(config_path, 'proxy')) + + vrrp = VrrpHandler( + pickle_dir = join(pickle_path, 'vrrp'), + config_dir = join(config_path, 'vrrp'), + pid_dir = '/var/run') + qos = QoSHandler( pickle_dir = join(pickle_path, 'qos'), config_dir = join(config_path, 'qos')) diff --git a/pymin/eventloop.py b/pymin/eventloop.py index b6be5a1..86b8932 100644 --- a/pymin/eventloop.py +++ b/pymin/eventloop.py @@ -147,6 +147,7 @@ class EventLoop: # If we use a timer, we set up the signal if self.timer is not None: signal.signal(signal.SIGALRM, alarm_handler) + self.handle_timer() signal.alarm(self.timer) while True: try: diff --git a/pymin/services/ip/__init__.py b/pymin/services/ip/__init__.py index 560e2f5..0c0ea5f 100644 --- a/pymin/services/ip/__init__.py +++ b/pymin/services/ip/__init__.py @@ -8,7 +8,7 @@ from pymin.dispatcher import handler, HandlerError, Handler from pymin.services.util import Restorable, ConfigWriter, InitdHandler, \ TransactionalHandler, SubHandler, call, \ get_network_devices, ListComposedSubHandler, \ - DictComposedSubHandler + DictComposedSubHandler, Device, Address, ExecutionError __ALL__ = ('IpHandler',) @@ -105,16 +105,6 @@ class RouteHandler(ListComposedSubHandler): _comp_subhandler_attr = 'routes' _comp_subhandler_class = Route -class Address(Sequence): - def __init__(self, ip, netmask, broadcast=None): - self.ip = ip - self.netmask = netmask - self.broadcast = broadcast - def update(self, netmask=None, broadcast=None): - if netmask is not None: self.netmask = netmask - if broadcast is not None: self.broadcast = broadcast - def as_tuple(self): - return (self.ip, self.netmask, self.broadcast) class AddressHandler(DictComposedSubHandler): handler_help = u"Manage IP addresses" @@ -122,14 +112,6 @@ class AddressHandler(DictComposedSubHandler): _comp_subhandler_attr = 'addrs' _comp_subhandler_class = Address -class Device(Sequence): - def __init__(self, name, mac): - self.name = name - self.mac = mac - self.addrs = dict() - self.routes = list() - def as_tuple(self): - return (self.name, self.mac) class DeviceHandler(SubHandler): @@ -172,8 +154,7 @@ class IpHandler(Restorable, ConfigWriter, TransactionalHandler): _persistent_attrs = ('devices','hops') _restorable_defaults = dict( - devices=dict((dev, Device(dev, mac)) - for (dev, mac) in get_network_devices().items()), + devices=get_network_devices(), hops = list() ) @@ -196,34 +177,52 @@ class IpHandler(Restorable, ConfigWriter, TransactionalHandler): def _write_config(self): r"_write_config() -> None :: Execute all commands." for device in self.devices.values(): - call(self._render_config('route_flush', dict(dev=device.name)), shell=True) - call(self._render_config('ip_flush', dict(dev=device.name)), shell=True) + try: + call(self._render_config('route_flush', dict(dev=device.name)), shell=True) + except ExecutionError, e: + print e + try: + call(self._render_config('ip_flush', dict(dev=device.name)), shell=True) + except ExecutionError, e: + print e for address in device.addrs.values(): broadcast = address.broadcast if broadcast is None: broadcast = '+' - call(self._render_config('ip_add', dict( + try: + call(self._render_config('ip_add', dict( dev = device.name, addr = address.ip, netmask = address.netmask, + peer = address.peer, broadcast = broadcast, - ) - ), shell=True) + ) + ), shell=True) + except ExecutionError, e: + print e for route in device.routes: - call(self._render_config('route_add', dict( - dev = device.name, - net_addr = route.net_addr, - prefix = route.prefix, - gateway = route.gateway, - ) - ), shell=True) - + try: + call(self._render_config('route_add', dict( + dev = device.name, + net_addr = route.net_addr, + prefix = route.prefix, + gateway = route.gateway, + ) + ), shell=True) + except ExecutionError, e: + print e if self.hops: - call('ip route del default', shell=True) - call(self._render_config('hop', dict( - hops = self.hops, - ) - ), shell=True) + try: + call('ip route del default', shell=True) + except ExecutionError, e: + print e + try: + call(self._render_config('hop', dict( + hops = self.hops, + ) + ), shell=True) + except ExecutionError, e: + print e def handle_timer(self): @@ -235,7 +234,7 @@ class IpHandler(Restorable, ConfigWriter, TransactionalHandler): #add not registered devices for k,v in devices.items(): if k not in self.devices: - self.devices[k] = Device(k,v) + self.devices[k] = v #delete dead devices for k in self.devices.keys(): if k not in devices: diff --git a/pymin/services/ip/templates/ip_add b/pymin/services/ip/templates/ip_add index d6307b3..8f5cc15 100644 --- a/pymin/services/ip/templates/ip_add +++ b/pymin/services/ip/templates/ip_add @@ -1 +1,5 @@ -ip addr add dev ${dev} ${addr}/${netmask} broadcast ${broadcast} \ No newline at end of file +%if peer is None: +ip addr add dev ${dev} ${addr}/${netmask} broadcast ${broadcast} +%else: +ip addr add dev ${dev} ${addr} peer ${peer} +%endif diff --git a/pymin/services/ppp/__init__.py b/pymin/services/ppp/__init__.py index caf8f4e..db2a535 100644 --- a/pymin/services/ppp/__init__.py +++ b/pymin/services/ppp/__init__.py @@ -1,6 +1,7 @@ # vim: set encoding=utf-8 et sw=4 sts=4 : import os +import subprocess from os import path from signal import SIGTERM @@ -120,7 +121,6 @@ class PppHandler(Restorable, ConfigWriter, ReloadHandler, TransactionalHandler): for name in names: if name in self.conns: if self.conns[name]._running: - call(('poff', name)) if path.exists('/var/run/ppp-' + name + '.pid'): pid = file('/var/run/ppp-' + name + '.pid').readline() try: @@ -162,6 +162,16 @@ class PppHandler(Restorable, ConfigWriter, ReloadHandler, TransactionalHandler): else: raise ConnectionNotFoundError(name) + def handle_timer(self): + for c in self.conns.values(): + p = subprocess.Popen(('pgrep', '-f', 'pppd call ' + c.name), + stdout=subprocess.PIPE) + pid = p.communicate()[0] + if p.wait() == 0 and len(pid) > 0: + c._running = True + else: + c._running = False + def _write_config(self): r"_write_config() -> None :: Generate all the configuration files." #guardo los pass que van el pap-secrets diff --git a/pymin/services/ppp/templates/nameX b/pymin/services/ppp/templates/nameX index ee70cf1..0e9716e 100644 --- a/pymin/services/ppp/templates/nameX +++ b/pymin/services/ppp/templates/nameX @@ -1,6 +1,6 @@ updetach % if conn.type != 'TUNNEL': -name ${conn.username} +user ${conn.username} file /etc/ppp/options.${conn.name} ipparam ${conn.name} # pppoe has a lower mtu/mru @@ -11,6 +11,7 @@ nopcomp # this is recommended novjccomp noccp +noauth % else: pty "pptp ${conn.server} --nolaunchpppd" name ${conn.username} diff --git a/pymin/services/util.py b/pymin/services/util.py index 6e09148..91d28c3 100644 --- a/pymin/services/util.py +++ b/pymin/services/util.py @@ -11,9 +11,10 @@ except ImportError: from pymin.dispatcher import Handler, handler, HandlerError, \ CommandNotFoundError +from pymin.seqtools import Sequence -#DEBUG = False -DEBUG = True +DEBUG = False +#DEBUG = True __ALL__ = ('Error', 'ReturnNot0Error', 'ExecutionError', 'ItemError', 'ItemAlreadyExistsError', 'ItemNotFoundError', 'ContainerError', @@ -21,7 +22,7 @@ __ALL__ = ('Error', 'ReturnNot0Error', 'ExecutionError', 'ItemError', 'Persistent', 'Restorable', 'ConfigWriter', 'ServiceHandler', 'RestartHandler', 'ReloadHandler', 'InitdHandler', 'SubHandler', 'DictSubHandler', 'ListSubHandler', 'ComposedSubHandler', - 'ListComposedSubHandler', 'DictComposedSubHandler') + 'ListComposedSubHandler', 'DictComposedSubHandler', 'Device','Address') class Error(HandlerError): r""" @@ -152,6 +153,30 @@ class ContainerNotFoundError(ContainerError): r"Initialize the object. See class documentation for more info." self.message = u'Container not found: "%s"' % key +class Address(Sequence): + def __init__(self, ip, netmask, broadcast=None, peer=None): + self.ip = ip + self.netmask = netmask + self.broadcast = broadcast + self.peer = peer + def update(self, netmask=None, broadcast=None): + if netmask is not None: self.netmask = netmask + if broadcast is not None: self.broadcast = broadcast + def as_tuple(self): + return (self.ip, self.netmask, self.broadcast, self.peer) + + +class Device(Sequence): + def __init__(self, name, mac, ppp): + self.name = name + self.mac = mac + self.ppp = ppp + self.addrs = dict() + self.routes = list() + def as_tuple(self): + return (self.name, self.mac, self.addrs) + + def get_network_devices(): p = subprocess.Popen(('ip', '-o', 'link'), stdout=subprocess.PIPE, @@ -165,16 +190,38 @@ def get_network_devices(): if dev.find('link/ether') != -1: i = dev.find('link/ether') mac = dev[i+11 : i+11+17] - i = dev.find(':',2) - name = dev[3: i] - d[name] = mac + i = dev.find(':') + j = dev.find(':', i+1) + name = dev[i+2: j] + d[name] = Device(name,mac,False) elif dev.find('link/ppp') != -1: i = dev.find('link/ppp') mac = '00:00:00:00:00:00' - i = dev.find(':',2) - name = dev[3 : i] - d[name] = mac + i = dev.find(':') + j = dev.find(':', i+1) + name = dev[i+2 : j] + d[name] = Device(name,mac,True) + #since the device is ppp, get the address and peer + try: + p = subprocess.Popen(('ip', '-o', 'addr', 'show', name), stdout=subprocess.PIPE, + close_fds=True, stderr=subprocess.PIPE) + string = p.stdout.read() + p.wait() + addrs = string.splitlines() + inet = addrs[1].find('inet') + peer = addrs[1].find('peer') + bar = addrs[1].find('/') + from_addr = addrs[1][inet+5 : peer-1] + to_addr = addrs[1][peer+5 : bar] + d[name].addrs[from_addr] = Address(from_addr,24, peer=to_addr) + except IndexError: + pass + return d + +def get_peers(): + p = subprocess.Popen(('ip', '-o', 'addr'), stdout=subprocess.PIPE, + close_fds=True) def call(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, universal_newlines=True, @@ -185,6 +232,7 @@ def call(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, print 'Executing command:', command return try: + print 'Executing command:', command r = subprocess.call(command, stdin=stdin, stdout=stdout, stderr=stderr, universal_newlines=universal_newlines, close_fds=close_fds, **kw) @@ -591,6 +639,15 @@ class InitdHandler(ServiceHandler): action) ServiceHandler.__init__(self, **actions) + def handle_timer(self): + p = subprocess.Popen(('pgrep', '-f', self._initd_name), + stdout=subprocess.PIPE) + pid = p.communicate()[0] + if p.wait() == 0 and len(pid) > 0: + c._service_running = True + else: + c._service_running = False + class TransactionalHandler(Handler): r"""Handle command transactions providing a commit and rollback commands. @@ -1039,6 +1096,8 @@ class DictComposedSubHandler(ComposedSubHandler): if __name__ == '__main__': + import sys + # Execution tests class STestHandler1(ServiceHandler): _service_start = ('service', 'start') @@ -1141,3 +1200,5 @@ if __name__ == '__main__': os.rmdir('templates') print + print get_network_devices() + diff --git a/pymin/services/vpn/__init__.py b/pymin/services/vpn/__init__.py new file mode 100644 index 0000000..789d137 --- /dev/null +++ b/pymin/services/vpn/__init__.py @@ -0,0 +1,171 @@ +# vim: set encoding=utf-8 et sw=4 sts=4 : + +import os +from os import path + +from pymin.seqtools import Sequence +from pymin.dispatcher import Handler, handler, HandlerError +from pymin.services.util import Restorable, ConfigWriter, InitdHandler, \ + TransactionalHandler, DictSubHandler, DictComposedSubHandler, call, ExecutionError + + +class Host(Sequence): + def __init__(self, vpn_src, ip, vpn_src_net, key): + self.name = vpn_src + self.ip = ip + self.src_net = vpn_src_net + self.pub_key = key + self.dele = False + + def as_tuple(self): + return(self.name, self.ip, self.src_net, self.pub_key) + +class HostHandler(DictComposedSubHandler): + + handler_help = u"Manage hosts for a vpn" + _comp_subhandler_cont = 'vpns' + _comp_subhandler_attr = 'hosts' + _comp_subhandler_class = Host + + @handler('usage: add ') + def delete(self, vpn_src, host): + DictComposedSubHandler.delete(self, vpn_src, host) + if vpn_src in parent.vpns: + if host in parent.vpns[vpn_src].hosts: + parent.vpns[vpn_src].hosts[host].dele = True + + +class Vpn(Sequence): + def __init__(self, vpn_src, vpn_dst, vpn_src_ip, vpn_src_mask, pub_key, priv_key): + self.vpn_src = vpn_src + self.vpn_dst = vpn_dst + self.vpn_src_ip = vpn_src_ip + self.vpn_src_mask = vpn_src_mask + self.pub_key = pub_key + self.priv_key = priv_key + self.hosts = dict() + self.dele = False + + def as_tuple(self): + return(self.vpn_src, self.vpn_dst, self.vpn_src_ip, self.vpn_src_mask, self.pub_key, self.priv_key) + + def update(self, vpn_dst=None, vpn_src_ip=None, vpn_src_mask=None): + if vpn_dst is not None: + self.vpn_dst = vpn_dst + if vpn_src_ip is not None: + self.vpn_src_ip = vpn_src_ip + if vpn_src_mask is not None: + self.vpn_src_mask = vpn_src_mask + + +class VpnHandler(Restorable, ConfigWriter, + TransactionalHandler, DictSubHandler): + + handler_help = u"Manage vpn service" + + _cont_subhandler_attr = 'vpns' + _cont_subhandler_class = Vpn + + _persistent_attrs = ('vpns','hosts') + + _restorable_defaults = dict( + vpns = dict(), + hosts = dict(), + ) + + _config_writer_files = ('tinc.conf','tinc-up','host') + _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates') + + def __init__(self, pickle_dir='.', config_dir='/etc/tinc'): + DictSubHandler.__init__(self,self) + self._config_writer_cfg_dir = config_dir + self._persistent_dir = pickle_dir + self._config_build_templates() + self._restore() + self.host = HostHandler(self) + + @handler('usage : add ') + def add(self, vpn_src, vpn_dst, vpn_src_ip, vpn_src_mask): + if not vpn_src in self.vpns: + DictSubHandler.add(self, vpn_src, vpn_dst, vpn_src_ip, vpn_src_mask, None, None) + elif vpn_src in self.vpns: + if self.vpns[vpn_src].dele : + self.vpns[vpn_src] = False + + @handler('usage : delete ') + def delete(self, vpn_src): + if vpn_src in self.vpns: + self.vpns[vpn_src].dele = True; + + + @handler('usage: start ') + def start(self, vpn_src): + if vpn_src in self.vpns: + call(('tincd','--net=',vpn_src)) + + @handler('usage: stop ') + def stop(self, vpn_src): + if vpn_src in self.vpns: + if path.exists('/var/lib/run/tincd.' + vpn_src + '.pid'): + pid = file('/var/lib/run/tincd.' + vpn_src + '.pid').readline() + try: + os.kill(int(pid.strip()), SIGTERM) + except OSError: + pass # XXX report error? + + def _write_config(self): + for v in self.vpns.values(): + #chek whether it's been created or not. + if not v.dele: + if v.pub_key is None : + try: + print 'douugh' + #first create the directory for the vpn + call(('mkdir','-p', path.join(self._config_writer_cfg_dir, v.vpn_src ,'hosts'))) + #this command should generate 2 files inside the vpn + #dir, one rsa_key.priv and one rsa_key.pub + #for some reason debian does not work like this + call(('tincd','-n', v.vpn_src,'-K','<','/dev/null')) + #open the created files and load the keys + f = file(path.join(self._config_writer_cfg_dir, v.vpn_src , 'rsa_key.priv'), 'r') + priv = f.read() + f.close() + f = file(path.join(self._config_writer_cfg_dir, v.vpn_src ,'rsa_key.pub'), 'r') + pub = f.read() + f.close() + v.pub_key = pub + v.priv_key = priv + except ExecutionError, e: + print e + + vars = dict( + vpn = v, + ) + self._write_single_config('tinc.conf',path.join(v.vpn_src,'tinc.conf'),vars) + self._write_single_config('tinc-up',path.join(v.vpn_src,'tinc-up'),vars) + for h in v.hosts.values(): + if not h.dele: + vars = dict( + host = h, + ) + self._write_single_config('host',path.join(v.vpn_src,'hosts',h.name),vars) + else: + try: + call(('rm','-f', path.join(v.vpn_src,'hosts',h.name))) + del v.hosts[h.name] + except ExecutionError, e: + print e + else: + #delete the vpn root at tinc dir + if path.exists('/etc/tinc/' + v.vpn_src): + self.stop(v.vpn_src) + call(('rm','-rf','/etc/tinc/' + v.vpn_src)) + del self.vpns[v.vpn_src] + + +if __name__ == '__main__': + v = VpnHandler() + v.add('test','127.0.0.1','192.168.0.1','255.255.255.0') + #v.host.add('test', 'sarasa' ,'127.0.0.1', '205.25.36.36','kjdhfkbdskljvkjblkbjeslkjbvkljbselvslberjhbvslbevlhb') + v.delete('test') + v.commit() diff --git a/pymin/services/vpn/templates/host b/pymin/services/vpn/templates/host new file mode 100644 index 0000000..c2a2acb --- /dev/null +++ b/pymin/services/vpn/templates/host @@ -0,0 +1,3 @@ +Address = ${host.ip} +Subnet = ${host.src_net} +${host.pub_key} diff --git a/pymin/services/vpn/templates/tinc-up b/pymin/services/vpn/templates/tinc-up new file mode 100644 index 0000000..fa9b987 --- /dev/null +++ b/pymin/services/vpn/templates/tinc-up @@ -0,0 +1 @@ +ifconfig $INTERFACE ${vpn.vpn_src_ip} netmask ${vpn.vpn_src_mask} diff --git a/pymin/services/vpn/templates/tinc.conf b/pymin/services/vpn/templates/tinc.conf new file mode 100644 index 0000000..a3e45ff --- /dev/null +++ b/pymin/services/vpn/templates/tinc.conf @@ -0,0 +1,4 @@ +Name = ${vpn.vpn_src} +Device = /dev/net/tun +PrivateKeyFile = /etc/tinc/${vpn.vpn_src}/rsa_key.priv +ConnectTo = ${vpn.vpn_dst}