1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# service.py
# Copyright (C) 2015-2017 LEAP
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
VPN service declaration.
"""
import os
from twisted.internet import defer
from leap.bitmask.hooks import HookableService
from leap.bitmask.vpn.vpn import VPNManager
from leap.bitmask.vpn._checks import is_service_ready, get_vpn_cert_path
from leap.bitmask.vpn import privilege
from leap.common.config import get_path_prefix
from leap.common.files import check_and_fix_urw_only
class VPNService(HookableService):
name = 'vpn'
def __init__(self, basepath=None):
"""
Initialize VPN service
"""
super(VPNService, self).__init__()
self._started = False
self._vpn = None
self._domain = ''
if basepath is None:
self._basepath = get_path_prefix()
else:
self._basepath = basepath
def startService(self):
print "Starting VPN Service..."
# TODO this could trigger a check for validity of the certificates,
# etc.
super(VPNService, self).startService()
def stopService(self):
print "Stopping VPN Service..."
super(VPNService, self).stopService()
@defer.inlineCallbacks
def start_vpn(self, domain):
# TODO check if the VPN is started and return an error if it is.
yield self._setup(domain)
self._vpn.start()
self._started = True
self._domain = domain
defer.returnValue({'result': 'started'})
def stop_vpn(self):
# TODO -----------------------------
# when shutting down the main bitmaskd daemon, this should be called.
if self._started:
self._vpn.stop()
self._started = False
return {'result': 'stopped'}
def do_status(self):
status = {
'status': 'off',
'error': None,
'childrenStatus': {}
}
if self._vpn:
status = self._vpn.get_status()
status['domain'] = self._domain
return status
def do_check(self, domain):
"""Check whether the VPN Service is properly configured,
and can be started"""
return {'vpn_ready': is_service_ready(domain)}
@defer.inlineCallbacks
def do_get_cert(self, username):
try:
_, provider = username.split('@')
except ValueError:
raise ValueError(username + ' is not a valid username, it should'
' contain an @')
# fetch vpn cert and store
bonafide = self.parent.getServiceNamed("bonafide")
_, cert_str = yield bonafide.do_get_vpn_cert(username)
cert_path = get_vpn_cert_path(provider)
cert_dir = os.path.dirname(cert_path)
if not os.path.exists(cert_dir):
os.makedirs(cert_dir, mode=0700)
with open(cert_path, 'w') as outf:
outf.write(cert_str)
check_and_fix_urw_only(cert_path)
defer.returnValue({'get_cert': 'ok'})
def do_install(self):
ask = privilege.install_helpers()
return {'install': 'ok'}
def do_uninstall(self):
ask = privilege.uninstall_helpers()
return {'uninstall': 'ok'}
@defer.inlineCallbacks
def _setup(self, provider):
"""Set up VPNManager for a specified provider.
:param provider: the provider to use, e.g. 'demo.bitmask.net'
:type provider: str"""
bonafide = self.parent.getServiceNamed("bonafide")
config = yield bonafide.do_provider_read(provider, "eip")
remotes = [(gw["ip_address"], gw["capabilities"]["ports"][0])
for gw in config.gateways]
# FIXME -- bitmask-root cannot parse some options!
# extra_flags = config.openvpn_configuration
# XXX picked manually from vpn-service.json
extra_flags = {
"auth": "SHA1",
"cipher": "AES-128-CBC",
"keepalive": "10 30",
"tls-cipher": "DHE-RSA-AES128-SHA",
}
prefix = os.path.join(self._basepath,
"leap/providers/{0}/keys".format(provider))
cert_path = key_path = prefix + "/client/openvpn.pem"
ca_path = prefix + "/ca/cacert.pem"
self._vpn = VPNManager(remotes, cert_path, key_path, ca_path,
extra_flags)
|