「L2TP over IPSec」- 服务搭建:Libreswan + xl2tpd

  CREATED BY JENKINSBOT

搭建L2TP/IPSec的VPN服务时,在网上找了很多的教程都不是很好用,或多或少都存在问题。后来通过自动化脚本vpnsetup.sh完成了配置,而这篇文章是通过分析vpnsetup.sh脚本后整理出来的,作为一个通用的配置教程(因为该脚本只支持Ubuntu和Debian的某些版本)。

注意事项

注意,不支持OpenVZ容器。不知道为什么,可能是内核没有对应的模块。

系统环境

Debian GNU/Linux 8.2 (jessie)

strongSwan

xl2tpd

ppp

配置过程

安装依赖的软件包

#!/bin/bash

################################################################################
# 安装依赖包
################################################################################
apt-get -yq install wget dnsutils openssl iptables iproute2 gawk grep sed net-tools

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

安装Libreswan服务

#!/bin/bash

################################################################################
# 安装 Libreswan,配置L2TP、IPSec、PPP
################################################################################
# Create and change to working dir
mkdir -p /opt/src && cd /opt/src

SWAN_VER=3.22
swan_file="libreswan-$SWAN_VER.tar.gz"
swan_url1="https://github.com/libreswan/libreswan/archive/v$SWAN_VER.tar.gz"
wget -t 3 -T 30 -nv -O "$swan_file" "$swan_url1"

/bin/rm -rf "/opt/src/libreswan-$SWAN_VER"
tar xzf "$swan_file" && /bin/rm -f "$swan_file"
cd "libreswan-$SWAN_VER"
[ "$SWAN_VER" = "3.22" ] && sed -i '/^#define LSWBUF_CANARY/s/-2$/((char) -2)/' include/lswlog.h
sed -i '/docker-targets\.mk/d' Makefile
cat > Makefile.inc.local <<'EOF'
WERROR_CFLAGS =
USE_DNSSEC = false
USE_GLIBC_KERN_FLIP_HEADERS = true
EOF
if [ "$(packaging/utils/lswan_detect.sh init)" = "systemd" ]; then
    apt-get -yq install libsystemd-dev
fi
NPROCS="$(grep -c ^processor /proc/cpuinfo)"
[ -z "$NPROCS" ] && NPROCS=1
make "-j$((NPROCS+1))" -s base && make -s install-base

cd /opt/src
/bin/rm -rf "/opt/src/libreswan-$SWAN_VER"
if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF "$SWAN_VER"; then
    echo  "Libreswan $SWAN_VER failed to build."
    exit
fi

定义使用的常量

#!/bin/bash

################################################################################
# 参数配置
################################################################################
net_iface='eth0'
PUBLIC_IP='115.159.122.157'
SYS_DT="$(date +%F-%T)"

VPN_IPSEC_PSK="$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' < /dev/urandom | head -c 16)"
VPN_USER=vpnuser
VPN_PASSWORD="$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' < /dev/urandom | head -c 16)"

进行IPSec、L2TP配置

#!/bin/bash

################################################################################
# 进行VPN的配置
################################################################################

L2TP_NET=${VPN_L2TP_NET:-'192.168.42.0/24'}
L2TP_LOCAL=${VPN_L2TP_LOCAL:-'192.168.42.1'}
L2TP_POOL=${VPN_L2TP_POOL:-'192.168.42.10-192.168.42.250'}
XAUTH_NET=${VPN_XAUTH_NET:-'192.168.43.0/24'}
XAUTH_POOL=${VPN_XAUTH_POOL:-'192.168.43.10-192.168.43.250'}
DNS_SRV1=${VPN_DNS_SRV1:-'8.8.8.8'}
DNS_SRV2=${VPN_DNS_SRV2:-'8.8.4.4'}

# Create IPsec config
cat > /etc/ipsec.conf <<EOF
version 2.0

config setup
  virtual-private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!$L2TP_NET,%v4:!$XAUTH_NET
  protostack=netkey
  interfaces=%defaultroute
  uniqueids=no

conn shared
  left=%defaultroute
  leftid=$PUBLIC_IP
  right=%any
  encapsulation=yes
  authby=secret
  pfs=no
  rekey=no
  keyingtries=5
  dpddelay=30
  dpdtimeout=120
  dpdaction=clear
  ike=3des-sha1,3des-sha2,aes-sha1,aes-sha1;modp1024,aes-sha2,aes-sha2;modp1024
  phase2alg=3des-sha1,3des-sha2,aes-sha1,aes-sha2,aes256-sha2_512
  sha2-truncbug=yes

conn l2tp-psk
  auto=add
  leftprotoport=17/1701
  rightprotoport=17/%any
  type=transport
  phase2=esp
  also=shared

conn xauth-psk
  auto=add
  leftsubnet=0.0.0.0/0
  rightaddresspool=$XAUTH_POOL
  modecfgdns1=$DNS_SRV1
  modecfgdns2=$DNS_SRV2
  leftxauthserver=yes
  rightxauthclient=yes
  leftmodecfgserver=yes
  rightmodecfgclient=yes
  modecfgpull=yes
  xauthby=file
  ike-frag=yes
  ikev2=never
  cisco-unity=yes
  also=shared
EOF

# Specify IPsec PSK
cat > /etc/ipsec.secrets <<EOF
%any  %any  : PSK "$VPN_IPSEC_PSK"
EOF

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

[lns default]
ip range = $L2TP_POOL
local ip = $L2TP_LOCAL
require chap = yes
refuse pap = yes
require authentication = yes
name = l2tpd
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes
EOF

# Set xl2tpd options
cat > /etc/ppp/options.xl2tpd <<EOF
+mschap-v2
ipcp-accept-local
ipcp-accept-remote
ms-dns $DNS_SRV1
ms-dns $DNS_SRV2
noccp
auth
mtu 1280
mru 1280
proxyarp
lcp-echo-failure 4
lcp-echo-interval 30
connect-delay 5000
EOF

# Create VPN credentials
cat > /etc/ppp/chap-secrets <<EOF
"$VPN_USER" l2tpd "$VPN_PASSWORD" *
EOF

VPN_PASSWORD_ENC=$(openssl passwd -1 "$VPN_PASSWORD")
cat > /etc/ipsec.d/passwd <<EOF
$VPN_USER:$VPN_PASSWORD_ENC:xauth-psk
EOF

修改sysctl配置

#!/bin/bash

################################################################################
# 修改sysctl配置
################################################################################
if ! grep -qs "hwdsl2 VPN script" /etc/sysctl.conf; then

    if [ "$(getconf LONG_BIT)" = "64" ]; then
	SHM_MAX=68719476736
	SHM_ALL=4294967296
    else
	SHM_MAX=4294967295
	SHM_ALL=268435456
    fi
    cat >> /etc/sysctl.conf <<EOF

# Added by hwdsl2 VPN script
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = $SHM_MAX
kernel.shmall = $SHM_ALL

net.ipv4.ip_forward = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.$net_iface.send_redirects = 0
net.ipv4.conf.$net_iface.rp_filter = 0

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
fi

# Reload sysctl.conf
sysctl -e -q -p

使用iptables进行防火墙配置

#!/bin/bash

#################################################################################
# 进行防火墙配置
################################################################################
# Check if rules need updating
ipt_flag=0
IPT_FILE="/etc/iptables/rules.v4"
if ! grep -qs "hwdsl2 VPN script" "$IPT_FILE" \
	|| ! 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
    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
    iptables -I INPUT 4 -p udp -m multiport --dports 500,4500 -j ACCEPT
    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 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
    # 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
    echo "# Modified by hwdsl2 VPN script" > "$IPT_FILE"
    iptables-save >> "$IPT_FILE"

fi

# Apply new IPTables rules
iptables-restore < "$IPT_FILE"

设置服务的开机启动

#!/bin/bash

################################################################################
# 设置开机启动
################################################################################

# IPSec

# L2TP

# iptables

启动服务

#!/bin/bash

################################################################################
# 启动服务
################################################################################

# Update file attributes
chmod 600 /etc/ipsec.secrets* /etc/ppp/chap-secrets* /etc/ipsec.d/passwd*

# Restart services
mkdir -p /run/pluto
service ipsec restart 2>/dev/null
service xl2tpd restart 2>/dev/null

进行如上配置之后,即可使用客户端进行连接。

注意事项

防火墙配置

这里防火墙配置与VPN并无直接关系。这里的防火墙配置是为了减少端口的暴露,对数据包进行拦截:

#!/bin/bash

iptables -A INPUT -i ppp0 -j ACCEPT
iptables -A INPUT -i eth0 -p udp -m udp --dport 500 -j ACCEPT
iptables -A INPUT -i eth0 -p udp -m udp --dport 4500 -j ACCEPT
iptables -A INPUT -i eth0 -p esp -j ACCEPT
iptables -A INPUT -i eth0 -p ah -j ACCEPT
iptables -A INPUT -i eth0 -p udp -m policy --dir in --pol ipsec -m udp --dport 1701 -j ACCEPT

使用Openswan + xl2tpd的教程

Setting up a L2TP over IPSec VPN on Debian on 10 steps
How to Set Up an L2TP/IPsec VPN Server on Linux

参考文献

(1)psanford/meraki_strongswan_notes.md
(1)Which ports for IPSEC/LT2P?
(1)https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/vpnsetup.sh
L2TP/IPsec Server configuration using openswan and xl2tpd
Using a Linux L2TP/IPsec VPN server
IPsec L2TP VPN server
搭建L2TP/IPsec VPN 过程
AWS搭建IPSec上的L2TP VPN服务器
strongSwan + xl2tpd でVPN(L2TP/IPsec)を構築する
strongSwan + xl2tpd VPN server: how to configure several config files?