Openswan L2TP/IPsec VPN 客户端设置
本文介绍如何在 Arch Linux 上配置和使用 L2TP/IPsec 虚拟专用网络客户端。它涵盖了几个所需软件包的安装和设置。L2TP 指的是 w:第二层隧道协议,对于 w:IPsec,采用了 Openswan 实现。
本指南主要针对连接到 Windows Server 机器的客户端,因为它使用了一些特定于 Microsoft L2TP/IPsec 实现的设置。但是,它可以适用于任何其他常见的 L2TP/IPsec 设置。Openswan wiki 提供了设置相应的 L2TP/IPSec Linux 服务器的说明。
安装
要与 NetworkManager 一起使用,安装 networkmanager-l2tp 和 strongswan 软件包。
否则,安装 xl2tpd 和 openswanAUR 软件包。
配置
NetworkManager
打开 NetworkManager UI,然后
- 转到网络 > VPN。点击“+”
- 选择“第二层隧道协议 (L2TP)”。
- 您可以为 VPN 选择一个名称。
- 在“网关”中输入您的 VPN 服务器 IP。
- 在“用户名”中输入您的 VPN 用户名。
- 右键单击密码字段中的?,选择“仅为此用户存储密码”。(如果此选项给您带来麻烦,您可能需要使用“为所有用户存储密码”)
- 在“密码”中输入您的 VPN 密码。
- 将“NT 域”字段留空。
- 点击“IPsec 设置...”按钮。
- 勾选“启用 IPsec 隧道到 L2TP 主机”复选框。
- 将“网关 ID”字段留空。
- 在“预共享密钥”中输入您的 VPN IPsec PSK。
- 点击“确定”,然后点击“添加”以保存 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.service
和 xl2tpd.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 服务器。如果您遗漏此步骤,您将失去与互联网的连接,并且隧道将崩溃。现在添加一个路由到 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
问题: 我收到来自 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 进行身份验证,该 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 名称并连接的脚本
如果您服务器的 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")