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