|
|
#!/bin/bash |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_cidr() { |
|
|
CIDR_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])(/(3[0-2]|[1-2][0-9]|[0-9]))$' |
|
|
printf '%s' "$1" | tr -d '\n' | grep -Eq "$CIDR_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 |
|
|
|
|
|
|
|
|
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_SPLIT_IKEV2" ]; then |
|
|
VPN_SPLIT_IKEV2=$(nospaces "$VPN_SPLIT_IKEV2") |
|
|
VPN_SPLIT_IKEV2=$(noquotes "$VPN_SPLIT_IKEV2") |
|
|
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_SPLIT_IKEV2" ]; then |
|
|
if ! check_cidr "$VPN_SPLIT_IKEV2"; then |
|
|
cat <<'EOF' |
|
|
|
|
|
Warning: Invalid split VPN subnet. Check VPN_SPLIT_IKEV2 in your 'env' file. |
|
|
EOF |
|
|
VPN_SPLIT_IKEV2="" |
|
|
fi |
|
|
fi |
|
|
|
|
|
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'." |
|
|
|
|
|
if [ -n "$VPN_DNS_NAME" ]; then |
|
|
server_addr="$VPN_DNS_NAME" |
|
|
else |
|
|
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 |
|
|
ikev1-policy=accept |
|
|
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=$public_ip |
|
|
right=%any |
|
|
encapsulation=yes |
|
|
authby=secret |
|
|
pfs=no |
|
|
rekey=no |
|
|
dpddelay=30 |
|
|
dpdtimeout=300 |
|
|
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' |
|
|
modprobe -q ip_tables 2>/dev/null |
|
|
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,4500 -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 |
|
|
if ! $ipp -s "$XAUTH_NET" -o "$NET_IFACE" -m policy --dir out --pol none -j MASQUERADE; then |
|
|
$ipp -s "$XAUTH_NET" -o "$NET_IFACE" ! -d "$XAUTH_NET" -j MASQUERADE |
|
|
fi |
|
|
$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\ |
|
|
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 [ -n "$VPN_SPLIT_IKEV2" ]; then |
|
|
sed -i "s|^ leftsubnet=0\.0\.0\.0/0$| leftsubnet=$VPN_SPLIT_IKEV2|g" "$ikev2_sh" |
|
|
fi |
|
|
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= | head -n 1) |
|
|
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 |
|
|
|