444403ba10
- New: IKEv2 change address helper script. This script can be used to change the IKEv2 VPN server's address.
321 lines
8.6 KiB
Bash
Executable File
321 lines
8.6 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Script to change IKEv2 VPN server address
|
|
#
|
|
# The latest version of this script is available at:
|
|
# https://github.com/hwdsl2/setup-ipsec-vpn
|
|
#
|
|
# Copyright (C) 2022 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_root() {
|
|
if [ "$(id -u)" != 0 ]; then
|
|
exiterr "Script must be run as root. Try 'sudo bash $0'"
|
|
fi
|
|
}
|
|
|
|
check_os() {
|
|
os_type=centos
|
|
rh_file="/etc/redhat-release"
|
|
if grep -qs "Red Hat" "$rh_file"; then
|
|
os_type=rhel
|
|
fi
|
|
if grep -qs "release 7" "$rh_file"; then
|
|
os_ver=7
|
|
elif grep -qs "release 8" "$rh_file"; then
|
|
os_ver=8
|
|
grep -qi stream "$rh_file" && os_ver=8s
|
|
grep -qi rocky "$rh_file" && os_type=rocky
|
|
grep -qi alma "$rh_file" && os_type=alma
|
|
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
|
|
;;
|
|
[Aa]lpine)
|
|
os_type=alpine
|
|
;;
|
|
*)
|
|
cat 1>&2 <<'EOF'
|
|
Error: This script only supports one of the following OS:
|
|
Ubuntu, Debian, CentOS/RHEL 7/8, Rocky Linux, AlmaLinux,
|
|
Amazon Linux 2 or Alpine Linux
|
|
EOF
|
|
exit 1
|
|
;;
|
|
esac
|
|
if [ "$os_type" = "alpine" ]; then
|
|
os_ver=$(. /etc/os-release && printf '%s' "$VERSION_ID" | cut -d '.' -f 1,2)
|
|
if [ "$os_ver" != "3.14" ] && [ "$os_ver" != "3.15" ]; then
|
|
exiterr "This script only supports Alpine Linux 3.14/3.15."
|
|
fi
|
|
else
|
|
os_ver=$(sed 's/\..*//' /etc/debian_version | tr -dc 'A-Za-z0-9')
|
|
fi
|
|
fi
|
|
}
|
|
|
|
check_libreswan() {
|
|
ipsec_ver=$(ipsec --version 2>/dev/null)
|
|
if ( ! grep -qs "hwdsl2 VPN script" /etc/sysctl.conf && ! grep -qs "hwdsl2" /opt/src/run.sh ) \
|
|
|| ! printf '%s' "$ipsec_ver" | grep -q "Libreswan"; then
|
|
cat 1>&2 <<'EOF'
|
|
Error: This script can only be used with an IPsec server created using:
|
|
https://github.com/hwdsl2/setup-ipsec-vpn
|
|
EOF
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_ikev2() {
|
|
if ! grep -qs "conn ikev2-cp" /etc/ipsec.d/ikev2.conf; then
|
|
cat 1>&2 <<'EOF'
|
|
Error: You must first set up IKEv2 before changing IKEv2 server address.
|
|
See: https://git.io/ikev2
|
|
EOF
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_utils_exist() {
|
|
command -v certutil >/dev/null 2>&1 || exiterr "'certutil' not found. Abort."
|
|
}
|
|
|
|
abort_and_exit() {
|
|
echo "Abort. No changes were made." >&2
|
|
exit 1
|
|
}
|
|
|
|
confirm_or_abort() {
|
|
printf '%s' "$1"
|
|
read -r response
|
|
case $response in
|
|
[yY][eE][sS]|[yY])
|
|
echo
|
|
;;
|
|
*)
|
|
abort_and_exit
|
|
;;
|
|
esac
|
|
}
|
|
|
|
check_cert_exists() {
|
|
certutil -L -d sql:/etc/ipsec.d -n "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
check_ca_cert_exists() {
|
|
check_cert_exists "IKEv2 VPN CA" || exiterr "Certificate 'IKEv2 VPN CA' does not exist. Abort."
|
|
}
|
|
|
|
get_server_address() {
|
|
server_addr_old=$(grep -s "leftcert=" /etc/ipsec.d/ikev2.conf | cut -f2 -d=)
|
|
[ -z "$server_addr_old" ] && server_addr_old=$(grep -s "leftcert=" /etc/ipsec.conf | cut -f2 -d=)
|
|
check_ip "$server_addr_old" || check_dns_name "$server_addr_old" || exiterr "Could not get current VPN server address."
|
|
}
|
|
|
|
show_welcome() {
|
|
cat <<EOF
|
|
Welcome! Use this script to change this IKEv2 VPN server's address. A new server
|
|
certificate will be generated if necessary.
|
|
|
|
Current server address: $server_addr_old
|
|
|
|
EOF
|
|
}
|
|
|
|
get_server_ip() {
|
|
bigecho "Trying to auto discover IP of this server..."
|
|
public_ip=${VPN_PUBLIC_IP:-''}
|
|
check_ip "$public_ip" || 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)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
check_server_address() {
|
|
if [ "$server_addr" = "$server_addr_old" ]; then
|
|
echo >&2
|
|
echo "Error: IKEv2 server address is already '$server_addr'. Nothing to do." >&2
|
|
abort_and_exit
|
|
fi
|
|
}
|
|
|
|
confirm_changes() {
|
|
cat <<EOF
|
|
|
|
You are about to change this IKEv2 VPN server's address.
|
|
Read the important notes below before continuing.
|
|
|
|
===========================================
|
|
|
|
Current server address: $server_addr_old
|
|
New server address: $server_addr
|
|
|
|
===========================================
|
|
|
|
*IMPORTANT*
|
|
After running this script, you must manually update the server address
|
|
on any existing IKEv2 client devices. For iOS clients, you'll need to
|
|
export and re-import client configuration using the IKEv2 helper script.
|
|
|
|
EOF
|
|
printf "Do you want to continue? [Y/n] "
|
|
read -r response
|
|
case $response in
|
|
[yY][eE][sS]|[yY]|'')
|
|
echo
|
|
;;
|
|
*)
|
|
abort_and_exit
|
|
;;
|
|
esac
|
|
}
|
|
|
|
create_server_cert() {
|
|
if check_cert_exists "$server_addr"; then
|
|
bigecho "Server certificate '$server_addr' already exists, skipping..."
|
|
else
|
|
bigecho "Generating server certificate..."
|
|
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 -g 3072 -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 -g 3072 -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
|
|
fi
|
|
}
|
|
|
|
update_ikev2_conf() {
|
|
bigecho "Updating IKEv2 configuration..."
|
|
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
|
|
sed -i -e "/^[[:space:]]\+leftcert=/d" \
|
|
-e "/^[[:space:]]\+leftid=/d" /etc/ipsec.d/ikev2.conf
|
|
if [ "$use_dns_name" = "1" ]; then
|
|
sed -i "/conn ikev2-cp/a \ leftid=@$server_addr" /etc/ipsec.d/ikev2.conf
|
|
else
|
|
sed -i "/conn ikev2-cp/a \ leftid=$server_addr" /etc/ipsec.d/ikev2.conf
|
|
fi
|
|
sed -i "/conn ikev2-cp/a \ leftcert=$server_addr" /etc/ipsec.d/ikev2.conf
|
|
}
|
|
|
|
restart_ipsec_service() {
|
|
bigecho "Restarting IPsec service..."
|
|
mkdir -p /run/pluto
|
|
service ipsec restart 2>/dev/null
|
|
}
|
|
|
|
print_client_info() {
|
|
cat <<EOF
|
|
|
|
Successfully changed IKEv2 server address!
|
|
|
|
EOF
|
|
}
|
|
|
|
ikev2changeaddr() {
|
|
check_root
|
|
check_os
|
|
check_libreswan
|
|
check_ikev2
|
|
check_utils_exist
|
|
check_ca_cert_exists
|
|
get_server_address
|
|
|
|
show_welcome
|
|
enter_server_address
|
|
check_server_address
|
|
confirm_changes
|
|
|
|
create_server_cert
|
|
update_ikev2_conf
|
|
if [ "$os_type" = "alpine" ]; then
|
|
ipsec auto --replace ikev2-cp >/dev/null
|
|
else
|
|
restart_ipsec_service
|
|
fi
|
|
print_client_info
|
|
}
|
|
|
|
## Defer until we have the complete script
|
|
ikev2changeaddr "$@"
|
|
|
|
exit 0
|