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