L2tp搭建

使用脚本

wget --no-check-certificate https://raw.githubusercontent.com/teddysun/across/master/l2tp.sh
赋权限然后安装
chmod 700 l2tp.sh
./l2tp.sh

会有以下交互式界面

###############################################################
# L2TP VPN Auto Installer                                     #
# System Supported: CentOS 6+ / Debian 7+ / Ubuntu 12+        #
# Intro: https://teddysun.com/448.html                        #
# Author: Teddysun <i@teddysun.com>                           #
###############################################################

########## System Information ##########

CPU model            : Intel(R) Xeon(R) CPU E5-26xx v3
Number of cores      : 1
CPU frequency        : 2299.998 MHz
Total amount of ram  : 996 MB
Total amount of swap : 0 MB
System uptime        : 0days, 0:9:12
Load average         : 0.00, 0.00, 0.00
OS                   : CentOS 6.8
Arch                 : x86_64 (64 Bit)
Kernel               : 2.6.32-642.6.2.el6.x86_64
Hostname             : VM_105_26_centos
IPv4 address         : 118.89.107.217

########################################


Please enter IP-Range:
(Default Range: 192.168.18):

Please input IP-Range:
(Default Range: 192.168.18):
输入本地IP段范围(本地电脑连接到VPS后给分配的一个本地IP地址),直接回车意味着输入默认值192.168.18

Please input PSK:
(Default PSK: teddysun.com):
PSK意为预共享密钥,即指定一个密钥将来在连接时需要用到,直接回车意味着输入默认值teddysun.com

Please input Username:
(Default Username: teddysun):
Username意为用户名,即第一个默认用户。直接回车意味着输入默认值teddysun

Please input teddysun’s password:
(Default Password: Q4SKhu2EXQ):
输入用户的密码,默认会随机生成一个10位包含大小写字母和数字的密码,当然你也可以指定密码。

ServerIP:your_server_main_IP
显示你的 VPS 的主 IP(如果是多 IP 的 VPS 也只显示一个)

Server Local IP:192.168.18.1
显示你的 VPS 的本地 IP(默认即可)

Client Remote IP Range:192.168.18.2-192.168.18.254
显示 IP 段范围

PSK:teddysun.com
显示 PSK

Press any key to start…or Press Ctrl+c to cancel
按下任意按键继续,如果想取消安装,请按Ctrl+c键

安装完成后会给出所有的安装信息和使用方式

l2tp -a 新增用户
l2tp -d 删除用户
l2tp -m 修改现有的用户的密码
l2tp -l 列出所有用户名和密码
l2tp -h 列出帮助信息

其他事项:
1、脚本在安装完成后,已自动启动进程,并加入了开机自启动。
2、脚本会改写 iptables 或 firewalld 的规则。
3、脚本安装时,会即时将安装日志写到 /root/l2tp.log 文件里,如果你安装失败,可以通过此文件来寻找错误信息。

使用命令:
ipsec status (查看 IPSec 运行状态)
ipsec verify (查看 IPSec 检查结果)
/etc/init.d/ipsec start|stop|restart|status (CentOS6 下使用)
/etc/init.d/xl2tpd start|stop|restart (CentOS6 下使用)
systemctl start|stop|restart|status ipsec (CentOS7 下使用)
systemctl start|stop|restart xl2tpd (CentOS7 下使用)
service ipsec start|stop|restart|status (Debian/Ubuntu 下使用)
service xl2tpd start|stop|restart (Debian/Ubuntu 下使用)

脚本代码如下

#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
#=======================================================================#
#   System Supported:  CentOS 6+ / Debian 7+ / Ubuntu 12+               #
#   Description: L2TP VPN Auto Installer                                #
#   Author: Teddysun <i@teddysun.com>                                   #
#   Intro:  https://teddysun.com/448.html                               #
#=======================================================================#
cur_dir=`pwd`

libreswan_filename="libreswan-3.20"

rootness(){
    if [[ $EUID -ne 0 ]]; then
       echo "Error:This script must be run as root!" 1>&2
       exit 1
    fi
}

tunavailable(){
    if [[ ! -e /dev/net/tun ]]; then
        echo "Error:TUN/TAP is not available!" 1>&2
        exit 1
    fi
}

disable_selinux(){
if [ -s /etc/selinux/config ] && grep 'SELINUX=enforcing' /etc/selinux/config; then
    sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
    setenforce 0
fi
}

get_opsy(){
    [ -f /etc/redhat-release ] && awk '{print ($1,$3~/^[0-9]/?$3:$4)}' /etc/redhat-release && return
    [ -f /etc/os-release ] && awk -F'[= "]' '/PRETTY_NAME/{print $3,$4,$5}' /etc/os-release && return
    [ -f /etc/lsb-release ] && awk -F'[="]+' '/DESCRIPTION/{print $2}' /etc/lsb-release && return
}

get_os_info(){
    IP=$( ip addr | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | egrep -v "^192\.168|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-2]\.|^10\.|^127\.|^255\.|^0\." | head -n 1 )
    [ -z ${IP} ] && IP=$( wget -qO- -t1 -T2 ipv4.icanhazip.com )

    local cname=$( awk -F: '/model name/ {name=$2} END {print name}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//' )
    local cores=$( awk -F: '/model name/ {core++} END {print core}' /proc/cpuinfo )
    local freq=$( awk -F: '/cpu MHz/ {freq=$2} END {print freq}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//' )
    local tram=$( free -m | awk '/Mem/ {print $2}' )
    local swap=$( free -m | awk '/Swap/ {print $2}' )
    local up=$( awk '{a=$1/86400;b=($1%86400)/3600;c=($1%3600)/60;d=$1%60} {printf("%ddays, %d:%d:%d\n",a,b,c,d)}' /proc/uptime )
    local load=$( w | head -1 | awk -F'load average:' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//' )
    local opsy=$( get_opsy )
    local arch=$( uname -m )
    local lbit=$( getconf LONG_BIT )
    local host=$( hostname )
    local kern=$( uname -r )

    echo "########## System Information ##########"
    echo 
    echo "CPU model            : ${cname}"
    echo "Number of cores      : ${cores}"
    echo "CPU frequency        : ${freq} MHz"
    echo "Total amount of ram  : ${tram} MB"
    echo "Total amount of swap : ${swap} MB"
    echo "System uptime        : ${up}"
    echo "Load average         : ${load}"
    echo "OS                   : ${opsy}"
    echo "Arch                 : ${arch} (${lbit} Bit)"
    echo "Kernel               : ${kern}"
    echo "Hostname             : ${host}"
    echo "IPv4 address         : ${IP}"
    echo 
    echo "########################################"
}

check_sys(){
    local checkType=$1
    local value=$2

    local release=''
    local systemPackage=''

    if [[ -f /etc/redhat-release ]]; then
        release="centos"
        systemPackage="yum"
    elif cat /etc/issue | grep -Eqi "debian"; then
        release="debian"
        systemPackage="apt"
    elif cat /etc/issue | grep -Eqi "ubuntu"; then
        release="ubuntu"
        systemPackage="apt"
    elif cat /etc/issue | grep -Eqi "centos|red hat|redhat"; then
        release="centos"
        systemPackage="yum"
    elif cat /proc/version | grep -Eqi "debian"; then
        release="debian"
        systemPackage="apt"
    elif cat /proc/version | grep -Eqi "ubuntu"; then
        release="ubuntu"
        systemPackage="apt"
    elif cat /proc/version | grep -Eqi "centos|red hat|redhat"; then
        release="centos"
        systemPackage="yum"
    fi

    if [[ ${checkType} == "sysRelease" ]]; then
        if [ "$value" == "$release" ];then
            return 0
        else
            return 1
        fi
    elif [[ ${checkType} == "packageManager" ]]; then
        if [ "$value" == "$systemPackage" ];then
            return 0
        else
            return 1
        fi
    fi
}

rand(){
    index=0
    str=""
    for i in {a..z}; do arr[index]=${i}; index=`expr ${index} + 1`; done
    for i in {A..Z}; do arr[index]=${i}; index=`expr ${index} + 1`; done
    for i in {0..9}; do arr[index]=${i}; index=`expr ${index} + 1`; done
    for i in {1..10}; do str="$str${arr[$RANDOM%$index]}"; done
    echo ${str}
}

is_64bit(){
    if [ `getconf WORD_BIT` = '32' ] && [ `getconf LONG_BIT` = '64' ] ; then
        return 0
    else
        return 1
    fi
}

download_file(){
    local download_root_url="http://dl.teddysun.com/files"

    if [ -s ${1} ]; then
        echo "$1 [found]"
    else
        echo "$1 not found!!!download now..."
        if ! wget -c -t3 -T60 ${download_root_url}/${1}; then
            echo "Failed to download $1, please download it to ${cur_dir} directory manually and try again."
            exit 1
        fi
    fi
}

versionget(){
    if [[ -s /etc/redhat-release ]];then
        grep -oE  "[0-9.]+" /etc/redhat-release
    else
        grep -oE  "[0-9.]+" /etc/issue
    fi
}

centosversion(){
    if check_sys sysRelease centos;then
        local code=${1}
        local version="`versionget`"
        local main_ver=${version%%.*}
        if [ "${main_ver}" == "${code}" ];then
            return 0
        else
            return 1
        fi
    else
        return 1
    fi
}

debianversion(){
    if check_sys sysRelease debian;then
        local version=$( get_opsy )
        local code=${1}
        local main_ver=$( echo ${version} | sed 's/[^0-9]//g')
        if [ "${main_ver}" == "${code}" ];then
            return 0
        else
            return 1
        fi
    else
        return 1
    fi
}

version_check(){
    if check_sys packageManager yum; then
        if centosversion 5; then
            echo "Error: CentOS 5 is not supported, Please re-install OS and try again."
            exit 1
        fi
    fi
}

get_char(){
    SAVEDSTTY=`stty -g`
    stty -echo
    stty cbreak
    dd if=/dev/tty bs=1 count=1 2> /dev/null
    stty -raw
    stty echo
    stty $SAVEDSTTY
}

preinstall_l2tp(){

    echo
    if [ -d "/proc/vz" ]; then
        echo -e "\033[41;37m WARNING: \033[0m Your VPS is based on OpenVZ, and IPSec might not be supported by the kernel."
        echo "Continue installation? (y/n)"
        read -p "(Default: n)" agree
        [ -z ${agree} ] && agree="n"
        if [ "${agree}" == "n" ]; then
            echo
            echo "L2TP installation cancelled."
            echo
            exit 0
        fi
    fi
    echo
    echo "Please enter IP-Range:"
    read -p "(Default Range: 192.168.18):" iprange
    [ -z ${iprange} ] && iprange="192.168.18"

    echo "Please enter PSK:"
    read -p "(Default PSK: teddysun.com):" mypsk
    [ -z ${mypsk} ] && mypsk="teddysun.com"

    echo "Please enter Username:"
    read -p "(Default Username: teddysun):" username
    [ -z ${username} ] && username="teddysun"

    password=`rand`
    echo "Please enter ${username}'s password:"
    read -p "(Default Password: ${password}):" tmppassword
    [ ! -z ${tmppassword} ] && password=${tmppassword}

    echo
    echo "ServerIP:${IP}"
    echo "Server Local IP:${iprange}.1"
    echo "Client Remote IP Range:${iprange}.2-${iprange}.254"
    echo "PSK:${mypsk}"
    echo
    echo "Press any key to start... or press Ctrl + C to cancel."
    char=`get_char`

}

install_l2tp(){

    mknod /dev/random c 1 9

    if check_sys packageManager apt; then
        apt-get -y update

        if debianversion 7; then
            if is_64bit; then
                local libnspr4_filename1="libnspr4_4.10.7-1_amd64.deb"
                local libnspr4_filename2="libnspr4-0d_4.10.7-1_amd64.deb"
                local libnspr4_filename3="libnspr4-dev_4.10.7-1_amd64.deb"
                local libnspr4_filename4="libnspr4-dbg_4.10.7-1_amd64.deb"
                local libnss3_filename1="libnss3_3.17.2-1.1_amd64.deb"
                local libnss3_filename2="libnss3-1d_3.17.2-1.1_amd64.deb"
                local libnss3_filename3="libnss3-tools_3.17.2-1.1_amd64.deb"
                local libnss3_filename4="libnss3-dev_3.17.2-1.1_amd64.deb"
                local libnss3_filename5="libnss3-dbg_3.17.2-1.1_amd64.deb"
            else
                local libnspr4_filename1="libnspr4_4.10.7-1_i386.deb"
                local libnspr4_filename2="libnspr4-0d_4.10.7-1_i386.deb"
                local libnspr4_filename3="libnspr4-dev_4.10.7-1_i386.deb"
                local libnspr4_filename4="libnspr4-dbg_4.10.7-1_i386.deb"
                local libnss3_filename1="libnss3_3.17.2-1.1_i386.deb"
                local libnss3_filename2="libnss3-1d_3.17.2-1.1_i386.deb"
                local libnss3_filename3="libnss3-tools_3.17.2-1.1_i386.deb"
                local libnss3_filename4="libnss3-dev_3.17.2-1.1_i386.deb"
                local libnss3_filename5="libnss3-dbg_3.17.2-1.1_i386.deb"
            fi
            rm -rf ${cur_dir}/l2tp
            mkdir -p ${cur_dir}/l2tp
            cd ${cur_dir}/l2tp
            download_file "${libnspr4_filename1}"
            download_file "${libnspr4_filename2}"
            download_file "${libnspr4_filename3}"
            download_file "${libnspr4_filename4}"
            download_file "${libnss3_filename1}"
            download_file "${libnss3_filename2}"
            download_file "${libnss3_filename3}"
            download_file "${libnss3_filename4}"
            download_file "${libnss3_filename5}"
            dpkg -i ${libnspr4_filename1} ${libnspr4_filename2} ${libnspr4_filename3} ${libnspr4_filename4}
            dpkg -i ${libnss3_filename1} ${libnss3_filename2} ${libnss3_filename3} ${libnss3_filename4} ${libnss3_filename5}

            apt-get -y install wget gcc ppp flex bison make pkg-config libpam0g-dev libcap-ng-dev iptables \
                               libcap-ng-utils libunbound-dev libevent-dev libcurl4-nss-dev libsystemd-daemon-dev
        else
            apt-get -y install wget gcc ppp flex bison make python libnss3-dev libnss3-tools libselinux-dev iptables \
                               libnspr4-dev pkg-config libpam0g-dev libcap-ng-dev libcap-ng-utils libunbound-dev \
                               libevent-dev libcurl4-nss-dev libsystemd-dev
        fi
        apt-get -y --no-install-recommends install xmlto
        apt-get -y install xl2tpd

        compile_install
    elif check_sys packageManager yum; then
        echo "Adding the EPEL repository..."
        yum -y install epel-release
        [ ! -f /etc/yum.repos.d/epel.repo ] && echo "Install EPEL repository failed, please check it." && exit 1

        if centosversion 7; then
            yum -y install ppp libreswan xl2tpd firewalld
            yum_install
        elif centosversion 6; then
            yum -y remove libevent-devel
            yum -y install libevent2-devel
            yum -y install nss-devel nspr-devel pkgconfig pam-devel \
                           libcap-ng-devel libselinux-devel lsof \
                           curl-devel flex bison gcc ppp make iptables gmp-devel \
                           fipscheck-devel unbound-devel xmlto libpcap-devel xl2tpd

            compile_install
        fi
    fi

}

config_install(){

    cat > /etc/ipsec.conf<<EOF
version 2.0

config setup
    protostack=netkey
    nhelpers=0
    uniqueids=no
    interfaces=%defaultroute
    virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!${iprange}.0/24

conn l2tp-psk
    rightsubnet=vhost:%priv
    also=l2tp-psk-nonat

conn l2tp-psk-nonat
    authby=secret
    pfs=no
    auto=add
    keyingtries=3
    rekey=no
    ikelifetime=8h
    keylife=1h
    type=transport
    left=%defaultroute
    leftid=${IP}
    leftprotoport=17/1701
    right=%any
    rightprotoport=17/%any
    dpddelay=40
    dpdtimeout=130
    dpdaction=clear
    sha2-truncbug=yes
EOF

    cat > /etc/ipsec.secrets<<EOF
%any %any : PSK "${mypsk}"
EOF

    cat > /etc/xl2tpd/xl2tpd.conf<<EOF
[global]
port = 1701

[lns default]
ip range = ${iprange}.2-${iprange}.254
local ip = ${iprange}.1
require chap = yes
refuse pap = yes
require authentication = yes
name = l2tpd
ppp debug = yes
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes
EOF

    cat > /etc/ppp/options.xl2tpd<<EOF
ipcp-accept-local
ipcp-accept-remote
require-mschap-v2
ms-dns 8.8.8.8
ms-dns 8.8.4.4
noccp
auth
hide-password
idle 1800
mtu 1410
mru 1410
nodefaultroute
debug
proxyarp
connect-delay 5000
EOF

    rm -f /etc/ppp/chap-secrets
    cat > /etc/ppp/chap-secrets<<EOF
# Secrets for authentication using CHAP
# client    server    secret    IP addresses
${username}    l2tpd    ${password}       *
EOF

}

compile_install(){

    rm -rf ${cur_dir}/l2tp
    mkdir -p ${cur_dir}/l2tp
    cd ${cur_dir}/l2tp
    download_file "${libreswan_filename}.tar.gz"
    tar -zxf ${libreswan_filename}.tar.gz

    cd ${cur_dir}/l2tp/${libreswan_filename}
    echo "WERROR_CFLAGS =" > Makefile.inc.local
    make programs && make install

    /usr/local/sbin/ipsec --version >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        echo "${libreswan_filename} install failed."
        exit 1
    fi

    config_install

    cp -pf /etc/sysctl.conf /etc/sysctl.conf.bak

    sed -i 's/net.ipv4.ip_forward = 0/net.ipv4.ip_forward = 1/g' /etc/sysctl.conf

    for each in `ls /proc/sys/net/ipv4/conf/`; do
        echo "net.ipv4.conf.${each}.accept_source_route=0" >> /etc/sysctl.conf
        echo "net.ipv4.conf.${each}.accept_redirects=0" >> /etc/sysctl.conf
        echo "net.ipv4.conf.${each}.send_redirects=0" >> /etc/sysctl.conf
        echo "net.ipv4.conf.${each}.rp_filter=0" >> /etc/sysctl.conf
    done
    sysctl -p

    if centosversion 6; then
        [ -f /etc/sysconfig/iptables ] && cp -pf /etc/sysconfig/iptables /etc/sysconfig/iptables.old.`date +%Y%m%d`

        if [ "`iptables -L -n | grep -c '\-\-'`" == "0" ]; then
            cat > /etc/sysconfig/iptables <<EOF
# Added by L2TP VPN script
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT
-A INPUT -p udp -m multiport --dports 500,4500,1701 -j ACCEPT
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s ${iprange}.0/24  -j ACCEPT
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s ${iprange}.0/24 -j SNAT --to-source ${IP}
COMMIT
EOF
        else
            iptables -I INPUT -p udp -m multiport --dports 500,4500,1701 -j ACCEPT
            iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
            iptables -I FORWARD -s ${iprange}.0/24  -j ACCEPT
            iptables -t nat -A POSTROUTING -s ${iprange}.0/24 -j SNAT --to-source ${IP}
            /etc/init.d/iptables save
        fi

        if [ ! -f /etc/ipsec.d/cert9.db ]; then
           echo > /var/tmp/libreswan-nss-pwd
           certutil -N -f /var/tmp/libreswan-nss-pwd -d /etc/ipsec.d
           rm -f /var/tmp/libreswan-nss-pwd
        fi

        chkconfig --add iptables
        chkconfig iptables on
        chkconfig --add ipsec
        chkconfig ipsec on
        chkconfig --add xl2tpd
        chkconfig xl2tpd on

        /etc/init.d/iptables restart
        /etc/init.d/ipsec start
        /etc/init.d/xl2tpd start

    else
        [ -f /etc/iptables.rules ] && cp -pf /etc/iptables.rules /etc/iptables.rules.old.`date +%Y%m%d`

        if [ "`iptables -L -n | grep -c '\-\-'`" == "0" ]; then
            cat > /etc/iptables.rules <<EOF
# Added by L2TP VPN script
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT
-A INPUT -p udp -m multiport --dports 500,4500,1701 -j ACCEPT
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s ${iprange}.0/24  -j ACCEPT
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s ${iprange}.0/24 -j SNAT --to-source ${IP}
COMMIT
EOF
        else
            iptables -I INPUT -p udp -m multiport --dports 500,4500,1701 -j ACCEPT
            iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
            iptables -I FORWARD -s ${iprange}.0/24  -j ACCEPT
            iptables -t nat -A POSTROUTING -s ${iprange}.0/24 -j SNAT --to-source ${IP}
            /sbin/iptables-save > /etc/iptables.rules
        fi

        cat > /etc/network/if-up.d/iptables <<EOF
#!/bin/sh
/sbin/iptables-restore < /etc/iptables.rules
EOF
        chmod +x /etc/network/if-up.d/iptables

        if [ ! -f /etc/ipsec.d/cert9.db ]; then
           echo > /var/tmp/libreswan-nss-pwd
           certutil -N -f /var/tmp/libreswan-nss-pwd -d /etc/ipsec.d
           rm -f /var/tmp/libreswan-nss-pwd
        fi

        update-rc.d -f xl2tpd defaults

        cp -f /etc/rc.local /etc/rc.local.old.`date +%Y%m%d`
        sed --follow-symlinks -i -e '/^exit 0/d' /etc/rc.local
        cat >> /etc/rc.local <<EOF

# Added by L2TP VPN script
echo 1 > /proc/sys/net/ipv4/ip_forward
/usr/sbin/service ipsec start
exit 0
EOF
        chmod +x /etc/rc.local
        echo 1 > /proc/sys/net/ipv4/ip_forward

        /sbin/iptables-restore < /etc/iptables.rules
        /usr/sbin/service ipsec start
        /usr/sbin/service xl2tpd restart

    fi

}

yum_install(){

    config_install

    cp -pf /etc/sysctl.conf /etc/sysctl.conf.bak

    echo "# Added by L2TP VPN" >> /etc/sysctl.conf
    echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
    echo "net.ipv4.tcp_syncookies=1" >> /etc/sysctl.conf
    echo "net.ipv4.icmp_echo_ignore_broadcasts=1" >> /etc/sysctl.conf
    echo "net.ipv4.icmp_ignore_bogus_error_responses=1" >> /etc/sysctl.conf

    for each in `ls /proc/sys/net/ipv4/conf/`; do
        echo "net.ipv4.conf.${each}.accept_source_route=0" >> /etc/sysctl.conf
        echo "net.ipv4.conf.${each}.accept_redirects=0" >> /etc/sysctl.conf
        echo "net.ipv4.conf.${each}.send_redirects=0" >> /etc/sysctl.conf
        echo "net.ipv4.conf.${each}.rp_filter=0" >> /etc/sysctl.conf
    done
    sysctl -p

    cat > /etc/firewalld/services/xl2tpd.xml<<EOF
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>xl2tpd</short>
  <description>L2TP IPSec</description>
  <port protocol="udp" port="4500"/>
  <port protocol="udp" port="1701"/>
</service>
EOF
    chmod 640 /etc/firewalld/services/xl2tpd.xml

    systemctl enable ipsec
    systemctl enable xl2tpd
    systemctl enable firewalld

    systemctl status firewalld > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        firewall-cmd --reload
        echo "Checking firewalld status..."
        firewall-cmd --list-all
        echo "add firewalld rules..."
        firewall-cmd --permanent --add-service=ipsec
        firewall-cmd --permanent --add-service=xl2tpd
        firewall-cmd --permanent --add-masquerade
        firewall-cmd --reload
    else
        echo "Firewalld looks like not running, trying to start..."
        systemctl start firewalld
        if [ $? -eq 0 ]; then
            echo "Firewalld start successfully..."
            firewall-cmd --reload
            echo "Checking firewalld status..."
            firewall-cmd --list-all
            echo "adding firewalld rules..."
            firewall-cmd --permanent --add-service=ipsec
            firewall-cmd --permanent --add-service=xl2tpd
            firewall-cmd --permanent --add-masquerade
            firewall-cmd --reload
        else
            echo "Failed to start firewalld. please enable udp port 500 4500 1701 manually if necessary."
        fi
    fi

    systemctl restart ipsec
    systemctl restart xl2tpd
    echo "Checking ipsec status..."
    systemctl -a | grep ipsec
    echo "Checking xl2tpd status..."
    systemctl -a | grep xl2tpd
    echo "Checking firewalld status..."
    firewall-cmd --list-all

}

finally(){

    cd ${cur_dir}
    rm -fr ${cur_dir}/l2tp
    # create l2tp command
    cp -f ${cur_dir}/`basename $0` /usr/bin/l2tp

    echo "Please wait a moment..."
    sleep 5
    ipsec verify
    echo
    echo "###############################################################"
    echo "# L2TP VPN Auto Installer                                     #"
    echo "# System Supported: CentOS 6+ / Debian 7+ / Ubuntu 12+        #"
    echo "# Intro: https://teddysun.com/448.html                        #"
    echo "# Author: Teddysun <i@teddysun.com>                           #"
    echo "###############################################################"
    echo "If there is no [FAILED] above, you can connect to your L2TP "
    echo "VPN Server with the default Username/Password is below:"
    echo
    echo "Server IP: ${IP}"
    echo "PSK      : ${mypsk}"
    echo "Username : ${username}"
    echo "Password : ${password}"
    echo
    echo "If you want to modify user settings, please use below command(s):"
    echo "l2tp -a (Add a user)"
    echo "l2tp -d (Delete a user)"
    echo "l2tp -l (List all users)"
    echo "l2tp -m (Modify a user password)"
    echo
    echo "Welcome to visit our website: https://teddysun.com/448.html"
    echo "Enjoy it!"
    echo
}


l2tp(){
    clear
    echo
    echo "###############################################################"
    echo "# L2TP VPN Auto Installer                                     #"
    echo "# System Supported: CentOS 6+ / Debian 7+ / Ubuntu 12+        #"
    echo "# Intro: https://teddysun.com/448.html                        #"
    echo "# Author: Teddysun <i@teddysun.com>                           #"
    echo "###############################################################"
    echo
    rootness
    tunavailable
    disable_selinux
    version_check
    get_os_info
    preinstall_l2tp
    install_l2tp
    finally
}

list_users(){
    if [ ! -f /etc/ppp/chap-secrets ];then
        echo "Error: /etc/ppp/chap-secrets file not found."
        exit 1
    fi
    local line="+-------------------------------------------+\n"
    local string=%20s
    printf "${line}|${string} |${string} |\n${line}" Username Password
    grep -v "^#" /etc/ppp/chap-secrets | awk '{printf "|'${string}' |'${string}' |\n", $1,$3}'
    printf ${line}
}

add_user(){
    while :
    do
        read -p "Please input your Username:" user
        if [ -z ${user} ]; then
            echo "Username can not be empty"
        else
            grep -w "${user}" /etc/ppp/chap-secrets > /dev/null 2>&1
            if [ $? -eq 0 ];then
                echo "Username (${user}) already exists. Please re-enter your username."
            else
                break
            fi
        fi
    done
    pass=`rand`
    echo "Please input ${user}'s password:"
    read -p "(Default Password: ${pass}):" tmppass
    [ ! -z ${tmppass} ] && pass=${tmppass}
    echo "${user}    l2tpd    ${pass}       *" >> /etc/ppp/chap-secrets
    echo "Username (${user}) add completed."
}

del_user(){
    while :
    do
        read -p "Please input Username you want to delete it:" user
        if [ -z ${user} ]; then
            echo "Username can not be empty"
        else
            grep -w "${user}" /etc/ppp/chap-secrets >/dev/null 2>&1
            if [ $? -eq 0 ];then
                break
            else
                echo "Username (${user}) is not exists. Please re-enter your username."
            fi
        fi
    done
    sed -i "/^\<${user}\>/d" /etc/ppp/chap-secrets
    echo "Username (${user}) delete completed."
}

mod_user(){
    while :
    do
        read -p "Please input Username you want to change password:" user
        if [ -z ${user} ]; then
            echo "Username can not be empty"
        else
            grep -w "${user}" /etc/ppp/chap-secrets >/dev/null 2>&1
            if [ $? -eq 0 ];then
                break
            else
                echo "Username (${user}) is not exists. Please re-enter your username."
            fi
        fi
    done
    pass=`rand`
    echo "Please input ${user}'s new password:"
    read -p "(Default Password: ${pass}):" tmppass
    [ ! -z ${tmppass} ] && pass=${tmppass}
    sed -i "/^\<${user}\>/d" /etc/ppp/chap-secrets
    echo "${user}    l2tpd    ${pass}       *" >> /etc/ppp/chap-secrets
    echo "Username ${user}'s password has been changed."
}

# Main process
action=$1
if [ -z ${action} ] && [ "`basename $0`" != "l2tp" ]; then
    action=install
fi

case ${action} in
    install)
        l2tp 2>&1 | tee ${cur_dir}/l2tp.log
        ;;
    -l|--list)
        list_users
        ;;
    -a|--add)
        add_user
        ;;
    -d|--del)
        del_user
        ;;
    -m|--mod)
        mod_user
        ;;
    -h|--help)
        echo "Usage: `basename $0` -l,--list   List all users"
        echo "       `basename $0` -a,--add    Add a user"
        echo "       `basename $0` -d,--del    Delete a user"
        echo "       `basename $0` -m,--mod    Modify a user password"
        echo "       `basename $0` -h,--help   Print this help information"
        ;;
    *)
        echo "Usage: `basename $0` [-l,--list|-a,--add|-d,--del|-m,--mod|-h,--help]" && exit
        ;;
esac

手动安装

下载环境包
yum install -y make gcc gmp-devel xmlto bison flex xmlto libpcap-devel lsof vim-enhanced man

安装
yum install openswan ppp xl2tpd

修改配置文件

修改ipsec.conf
vi /etc/ipsec.conf

替换为如下内容,把下面0.0.0.0换成服务器的外网IP(注意一定要有字符缩进,距离不要改变)

config setup
    nat_traversal=yes
    virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12
    oe=off
    protostack=netkey
    conn L2TP-PSK-NAT
    rightsubnet=vhost:%priv
    also=L2TP-PSK-noNAT
  conn L2TP-PSK-noNAT
    authby=secret
    pfs=no
    auto=add
    keyingtries=3
    rekey=no
    ikelifetime=8h
    keylife=1h
    type=transport
    left=0.0.0.0  #服务器的外网IP
    leftprotoport=17/1701
    right=%any
    rightprotoport=17/%any
#网上查找客户端经常断开优化

dpddelay=40
dpdtimeout=130
dpdaction=clear
leftnexthop=%defaultroute
rightnexthop=%defaultroute

修改xl2tpd.conf
/etc/xl2tpd/xl2tpd.conf

ip range 写客户端的内网IP段,local ip写客户端内网IP

[lns default]
ip range = 10.10.0.2-10.10.0.100
local ip = 10.10.0.1
require chap = yes
refuse pap = yes
require authentication = yes
name = LinuxVPNserver
ppp debug = yes
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes
bps = 1000000

修改ipsec.secrets
vi /etc/ipsec.secrets
替换内容如下:(0.0.0.0换成服务器的外网IP也可以写%any)

include /etc/ipsec.d/*.secrets
0.0.0.0 %any: PSK "自己定"  隧道密码

配置用户名,密码:编辑 /etc/ppp/chap-secrets

# Secrets for authentication using CHAP
# client        server  secret                  IP addresses
"username"   l2tpd  "userpass"   *       #619错误注意双引号

注:username换成你要登录的用户名,userpass换成密码

修改sysctl.conf
vi /etc/sysctl.conf

在/etc/sysctl.conf的末尾加上如下内容

net.ipv4.ip_forward = 1
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.log_martians = 0
net.ipv4.conf.default.log_martians = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.icmp_ignore_bogus_error_responses = 1

生效上面的修改使用如下命令
sysctl -p

验证ipsec运行状态
ipsec restart

ipsec verify

出现以下说明成功

Verifying installed system and configuration files

Version check and ipsec on-path                         [OK]
Libreswan 3.20 (netkey) on 2.6.32-642.6.2.el6.x86_64
Checking for IPsec support in kernel                    [OK]
 NETKEY: Testing XFRM related proc values
         ICMP default/send_redirects                    [OK]
         ICMP default/accept_redirects                  [OK]
         XFRM larval drop                               [OK]
Pluto ipsec.conf syntax                                 [OK]
Checking rp_filter                                      [OK]
Checking that pluto is running                          [OK]
 Pluto listening for IKE on udp 500                     [OK]
 Pluto listening for IKE/NAT-T on udp 4500              [OK]
 Pluto ipsec.secret syntax                        INTERNAL ERROR - unknown rcode:WARNING(密码强度不足导致)
  003 WARNING: using a weak secret (PSK)
Checking 'ip' command                                   [OK]
Checking 'iptables' command                             [OK]
Checking 'prelink' command does not interfere with FIPS [IN USE]
Checking for obsolete ipsec.conf options                [OK]

ipsec verify: encountered 2 errors - see 'man ipsec_verify' for help

重启xl2tp
service xl2tpd restart

因为VPN需要路由功能习惯使用IPTABLES
vi /etc/sysconfig/iptables
在:OUTPUT ACCEPT添加以下条目

-A POSTROUTING -s 192.168.20.0/24 -o eth0 -j SNAT --to-source 10.105.105.26

vpn拨入后的包通过eth0转发
192.168.20.0/24跟/etc/xl2tpd/xl2tpd.conf的设置相对应,eth0要改成你内网的网络名字
10.105.105.26要改成你eth0对应的ip地址
还有对应的所需端口的防火墙的通行
查看已用端口
netstat -tuanp

保存后记得
service iptables restart

chkconfig iptables on

查看拨号日志

vi /var/log/message

Maximum retries exceeded for tunnel 可能是认证之间的协议问题,最好有2台以上的客户端连接,可能是服务器或者客户端问题

额外需求

1、配置单独的l2tp日志记录
这里可以利用syslog来配置,在/etc/rsyslog.d/ 下新建20-xl2tpd.conf文件,内容如下:

[root@server17 rsyslog.d]# cat 20-xl2tpd.conf
if $programname == 'xl2tpd' then /var/log/xl2tpd.log
&~
这里可以利用syslog来配置,在/etc/rsyslog.d/ 下新建20-pptpd.conf文件,内容如下:

[root@server17 rsyslog.d]# cat 20-pptpd.conf
if $programname == 'pppd' then /var/log/xl2tpd.log
&~
但是这样只能在日志中看到客户端的公网IP地址、私网IP等信息,却无法看到是哪个用户登录的,这不利于做审计工作,所以需要能将连接用户的信息也写入到日志中,解决方法如下:

在/etc/ppp/ip-up 脚本中加入

echo "Start_Time: `date -d today +%F_%T`" >> /var/log/xl2tpd.log  ##登录时间戳
echo "username: $PEERNAME" >> /var/log/xl2tpd.log  ##用户名
在/etc/ppp/ip-down 脚本中加入

echo "Stop_Time: `date -d today +%F_%T`" >> /var/log/xl2tpd.log  ##断开时间戳
echo "username: $PEERNAME" >> /var/log/xl2tpd.log  ##用户名

重启rsyslog服务

service rsyslog restart
最终的日志信息如下,客户端的公网IP、获取的内网IP、用户名、时间等重要信息都被记录下来了。

cat /var/log/xl2tpd.log

Nov  5 13:47:57 server17 xl2tpd[24509]: control_finish: Peer requested tunnel 29 twice, ignoring second one.
Nov  5 13:47:58 server17 xl2tpd[24509]: Connection established to 202.202.202.202, 1701.  Local: 36071, Remote: 29 (ref=0/0).  LNS session is 'default'
Nov  5 13:47:58 server17 xl2tpd[24509]: result_code_avp: result code not appropriate for Incoming-Call-Request.  Ignoring.
Nov  5 13:47:58 server17 xl2tpd[24509]: Call established with 202.202.202.202, Local: 3764, Remote: 1, Serial: 0
Nov  5 13:47:58 server17 pppd[16218]: pppd 2.4.5 started by root, uid 0
Nov  5 13:47:58 server17 pppd[16218]: using channel 28
Nov  5 13:47:58 server17 pppd[16218]: Using interface ppp0
Nov  5 13:47:58 server17 pppd[16218]: Connect: ppp0  /dev/pts/0
Nov  5 13:47:58 server17 pppd[16218]: sent [LCP ConfReq id=0x1      ]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [LCP ConfReq id=0x0     ]
Nov  5 13:47:58 server17 pppd[16218]: sent [LCP ConfRej id=0x0 ]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [LCP ConfAck id=0x1      ]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [LCP ConfReq id=0x1    ]
Nov  5 13:47:58 server17 pppd[16218]: sent [LCP ConfAck id=0x1    ]
Nov  5 13:47:58 server17 pppd[16218]: sent [CHAP Challenge id=0xfd , name = "LinuxVPNserver"]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [LCP Ident id=0x2 magic=0x5597000a "MSRASV5.20"]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [LCP Ident id=0x3 magic=0x5597000a "MSRAS-0-WWW-PC"]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [LCP Ident id=0x4 magic=0x5597000a "\3777777774012@?\37777777642\37777777705A\37777777642\37777777623\021\37777777764\37777777656;t$"]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [CHAP Response id=0xfd , name = "wujr"]
Nov  5 13:47:58 server17 pppd[16218]: sent [CHAP Success id=0xfd "Access granted"]
Nov  5 13:47:58 server17 pppd[16218]: sent [IPCP ConfReq id=0x1  ]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [IPV6CP ConfReq id=0x5 ]
Nov  5 13:47:58 server17 pppd[16218]: Unsupported protocol 'IPv6 Control Protocol' (0x8057) received
Nov  5 13:47:58 server17 pppd[16218]: sent [LCP ProtRej id=0x2 80 57 01 05 00 0e 01 0a b8 71 8f aa 3d c3 d8 78]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [IPCP ConfReq id=0x6     ]
Nov  5 13:47:58 server17 pppd[16218]: sent [IPCP ConfRej id=0x6  ]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [IPCP ConfRej id=0x1 ]
Nov  5 13:47:58 server17 pppd[16218]: sent [IPCP ConfReq id=0x2 ]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [IPCP ConfReq id=0x7   ]
Nov  5 13:47:58 server17 pppd[16218]: sent [IPCP ConfNak id=0x7   ]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [IPCP ConfAck id=0x2 ]
Nov  5 13:47:58 server17 pppd[16218]: rcvd [IPCP ConfReq id=0x8   ]
Nov  5 13:47:58 server17 pppd[16218]: sent [IPCP ConfAck id=0x8   ]
Nov  5 13:47:58 server17 pppd[16218]: Cannot determine ethernet address for proxy ARP
Nov  5 13:47:58 server17 pppd[16218]: local  IP address 192.168.100.1
Nov  5 13:47:58 server17 pppd[16218]: remote IP address 192.168.100.10
Nov  5 13:47:58 server17 pppd[16218]: Script /etc/ppp/ip-up started (pid 16225)
Start_Time: 2015-11-05_13:47:58
username: test
Nov  5 13:47:58 server17 pppd[16218]: Script /etc/ppp/ip-up finished (pid 16225), status = 0x0

2、使用VPN服务器公网做为客户端互联网出口(跳板机、代理)
使用iptables实现,增加规则

iptables -t nat -A POSTROUTING -o eth1 -s 192.168.100.0/24 -j MASQUERADE (eth1为公网网卡)
3、访问VPN服务器所在的内网其它服务器
使用iptables实现,增加规则

iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o eth0 -j MASQUERADE (eth0为私网网卡)h

错误处理

这两个错误可以不管,运行“/etc/init.d/ipsec restart
”之后,重新“ipsec verify

解决新的错误,需要在终端运行:

for each in /proc/sys/net/ipv4/conf/*
do
    echo 0 > $each/accept_redirects
    echo 0 > $each/send_redirects
done

继续“ipsec verify”,已知的错误成功解决。