You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
317 lines
12 KiB
317 lines
12 KiB
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import logging
|
|
|
|
from autotest_lib.client.bin import utils
|
|
from autotest_lib.client.cros import network_chroot
|
|
from autotest_lib.client.common_lib.cros import site_eap_certs
|
|
|
|
class VPNServer(object):
|
|
"""Context enclosing the use of a VPN server instance."""
|
|
|
|
def __enter__(self):
|
|
self.start_server()
|
|
return self
|
|
|
|
|
|
def __exit__(self, exception, value, traceback):
|
|
logging.info('Log contents: %s', self.get_log_contents())
|
|
self.stop_server()
|
|
|
|
|
|
class L2TPIPSecVPNServer(VPNServer):
|
|
"""Implementation of an L2TP/IPSec VPN. Uses ipsec starter and xl2tpd."""
|
|
ROOT_DIRECTORIES = ('etc/ipsec.d', 'etc/ipsec.d/cacerts',
|
|
'etc/ipsec.d/certs', 'etc/ipsec.d/crls',
|
|
'etc/ipsec.d/private', 'etc/ppp', 'etc/xl2tpd')
|
|
CHAP_USER = 'chapuser'
|
|
CHAP_SECRET = 'chapsecret'
|
|
IPSEC_COMMAND = '/usr/sbin/ipsec'
|
|
IPSEC_LOGFILE = 'var/log/charon.log'
|
|
IPSEC_PRESHARED_KEY = 'preshared-key'
|
|
IPSEC_CA_CERTIFICATE = 'etc/ipsec.d/cacerts/ca.cert'
|
|
IPSEC_SERVER_CERTIFICATE = 'etc/ipsec.d/certs/server.cert'
|
|
PPPD_PID_FILE = 'run/ppp0.pid'
|
|
XAUTH_USER = 'xauth_user'
|
|
XAUTH_PASSWORD = 'xauth_password'
|
|
XAUTH_SECONDARY_AUTHENTICATION_STANZA = 'rightauth2=xauth'
|
|
XL2TPD_COMMAND = '/usr/sbin/xl2tpd'
|
|
XL2TPD_CONFIG_FILE = 'etc/xl2tpd/xl2tpd.conf'
|
|
XL2TPD_PID_FILE = 'run/xl2tpd.pid'
|
|
SERVER_IP_ADDRESS = '192.168.1.99'
|
|
IPSEC_COMMON_CONFIGS = {
|
|
'etc/strongswan.conf' :
|
|
'charon {\n'
|
|
' filelog {\n'
|
|
' test_vpn {\n'
|
|
' path = %(charon-logfile)s\n'
|
|
' default = 3\n'
|
|
' time_format = %%b %%e %%T\n'
|
|
' }\n'
|
|
' }\n'
|
|
' install_routes = no\n'
|
|
' ignore_routing_tables = 0\n'
|
|
' routing_table = 0\n'
|
|
'}\n',
|
|
|
|
'etc/passwd' :
|
|
'root:x:0:0:root:/root:/bin/bash\n'
|
|
'ipsec:*:212:212::/dev/null:/bin/false\n',
|
|
|
|
'etc/group' :
|
|
'ipsec:x:212:\n',
|
|
|
|
XL2TPD_CONFIG_FILE :
|
|
'[global]\n'
|
|
'\n'
|
|
'[lns default]\n'
|
|
' ip range = 192.168.1.128-192.168.1.254\n'
|
|
' local ip = 192.168.1.99\n'
|
|
' require chap = yes\n'
|
|
' refuse pap = yes\n'
|
|
' require authentication = yes\n'
|
|
' name = LinuxVPNserver\n'
|
|
' ppp debug = yes\n'
|
|
' pppoptfile = /etc/ppp/options.xl2tpd\n'
|
|
' length bit = yes\n',
|
|
|
|
'etc/xl2tpd/l2tp-secrets' :
|
|
'* them l2tp-secret',
|
|
|
|
'etc/ppp/chap-secrets' :
|
|
'%(chap-user)s * %(chap-secret)s *',
|
|
|
|
'etc/ppp/options.xl2tpd' :
|
|
'ipcp-accept-local\n'
|
|
'ipcp-accept-remote\n'
|
|
'noccp\n'
|
|
'auth\n'
|
|
'crtscts\n'
|
|
'idle 1800\n'
|
|
'mtu 1410\n'
|
|
'mru 1410\n'
|
|
'nodefaultroute\n'
|
|
'debug\n'
|
|
'lock\n'
|
|
'proxyarp\n'
|
|
}
|
|
IPSEC_TYPED_CONFIGS = {
|
|
'psk': {
|
|
'etc/ipsec.conf' :
|
|
'config setup\n'
|
|
' charondebug="%(charon-debug-flags)s"\n'
|
|
'conn L2TP\n'
|
|
' keyexchange=ikev1\n'
|
|
' ike=aes128-sha1-modp2048!\n'
|
|
' esp=3des-sha1!\n'
|
|
' type=transport\n'
|
|
' authby=psk\n'
|
|
' %(xauth-stanza)s\n'
|
|
' rekey=no\n'
|
|
' left=%(local-ip)s\n'
|
|
' leftprotoport=17/1701\n'
|
|
' right=%%any\n'
|
|
' rightprotoport=17/%%any\n'
|
|
' auto=add\n',
|
|
|
|
'etc/ipsec.secrets' :
|
|
'%(local-ip)s %%any : PSK "%(preshared-key)s"\n'
|
|
'%(xauth-user)s : XAUTH "%(xauth-password)s"\n',
|
|
},
|
|
'cert': {
|
|
'etc/ipsec.conf' :
|
|
'config setup\n'
|
|
' charondebug="%(charon-debug-flags)s"\n'
|
|
'conn L2TP\n'
|
|
' keyexchange=ikev1\n'
|
|
' ike=aes128-sha1-modp2048!\n'
|
|
' esp=3des-sha1!\n'
|
|
' type=transport\n'
|
|
' left=%(local-ip)s\n'
|
|
' leftcert=server.cert\n'
|
|
' leftid="C=US, ST=California, L=Mountain View, '
|
|
'CN=chromelab-wifi-testbed-server.mtv.google.com"\n'
|
|
' leftprotoport=17/1701\n'
|
|
' right=%%any\n'
|
|
' rightca="C=US, ST=California, L=Mountain View, '
|
|
'CN=chromelab-wifi-testbed-root.mtv.google.com"\n'
|
|
' rightprotoport=17/%%any\n'
|
|
' auto=add\n',
|
|
|
|
'etc/ipsec.secrets' : ': RSA server.key ""\n',
|
|
|
|
IPSEC_SERVER_CERTIFICATE : site_eap_certs.server_cert_1,
|
|
IPSEC_CA_CERTIFICATE : site_eap_certs.ca_cert_1,
|
|
'etc/ipsec.d/private/server.key' :
|
|
site_eap_certs.server_private_key_1,
|
|
},
|
|
}
|
|
|
|
"""Implementation of an L2TP/IPSec server instance."""
|
|
def __init__(self, auth_type, interface_name, address, network_prefix,
|
|
perform_xauth_authentication=False,
|
|
local_ip_is_public_ip=False):
|
|
self._auth_type = auth_type
|
|
self._chroot = network_chroot.NetworkChroot(interface_name,
|
|
address, network_prefix)
|
|
self._perform_xauth_authentication = perform_xauth_authentication
|
|
|
|
if local_ip_is_public_ip:
|
|
self.IPSEC_COMMON_CONFIGS[self.XL2TPD_CONFIG_FILE] = \
|
|
self.IPSEC_COMMON_CONFIGS[self.XL2TPD_CONFIG_FILE].replace(
|
|
self.SERVER_IP_ADDRESS, address)
|
|
self.SERVER_IP_ADDRESS = address
|
|
|
|
|
|
def start_server(self):
|
|
"""Start VPN server instance"""
|
|
if self._auth_type not in self.IPSEC_TYPED_CONFIGS:
|
|
raise RuntimeError('L2TP/IPSec type %s is not define' %
|
|
self._auth_type)
|
|
chroot = self._chroot
|
|
chroot.add_root_directories(self.ROOT_DIRECTORIES)
|
|
chroot.add_config_templates(self.IPSEC_COMMON_CONFIGS)
|
|
chroot.add_config_templates(self.IPSEC_TYPED_CONFIGS[self._auth_type])
|
|
chroot.add_config_values({
|
|
'chap-user': self.CHAP_USER,
|
|
'chap-secret': self.CHAP_SECRET,
|
|
'charon-debug-flags': 'dmn 2, mgr 2, ike 2, net 2',
|
|
'charon-logfile': self.IPSEC_LOGFILE,
|
|
'preshared-key': self.IPSEC_PRESHARED_KEY,
|
|
'xauth-user': self.XAUTH_USER,
|
|
'xauth-password': self.XAUTH_PASSWORD,
|
|
'xauth-stanza': self.XAUTH_SECONDARY_AUTHENTICATION_STANZA
|
|
if self._perform_xauth_authentication else '',
|
|
})
|
|
chroot.add_startup_command('%s start' % self.IPSEC_COMMAND)
|
|
chroot.add_startup_command('%s -c /%s -C /tmp/l2tpd.control' %
|
|
(self.XL2TPD_COMMAND,
|
|
self.XL2TPD_CONFIG_FILE))
|
|
chroot.startup()
|
|
|
|
|
|
def stop_server(self):
|
|
"""Start VPN server instance"""
|
|
chroot = self._chroot
|
|
chroot.run([self.IPSEC_COMMAND, 'stop'], ignore_status=True)
|
|
chroot.kill_pid_file(self.XL2TPD_PID_FILE, missing_ok=True)
|
|
chroot.kill_pid_file(self.PPPD_PID_FILE, missing_ok=True)
|
|
chroot.shutdown()
|
|
|
|
|
|
def get_log_contents(self):
|
|
"""Return all logs related to the chroot."""
|
|
return self._chroot.get_log_contents()
|
|
|
|
|
|
class OpenVPNServer(VPNServer):
|
|
"""Implementation of an OpenVPN service."""
|
|
PRELOAD_MODULES = ('tun',)
|
|
ROOT_DIRECTORIES = ('etc/openvpn',)
|
|
CA_CERTIFICATE_FILE = 'etc/openvpn/ca.crt'
|
|
SERVER_CERTIFICATE_FILE = 'etc/openvpn/server.crt'
|
|
SERVER_KEY_FILE = 'etc/openvpn/server.key'
|
|
DIFFIE_HELLMAN_FILE = 'etc/openvpn/diffie-hellman.pem'
|
|
OPENVPN_COMMAND = '/usr/sbin/openvpn'
|
|
OPENVPN_CONFIG_FILE = 'etc/openvpn/openvpn.conf'
|
|
OPENVPN_PID_FILE = 'run/openvpn.pid'
|
|
OPENVPN_STATUS_FILE = 'tmp/openvpn.status'
|
|
AUTHENTICATION_SCRIPT = 'etc/openvpn_authentication_script.sh'
|
|
EXPECTED_AUTHENTICATION_FILE = 'etc/openvpn_expected_authentication.txt'
|
|
PASSWORD = 'password'
|
|
USERNAME = 'username'
|
|
SERVER_IP_ADDRESS = '10.11.12.1'
|
|
# TODO b:169251326 terms below are set outside of this codebase
|
|
# and should be updated when possible. ("blacklist" -> "blocklist")
|
|
CONFIGURATION = {
|
|
'etc/ssl/blacklist' : '',
|
|
CA_CERTIFICATE_FILE : site_eap_certs.ca_cert_1,
|
|
SERVER_CERTIFICATE_FILE : site_eap_certs.server_cert_1,
|
|
SERVER_KEY_FILE : site_eap_certs.server_private_key_1,
|
|
DIFFIE_HELLMAN_FILE : site_eap_certs.dh1024_pem_key_1,
|
|
AUTHENTICATION_SCRIPT :
|
|
'#!/bin/bash\n'
|
|
'diff -q $1 %(expected-authentication-file)s\n',
|
|
EXPECTED_AUTHENTICATION_FILE : '%(username)s\n%(password)s\n',
|
|
OPENVPN_CONFIG_FILE :
|
|
'ca /%(ca-cert)s\n'
|
|
'cert /%(server-cert)s\n'
|
|
'dev tun\n'
|
|
'dh /%(diffie-hellman-params-file)s\n'
|
|
'keepalive 10 120\n'
|
|
'local %(local-ip)s\n'
|
|
'log /var/log/openvpn.log\n'
|
|
'ifconfig-pool-persist /tmp/ipp.txt\n'
|
|
'key /%(server-key)s\n'
|
|
'persist-key\n'
|
|
'persist-tun\n'
|
|
'port 1194\n'
|
|
'proto udp\n'
|
|
'server 10.11.12.0 255.255.255.0\n'
|
|
'status /%(status-file)s\n'
|
|
'verb 5\n'
|
|
'writepid /%(pid-file)s\n'
|
|
'%(optional-user-verification)s\n'
|
|
}
|
|
|
|
def __init__(self, interface_name, address, network_prefix,
|
|
perform_username_authentication=False):
|
|
self._chroot = network_chroot.NetworkChroot(interface_name,
|
|
address, network_prefix)
|
|
self._perform_username_authentication = perform_username_authentication
|
|
|
|
|
|
def start_server(self):
|
|
"""Start VPN server instance"""
|
|
chroot = self._chroot
|
|
chroot.add_root_directories(self.ROOT_DIRECTORIES)
|
|
# Create a configuration template from the key-value pairs.
|
|
chroot.add_config_templates(self.CONFIGURATION)
|
|
config_values = {
|
|
'ca-cert': self.CA_CERTIFICATE_FILE,
|
|
'diffie-hellman-params-file': self.DIFFIE_HELLMAN_FILE,
|
|
'expected-authentication-file': self.EXPECTED_AUTHENTICATION_FILE,
|
|
'optional-user-verification': '',
|
|
'password': self.PASSWORD,
|
|
'pid-file': self.OPENVPN_PID_FILE,
|
|
'server-cert': self.SERVER_CERTIFICATE_FILE,
|
|
'server-key': self.SERVER_KEY_FILE,
|
|
'status-file': self.OPENVPN_STATUS_FILE,
|
|
'username': self.USERNAME,
|
|
}
|
|
if self._perform_username_authentication:
|
|
config_values['optional-user-verification'] = (
|
|
'auth-user-pass-verify /%s via-file\nscript-security 2' %
|
|
self.AUTHENTICATION_SCRIPT)
|
|
chroot.add_config_values(config_values)
|
|
chroot.add_startup_command('chmod 755 %s' % self.AUTHENTICATION_SCRIPT)
|
|
chroot.add_startup_command('%s --config /%s &' %
|
|
(self.OPENVPN_COMMAND,
|
|
self.OPENVPN_CONFIG_FILE))
|
|
chroot.add_environment({
|
|
'OPENSSL_CONF': '/etc/ssl/openssl.cnf.compat',
|
|
'OPENSSL_CHROMIUM_SKIP_TRUSTED_PURPOSE_CHECK': '1'
|
|
});
|
|
self.preload_modules()
|
|
chroot.startup()
|
|
|
|
|
|
def preload_modules(self):
|
|
"""Pre-load modules since they can't be loaded from chroot."""
|
|
for module in self.PRELOAD_MODULES:
|
|
utils.system('modprobe %s' % module)
|
|
|
|
|
|
def get_log_contents(self):
|
|
"""Return all logs related to the chroot."""
|
|
return self._chroot.get_log_contents()
|
|
|
|
|
|
def stop_server(self):
|
|
"""Start VPN server instance"""
|
|
chroot = self._chroot
|
|
chroot.kill_pid_file(self.OPENVPN_PID_FILE, missing_ok=True)
|
|
chroot.shutdown()
|