Spaces:
Build error
Build error
# | |
# Docker script to configure and start an IPsec VPN server | |
# | |
# DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC! THIS IS ONLY MEANT TO BE RUN | |
# IN A CONTAINER! | |
# | |
# This file is part of IPsec VPN Docker image, available at: | |
# https://github.com/hwdsl2/docker-ipsec-vpn-server | |
# | |
# Copyright (C) 2016-2023 Lin Song <linsongui@gmail.com> | |
# Based on the work of Thomas Sarlandie (Copyright 2012) | |
# | |
# 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; } | |
nospaces() { printf '%s' "$1" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'; } | |
onespace() { printf '%s' "$1" | tr -s ' '; } | |
noquotes() { printf '%s' "$1" | sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'$/\1/"; } | |
noquotes2() { printf '%s' "$1" | sed -e 's/" "/ /g' -e "s/' '/ /g"; } | |
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_client_name() { | |
! { [ "${#1}" -gt "64" ] || printf '%s' "$1" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\+' \ | |
|| case $1 in -*) true ;; *) false ;; esac; } | |
} | |
if [ ! -f "/.dockerenv" ] && [ ! -f "/run/.containerenv" ] \ | |
&& [ -z "$KUBERNETES_SERVICE_HOST" ] \ | |
&& ! head -n 1 /proc/1/sched 2>/dev/null | grep -q '^run\.sh '; then | |
exiterr "This script ONLY runs in a container (e.g. Docker, Podman)." | |
fi | |
if ip link add dummy0 type dummy 2>&1 | grep -q "not permitted"; then | |
cat 1>&2 <<'EOF' | |
Error: This Docker image should be run in privileged mode. | |
See: https://github.com/hwdsl2/docker-ipsec-vpn-server | |
EOF | |
exit 1 | |
fi | |
ip link delete dummy0 >/dev/null 2>&1 | |
os_type=debian | |
os_arch=$(uname -m | tr -dc 'A-Za-z0-9_-') | |
[ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' "$ID") | |
if [ ! -e /dev/ppp ]; then | |
cat <<'EOF' | |
Warning: /dev/ppp is missing, and IPsec/L2TP mode may not work. | |
Please use IKEv2 or IPsec/XAuth mode to connect. | |
Debian 11/10 users, see https://vpnsetup.net/debian10 | |
EOF | |
fi | |
NET_IFACE=$(route 2>/dev/null | grep -m 1 '^default' | grep -o '[^ ]*$') | |
[ -z "$NET_IFACE" ] && NET_IFACE=$(ip -4 route list 0/0 2>/dev/null | grep -m 1 -Po '(?<=dev )(\S+)') | |
[ -z "$NET_IFACE" ] && NET_IFACE=eth0 | |
mkdir -p /opt/src | |
vpn_env="/opt/src/vpn.env" | |
vpn_env_dir="/opt/src/env/vpn.env" | |
if [ -f "$vpn_env_dir" ]; then | |
vpn_env="$vpn_env_dir" | |
fi | |
vpn_gen_env="/etc/ipsec.d/vpn-gen.env" | |
if [ -z "$VPN_IPSEC_PSK" ] && [ -z "$VPN_USER" ] && [ -z "$VPN_PASSWORD" ]; then | |
if [ -f "$vpn_env" ]; then | |
echo | |
echo 'Retrieving VPN credentials...' | |
. "$vpn_env" | |
elif [ -f "$vpn_gen_env" ]; then | |
echo | |
echo 'Retrieving previously generated VPN credentials...' | |
. "$vpn_gen_env" | |
else | |
echo | |
echo 'VPN credentials not set by user. Generating random PSK and password...' | |
VPN_IPSEC_PSK=$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' </dev/urandom 2>/dev/null | head -c 20) | |
VPN_USER=vpnuser | |
VPN_PASSWORD=$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' </dev/urandom 2>/dev/null | head -c 16) | |
printf '%s\n' "VPN_IPSEC_PSK='$VPN_IPSEC_PSK'" > "$vpn_gen_env" | |
printf '%s\n' "VPN_USER='$VPN_USER'" >> "$vpn_gen_env" | |
printf '%s\n' "VPN_PASSWORD='$VPN_PASSWORD'" >> "$vpn_gen_env" | |
chmod 600 "$vpn_gen_env" | |
fi | |
fi | |
# Remove whitespace and quotes around VPN variables, if any | |
VPN_IPSEC_PSK=$(nospaces "$VPN_IPSEC_PSK") | |
VPN_IPSEC_PSK=$(noquotes "$VPN_IPSEC_PSK") | |
VPN_USER=$(nospaces "$VPN_USER") | |
VPN_USER=$(noquotes "$VPN_USER") | |
VPN_PASSWORD=$(nospaces "$VPN_PASSWORD") | |
VPN_PASSWORD=$(noquotes "$VPN_PASSWORD") | |
if [ -n "$VPN_ADDL_USERS" ] && [ -n "$VPN_ADDL_PASSWORDS" ]; then | |
VPN_ADDL_USERS=$(nospaces "$VPN_ADDL_USERS") | |
VPN_ADDL_USERS=$(noquotes "$VPN_ADDL_USERS") | |
VPN_ADDL_USERS=$(onespace "$VPN_ADDL_USERS") | |
VPN_ADDL_USERS=$(noquotes2 "$VPN_ADDL_USERS") | |
VPN_ADDL_PASSWORDS=$(nospaces "$VPN_ADDL_PASSWORDS") | |
VPN_ADDL_PASSWORDS=$(noquotes "$VPN_ADDL_PASSWORDS") | |
VPN_ADDL_PASSWORDS=$(onespace "$VPN_ADDL_PASSWORDS") | |
VPN_ADDL_PASSWORDS=$(noquotes2 "$VPN_ADDL_PASSWORDS") | |
if [ -n "$VPN_ADDL_IP_ADDRS" ]; then | |
VPN_ADDL_IP_ADDRS=$(nospaces "$VPN_ADDL_IP_ADDRS") | |
VPN_ADDL_IP_ADDRS=$(noquotes "$VPN_ADDL_IP_ADDRS") | |
VPN_ADDL_IP_ADDRS=$(onespace "$VPN_ADDL_IP_ADDRS") | |
VPN_ADDL_IP_ADDRS=$(noquotes2 "$VPN_ADDL_IP_ADDRS") | |
fi | |
else | |
VPN_ADDL_USERS="" | |
VPN_ADDL_PASSWORDS="" | |
VPN_ADDL_IP_ADDRS="" | |
fi | |
if [ -n "$VPN_DNS_SRV1" ]; then | |
VPN_DNS_SRV1=$(nospaces "$VPN_DNS_SRV1") | |
VPN_DNS_SRV1=$(noquotes "$VPN_DNS_SRV1") | |
fi | |
if [ -n "$VPN_DNS_SRV2" ]; then | |
VPN_DNS_SRV2=$(nospaces "$VPN_DNS_SRV2") | |
VPN_DNS_SRV2=$(noquotes "$VPN_DNS_SRV2") | |
fi | |
if [ -n "$VPN_CLIENT_NAME" ]; then | |
VPN_CLIENT_NAME=$(nospaces "$VPN_CLIENT_NAME") | |
VPN_CLIENT_NAME=$(noquotes "$VPN_CLIENT_NAME") | |
fi | |
if [ -n "$VPN_DNS_NAME" ]; then | |
VPN_DNS_NAME=$(nospaces "$VPN_DNS_NAME") | |
VPN_DNS_NAME=$(noquotes "$VPN_DNS_NAME") | |
fi | |
if [ -n "$VPN_PUBLIC_IP" ]; then | |
VPN_PUBLIC_IP=$(nospaces "$VPN_PUBLIC_IP") | |
VPN_PUBLIC_IP=$(noquotes "$VPN_PUBLIC_IP") | |
fi | |
if [ -n "$VPN_ANDROID_MTU_FIX" ]; then | |
VPN_ANDROID_MTU_FIX=$(nospaces "$VPN_ANDROID_MTU_FIX") | |
VPN_ANDROID_MTU_FIX=$(noquotes "$VPN_ANDROID_MTU_FIX") | |
fi | |
if [ -n "$VPN_SHA2_TRUNCBUG" ]; then | |
VPN_SHA2_TRUNCBUG=$(nospaces "$VPN_SHA2_TRUNCBUG") | |
VPN_SHA2_TRUNCBUG=$(noquotes "$VPN_SHA2_TRUNCBUG") | |
fi | |
if [ -n "$VPN_PROTECT_CONFIG" ]; then | |
VPN_PROTECT_CONFIG=$(nospaces "$VPN_PROTECT_CONFIG") | |
VPN_PROTECT_CONFIG=$(noquotes "$VPN_PROTECT_CONFIG") | |
fi | |
if [ -n "$VPN_DISABLE_IPSEC_L2TP" ]; then | |
VPN_DISABLE_IPSEC_L2TP=$(nospaces "$VPN_DISABLE_IPSEC_L2TP") | |
VPN_DISABLE_IPSEC_L2TP=$(noquotes "$VPN_DISABLE_IPSEC_L2TP") | |
fi | |
if [ -n "$VPN_DISABLE_IPSEC_XAUTH" ]; then | |
VPN_DISABLE_IPSEC_XAUTH=$(nospaces "$VPN_DISABLE_IPSEC_XAUTH") | |
VPN_DISABLE_IPSEC_XAUTH=$(noquotes "$VPN_DISABLE_IPSEC_XAUTH") | |
fi | |
if [ -n "$VPN_IKEV2_ONLY" ]; then | |
VPN_IKEV2_ONLY=$(nospaces "$VPN_IKEV2_ONLY") | |
VPN_IKEV2_ONLY=$(noquotes "$VPN_IKEV2_ONLY") | |
fi | |
if [ -n "$VPN_ENABLE_MODP1024" ]; then | |
VPN_ENABLE_MODP1024=$(nospaces "$VPN_ENABLE_MODP1024") | |
VPN_ENABLE_MODP1024=$(noquotes "$VPN_ENABLE_MODP1024") | |
fi | |
if [ -n "$VPN_ENABLE_MODP1536" ]; then | |
VPN_ENABLE_MODP1536=$(nospaces "$VPN_ENABLE_MODP1536") | |
VPN_ENABLE_MODP1536=$(noquotes "$VPN_ENABLE_MODP1536") | |
fi | |
if [ -n "$VPN_L2TP_NET" ]; then | |
VPN_L2TP_NET=$(nospaces "$VPN_L2TP_NET") | |
VPN_L2TP_NET=$(noquotes "$VPN_L2TP_NET") | |
fi | |
if [ -n "$VPN_L2TP_LOCAL" ]; then | |
VPN_L2TP_LOCAL=$(nospaces "$VPN_L2TP_LOCAL") | |
VPN_L2TP_LOCAL=$(noquotes "$VPN_L2TP_LOCAL") | |
fi | |
if [ -n "$VPN_L2TP_POOL" ]; then | |
VPN_L2TP_POOL=$(nospaces "$VPN_L2TP_POOL") | |
VPN_L2TP_POOL=$(noquotes "$VPN_L2TP_POOL") | |
fi | |
if [ -n "$VPN_XAUTH_NET" ]; then | |
VPN_XAUTH_NET=$(nospaces "$VPN_XAUTH_NET") | |
VPN_XAUTH_NET=$(noquotes "$VPN_XAUTH_NET") | |
fi | |
if [ -n "$VPN_XAUTH_POOL" ]; then | |
VPN_XAUTH_POOL=$(nospaces "$VPN_XAUTH_POOL") | |
VPN_XAUTH_POOL=$(noquotes "$VPN_XAUTH_POOL") | |
fi | |
if [ -z "$VPN_IPSEC_PSK" ] || [ -z "$VPN_USER" ] || [ -z "$VPN_PASSWORD" ]; then | |
exiterr "All VPN credentials must be specified. Edit your 'env' file and re-enter them." | |
fi | |
if printf '%s' "$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD $VPN_ADDL_USERS $VPN_ADDL_PASSWORDS" | LC_ALL=C grep -q '[^ -~]\+'; then | |
exiterr "VPN credentials must not contain non-ASCII characters." | |
fi | |
case "$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD $VPN_ADDL_USERS $VPN_ADDL_PASSWORDS" in | |
*[\\\"\']*) | |
exiterr "VPN credentials must not contain these special characters: \\ \" '" | |
;; | |
esac | |
if printf '%s' "$VPN_USER $VPN_ADDL_USERS" | tr ' ' '\n' | sort | uniq -c | grep -qv '^ *1 '; then | |
exiterr "VPN usernames must not contain duplicates." | |
fi | |
# Check DNS servers and try to resolve hostnames to IPs | |
if [ -n "$VPN_DNS_SRV1" ]; then | |
check_ip "$VPN_DNS_SRV1" || VPN_DNS_SRV1=$(dig -t A -4 +short "$VPN_DNS_SRV1") | |
if ! check_ip "$VPN_DNS_SRV1"; then | |
cat <<'EOF' | |
Warning: Invalid DNS server. Check VPN_DNS_SRV1 in your 'env' file. | |
EOF | |
VPN_DNS_SRV1="" | |
fi | |
fi | |
if [ -n "$VPN_DNS_SRV2" ]; then | |
check_ip "$VPN_DNS_SRV2" || VPN_DNS_SRV2=$(dig -t A -4 +short "$VPN_DNS_SRV2") | |
if ! check_ip "$VPN_DNS_SRV2"; then | |
cat <<'EOF' | |
Warning: Invalid DNS server. Check VPN_DNS_SRV2 in your 'env' file. | |
EOF | |
VPN_DNS_SRV2="" | |
fi | |
fi | |
if [ -n "$VPN_CLIENT_NAME" ]; then | |
if ! check_client_name "$VPN_CLIENT_NAME"; then | |
cat <<'EOF' | |
Warning: Invalid client name. Use one word only, no special characters except '-' and '_'. | |
Falling back to default client name 'vpnclient'. | |
EOF | |
VPN_CLIENT_NAME="" | |
fi | |
fi | |
if [ -n "$VPN_DNS_NAME" ]; then | |
if ! check_dns_name "$VPN_DNS_NAME"; then | |
cat <<'EOF' | |
Warning: Invalid DNS name. 'VPN_DNS_NAME' must be a fully qualified domain name (FQDN). | |
Falling back to using this server's IP address. | |
EOF | |
VPN_DNS_NAME="" | |
fi | |
fi | |
if [ -n "$VPN_DNS_NAME" ]; then | |
server_addr="$VPN_DNS_NAME" | |
else | |
echo | |
echo 'Trying to auto discover IP of this server...' | |
# In case auto IP discovery fails, manually define the public IP | |
# of this server in your 'env' file, as variable 'VPN_PUBLIC_IP'. | |
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 2 -T 10 -qO- http://ipv4.icanhazip.com) | |
check_ip "$public_ip" || public_ip=$(wget -t 2 -T 10 -qO- http://ip1.dynupdate.no-ip.com) | |
check_ip "$public_ip" || exiterr "Cannot detect this server's public IP. Define it in your 'env' file as 'VPN_PUBLIC_IP'." | |
server_addr="$public_ip" | |
fi | |
L2TP_NET=${VPN_L2TP_NET:-'192.168.42.0/24'} | |
L2TP_LOCAL=${VPN_L2TP_LOCAL:-'192.168.42.1'} | |
L2TP_POOL=${VPN_L2TP_POOL:-'192.168.42.10-192.168.42.250'} | |
XAUTH_NET=${VPN_XAUTH_NET:-'192.168.43.0/24'} | |
XAUTH_POOL=${VPN_XAUTH_POOL:-'192.168.43.10-192.168.43.250'} | |
DNS_SRV1=${VPN_DNS_SRV1:-'8.8.8.8'} | |
DNS_SRV2=${VPN_DNS_SRV2:-'8.8.4.4'} | |
DNS_SRVS="\"$DNS_SRV1 $DNS_SRV2\"" | |
[ -n "$VPN_DNS_SRV1" ] && [ -z "$VPN_DNS_SRV2" ] && DNS_SRVS="$DNS_SRV1" | |
if [ -n "$VPN_DNS_SRV1" ] && [ -n "$VPN_DNS_SRV2" ]; then | |
echo | |
echo "Setting DNS servers to $VPN_DNS_SRV1 and $VPN_DNS_SRV2..." | |
elif [ -n "$VPN_DNS_SRV1" ]; then | |
echo | |
echo "Setting DNS server to $VPN_DNS_SRV1..." | |
fi | |
sha2_truncbug=no | |
case $VPN_SHA2_TRUNCBUG in | |
[yY][eE][sS]) | |
echo | |
echo "Setting sha2-truncbug to yes in ipsec.conf..." | |
sha2_truncbug=yes | |
;; | |
esac | |
disable_ipsec_l2tp=no | |
case $VPN_DISABLE_IPSEC_L2TP in | |
[yY][eE][sS]) | |
disable_ipsec_l2tp=yes | |
;; | |
esac | |
disable_ipsec_xauth=no | |
case $VPN_DISABLE_IPSEC_XAUTH in | |
[yY][eE][sS]) | |
disable_ipsec_xauth=yes | |
;; | |
esac | |
case $VPN_IKEV2_ONLY in | |
[yY][eE][sS]) | |
disable_ipsec_l2tp=yes | |
disable_ipsec_xauth=yes | |
;; | |
esac | |
ike_algs="aes256-sha2;modp2048,aes128-sha2;modp2048,aes256-sha1;modp2048,aes128-sha1;modp2048" | |
ike_algs_addl_1=",aes256-sha2;modp1024,aes128-sha1;modp1024" | |
ike_algs_addl_2=",aes256-sha2;modp1536,aes128-sha1;modp1536" | |
case $VPN_ENABLE_MODP1024 in | |
[yY][eE][sS]) | |
echo | |
echo "Enabling modp1024 in ipsec.conf..." | |
ike_algs="$ike_algs$ike_algs_addl_1" | |
;; | |
esac | |
case $VPN_ENABLE_MODP1536 in | |
[yY][eE][sS]) | |
echo | |
echo "Enabling modp1536 in ipsec.conf..." | |
ike_algs="$ike_algs$ike_algs_addl_2" | |
;; | |
esac | |
if [ "$disable_ipsec_l2tp" = yes ] && [ "$disable_ipsec_xauth" = yes ]; then | |
cat <<'EOF' | |
Note: Running in IKEv2-only mode via env file option. | |
IPsec/L2TP and IPsec/XAuth ("Cisco IPsec") modes are disabled. | |
EOF | |
if ! grep -q " /etc/ipsec.d " /proc/mounts; then | |
cat <<'EOF' | |
Warning: /etc/ipsec.d not mounted. IKEv2 setup requires a Docker volume | |
mounted at /etc/ipsec.d. | |
EOF | |
fi | |
elif [ "$disable_ipsec_l2tp" = yes ]; then | |
cat <<'EOF' | |
Note: IPsec/L2TP mode is disabled via env file option. | |
EOF | |
elif [ "$disable_ipsec_xauth" = yes ]; then | |
cat <<'EOF' | |
Note: IPsec/XAuth ("Cisco IPsec") mode is disabled via env file option. | |
EOF | |
fi | |
# Create IPsec config | |
cat > /etc/ipsec.conf <<EOF | |
version 2.0 | |
config setup | |
virtual-private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!$L2TP_NET,%v4:!$XAUTH_NET | |
uniqueids=no | |
conn shared | |
left=%defaultroute | |
leftid=$server_addr | |
right=%any | |
encapsulation=yes | |
authby=secret | |
pfs=no | |
rekey=no | |
keyingtries=5 | |
dpddelay=30 | |
dpdtimeout=300 | |
dpdaction=clear | |
ikev2=never | |
ike=$ike_algs | |
phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes256-sha2_512,aes128-sha2,aes256-sha2 | |
ikelifetime=24h | |
salifetime=24h | |
sha2-truncbug=$sha2_truncbug | |
EOF | |
if [ "$disable_ipsec_l2tp" != yes ]; then | |
cat >> /etc/ipsec.conf <<'EOF' | |
conn l2tp-psk | |
auto=add | |
leftprotoport=17/1701 | |
rightprotoport=17/%any | |
type=transport | |
also=shared | |
EOF | |
fi | |
if [ "$disable_ipsec_xauth" != yes ]; then | |
cat >> /etc/ipsec.conf <<EOF | |
conn xauth-psk | |
auto=add | |
leftsubnet=0.0.0.0/0 | |
rightaddresspool=$XAUTH_POOL | |
modecfgdns=$DNS_SRVS | |
leftxauthserver=yes | |
rightxauthclient=yes | |
leftmodecfgserver=yes | |
rightmodecfgclient=yes | |
modecfgpull=yes | |
cisco-unity=yes | |
also=shared | |
EOF | |
fi | |
cat >> /etc/ipsec.conf <<'EOF' | |
include /etc/ipsec.d/*.conf | |
EOF | |
if uname -r | grep -qi 'coreos'; then | |
sed -i '/phase2alg/s/,aes256-sha2_512//' /etc/ipsec.conf | |
fi | |
if grep -qs ike-frag /etc/ipsec.d/ikev2.conf; then | |
sed -i 's/^[[:space:]]\+ike-frag=/ fragmentation=/' /etc/ipsec.d/ikev2.conf | |
fi | |
# Specify IPsec PSK | |
cat > /etc/ipsec.secrets <<EOF | |
%any %any : PSK "$VPN_IPSEC_PSK" | |
EOF | |
# Create xl2tpd config | |
cat > /etc/xl2tpd/xl2tpd.conf <<EOF | |
[global] | |
port = 1701 | |
[lns default] | |
ip range = $L2TP_POOL | |
local ip = $L2TP_LOCAL | |
require chap = yes | |
refuse pap = yes | |
require authentication = yes | |
name = l2tpd | |
pppoptfile = /etc/ppp/options.xl2tpd | |
length bit = yes | |
EOF | |
# Set xl2tpd options | |
cat > /etc/ppp/options.xl2tpd <<EOF | |
+mschap-v2 | |
ipcp-accept-local | |
ipcp-accept-remote | |
noccp | |
auth | |
mtu 1280 | |
mru 1280 | |
proxyarp | |
lcp-echo-failure 4 | |
lcp-echo-interval 30 | |
connect-delay 5000 | |
ms-dns $DNS_SRV1 | |
EOF | |
if [ -z "$VPN_DNS_SRV1" ] || [ -n "$VPN_DNS_SRV2" ]; then | |
cat >> /etc/ppp/options.xl2tpd <<EOF | |
ms-dns $DNS_SRV2 | |
EOF | |
fi | |
# Create VPN credentials | |
cat > /etc/ppp/chap-secrets <<EOF | |
"$VPN_USER" l2tpd "$VPN_PASSWORD" * | |
EOF | |
VPN_PASSWORD_ENC=$(openssl passwd -1 "$VPN_PASSWORD") | |
cat > /etc/ipsec.d/passwd <<EOF | |
$VPN_USER:$VPN_PASSWORD_ENC:xauth-psk | |
EOF | |
if [ -n "$VPN_ADDL_USERS" ] && [ -n "$VPN_ADDL_PASSWORDS" ]; then | |
count=1 | |
addl_user=$(printf '%s' "$VPN_ADDL_USERS" | cut -d ' ' -f 1) | |
addl_password=$(printf '%s' "$VPN_ADDL_PASSWORDS" | cut -d ' ' -f 1) | |
addl_ip=$(printf '%s' "$VPN_ADDL_IP_ADDRS" | cut -d ' ' -f 1) | |
while [ -n "$addl_user" ] && [ -n "$addl_password" ]; do | |
addl_ip_l2tp="$addl_ip" | |
addl_ip_xauth="$addl_ip" | |
if [ "$addl_ip" = "*" ] || ! check_ip "$addl_ip"; then | |
addl_ip_l2tp="" | |
addl_ip_xauth="" | |
elif [ "$L2TP_NET" = "192.168.42.0/24" ] && [ "$XAUTH_NET" = "192.168.43.0/24" ]; then | |
addl_ip_part=$(printf '%s' "$addl_ip" | cut -f 1-3 -d '.') | |
if [ "$addl_ip_part" = "192.168.42" ]; then | |
addl_ip_xauth="" | |
elif [ "$addl_ip_part" = "192.168.43" ]; then | |
addl_ip_l2tp="" | |
else | |
addl_ip_l2tp="" | |
addl_ip_xauth="" | |
fi | |
fi | |
cat >> /etc/ppp/chap-secrets <<EOF | |
"$addl_user" l2tpd "$addl_password" ${addl_ip_l2tp:-*} | |
EOF | |
[ -n "$addl_ip_xauth" ] && addl_ip_xauth=$(printf '%s' ":$addl_ip_xauth") | |
addl_password_enc=$(openssl passwd -1 "$addl_password") | |
cat >> /etc/ipsec.d/passwd <<EOF | |
$addl_user:$addl_password_enc:xauth-psk${addl_ip_xauth} | |
EOF | |
count=$((count+1)) | |
addl_user=$(printf '%s' "$VPN_ADDL_USERS" | cut -s -d ' ' -f "$count") | |
addl_password=$(printf '%s' "$VPN_ADDL_PASSWORDS" | cut -s -d ' ' -f "$count") | |
addl_ip=$(printf '%s' "$VPN_ADDL_IP_ADDRS" | cut -s -d ' ' -f "$count") | |
done | |
fi | |
# Update sysctl settings | |
syt='/sbin/sysctl -e -q -w' | |
$syt kernel.msgmnb=65536 2>/dev/null | |
$syt kernel.msgmax=65536 2>/dev/null | |
$syt net.ipv4.ip_forward=1 2>/dev/null | |
$syt net.ipv4.conf.all.accept_redirects=0 2>/dev/null | |
$syt net.ipv4.conf.all.send_redirects=0 2>/dev/null | |
$syt net.ipv4.conf.all.rp_filter=0 2>/dev/null | |
$syt net.ipv4.conf.default.accept_redirects=0 2>/dev/null | |
$syt net.ipv4.conf.default.send_redirects=0 2>/dev/null | |
$syt net.ipv4.conf.default.rp_filter=0 2>/dev/null | |
$syt "net.ipv4.conf.$NET_IFACE.send_redirects=0" 2>/dev/null | |
$syt "net.ipv4.conf.$NET_IFACE.rp_filter=0" 2>/dev/null | |
$syt net.ipv4.tcp_rmem="4096 87380 16777216" 2>/dev/null | |
$syt net.ipv4.tcp_wmem="4096 87380 16777216" 2>/dev/null | |
if modprobe -q tcp_bbr 2>/dev/null \ | |
&& printf '%s\n%s' "4.20" "$(uname -r)" | sort -C -V; then | |
$syt net.ipv4.tcp_congestion_control=bbr 2>/dev/null | |
fi | |
# Create IPTables rules | |
ipi='iptables -I INPUT' | |
ipf='iptables -I FORWARD' | |
ipp='iptables -t nat -I POSTROUTING' | |
res='RELATED,ESTABLISHED' | |
if ! iptables -t nat -C POSTROUTING -s "$L2TP_NET" -o "$NET_IFACE" -j MASQUERADE 2>/dev/null; then | |
$ipi 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP | |
$ipi 2 -m conntrack --ctstate INVALID -j DROP | |
$ipi 3 -m conntrack --ctstate "$res" -j ACCEPT | |
$ipi 4 -p udp -m multiport --dports 500,7860 -j ACCEPT | |
$ipi 5 -p udp --dport 1701 -m policy --dir in --pol ipsec -j ACCEPT | |
$ipi 6 -p udp --dport 1701 -j DROP | |
$ipf 1 -m conntrack --ctstate INVALID -j DROP | |
$ipf 2 -i "$NET_IFACE" -o ppp+ -m conntrack --ctstate "$res" -j ACCEPT | |
$ipf 3 -i ppp+ -o "$NET_IFACE" -j ACCEPT | |
$ipf 4 -i ppp+ -o ppp+ -j ACCEPT | |
$ipf 5 -i "$NET_IFACE" -d "$XAUTH_NET" -m conntrack --ctstate "$res" -j ACCEPT | |
$ipf 6 -s "$XAUTH_NET" -o "$NET_IFACE" -j ACCEPT | |
$ipf 7 -s "$XAUTH_NET" -o ppp+ -j ACCEPT | |
# Client-to-client traffic is allowed by default. To *disallow* such traffic, | |
# uncomment below and restart the Docker container. | |
# $ipf 2 -i ppp+ -o ppp+ -s "$L2TP_NET" -d "$L2TP_NET" -j DROP | |
# $ipf 3 -s "$XAUTH_NET" -d "$XAUTH_NET" -j DROP | |
# $ipf 4 -i ppp+ -d "$XAUTH_NET" -j DROP | |
# $ipf 5 -s "$XAUTH_NET" -o ppp+ -j DROP | |
iptables -A FORWARD -j DROP | |
$ipp -s "$XAUTH_NET" -o "$NET_IFACE" -m policy --dir out --pol none -j MASQUERADE | |
$ipp -s "$L2TP_NET" -o "$NET_IFACE" -j MASQUERADE | |
fi | |
case $VPN_ANDROID_MTU_FIX in | |
[yY][eE][sS]) | |
echo | |
echo "Applying fix for Android MTU/MSS issues..." | |
iptables -t mangle -A FORWARD -m policy --pol ipsec --dir in \ | |
-p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 \ | |
-j TCPMSS --set-mss 1360 | |
iptables -t mangle -A FORWARD -m policy --pol ipsec --dir out \ | |
-p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 \ | |
-j TCPMSS --set-mss 1360 | |
echo 1 > /proc/sys/net/ipv4/ip_no_pmtu_disc | |
;; | |
esac | |
# Update file attributes | |
chmod 600 /etc/ipsec.secrets /etc/ppp/chap-secrets /etc/ipsec.d/passwd | |
echo | |
echo "Starting IPsec service..." | |
mkdir -p /run/pluto /var/run/pluto | |
rm -f /run/pluto/pluto.pid /var/run/pluto/pluto.pid | |
if [ "$os_type" = "alpine" ]; then | |
sed -i '1c\#!/sbin/openrc-run' /etc/init.d/ipsec | |
rc-status >/dev/null 2>&1 | |
rc-service ipsec zap >/dev/null | |
rc-service -D ipsec start >/dev/null 2>&1 | |
mkdir -p /etc/crontabs | |
cron_cmd="rc-service -c -D ipsec zap start" | |
if ! grep -qs "$cron_cmd" /etc/crontabs/root; then | |
cat >> /etc/crontabs/root <<EOF | |
* * * * * $cron_cmd | |
* * * * * sleep 15; $cron_cmd | |
* * * * * sleep 30; $cron_cmd | |
* * * * * sleep 45; $cron_cmd | |
EOF | |
fi | |
/usr/sbin/crond -L /dev/null | |
else | |
service ipsec start >/dev/null 2>&1 | |
fi | |
if [ -n "$VPN_DNS_NAME" ]; then | |
server_text="Server" | |
else | |
server_text="Server IP" | |
fi | |
if [ "$disable_ipsec_l2tp" != yes ] || [ "$disable_ipsec_xauth" != yes ]; then | |
cat <<EOF | |
================================================ | |
IPsec VPN server is now ready for use! | |
Connect to your new VPN with these details: | |
$server_text: $server_addr | |
IPsec PSK: $VPN_IPSEC_PSK | |
Username: $VPN_USER | |
Password: $VPN_PASSWORD | |
EOF | |
if [ -n "$VPN_ADDL_USERS" ] && [ -n "$VPN_ADDL_PASSWORDS" ]; then | |
count=1 | |
addl_user=$(printf '%s' "$VPN_ADDL_USERS" | cut -d ' ' -f 1) | |
addl_password=$(printf '%s' "$VPN_ADDL_PASSWORDS" | cut -d ' ' -f 1) | |
cat <<'EOF' | |
Additional VPN users (username | password): | |
EOF | |
while [ -n "$addl_user" ] && [ -n "$addl_password" ]; do | |
cat <<EOF | |
$addl_user | $addl_password | |
EOF | |
count=$((count+1)) | |
addl_user=$(printf '%s' "$VPN_ADDL_USERS" | cut -s -d ' ' -f "$count") | |
addl_password=$(printf '%s' "$VPN_ADDL_PASSWORDS" | cut -s -d ' ' -f "$count") | |
done | |
fi | |
cat <<'EOF' | |
Write these down. You'll need them to connect! | |
VPN client setup: https://vpnsetup.net/clients2 | |
================================================ | |
EOF | |
fi | |
# Set up IKEv2 | |
status=0 | |
ikev2_sh="/opt/src/ikev2.sh" | |
ikev2_conf="/etc/ipsec.d/ikev2.conf" | |
ikev2_log="/etc/ipsec.d/ikev2setup.log" | |
if grep -q " /etc/ipsec.d " /proc/mounts && [ -s "$ikev2_sh" ] && [ ! -f "$ikev2_conf" ]; then | |
echo | |
echo "Setting up IKEv2. This may take a few moments..." | |
if VPN_DNS_NAME="$VPN_DNS_NAME" VPN_PUBLIC_IP="$public_ip" \ | |
VPN_CLIENT_NAME="$VPN_CLIENT_NAME" VPN_XAUTH_POOL="$VPN_XAUTH_POOL" \ | |
VPN_DNS_SRV1="$VPN_DNS_SRV1" VPN_DNS_SRV2="$VPN_DNS_SRV2" \ | |
VPN_PROTECT_CONFIG="$VPN_PROTECT_CONFIG" \ | |
/bin/bash "$ikev2_sh" --auto >"$ikev2_log" 2>&1; then | |
status=1 | |
status_text="IKEv2 setup successful." | |
else | |
status=4 | |
rm -f "$ikev2_conf" | |
echo "IKEv2 setup failed." | |
fi | |
chmod 600 "$ikev2_log" | |
fi | |
if [ "$status" = 0 ] && [ -f "$ikev2_conf" ] && [ -s "$ikev2_log" ]; then | |
status=2 | |
status_text="IKEv2 is already set up." | |
fi | |
if [ "$status" = 1 ] || [ "$status" = 2 ]; then | |
cat <<EOF | |
================================================ | |
$status_text Details for IKEv2 mode: | |
EOF | |
sed -n '/VPN server address:/,/Next steps:/p' "$ikev2_log" | |
cat <<'EOF' | |
https://vpnsetup.net/clients2 | |
================================================ | |
EOF | |
else | |
echo | |
fi | |
if [ "$status" = 2 ] && [ -n "$VPN_DNS_NAME" ]; then | |
server_addr_cur=$(grep -s "leftcert=" /etc/ipsec.d/ikev2.conf | cut -f2 -d=) | |
if [ "$VPN_DNS_NAME" != "$server_addr_cur" ]; then | |
cat <<'EOF' | |
Warning: The VPN_DNS_NAME variable you specified has no effect | |
for IKEv2 mode, because IKEv2 is already set up in this | |
container. To change the IKEv2 server address, see: | |
https://vpnsetup.net/ikev2docker | |
EOF | |
fi | |
fi | |
# Check for new Libreswan version | |
ts_file="/opt/src/swanver" | |
if [ ! -f "$ts_file" ] || [ "$(find "$ts_file" -mmin +10080)" ]; then | |
touch "$ts_file" | |
ipsec_ver=$(ipsec --version 2>/dev/null) | |
swan_ver=$(printf '%s' "$ipsec_ver" | sed -e 's/.*Libreswan U\?//' -e 's/\( (\|\/K\).*//') | |
base_url="https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0" | |
swan_ver_url="$base_url/upg-docker-$os_type-$os_arch-swanver" | |
swan_ver_latest=$(wget -t 2 -T 10 -qO- "$swan_ver_url" | head -n 1) | |
if printf '%s' "$swan_ver_latest" | grep -Eq '^([3-9]|[1-9][0-9]{1,2})(\.([0-9]|[1-9][0-9]{1,2})){1,2}$' \ | |
&& [ -n "$swan_ver" ] && [ "$swan_ver" != "$swan_ver_latest" ] \ | |
&& printf '%s\n%s' "$swan_ver" "$swan_ver_latest" | sort -C -V; then | |
cat <<EOF | |
Note: A newer version of Libreswan ($swan_ver_latest) is available. | |
To update this Docker image, see: https://vpnsetup.net/dockerupdate | |
EOF | |
fi | |
fi | |
# Start xl2tpd | |
mkdir -p /var/run/xl2tpd | |
rm -f /var/run/xl2tpd.pid | |
exec /usr/sbin/xl2tpd -D -c /etc/xl2tpd/xl2tpd.conf | |