VPNScripter:一个为Windows的VPN连接设计脚本的工具

根据XML配置文件快速创建Windows中的VPN连接

介绍

这是一个通用的PowerShell脚本,根据XML配置文件自动创建一组VPN连接。非常有用,如果您想在Windows中直接配置VPN而不使用VPN提供商开发的任何自定义VPN软件。

背景

VPN一直是从互联网连接到公司私人网络的一种方式。如今,它们已经商业化,主要用于隐私问题,将所有客户的互联网流量路由到分布在世界各地的中继服务器上。有几种不同的VPN连接协议,Windows本地支持其中大部分,特别是:

  • PPTP:最早的VPN协议之一,基于PPP协议的封装(通过GRE协议)和加密(RC4)[1]。PPTP由Microsoft开发,由于弱而不安全的加密算法,目前正在被放弃使用。通常客户端认证是通过登录和密码进行的,尽管也可以使用客户端证书。从网络角度看,PPTP使用TCP端口1723,并且需要路由器转发IP协议GRE。
  • L2TP/IPSEC:L2TP是一个隧道协议,类似于PPTP,用于封装PPP协议。由于L2TP是不安全的(没有任何加密方式),为了提供安全性,通常与另一种协议IPSEC一起使用[2]。L2TP客户端认证需要登录名和密码,此外客户端和服务器通常还共享一个PSK,以便允许客户端建立IPSEC隧道,尽管客户端也可以使用证书对IPSEC服务器进行身份验证。从网络角度看,L2TP使用UDP端口1701,而IPSEC使用UDP端口4500和500(如果不在NAT后面,则还必须通过路由器转发IP协议ESP)。它是”体积最大”的协议。
  • SSTP:由Microsoft开发,类似于PPTP和L2TP,它基于使用SSL/TLS通道封装PPP协议来安全地传输所有流量(与在安全的互联网网站上使用https时使用的相同协议)。通常客户端认证是通过登录和密码进行的,尽管也可以使用客户端证书。由于它只使用标准的HTTPS端口(TCP 443),它是最适合绕过几乎所有防火墙限制的协议,并且还可以与代理服务器完美配合使用。
  • IKEv2:这是IPSEC的一个小变体,客户端认证不仅可以使用PSK或证书,还可以使用标准的用户名密码凭据。此外,IKEv2对于网络连接的变化更具弹性,这使得它成为移动用户在接入点之间移动时的良好选择。从网络角度看,IKEv2使用UDP端口500和4500(如果不在NAT后面,则还必须通过路由器转发IP协议ESP)。

Windows还有自动协议,它会尝试使用所有协议IKEv2、SSTP、L2TP/IPSEC、PPTP按顺序建立VPN连接。有关更多信息,请参见[3]

使用代码

所有脚本配置都在名为vpnconfig.xml的XML文件中进行(请参见下文)。该文件定义了一组VPN提供商(Provider元素节点),对于每个提供商,为其指定一组服务器(Server子元素节点),为这些服务器在Windows中创建VPN连接。让我们来看看这些节点:

  • Provider:此节点对应于一个VPN提供商。属性:
    • name:用于在Windows中生成VPN连接名称
    • basedomain:用于生成VPN服务器的主机名(通常VPN提供商提供一组共享公共域名的服务器)。可以在服务器节点中覆盖此项。
    • l2tppsk:这是L2TP/IPSEC连接的预共享密钥(通常在所有提供商服务器中相同)。
    • user:用于访问VPN的用户名(通常在所有提供商服务器中相同)。
    • password:与用户名关联的密码(通常在所有提供商服务器中相同)。
    • proto:指定用于所有服务器的VPN协议,如果留空,则表示自动。
  • Server:此节点对应于VPN提供商的服务器。属性:
    • server:指定服务器的主机名。如果此属性不包含”.”字符,则主机名通过将此字段串联到提供商的基本域名来获取,否则主机名等于此字段。
    • proto:指定要使用的VPN协议。它还会覆盖提供商节点中定义的任何协议。
    • user:用于访问VPN的用户名。它还会覆盖提供商节点中定义的任何用户。
    • password:与username关联的密码。它还会覆盖提供商节点中定义的任何密码。
<!-- VpnScripter 配置文件 © 2016 Federico Di Marco

Provider 定义了您拥有的 VPN 提供商。
每个 VPN 提供商通常有一组可以连接的服务器,
脚本会为每个提供商中指定的每个服务器创建一个 VPN 连接。
创建的连接具有以下属性:
- 名称:服务器属性(截止到第一个“.”)+ 提供商名称(如果 proto 为空或自动,则为服务器 + proto + 提供商名称)。
- 协议:在服务器元素中指定的协议,如果为 null,则为提供商元素中指定的协议,如果也为 null,则为自动。
- L2tp PSK、用户、密码:在服务器元素中指定的 L2tp PSK、用户、密码,如果为 null,则为提供商元素中指定的 L2tp PSK、用户、密码
(您不需要为所有服务器重复这些属性)。
- 服务器主机名:如果服务器属性不包含任何“.”字符,则为服务器属性 + 提供商基本域名,否则为服务器属性。
-->

<Providers>
  <Provider name="TestVPN1"  
  basedomain="myvpn.com" user="user01"  
  password="hottie">   
    <Server server="sw" />   
    <!-- VPN 将具有 sw.myvpn.com 作为主机地址,
    SW TestVPN1 作为名称,协议自动选择 -->
    <Server server="ro" proto="PPTP"/>   
    <!-- 服务器的协议覆盖了提供商指定的协议(在此情况下为自动) -->
    <Server server="kick-vm.myvpnext.com" 
    proto="SSTP"/>  
    <!-- VPN 将具有 kick-vm.myvpnext.com 作为主机地址,
    KICK-VM TestVPN1 作为名称 -->
    <Server server="sp" proto="IKEV2" 
    user="user15" password="beer" /> 
</Provider>
<Provider name="TestVPN2" basedomain="myvpn2.com" 
l2tppsk="12345" user="test001" password="master">
    <Server server="karate" proto="L2TP" 
    l2tppsk="314pi"/>
    <Server server="kazu"  />
    <Server server="moon"  />
    <Server server="sun" />
</Provider>
</Providers>

在压缩档案中,您会找到 3 个文件:

  • DotRas.dll:它是一个.NET类库,由PowerShell脚本用于创建 VPN 连接,
    并且必须与脚本位于同一个文件夹中。
  • vpnconfig.xml:这是上述 XML 配置文件,必须使用您的设置进行编辑。
  • VpnScripter.ps1:它是一个PowerShell脚本,可以从PowerShell或双击启动。
    它接受一个名为 ConfigFile 的可选参数,用于指定要使用的 XML 配置文件的名称(默认为 vpnconfig.xml)。
    您可以指定 -Debug 标志以获得更详细的日志输出。

该脚本已在Windows 10上进行了测试,
但应在至少具有 PowerShell 3.0 的任何Windows上工作。

实现概述

基本上,所有的代码都在一个名为
VpnScripter.ps1 的单个 PowerShell 文件中,
其中包含了XSD、C#和PowerShell代码的混合体。基本上,它执行以下操作:

  • 解析和验证 XML 配置文件 vpnconfig.xml,
    使用嵌入在 PowerShell 脚本中定义的 XSD 模式。该模式本身非常简单(例如,主要包含指定配置文件允许/要求的属性的 xs:attribute 子句),
    并定义了一个简单类型 NotEmptyTrimmedString,该类型通过正则表达式检查属性值是否为“非空修剪字符串”(用于必须是“有意义”的服务器属性)。
    XSD 模式的验证通过 PowerShell 函数 ValidateLoadXml 执行,该函数使用标准的 .NET 函数进行验证
    (例如,C# new XmlDocument().Load(XmlReader.Create(<file>,<具有模式文件的设置>)))。
  • 循环遍历 XML 配置文件中所有 Provider 节点下的所有 Server 节点
    • 根据前面提到的规则构建在Windows中创建VPN条目所需的参数列表
      (如果服务器属性包含点“.”,则为 VPN 端点的完整 DNS 名称,否则必须与 basedomain 属性连接,
      等等)。为了从 Server 和 Provider 节点中包含的信息中评估所需的用户、密码、协议和 L2tp PSK,
      脚本使用了一个合并运算符,在SQL查询和C#中非常常见(运算符 ??),
      但不幸的是在 PowerShell 中缺失,因此在自定义定义的 PowerShell 函数 Coalesce 中实现。
    • 对参数执行附加检查,这些检查不太容易使用 XSD 实现:
      • 如果proto属性为 L2TP,则 l2tppsk 属性不能是空的
      • userpassword 属性不能是空的
    • 通过 Get-VpnConnection cmdlet 检查 Windows 中是否已存在 VPN 条目,如果存在,则通过 Remove-VpnConnection cmdlet 删除它。
      $exist=Get-VpnConnection -Name $vpnname -ErrorAction silentlycontinue
      if ($exist -ne $null) {
          Write-Host "Info: Removing VPN connection $vpnname"
      
          Remove-VpnConnection -Name $vpnname -Force
      }
      
    • 通过调用自定义定义的 C# 函数 Add 创建新的 VPN 条目。
      基本上,该函数设置 VPN 参数(proto 通过一个简单的转换函数 ConvertProto 转换为 enum
      IKEV2 VPN 必须使用 EAP 身份验证等),并直接调用 DotRas.dll 函数将新的 VPN 条目添加到 Windows

      正如已经提到的,XSD模式和.NET helper代码已经嵌入在PowerShell脚本中,成为一个单独的、几乎是自包含的(需要DotRas.dll)文件。实际上,PowerShell脚本有一个很好的特性,可以允许包含任何.NET代码,从而使它们能够完成使用C#代码可以完成的所有工作。有趣的是,C#代码可以被解析和编译的方式:

      • 首先,使用Add-Type -Path<dll文件>加载任何DLL文件(使用Add-Type -AssemblyName<assembly>加载任何程序集),这些DLL文件或程序集由自定义代码使用
      • 然后,使用Add-Type -ReferencedAssemblies<引用的程序集列表> -TypeDefinition<包含C#代码的字符串> -Language CSharp解析和编译自定义的C#代码
      Add-Type -Path $psscriptroot\DotRas.dll
      Add-Type -AssemblyName System.Xml
      Add-Type -ReferencedAssemblies $psscriptroot\DotRas.dll,System.Xml 
               -TypeDefinition $Source -Language CSharp

      Points of Interest

      使用外部库DotRas.dll是因为似乎没有办法使用标准的PowerShell命令Add-VpnConnection配置凭据(登录名和密码),如果你找到了方法,请告诉我。

      仓库

      你可以在GitHub上找到源代码仓库。如果你想为你的VPN提供商添加一个预定义的配置文件,其中包含所有服务器,或者改进代码,欢迎你。

      历史

      • V1.0(2016年12月2日)
        • 首次发布
      • V1.1(2016年12月7日)
        • 在服务器节点中添加了对l2tppskuserpassword的重写
        • 通过XSD进行XML验证,并对user/password/l2tppsk参数进行简单检查
      • V1.2(2017年3月27日)
        • 添加了”实现概述”部分

      参考文献

      • [1] PPP是一种旧的点对点协议,历来用于通过调制解调器连接到ISP。它允许在两个端点之间建立连接。
      • [2] IPSEC是两个端点之间的加密隧道,基于一组规则(称为安全关联)建立加密和完整性算法,用于在隧道中传输的网络数据包(如所有TCP数据包、TCP寻址到特定端口的数据包等)。基本上,它将TCP/UDP封装在一个新的加密IP数据包(ESP)中。用于加密和检查消息完整性的算法通过一个叫做IKE的协商协议来确定。由于客户端和服务器主要通过证书进行相互认证,因此IPSEC通常用于局域网到局域网VPN(例如,连接两个不同组织的网络),而不是客户端到局域网的场景中。然而,对于这种场景,可以通过PSK(预共享密钥或共享密钥)进行身份验证,尽管这会降低安全性。
      • [3] Microsoft VPN隧道协议

Leave a Reply

Your email address will not be published. Required fields are marked *