from ...schema import X509_FILE_MODE
from ..base.backend import BaseBackend
from . import converters
from .parser import OpenVpnParser, config_suffix, vpn_pattern
from .renderer import OpenVpnRenderer
from .schema import schema
class OpenVpn(BaseBackend):
"""
OpenVPN 2.x Configuration Backend
"""
schema = schema
converters = [converters.OpenVpn]
parser = OpenVpnParser
renderer = OpenVpnRenderer
list_identifiers = ['name']
def _generate_contents(self, tar):
"""
Adds configuration files to tarfile instance.
:param tar: tarfile instance
:returns: None
"""
text = self.render(files=False)
# create a list with all the packages (and remove empty entries)
vpn_instances = vpn_pattern.split(text)
if '' in vpn_instances:
vpn_instances.remove('')
# create a file for each VPN
for vpn in vpn_instances:
lines = vpn.split('\n')
vpn_name = lines[0]
text_contents = '\n'.join(lines[2:])
# do not end with double new line
if text_contents.endswith('\n\n'):
text_contents = text_contents[0:-1]
self._add_file(
tar=tar,
name='{0}{1}'.format(vpn_name, config_suffix),
contents=text_contents,
)
[docs] @classmethod
def auto_client(
cls,
host,
server,
ca_path=None,
ca_contents=None,
cert_path=None,
cert_contents=None,
key_path=None,
key_contents=None,
):
"""
Returns a configuration dictionary representing an OpenVPN client configuration
that is compatible with the passed server configuration.
:param host: remote VPN server
:param server: dictionary representing a single OpenVPN server configuration
:param ca_path: optional string representing path to CA, will consequently add
a file in the resulting configuration dictionary
:param ca_contents: optional string representing contents of CA file
:param cert_path: optional string representing path to certificate, will consequently add
a file in the resulting configuration dictionary
:param cert_contents: optional string representing contents of cert file
:param key_path: optional string representing path to key, will consequently add
a file in the resulting configuration dictionary
:param key_contents: optional string representing contents of key file
:returns: dictionary representing a single OpenVPN client configuration
"""
# client defaults
client = {
"mode": "p2p",
"nobind": True,
"resolv_retry": "infinite",
"tls_client": True,
}
# remote
port = server.get('port') or 1195
client['remote'] = [{'host': host, 'port': port}]
# proto
if server.get('proto') == 'tcp-server':
client['proto'] = 'tcp-client'
else:
client['proto'] = 'udp'
# determine if pull must be True
if 'server' in server or 'server_bridge' in server:
client['pull'] = True
# tls_client
if 'tls_server' not in server or not server['tls_server']:
client['tls_client'] = False
# ns_cert_type
ns_cert_type = {None: '', '': '', 'client': 'server'}
client['ns_cert_type'] = ns_cert_type[server.get('ns_cert_type')]
# remote_cert_tls
remote_cert_tls = {None: '', '': '', 'client': 'server'}
client['remote_cert_tls'] = remote_cert_tls[server.get('remote_cert_tls')]
copy_keys = [
'name',
'dev_type',
'dev',
'comp_lzo',
'auth',
'cipher',
'ca',
'cert',
'key',
'pkcs12',
'mtu_test',
'fragment',
'mssfix',
'keepalive',
'persist_tun',
'mute',
'persist_key',
'script_security',
'user',
'group',
'log',
'mute_replay_warnings',
'secret',
'reneg_sec',
'tls_timeout',
'tls_cipher',
'float',
'fast_io',
'verb',
]
for key in copy_keys:
if key in server:
client[key] = server[key]
files = cls._auto_client_files(
client,
ca_path,
ca_contents,
cert_path,
cert_contents,
key_path,
key_contents,
)
return {'openvpn': [client], 'files': files}
@classmethod
def _auto_client_files(
cls,
client,
ca_path=None,
ca_contents=None,
cert_path=None,
cert_contents=None,
key_path=None,
key_contents=None,
):
"""
returns a list of NetJSON extra files for automatically generated clients
produces side effects in ``client`` dictionary
"""
files = []
if ca_path and ca_contents:
client['ca'] = ca_path
files.append(dict(path=ca_path, contents=ca_contents, mode=X509_FILE_MODE))
if cert_path and cert_contents:
client['cert'] = cert_path
files.append(
dict(path=cert_path, contents=cert_contents, mode=X509_FILE_MODE)
)
if key_path and key_contents:
client['key'] = key_path
files.append(
dict(path=key_path, contents=key_contents, mode=X509_FILE_MODE,)
)
return files