11f8502e3a
- Use default key size (2048 bits) when generating key pairs using certutil. This significantly reduces IKEv2 setup time on servers with less powerful CPUs, such as Raspberry Pis, while still providing sufficient security. - Update docs
1425 lines
40 KiB
Bash
Executable File
1425 lines
40 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Script to set up IKEv2 on Ubuntu, Debian, CentOS/RHEL and Amazon Linux 2
|
|
#
|
|
# The latest version of this script is available at:
|
|
# https://github.com/hwdsl2/setup-ipsec-vpn
|
|
#
|
|
# Copyright (C) 2020-2021 Lin Song <linsongui@gmail.com>
|
|
#
|
|
# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0
|
|
# Unported License: http://creativecommons.org/licenses/by-sa/3.0/
|
|
#
|
|
# Attribution required: please include my name in any derivative and let me
|
|
# know how you have improved it!
|
|
|
|
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
|
exiterr() { echo "Error: $1" >&2; exit 1; }
|
|
bigecho() { echo "## $1"; }
|
|
|
|
check_ip() {
|
|
IP_REGEX='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
|
|
printf '%s' "$1" | tr -d '\n' | grep -Eq "$IP_REGEX"
|
|
}
|
|
|
|
check_dns_name() {
|
|
FQDN_REGEX='^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$'
|
|
printf '%s' "$1" | tr -d '\n' | grep -Eq "$FQDN_REGEX"
|
|
}
|
|
|
|
check_run_as_root() {
|
|
if [ "$(id -u)" != 0 ]; then
|
|
exiterr "Script must be run as root. Try 'sudo bash $0'"
|
|
fi
|
|
}
|
|
|
|
check_os_type() {
|
|
os_arch=$(uname -m | tr -dc 'A-Za-z0-9_-')
|
|
if grep -qs -e "release 7" -e "release 8" /etc/redhat-release; then
|
|
os_type=centos
|
|
if grep -qs "Red Hat" /etc/redhat-release; then
|
|
os_type=rhel
|
|
fi
|
|
if grep -qs "release 7" /etc/redhat-release; then
|
|
os_ver=7
|
|
elif grep -qs "release 8" /etc/redhat-release; then
|
|
os_ver=8
|
|
fi
|
|
elif grep -qs "Amazon Linux release 2" /etc/system-release; then
|
|
os_type=amzn
|
|
os_ver=2
|
|
else
|
|
os_type=$(lsb_release -si 2>/dev/null)
|
|
[ -z "$os_type" ] && [ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' "$ID")
|
|
case $os_type in
|
|
[Uu]buntu)
|
|
os_type=ubuntu
|
|
;;
|
|
[Dd]ebian)
|
|
os_type=debian
|
|
;;
|
|
[Rr]aspbian)
|
|
os_type=raspbian
|
|
;;
|
|
*)
|
|
exiterr "This script only supports Ubuntu, Debian, CentOS/RHEL 7/8 and Amazon Linux 2."
|
|
exit 1
|
|
;;
|
|
esac
|
|
os_ver=$(sed 's/\..*//' /etc/debian_version | tr -dc 'A-Za-z0-9')
|
|
fi
|
|
}
|
|
|
|
check_swan_install() {
|
|
ipsec_ver=$(/usr/local/sbin/ipsec --version 2>/dev/null)
|
|
swan_ver=$(printf '%s' "$ipsec_ver" | sed -e 's/Linux Libreswan //' -e 's/ (netkey).*//' -e 's/^U//' -e 's/\/K.*//')
|
|
if ( ! grep -qs "hwdsl2 VPN script" /etc/sysctl.conf && ! grep -qs "hwdsl2" /opt/src/run.sh ) \
|
|
|| ! printf '%s' "$ipsec_ver" | grep -q "Libreswan" \
|
|
|| [ ! -f /etc/ppp/chap-secrets ] || [ ! -f /etc/ipsec.d/passwd ]; then
|
|
cat 1>&2 <<'EOF'
|
|
Error: Your must first set up the IPsec VPN server before setting up IKEv2.
|
|
See: https://github.com/hwdsl2/setup-ipsec-vpn
|
|
EOF
|
|
exit 1
|
|
fi
|
|
|
|
case $swan_ver in
|
|
3.19|3.2[01235679]|3.3[12]|4.*)
|
|
true
|
|
;;
|
|
*)
|
|
cat 1>&2 <<EOF
|
|
Error: Libreswan version '$swan_ver' is not supported.
|
|
This script requires one of these versions:
|
|
3.19-3.23, 3.25-3.27, 3.29, 3.31-3.32 or 4.x
|
|
To update Libreswan, see:
|
|
https://github.com/hwdsl2/setup-ipsec-vpn#upgrade-libreswan
|
|
EOF
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
check_utils_exist() {
|
|
command -v certutil >/dev/null 2>&1 || exiterr "'certutil' not found. Abort."
|
|
command -v pk12util >/dev/null 2>&1 || exiterr "'pk12util' not found. Abort."
|
|
}
|
|
|
|
check_container() {
|
|
in_container=0
|
|
if grep -qs "hwdsl2" /opt/src/run.sh; then
|
|
in_container=1
|
|
fi
|
|
}
|
|
|
|
show_usage() {
|
|
if [ -n "$1" ]; then
|
|
echo "Error: $1" >&2;
|
|
fi
|
|
cat 1>&2 <<EOF
|
|
Usage: bash $0 [options]
|
|
|
|
Options:
|
|
--auto run IKEv2 setup in auto mode using default options (for initial IKEv2 setup only)
|
|
--addclient [client name] add a new IKEv2 client using default options (after IKEv2 setup)
|
|
--exportclient [client name] export an existing IKEv2 client using default options (after IKEv2 setup)
|
|
--listclients list the names of existing IKEv2 clients (after IKEv2 setup)
|
|
--removeikev2 remove IKEv2 and delete all certificates and keys from the IPsec database
|
|
-h, --help show this help message and exit
|
|
|
|
To customize IKEv2 or client options, run this script without arguments.
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
check_arguments() {
|
|
if [ "$use_defaults" = "1" ]; then
|
|
if grep -qs "conn ikev2-cp" /etc/ipsec.conf || [ -f /etc/ipsec.d/ikev2.conf ]; then
|
|
echo "Warning: Ignoring parameter '--auto'. Use '-h' for usage information." >&2
|
|
echo >&2
|
|
fi
|
|
fi
|
|
if [ "$((add_client_using_defaults + export_client_using_defaults + list_clients))" -gt 1 ]; then
|
|
show_usage "Invalid parameters. Specify only one of '--addclient', '--exportclient' or '--listclients'."
|
|
fi
|
|
if [ "$add_client_using_defaults" = "1" ]; then
|
|
if ! grep -qs "conn ikev2-cp" /etc/ipsec.conf && [ ! -f /etc/ipsec.d/ikev2.conf ]; then
|
|
exiterr "You must first set up IKEv2 before adding a new client."
|
|
fi
|
|
if [ -z "$client_name" ] || [ "${#client_name}" -gt "64" ] \
|
|
|| printf '%s' "$client_name" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\+' \
|
|
|| case $client_name in -*) true;; *) false;; esac; then
|
|
exiterr "Invalid client name. Use one word only, no special characters except '-' and '_'."
|
|
elif certutil -L -d sql:/etc/ipsec.d -n "$client_name" >/dev/null 2>&1; then
|
|
exiterr "Invalid client name. Client '$client_name' already exists."
|
|
fi
|
|
fi
|
|
if [ "$export_client_using_defaults" = "1" ]; then
|
|
if ! grep -qs "conn ikev2-cp" /etc/ipsec.conf && [ ! -f /etc/ipsec.d/ikev2.conf ]; then
|
|
exiterr "You must first set up IKEv2 before exporting a client configuration."
|
|
fi
|
|
get_server_address
|
|
if [ -z "$client_name" ] || [ "${#client_name}" -gt "64" ] \
|
|
|| printf '%s' "$client_name" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\+' \
|
|
|| [ "$client_name" = "IKEv2 VPN CA" ] || [ "$client_name" = "$server_addr" ] \
|
|
|| case $client_name in -*) true;; *) false;; esac \
|
|
|| ! certutil -L -d sql:/etc/ipsec.d -n "$client_name" >/dev/null 2>&1; then
|
|
exiterr "Invalid client name, or client does not exist."
|
|
fi
|
|
fi
|
|
if [ "$list_clients" = "1" ]; then
|
|
if ! grep -qs "conn ikev2-cp" /etc/ipsec.conf && [ ! -f /etc/ipsec.d/ikev2.conf ]; then
|
|
exiterr "You must first set up IKEv2 before listing clients."
|
|
fi
|
|
fi
|
|
if [ "$remove_ikev2" = "1" ]; then
|
|
if ! grep -qs "conn ikev2-cp" /etc/ipsec.conf && [ ! -f /etc/ipsec.d/ikev2.conf ]; then
|
|
exiterr "Cannot remove IKEv2 because it has not been set up on this server."
|
|
fi
|
|
if [ "$((add_client_using_defaults + export_client_using_defaults + list_clients + use_defaults))" -gt 0 ]; then
|
|
show_usage "Invalid parameters. '--removeikev2' cannot be specified with other parameters."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
check_server_dns_name() {
|
|
if [ -n "$VPN_DNS_NAME" ]; then
|
|
check_dns_name "$VPN_DNS_NAME" || exiterr "Invalid DNS name. 'VPN_DNS_NAME' must be a fully qualified domain name (FQDN)."
|
|
fi
|
|
}
|
|
|
|
check_custom_dns() {
|
|
if { [ -n "$VPN_DNS_SRV1" ] && ! check_ip "$VPN_DNS_SRV1"; } \
|
|
|| { [ -n "$VPN_DNS_SRV2" ] && ! check_ip "$VPN_DNS_SRV2"; } then
|
|
exiterr "The DNS server specified is invalid."
|
|
fi
|
|
}
|
|
|
|
check_ca_cert_exists() {
|
|
if certutil -L -d sql:/etc/ipsec.d -n "IKEv2 VPN CA" >/dev/null 2>&1; then
|
|
exiterr "Certificate 'IKEv2 VPN CA' already exists."
|
|
fi
|
|
}
|
|
|
|
check_server_cert_exists() {
|
|
if certutil -L -d sql:/etc/ipsec.d -n "$server_addr" >/dev/null 2>&1; then
|
|
echo "Error: Certificate '$server_addr' already exists." >&2
|
|
echo "Abort. No changes were made." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_client_cert_exists() {
|
|
if certutil -L -d sql:/etc/ipsec.d -n "$client_name" >/dev/null 2>&1; then
|
|
echo "Error: Client '$client_name' already exists." >&2
|
|
echo "Abort. No changes were made." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_swan_ver() {
|
|
if [ "$in_container" = "0" ]; then
|
|
swan_ver_url="https://dl.ls20.com/v1/$os_type/$os_ver/swanverikev2?arch=$os_arch&ver=$swan_ver&auto=$use_defaults"
|
|
else
|
|
swan_ver_url="https://dl.ls20.com/v1/docker/$os_arch/swanverikev2?ver=$swan_ver&auto=$use_defaults"
|
|
fi
|
|
swan_ver_latest=$(wget -t 3 -T 15 -qO- "$swan_ver_url")
|
|
}
|
|
|
|
run_swan_update() {
|
|
update_url=vpnupgrade
|
|
if [ "$os_type" = "centos" ] || [ "$os_type" = "rhel" ]; then
|
|
update_url=vpnupgrade-centos
|
|
elif [ "$os_type" = "amzn" ]; then
|
|
update_url=vpnupgrade-amzn
|
|
fi
|
|
TMPDIR=$(mktemp -d /tmp/vpnupg.XXX 2>/dev/null)
|
|
if [ -d "$TMPDIR" ]; then
|
|
set -x
|
|
if wget -t 3 -T 30 -q -O "$TMPDIR/vpnupg.sh" "https://git.io/$update_url"; then
|
|
/bin/sh "$TMPDIR/vpnupg.sh"
|
|
fi
|
|
{ set +x; } 2>&-
|
|
[ ! -s "$TMPDIR/vpnupg.sh" ] && echo "Error: Could not download update script." >&2
|
|
/bin/rm -f "$TMPDIR/vpnupg.sh"
|
|
/bin/rmdir "$TMPDIR"
|
|
else
|
|
echo "Error: Could not create temporary directory." >&2
|
|
fi
|
|
read -n 1 -s -r -p "Press any key to continue IKEv2 setup..."
|
|
echo
|
|
}
|
|
|
|
select_swan_update() {
|
|
if printf '%s' "$swan_ver_latest" | grep -Eq '^([3-9]|[1-9][0-9])\.([0-9]|[1-9][0-9])$' \
|
|
&& [ "$swan_ver" != "$swan_ver_latest" ] \
|
|
&& printf '%s\n%s' "$swan_ver" "$swan_ver_latest" | sort -C -V; then
|
|
echo "Note: A newer version of Libreswan ($swan_ver_latest) is available."
|
|
echo " It is recommended to update Libreswan before setting up IKEv2."
|
|
if [ "$in_container" = "0" ]; then
|
|
echo
|
|
printf "Do you want to update Libreswan? [Y/n] "
|
|
read -r response
|
|
case $response in
|
|
[yY][eE][sS]|[yY]|'')
|
|
echo
|
|
run_swan_update
|
|
;;
|
|
*)
|
|
echo
|
|
;;
|
|
esac
|
|
else
|
|
echo " To update this Docker image, see: https://git.io/updatedockervpn"
|
|
echo
|
|
printf "Do you want to continue anyway? [y/N] "
|
|
read -r response
|
|
case $response in
|
|
[yY][eE][sS]|[yY])
|
|
echo
|
|
;;
|
|
*)
|
|
echo "Abort. No changes were made."
|
|
exit 1
|
|
;;
|
|
esac
|
|
fi
|
|
fi
|
|
}
|
|
|
|
show_welcome_message() {
|
|
clear
|
|
cat <<'EOF'
|
|
Welcome! Use this script to set up IKEv2 after setting up your own IPsec VPN server.
|
|
Alternatively, you may manually set up IKEv2. See: https://git.io/ikev2
|
|
|
|
I need to ask you a few questions before starting setup.
|
|
You can use the default options and just press enter if you are OK with them.
|
|
|
|
EOF
|
|
}
|
|
|
|
show_start_message() {
|
|
bigecho "Starting IKEv2 setup in auto mode, using default options."
|
|
}
|
|
|
|
show_add_client_message() {
|
|
bigecho "Adding a new IKEv2 client '$client_name', using default options."
|
|
}
|
|
|
|
show_export_client_message() {
|
|
bigecho "Exporting existing IKEv2 client '$client_name', using default options."
|
|
}
|
|
|
|
get_export_dir() {
|
|
export_to_home_dir=0
|
|
if grep -qs "hwdsl2" /opt/src/run.sh; then
|
|
export_dir="/etc/ipsec.d/"
|
|
else
|
|
export_dir=~/
|
|
if [ -n "$SUDO_USER" ] && getent group "$SUDO_USER" >/dev/null 2>&1; then
|
|
user_home_dir=$(getent passwd "$SUDO_USER" 2>/dev/null | cut -d: -f6)
|
|
if [ -d "$user_home_dir" ] && [ "$user_home_dir" != "/" ]; then
|
|
export_dir="$user_home_dir/"
|
|
export_to_home_dir=1
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
get_server_ip() {
|
|
bigecho "Trying to auto discover IP of this server..."
|
|
public_ip=$(dig @resolver1.opendns.com -t A -4 myip.opendns.com +short)
|
|
check_ip "$public_ip" || public_ip=$(wget -t 3 -T 15 -qO- http://ipv4.icanhazip.com)
|
|
}
|
|
|
|
get_server_address() {
|
|
server_addr=$(grep -s "leftcert=" /etc/ipsec.d/ikev2.conf | cut -f2 -d=)
|
|
[ -z "$server_addr" ] && server_addr=$(grep -s "leftcert=" /etc/ipsec.conf | cut -f2 -d=)
|
|
check_ip "$server_addr" || check_dns_name "$server_addr" || exiterr "Could not get VPN server address."
|
|
}
|
|
|
|
list_existing_clients() {
|
|
echo "Checking for existing IKEv2 client(s)..."
|
|
certutil -L -d sql:/etc/ipsec.d | grep -v -e '^$' -e 'IKEv2 VPN CA' -e '\.' | tail -n +3 | cut -f1 -d ' '
|
|
}
|
|
|
|
enter_server_address() {
|
|
echo "Do you want IKEv2 VPN clients to connect to this server using a DNS name,"
|
|
printf "e.g. vpn.example.com, instead of its IP address? [y/N] "
|
|
read -r response
|
|
case $response in
|
|
[yY][eE][sS]|[yY])
|
|
use_dns_name=1
|
|
echo
|
|
;;
|
|
*)
|
|
use_dns_name=0
|
|
echo
|
|
;;
|
|
esac
|
|
|
|
if [ "$use_dns_name" = "1" ]; then
|
|
read -rp "Enter the DNS name of this VPN server: " server_addr
|
|
until check_dns_name "$server_addr"; do
|
|
echo "Invalid DNS name. You must enter a fully qualified domain name (FQDN)."
|
|
read -rp "Enter the DNS name of this VPN server: " server_addr
|
|
done
|
|
else
|
|
get_server_ip
|
|
echo
|
|
read -rp "Enter the IPv4 address of this VPN server: [$public_ip] " server_addr
|
|
[ -z "$server_addr" ] && server_addr="$public_ip"
|
|
until check_ip "$server_addr"; do
|
|
echo "Invalid IP address."
|
|
read -rp "Enter the IPv4 address of this VPN server: [$public_ip] " server_addr
|
|
[ -z "$server_addr" ] && server_addr="$public_ip"
|
|
done
|
|
fi
|
|
}
|
|
|
|
enter_client_name() {
|
|
echo
|
|
echo "Provide a name for the IKEv2 VPN client."
|
|
echo "Use one word only, no special characters except '-' and '_'."
|
|
read -rp "Client name: " client_name
|
|
while [ -z "$client_name" ] || [ "${#client_name}" -gt "64" ] \
|
|
|| printf '%s' "$client_name" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\+' \
|
|
|| case $client_name in -*) true;; *) false;; esac \
|
|
|| certutil -L -d sql:/etc/ipsec.d -n "$client_name" >/dev/null 2>&1; do
|
|
if [ -z "$client_name" ] || [ "${#client_name}" -gt "64" ] \
|
|
|| printf '%s' "$client_name" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\+' \
|
|
|| case $client_name in -*) true;; *) false;; esac; then
|
|
echo "Invalid client name."
|
|
else
|
|
echo "Invalid client name. Client '$client_name' already exists."
|
|
fi
|
|
read -rp "Client name: " client_name
|
|
done
|
|
}
|
|
|
|
enter_client_name_with_defaults() {
|
|
echo
|
|
echo "Provide a name for the IKEv2 VPN client."
|
|
echo "Use one word only, no special characters except '-' and '_'."
|
|
read -rp "Client name: [vpnclient] " client_name
|
|
[ -z "$client_name" ] && client_name=vpnclient
|
|
while [ "${#client_name}" -gt "64" ] \
|
|
|| printf '%s' "$client_name" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\+' \
|
|
|| case $client_name in -*) true;; *) false;; esac \
|
|
|| certutil -L -d sql:/etc/ipsec.d -n "$client_name" >/dev/null 2>&1; do
|
|
if [ "${#client_name}" -gt "64" ] \
|
|
|| printf '%s' "$client_name" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\+' \
|
|
|| case $client_name in -*) true;; *) false;; esac; then
|
|
echo "Invalid client name."
|
|
else
|
|
echo "Invalid client name. Client '$client_name' already exists."
|
|
fi
|
|
read -rp "Client name: [vpnclient] " client_name
|
|
[ -z "$client_name" ] && client_name=vpnclient
|
|
done
|
|
}
|
|
|
|
enter_client_name_for_export() {
|
|
echo
|
|
list_existing_clients
|
|
get_server_address
|
|
echo
|
|
read -rp "Enter the name of the IKEv2 client to export: " client_name
|
|
while [ -z "$client_name" ] || [ "${#client_name}" -gt "64" ] \
|
|
|| printf '%s' "$client_name" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\+' \
|
|
|| [ "$client_name" = "IKEv2 VPN CA" ] || [ "$client_name" = "$server_addr" ] \
|
|
|| case $client_name in -*) true;; *) false;; esac \
|
|
|| ! certutil -L -d sql:/etc/ipsec.d -n "$client_name" >/dev/null 2>&1; do
|
|
echo "Invalid client name, or client does not exist."
|
|
read -rp "Enter the name of the IKEv2 client to export: " client_name
|
|
done
|
|
}
|
|
|
|
enter_client_cert_validity() {
|
|
echo
|
|
echo "Specify the validity period (in months) for this VPN client certificate."
|
|
read -rp "Enter a number between 1 and 120: [120] " client_validity
|
|
[ -z "$client_validity" ] && client_validity=120
|
|
while printf '%s' "$client_validity" | LC_ALL=C grep -q '[^0-9]\+' \
|
|
|| [ "$client_validity" -lt "1" ] || [ "$client_validity" -gt "120" ] \
|
|
|| [ "$client_validity" != "$((10#$client_validity))" ]; do
|
|
echo "Invalid validity period."
|
|
read -rp "Enter a number between 1 and 120: [120] " client_validity
|
|
[ -z "$client_validity" ] && client_validity=120
|
|
done
|
|
}
|
|
|
|
enter_custom_dns() {
|
|
echo
|
|
echo "By default, clients are set to use Google Public DNS when the VPN is active."
|
|
printf "Do you want to specify custom DNS servers for IKEv2? [y/N] "
|
|
read -r response
|
|
case $response in
|
|
[yY][eE][sS]|[yY])
|
|
use_custom_dns=1
|
|
;;
|
|
*)
|
|
use_custom_dns=0
|
|
dns_server_1=8.8.8.8
|
|
dns_server_2=8.8.4.4
|
|
dns_servers="8.8.8.8 8.8.4.4"
|
|
;;
|
|
esac
|
|
|
|
if [ "$use_custom_dns" = "1" ]; then
|
|
read -rp "Enter primary DNS server: " dns_server_1
|
|
until check_ip "$dns_server_1"; do
|
|
echo "Invalid DNS server."
|
|
read -rp "Enter primary DNS server: " dns_server_1
|
|
done
|
|
|
|
read -rp "Enter secondary DNS server (Enter to skip): " dns_server_2
|
|
until [ -z "$dns_server_2" ] || check_ip "$dns_server_2"; do
|
|
echo "Invalid DNS server."
|
|
read -rp "Enter secondary DNS server (Enter to skip): " dns_server_2
|
|
done
|
|
|
|
if [ -n "$dns_server_2" ]; then
|
|
dns_servers="$dns_server_1 $dns_server_2"
|
|
else
|
|
dns_servers="$dns_server_1"
|
|
fi
|
|
else
|
|
echo "Using Google Public DNS (8.8.8.8, 8.8.4.4)."
|
|
fi
|
|
echo
|
|
}
|
|
|
|
check_mobike_support() {
|
|
mobike_support=0
|
|
case $swan_ver in
|
|
3.2[35679]|3.3[12]|4.*)
|
|
mobike_support=1
|
|
;;
|
|
esac
|
|
|
|
if uname -m | grep -qi -e '^arm' -e '^aarch64'; then
|
|
modprobe -q configs
|
|
if [ -f /proc/config.gz ]; then
|
|
if ! zcat /proc/config.gz | grep -q "CONFIG_XFRM_MIGRATE=y"; then
|
|
mobike_support=0
|
|
fi
|
|
else
|
|
mobike_support=0
|
|
fi
|
|
fi
|
|
|
|
kernel_conf="/boot/config-$(uname -r)"
|
|
if [ -f "$kernel_conf" ]; then
|
|
if ! grep -qs "CONFIG_XFRM_MIGRATE=y" "$kernel_conf"; then
|
|
mobike_support=0
|
|
fi
|
|
fi
|
|
|
|
# Linux kernels on Ubuntu do not support MOBIKE
|
|
if [ "$in_container" = "0" ]; then
|
|
if [ "$os_type" = "ubuntu" ] || uname -v | grep -qi ubuntu; then
|
|
mobike_support=0
|
|
fi
|
|
else
|
|
if uname -v | grep -qi ubuntu; then
|
|
mobike_support=0
|
|
fi
|
|
fi
|
|
|
|
echo -n "## Checking for MOBIKE support... "
|
|
if [ "$mobike_support" = "1" ]; then
|
|
echo "available"
|
|
else
|
|
echo "not available"
|
|
fi
|
|
}
|
|
|
|
select_mobike() {
|
|
mobike_enable=0
|
|
if [ "$mobike_support" = "1" ]; then
|
|
echo
|
|
echo "The MOBIKE IKEv2 extension allows VPN clients to change network attachment points,"
|
|
echo "e.g. switch between mobile data and Wi-Fi and keep the IPsec tunnel up on the new IP."
|
|
echo
|
|
printf "Do you want to enable MOBIKE support? [Y/n] "
|
|
read -r response
|
|
case $response in
|
|
[yY][eE][sS]|[yY]|'')
|
|
mobike_enable=1
|
|
;;
|
|
*)
|
|
mobike_enable=0
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
select_p12_password() {
|
|
cat <<'EOF'
|
|
|
|
Client configuration will be exported as .p12, .sswan and .mobileconfig files,
|
|
which contain the client certificate, private key and CA certificate.
|
|
To protect these files, this script can generate a random password for you,
|
|
which will be displayed when finished.
|
|
|
|
EOF
|
|
|
|
printf "Do you want to specify your own password instead? [y/N] "
|
|
read -r response
|
|
case $response in
|
|
[yY][eE][sS]|[yY])
|
|
use_own_password=1
|
|
echo
|
|
;;
|
|
*)
|
|
use_own_password=0
|
|
echo
|
|
;;
|
|
esac
|
|
}
|
|
|
|
select_menu_option() {
|
|
echo "IKEv2 is already set up on this server."
|
|
echo
|
|
echo "Select an option:"
|
|
echo " 1) Add a new client"
|
|
echo " 2) Export configuration for an existing client"
|
|
echo " 3) List existing clients"
|
|
echo " 4) Remove IKEv2"
|
|
echo " 5) Exit"
|
|
read -rp "Option: " selected_option
|
|
until [[ "$selected_option" =~ ^[1-5]$ ]]; do
|
|
printf '%s\n' "$selected_option: invalid selection."
|
|
read -rp "Option: " selected_option
|
|
done
|
|
}
|
|
|
|
confirm_setup_options() {
|
|
cat <<EOF
|
|
Below are the IKEv2 setup options you selected.
|
|
Please double check before continuing!
|
|
|
|
======================================
|
|
|
|
VPN server address: $server_addr
|
|
VPN client name: $client_name
|
|
|
|
EOF
|
|
|
|
if [ "$client_validity" = "1" ]; then
|
|
echo "Client cert valid for: 1 month"
|
|
else
|
|
echo "Client cert valid for: $client_validity months"
|
|
fi
|
|
|
|
if [ "$mobike_support" = "1" ]; then
|
|
if [ "$mobike_enable" = "1" ]; then
|
|
echo "MOBIKE support: Enable"
|
|
else
|
|
echo "MOBIKE support: Disable"
|
|
fi
|
|
else
|
|
echo "MOBIKE support: Not available"
|
|
fi
|
|
|
|
cat <<EOF
|
|
DNS server(s): $dns_servers
|
|
|
|
======================================
|
|
|
|
EOF
|
|
|
|
printf "We are ready to set up IKEv2 now. Do you want to continue? [y/N] "
|
|
read -r response
|
|
case $response in
|
|
[yY][eE][sS]|[yY])
|
|
echo
|
|
;;
|
|
*)
|
|
echo "Abort. No changes were made."
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
create_client_cert() {
|
|
bigecho "Generating client certificate..."
|
|
|
|
sleep $((RANDOM % 3 + 1))
|
|
|
|
certutil -z <(head -c 1024 /dev/urandom) \
|
|
-S -c "IKEv2 VPN CA" -n "$client_name" \
|
|
-s "O=IKEv2 VPN,CN=$client_name" \
|
|
-k rsa -v "$client_validity" \
|
|
-d sql:/etc/ipsec.d -t ",," \
|
|
--keyUsage digitalSignature,keyEncipherment \
|
|
--extKeyUsage serverAuth,clientAuth -8 "$client_name" >/dev/null 2>&1 || exiterr "Failed to create client certificate."
|
|
}
|
|
|
|
export_p12_file() {
|
|
bigecho "Creating client configuration..."
|
|
|
|
if [ "$use_own_password" = "1" ]; then
|
|
cat <<'EOF'
|
|
Enter a *secure* password to protect the client configuration files.
|
|
When importing into an iOS or macOS device, this password cannot be empty.
|
|
|
|
EOF
|
|
else
|
|
p12_password=$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' < /dev/urandom | head -c 16)
|
|
[ -z "$p12_password" ] && exiterr "Could not generate a random password for .p12 file."
|
|
fi
|
|
|
|
p12_file="$export_dir$client_name.p12"
|
|
if [ "$use_own_password" = "1" ]; then
|
|
pk12util -d sql:/etc/ipsec.d -n "$client_name" -o "$p12_file" || exit 1
|
|
else
|
|
pk12util -W "$p12_password" -d sql:/etc/ipsec.d -n "$client_name" -o "$p12_file" >/dev/null || exit 1
|
|
fi
|
|
|
|
if [ "$export_to_home_dir" = "1" ]; then
|
|
chown "$SUDO_USER:$SUDO_USER" "$p12_file"
|
|
fi
|
|
chmod 600 "$p12_file"
|
|
}
|
|
|
|
install_base64_uuidgen() {
|
|
if ! command -v base64 >/dev/null 2>&1 || ! command -v uuidgen >/dev/null 2>&1; then
|
|
bigecho "Installing required packages..."
|
|
if [ "$os_type" = "ubuntu" ] || [ "$os_type" = "debian" ] || [ "$os_type" = "raspbian" ]; then
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
(
|
|
set -x
|
|
apt-get -yqq update
|
|
) || exiterr "'apt-get update' failed."
|
|
fi
|
|
fi
|
|
if ! command -v base64 >/dev/null 2>&1; then
|
|
if [ "$os_type" = "ubuntu" ] || [ "$os_type" = "debian" ] || [ "$os_type" = "raspbian" ]; then
|
|
(
|
|
set -x
|
|
apt-get -yqq install coreutils >/dev/null
|
|
) || exiterr "'apt-get install' failed."
|
|
else
|
|
(
|
|
set -x
|
|
yum -y -q install coreutils >/dev/null
|
|
) || exiterr "'yum install' failed."
|
|
fi
|
|
fi
|
|
if ! command -v uuidgen >/dev/null 2>&1; then
|
|
if [ "$os_type" = "ubuntu" ] || [ "$os_type" = "debian" ] || [ "$os_type" = "raspbian" ]; then
|
|
(
|
|
set -x
|
|
apt-get -yqq install uuid-runtime >/dev/null
|
|
) || exiterr "'apt-get install' failed."
|
|
else
|
|
(
|
|
set -x
|
|
yum -y -q install util-linux >/dev/null
|
|
) || exiterr "'yum install' failed."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
create_mobileconfig() {
|
|
[ -z "$server_addr" ] && get_server_address
|
|
|
|
p12_base64=$(base64 -w 52 "$export_dir$client_name.p12")
|
|
[ -z "$p12_base64" ] && exiterr "Could not encode .p12 file."
|
|
|
|
ca_base64=$(certutil -L -d sql:/etc/ipsec.d -n "IKEv2 VPN CA" -a | grep -v CERTIFICATE)
|
|
[ -z "$ca_base64" ] && exiterr "Could not encode IKEv2 VPN CA certificate."
|
|
|
|
uuid1=$(uuidgen)
|
|
[ -z "$uuid1" ] && exiterr "Could not generate UUID value."
|
|
|
|
mc_file="$export_dir$client_name.mobileconfig"
|
|
|
|
cat > "$mc_file" <<EOF
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>PayloadContent</key>
|
|
<array>
|
|
<dict>
|
|
<key>IKEv2</key>
|
|
<dict>
|
|
<key>AuthenticationMethod</key>
|
|
<string>Certificate</string>
|
|
<key>ChildSecurityAssociationParameters</key>
|
|
<dict>
|
|
<key>DiffieHellmanGroup</key>
|
|
<integer>14</integer>
|
|
<key>EncryptionAlgorithm</key>
|
|
<string>AES-256-GCM</string>
|
|
<key>LifeTimeInMinutes</key>
|
|
<integer>1410</integer>
|
|
</dict>
|
|
<key>DeadPeerDetectionRate</key>
|
|
<string>Medium</string>
|
|
<key>DisableRedirect</key>
|
|
<true/>
|
|
<key>EnableCertificateRevocationCheck</key>
|
|
<integer>0</integer>
|
|
<key>EnablePFS</key>
|
|
<integer>0</integer>
|
|
<key>IKESecurityAssociationParameters</key>
|
|
<dict>
|
|
<key>DiffieHellmanGroup</key>
|
|
<integer>14</integer>
|
|
<key>EncryptionAlgorithm</key>
|
|
<string>AES-256</string>
|
|
<key>IntegrityAlgorithm</key>
|
|
<string>SHA2-256</string>
|
|
<key>LifeTimeInMinutes</key>
|
|
<integer>1410</integer>
|
|
</dict>
|
|
<key>LocalIdentifier</key>
|
|
<string>$client_name</string>
|
|
<key>PayloadCertificateUUID</key>
|
|
<string>$uuid1</string>
|
|
<key>OnDemandEnabled</key>
|
|
<integer>0</integer>
|
|
<key>OnDemandRules</key>
|
|
<array>
|
|
<dict>
|
|
<key>Action</key>
|
|
<string>Connect</string>
|
|
</dict>
|
|
</array>
|
|
<key>RemoteAddress</key>
|
|
<string>$server_addr</string>
|
|
<key>RemoteIdentifier</key>
|
|
<string>$server_addr</string>
|
|
<key>UseConfigurationAttributeInternalIPSubnet</key>
|
|
<integer>0</integer>
|
|
</dict>
|
|
<key>IPv4</key>
|
|
<dict>
|
|
<key>OverridePrimary</key>
|
|
<integer>1</integer>
|
|
</dict>
|
|
<key>PayloadDescription</key>
|
|
<string>Configures VPN settings</string>
|
|
<key>PayloadDisplayName</key>
|
|
<string>VPN</string>
|
|
<key>PayloadIdentifier</key>
|
|
<string>com.apple.vpn.managed.$(uuidgen)</string>
|
|
<key>PayloadType</key>
|
|
<string>com.apple.vpn.managed</string>
|
|
<key>PayloadUUID</key>
|
|
<string>$(uuidgen)</string>
|
|
<key>PayloadVersion</key>
|
|
<integer>1</integer>
|
|
<key>Proxies</key>
|
|
<dict>
|
|
<key>HTTPEnable</key>
|
|
<integer>0</integer>
|
|
<key>HTTPSEnable</key>
|
|
<integer>0</integer>
|
|
</dict>
|
|
<key>UserDefinedName</key>
|
|
<string>$server_addr</string>
|
|
<key>VPNType</key>
|
|
<string>IKEv2</string>
|
|
</dict>
|
|
<dict>
|
|
<key>PayloadCertificateFileName</key>
|
|
<string>$client_name</string>
|
|
<key>PayloadContent</key>
|
|
<data>
|
|
$p12_base64
|
|
</data>
|
|
<key>PayloadDescription</key>
|
|
<string>Adds a PKCS#12-formatted certificate</string>
|
|
<key>PayloadDisplayName</key>
|
|
<string>$client_name</string>
|
|
<key>PayloadIdentifier</key>
|
|
<string>com.apple.security.pkcs12.$(uuidgen)</string>
|
|
<key>PayloadType</key>
|
|
<string>com.apple.security.pkcs12</string>
|
|
<key>PayloadUUID</key>
|
|
<string>$uuid1</string>
|
|
<key>PayloadVersion</key>
|
|
<integer>1</integer>
|
|
</dict>
|
|
<dict>
|
|
<key>PayloadContent</key>
|
|
<data>
|
|
$ca_base64
|
|
</data>
|
|
<key>PayloadCertificateFileName</key>
|
|
<string>ikev2vpnca</string>
|
|
<key>PayloadDescription</key>
|
|
<string>Adds a CA root certificate</string>
|
|
<key>PayloadDisplayName</key>
|
|
<string>Certificate Authority (CA)</string>
|
|
<key>PayloadIdentifier</key>
|
|
<string>com.apple.security.root.$(uuidgen)</string>
|
|
<key>PayloadType</key>
|
|
<string>com.apple.security.root</string>
|
|
<key>PayloadUUID</key>
|
|
<string>$(uuidgen)</string>
|
|
<key>PayloadVersion</key>
|
|
<integer>1</integer>
|
|
</dict>
|
|
</array>
|
|
<key>PayloadDisplayName</key>
|
|
<string>IKEv2 VPN configuration ($server_addr)</string>
|
|
<key>PayloadIdentifier</key>
|
|
<string>com.apple.vpn.managed.$(uuidgen)</string>
|
|
<key>PayloadRemovalDisallowed</key>
|
|
<false/>
|
|
<key>PayloadType</key>
|
|
<string>Configuration</string>
|
|
<key>PayloadUUID</key>
|
|
<string>$(uuidgen)</string>
|
|
<key>PayloadVersion</key>
|
|
<integer>1</integer>
|
|
</dict>
|
|
</plist>
|
|
EOF
|
|
|
|
if [ "$export_to_home_dir" = "1" ]; then
|
|
chown "$SUDO_USER:$SUDO_USER" "$mc_file"
|
|
fi
|
|
chmod 600 "$mc_file"
|
|
}
|
|
|
|
create_android_profile() {
|
|
[ -z "$server_addr" ] && get_server_address
|
|
|
|
p12_base64_oneline=$(base64 -w 52 "$export_dir$client_name.p12" | sed 's/$/\\n/' | tr -d '\n')
|
|
[ -z "$p12_base64_oneline" ] && exiterr "Could not encode .p12 file."
|
|
|
|
uuid2=$(uuidgen)
|
|
[ -z "$uuid2" ] && exiterr "Could not generate UUID value."
|
|
|
|
sswan_file="$export_dir$client_name.sswan"
|
|
|
|
cat > "$sswan_file" <<EOF
|
|
{
|
|
"uuid": "$uuid2",
|
|
"name": "IKEv2 VPN profile ($server_addr)",
|
|
"type": "ikev2-cert",
|
|
"remote": {
|
|
"addr": "$server_addr"
|
|
},
|
|
"local": {
|
|
"p12": "$p12_base64_oneline",
|
|
"rsa-pss": "true"
|
|
},
|
|
"ike-proposal": "aes256-sha256-modp2048",
|
|
"esp-proposal": "aes256gcm16"
|
|
}
|
|
EOF
|
|
|
|
if [ "$export_to_home_dir" = "1" ]; then
|
|
chown "$SUDO_USER:$SUDO_USER" "$sswan_file"
|
|
fi
|
|
chmod 600 "$sswan_file"
|
|
}
|
|
|
|
create_ca_server_certs() {
|
|
bigecho "Generating CA and server certificates..."
|
|
|
|
certutil -z <(head -c 1024 /dev/urandom) \
|
|
-S -x -n "IKEv2 VPN CA" \
|
|
-s "O=IKEv2 VPN,CN=IKEv2 VPN CA" \
|
|
-k rsa -v 120 \
|
|
-d sql:/etc/ipsec.d -t "CT,," -2 >/dev/null 2>&1 <<ANSWERS || exiterr "Failed to create CA certificate."
|
|
y
|
|
|
|
N
|
|
ANSWERS
|
|
|
|
sleep $((RANDOM % 3 + 1))
|
|
|
|
if [ "$use_dns_name" = "1" ]; then
|
|
certutil -z <(head -c 1024 /dev/urandom) \
|
|
-S -c "IKEv2 VPN CA" -n "$server_addr" \
|
|
-s "O=IKEv2 VPN,CN=$server_addr" \
|
|
-k rsa -v 120 \
|
|
-d sql:/etc/ipsec.d -t ",," \
|
|
--keyUsage digitalSignature,keyEncipherment \
|
|
--extKeyUsage serverAuth \
|
|
--extSAN "dns:$server_addr" >/dev/null 2>&1 || exiterr "Failed to create server certificate."
|
|
else
|
|
certutil -z <(head -c 1024 /dev/urandom) \
|
|
-S -c "IKEv2 VPN CA" -n "$server_addr" \
|
|
-s "O=IKEv2 VPN,CN=$server_addr" \
|
|
-k rsa -v 120 \
|
|
-d sql:/etc/ipsec.d -t ",," \
|
|
--keyUsage digitalSignature,keyEncipherment \
|
|
--extKeyUsage serverAuth \
|
|
--extSAN "ip:$server_addr,dns:$server_addr" >/dev/null 2>&1 || exiterr "Failed to create server certificate."
|
|
fi
|
|
}
|
|
|
|
add_ikev2_connection() {
|
|
bigecho "Adding a new IKEv2 connection..."
|
|
|
|
if ! grep -qs '^include /etc/ipsec\.d/\*\.conf$' /etc/ipsec.conf; then
|
|
echo >> /etc/ipsec.conf
|
|
echo 'include /etc/ipsec.d/*.conf' >> /etc/ipsec.conf
|
|
fi
|
|
|
|
cat > /etc/ipsec.d/ikev2.conf <<EOF
|
|
|
|
conn ikev2-cp
|
|
left=%defaultroute
|
|
leftcert=$server_addr
|
|
leftsendcert=always
|
|
leftsubnet=0.0.0.0/0
|
|
leftrsasigkey=%cert
|
|
right=%any
|
|
rightid=%fromcert
|
|
rightaddresspool=192.168.43.10-192.168.43.250
|
|
rightca=%same
|
|
rightrsasigkey=%cert
|
|
narrowing=yes
|
|
dpddelay=30
|
|
dpdtimeout=120
|
|
dpdaction=clear
|
|
auto=add
|
|
ikev2=insist
|
|
rekey=no
|
|
pfs=no
|
|
fragmentation=yes
|
|
ike=aes256-sha2,aes128-sha2,aes256-sha1,aes128-sha1,aes256-sha2;modp1024,aes128-sha1;modp1024
|
|
phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes128-sha2,aes256-sha2
|
|
ikelifetime=24h
|
|
salifetime=24h
|
|
encapsulation=yes
|
|
EOF
|
|
|
|
if [ "$use_dns_name" = "1" ]; then
|
|
cat >> /etc/ipsec.d/ikev2.conf <<EOF
|
|
leftid=@$server_addr
|
|
EOF
|
|
else
|
|
cat >> /etc/ipsec.d/ikev2.conf <<EOF
|
|
leftid=$server_addr
|
|
EOF
|
|
fi
|
|
|
|
case $swan_ver in
|
|
3.2[35679]|3.3[12]|4.*)
|
|
if [ -n "$dns_server_2" ]; then
|
|
cat >> /etc/ipsec.d/ikev2.conf <<EOF
|
|
modecfgdns="$dns_servers"
|
|
EOF
|
|
else
|
|
cat >> /etc/ipsec.d/ikev2.conf <<EOF
|
|
modecfgdns=$dns_server_1
|
|
EOF
|
|
fi
|
|
if [ "$mobike_enable" = "1" ]; then
|
|
echo " mobike=yes" >> /etc/ipsec.d/ikev2.conf
|
|
else
|
|
echo " mobike=no" >> /etc/ipsec.d/ikev2.conf
|
|
fi
|
|
;;
|
|
3.19|3.2[012])
|
|
if [ -n "$dns_server_2" ]; then
|
|
cat >> /etc/ipsec.d/ikev2.conf <<EOF
|
|
modecfgdns1=$dns_server_1
|
|
modecfgdns2=$dns_server_2
|
|
EOF
|
|
else
|
|
cat >> /etc/ipsec.d/ikev2.conf <<EOF
|
|
modecfgdns1=$dns_server_1
|
|
EOF
|
|
fi
|
|
;;
|
|
esac
|
|
}
|
|
|
|
apply_ubuntu1804_nss_fix() {
|
|
if [ "$os_type" = "ubuntu" ] && [ "$os_ver" = "bustersid" ] && [ "$os_arch" = "x86_64" ]; then
|
|
nss_url1="https://mirrors.kernel.org/ubuntu/pool/main/n/nss"
|
|
nss_url2="https://mirrors.kernel.org/ubuntu/pool/universe/n/nss"
|
|
nss_deb1="libnss3_3.49.1-1ubuntu1.5_amd64.deb"
|
|
nss_deb2="libnss3-dev_3.49.1-1ubuntu1.5_amd64.deb"
|
|
nss_deb3="libnss3-tools_3.49.1-1ubuntu1.5_amd64.deb"
|
|
TMPDIR=$(mktemp -d /tmp/nss.XXX 2>/dev/null)
|
|
if [ -d "$TMPDIR" ]; then
|
|
bigecho "Applying fix for NSS bug on Ubuntu 18.04..."
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
set -x
|
|
if wget -t 3 -T 30 -q -O "$TMPDIR/1.deb" "$nss_url1/$nss_deb1" \
|
|
&& wget -t 3 -T 30 -q -O "$TMPDIR/2.deb" "$nss_url1/$nss_deb2" \
|
|
&& wget -t 3 -T 30 -q -O "$TMPDIR/3.deb" "$nss_url2/$nss_deb3"; then
|
|
apt-get -yqq update
|
|
apt-get -yqq install "$TMPDIR/1.deb" "$TMPDIR/2.deb" "$TMPDIR/3.deb" >/dev/null
|
|
fi
|
|
{ set +x; } 2>&-
|
|
/bin/rm -f "$TMPDIR/1.deb" "$TMPDIR/2.deb" "$TMPDIR/3.deb"
|
|
/bin/rmdir "$TMPDIR"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
restart_ipsec_service() {
|
|
if [ "$in_container" = "0" ] || { [ "$in_container" = "1" ] && service ipsec status >/dev/null 2>&1; } then
|
|
bigecho "Restarting IPsec service..."
|
|
|
|
mkdir -p /run/pluto
|
|
service ipsec restart 2>/dev/null
|
|
fi
|
|
}
|
|
|
|
print_client_added_message() {
|
|
cat <<EOF
|
|
|
|
================================================
|
|
|
|
New IKEv2 VPN client "$client_name" added!
|
|
|
|
VPN server address: $server_addr
|
|
VPN client name: $client_name
|
|
|
|
EOF
|
|
}
|
|
|
|
print_client_exported_message() {
|
|
cat <<EOF
|
|
|
|
================================================
|
|
|
|
IKEv2 VPN client "$client_name" exported!
|
|
|
|
VPN server address: $server_addr
|
|
VPN client name: $client_name
|
|
|
|
EOF
|
|
}
|
|
|
|
show_swan_update_info() {
|
|
if printf '%s' "$swan_ver_latest" | grep -Eq '^([3-9]|[1-9][0-9])\.([0-9]|[1-9][0-9])$' \
|
|
&& [ "$swan_ver" != "$swan_ver_latest" ] \
|
|
&& printf '%s\n%s' "$swan_ver" "$swan_ver_latest" | sort -C -V; then
|
|
echo
|
|
echo "Note: A newer version of Libreswan ($swan_ver_latest) is available."
|
|
if [ "$in_container" = "0" ]; then
|
|
echo " To update, run:"
|
|
update_url=vpnupgrade
|
|
if [ "$os_type" = "centos" ] || [ "$os_type" = "rhel" ]; then
|
|
update_url=vpnupgrade-centos
|
|
elif [ "$os_type" = "amzn" ]; then
|
|
update_url=vpnupgrade-amzn
|
|
fi
|
|
echo " wget https://git.io/$update_url -O vpnupgrade.sh"
|
|
echo " sudo sh vpnupgrade.sh"
|
|
else
|
|
echo " To update this Docker image, see: https://git.io/updatedockervpn"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
print_setup_complete_message() {
|
|
cat <<EOF
|
|
|
|
================================================
|
|
|
|
IKEv2 VPN setup is now complete!
|
|
|
|
VPN server address: $server_addr
|
|
VPN client name: $client_name
|
|
|
|
EOF
|
|
}
|
|
|
|
print_client_info() {
|
|
cat <<EOF
|
|
Client configuration is available at:
|
|
|
|
$export_dir$client_name.p12 (for Windows)
|
|
$export_dir$client_name.sswan (for Android)
|
|
$export_dir$client_name.mobileconfig (for iOS & macOS)
|
|
EOF
|
|
|
|
if [ "$use_own_password" = "0" ]; then
|
|
cat <<EOF
|
|
|
|
*IMPORTANT* Password for client config files:
|
|
$p12_password
|
|
Write this down, you'll need it for import!
|
|
EOF
|
|
fi
|
|
|
|
cat <<'EOF'
|
|
|
|
Next steps: Configure IKEv2 VPN clients. See:
|
|
https://git.io/ikev2clients
|
|
|
|
================================================
|
|
|
|
EOF
|
|
}
|
|
|
|
check_ipsec_conf() {
|
|
if grep -qs "conn ikev2-cp" /etc/ipsec.conf; then
|
|
echo "Error: IKEv2 configuration section found in /etc/ipsec.conf." >&2
|
|
echo " This script cannot automatically remove IKEv2 from this server." >&2
|
|
echo " To manually remove IKEv2, see https://git.io/ikev2" >&2
|
|
echo "Abort. No changes were made." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
confirm_remove_ikev2() {
|
|
echo
|
|
echo "WARNING: This option will remove IKEv2 from this VPN server, but keep the IPsec/L2TP"
|
|
echo " and IPsec/XAuth (\"Cisco IPsec\") modes, if installed. All IKEv2 configuration"
|
|
echo " including certificates and keys will be permanently deleted."
|
|
echo " This *cannot* be undone! "
|
|
echo
|
|
printf "Are you sure you want to remove IKEv2? [y/N] "
|
|
read -r response
|
|
case $response in
|
|
[yY][eE][sS]|[yY])
|
|
echo
|
|
;;
|
|
*)
|
|
echo "Abort. No changes were made."
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
delete_ikev2_conf() {
|
|
bigecho "Deleting /etc/ipsec.d/ikev2.conf..."
|
|
/bin/rm -f /etc/ipsec.d/ikev2.conf
|
|
}
|
|
|
|
delete_certificates() {
|
|
bigecho "Deleting certificates and keys from the IPsec database..."
|
|
certutil -L -d sql:/etc/ipsec.d | grep -v -e '^$' -e 'IKEv2 VPN CA' | tail -n +3 | cut -f1 -d ' ' | while read -r line; do
|
|
certutil -F -d sql:/etc/ipsec.d -n "$line"
|
|
certutil -D -d sql:/etc/ipsec.d -n "$line" 2>/dev/null
|
|
done
|
|
certutil -F -d sql:/etc/ipsec.d -n "IKEv2 VPN CA"
|
|
certutil -D -d sql:/etc/ipsec.d -n "IKEv2 VPN CA" 2>/dev/null
|
|
}
|
|
|
|
print_ikev2_removed_message() {
|
|
echo "IKEv2 removed!"
|
|
}
|
|
|
|
ikev2setup() {
|
|
check_run_as_root
|
|
check_os_type
|
|
check_swan_install
|
|
check_utils_exist
|
|
check_container
|
|
|
|
use_defaults=0
|
|
add_client_using_defaults=0
|
|
export_client_using_defaults=0
|
|
list_clients=0
|
|
remove_ikev2=0
|
|
while [ "$#" -gt 0 ]; do
|
|
case $1 in
|
|
--auto)
|
|
use_defaults=1
|
|
shift
|
|
;;
|
|
--addclient)
|
|
add_client_using_defaults=1
|
|
client_name="$2"
|
|
shift
|
|
shift
|
|
;;
|
|
--exportclient)
|
|
export_client_using_defaults=1
|
|
client_name="$2"
|
|
shift
|
|
shift
|
|
;;
|
|
--listclients)
|
|
list_clients=1
|
|
shift
|
|
;;
|
|
--removeikev2)
|
|
remove_ikev2=1
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
show_usage
|
|
;;
|
|
*)
|
|
show_usage "Unknown parameter: $1"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
check_arguments
|
|
get_export_dir
|
|
|
|
if [ "$add_client_using_defaults" = "1" ]; then
|
|
show_add_client_message
|
|
client_validity=120
|
|
use_own_password=0
|
|
create_client_cert
|
|
install_base64_uuidgen
|
|
export_p12_file
|
|
create_mobileconfig
|
|
create_android_profile
|
|
print_client_added_message
|
|
print_client_info
|
|
exit 0
|
|
fi
|
|
|
|
if [ "$export_client_using_defaults" = "1" ]; then
|
|
show_export_client_message
|
|
use_own_password=0
|
|
install_base64_uuidgen
|
|
export_p12_file
|
|
create_mobileconfig
|
|
create_android_profile
|
|
print_client_exported_message
|
|
print_client_info
|
|
exit 0
|
|
fi
|
|
|
|
if [ "$list_clients" = "1" ]; then
|
|
list_existing_clients
|
|
exit 0
|
|
fi
|
|
|
|
if [ "$remove_ikev2" = "1" ]; then
|
|
check_ipsec_conf
|
|
confirm_remove_ikev2
|
|
delete_ikev2_conf
|
|
restart_ipsec_service
|
|
delete_certificates
|
|
print_ikev2_removed_message
|
|
exit 0
|
|
fi
|
|
|
|
if grep -qs "conn ikev2-cp" /etc/ipsec.conf || [ -f /etc/ipsec.d/ikev2.conf ]; then
|
|
select_menu_option
|
|
case $selected_option in
|
|
1)
|
|
enter_client_name
|
|
enter_client_cert_validity
|
|
select_p12_password
|
|
create_client_cert
|
|
install_base64_uuidgen
|
|
export_p12_file
|
|
create_mobileconfig
|
|
create_android_profile
|
|
print_client_added_message
|
|
print_client_info
|
|
exit 0
|
|
;;
|
|
2)
|
|
enter_client_name_for_export
|
|
select_p12_password
|
|
install_base64_uuidgen
|
|
export_p12_file
|
|
create_mobileconfig
|
|
create_android_profile
|
|
print_client_exported_message
|
|
print_client_info
|
|
exit 0
|
|
;;
|
|
3)
|
|
echo
|
|
list_existing_clients
|
|
exit 0
|
|
;;
|
|
4)
|
|
check_ipsec_conf
|
|
confirm_remove_ikev2
|
|
delete_ikev2_conf
|
|
restart_ipsec_service
|
|
delete_certificates
|
|
print_ikev2_removed_message
|
|
exit 0
|
|
;;
|
|
*)
|
|
exit 0
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
check_ca_cert_exists
|
|
check_swan_ver
|
|
|
|
if [ "$use_defaults" = "0" ]; then
|
|
select_swan_update
|
|
show_welcome_message
|
|
enter_server_address
|
|
check_server_cert_exists
|
|
enter_client_name_with_defaults
|
|
enter_client_cert_validity
|
|
enter_custom_dns
|
|
check_mobike_support
|
|
select_mobike
|
|
select_p12_password
|
|
confirm_setup_options
|
|
else
|
|
check_server_dns_name
|
|
check_custom_dns
|
|
show_start_message
|
|
if [ -n "$VPN_DNS_NAME" ]; then
|
|
use_dns_name=1
|
|
server_addr="$VPN_DNS_NAME"
|
|
else
|
|
use_dns_name=0
|
|
get_server_ip
|
|
check_ip "$public_ip" || exiterr "Cannot detect this server's public IP."
|
|
server_addr="$public_ip"
|
|
fi
|
|
check_server_cert_exists
|
|
client_name=vpnclient
|
|
check_client_cert_exists
|
|
client_validity=120
|
|
if [ -n "$VPN_DNS_SRV1" ] && [ -n "$VPN_DNS_SRV2" ]; then
|
|
dns_server_1="$VPN_DNS_SRV1"
|
|
dns_server_2="$VPN_DNS_SRV2"
|
|
dns_servers="$VPN_DNS_SRV1 $VPN_DNS_SRV2"
|
|
elif [ -n "$VPN_DNS_SRV1" ]; then
|
|
dns_server_1="$VPN_DNS_SRV1"
|
|
dns_server_2=""
|
|
dns_servers="$VPN_DNS_SRV1"
|
|
else
|
|
dns_server_1=8.8.8.8
|
|
dns_server_2=8.8.4.4
|
|
dns_servers="8.8.8.8 8.8.4.4"
|
|
fi
|
|
check_mobike_support
|
|
mobike_enable="$mobike_support"
|
|
use_own_password=0
|
|
fi
|
|
|
|
apply_ubuntu1804_nss_fix
|
|
create_ca_server_certs
|
|
create_client_cert
|
|
install_base64_uuidgen
|
|
export_p12_file
|
|
create_mobileconfig
|
|
create_android_profile
|
|
add_ikev2_connection
|
|
restart_ipsec_service
|
|
|
|
if [ "$use_defaults" = "1" ]; then
|
|
show_swan_update_info
|
|
fi
|
|
|
|
print_setup_complete_message
|
|
print_client_info
|
|
}
|
|
|
|
## Defer setup until we have the complete script
|
|
ikev2setup "$@"
|
|
|
|
exit 0
|