Openswan L2TP/IPsec VPN 客户端设置

来自 ArchWiki

这篇文章或章节需要改进语言、wiki 语法或风格。请参阅 Help:Style 以供参考。

原因: 这篇文章需要改进语言,请勿使用第一人称写作(在 Talk:Openswan L2TP/IPsec VPN client setup 中讨论)

本文介绍如何在 Arch Linux 上配置和使用 L2TP/IPsec 虚拟专用网络客户端。它涵盖了几个所需软件包的安装和设置。L2TP 指的是 w:第二层隧道协议,对于 w:IPsec,采用的是 Openswan 实现。

本指南主要针对连接到 Windows Server 机器的客户端,因为它使用了一些特定于 Microsoft L2TP/IPsec 实现的设置。但是,它可以适应任何其他常见的 L2TP/IPsec 设置。Openswan wiki 提供了使用 Openswan 和 xl2tpd 设置相应的 L2TP/IPSec Linux 服务器的说明。

安装

要与 NetworkManager 一起使用,安装 networkmanager-l2tpstrongswan 软件包。

否则,安装 xl2tpdopenswanAUR 软件包。

配置

NetworkManager

打开 NetworkManager UI,然后

  1. 转到 “网络” > “VPN”。点击 “+”
  2. 选择 “Layer 2 Tunneling Protocol (L2TP)”。
  3. 您可以为 VPN 选择一个名称。
  4. 在 “网关” 中输入您的 VPN 服务器 IP。
  5. 在 “用户名” 中输入您的 VPN 用户名。
  6. 右键单击 “密码” 字段中的  ?,选择 “仅为此用户存储密码”。(如果此选项给您带来麻烦,您可能需要使用 “为所有用户存储密码”)
  7. 在 “密码” 中输入您的 VPN 密码。
  8. 将 “NT 域” 字段留空。
  9. 单击 “IPsec 设置...” 按钮。
  10. 选中 “启用 IPsec 隧道到 L2TP 主机” 复选框。
  11. 将 “网关 ID” 字段留空。
  12. 在 “预共享密钥” 中输入您的 VPN IPsec PSK。
  13. 点击 “确定”,然后点击 “添加” 以保存 VPN 连接信息。

现在您应该可以通过切换切换按钮来启动 VPN。

OpenSwan

编辑 /etc/ipsec.conf 以包含以下行

config setup
     virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12
     nat_traversal=yes
     protostack=netkey            # default is auto, which will try netkey first
     plutoopts="--interface=eth0" # Replace eth0 with your network interface or use %defaultroute to use default route

conn L2TP-PSK
     authby=secret
     pfs=no
     auto=add
     keyingtries=3
     dpddelay=30
     dpdtimeout=120
     dpdaction=clear
     rekey=yes
     ikelifetime=8h
     keylife=1h
     type=transport
     left=192.168.0.123           # Replace with your local IP address (private, behind NAT IP is okay as well)
     leftprotoport=17/1701
     right=68.68.32.79            # Replace with your VPN server's IP
     rightprotoport=17/1701

此文件包含建立与 VPN 服务器的安全 IPsec 隧道的基本信息。如果您的机器位于 NAT 路由器之后(大多数人都是这种情况),它会启用 NAT 穿越,以及其他各种必要的选项,以便正确连接到远程 IPsec 服务器。下一个文件包含服务器的预共享密钥 (PSK)。

创建文件 /etc/ipsec.secrets:它应包含以下行

192.168.0.123 68.68.32.79 : PSK "your_pre_shared_key"

请记住将本地 (192.168.0.123) 和远程 (68.68.32.79) IP 地址替换为您所在位置的正确数字。预共享密钥将由 VPN 提供商提供,并且需要以明文形式放置在此文件中。您可能会发现此文件已存在并且已经有一些数据,如果您在下一节中启用连接时看到 Can't authenticate: no preshared key found for ...,请尝试备份它并仅使用您的 PSK 创建一个新文件。不要忘记为此文件设置正确的权限 (600),否则您将收到错误消息 We cannot identify ourselves with either end of this connection.

添加连接,使其可用

# ipsec auto --add L2TP-PSK

至此,IPsec 配置已完成,我们可以继续进行 L2TP 配置。

在容器中运行 Openswan

不要忘记添加 CAP_SYS_MODULE 功能以及对主机模块树的访问权限。nspawn 示例

--bind=/lib/modules --capability=CAP_SYS_MODULE

xl2tpd

编辑 /etc/xl2tpd/xl2tpd.conf,使其具有以下内容

[lac vpn-connection]
lns = 68.68.32.79
ppp debug = yes
pppoptfile = /etc/ppp/options.l2tpd.client
length bit = yes

此文件使用连接名称、服务器 IP 地址(再次提醒,请记住更改为您的服务器地址)以及在隧道建立后将传递给 pppd 的各种选项来配置 xl2tpd。

现在创建 /etc/ppp/options.l2tpd.client,内容如下

ipcp-accept-local
ipcp-accept-remote
refuse-eap
require-mschap-v2
noccp
noauth
idle 1800
mtu 1410
mru 1410
defaultroute
usepeerdns
debug
connect-delay 5000
name your_vpn_username
password your_password

在此文件中放置您为 VPN 服务器分配的用户名和密码。许多这些选项都是为了与 Windows Server L2TP 服务器互操作。如果您的 VPN 服务器使用 PAP 身份验证,请将 require-mschap-v2 替换为 require-pap

至此,连接到 L2TP/IPsec 服务器的适用软件套件的配置已完成。要启动连接,请执行以下操作

启动 openswan.servicexl2tpd.service

# ipsec auto --up L2TP-PSK
# echo "c vpn-connection" > /var/run/xl2tpd/l2tp-control

此时隧道已建立,如果您输入以下命令,您应该能够看到它的接口

$ ip link

您应该看到一个代表隧道的 pppX 设备。现在,没有任何流量会通过它路由。您需要添加一些路由规则才能使其正常工作

路由

通过隧道路由到单个 IP 地址或子网的流量

这就像向您的内核表添加路由规则一样简单

# ip route add xxx.xxx.xxx.xxx via yyy.yyy.yyy.yyy dev pppX

注意 xxx.xxx.xxx.xxx 是您希望通过隧道设备(例如 ppp0)与之通信的特定 IP 地址(例如 192.168.3.10)或子网(例如 192.168.3.0/24)。

注意 yyy.yyy.yyy.yyy 是您的 pppX 设备的 “对等 IP”,用于将流量路由到隧道目标 xxx.xxx.xxx.xxx。


请参阅下面的示例,了解如何识别隧道设备名称和对等 IP,然后添加路由。 

$ ip address
4: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1400 qdisc fq_codel state UNKNOWN group default qlen 3
    link/ppp 
    inet 10.192.168.40 peer 192.0.2.1/32 scope global ppp0
       valid_lft forever preferred_lft forever
# ip route add 192.168.3.0/24 via 192.0.2.1 dev ppp0

通过隧道路由所有流量

这要复杂得多,但您的所有流量都将通过隧道传输。首先,通过您当前的网关为实际的 VPN 服务器添加一个特殊路由

# ip route add 68.68.32.79 via 192.168.1.1 dev eth0

这将确保一旦默认网关更改为 ppp 接口,您的网络堆栈仍然可以通过绕过隧道找到 VPN 服务器。如果您遗漏此步骤,您将失去与 Internet 的连接,并且隧道将崩溃。现在添加一个默认路由,该路由指向 PPP 远程端

# ip route add default via yyy.yyy.yyy.yyy dev pppX

可以通过遵循上一节中的步骤来发现远程 PPP 端。现在,为了确保所有流量都通过隧道路由,请删除原始的默认路由

# ip route delete default via 192.168.1.1 dev eth0

要将您的系统恢复到之前的状态,您可以重新启动或反向执行上述所有步骤。

路由创建也可以通过在 /etc/ppp/ip-up.d 中放置脚本来自动化。

故障排除

问题: journalctl 日志 VPN 连接:连接失败:'无法重启 ipsec 服务。

解决方案 确保您已安装 strongswan

注意: 第一步可能是使用 ipsec verify 命令来检查已安装的 IPSEC 的配置。

问题: 我收到来自 pppd 的消息 “Failed to authenticate ourselves to peer”,并且我已经验证我的密码是正确的。可能是什么问题?

解决方案 1: 如果您在您的 /var/log/daemon.log 中看到以下内容

Dec 20 15:14:03 myhost pppd[26529]: rcvd [CHAP Challenge id=0x1 <some_or_another_hash>, name = "SonicWALL"]
Dec 20 15:14:03 myhost pppd[26529]: sent [CHAP Response id=0x1 <some_or_another_hash>, name = "your_vpn_username"]
Dec 20 15:14:03 myhost pppd[26529]: rcvd [LCP EchoRep id=0x0 magic=0x45c269c6]
Dec 20 15:14:03 myhost pppd[26529]: rcvd [CHAP Failure id=0x1 ""]
Dec 20 15:14:03 myhost pppd[26529]: CHAP authentication failed
Dec 20 15:14:03 myhost pppd[26529]: CHAP authentication failed
Dec 20 15:14:03 myhost pppd[26529]: sent [LCP TermReq id=0x3 "Failed to authenticate ourselves to peer"]
Dec 20 15:14:03 myhost pppd[26529]: rcvd [LCP TermReq id=0x2]
Dec 20 15:14:03 myhost pppd[26529]: sent [LCP TermAck id=0x2]
Dec 20 15:14:03 myhost pppd[26529]: rcvd [LCP TermAck id=0x3]

那么您正在针对 SonicWALL LNS 进行身份验证,而 SonicWALL LNS 不知道如何正确处理 CHAP 样式的身份验证。

此问题的解决方案是将以下内容添加到您的 options.l2tp.client 文件中

   refuse-chap

这将导致 SonicWALL 默认为下一个身份验证机制,即 MSCHAP-v2。这应该可以成功进行身份验证,并且从那时起,xl2tpd 应该可以成功地在您和远程 L2TP 服务器之间构建隧道。

解决方案 2: 如果您在以 root 身份运行 journalctl -ru xl2tpd 后在日志中看到以下内容

vas. 03 12:31:21 myhost pppd[8922]: rcvd [LCP EchoRep id=0x0 magic=<some_or_another_hash>]
vas. 03 12:31:21 myhost pppd[8922]: rcvd [CHAP Failure id=0x1 "E=691 R=0 C=<some_or_another_hash> V=3 M=bad username or password"]
vas. 03 12:31:21 myhost pppd[8922]: MS-CHAP authentication failed: bad username or password
vas. 03 12:31:21 myhost pppd[8922]: CHAP authentication failed

尝试在您的 options.l2tp.client 文件中的用户名之前添加域名(注意双反斜杠),即

…
name DOMAIN\\your_vpn_username
password your_password

问题: 使用 Openswan 3.0.0 运行 ipsec auto --ad L2TP-PSK 后出现 cannot initiate connection with ID wildcards (kind=CK_TEMPLATE)

确定 VPN 服务器在 VPN 后面的目标网络中的私有 IP,并将相应的行添加到 /etc/ipsec.conf

rightid = private IP of VPN server

技巧和窍门

脚本启动和关闭

您可以在您的主目录或其他位置(记住您放置它们的位置)创建一些脚本,以启动隧道,然后再关闭它。

首先,一个自动发现 PPP 远端的实用程序脚本

getip.sh
#!/bin/bash

ifconfig $1 | grep "P-t-P" | gawk -F: '{print $2}' | gawk '{print $1}'

接下来,是启动隧道的脚本。这将替换默认路由,因此所有流量都将通过隧道传递

startvpn.sh
#!/bin/bash

systemctl start openswan
sleep 2                                                   #delay to ensure that IPsec is started before overlaying L2TP
systemctl start xl2tpd
ipsec auto --up L2TP-PSK                        
echo "c vpn-connection" > /var/run/xl2tpd/l2tp-control     
sleep 2                                                   #delay again to make that the PPP connection is up.
PPP_GW_ADD=`./getip.sh ppp0`

ip route add 68.68.32.79 via 192.168.1.1 dev eth0
ip route add default via $PPP_GW_ADD
ip route del default via 192.168.1.1

最后,关闭脚本,它只是反转该过程

stopvpn.sh
#!/bin/bash

ipsec auto --down L2TP-PSK
echo "d vpn-connection" > /var/run/xl2tpd/l2tp-control
systemctl stop xl2tpd
systemctl stop openswan

ip route del 68.68.32.79 via 192.168.1.1 dev eth0
ip route add default via 192.168.1.1

另一个脚本

上面的脚本确实对我的工作有帮助。并注意到脚本使用固定 IP,而像我这样的人可能会更改网络 vpn 地址,我想把我的另一个脚本放在下面(不确定如何添加附件,所以只是原始文本)

#!/bin/bash
if [ $# != 1 ] ; then
	echo "Usage: (sudo) sh $0 {init|start|stop}" 
	exit 1;
fi

VPN_ADDR=XXX
IFACE=wlan0

function getIP(){
	ip addr show $1 | grep "inet " | awk '{print $2}' | sed 's:/.*::'       
}

function getGateWay(){
	ip route show default | awk '/default/ {print $3}'
}
function getVPNGateWay(){
	ip route | grep -m 1 "$VPN_ADDR" | awk '{print $3}'
}

GW_ADDR=$(getGateWay)  

function init(){
	cp ./options.l2tpd.client /etc/ppp/
	cp ./ipsec.conf /etc/
	cp ./ipsec.secrets /etc/
	cp ./xl2tpd.conf /etc/xl2tpd/
}

function start(){
	sed -i "s/^lns =.*/lns = $VPN_ADDR/g" /etc/xl2tpd/xl2tpd.conf
	sed -i "s/plutoopts=.*/plutoopts=\"--interface=$IFACE\"/g" /etc/ipsec.conf
	sed -i "s/left=.*$/left=$(getIP $IFACE)/g" /etc/ipsec.conf
	sed -i "s/right=.*$/right=$VPN_ADDR/g" /etc/ipsec.conf
	sed -i "s/^.*: PSK/$(getIP $IFACE) $VPN_ADDR : PSK/g" /etc/ipsec.secrets
	systemctl start openswan
	sleep 2    #delay to ensure that IPsec is started before overlaying L2TP

	systemctl start xl2tpd
	ipsec auto --up L2TP-PSK                        
	echo "c vpn-connection" > /var/run/xl2tpd/l2tp-control     
	sleep 2    #delay again to make that the PPP connection is up.

        ip route add $VPN_ADDR via $GW_ADDR dev $IFACE
        ip route add default via $(getIP ppp0)
        ip route del default via $GW_ADDR
}

function stop(){
	ipsec auto --down L2TP-PSK
	echo "d vpn-connection" > /var/run/xl2tpd/l2tp-control
	systemctl stop xl2tpd
	systemctl stop openswan
	
	VPN_GW=$(getVPNGateWay)
        ip route del $VPN_ADDR via $VPN_GW dev $IFACE
        ip route add default via $VPN_GW
}

$1
exit 0

解析 dns 名称并连接的脚本

这篇文章或章节需要改进语言、wiki 语法或风格。请参阅 Help:Style 以供参考。

原因: Wiki 不应托管脚本。(在 Talk:Openswan L2TP/IPsec VPN client setup 中讨论)

如果您服务器的 IP 是动态的,这将非常有用。

#!/bin/python

from os import system
from socket import gethostbyname
from netifaces import ifaddresses, AF_INET
from time import sleep

# netifaces is a library installed with pip, not part of default insatllation of python
# The script is useful if you have dynamic IP, or need to use a domain for the vpn server
# gist: https://gist.github.com/physicalit/bf9e27c7ecbc12843cd68e442358616c
# The template files are identical to the examples from the link above, except they use the sign `<` as placeholder for the server ip
# can be added to cron, do not forghet to modify your domain and the ip/subnet from the `ip add route ...`

ip = gethostbyname('your.domain.tld')

file_list = ['/etc/xl2tpd/xl2tpd.conf_tmp', '/etc/ipsec.secrets_tmp', '/etc/ipsec.conf_tmp']

def read_file(file):
    with open(file, 'r') as f:
        result = f.readlines()
        #result = [l.rstrip('\n') for l in result]  # l.split('_')[0] 
        return result

def write_ip(ip):
    for l in file_list:
        result = [ip.join(e.split('<')) if "<" in e else e for e in read_file(l)]
        with open(l.split('_')[0], 'w') as f:
            for e in result:
                f.write(e)

if __name__ == "__main__":
    write_ip(ip)
    [ system('systemctl restart {}'.format(l)) for l in ['openswan', 'xl2tpd']]
    vpn = system('ipsec auto --up L2TP-PSK')
    system('echo "c vpn-connection" > /var/run/xl2tpd/l2tp-control')
    sleep(2) # very important or is not going to see ppp0 interface
    if not vpn:
        peer = ifaddresses('ppp0')[AF_INET][0]['peer']
        route = system('ip route add 192.168.88.0/24 via {0} dev ppp0'.format(peer))
        if not route:
            print("VPN sucesfully connected. Route created.")
        else:
            print("VPN KO")

参见