]> git.llucax.com Git - software/pymin.git/blob - services/vpn/handler.py
Split proxy handler in submodules (refs #2).
[software/pymin.git] / services / vpn / handler.py
1 # vim: set encoding=utf-8 et sw=4 sts=4 :
2
3 import os
4 import errno
5 import signal
6 from os import path
7 import logging ; log = logging.getLogger('pymin.services.vpn')
8
9 from pymin.seqtools import Sequence
10 from pymin.dispatcher import handler
11 from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
12                                TransactionalHandler, DictSubHandler, \
13                                call, ExecutionError
14
15 from host import HostHandler
16
17 __all__ = ('VpnHandler',)
18
19
20 class Vpn(Sequence):
21     def __init__(self, vpn_src, vpn_dst, vpn_src_ip, vpn_src_mask,
22                     pub_key=None, priv_key=None):
23         self.vpn_src = vpn_src
24         self.vpn_dst = vpn_dst
25         self.vpn_src_ip = vpn_src_ip
26         self.vpn_src_mask = vpn_src_mask
27         self.pub_key = pub_key
28         self.priv_key = priv_key
29         self.hosts = dict()
30         self._delete = False
31
32     def as_tuple(self):
33         return(self.vpn_src, self.vpn_dst, self.vpn_src_ip, self.vpn_src_mask, self.pub_key, self.priv_key)
34
35     def update(self, vpn_dst=None, vpn_src_ip=None, vpn_src_mask=None):
36         if vpn_dst is not None:
37             self.vpn_dst = vpn_dst
38         if vpn_src_ip is not None:
39             self.vpn_src_ip = vpn_src_ip
40         if vpn_src_mask is not None:
41             self.vpn_src_mask = vpn_src_mask
42
43
44 class VpnHandler(Restorable, ConfigWriter,
45                    TransactionalHandler, DictSubHandler):
46
47     handler_help = u"Manage vpn service"
48
49     _cont_subhandler_attr = 'vpns'
50     _cont_subhandler_class = Vpn
51
52     _persistent_attrs = ('vpns','hosts')
53
54     _restorable_defaults = dict(
55             vpns = dict(),
56             hosts = dict(),
57     )
58
59     _config_writer_files = ('tinc.conf','tinc-up','host')
60     _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
61
62     def __init__(self,  pickle_dir='.', config_dir='/etc/tinc'):
63         log.debug(u'VpnHandler(%r, %r)', pickle_dir, config_dir)
64         DictSubHandler.__init__(self, self)
65         self._config_writer_cfg_dir = config_dir
66         self._persistent_dir = pickle_dir
67         self._config_build_templates()
68         self._restore()
69         self.host = HostHandler(self)
70
71     @handler('usage: start <vpn_name>')
72     def start(self, vpn_src):
73         log.debug(u'VpnHandler.start(%r)', vpn_src)
74         if vpn_src in self.vpns:
75             call(('tincd','--net='+ vpn_src))
76
77     @handler('usage: stop <vpn_name>')
78     def stop(self, vpn_src):
79         log.debug(u'VpnHandler.stop(%r)', vpn_src)
80         if vpn_src in self.vpns:
81             pid_file = '/var/run/tinc.' + vpn_src + '.pid'
82             log.debug(u'VpnHandler.stop: getting pid from %r', pid_file)
83             if path.exists(pid_file):
84                 pid = file(pid_file).readline()
85                 pid = int(pid.strip())
86                 try:
87                     log.debug(u'VpnHandler.stop: killing pid %r', pid)
88                     os.kill(pid, signal.SIGTERM)
89                 except OSError:
90                     log.debug(u'VpnHandler.stop: error killing: %r', e)
91             else:
92                 log.debug(u'VpnHandler.stop: pid file not found')
93
94     def _write_config(self):
95         log.debug(u'VpnHandler._write_config()')
96         for v in self.vpns.values():
97             log.debug(u'VpnHandler._write_config: processing %r', v)
98             #chek whether it's been created or not.
99             if not v._delete:
100                 if v.pub_key is None:
101                     log.debug(u'VpnHandler._write_config: new VPN, generating '
102                                 'key...')
103                     try:
104                         log.debug(u'VpnHandler._write_config: creating dir %r',
105                                     path.join(self._config_writer_cfg_dir,
106                                                 v.vpn_src ,'hosts'))
107                         #first create the directory for the vpn
108                         try:
109                             os.makedirs(path.join(self._config_writer_cfg_dir,
110                                                   v.vpn_src, 'hosts'))
111                         except (IOError, OSError), e:
112                             if e.errno != errno.EEXIST:
113                                 raise HandlerError(u"Can't create VPN config "
114                                                    "directory '%s' (%s)'"
115                                                     % (e.filename, e.strerror))
116                         #this command should generate 2 files inside the vpn
117                         #dir, one rsa_key.priv and one rsa_key.pub
118                         #for some reason debian does not work like this
119                         # FIXME if the < /dev/null works, is magic!
120                         log.debug(u'VpnHandler._write_config: creating key...')
121                         call(('tincd', '-n', v.vpn_src, '-K', '<', '/dev/null'))
122                         #open the created files and load the keys
123                         try:
124                             f = file(path.join(self._config_writer_cfg_dir,
125                                                v.vpn_src, 'rsa_key.pub'),
126                                      'r')
127                             pub = f.read()
128                             f.close()
129                         except (IOError, OSError), e:
130                             raise HandlerError(u"Can't read VPN key '%s' (%s)'"
131                                                 % (e.filename, e.strerror))
132
133                         v.pub_key = pub
134                         v.priv_key = priv
135                     except ExecutionError, e:
136                         log.debug(u'VpnHandler._write_config: error executing '
137                                     'the command: %r', e)
138
139                 vars = dict(
140                     vpn = v,
141                 )
142                 self._write_single_config('tinc.conf',
143                                 path.join(v.vpn_src, 'tinc.conf'), vars)
144                 self._write_single_config('tinc-up',
145                                 path.join(v.vpn_src, 'tinc-up'), vars)
146                 for h in v.hosts.values():
147                     if not h._delete:
148                         vars = dict(
149                             host = h,
150                         )
151                         self._write_single_config('host',
152                                 path.join(v.vpn_src, 'hosts', h.name), vars)
153                     else:
154                         log.debug(u'VpnHandler._write_config: removing...')
155                         try:
156                             # FIXME use os.unlink()
157                             call(('rm','-f',
158                                     path.join(v.vpn_src, 'hosts', h.name)))
159                             del v.hosts[h.name]
160                         except ExecutionError, e:
161                             log.debug(u'VpnHandler._write_config: error '
162                                     'removing files: %r', e)
163             else:
164                 #delete the vpn root at tinc dir
165                 if path.exists('/etc/tinc/' + v.vpn_src):
166                     self.stop(v.vpn_src)
167                     call(('rm','-rf','/etc/tinc/' + v.vpn_src))
168                     del self.vpns[v.vpn_src]
169
170
171 if __name__ == '__main__':
172
173     logging.basicConfig(
174         level   = logging.DEBUG,
175         format  = '%(asctime)s %(levelname)-8s %(message)s',
176         datefmt = '%H:%M:%S',
177     )
178
179     v = VpnHandler()
180     v.add('prueba','sarasa','192.168.0.188','255.255.255.0')
181     v.host.add('prueba', 'azazel' ,'192.168.0.77', '192.168.0.0',
182                 'kjdhfkbdskljvkjblkbjeslkjbvkljbselvslberjhbvslbevlhb')
183     v.commit()
184