Skip to content

Instantly share code, notes, and snippets.

@sahal
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sahal/77810e0af65594a2a26e to your computer and use it in GitHub Desktop.
Save sahal/77810e0af65594a2a26e to your computer and use it in GitHub Desktop.
IPSec/L2TP VPN on Debian Wheezy, CentOS/RHEL - no compilation, no need to configure users (outside OS)
#!/bin/bash
# Installing an L2TP/IPSec VPN on Debian Wheezy, CentOS, RHEL
# see: http://blog.sahal.info/post/103242887966/ipsec-l2tp-vpn-on-debian
#
# adapted from: https://gist.github.com/hwdsl2/9030462 # need to compile libreswan :(
# adapted from: https://raymii.org/s/tutorials/IPSEC_L2TP_vpn_with_Ubuntu_14.04.html # installs Openswan (unmaintained) :(
#
# Copyright (c) 2014 Sahal Ansari - github@sahal.info
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
DIR="$( cd "$( dirname "$0" )" && pwd )"
backup_dir="$DIR""/backup-configs_""$(date +%s)"
main_interface="eth0"
# You might want to set these manually
PUBLIC_IP="$(ip -o addr | grep "$main_interface" | grep inet\ | sed -e s/^.*inet\ // -e s@/.*@@)"
PRIVATE_IP="$PUBLIC_IP"
# disable update check 1=True/Yes, 0=False/No
DISABLE_UPDATE_CHECK="0"
### DIE FUNCTION
function die { #$1 = message
echo "$1"
exit 1
}
### PRINT HELP
function do_help {
cat <<EOF
Usage: ${0##*/:-} [OPTION...]
Install and configure IPSec/L2TP VPN on Debian Wheezy, CentOS/RHEL
help - print this help
install - install packages
backups - backup (default|current) configuration
config - update configuration
restart - restart daemons
print - print configuration
wrapper - run all at once (only if each exists successfully)
EOF
}
### BASIC CHECKS
# are you root?
if [ "$(id -u)" -ne "0" ]; then
do_help
die "Oops, you're not root!"
fi
# determine distribution
# todo: ubuntu, fedora (?) support
if [ -f "/etc/debian_version" ]; then
grep ^7 /etc/debian_version &> /dev/null
if [ "$?" -ne "0" ]; then
die "This script currently only supports Debian Wheezy, sorry."
fi
if [ "$(arch)" != "x86_64" ]; then
die "This script currently only supports Debian Wheezy (64bit), sorry."
fi
DISTRO="0"
elif [ -f "/etc/redhat-release" ]; then
DISTRO="1"
else
die "Your distribution is currently unsupported by this script, sorry."
fi
# check if $main_interface exists
ip link show "$main_interface" &> /dev/null
if [ "$?" -ne "0" ]; then
echo "OOps, ""$main_interface"" isn't an interface?"
die "Please set \$main_interface to an existing interface on this system."
fi
function do_check_update {
if [ "$DISTRO" -eq "0" ]; then
echo "You're running Debian. I will now try to run apt-get update."
apt-get update && apt-get upgrade
elif [ "$DISTRO" -eq "1" ]; then
yum check-update
if [ "$?" -ne "0" ]; then
die "Update your system (i.e. yum update) before running. To disable this see var \$DISABLE_UPDATE_CHECK in script."
fi
fi
}
function do_install {
if [ "$DISABLE_UPDATE_CHECK" -eq "0" ]; then
do_check_update
fi
if [ "$DISTRO" -eq "0" ]; then
echo "Installing xl2tpd, haveged, and ppp."
apt-get install haveged xl2tpd ppp
echo "Installing libreswan dependencies."
apt-get install libldns1 libgmp10 libnspr4 libnspr4-0d libnss3 libnss3-1d libunbound2 libnspr4 libnss3 libnss3-tools
echo "Installing libreswan."
# check the integrity of the package - there is nothing to check against on download.libreswan.org
# trust in their SSL certificate!
wget --no-clobber https://download.libreswan.org/binaries/debian/wheezy/libreswan_3.12~3-gdd6f200-deb_amd64.deb
dpkg -i --force-depends libreswan_3.12~3-gdd6f200-deb_amd64.deb
if [ "$?" -ne "0" ]; then
die "libreswan install failed."
fi
elif [ "$DISTRO" -eq "1" ]; then
yum -v repolist | grep epel &> /dev/null
if [ "$?" -ne "0" ]; then
echo "Adding epel repository."
# (red hat) enterprise linux release number
el_release="$(sed -e 's/^.*\ release\ //' -e 's/\ .*$//' -e 's/\..*//' /etc/redhat-release)"
# check architecture
proc_arch="$(uname -p)"
if [ "$el_release" == "6" ]; then
if [ "$proc_arch" == "i386" ]; then
rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
elif [ "$proc_arch" == "ppc64" ]; then
rpm -Uvh http://download.fedoraproject.org/pub/epel/6/ppc64/epel-release-6-8.noarch.rpm
elif [ "$proc_arch" == "x86_64" ]; then
rpm -Uvh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
else
die "Your architecture is not supported by epel."
fi
elif [ "$el_release" == "7" ]; then
if [ "$proc_arch" == "x86_64" ]; then
rpm -Uvh http://download.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-2.noarch.rpm
elif [ "$proc_arch" == "ppc64" ]; then
rpm -Uvh http://download.fedoraproject.org/pub/epel/7/ppc64/e/epel-release-7-2.noarch.rpm
else
die "Your architecture is not supported by epel."
fi
else
die "Your version of enterprise linux is not supported by epel and/or libreswan packages are out of date in epel."
fi
if [ "$?" -ne "0" ]; then
die "Couldn't add epel repo."
fi
fi
echo "Installing haveged, ppp, xl2tpd, and libreswan."
yum clean all
yum install xl2tpd haveged libreswan ppp
if [ "$?" -ne "0" ]; then
die "Install of xl2tpd, haveged, libreswan, and/or ppp failed."
fi
chkconfig ipsec on
chkconfig xl2tpd on
chkconfig haveged on
echo "Starting haveged."
service haveged start
fi
}
function copythatf {
if [ -f "$1" ]; then
cp "$1" "$backup_dir"/"$(basename "$1")"
fi
}
function do_backups {
echo "Creating backup directory."
mkdir -p "$backup_dir"
if [ "$?" -ne "0" ]; then
die "Creating ""$backup_dir"" failed."
fi
echo "Creating backups of configuration files."
copythatf "/etc/sysctl.conf"
copythatf "/etc/rc.local"
copythatf "/etc/ipsec.conf"
copythatf "/etc/ipsec.secrets"
copythatf "/etc/xl2tpd/xl2tpd.conf"
copythatf "/etc/ppp/options.xl2tpd"
copythatf "/etc/pam.d/ppp"
copythatf "/etc/ppp/pap-secrets"
}
### CONFIGURATION
function do_configuration {
echo "Updating iptables."
iptables --table nat --append POSTROUTING --jump MASQUERADE
if [ "$DISTRO" -eq "1" ]; then
echo "Saving iptables."
service iptables save
fi
echo "Updating sysctl.conf"
cat > /etc/sysctl.conf <<EOF
kernel.sysrq = 0
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.ip_forward = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
kernel.randomize_va_space = 1
net.core.wmem_max=12582912
net.core.rmem_max=12582912
net.ipv4.tcp_rmem= 10240 87380 12582912
net.ipv4.tcp_wmem= 10240 87380 12582912
EOF
sysctl -p &> /dev/null
# accept_redirects/ send_redirects configuration for your interfaces
for interface in /proc/sys/net/ipv4/conf/*; do echo 0 > $interface/accept_redirects; echo 0 > $interface/send_redirects; done
echo "Updating rc.local"
# todo: this could be dangerous if the user has a complex rc.local, fix it!
grep -v "^exit\ 0" < /etc/rc.local > /etc/rc.local.new
echo "for interface in /proc/sys/net/ipv4/conf/*; do echo 0 > \$interface/accept_redirects; echo 0 > \$interface/send_redirects; done" >> /etc/rc.local.new
echo "iptables --table nat --append POSTROUTING --jump MASQUERADE" >> /etc/rc.local.new
echo "exit 0" >> /etc/rc.local.new
mv /etc/rc.local.new /etc/rc.local
echo "Updating ipsec.conf."
cat > /etc/ipsec.conf <<EOF
version 2.0
config setup
dumpdir=/var/run/pluto/
nat_traversal=yes
virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!192.168.42.0/24
oe=off
protostack=netkey
nhelpers=0
interfaces=%defaultroute
conn vpnpsk
connaddrfamily=ipv4
auto=add
left=$PRIVATE_IP
leftid=$PUBLIC_IP
leftsubnet=$PRIVATE_IP/32
leftnexthop=%defaultroute
leftprotoport=17/1701
rightprotoport=17/%any
right=%any
rightsubnetwithin=0.0.0.0/0
forceencaps=yes
authby=secret
pfs=no
type=transport
auth=esp
ike=3des-sha1,aes-sha1
phase2alg=3des-sha1,aes-sha1
rekey=no
keyingtries=5
dpddelay=30
dpdtimeout=120
dpdaction=clear
EOF
echo "Updating ipsec.secrets."
pre_shared_key="$(hexdump -n 32 -v -e '/1 "%02X"' /dev/random)"
echo "$PUBLIC_IP"" %any: PSK \"$pre_shared_key\"" > /etc/ipsec.secrets
echo "Updating xl2tpd.conf."
cat > /etc/xl2tpd/xl2tpd.conf <<EOF
[global]
; ipsec saref = yes
; saref refinfo = 30
; debug avp = yes
; debug network = yes
; debug state = yes
; debug tunnel = yes
[lns default]
ip range = 172.16.1.30-172.16.1.100
local ip = 172.16.1.1
require authentication = yes
unix authentication = yes
; ppp debug = yes
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes
EOF
echo "Updating options.xl2tpd."
cat > /etc/ppp/options.xl2tpd <<EOF
ipcp-accept-local
ipcp-accept-remote
ms-dns 8.8.8.8
ms-dns 8.8.4.4
auth
crtscts
idle 1800
mtu 1280
mru 1280
lock
lcp-echo-failure 10
lcp-echo-interval 60
connect-delay 5000
name l2tpd
login
EOF
echo "Updating ppp."
cat > /etc/pam.d/ppp <<EOF
auth required pam_nologin.so
auth required pam_unix.so
account required pam_unix.so
session required pam_unix.so
EOF
echo "Updating pap-secrets."
echo "* l2tpd \"\" *" >> /etc/ppp/pap-secrets
}
### RESTART DAEMONS
function do_restart {
echo "Restarting libreswan and xl2tpd."
if [ "$DISTRO" -eq "0" ]; then
/etc/init.d/ipsec restart
/etc/init.d/xl2tpd restart
elif [ "$DISTRO" -eq "1" ]; then
service ipsec restart
service xl2tpd restart
fi
}
### PRINT CONFIGURATION
function do_print {
echo "IP Address: ""$PRIVATE_IP"
echo
echo "PRE SHARED KEY: ""$(sed -e s/^.*\ \"// -e s/\"// < /etc/ipsec.secrets)"
echo
echo "User/Password: All users on system."
echo " to see users: /etc/passwd"
echo " to add users on Debian: \`man adduser\`"
echo " to add users on RHEL/CentOS: \`man useradd\`"
}
case "$1" in
install)
do_install
;;
backup|backups)
do_backups
;;
config)
do_configuration
;;
restart)
do_restart
;;
print)
do_print
;;
wrapper)
do_install && do_backups && do_configuration && do_restart && do_print
;;
*|help)
do_help
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment