Openswan L2TP/IPsec VPN 客户端设置

来自 ArchWiki
(重定向自 Openswan

本文或章节需要改进语言、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 提供了设置相应的 L2TP/IPSec Linux 服务器的说明。

安装

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

否则,安装 xl2tpdopenswanAUR 软件包。

配置

NetworkManager

打开 NetworkManager UI,然后

  1. 转到网络 > VPN。点击“+”
  2. 选择“第二层隧道协议 (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 服务器。如果您遗漏此步骤,您将失去与互联网的连接,并且隧道将崩溃。现在添加一个路由到 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 进行身份验证,该 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")

参见