From caf9293b8a4316a404aebf243841fd6e29123850 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Sun, 20 Aug 2017 10:52:28 -0500 Subject: [PATCH 01/29] New Libreswan version 3.21 --- extras/vpnupgrade.sh | 7 +++++-- extras/vpnupgrade_centos.sh | 7 +++++-- vpnsetup.sh | 7 +++++-- vpnsetup_centos.sh | 7 +++++-- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index de6cc24..32e4cd4 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -11,7 +11,7 @@ # know how you have improved it! # Check https://libreswan.org for the latest version -swan_ver=3.20 +swan_ver=3.21 ### DO NOT edit below this line ### @@ -145,7 +145,10 @@ fi /bin/rm -rf "/opt/src/libreswan-$swan_ver" tar xzf "$swan_file" && /bin/rm -f "$swan_file" cd "libreswan-$swan_ver" || exiterr "Cannot enter Libreswan source dir." -echo "WERROR_CFLAGS =" > Makefile.inc.local +cat > Makefile.inc.local <<'EOF' +WERROR_CFLAGS = +USE_DNSSEC = false +EOF if [ "$(packaging/utils/lswan_detect.sh init)" = "systemd" ]; then apt-get -yq install libsystemd-dev || exiterr2 fi diff --git a/extras/vpnupgrade_centos.sh b/extras/vpnupgrade_centos.sh index 14f8be9..e44887f 100644 --- a/extras/vpnupgrade_centos.sh +++ b/extras/vpnupgrade_centos.sh @@ -11,7 +11,7 @@ # know how you have improved it! # Check https://libreswan.org for the latest version -swan_ver=3.20 +swan_ver=3.21 ### DO NOT edit below this line ### @@ -139,7 +139,10 @@ fi /bin/rm -rf "/opt/src/libreswan-$swan_ver" tar xzf "$swan_file" && /bin/rm -f "$swan_file" cd "libreswan-$swan_ver" || exiterr "Cannot enter Libreswan source dir." -echo "WERROR_CFLAGS =" > Makefile.inc.local +cat > Makefile.inc.local <<'EOF' +WERROR_CFLAGS = +USE_DNSSEC = false +EOF make -s programs && make -s install # Verify the install and clean up diff --git a/vpnsetup.sh b/vpnsetup.sh index 33bee0a..bd84466 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -185,7 +185,7 @@ apt-get -yq install fail2ban || exiterr2 bigecho "Compiling and installing Libreswan..." -swan_ver=3.20 +swan_ver=3.21 swan_file="libreswan-$swan_ver.tar.gz" swan_url1="https://github.com/libreswan/libreswan/archive/v$swan_ver.tar.gz" swan_url2="https://download.libreswan.org/$swan_file" @@ -195,7 +195,10 @@ fi /bin/rm -rf "/opt/src/libreswan-$swan_ver" tar xzf "$swan_file" && /bin/rm -f "$swan_file" cd "libreswan-$swan_ver" || exiterr "Cannot enter Libreswan source dir." -echo "WERROR_CFLAGS =" > Makefile.inc.local +cat > Makefile.inc.local <<'EOF' +WERROR_CFLAGS = +USE_DNSSEC = false +EOF if [ "$(packaging/utils/lswan_detect.sh init)" = "systemd" ]; then apt-get -yq install libsystemd-dev || exiterr2 fi diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index c4351e6..66ac0ec 100755 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -174,7 +174,7 @@ yum -y install fail2ban || exiterr2 bigecho "Compiling and installing Libreswan..." -swan_ver=3.20 +swan_ver=3.21 swan_file="libreswan-$swan_ver.tar.gz" swan_url1="https://github.com/libreswan/libreswan/archive/v$swan_ver.tar.gz" swan_url2="https://download.libreswan.org/$swan_file" @@ -184,7 +184,10 @@ fi /bin/rm -rf "/opt/src/libreswan-$swan_ver" tar xzf "$swan_file" && /bin/rm -f "$swan_file" cd "libreswan-$swan_ver" || exiterr "Cannot enter Libreswan source dir." -echo "WERROR_CFLAGS =" > Makefile.inc.local +cat > Makefile.inc.local <<'EOF' +WERROR_CFLAGS = +USE_DNSSEC = false +EOF make -s programs && make -s install # Verify the install and clean up From 3f2b2cbc0bcf17cde7ec72eb148b8a1c68f82cf0 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Sun, 20 Aug 2017 11:50:46 -0500 Subject: [PATCH 02/29] Remove Debian 7 - Remove support for Debian 7 (Wheezy) - Libreswan 3.21 no longer compiles on Debian 7 or Ubuntu 12.04 - Fix tests by switching to Ubuntu 14.04 --- .travis.yml | 1 + README-zh.md | 5 +- README.md | 5 +- extras/vpnsetup-debian-7-workaround.sh | 73 -------------------------- extras/vpnupgrade.sh | 13 ++--- vpnsetup.sh | 16 ++---- 6 files changed, 11 insertions(+), 102 deletions(-) delete mode 100644 extras/vpnsetup-debian-7-workaround.sh diff --git a/.travis.yml b/.travis.yml index e03cca1..3eb710a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: bash sudo: required +dist: trusty addons: apt: diff --git a/README-zh.md b/README-zh.md index ca71398..ab4e44f 100644 --- a/README-zh.md +++ b/README-zh.md @@ -66,7 +66,7 @@ wget https://git.io/vpnsetup -O vpnsetup.sh && sudo sh vpnsetup.sh **-或者-** -一个专用服务器或者虚拟专用服务器 (VPS),全新安装以上操作系统之一。另外也可使用 Debian 7 (Wheezy),但是必须首先运行另一个脚本。 OpenVZ VPS 不受支持,用户可以尝试使用 Shadowsocks 或者 OpenVPN。 +一个专用服务器,或者基于 KVM/Xen 的虚拟专用服务器 (VPS),全新安装以上操作系统之一。OpenVZ VPS 不受支持,用户可以尝试使用比如 Shadowsocks 或者 OpenVPN。 这也包括各种公共云服务中的 Linux 虚拟机,比如 DigitalOcean, Vultr, Linode, Google Compute Engine, Amazon Lightsail, Microsoft Azure, IBM SoftLayer, OVHRackspace。 @@ -180,10 +180,7 @@ wget https://git.io/vpnupgrade-centos -O vpnupgrade.sh - IKEv2 VPN Server on Docker - Streisand - Algo VPN -- SoftEther VPN -- Shadowsocks - OpenVPN Install -- Setup strongSwan ## 授权协议 diff --git a/README.md b/README.md index 3b2b78c..b3f4319 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Please see this workaround. OpenVZ VPS is NOT supported, users could instead try OpenVPN. +A dedicated server or KVM/Xen-based virtual private server (VPS), freshly installed with one of the above OS. OpenVZ VPS is not supported, users could instead try OpenVPN or Shadowsocks. This also includes Linux VMs in public clouds, such as DigitalOcean, Vultr, Linode, Google Compute Engine, Amazon Lightsail, Microsoft Azure, IBM SoftLayer, OVH and Rackspace. @@ -180,10 +180,7 @@ Please refer to Uninstall the VPNIKEv2 VPN Server on Docker - Streisand - Algo VPN -- SoftEther VPN -- Shadowsocks - OpenVPN Install -- Setup strongSwan ## License diff --git a/extras/vpnsetup-debian-7-workaround.sh b/extras/vpnsetup-debian-7-workaround.sh deleted file mode 100644 index c767c25..0000000 --- a/extras/vpnsetup-debian-7-workaround.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/sh -# -# Debian 7 (Wheezy) does NOT have the required libnss version (>= 3.16) for Libreswan. -# This script provides a workaround by installing newer packages from libreswan.org. -# Debian 7 users: Run this script first, before using the VPN setup script. -# -# IMPORTANT: These unofficial packages may not receive security updates compared to -# official Debian packages. They could contain vulnerabilities. Use at your own risk! -# -# Copyright (C) 2015-2017 Lin Song -# -# This program is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# this program. If not, see http://www.gnu.org/licenses/. - -export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - -exiterr() { echo "Error: $1" >&2; exit 1; } - -if [ "$(sed 's/\..*//' /etc/debian_version 2>/dev/null)" != "7" ]; then - exiterr "This script only supports Debian 7 (Wheezy)." -fi - -if [ "$(uname -m)" != "x86_64" ]; then - exiterr "This script only supports 64-bit Debian 7." -fi - -if [ "$(id -u)" != 0 ]; then - exiterr "Script must be run as root. Try 'sudo sh $0'" -fi - -# Create and change to working dir -mkdir -p /opt/src -cd /opt/src || exiterr "Cannot enter /opt/src." - -# Update package index and install wget -export DEBIAN_FRONTEND=noninteractive -apt-get -yq update || exiterr "'apt-get update' failed." -apt-get -yq install wget || exiterr "Failed to install 'wget'." - -# Install libnss/libnspr packages from download.libreswan.org. -# Ref: https://libreswan.org/wiki/3.14_on_Debian_Wheezy -base_url=https://download.libreswan.org/binaries/debian/wheezy - -deb1=libnspr4_4.10.7-1_amd64.deb -deb2=libnspr4-dev_4.10.7-1_amd64.deb -deb3=libnss3_3.17.2-1.1_amd64.deb -deb4=libnss3-dev_3.17.2-1.1_amd64.deb -deb5=libnss3-tools_3.17.2-1.1_amd64.deb - -wget -t 3 -T 30 -nv -O "$deb1" "$base_url/$deb1" -wget -t 3 -T 30 -nv -O "$deb2" "$base_url/$deb2" -wget -t 3 -T 30 -nv -O "$deb3" "$base_url/$deb3" -wget -t 3 -T 30 -nv -O "$deb4" "$base_url/$deb4" -wget -t 3 -T 30 -nv -O "$deb5" "$base_url/$deb5" - -if [ -s "$deb1" ] && [ -s "$deb2" ] && [ -s "$deb3" ] && [ -s "$deb4" ] && [ -s "$deb5" ]; then - dpkg -i "$deb1" "$deb2" "$deb3" "$deb4" "$deb5" && /bin/rm -f "$deb1" "$deb2" "$deb3" "$deb4" "$deb5" - apt-get install -f - echo - echo 'Completed! If no error, you may now proceed to run the VPN setup script.' - exit 0 -else - /bin/rm -f "$deb1" "$deb2" "$deb3" "$deb4" "$deb5" - exiterr 'Could not download libnss/libnspr package(s).' -fi diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index 32e4cd4..bb9aaec 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -29,6 +29,10 @@ if ! printf %s "$os_type" | head -n 1 | grep -qiF -e ubuntu -e debian -e raspbia exiterr "This script only supports Ubuntu/Debian." fi +if [ "$(sed 's/\..*//' /etc/debian_version)" = "7" ]; then + exiterr "This script does not support Debian 7 (Wheezy)." +fi + if [ -f /proc/user_beancounters ]; then exiterr "This script does not support OpenVZ VPS." fi @@ -96,15 +100,6 @@ Your other VPN configuration files will not be modified. EOF -if [ "$(sed 's/\..*//' /etc/debian_version)" = "7" ]; then -cat <<'EOF' -IMPORTANT: Workaround required for Debian 7 (Wheezy). -You must first run the script at: https://git.io/vpndeb7 -Continue only after completing this workaround. - -EOF -fi - printf "Do you wish to continue? [y/N] " read -r response case $response in diff --git a/vpnsetup.sh b/vpnsetup.sh index bd84466..fc4932a 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -55,6 +55,10 @@ if ! printf %s "$os_type" | head -n 1 | grep -qiF -e ubuntu -e debian -e raspbia exiterr "This script only supports Ubuntu/Debian." fi +if [ "$(sed 's/\..*//' /etc/debian_version)" = "7" ]; then + exiterr "This script does not support Debian 7 (Wheezy)." +fi + if [ -f /proc/user_beancounters ]; then echo "Error: This script does not support OpenVZ VPS." >&2 echo "Try OpenVPN: https://github.com/Nyr/openvpn-install" >&2 @@ -125,18 +129,6 @@ case "$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD" in ;; esac -if [ "$(sed 's/\..*//' /etc/debian_version)" = "7" ]; then -cat <<'EOF' -IMPORTANT: Workaround required for Debian 7 (Wheezy). -You must first run the script at: https://git.io/vpndeb7 -If not already done so, press Ctrl-C to interrupt now. - -Continuing in 30 seconds ... - -EOF - sleep 30 -fi - bigecho "VPN setup in progress... Please be patient." # Create and change to working dir From dc71db34515fe870b82bd219cc8bfc63adb27bfc Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Thu, 21 Sep 2017 01:23:03 -0500 Subject: [PATCH 03/29] Fixes for Raspberry Pi - Change "start" to "restart", so that the 15-second delay actually works (wait for network interfaces to initialize) - Workaround for Raspbian 9 (requires left=$PRIVATE_IP in ipsec.conf) --- vpnsetup.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/vpnsetup.sh b/vpnsetup.sh index fc4932a..d4e5fcf 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -425,8 +425,8 @@ cat >> /etc/rc.local <<'EOF' # Added by hwdsl2 VPN script (sleep 15 -service ipsec start -service xl2tpd start +service ipsec restart +service xl2tpd restart echo 1 > /proc/sys/net/ipv4/ip_forward)& exit 0 EOF @@ -449,6 +449,15 @@ service fail2ban restart 2>/dev/null service ipsec restart 2>/dev/null service xl2tpd restart 2>/dev/null +# Workaround for Raspbian 9 +if grep -qs raspbian /etc/os-release; then + if [ "$(sed 's/\..*//' /etc/debian_version)" = "9" ]; then + PRIVATE_IP=$(ip -4 route get 1 | awk '{print $NF;exit}') + check_ip "$PRIVATE_IP" && sed -i "s/left=%defaultroute/left=$PRIVATE_IP/" /etc/ipsec.conf + service ipsec restart + fi +fi + cat < Date: Sat, 23 Sep 2017 14:19:30 -0500 Subject: [PATCH 04/29] Improve RPi fix - Minor improvement to Raspberry Pi fix --- vpnsetup.sh | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/vpnsetup.sh b/vpnsetup.sh index d4e5fcf..2d4b1f4 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -267,6 +267,12 @@ conn xauth-psk also=shared EOF +# Workaround for Raspbian 9 +if grep -qs 'Raspbian GNU/Linux 9' /etc/os-release; then + PRIVATE_IP=$(ip -4 route get 1 | awk '{print $NF;exit}') + check_ip "$PRIVATE_IP" && sed -i "s/left=%defaultroute/left=$PRIVATE_IP/" /etc/ipsec.conf +fi + # Specify IPsec PSK conf_bk "/etc/ipsec.secrets" cat > /etc/ipsec.secrets </dev/null service ipsec restart 2>/dev/null service xl2tpd restart 2>/dev/null -# Workaround for Raspbian 9 -if grep -qs raspbian /etc/os-release; then - if [ "$(sed 's/\..*//' /etc/debian_version)" = "9" ]; then - PRIVATE_IP=$(ip -4 route get 1 | awk '{print $NF;exit}') - check_ip "$PRIVATE_IP" && sed -i "s/left=%defaultroute/left=$PRIVATE_IP/" /etc/ipsec.conf - service ipsec restart - fi -fi - cat < Date: Mon, 25 Sep 2017 00:28:10 -0500 Subject: [PATCH 05/29] Enable MS-CHAP v2 - Allow MS-CHAP v2 for better compatibility with the built-in Windows 10 VPN client. Thanks @remini1998! --- vpnsetup.sh | 1 + vpnsetup_centos.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/vpnsetup.sh b/vpnsetup.sh index 2d4b1f4..aebc7ce 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -299,6 +299,7 @@ EOF # Set xl2tpd options conf_bk "/etc/ppp/options.xl2tpd" cat > /etc/ppp/options.xl2tpd < /etc/ppp/options.xl2tpd < Date: Mon, 25 Sep 2017 18:55:27 -0500 Subject: [PATCH 06/29] Update images - Update VPN properties screenshots for MS-CHAP v2 --- docs/images/vpn-properties-zh.png | Bin 85831 -> 85508 bytes docs/images/vpn-properties.png | Bin 95100 -> 95097 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/images/vpn-properties-zh.png b/docs/images/vpn-properties-zh.png index 7b2948ea51e46efabcec6700a0c123c4437b064a..40d9f4fdbea5a12c960b6782e2b9ce433e0da7b1 100644 GIT binary patch delta 32980 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 delta 33402 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 vE(A8R2boJ~_xW>mO)iu0uEO=@*E6!I{h#i{ diff --git a/docs/images/vpn-properties.png b/docs/images/vpn-properties.png index c7dd884f72ad5dc463f27a149455d7b1ffff6207..e2bc9172cecb4cab4e66b5c0143b4f7b288eca5a 100644 GIT binary patch delta 8400 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 TN#*C`e;xr*cq3mYXA$;)RF-{C delta 8410 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 ao9y=EI+io(hutTSrlO!BUnOf9`u_l!2!FBw From 536ac8f54b3cc8682f56a0ade828429284d5beb6 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Wed, 27 Sep 2017 21:41:24 -0500 Subject: [PATCH 07/29] Update ipsec.conf - Replace obsolete keyword "virtual_private" with "virtual-private" --- vpnsetup.sh | 2 +- vpnsetup_centos.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vpnsetup.sh b/vpnsetup.sh index aebc7ce..773fcc7 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -219,7 +219,7 @@ cat > /etc/ipsec.conf < /etc/ipsec.conf < Date: Thu, 28 Sep 2017 00:15:08 -0500 Subject: [PATCH 08/29] Skip building manpages - Skip building manpages for Libreswan - No longer need/install "xmlto" package - Reduce Libreswan compilation time by ~30% --- extras/vpnupgrade.sh | 3 +-- extras/vpnupgrade_centos.sh | 4 ++-- vpnsetup.sh | 3 +-- vpnsetup_centos.sh | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index bb9aaec..e3b1137 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -128,7 +128,6 @@ apt-get -yq install libnss3-dev libnspr4-dev pkg-config libpam0g-dev \ libcap-ng-dev libcap-ng-utils libselinux1-dev \ libcurl4-nss-dev flex bison gcc make \ libunbound-dev libnss3-tools libevent-dev || exiterr2 -apt-get -yq --no-install-recommends install xmlto || exiterr2 # Compile and install Libreswan swan_file="libreswan-$swan_ver.tar.gz" @@ -147,7 +146,7 @@ EOF if [ "$(packaging/utils/lswan_detect.sh init)" = "systemd" ]; then apt-get -yq install libsystemd-dev || exiterr2 fi -make -s programs && make -s install +make -s base && make -s install-base # Verify the install and clean up cd /opt/src || exiterr "Cannot enter /opt/src." diff --git a/extras/vpnupgrade_centos.sh b/extras/vpnupgrade_centos.sh index e44887f..7030d17 100644 --- a/extras/vpnupgrade_centos.sh +++ b/extras/vpnupgrade_centos.sh @@ -119,7 +119,7 @@ yum -y install epel-release || exiterr2 yum -y install nss-devel nspr-devel pkgconfig pam-devel \ libcap-ng-devel libselinux-devel \ curl-devel flex bison gcc make \ - fipscheck-devel unbound-devel xmlto || exiterr2 + fipscheck-devel unbound-devel || exiterr2 # Install libevent2 and systemd-devel if grep -qs "release 6" /etc/redhat-release; then @@ -143,7 +143,7 @@ cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false EOF -make -s programs && make -s install +make -s base && make -s install-base # Verify the install and clean up cd /opt/src || exiterr "Cannot enter /opt/src." diff --git a/vpnsetup.sh b/vpnsetup.sh index 773fcc7..bb89b3f 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -168,7 +168,6 @@ apt-get -yq install libnss3-dev libnspr4-dev pkg-config libpam0g-dev \ libcap-ng-dev libcap-ng-utils libselinux1-dev \ libcurl4-nss-dev flex bison gcc make \ libunbound-dev libnss3-tools libevent-dev || exiterr2 -apt-get -yq --no-install-recommends install xmlto || exiterr2 apt-get -yq install ppp xl2tpd || exiterr2 bigecho "Installing Fail2Ban to protect SSH..." @@ -194,7 +193,7 @@ EOF if [ "$(packaging/utils/lswan_detect.sh init)" = "systemd" ]; then apt-get -yq install libsystemd-dev || exiterr2 fi -make -s programs && make -s install +make -s base && make -s install-base # Verify the install and clean up cd /opt/src || exiterr "Cannot enter /opt/src." diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index 2bee99d..e294341 100755 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -157,7 +157,7 @@ bigecho "Installing packages required for the VPN..." yum -y install nss-devel nspr-devel pkgconfig pam-devel \ libcap-ng-devel libselinux-devel \ curl-devel flex bison gcc make \ - fipscheck-devel unbound-devel xmlto || exiterr2 + fipscheck-devel unbound-devel || exiterr2 yum -y install ppp xl2tpd || exiterr2 if grep -qs "release 6" /etc/redhat-release; then @@ -188,7 +188,7 @@ cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false EOF -make -s programs && make -s install +make -s base && make -s install-base # Verify the install and clean up cd /opt/src || exiterr "Cannot enter /opt/src." From 23c4a287d3dc074432d2d6bcf1bcc764efdf2d8d Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Thu, 28 Sep 2017 01:02:15 -0500 Subject: [PATCH 09/29] Use parallel make - Speed up Libreswan compilation using parallel make ("-j" option) --- extras/vpnupgrade.sh | 4 +++- extras/vpnupgrade_centos.sh | 4 +++- vpnsetup.sh | 4 +++- vpnsetup_centos.sh | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index e3b1137..a79864b 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -146,7 +146,9 @@ EOF if [ "$(packaging/utils/lswan_detect.sh init)" = "systemd" ]; then apt-get -yq install libsystemd-dev || exiterr2 fi -make -s base && make -s install-base +NPROCS="$(grep -c ^processor /proc/cpuinfo)" +[ -z "$NPROCS" ] && NPROCS=1 +make "-j$((NPROCS+1))" -s base && make -s install-base # Verify the install and clean up cd /opt/src || exiterr "Cannot enter /opt/src." diff --git a/extras/vpnupgrade_centos.sh b/extras/vpnupgrade_centos.sh index 7030d17..1b04fc6 100644 --- a/extras/vpnupgrade_centos.sh +++ b/extras/vpnupgrade_centos.sh @@ -143,7 +143,9 @@ cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false EOF -make -s base && make -s install-base +NPROCS="$(grep -c ^processor /proc/cpuinfo)" +[ -z "$NPROCS" ] && NPROCS=1 +make "-j$((NPROCS+1))" -s base && make -s install-base # Verify the install and clean up cd /opt/src || exiterr "Cannot enter /opt/src." diff --git a/vpnsetup.sh b/vpnsetup.sh index bb89b3f..ca280da 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -193,7 +193,9 @@ EOF if [ "$(packaging/utils/lswan_detect.sh init)" = "systemd" ]; then apt-get -yq install libsystemd-dev || exiterr2 fi -make -s base && make -s install-base +NPROCS="$(grep -c ^processor /proc/cpuinfo)" +[ -z "$NPROCS" ] && NPROCS=1 +make "-j$((NPROCS+1))" -s base && make -s install-base # Verify the install and clean up cd /opt/src || exiterr "Cannot enter /opt/src." diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index e294341..290ef44 100755 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -188,7 +188,9 @@ cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false EOF -make -s base && make -s install-base +NPROCS="$(grep -c ^processor /proc/cpuinfo)" +[ -z "$NPROCS" ] && NPROCS=1 +make "-j$((NPROCS+1))" -s base && make -s install-base # Verify the install and clean up cd /opt/src || exiterr "Cannot enter /opt/src." From 9cd6cb50b7c67c4683fb0eb8da2d7499e8d67b34 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Mon, 2 Oct 2017 20:33:24 -0500 Subject: [PATCH 10/29] Clean up packages - Remove libunbound-dev / unbound-devel (these packages are not needed because we are not enabling DNSSEC) Ref: https://github.com/libreswan/libreswan/issues/117 --- extras/vpnupgrade.sh | 2 +- extras/vpnupgrade_centos.sh | 2 +- vpnsetup.sh | 2 +- vpnsetup_centos.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index a79864b..2351684 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -127,7 +127,7 @@ apt-get -yq install wget || exiterr2 apt-get -yq install libnss3-dev libnspr4-dev pkg-config libpam0g-dev \ libcap-ng-dev libcap-ng-utils libselinux1-dev \ libcurl4-nss-dev flex bison gcc make \ - libunbound-dev libnss3-tools libevent-dev || exiterr2 + libnss3-tools libevent-dev || exiterr2 # Compile and install Libreswan swan_file="libreswan-$swan_ver.tar.gz" diff --git a/extras/vpnupgrade_centos.sh b/extras/vpnupgrade_centos.sh index 1b04fc6..552bb4f 100644 --- a/extras/vpnupgrade_centos.sh +++ b/extras/vpnupgrade_centos.sh @@ -119,7 +119,7 @@ yum -y install epel-release || exiterr2 yum -y install nss-devel nspr-devel pkgconfig pam-devel \ libcap-ng-devel libselinux-devel \ curl-devel flex bison gcc make \ - fipscheck-devel unbound-devel || exiterr2 + fipscheck-devel || exiterr2 # Install libevent2 and systemd-devel if grep -qs "release 6" /etc/redhat-release; then diff --git a/vpnsetup.sh b/vpnsetup.sh index ca280da..34f50f7 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -167,7 +167,7 @@ bigecho "Installing packages required for the VPN..." apt-get -yq install libnss3-dev libnspr4-dev pkg-config libpam0g-dev \ libcap-ng-dev libcap-ng-utils libselinux1-dev \ libcurl4-nss-dev flex bison gcc make \ - libunbound-dev libnss3-tools libevent-dev || exiterr2 + libnss3-tools libevent-dev || exiterr2 apt-get -yq install ppp xl2tpd || exiterr2 bigecho "Installing Fail2Ban to protect SSH..." diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index 290ef44..5a6204e 100755 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -157,7 +157,7 @@ bigecho "Installing packages required for the VPN..." yum -y install nss-devel nspr-devel pkgconfig pam-devel \ libcap-ng-devel libselinux-devel \ curl-devel flex bison gcc make \ - fipscheck-devel unbound-devel || exiterr2 + fipscheck-devel || exiterr2 yum -y install ppp xl2tpd || exiterr2 if grep -qs "release 6" /etc/redhat-release; then From 087306dbf5f6207215e566df7ace5ae150f7bab7 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Mon, 2 Oct 2017 21:55:21 -0500 Subject: [PATCH 11/29] Update docs --- README-zh.md | 18 ++++++++++-------- README.md | 16 +++++++++------- docs/clients-zh.md | 30 ++++++++++++++++-------------- docs/clients.md | 18 ++++++++++-------- docs/manage-users-zh.md | 18 +++++++++--------- 5 files changed, 54 insertions(+), 46 deletions(-) diff --git a/README-zh.md b/README-zh.md index ab4e44f..14eb4d3 100644 --- a/README-zh.md +++ b/README-zh.md @@ -28,7 +28,7 @@ IPsec VPN 可以加密你的网络流量,以防止在通过因特网传送时 ## 快速开始 -首先,在你的 Linux 服务器* 上全新安装一个 Ubuntu LTS, Debian 或者 CentOS 系统。 +首先,在你的 Linux 服务器[*](#quick-start-note) 上全新安装一个 Ubuntu LTS, Debian 或者 CentOS 系统。 使用以下命令快速搭建 IPsec VPN 服务器: @@ -42,6 +42,7 @@ wget https://git.io/vpnsetup -O vpnsetup.sh && sudo sh vpnsetup.sh 如需了解其它安装选项,以及如何配置 VPN 客户端,请继续阅读以下部分。 + \* 一个专用服务器或者虚拟专用服务器 (VPS)。OpenVZ VPS 不受支持。 ## 功能特性 @@ -66,9 +67,9 @@ wget https://git.io/vpnsetup -O vpnsetup.sh && sudo sh vpnsetup.sh **-或者-** -一个专用服务器,或者基于 KVM/Xen 的虚拟专用服务器 (VPS),全新安装以上操作系统之一。OpenVZ VPS 不受支持,用户可以尝试使用比如 Shadowsocks 或者 OpenVPN。 +一个专用服务器,或者基于 KVM/Xen 的虚拟专用服务器 (VPS),全新安装以上操作系统之一。OpenVZ VPS 不受支持,用户可以另外尝试比如 Shadowsocks 或者 OpenVPN。 -这也包括各种公共云服务中的 Linux 虚拟机,比如 DigitalOcean, Vultr, Linode, Google Compute Engine, Amazon Lightsail, Microsoft Azure, IBM SoftLayer, OVHRackspace。 +这也包括各种公共云服务中的 Linux 虚拟机,比如 DigitalOcean, Vultr, Linode, Google Compute Engine, Amazon Lightsail, Microsoft Azure, IBM Bluemix, OVHRackspaceDeploy to Azure Install on DigitalOcean Deploy to Linode @@ -124,10 +125,11 @@ VPN_PASSWORD='你的VPN密码' sh vpnsetup.sh 配置你的计算机或其它设备使用 VPN 。请参见: -配置 IPsec/L2TP VPN 客户端 -配置 IPsec/XAuth ("Cisco IPsec") VPN 客户端 +**配置 IPsec/L2TP VPN 客户端** -如何配置 IKEv2 VPN: Windows 和 Android +**配置 IPsec/XAuth ("Cisco IPsec") VPN 客户端** + +**如何配置 IKEv2 VPN: Windows 和 Android** 如果在连接过程中遇到错误,请参见 故障排除。 @@ -139,7 +141,7 @@ VPN_PASSWORD='你的VPN密码' sh vpnsetup.sh **Windows 用户** 在首次连接之前需要修改一次注册表,以解决 VPN 服务器 和/或 客户端与 NAT (比如家用路由器)的兼容问题。 -同一个 VPN 账户可以在你的多个设备上使用。但是由于 IPsec/L2TP 的局限性,如果需要同时连接在同一个 NAT (比如家用路由器)后面的多个设备到 VPN 服务器,你必须仅使用 IPsec/XAuth 模式。另外,你的服务器必须运行 [Libreswan 3.19 或更新版本](#升级libreswan)。 +同一个 VPN 账户可以在你的多个设备上使用。但是由于 IPsec/L2TP 的局限性,如果需要同时连接在同一个 NAT (比如家用路由器)后面的多个设备到 VPN 服务器,你必须仅使用 IPsec/XAuth 模式。 对于有外部防火墙的服务器(比如 EC2/GCE),请为 VPN 打开 UDP 端口 500 和 4500。 @@ -155,7 +157,7 @@ VPN_PASSWORD='你的VPN密码' sh vpnsetup.sh ## 升级Libreswan -提供两个额外的脚本 vpnupgrade.shvpnupgrade_centos.sh,可用于升级 Libreswan更新日志 | 通知列表)。请在运行前根据需要修改 `swan_ver` 变量。检查已安装版本: `ipsec --version`. +提供两个额外的脚本 vpnupgrade.shvpnupgrade_centos.sh,可用于升级 Libreswan更新日志 | 通知列表)。请在运行前根据需要修改 `swan_ver` 变量。查看已安装版本: `ipsec --version`. ```bash # Ubuntu & Debian diff --git a/README.md b/README.md index b3f4319..860c00f 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ We will use Libreswan as th ## Quick start -First, prepare your Linux server* with a fresh install of Ubuntu LTS, Debian or CentOS. +First, prepare your Linux server[*](#quick-start-note) with a fresh install of Ubuntu LTS, Debian or CentOS. Use this one-liner to set up an IPsec VPN server: @@ -42,6 +42,7 @@ Your VPN login details will be randomly generated, and displayed on the screen w For other installation options and how to set up VPN clients, read the sections below. + \* A dedicated server or virtual private server (VPS). OpenVZ VPS is not supported. ## Features @@ -68,7 +69,7 @@ Please see OpenVPN or Shadowsocks. -This also includes Linux VMs in public clouds, such as DigitalOcean, Vultr, Linode, Google Compute Engine, Amazon Lightsail, Microsoft Azure, IBM SoftLayer, OVH and Rackspace. +This also includes Linux VMs in public clouds, such as DigitalOcean, Vultr, Linode, Google Compute Engine, Amazon Lightsail, Microsoft Azure, IBM Bluemix, OVH and Rackspace. Deploy to Azure Install on DigitalOcean Deploy to Linode @@ -124,10 +125,11 @@ Follow the same steps as above, but replace `https://git.io/vpnsetup` with `http Get your computer or device to use the VPN. Please refer to: -Configure IPsec/L2TP VPN Clients -Configure IPsec/XAuth ("Cisco IPsec") VPN Clients +**Configure IPsec/L2TP VPN Clients** -How-To: IKEv2 VPN for Windows and Android +**Configure IPsec/XAuth ("Cisco IPsec") VPN Clients** + +**How-To: IKEv2 VPN for Windows and Android** If you get an error when trying to connect, see Troubleshooting. @@ -139,7 +141,7 @@ Enjoy your very own VPN! :sparkles::tada::rocket::sparkles: For **Windows users**, this one-time registry change is required if the VPN server and/or client is behind NAT (e.g. home router). -The same VPN account can be used by your multiple devices. However, due to an IPsec/L2TP limitation, if you wish to connect multiple devices simultaneously from behind the same NAT (e.g. home router), you must use only IPsec/XAuth mode. Also, your server must run [Libreswan 3.19 or newer](#upgrade-libreswan). +The same VPN account can be used by your multiple devices. However, due to an IPsec/L2TP limitation, if you wish to connect multiple devices simultaneously from behind the same NAT (e.g. home router), you must use only IPsec/XAuth mode. For servers with an external firewall (e.g. EC2/GCE), open UDP ports 500 and 4500 for the VPN. @@ -155,7 +157,7 @@ The scripts will backup existing config files before making changes, with `.old- ## Upgrade Libreswan -The additional scripts vpnupgrade.sh and vpnupgrade_centos.sh can be used to upgrade Libreswan (changelog | announce). Edit the `swan_ver` variable as necessary. Check installed version: `ipsec --version`. +The additional scripts vpnupgrade.sh and vpnupgrade_centos.sh can be used to upgrade Libreswan (changelog | announce). Edit the `swan_ver` variable as necessary. Check which version is installed: `ipsec --version`. ```bash # Ubuntu & Debian diff --git a/docs/clients-zh.md b/docs/clients-zh.md index be2d84f..7f7014b 100644 --- a/docs/clients-zh.md +++ b/docs/clients-zh.md @@ -20,7 +20,7 @@ * [故障排除](#故障排除) * [Windows 错误 809](#windows-错误-809) * [Windows 错误 628](#windows-错误-628) - * [Android 6 and 7](#android-6-and-7) + * [Android 6 及以上版本](#android-6-及以上版本) * [Chromebook](#chromebook) * [其它错误](#其它错误) * [额外的步骤](#额外的步骤) @@ -182,10 +182,10 @@ yum -y install strongswan xl2tpd 创建 VPN 变量 (替换为你自己的值): ```bash -VPN_SERVER_IP='your_vpn_server_ip' -VPN_IPSEC_PSK='your_ipsec_pre_shared_key' -VPN_USER='your_vpn_username' -VPN_PASSWORD='your_vpn_password' +VPN_SERVER_IP='你的VPN服务器IP' +VPN_IPSEC_PSK='你的IPsec预共享密钥' +VPN_USER='你的VPN用户名' +VPN_PASSWORD='你的VPN密码' ``` 配置 strongSwan: @@ -316,13 +316,13 @@ ip route 从新的默认路由中排除你的 VPN 服务器 IP (替换为你自己的值): ```bash -route add YOUR_VPN_SERVER_IP gw X.X.X.X +route add 你的VPN服务器IP gw X.X.X.X ``` -如果你的 VPN 客户端是一个远程服务器,则必须从新的默认路由中排除你本地电脑的公有 IP,以避免 SSH 会话被断开 (替换为你自己的公有 IP,可在 这里 查看): +如果你的 VPN 客户端是一个远程服务器,则必须从新的默认路由中排除你的本地电脑的公有 IP,以避免 SSH 会话被断开 (替换为实际值): ```bash -route add YOUR_LOCAL_PC_PUBLIC_IP gw X.X.X.X +route add 你的本地电脑的公有IP gw X.X.X.X ``` 添加一个新的默认路由,并且开始通过 VPN 服务器发送数据: @@ -395,13 +395,12 @@ strongswan down myvpn ![Select CHAP in VPN connection properties](images/vpn-properties-zh.png) -### Android 6 and 7 +### Android 6 及以上版本 -如果你无法使用 Android 6 (Marshmallow) 或者 7 (Nougat) 连接: +如果你无法使用 Android 6 或以上版本连接: 1. 单击 VPN 连接旁边的设置按钮,选择 "Show advanced options" 并且滚动到底部。如果选项 "Backward compatible mode" 存在,请启用它并重试连接。如果不存在,请尝试下一步。 -1. **注:** 最新版本的 VPN 脚本已经包含这个更改。 - (适用于 Android 7.1.2 及以上版本) 编辑 VPN 服务器上的 `/etc/ipsec.conf`。在 `ike=` 和 `phase2alg=` 两行的末尾添加 `,aes256-sha2_512` 字样。保存修改并运行 `service ipsec restart`。(参见) +1. (适用于 Android 7.1.2 及以上版本) 编辑 VPN 服务器上的 `/etc/ipsec.conf`。在 `ike=` 和 `phase2alg=` 两行的末尾添加 `,aes256-sha2_512` 字样。保存修改并运行 `service ipsec restart`。(参见) 注:最新版本的 VPN 脚本已经包含这个更改。 1. 编辑 VPN 服务器上的 `/etc/ipsec.conf`。找到 `sha2-truncbug=yes` 并将它替换为 `sha2-truncbug=no`,开头必须空两格。保存修改并运行 `service ipsec restart`。(参见) ![Android VPN workaround](images/vpn-profile-Android.png) @@ -414,9 +413,9 @@ Chromebook 用户: 如果你无法连接,请尝试 from here): +If your VPN client is a remote server, you must also exclude your Local PC's public IP from the new default route, to prevent your SSH session from being disconnected (replace with actual value): ```bash route add YOUR_LOCAL_PC_PUBLIC_IP gw X.X.X.X @@ -394,13 +394,12 @@ To fix this error, please follow these steps: ![Select CHAP in VPN connection properties](images/vpn-properties.png) -### Android 6 and 7 +### Android 6 and above -If you are unable to connect using Android 6 (Marshmallow) or 7 (Nougat): +If you are unable to connect using Android 6 or above: 1. Tap the "Settings" icon next to your VPN profile. Select "Show advanced options" and scroll down to the bottom. If the option "Backward compatible mode" exists, enable it and reconnect the VPN. If not, try the next step. -1. **Note:** The latest version of VPN scripts already includes this change. - (For Android 7.1.2 and newer) Edit `/etc/ipsec.conf` on the VPN server. Append `,aes256-sha2_512` to the end of both `ike=` and `phase2alg=` lines. Save the file and run `service ipsec restart`. (Ref) +1. (For Android 7.1.2 and newer) Edit `/etc/ipsec.conf` on the VPN server. Append `,aes256-sha2_512` to the end of both `ike=` and `phase2alg=` lines. Save the file and run `service ipsec restart`. (Ref) Note that the latest version of VPN scripts already includes this change. 1. Edit `/etc/ipsec.conf` on the VPN server. Find `sha2-truncbug=yes` and replace it with `sha2-truncbug=no`, indented with two spaces. Save the file and run `service ipsec restart`. (Ref) ![Android VPN workaround](images/vpn-profile-Android.png) @@ -413,9 +412,9 @@ Chromebook users: If you are unable to connect, try Date: Thu, 26 Oct 2017 01:30:37 -0500 Subject: [PATCH 12/29] Workaround for Netplan - Newer Ubuntu versions use netplan instead of ifupdown by default for network configuration - Scripts in /etc/network/if-pre-up.d/ does not work under netplan - Add workaround in /etc/rc.local for the above --- vpnsetup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/vpnsetup.sh b/vpnsetup.sh index 34f50f7..3c3494b 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -435,6 +435,7 @@ cat >> /etc/rc.local <<'EOF' (sleep 15 service ipsec restart service xl2tpd restart +[ -f "/usr/sbin/netplan" ] && iptables-restore < /etc/iptables.rules echo 1 > /proc/sys/net/ipv4/ip_forward)& exit 0 EOF From 47e1c9205166099beacfcbeda5fa52ebc07490aa Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Thu, 26 Oct 2017 01:37:35 -0500 Subject: [PATCH 13/29] Clean up ipsec.conf - Remove unneeded option nhelpers=0 --- vpnsetup.sh | 1 - vpnsetup_centos.sh | 1 - 2 files changed, 2 deletions(-) diff --git a/vpnsetup.sh b/vpnsetup.sh index 3c3494b..ce468cb 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -222,7 +222,6 @@ 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 protostack=netkey - nhelpers=0 interfaces=%defaultroute uniqueids=no diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index 5a6204e..0f7c115 100755 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -217,7 +217,6 @@ 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 protostack=netkey - nhelpers=0 interfaces=%defaultroute uniqueids=no From ef90b6ff1976eb1c5dd0eb74d1fe94b7c4c0ab68 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Thu, 26 Oct 2017 01:42:50 -0500 Subject: [PATCH 14/29] Upgrade Libreswan to 3.22 --- extras/vpnupgrade.sh | 2 +- extras/vpnupgrade_centos.sh | 2 +- vpnsetup.sh | 2 +- vpnsetup_centos.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index 2351684..712eaf5 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -11,7 +11,7 @@ # know how you have improved it! # Check https://libreswan.org for the latest version -swan_ver=3.21 +swan_ver=3.22 ### DO NOT edit below this line ### diff --git a/extras/vpnupgrade_centos.sh b/extras/vpnupgrade_centos.sh index 552bb4f..dfe2f10 100644 --- a/extras/vpnupgrade_centos.sh +++ b/extras/vpnupgrade_centos.sh @@ -11,7 +11,7 @@ # know how you have improved it! # Check https://libreswan.org for the latest version -swan_ver=3.21 +swan_ver=3.22 ### DO NOT edit below this line ### diff --git a/vpnsetup.sh b/vpnsetup.sh index ce468cb..3c39bef 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -176,7 +176,7 @@ apt-get -yq install fail2ban || exiterr2 bigecho "Compiling and installing Libreswan..." -swan_ver=3.21 +swan_ver=3.22 swan_file="libreswan-$swan_ver.tar.gz" swan_url1="https://github.com/libreswan/libreswan/archive/v$swan_ver.tar.gz" swan_url2="https://download.libreswan.org/$swan_file" diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index 0f7c115..bfa11a4 100755 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -174,7 +174,7 @@ yum -y install fail2ban || exiterr2 bigecho "Compiling and installing Libreswan..." -swan_ver=3.21 +swan_ver=3.22 swan_file="libreswan-$swan_ver.tar.gz" swan_url1="https://github.com/libreswan/libreswan/archive/v$swan_ver.tar.gz" swan_url2="https://download.libreswan.org/$swan_file" From 1488ac0ce88c6f938604b59ba8669e90c7bda006 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Fri, 27 Oct 2017 00:14:38 -0500 Subject: [PATCH 15/29] Workaround for Raspberry Pi - Libreswan version 3.22 does not start on Raspberry Pi - Install version 3.21 on these systems as a workaround --- extras/vpnupgrade.sh | 20 ++++++++++++++++++++ vpnsetup.sh | 3 +++ 2 files changed, 23 insertions(+) diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index 712eaf5..29089b2 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -49,6 +49,26 @@ if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -q "Libreswan"; then exiterr "This script requires Libreswan already installed." fi +if [ "$swan_ver" = "3.22" ]; then + if grep -qs raspbian /etc/os-release; then + echo "Note: For Raspberry Pi systems, this script will install Libreswan" + echo "version 3.21 instead of 3.22, to avoid some recent bugs." + echo + printf "Do you wish to continue? [y/N] " + read -r response + case $response in + [yY][eE][sS]|[yY]) + echo + swan_ver=3.21 + ;; + *) + echo "Aborting." + exit 1 + ;; + esac + fi +fi + if /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$swan_ver"; then echo "You already have Libreswan version $swan_ver installed! " echo "If you continue, the same version will be re-installed." diff --git a/vpnsetup.sh b/vpnsetup.sh index 3c39bef..d61db85 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -177,6 +177,9 @@ apt-get -yq install fail2ban || exiterr2 bigecho "Compiling and installing Libreswan..." swan_ver=3.22 +if grep -qs raspbian /etc/os-release; then + swan_ver=3.21 +fi swan_file="libreswan-$swan_ver.tar.gz" swan_url1="https://github.com/libreswan/libreswan/archive/v$swan_ver.tar.gz" swan_url2="https://download.libreswan.org/$swan_file" From e316c8cdf81440fbd29342677d6ba7fc09cc9661 Mon Sep 17 00:00:00 2001 From: Any <406088125@qq.com> Date: Fri, 27 Oct 2017 13:35:51 +0800 Subject: [PATCH 16/29] Troubleshooting error 728 (#250) * Update docs --- docs/clients-zh.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/clients-zh.md b/docs/clients-zh.md index 7f7014b..0d241ef 100644 --- a/docs/clients-zh.md +++ b/docs/clients-zh.md @@ -18,7 +18,7 @@ * [Windows Phone](#windows-phone) * [Linux](#linux) * [故障排除](#故障排除) - * [Windows 错误 809](#windows-错误-809) + * [Windows 错误 809 和 728](#windows-错误-809-和-728) * [Windows 错误 628](#windows-错误-628) * [Android 6 及以上版本](#android-6-及以上版本) * [Chromebook](#chromebook) @@ -362,7 +362,7 @@ strongswan down myvpn *其他语言版本: [English](clients.md#troubleshooting), [简体中文](clients-zh.md#故障排除).* -### Windows 错误 809 +### Windows 错误 809 和 728 > 无法建立计算机与 VPN 服务器之间的网络连接,因为远程服务器未响应。 @@ -378,6 +378,11 @@ strongswan down myvpn REG ADD HKLM\SYSTEM\CurrentControlSet\Services\IPSec /v AssumeUDPEncapsulationContextOnSendRule /t REG_DWORD /d 0x2 /f ``` +- 某些 Windows 系统默认禁用了 IPSec 加密, 此时也会导致连接失败. 可通过该命令启用 IPSec + ```console + REG ADD HKLM\SYSTEM\CurrentControlSet\Services\RasMan\Parameters /v ProhibitIpSec /t REG_DWORD /d 0x0 /f + ``` + ### Windows 错误 628 > 在连接完成前,连接被远程计算机终止。 From 68a6375399f947bb391ff8ccfe56751950b1e04b Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Fri, 27 Oct 2017 01:02:03 -0500 Subject: [PATCH 17/29] Update docs --- docs/clients-zh.md | 13 +++++++------ docs/clients.md | 6 ++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/clients-zh.md b/docs/clients-zh.md index 0d241ef..f478aa4 100644 --- a/docs/clients-zh.md +++ b/docs/clients-zh.md @@ -18,7 +18,7 @@ * [Windows Phone](#windows-phone) * [Linux](#linux) * [故障排除](#故障排除) - * [Windows 错误 809 和 728](#windows-错误-809-和-728) + * [Windows 错误 809](#windows-错误-809) * [Windows 错误 628](#windows-错误-628) * [Android 6 及以上版本](#android-6-及以上版本) * [Chromebook](#chromebook) @@ -362,7 +362,7 @@ strongswan down myvpn *其他语言版本: [English](clients.md#troubleshooting), [简体中文](clients-zh.md#故障排除).* -### Windows 错误 809 和 728 +### Windows 错误 809 > 无法建立计算机与 VPN 服务器之间的网络连接,因为远程服务器未响应。 @@ -378,10 +378,11 @@ strongswan down myvpn REG ADD HKLM\SYSTEM\CurrentControlSet\Services\IPSec /v AssumeUDPEncapsulationContextOnSendRule /t REG_DWORD /d 0x2 /f ``` -- 某些 Windows 系统默认禁用了 IPSec 加密, 此时也会导致连接失败. 可通过该命令启用 IPSec - ```console - REG ADD HKLM\SYSTEM\CurrentControlSet\Services\RasMan\Parameters /v ProhibitIpSec /t REG_DWORD /d 0x0 /f - ``` +另外,某些个别的 Windows 系统禁用了 IPsec 加密,此时也会导致连接失败。要重新启用它,可以运行以下命令并重启计算机。 + +```console +REG ADD HKLM\SYSTEM\CurrentControlSet\Services\RasMan\Parameters /v ProhibitIpSec /t REG_DWORD /d 0x0 /f +``` ### Windows 错误 628 diff --git a/docs/clients.md b/docs/clients.md index cae2c39..b3ac7e9 100644 --- a/docs/clients.md +++ b/docs/clients.md @@ -377,6 +377,12 @@ To fix this error, a > /etc/sysctl.conf <> /etc/sysctl.conf < Date: Sat, 28 Oct 2017 17:06:35 -0500 Subject: [PATCH 19/29] Update docs - Add a note on using L2TP kernel support --- README-zh.md | 2 ++ README.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README-zh.md b/README-zh.md index 14eb4d3..aa33857 100644 --- a/README-zh.md +++ b/README-zh.md @@ -149,6 +149,8 @@ VPN_PASSWORD='你的VPN密码' sh vpnsetup.sh 在 VPN 已连接时,客户端配置为使用 Google Public DNS。如果偏好其它的域名解析服务,请编辑 `/etc/ppp/options.xl2tpd` 和 `/etc/ipsec.conf` 并替换 `8.8.8.8` 和 `8.8.4.4`。然后重启服务器。 +使用 L2TP 内核支持有助于提高 IPsec/L2TP 性能。它在以下系统上可用: Ubuntu 16.04, Debian 9, CentOS 7 和 6。 Ubuntu 16.04 用户需要安装 `` linux-image-extra-`uname -r` `` 软件包并且重启 `xl2tpd` 服务。 + 如果需要在安装后更改 IPTables 规则,请编辑 `/etc/iptables.rules` 和/或 `/etc/iptables/rules.v4` (Ubuntu/Debian),或者 `/etc/sysconfig/iptables` (CentOS)。然后重启服务器。 在使用 `IPsec/L2TP` 连接时,VPN 服务器在虚拟网络 `192.168.42.0/24` 内具有 IP `192.168.42.1`。 diff --git a/README.md b/README.md index 860c00f..fb7c7e5 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,8 @@ If you wish to add, edit or remove VPN user accounts, see Google Public DNS when the VPN is active. If another DNS provider is preferred, replace `8.8.8.8` and `8.8.4.4` in both `/etc/ppp/options.xl2tpd` and `/etc/ipsec.conf`. Then reboot your server. +Using L2TP kernel support could improve IPsec/L2TP performance. It is available on Ubuntu 16.04, Debian 9, CentOS 7 and 6. Ubuntu 16.04 users should install the `` linux-image-extra-`uname -r` `` package and restart the `xl2tpd` service. + To modify the IPTables rules after install, edit `/etc/iptables.rules` and/or `/etc/iptables/rules.v4` (Ubuntu/Debian), or `/etc/sysconfig/iptables` (CentOS). Then reboot your server. When connecting via `IPsec/L2TP`, the VPN server has IP `192.168.42.1` within the VPN subnet `192.168.42.0/24`. From 16e437f58ed2448222e21561b70ec039ff91bd6c Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Sun, 29 Oct 2017 19:53:35 -0500 Subject: [PATCH 20/29] Minor clean up - Wrap the scripts in a big function which is only called at the very end, to protect against the possibility of connection interruptions - Clean up some variables names --- .travis.yml | 2 +- extras/vpnupgrade.sh | 7 +++++ extras/vpnupgrade_centos.sh | 7 +++++ vpnsetup.sh | 58 ++++++++++++++++++++----------------- vpnsetup_centos.sh | 58 ++++++++++++++++++++----------------- 5 files changed, 79 insertions(+), 53 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3eb710a..e4b7961 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ addons: - shellcheck script: - - export SHELLCHECK_OPTS="-e SC1091" + - export SHELLCHECK_OPTS="-e SC1091,SC1117" - shellcheck *.sh extras/*.sh - sudo sed -i "/debian unstable/d" /etc/apt/sources.list - sudo VPN_IPSEC_PSK='vpn_psk' diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index 29089b2..65644b0 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -20,6 +20,8 @@ export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" exiterr() { echo "Error: $1" >&2; exit 1; } exiterr2() { echo "Error: 'apt-get install' failed." >&2; exit 1; } +vpnupgrade() { + os_type="$(lsb_release -si 2>/dev/null)" if [ -z "$os_type" ]; then [ -f /etc/os-release ] && os_type="$(. /etc/os-release && echo "$ID")" @@ -193,4 +195,9 @@ echo echo "Libreswan $swan_ver was installed successfully! " echo +} + +## Defer setup until we have the complete script +vpnupgrade "$@" + exit 0 diff --git a/extras/vpnupgrade_centos.sh b/extras/vpnupgrade_centos.sh index dfe2f10..f4f607a 100644 --- a/extras/vpnupgrade_centos.sh +++ b/extras/vpnupgrade_centos.sh @@ -20,6 +20,8 @@ export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" exiterr() { echo "Error: $1" >&2; exit 1; } exiterr2() { echo "Error: 'yum install' failed." >&2; exit 1; } +vpnupgrade() { + if ! grep -qs -e "release 6" -e "release 7" /etc/redhat-release; then exiterr "This script only supports CentOS/RHEL 6 and 7." fi @@ -175,4 +177,9 @@ echo echo "Libreswan $swan_ver was installed successfully! " echo +} + +## Defer setup until we have the complete script +vpnupgrade "$@" + exit 0 diff --git a/vpnsetup.sh b/vpnsetup.sh index c6335be..13d04b7 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -34,18 +34,19 @@ YOUR_PASSWORD='' # ===================================================== export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" -SYS_DT="$(date +%Y-%m-%d-%H:%M:%S)"; export SYS_DT exiterr() { echo "Error: $1" >&2; exit 1; } exiterr2() { echo "Error: 'apt-get install' failed." >&2; exit 1; } -conf_bk() { /bin/cp -f "$1" "$1.old-$SYS_DT" 2>/dev/null; } +conf_bk() { /bin/cp -f "$1" "$1.old-$(date +%Y-%m-%d-%H:%M:%S)" 2>/dev/null; } bigecho() { echo; echo "## $1"; echo; } 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])$" + 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" } +vpnsetup() { + os_type="$(lsb_release -si 2>/dev/null)" if [ -z "$os_type" ]; then [ -f /etc/os-release ] && os_type="$(. /etc/os-release && echo "$ID")" @@ -69,31 +70,31 @@ if [ "$(id -u)" != 0 ]; then exiterr "Script must be run as root. Try 'sudo sh $0'" fi -NET_IFACE=${VPN_NET_IFACE:-'eth0'} -DEF_IFACE="$(route 2>/dev/null | grep '^default' | grep -o '[^ ]*$')" -[ -z "$DEF_IFACE" ] && DEF_IFACE="$(ip -4 route list 0/0 2>/dev/null | grep -Po '(?<=dev )(\S+)')" +net_iface=${VPN_NET_IFACE:-'eth0'} +def_iface="$(route 2>/dev/null | grep '^default' | grep -o '[^ ]*$')" +[ -z "$def_iface" ] && def_iface="$(ip -4 route list 0/0 2>/dev/null | grep -Po '(?<=dev )(\S+)')" -if_state1=$(cat "/sys/class/net/$DEF_IFACE/operstate" 2>/dev/null) -if [ -z "$VPN_NET_IFACE" ] && [ -n "$if_state1" ] && [ "$if_state1" != "down" ]; then +def_iface_state=$(cat "/sys/class/net/$def_iface/operstate" 2>/dev/null) +if [ -z "$VPN_NET_IFACE" ] && [ -n "$def_iface_state" ] && [ "$def_iface_state" != "down" ]; then if ! grep -qs raspbian /etc/os-release; then - case "$DEF_IFACE" in + case "$def_iface" in wl*) cat 1>&2 <> DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC! << If you are certain that this script is running on a server, re-run it with: - sudo VPN_NET_IFACE="$DEF_IFACE" sh "$0" + sudo VPN_NET_IFACE="$def_iface" sh "$0" EOF exit 1 ;; esac fi - NET_IFACE="$DEF_IFACE" + net_iface="$def_iface" fi -if_state2=$(cat "/sys/class/net/$NET_IFACE/operstate" 2>/dev/null) -if [ -z "$if_state2" ] || [ "$if_state2" = "down" ] || [ "$NET_IFACE" = "lo" ]; then - printf "Error: Network interface '%s' is not available.\n" "$NET_IFACE" >&2 +net_iface_state=$(cat "/sys/class/net/$net_iface/operstate" 2>/dev/null) +if [ -z "$net_iface_state" ] || [ "$net_iface_state" = "down" ] || [ "$net_iface" = "lo" ]; then + printf "Error: Network interface '%s' is not available.\n" "$net_iface" >&2 if [ -z "$VPN_NET_IFACE" ]; then cat 1>&2 </dev/null \ - || ! iptables -t nat -C POSTROUTING -s "$XAUTH_NET" -o "$NET_IFACE" -m policy --dir out --pol none -j MASQUERADE 2>/dev/null; then + || ! iptables -t nat -C POSTROUTING -s "$L2TP_NET" -o "$net_iface" -j MASQUERADE 2>/dev/null \ + || ! iptables -t nat -C POSTROUTING -s "$XAUTH_NET" -o "$net_iface" -m policy --dir out --pol none -j MASQUERADE 2>/dev/null; then ipt_flag=1 fi # Add IPTables rules for VPN if [ "$ipt_flag" = "1" ]; then service fail2ban stop >/dev/null 2>&1 - iptables-save > "$IPT_FILE.old-$SYS_DT" + iptables-save > "$IPT_FILE.old-$(date +%Y-%m-%d-%H:%M:%S)" iptables -I INPUT 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP iptables -I INPUT 2 -m conntrack --ctstate INVALID -j DROP iptables -I INPUT 3 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT @@ -391,17 +392,17 @@ if [ "$ipt_flag" = "1" ]; then iptables -I INPUT 5 -p udp --dport 1701 -m policy --dir in --pol ipsec -j ACCEPT iptables -I INPUT 6 -p udp --dport 1701 -j DROP iptables -I FORWARD 1 -m conntrack --ctstate INVALID -j DROP - iptables -I FORWARD 2 -i "$NET_IFACE" -o ppp+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT - iptables -I FORWARD 3 -i ppp+ -o "$NET_IFACE" -j ACCEPT + iptables -I FORWARD 2 -i "$net_iface" -o ppp+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + iptables -I FORWARD 3 -i ppp+ -o "$net_iface" -j ACCEPT iptables -I FORWARD 4 -i ppp+ -o ppp+ -s "$L2TP_NET" -d "$L2TP_NET" -j ACCEPT - iptables -I FORWARD 5 -i "$NET_IFACE" -d "$XAUTH_NET" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT - iptables -I FORWARD 6 -s "$XAUTH_NET" -o "$NET_IFACE" -j ACCEPT + iptables -I FORWARD 5 -i "$net_iface" -d "$XAUTH_NET" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + iptables -I FORWARD 6 -s "$XAUTH_NET" -o "$net_iface" -j ACCEPT # Uncomment if you wish to disallow traffic between VPN clients themselves # iptables -I FORWARD 2 -i ppp+ -o ppp+ -s "$L2TP_NET" -d "$L2TP_NET" -j DROP # iptables -I FORWARD 3 -s "$XAUTH_NET" -d "$XAUTH_NET" -j DROP iptables -A FORWARD -j DROP - iptables -t nat -I POSTROUTING -s "$XAUTH_NET" -o "$NET_IFACE" -m policy --dir out --pol none -j MASQUERADE - iptables -t nat -I POSTROUTING -s "$L2TP_NET" -o "$NET_IFACE" -j MASQUERADE + iptables -t nat -I POSTROUTING -s "$XAUTH_NET" -o "$net_iface" -m policy --dir out --pol none -j MASQUERADE + iptables -t nat -I POSTROUTING -s "$L2TP_NET" -o "$net_iface" -j MASQUERADE echo "# Modified by hwdsl2 VPN script" > "$IPT_FILE" iptables-save >> "$IPT_FILE" @@ -484,4 +485,9 @@ Setup VPN clients: https://git.io/vpnclients EOF +} + +## Defer setup until we have the complete script +vpnsetup "$@" + exit 0 diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index 43b4f92..bc8405d 100755 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -34,18 +34,19 @@ YOUR_PASSWORD='' # ===================================================== export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" -SYS_DT="$(date +%Y-%m-%d-%H:%M:%S)"; export SYS_DT exiterr() { echo "Error: $1" >&2; exit 1; } exiterr2() { echo "Error: 'yum install' failed." >&2; exit 1; } -conf_bk() { /bin/cp -f "$1" "$1.old-$SYS_DT" 2>/dev/null; } +conf_bk() { /bin/cp -f "$1" "$1.old-$(date +%Y-%m-%d-%H:%M:%S)" 2>/dev/null; } bigecho() { echo; echo "## $1"; echo; } 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])$" + 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" } +vpnsetup() { + if ! grep -qs -e "release 6" -e "release 7" /etc/redhat-release; then exiterr "This script only supports CentOS/RHEL 6 and 7." fi @@ -60,31 +61,31 @@ if [ "$(id -u)" != 0 ]; then exiterr "Script must be run as root. Try 'sudo sh $0'" fi -NET_IFACE=${VPN_NET_IFACE:-'eth0'} -DEF_IFACE="$(route 2>/dev/null | grep '^default' | grep -o '[^ ]*$')" -[ -z "$DEF_IFACE" ] && DEF_IFACE="$(ip -4 route list 0/0 2>/dev/null | grep -Po '(?<=dev )(\S+)')" +net_iface=${VPN_NET_IFACE:-'eth0'} +def_iface="$(route 2>/dev/null | grep '^default' | grep -o '[^ ]*$')" +[ -z "$def_iface" ] && def_iface="$(ip -4 route list 0/0 2>/dev/null | grep -Po '(?<=dev )(\S+)')" -if_state1=$(cat "/sys/class/net/$DEF_IFACE/operstate" 2>/dev/null) -if [ -z "$VPN_NET_IFACE" ] && [ -n "$if_state1" ] && [ "$if_state1" != "down" ]; then +def_iface_state=$(cat "/sys/class/net/$def_iface/operstate" 2>/dev/null) +if [ -z "$VPN_NET_IFACE" ] && [ -n "$def_iface_state" ] && [ "$def_iface_state" != "down" ]; then if ! grep -qs raspbian /etc/os-release; then - case "$DEF_IFACE" in + case "$def_iface" in wl*) cat 1>&2 <> DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC! << If you are certain that this script is running on a server, re-run it with: - sudo VPN_NET_IFACE="$DEF_IFACE" sh "$0" + sudo VPN_NET_IFACE="$def_iface" sh "$0" EOF exit 1 ;; esac fi - NET_IFACE="$DEF_IFACE" + net_iface="$def_iface" fi -if_state2=$(cat "/sys/class/net/$NET_IFACE/operstate" 2>/dev/null) -if [ -z "$if_state2" ] || [ "$if_state2" = "down" ] || [ "$NET_IFACE" = "lo" ]; then - printf "Error: Network interface '%s' is not available.\n" "$NET_IFACE" >&2 +net_iface_state=$(cat "/sys/class/net/$net_iface/operstate" 2>/dev/null) +if [ -z "$net_iface_state" ] || [ "$net_iface_state" = "down" ] || [ "$net_iface" = "lo" ]; then + printf "Error: Network interface '%s' is not available.\n" "$net_iface" >&2 if [ -z "$VPN_NET_IFACE" ]; then cat 1>&2 </dev/null \ - || ! iptables -t nat -C POSTROUTING -s "$XAUTH_NET" -o "$NET_IFACE" -m policy --dir out --pol none -j MASQUERADE 2>/dev/null; then + || ! iptables -t nat -C POSTROUTING -s "$L2TP_NET" -o "$net_iface" -j MASQUERADE 2>/dev/null \ + || ! iptables -t nat -C POSTROUTING -s "$XAUTH_NET" -o "$net_iface" -m policy --dir out --pol none -j MASQUERADE 2>/dev/null; then ipt_flag=1 fi # Add IPTables rules for VPN if [ "$ipt_flag" = "1" ]; then service fail2ban stop >/dev/null 2>&1 - iptables-save > "$IPT_FILE.old-$SYS_DT" + iptables-save > "$IPT_FILE.old-$(date +%Y-%m-%d-%H:%M:%S)" iptables -I INPUT 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP iptables -I INPUT 2 -m conntrack --ctstate INVALID -j DROP iptables -I INPUT 3 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT @@ -377,17 +378,17 @@ if [ "$ipt_flag" = "1" ]; then iptables -I INPUT 5 -p udp --dport 1701 -m policy --dir in --pol ipsec -j ACCEPT iptables -I INPUT 6 -p udp --dport 1701 -j DROP iptables -I FORWARD 1 -m conntrack --ctstate INVALID -j DROP - iptables -I FORWARD 2 -i "$NET_IFACE" -o ppp+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT - iptables -I FORWARD 3 -i ppp+ -o "$NET_IFACE" -j ACCEPT + iptables -I FORWARD 2 -i "$net_iface" -o ppp+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + iptables -I FORWARD 3 -i ppp+ -o "$net_iface" -j ACCEPT iptables -I FORWARD 4 -i ppp+ -o ppp+ -s "$L2TP_NET" -d "$L2TP_NET" -j ACCEPT - iptables -I FORWARD 5 -i "$NET_IFACE" -d "$XAUTH_NET" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT - iptables -I FORWARD 6 -s "$XAUTH_NET" -o "$NET_IFACE" -j ACCEPT + iptables -I FORWARD 5 -i "$net_iface" -d "$XAUTH_NET" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + iptables -I FORWARD 6 -s "$XAUTH_NET" -o "$net_iface" -j ACCEPT # Uncomment if you wish to disallow traffic between VPN clients themselves # iptables -I FORWARD 2 -i ppp+ -o ppp+ -s "$L2TP_NET" -d "$L2TP_NET" -j DROP # iptables -I FORWARD 3 -s "$XAUTH_NET" -d "$XAUTH_NET" -j DROP iptables -A FORWARD -j DROP - iptables -t nat -I POSTROUTING -s "$XAUTH_NET" -o "$NET_IFACE" -m policy --dir out --pol none -j MASQUERADE - iptables -t nat -I POSTROUTING -s "$L2TP_NET" -o "$NET_IFACE" -j MASQUERADE + iptables -t nat -I POSTROUTING -s "$XAUTH_NET" -o "$net_iface" -m policy --dir out --pol none -j MASQUERADE + iptables -t nat -I POSTROUTING -s "$L2TP_NET" -o "$net_iface" -j MASQUERADE echo "# Modified by hwdsl2 VPN script" > "$IPT_FILE" iptables-save >> "$IPT_FILE" fi @@ -484,4 +485,9 @@ Setup VPN clients: https://git.io/vpnclients EOF +} + +## Defer setup until we have the complete script +vpnsetup "$@" + exit 0 From b7a4bed866ac70efc617789460edd340aef73114 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Mon, 30 Oct 2017 01:56:00 -0500 Subject: [PATCH 21/29] Improve startup - Ubuntu 16.04 (and newer) may run apt tasks automatically on boot - If used as a startup script, apt-get commands could fail due to this - Wait for apt/dpkg lock (up to 60s) as a workaround - Ref: #252 --- vpnsetup.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vpnsetup.sh b/vpnsetup.sh index 13d04b7..90f21e4 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -138,6 +138,14 @@ cd /opt/src || exiterr "Cannot enter /opt/src." bigecho "Populating apt-get cache..." +count=0 +while fuser /var/lib/apt/lists/lock /var/lib/dpkg/lock >/dev/null 2>&1; do + [ "$count" -ge "20" ] && exiterr "Cannot get apt/dpkg lock." + count=$((count+1)) + printf %s . + sleep 3 +done + export DEBIAN_FRONTEND=noninteractive apt-get -yq update || exiterr "'apt-get update' failed." From 70c6d6b5401e8955b5322cbd4b4e42c3b5ace0e7 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Wed, 1 Nov 2017 01:01:49 -0500 Subject: [PATCH 22/29] Various clean up --- README-zh.md | 2 +- README.md | 4 +- docs/manage-users.md | 2 +- extras/vpnupgrade.sh | 52 +++++++++++------------ extras/vpnupgrade_centos.sh | 40 +++++++++--------- vpnsetup.sh | 82 ++++++++++++++++--------------------- vpnsetup_centos.sh | 72 +++++++++++++------------------- 7 files changed, 114 insertions(+), 140 deletions(-) diff --git a/README-zh.md b/README-zh.md index aa33857..1bd9c08 100644 --- a/README-zh.md +++ b/README-zh.md @@ -159,7 +159,7 @@ VPN_PASSWORD='你的VPN密码' sh vpnsetup.sh ## 升级Libreswan -提供两个额外的脚本 vpnupgrade.shvpnupgrade_centos.sh,可用于升级 Libreswan更新日志 | 通知列表)。请在运行前根据需要修改 `swan_ver` 变量。查看已安装版本: `ipsec --version`. +提供两个额外的脚本 vpnupgrade.shvpnupgrade_centos.sh,可用于升级 Libreswan更新日志 | 通知列表)。请在运行前根据需要修改 `SWAN_VER` 变量。查看已安装版本: `ipsec --version`. ```bash # Ubuntu & Debian diff --git a/README.md b/README.md index fb7c7e5..37eecff 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ sudo sh vpnsetup.sh ```bash # All values MUST be placed inside 'single quotes' -# DO NOT use these characters within values: \ " ' +# DO NOT use these special characters within values: \ " ' wget https://git.io/vpnsetup -O vpnsetup.sh && sudo \ VPN_IPSEC_PSK='your_ipsec_pre_shared_key' \ VPN_USER='your_vpn_username' \ @@ -159,7 +159,7 @@ The scripts will backup existing config files before making changes, with `.old- ## Upgrade Libreswan -The additional scripts vpnupgrade.sh and vpnupgrade_centos.sh can be used to upgrade Libreswan (changelog | announce). Edit the `swan_ver` variable as necessary. Check which version is installed: `ipsec --version`. +The additional scripts vpnupgrade.sh and vpnupgrade_centos.sh can be used to upgrade Libreswan (changelog | announce). Edit the `SWAN_VER` variable as necessary. Check which version is installed: `ipsec --version`. ```bash # Ubuntu & Debian diff --git a/docs/manage-users.md b/docs/manage-users.md index cfd7bf4..c14dc53 100644 --- a/docs/manage-users.md +++ b/docs/manage-users.md @@ -18,7 +18,7 @@ For `IPsec/L2TP`, VPN users are specified in `/etc/ppp/chap-secrets`. The format ... ... ``` -You can add more users, use one line for each user. DO NOT use these characters within values: `\ " '` +You can add more users, use one line for each user. DO NOT use these special characters within values: `\ " '` For `IPsec/XAuth ("Cisco IPsec")`, VPN users are specified in `/etc/ipsec.d/passwd`. The format of this file is: diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index 65644b0..1a4616d 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -11,14 +11,14 @@ # know how you have improved it! # Check https://libreswan.org for the latest version -swan_ver=3.22 +SWAN_VER=3.22 ### DO NOT edit below this line ### export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" exiterr() { echo "Error: $1" >&2; exit 1; } -exiterr2() { echo "Error: 'apt-get install' failed." >&2; exit 1; } +exiterr2() { exiterr "'apt-get install' failed."; } vpnupgrade() { @@ -27,31 +27,31 @@ if [ -z "$os_type" ]; then [ -f /etc/os-release ] && os_type="$(. /etc/os-release && echo "$ID")" [ -f /etc/lsb-release ] && os_type="$(. /etc/lsb-release && echo "$DISTRIB_ID")" fi -if ! printf %s "$os_type" | head -n 1 | grep -qiF -e ubuntu -e debian -e raspbian; then - exiterr "This script only supports Ubuntu/Debian." +if ! printf '%s' "$os_type" | head -n 1 | grep -qiF -e ubuntu -e debian -e raspbian; then + exiterr "This script only supports Ubuntu and Debian." fi if [ "$(sed 's/\..*//' /etc/debian_version)" = "7" ]; then - exiterr "This script does not support Debian 7 (Wheezy)." + exiterr "Debian 7 is not supported." fi if [ -f /proc/user_beancounters ]; then - exiterr "This script does not support OpenVZ VPS." + exiterr "OpenVZ VPS is not supported." fi if [ "$(id -u)" != 0 ]; then exiterr "Script must be run as root. Try 'sudo sh $0'" fi -if [ -z "$swan_ver" ]; then - exiterr "Libreswan version 'swan_ver' not specified." +if [ -z "$SWAN_VER" ]; then + exiterr "Libreswan version 'SWAN_VER' not specified." fi if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -q "Libreswan"; then exiterr "This script requires Libreswan already installed." fi -if [ "$swan_ver" = "3.22" ]; then +if [ "$SWAN_VER" = "3.22" ]; then if grep -qs raspbian /etc/os-release; then echo "Note: For Raspberry Pi systems, this script will install Libreswan" echo "version 3.21 instead of 3.22, to avoid some recent bugs." @@ -61,7 +61,7 @@ if [ "$swan_ver" = "3.22" ]; then case $response in [yY][eE][sS]|[yY]) echo - swan_ver=3.21 + SWAN_VER=3.21 ;; *) echo "Aborting." @@ -71,8 +71,8 @@ if [ "$swan_ver" = "3.22" ]; then fi fi -if /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$swan_ver"; then - echo "You already have Libreswan version $swan_ver installed! " +if /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$SWAN_VER"; then + echo "You already have Libreswan version $SWAN_VER installed! " echo "If you continue, the same version will be re-installed." echo printf "Do you wish to continue anyway? [y/N] " @@ -91,7 +91,7 @@ fi clear cat < Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false @@ -174,15 +174,15 @@ make "-j$((NPROCS+1))" -s base && make -s install-base # Verify the install and clean up cd /opt/src || exiterr "Cannot enter /opt/src." -/bin/rm -rf "/opt/src/libreswan-$swan_ver" -if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$swan_ver"; then - exiterr "Libreswan $swan_ver failed to build." +/bin/rm -rf "/opt/src/libreswan-$SWAN_VER" +if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$SWAN_VER"; then + exiterr "Libreswan $SWAN_VER failed to build." fi # Update ipsec.conf for Libreswan 3.19 and newer IKE_NEW=" ike=3des-sha1,3des-sha2,aes-sha1,aes-sha1;modp1024,aes-sha2,aes-sha2;modp1024,aes256-sha2_512" PHASE2_NEW=" phase2alg=3des-sha1,3des-sha2,aes-sha1,aes-sha2,aes256-sha2_512" -sed -i".old-$(date +%Y-%m-%d-%H:%M:%S)" \ +sed -i".old-$(date +%F-%T)" \ -e "s/^[[:space:]]\+auth=esp\$/ phase2=esp/" \ -e "s/^[[:space:]]\+forceencaps=yes\$/ encapsulation=yes/" \ -e "s/^[[:space:]]\+ike=.\+\$/$IKE_NEW/" \ @@ -192,7 +192,7 @@ sed -i".old-$(date +%Y-%m-%d-%H:%M:%S)" \ service ipsec restart echo -echo "Libreswan $swan_ver was installed successfully! " +echo "Libreswan $SWAN_VER was installed successfully! " echo } diff --git a/extras/vpnupgrade_centos.sh b/extras/vpnupgrade_centos.sh index f4f607a..f7337ff 100644 --- a/extras/vpnupgrade_centos.sh +++ b/extras/vpnupgrade_centos.sh @@ -11,14 +11,14 @@ # know how you have improved it! # Check https://libreswan.org for the latest version -swan_ver=3.22 +SWAN_VER=3.22 ### DO NOT edit below this line ### export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" exiterr() { echo "Error: $1" >&2; exit 1; } -exiterr2() { echo "Error: 'yum install' failed." >&2; exit 1; } +exiterr2() { exiterr "'yum install' failed."; } vpnupgrade() { @@ -27,23 +27,23 @@ if ! grep -qs -e "release 6" -e "release 7" /etc/redhat-release; then fi if [ -f /proc/user_beancounters ]; then - exiterr "This script does not support OpenVZ VPS." + exiterr "OpenVZ VPS is not supported." fi if [ "$(id -u)" != 0 ]; then exiterr "Script must be run as root. Try 'sudo sh $0'" fi -if [ -z "$swan_ver" ]; then - exiterr "Libreswan version 'swan_ver' not specified." +if [ -z "$SWAN_VER" ]; then + exiterr "Libreswan version 'SWAN_VER' not specified." fi if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -q "Libreswan"; then exiterr "This script requires Libreswan already installed." fi -if /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$swan_ver"; then - echo "You already have Libreswan version $swan_ver installed! " +if /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$SWAN_VER"; then + echo "You already have Libreswan version $SWAN_VER installed! " echo "If you continue, the same version will be re-installed." echo printf "Do you wish to continue anyway? [y/N] " @@ -62,7 +62,7 @@ fi clear cat < Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false @@ -151,9 +149,9 @@ make "-j$((NPROCS+1))" -s base && make -s install-base # Verify the install and clean up cd /opt/src || exiterr "Cannot enter /opt/src." -/bin/rm -rf "/opt/src/libreswan-$swan_ver" -if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$swan_ver"; then - exiterr "Libreswan $swan_ver failed to build." +/bin/rm -rf "/opt/src/libreswan-$SWAN_VER" +if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$SWAN_VER"; then + exiterr "Libreswan $SWAN_VER failed to build." fi # Restore SELinux contexts @@ -164,7 +162,7 @@ restorecon /usr/local/libexec/ipsec -Rv 2>/dev/null # Update ipsec.conf for Libreswan 3.19 and newer IKE_NEW=" ike=3des-sha1,3des-sha2,aes-sha1,aes-sha1;modp1024,aes-sha2,aes-sha2;modp1024,aes256-sha2_512" PHASE2_NEW=" phase2alg=3des-sha1,3des-sha2,aes-sha1,aes-sha2,aes256-sha2_512" -sed -i".old-$(date +%Y-%m-%d-%H:%M:%S)" \ +sed -i".old-$(date +%F-%T)" \ -e "s/^[[:space:]]\+auth=esp\$/ phase2=esp/" \ -e "s/^[[:space:]]\+forceencaps=yes\$/ encapsulation=yes/" \ -e "s/^[[:space:]]\+ike=.\+\$/$IKE_NEW/" \ @@ -174,7 +172,7 @@ sed -i".old-$(date +%Y-%m-%d-%H:%M:%S)" \ service ipsec restart echo -echo "Libreswan $swan_ver was installed successfully! " +echo "Libreswan $SWAN_VER was installed successfully! " echo } diff --git a/vpnsetup.sh b/vpnsetup.sh index 90f21e4..b76df8a 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -22,7 +22,7 @@ # Define your own values for these variables # - IPsec pre-shared key, VPN username and password # - All values MUST be placed inside 'single quotes' -# - DO NOT use these characters within values: \ " ' +# - DO NOT use these special characters within values: \ " ' YOUR_IPSEC_PSK='' YOUR_USERNAME='' @@ -36,13 +36,13 @@ YOUR_PASSWORD='' export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" exiterr() { echo "Error: $1" >&2; exit 1; } -exiterr2() { echo "Error: 'apt-get install' failed." >&2; exit 1; } -conf_bk() { /bin/cp -f "$1" "$1.old-$(date +%Y-%m-%d-%H:%M:%S)" 2>/dev/null; } +exiterr2() { exiterr "'apt-get install' failed."; } +conf_bk() { /bin/cp -f "$1" "$1.old-$(date +%F-%T)" 2>/dev/null; } bigecho() { echo; echo "## $1"; echo; } 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" + printf '%s' "$1" | tr -d '\n' | grep -Eq "$IP_REGEX" } vpnsetup() { @@ -52,18 +52,16 @@ if [ -z "$os_type" ]; then [ -f /etc/os-release ] && os_type="$(. /etc/os-release && echo "$ID")" [ -f /etc/lsb-release ] && os_type="$(. /etc/lsb-release && echo "$DISTRIB_ID")" fi -if ! printf %s "$os_type" | head -n 1 | grep -qiF -e ubuntu -e debian -e raspbian; then - exiterr "This script only supports Ubuntu/Debian." +if ! printf '%s' "$os_type" | head -n 1 | grep -qiF -e ubuntu -e debian -e raspbian; then + exiterr "This script only supports Ubuntu and Debian." fi if [ "$(sed 's/\..*//' /etc/debian_version)" = "7" ]; then - exiterr "This script does not support Debian 7 (Wheezy)." + exiterr "Debian 7 is not supported." fi if [ -f /proc/user_beancounters ]; then - echo "Error: This script does not support OpenVZ VPS." >&2 - echo "Try OpenVPN: https://github.com/Nyr/openvpn-install" >&2 - exit 1 + exiterr "OpenVZ VPS is not supported. Try OpenVPN: github.com/Nyr/openvpn-install" fi if [ "$(id -u)" != 0 ]; then @@ -75,17 +73,11 @@ def_iface="$(route 2>/dev/null | grep '^default' | grep -o '[^ ]*$')" [ -z "$def_iface" ] && def_iface="$(ip -4 route list 0/0 2>/dev/null | grep -Po '(?<=dev )(\S+)')" def_iface_state=$(cat "/sys/class/net/$def_iface/operstate" 2>/dev/null) -if [ -z "$VPN_NET_IFACE" ] && [ -n "$def_iface_state" ] && [ "$def_iface_state" != "down" ]; then +if [ -n "$def_iface_state" ] && [ "$def_iface_state" != "down" ]; then if ! grep -qs raspbian /etc/os-release; then case "$def_iface" in wl*) -cat 1>&2 <> DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC! << -If you are certain that this script is running on a server, re-run it with: - sudo VPN_NET_IFACE="$def_iface" sh "$0" -EOF - exit 1 + exiterr "Wireless interface '$def_iface' detected. DO NOT run this script on your PC or Mac!" ;; esac fi @@ -97,9 +89,8 @@ if [ -z "$net_iface_state" ] || [ "$net_iface_state" = "down" ] || [ "$net_iface printf "Error: Network interface '%s' is not available.\n" "$net_iface" >&2 if [ -z "$VPN_NET_IFACE" ]; then cat 1>&2 </dev/null 2>&1; do [ "$count" -ge "20" ] && exiterr "Cannot get apt/dpkg lock." count=$((count+1)) - printf %s . + printf '%s' '.' sleep 3 done @@ -151,14 +143,14 @@ apt-get -yq update || exiterr "'apt-get update' failed." bigecho "Installing packages required for setup..." -apt-get -yq install wget dnsutils openssl || exiterr2 -apt-get -yq install iproute gawk grep sed net-tools || exiterr2 +apt-get -yq install wget dnsutils openssl \ + iproute gawk grep sed net-tools || exiterr2 bigecho "Trying to auto discover IP of this server..." cat <<'EOF' In case the script hangs here for more than a few minutes, -use Ctrl-C to interrupt. Then edit it and manually enter IP. +press Ctrl-C to abort. Then edit it and manually enter IP. EOF # In case auto IP discovery fails, enter server's public IP here. @@ -169,15 +161,14 @@ PUBLIC_IP=${VPN_PUBLIC_IP:-''} # Check IP for correct format check_ip "$PUBLIC_IP" || PUBLIC_IP=$(wget -t 3 -T 15 -qO- http://ipv4.icanhazip.com) -check_ip "$PUBLIC_IP" || exiterr "Cannot find valid public IP. Edit the script and manually enter it." +check_ip "$PUBLIC_IP" || exiterr "Cannot detect this server's public IP. Edit the script and manually enter it." bigecho "Installing packages required for the VPN..." -apt-get -yq install libnss3-dev libnspr4-dev pkg-config libpam0g-dev \ - libcap-ng-dev libcap-ng-utils libselinux1-dev \ - libcurl4-nss-dev flex bison gcc make \ - libnss3-tools libevent-dev || exiterr2 -apt-get -yq install ppp xl2tpd || exiterr2 +apt-get -yq install libnss3-dev libnspr4-dev pkg-config \ + libpam0g-dev libcap-ng-dev libcap-ng-utils libselinux1-dev \ + libcurl4-nss-dev flex bison gcc make libnss3-tools \ + libevent-dev ppp xl2tpd || exiterr2 bigecho "Installing Fail2Ban to protect SSH..." @@ -185,19 +176,20 @@ apt-get -yq install fail2ban || exiterr2 bigecho "Compiling and installing Libreswan..." -swan_ver=3.22 -if grep -qs raspbian /etc/os-release; then - swan_ver=3.21 +if ! grep -qs raspbian /etc/os-release; then + SWAN_VER=3.22 +else + SWAN_VER=3.21 fi -swan_file="libreswan-$swan_ver.tar.gz" -swan_url1="https://github.com/libreswan/libreswan/archive/v$swan_ver.tar.gz" +swan_file="libreswan-$SWAN_VER.tar.gz" +swan_url1="https://github.com/libreswan/libreswan/archive/v$SWAN_VER.tar.gz" swan_url2="https://download.libreswan.org/$swan_file" if ! { wget -t 3 -T 30 -nv -O "$swan_file" "$swan_url1" || wget -t 3 -T 30 -nv -O "$swan_file" "$swan_url2"; }; then exiterr "Cannot download Libreswan source." fi -/bin/rm -rf "/opt/src/libreswan-$swan_ver" +/bin/rm -rf "/opt/src/libreswan-$SWAN_VER" tar xzf "$swan_file" && /bin/rm -f "$swan_file" -cd "libreswan-$swan_ver" || exiterr "Cannot enter Libreswan source dir." +cd "libreswan-$SWAN_VER" || exiterr "Cannot enter Libreswan source dir." cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false @@ -211,9 +203,9 @@ make "-j$((NPROCS+1))" -s base && make -s install-base # Verify the install and clean up cd /opt/src || exiterr "Cannot enter /opt/src." -/bin/rm -rf "/opt/src/libreswan-$swan_ver" -if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$swan_ver"; then - exiterr "Libreswan $swan_ver failed to build." +/bin/rm -rf "/opt/src/libreswan-$SWAN_VER" +if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$SWAN_VER"; then + exiterr "Libreswan $SWAN_VER failed to build." fi bigecho "Creating VPN configuration..." @@ -329,8 +321,6 @@ EOF # Create VPN credentials conf_bk "/etc/ppp/chap-secrets" cat > /etc/ppp/chap-secrets </dev/null 2>&1 - iptables-save > "$IPT_FILE.old-$(date +%Y-%m-%d-%H:%M:%S)" + iptables-save > "$IPT_FILE.old-$(date +%F-%T)" iptables -I INPUT 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP iptables -I INPUT 2 -m conntrack --ctstate INVALID -j DROP iptables -I INPUT 3 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index bc8405d..1827d07 100755 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -22,7 +22,7 @@ # Define your own values for these variables # - IPsec pre-shared key, VPN username and password # - All values MUST be placed inside 'single quotes' -# - DO NOT use these characters within values: \ " ' +# - DO NOT use these special characters within values: \ " ' YOUR_IPSEC_PSK='' YOUR_USERNAME='' @@ -36,13 +36,13 @@ YOUR_PASSWORD='' export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" exiterr() { echo "Error: $1" >&2; exit 1; } -exiterr2() { echo "Error: 'yum install' failed." >&2; exit 1; } -conf_bk() { /bin/cp -f "$1" "$1.old-$(date +%Y-%m-%d-%H:%M:%S)" 2>/dev/null; } +exiterr2() { exiterr "'yum install' failed."; } +conf_bk() { /bin/cp -f "$1" "$1.old-$(date +%F-%T)" 2>/dev/null; } bigecho() { echo; echo "## $1"; echo; } 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" + printf '%s' "$1" | tr -d '\n' | grep -Eq "$IP_REGEX" } vpnsetup() { @@ -52,9 +52,7 @@ if ! grep -qs -e "release 6" -e "release 7" /etc/redhat-release; then fi if [ -f /proc/user_beancounters ]; then - echo "Error: This script does not support OpenVZ VPS." >&2 - echo "Try OpenVPN: https://github.com/Nyr/openvpn-install" >&2 - exit 1 + exiterr "OpenVZ VPS is not supported. Try OpenVPN: github.com/Nyr/openvpn-install" fi if [ "$(id -u)" != 0 ]; then @@ -66,17 +64,11 @@ def_iface="$(route 2>/dev/null | grep '^default' | grep -o '[^ ]*$')" [ -z "$def_iface" ] && def_iface="$(ip -4 route list 0/0 2>/dev/null | grep -Po '(?<=dev )(\S+)')" def_iface_state=$(cat "/sys/class/net/$def_iface/operstate" 2>/dev/null) -if [ -z "$VPN_NET_IFACE" ] && [ -n "$def_iface_state" ] && [ "$def_iface_state" != "down" ]; then +if [ -n "$def_iface_state" ] && [ "$def_iface_state" != "down" ]; then if ! grep -qs raspbian /etc/os-release; then case "$def_iface" in wl*) -cat 1>&2 <> DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC! << -If you are certain that this script is running on a server, re-run it with: - sudo VPN_NET_IFACE="$def_iface" sh "$0" -EOF - exit 1 + exiterr "Wireless interface '$def_iface' detected. DO NOT run this script on your PC or Mac!" ;; esac fi @@ -88,9 +80,8 @@ if [ -z "$net_iface_state" ] || [ "$net_iface_state" = "down" ] || [ "$net_iface printf "Error: Network interface '%s' is not available.\n" "$net_iface" >&2 if [ -z "$VPN_NET_IFACE" ]; then cat 1>&2 < Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false @@ -195,9 +184,9 @@ make "-j$((NPROCS+1))" -s base && make -s install-base # Verify the install and clean up cd /opt/src || exiterr "Cannot enter /opt/src." -/bin/rm -rf "/opt/src/libreswan-$swan_ver" -if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$swan_ver"; then - exiterr "Libreswan $swan_ver failed to build." +/bin/rm -rf "/opt/src/libreswan-$SWAN_VER" +if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$SWAN_VER"; then + exiterr "Libreswan $SWAN_VER failed to build." fi bigecho "Creating VPN configuration..." @@ -307,8 +296,6 @@ EOF # Create VPN credentials conf_bk "/etc/ppp/chap-secrets" cat > /etc/ppp/chap-secrets </dev/null 2>&1 - iptables-save > "$IPT_FILE.old-$(date +%Y-%m-%d-%H:%M:%S)" + iptables-save > "$IPT_FILE.old-$(date +%F-%T)" iptables -I INPUT 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP iptables -I INPUT 2 -m conntrack --ctstate INVALID -j DROP iptables -I INPUT 3 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT @@ -448,8 +435,7 @@ chmod 600 /etc/ipsec.secrets* /etc/ppp/chap-secrets* /etc/ipsec.d/passwd* # Apply new IPTables rules iptables-restore < "$IPT_FILE" -# Fix xl2tpd on CentOS 7 for providers such as Linode, -# where kernel module "l2tp_ppp" is unavailable +# Fix xl2tpd on CentOS 7, if kernel module "l2tp_ppp" is unavailable if grep -qs "release 7" /etc/redhat-release; then if ! modprobe -q l2tp_ppp; then sed -i '/ExecStartPre/s/^/#/' /usr/lib/systemd/system/xl2tpd.service From 7190577c9999b21c8f0154c9aac4a77345e2f973 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Wed, 1 Nov 2017 22:15:56 -0500 Subject: [PATCH 23/29] Minor clean up --- vpnsetup.sh | 5 +++-- vpnsetup_centos.sh | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/vpnsetup.sh b/vpnsetup.sh index b76df8a..a4eedb8 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -34,10 +34,11 @@ YOUR_PASSWORD='' # ===================================================== export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +SYS_DT="$(date +%F-%T)" exiterr() { echo "Error: $1" >&2; exit 1; } exiterr2() { exiterr "'apt-get install' failed."; } -conf_bk() { /bin/cp -f "$1" "$1.old-$(date +%F-%T)" 2>/dev/null; } +conf_bk() { /bin/cp -f "$1" "$1.old-$SYS_DT" 2>/dev/null; } bigecho() { echo; echo "## $1"; echo; } check_ip() { @@ -382,7 +383,7 @@ fi # Add IPTables rules for VPN if [ "$ipt_flag" = "1" ]; then service fail2ban stop >/dev/null 2>&1 - iptables-save > "$IPT_FILE.old-$(date +%F-%T)" + iptables-save > "$IPT_FILE.old-$SYS_DT" iptables -I INPUT 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP iptables -I INPUT 2 -m conntrack --ctstate INVALID -j DROP iptables -I INPUT 3 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index 1827d07..8cb8401 100755 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -34,10 +34,11 @@ YOUR_PASSWORD='' # ===================================================== export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +SYS_DT="$(date +%F-%T)" exiterr() { echo "Error: $1" >&2; exit 1; } exiterr2() { exiterr "'yum install' failed."; } -conf_bk() { /bin/cp -f "$1" "$1.old-$(date +%F-%T)" 2>/dev/null; } +conf_bk() { /bin/cp -f "$1" "$1.old-$SYS_DT" 2>/dev/null; } bigecho() { echo; echo "## $1"; echo; } check_ip() { @@ -357,7 +358,7 @@ fi # Add IPTables rules for VPN if [ "$ipt_flag" = "1" ]; then service fail2ban stop >/dev/null 2>&1 - iptables-save > "$IPT_FILE.old-$(date +%F-%T)" + iptables-save > "$IPT_FILE.old-$SYS_DT" iptables -I INPUT 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP iptables -I INPUT 2 -m conntrack --ctstate INVALID -j DROP iptables -I INPUT 3 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT @@ -438,7 +439,7 @@ iptables-restore < "$IPT_FILE" # Fix xl2tpd on CentOS 7, if kernel module "l2tp_ppp" is unavailable if grep -qs "release 7" /etc/redhat-release; then if ! modprobe -q l2tp_ppp; then - sed -i '/ExecStartPre/s/^/#/' /usr/lib/systemd/system/xl2tpd.service + sed -i '/^ExecStartPre/s/^/#/' /usr/lib/systemd/system/xl2tpd.service systemctl daemon-reload fi fi From 2dfa587a7193d265bbdb86360ab8951521d25572 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Sun, 12 Nov 2017 23:51:53 -0600 Subject: [PATCH 24/29] Fix Libreswan 3.22 bug - This bug causes Libreswan 3.22 fail to start on a Raspberry Pi - Apply fix from Libreswan GitHub repo: libreswan/libreswan@e154ae7 - Ref: https://lists.libreswan.org/pipermail/swan/2017/002338.html --- extras/vpnupgrade.sh | 1 + extras/vpnupgrade_centos.sh | 1 + vpnsetup.sh | 1 + vpnsetup_centos.sh | 1 + 4 files changed, 4 insertions(+) diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index 1a4616d..88f0d0e 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -161,6 +161,7 @@ fi /bin/rm -rf "/opt/src/libreswan-$SWAN_VER" tar xzf "$swan_file" && /bin/rm -f "$swan_file" cd "libreswan-$SWAN_VER" || exiterr "Cannot enter Libreswan source dir." +sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false diff --git a/extras/vpnupgrade_centos.sh b/extras/vpnupgrade_centos.sh index f7337ff..ee2ad84 100644 --- a/extras/vpnupgrade_centos.sh +++ b/extras/vpnupgrade_centos.sh @@ -139,6 +139,7 @@ fi /bin/rm -rf "/opt/src/libreswan-$SWAN_VER" tar xzf "$swan_file" && /bin/rm -f "$swan_file" cd "libreswan-$SWAN_VER" || exiterr "Cannot enter Libreswan source dir." +sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false diff --git a/vpnsetup.sh b/vpnsetup.sh index a4eedb8..30cd001 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -191,6 +191,7 @@ fi /bin/rm -rf "/opt/src/libreswan-$SWAN_VER" tar xzf "$swan_file" && /bin/rm -f "$swan_file" cd "libreswan-$SWAN_VER" || exiterr "Cannot enter Libreswan source dir." +sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index 8cb8401..8c6513b 100755 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -175,6 +175,7 @@ fi /bin/rm -rf "/opt/src/libreswan-$SWAN_VER" tar xzf "$swan_file" && /bin/rm -f "$swan_file" cd "libreswan-$SWAN_VER" || exiterr "Cannot enter Libreswan source dir." +sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false From 8b40709d4da7d1565486960e17fb264c3e3769e8 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Mon, 13 Nov 2017 00:12:16 -0600 Subject: [PATCH 25/29] Improve VPN ciphers - Remove unsupported ESP algorithm on Raspbian --- extras/vpnupgrade.sh | 3 +++ vpnsetup.sh | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index 88f0d0e..83569e2 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -183,6 +183,9 @@ fi # Update ipsec.conf for Libreswan 3.19 and newer IKE_NEW=" ike=3des-sha1,3des-sha2,aes-sha1,aes-sha1;modp1024,aes-sha2,aes-sha2;modp1024,aes256-sha2_512" PHASE2_NEW=" phase2alg=3des-sha1,3des-sha2,aes-sha1,aes-sha2,aes256-sha2_512" +if grep -qs raspbian /etc/os-release; then + PHASE2_NEW=" phase2alg=3des-sha1,3des-sha2,aes-sha1,aes-sha2" +fi sed -i".old-$(date +%F-%T)" \ -e "s/^[[:space:]]\+auth=esp\$/ phase2=esp/" \ -e "s/^[[:space:]]\+forceencaps=yes\$/ encapsulation=yes/" \ diff --git a/vpnsetup.sh b/vpnsetup.sh index 30cd001..22b22c9 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -279,6 +279,11 @@ if grep -qs 'Raspbian GNU/Linux 9' /etc/os-release; then check_ip "$PRIVATE_IP" && sed -i "s/left=%defaultroute/left=$PRIVATE_IP/" /etc/ipsec.conf fi +# Remove unsupported ESP algorithm on Raspbian +if grep -qs raspbian /etc/os-release; then + sed -i '/phase2alg/s/,aes256-sha2_512//' /etc/ipsec.conf +fi + # Specify IPsec PSK conf_bk "/etc/ipsec.secrets" cat > /etc/ipsec.secrets < Date: Mon, 13 Nov 2017 00:17:38 -0600 Subject: [PATCH 26/29] Remove RPi workaround - No longer needed with fix 2dfa587 and 8b40709 - Ref: 1488ac0 --- extras/vpnupgrade.sh | 20 -------------------- vpnsetup.sh | 6 +----- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index 83569e2..b8fdb8e 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -51,26 +51,6 @@ if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -q "Libreswan"; then exiterr "This script requires Libreswan already installed." fi -if [ "$SWAN_VER" = "3.22" ]; then - if grep -qs raspbian /etc/os-release; then - echo "Note: For Raspberry Pi systems, this script will install Libreswan" - echo "version 3.21 instead of 3.22, to avoid some recent bugs." - echo - printf "Do you wish to continue? [y/N] " - read -r response - case $response in - [yY][eE][sS]|[yY]) - echo - SWAN_VER=3.21 - ;; - *) - echo "Aborting." - exit 1 - ;; - esac - fi -fi - if /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$SWAN_VER"; then echo "You already have Libreswan version $SWAN_VER installed! " echo "If you continue, the same version will be re-installed." diff --git a/vpnsetup.sh b/vpnsetup.sh index 22b22c9..3954085 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -177,11 +177,7 @@ apt-get -yq install fail2ban || exiterr2 bigecho "Compiling and installing Libreswan..." -if ! grep -qs raspbian /etc/os-release; then - SWAN_VER=3.22 -else - SWAN_VER=3.21 -fi +SWAN_VER=3.22 swan_file="libreswan-$SWAN_VER.tar.gz" swan_url1="https://github.com/libreswan/libreswan/archive/v$SWAN_VER.tar.gz" swan_url2="https://download.libreswan.org/$swan_file" From 3f39255f841e2ee612bffba9633b3d71b7729626 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Mon, 20 Nov 2017 00:33:36 -0600 Subject: [PATCH 27/29] Bug fix for RHEL 6/7 - Fix compatibility with Red Hat Enterprise Linux (RHEL) 6 and 7 - Ref: #273 --- extras/vpnupgrade_centos.sh | 12 ++++++++---- vpnsetup_centos.sh | 13 ++++++++----- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/extras/vpnupgrade_centos.sh b/extras/vpnupgrade_centos.sh index ee2ad84..76692d0 100644 --- a/extras/vpnupgrade_centos.sh +++ b/extras/vpnupgrade_centos.sh @@ -115,18 +115,22 @@ cd /opt/src || exiterr "Cannot enter /opt/src." yum -y install wget || exiterr2 # Add the EPEL repository -yum -y install epel-release || exiterr2 +epel_url="https://dl.fedoraproject.org/pub/epel/epel-release-latest-$(rpm -E '%{rhel}').noarch.rpm" +yum -y install epel-release || yum -y install "$epel_url" || exiterr2 # Install necessary packages yum -y install nss-devel nspr-devel pkgconfig pam-devel \ libcap-ng-devel libselinux-devel curl-devel \ - flex bison gcc make fipscheck-devel || exiterr2 + flex bison gcc make || exiterr2 +OPT1='--enablerepo=*server-optional*' +OPT2='--enablerepo=*releases-optional*' if grep -qs "release 6" /etc/redhat-release; then yum -y remove libevent-devel - yum -y install libevent2-devel || exiterr2 + yum "$OPT1" "$OPT2" -y install libevent2-devel fipscheck-devel || exiterr2 else - yum -y install libevent-devel systemd-devel || exiterr2 + yum -y install systemd-devel || exiterr2 + yum "$OPT1" "$OPT2" -y install libevent-devel fipscheck-devel || exiterr2 fi # Compile and install Libreswan diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index 8c6513b..405fc09 100755 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -143,20 +143,23 @@ check_ip "$PUBLIC_IP" || exiterr "Cannot detect this server's public IP. Edit th bigecho "Adding the EPEL repository..." -yum -y install epel-release || exiterr2 +epel_url="https://dl.fedoraproject.org/pub/epel/epel-release-latest-$(rpm -E '%{rhel}').noarch.rpm" +yum -y install epel-release || yum -y install "$epel_url" || exiterr2 bigecho "Installing packages required for the VPN..." yum -y install nss-devel nspr-devel pkgconfig pam-devel \ libcap-ng-devel libselinux-devel curl-devel \ - flex bison gcc make fipscheck-devel \ - ppp xl2tpd || exiterr2 + flex bison gcc make ppp xl2tpd || exiterr2 +OPT1='--enablerepo=*server-optional*' +OPT2='--enablerepo=*releases-optional*' if grep -qs "release 6" /etc/redhat-release; then yum -y remove libevent-devel - yum -y install libevent2-devel || exiterr2 + yum "$OPT1" "$OPT2" -y install libevent2-devel fipscheck-devel || exiterr2 else - yum -y install libevent-devel systemd-devel iptables-services || exiterr2 + yum -y install systemd-devel iptables-services || exiterr2 + yum "$OPT1" "$OPT2" -y install libevent-devel fipscheck-devel || exiterr2 fi bigecho "Installing Fail2Ban to protect SSH..." From cc64a29c016c6937bb7d7d8b031c702c33636821 Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Wed, 6 Dec 2017 04:36:33 -0600 Subject: [PATCH 28/29] Re-add RPi workaround - Libreswan 3.22 may fail to compile on Raspberry Pi w/ Raspbian 9 - Use version 3.21 instead of 3.22 for Raspbian systems - Ref: d472c65 --- extras/vpnupgrade.sh | 22 +++++++++++++++++++++- extras/vpnupgrade_centos.sh | 2 +- vpnsetup.sh | 8 ++++++-- vpnsetup_centos.sh | 2 +- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/extras/vpnupgrade.sh b/extras/vpnupgrade.sh index b8fdb8e..27f2b88 100644 --- a/extras/vpnupgrade.sh +++ b/extras/vpnupgrade.sh @@ -51,6 +51,26 @@ if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -q "Libreswan"; then exiterr "This script requires Libreswan already installed." fi +if [ "$SWAN_VER" = "3.22" ]; then + if grep -qs raspbian /etc/os-release; then + echo "Note: For Raspberry Pi systems, this script will install Libreswan" + echo "version 3.21 instead of 3.22, to avoid some recent bugs." + echo + printf "Do you wish to continue? [y/N] " + read -r response + case $response in + [yY][eE][sS]|[yY]) + echo + SWAN_VER=3.21 + ;; + *) + echo "Aborting." + exit 1 + ;; + esac + fi +fi + if /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$SWAN_VER"; then echo "You already have Libreswan version $SWAN_VER installed! " echo "If you continue, the same version will be re-installed." @@ -141,7 +161,7 @@ fi /bin/rm -rf "/opt/src/libreswan-$SWAN_VER" tar xzf "$swan_file" && /bin/rm -f "$swan_file" cd "libreswan-$SWAN_VER" || exiterr "Cannot enter Libreswan source dir." -sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h +[ "$SWAN_VER" = "3.22" ] && sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false diff --git a/extras/vpnupgrade_centos.sh b/extras/vpnupgrade_centos.sh index 76692d0..1e44f5b 100644 --- a/extras/vpnupgrade_centos.sh +++ b/extras/vpnupgrade_centos.sh @@ -143,7 +143,7 @@ fi /bin/rm -rf "/opt/src/libreswan-$SWAN_VER" tar xzf "$swan_file" && /bin/rm -f "$swan_file" cd "libreswan-$SWAN_VER" || exiterr "Cannot enter Libreswan source dir." -sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h +[ "$SWAN_VER" = "3.22" ] && sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false diff --git a/vpnsetup.sh b/vpnsetup.sh index 3954085..a8527e6 100755 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -177,7 +177,11 @@ apt-get -yq install fail2ban || exiterr2 bigecho "Compiling and installing Libreswan..." -SWAN_VER=3.22 +if ! grep -qs raspbian /etc/os-release; then + SWAN_VER=3.22 +else + SWAN_VER=3.21 +fi swan_file="libreswan-$SWAN_VER.tar.gz" swan_url1="https://github.com/libreswan/libreswan/archive/v$SWAN_VER.tar.gz" swan_url2="https://download.libreswan.org/$swan_file" @@ -187,7 +191,7 @@ fi /bin/rm -rf "/opt/src/libreswan-$SWAN_VER" tar xzf "$swan_file" && /bin/rm -f "$swan_file" cd "libreswan-$SWAN_VER" || exiterr "Cannot enter Libreswan source dir." -sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h +[ "$SWAN_VER" = "3.22" ] && sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index 405fc09..0c8121a 100755 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -178,7 +178,7 @@ fi /bin/rm -rf "/opt/src/libreswan-$SWAN_VER" tar xzf "$swan_file" && /bin/rm -f "$swan_file" cd "libreswan-$SWAN_VER" || exiterr "Cannot enter Libreswan source dir." -sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h +[ "$SWAN_VER" = "3.22" ] && sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h cat > Makefile.inc.local <<'EOF' WERROR_CFLAGS = USE_DNSSEC = false From 076406b80c888dfc6b4ec5105095ba1a2c6d934e Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Wed, 20 Dec 2017 01:22:09 -0600 Subject: [PATCH 29/29] Fix tests - Add workaround for Travis CI build issues --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e4b7961..8e4ea96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: bash sudo: required dist: trusty +group: deprecated-2017Q4 addons: apt: