OpenVPN,您对此了解甚少

OpenVPN,这个词多少钱。 一个多平台,可灵活配置的免费开源VPN服务器,实际上是组织内部公司网络访问的事实上的标准。 大多数管理员将其与默认设置或不同HOW-TO中广泛描述的典型配置一起使用。 但是,OpenVPN看起来是否如此简单? 在本文中,我们将考虑隐藏在内部的OpenVPN的内部机制,这些机制将从根本上改变其功能的概念。


OpenVPN服务器以源代码或即装即用的已编译软件包的形式分发给各种操作系统。 OpenSSL用作提供加密的库。


用于将客户端连接到服务器以及服务器之间的大多数配置都涉及使用一堆私钥或私钥/公钥来确保内部流量的安全。 对于采用MultiPoint-To-SinglePoint模式的公司网络,通常使用其自己的PKI证书颁发机构,该证书颁发机构可以使用easy-rsa或基于XCA的方法轻松构建。 对于点对点服务器间通信,主要使用共享密钥配置。 回顾基本的,众所周知的机制和功能。


关键机制和能力


  • 证书认证


    已经编写了大量的文档。 重点很简单。 正在创建一个颁发用户证书的证书颁发机构。 在证书颁发机构的帮助下,提供了用于将用户连接到OpenVPN服务器的控件。 当证书过期或被吊销时,用户访问被阻止。 与证书一起颁发的带有密码的私钥可提供安全性,以防止未经授权的内部资源连接。


  • 专用点对点密钥


    从仅将一个用户/服务器连接到公司资源的角度来看,使用具有私钥的方案。 在主机之一上生成一个密钥,该密钥在服务器和客户端之间共享。



在为确保客户端与服务器之间的“握手”握手的安全性而进行的所有连接情况下,均使用Diffie-Hellmann协议。


  • 外部用户认证


    为了简化对用户连接的控制,可以使用通过登录名/密码进行外部用户身份验证的方案来代替具有自己的PKI的方案。 此方案便于通过域登录名/密码来验证用户身份。 要连接到服务器,服务器证书和HARDENING OPENVPN SECURITY数据包签名密钥将添加到客户端配置文件中。
    客户端配置示例


    dev tun proto udp #  IP  OpenVPN remote 172.16.111.166 # Port  port 1200 client resolv-retry infinite tls-client key-direction 1 auth SHA1 cipher BF-CBC #comp-lzo persist-key persist-tun # auth-user-pass c:/temp/pass.txt # # just create a file with name pass.txt # and put to it two lines # ------------- #username #password # ------------- #auth-user-pass verb 3 <ca> -----BEGIN CERTIFICATE----- MIIE5jCCA86gAwIBAgIJAOt3kFH7PxA0MA0GCSqGSIb3DQEBCwUAMIGjMQswCQYD .... -----END CERTIFICATE----- </ca> <tls-auth> -----BEGIN OpenVPN Static key V1----- 83ddd29fa82212f3059d85a41490134c .... a4f2c7df3a22364a49093bca102dedeb -----END OpenVPN Static key V1----- </tls-auth> 

    服务器配置的一部分,用于通过文件进行客户端身份验证
    使用其他身份验证方法


     verify-client-cert none #client-cert-not-required username-as-common-name tls-server tls-auth /usr/local/etc/openvpn/ssl/tlsauth.key key-direction 0 tls-timeout 120 auth SHA1 cipher BF-CBC auth-user-pass-verify /usr/local/etc/openvpn/auth/auth-static-file.pl via-file 

    此方案很方便,但是非常不安全。


  • PAM


    为了提高安全性,您可以使用在外部系统中提供登录名/密码验证的插件。 最常见的方法是系统PAM(可插入身份验证模块)。
    将行添加到OpenVPN配置文件


     plugin /usr/share/openvpn/plugin/lib/openvpn-auth-pam.so login 

  • 路由选择


    因为 服务器的主要任务是为远程用户/服务器提供对内部资源的访问,服务器允许您确定从客户端到服务器以及从服务器到客户端的静态路由。 从客户端访问内部资源的角度来看,使用DHCP和伪指令“ route”或“ push route”的服务器允许您将内部网络路由传输到客户端。 为了向服务器本身通知客户端的远程网络,使用了“ client config dir”(ccd),该机制允许使用“ iroute”指令来描述必须在服务器路由表中的客户端内部网络的列表,才能将通信量传输到这些内部网络。



在此“常规”广泛使用的功能上,结束并针对每种特定情况进行本地自定义。


其他OpenVPN功能


考虑一下人们可能听说过但实际上没有看到或使用过的OpenVPN的其他功能。


  • 网络安全/数据包过滤


    因为 OpenVPN路由流量,它具有两种常规的互斥操作模式。 第一种模式是OpenVPN服务器内部的路由,第二种模式是接口间的核路由。 在第一种情况下,OpenVPN负责在客户端/网络之间切换和过滤数据包,在第二种情况下,负责主机上支持的任何系统数据包过滤器(pf,iptables等)。
    很少有人知道OpenVPN具有内置的数据包筛选器,可让您允许或隔离用户与网络之间的连接。
    是的是的 您没看错。 OpenVPN有自己的内置数据包过滤器。 过滤流量的功能早在2010年就已实现
    通过管理界面或通过连接到OpenVPN的插件来控制OpenVPN数据包筛选器
    流量规则通过文件进行管理。 文件格式很简单。


     [CLIENTS DROP|ACCEPT] {+|-}common_name1 {+|-}common_name2 . . . [SUBNETS DROP|ACCEPT] {+|-}subnet1 {+|-}subnet2 . . . [END] 

    块指令(ACCEPT / DENY)为未在块内指定的所有客户端设置默认操作。
    例如,客户端用户2的文件


     [CLIENTS DROP] +user1 [SUBNETS DROP] [END] 

    将阻止到所有用户和网络的流量,但允许到客户端1的流量。 如果user1没有明确描述将流量传输到user2的权限,则流量将仅在一个方向上进入user2-> user1。



或另一个例子。
禁用除用户与位于本地网络上的DNS服务器以及网络192.168.0.0/24上的测试电路之间的访问以外的所有功能


 [CLIENTS DROP] +user1 +user2 [SUBNETS DROP] +10.150.0.1 +10.150.1.1 +192.168.0.0/24 [END] 

通过配置文件或连接“设置”标志“ OPENVPN_PLUGIN_ENABLE_PF”的插件时,可以激活过滤机制。
我们稍后将讨论这个机会。
流量过滤的第二种模式是系统内置的数据包过滤器。 要激活它,配置中不应包含“ client-to-client”指令。 从连接/断开客户端时自动打开/关闭必要规则的角度来看,在规则列表中使用单独的插入最为方便,可以通过Iptables(Linux)中的CHAINS或PF(FreeBSD)中的Anchors实现。 规则的激活/停用通常是通过服务器配置文件中的client-connect / client-disconnect指令完成的,当用户连接/断开连接时,它们会调用相应的脚本。


  • 先进的PAM身份验证


    扩展的PAM身份验证意味着更改用户登录和密码验证的逻辑。 这可以通过安装适用于OpenVPN的适当插件来实现,该插件可以读取和验证外部源中的数据,也可以通过将库连接到系统以允许编写任何逻辑来编写脚本。 这样的库之一是pam_python ,它可以帮助通过Python脚本编写任何登录名/密码验证逻辑。
    如果使用它,则用户验证字符串将如下更改。


     plugin openvpn-plugin-auth-pam.so pam_python login USERNAME password PASSWORD domain mydomain.com 

    由于PAM的“幕后”是带有用户或外部库的系统的对话算法,因此可以控制这些对话。 例如, 将OTP令牌连接到系统 。 LinOTP库仅作为示例,因为 我在¯\ (ツ) /¯某个地方测试期间丢失了自己的自写库
    此外,示例中的单词“ pam_python”很容易被搜索到。
    使用外部PAM模块时的主要问题是无法在被称为Python或通过系统pam调用的任何其他脚本中获取OpenVPN会话环境。 即 该脚本仅提供检查分配给它的登录名/密码的那些功能。


  • 延迟身份验证


    OpenVPN服务器支持所谓的“延迟”身份验证。 如果身份验证服务无法实时处理登录名/密码验证请求,则使用“延迟”身份验证。


  • OpenVPN插件


    这是一个独立的并行宇宙,可能对此有所了解,但由于有些混淆,它们无法或不敢使用。 确实,为OpenVPN编写功能性插件需要使用C进行编程,包含所有暗示的内容。 简单插件的示例包含在OpenVPN源代码树中,例如,有一个插件用于演示OpenVPN的方法调用



让我们尝试弄清楚插件如何通过OpenVPN运行。
用于插件的功能和参数在单独的文件中描述
当插件由OpenVPN服务器初始化时,插件的主要任务是传输插件支持的功能列表,并在调用任何功能时返回正确的响应代码,该代码将清晰地显示在服务器上。


 #define OPENVPN_PLUGIN_FUNC_SUCCESS 0 #define OPENVPN_PLUGIN_FUNC_ERROR 1 #define OPENVPN_PLUGIN_FUNC_DEFERRED 2 

让我们详细介绍每个小组。 我们将基于用户的密码验证来考虑工作逻辑。
服务器启动时,在读取配置文件后,服​​务器将调用OPENVPN_PLUGIN_UP和OPENVPN_PLUGIN_ROUTE_UP函数。 在被调用函数的可变环境中,正在运行的服务器的主要参数被传送。


 OPENVPN_PLUGIN_UP { "route_netmask_1":"255.255.0.0", "daemon_start_time":"1545994898", "ifconfig_remote":"10.150.0.2", "local_1":"172.16.100.139", "script_context":"init", "config":"/usr/local/etc/openvpn/server150.conf", "link_mtu":"1622", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "verb":"2", "daemon_pid":"626", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "daemon_log_redirect":"1", "daemon":"1", "route_net_gateway":"172.16.100.1", "dev_type":"tun", "route_gateway_1":"10.150.0.2", "remote_port_1":"1200", "dev":"tun150", "pluginid":"0", "local_port_1":"1200", "route_network_1":"10.150.0.0" } 

 OPENVPN_PLUGIN_ROUTE_UP { "route_netmask_1":"255.255.0.0", "daemon_start_time":"1545994898", "redirect_gateway":"0", "ifconfig_remote":"10.150.0.2", "local_1":"172.16.100.139", "script_context":"init", "config":"/usr/local/etc/openvpn/server150.conf", "link_mtu":"1622", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "verb":"2", "daemon_pid":"626", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "daemon_log_redirect":"1", "daemon":"1", "route_net_gateway":"172.16.100.1", "dev_type":"tun", "route_gateway_1":"10.150.0.2", "remote_port_1":"1200", "dev":"tun150", "pluginid":"2", "local_port_1":"1200", "route_network_1":"10.150.0.0" } 

这些功能可用于在服务器启动或配置更改时发出警报。
连接客户端时,OpenVPN要求能够激活内部数据包过滤器。


 OPENVPN_PLUGIN_ENABLE_PF { "route_netmask_1":"255.255.0.0", "daemon_start_time":"1545994898", "redirect_gateway":"0", "ifconfig_remote":"10.150.0.2", "local_1":"172.16.100.139", "script_context":"init", "config":"/usr/local/etc/openvpn/server150.conf", "link_mtu":"1622", "pf_file":"/tmp/openvpn_pf_b7a18ca8fac838679ca87ada6b8a356.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "verb":"2", "daemon_pid":"626", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "daemon":"1", "daemon_log_redirect":"1", "dev_type":"tun", "route_gateway_1":"10.150.0.2", "remote_port_1":"1200", "dev":"tun150", "pluginid":"11", "local_port_1":"1200", "route_network_1":"10.150.0.0" } 

从转储中可以看到,出现了pf_file变量。 此文件应包含正在处理的当前会话的内部数据包筛选器的规则。
接下来,在OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY函数中检查用户的用户名和密码


 OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "IV_NCP":"2", "IV_COMP_STUB":"1", "daemon_start_time":"1545994898", "IV_LZ4":"1", "redirect_gateway":"0", "ifconfig_remote":"10.150.0.2", "untrusted_port":"1200", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "link_mtu":"1622", "pf_file":"/tmp/openvpn_pf_b7a18ca8fac838679ca87ada6b8a356.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_a3d0650a43b88ca1b5f305ce2c8f682.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"2", "IV_PLAT":"win", "daemon_pid":"626", "password":"12312312312312", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "remote_port_1":"1200", "dev":"tun150", "pluginid":"5", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" } 

这是唯一在明文环境中提供可变环境密码的地方。
此功能的结果应该是三个可能的答案。


 #define OPENVPN_PLUGIN_FUNC_SUCCESS 0 #define OPENVPN_PLUGIN_FUNC_ERROR 1 #define OPENVPN_PLUGIN_FUNC_DEFERRED 2 

如果服务器收到答案OPENVPN_PLUGIN_FUNC_DEFERRED,则“延迟”身份验证机制开始运行。 如我们所见,变量“ auth_control_file”出现在变量环境中,该变量的内容包含文件名,在该文件中将期望来自身份验证系统的响应。 答案是放在指定文件中的符号0(允许访问),1(拒绝访问)。 服务器参数“ hand-window”确定超时(以秒为单位),在此期间服务器将等待响应。 在等待期间,其他客户端的流量不会中断。


由于我们使用密码身份验证,因此不会调用证书验证功能OPENVPN_PLUGIN_TLS_VERIFY。 而是,立即调用OPENVPN_PLUGIN_TLS_FINAL,以确认会话的建立。


 OPENVPN_PLUGIN_TLS_FINAL { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "IV_NCP":"2", "IV_COMP_STUB":"1", "daemon_start_time":"1545994898", "IV_LZ4":"1", "redirect_gateway":"0", "ifconfig_remote":"10.150.0.2", "untrusted_port":"1200", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "link_mtu":"1622", "pf_file":"/tmp/openvpn_pf_b7a18ca8fac838679ca87ada6b8a356.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_a3d0650a43b88ca1b5f305ce2c8f682.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"2", "IV_PLAT":"win", "daemon_pid":"626", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "remote_port_1":"1200", "dev":"tun150", "pluginid":"10", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" } 

接下来,调用OPENVPN_PLUGIN_IPCHANGE,在更改客户端的IP地址之前被调用。


 OPENVPN_PLUGIN_IPCHANGE { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "trusted_ip":"172.16.111.168", "link_mtu":"1622", "IV_COMP_STUB":"1", "daemon_start_time":"1547319280", "IV_LZ4":"1", "redirect_gateway":"0", "common_name":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "ifconfig_remote":"10.150.0.2", "IV_NCP":"2", "untrusted_port":"1200", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "trusted_port":"1200", "pf_file":"/tmp/openvpn_pf_4fcad505693b33f97c4fe105df8681cb.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_321bb12075dc0e1b5440d227220bac5d.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"3", "IV_PLAT":"win", "daemon_pid":"52435", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "remote_port_1":"1200", "dev":"tun150", "pluginid":"3", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" } 

当内部DHCP服务器设置IP地址时,将调用OPENVPN_PLUGIN_CLIENT_CONNECT_V2函数。


 OPENVPN_PLUGIN_CLIENT_CONNECT_V2 { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "trusted_ip":"172.16.111.168", "link_mtu":"1622", "IV_COMP_STUB":"1", "daemon_start_time":"1547319280", "IV_LZ4":"1", "dev":"tun150", "common_name":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "time_ascii":"Sat Jan 12 18:54:48 2019", "ifconfig_remote":"10.150.0.2", "IV_NCP":"2", "untrusted_port":"1200", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "trusted_port":"1200", "pf_file":"/tmp/openvpn_pf_4fcad505693b33f97c4fe105df8681cb.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_321bb12075dc0e1b5440d227220bac5d.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"3", "IV_PLAT":"win", "daemon_pid":"52435", "time_unix":"1547319288", "redirect_gateway":"0", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "remote_port_1":"1200", "ifconfig_pool_local_ip":"10.150.0.5", "pluginid":"9", "ifconfig_pool_remote_ip":"10.150.0.6", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" } 

在变量环境中,将出现包含隧道参数“ ifconfig_pool_local_ip”和“ ifconfig_pool_remote_ip”的变量。


当OpenVPN服务器学习IP地址的连接并路由到它们时,将调用OPENVPN_PLUGIN_LEARN_ADDRESS函数。 退出此功能后,将激活应用文件中包过滤器设置的过程。 在这种情况下,环境变量OPENVPN_PLUGIN_LEARN_ADDRESS对应于阶段OPENVPN_PLUGIN_CLIENT_CONNECT_V2。


 fa56bf61-.../172.16.111.168:1200 ----- pf_check_reload : struct pf_context ----- fa56bf61-.../172.16.111.168:1200 enabled=1 fa56bf61-.../172.16.111.168:1200 filename='/tmp/openvpn_pf_343330698e4acdea34c8a8c7fb87d861.tmp' fa56bf61-.../172.16.111.168:1200 file_last_mod=1547319124 fa56bf61-.../172.16.111.168:1200 n_check_reload=1 fa56bf61-.../172.16.111.168:1200 reload=[1,15,1547319125] fa56bf61-.../172.16.111.168:1200 ----- struct pf_set ----- fa56bf61-.../172.16.111.168:1200 kill=0 fa56bf61-.../172.16.111.168:1200 ----- struct pf_subnet_set ----- fa56bf61-.../172.16.111.168:1200 default_allow=ACCEPT fa56bf61-.../172.16.111.168:1200 ----- struct pf_cn_set ----- fa56bf61-.../172.16.111.168:1200 default_allow=DROP fa56bf61-.../172.16.111.168:1200 12345678-90da-11e8-bf33-005056a12a82-1234567 ACCEPT fa56bf61-.../172.16.111.168:1200 fa56bf61-90da-11e8-bf33-005056a12a82-1234567 ACCEPT fa56bf61-.../172.16.111.168:1200 ---------- fa56bf61-.../172.16.111.168:1200 fa56bf61-90da-11e8-bf33-005056a12a82-1234567 ACCEPT fa56bf61-.../172.16.111.168:1200 12345678-90da-11e8-bf33-005056a12a82-1234567 ACCEPT fa56bf61-.../172.16.111.168:1200 -------------------- 

当客户端断开连接时,将调用OPENVPN_PLUGIN_CLIENT_DISCONNECT函数。


 OPENVPN_PLUGIN_CLIENT_DISCONNECT { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "trusted_ip":"172.16.111.168", "link_mtu":"1622", "IV_COMP_STUB":"1", "daemon_start_time":"1547319280", "IV_LZ4":"1", "dev":"tun150", "common_name":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "time_ascii":"Sat Jan 12 18:54:48 2019", "bytes_received":"30893", "IV_NCP":"2", "untrusted_port":"1200", "ifconfig_remote":"10.150.0.2", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "trusted_port":"1200", "pf_file":"/tmp/openvpn_pf_4fcad505693b33f97c4fe105df8681cb.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_4bdddbada2885cde42cd3cb1b85d77e5.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"3", "IV_PLAT":"win", "daemon_pid":"52435", "time_unix":"1547319288", "redirect_gateway":"0", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "time_duration":"3781", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "bytes_sent":"22684", "remote_port_1":"1200", "ifconfig_pool_local_ip":"10.150.0.5", "pluginid":"7", "ifconfig_pool_remote_ip":"10.150.0.6", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" } 

在可变环境中,添加了连接持续时间和用户流量。


如您所见,由于不同调用中的数据很多,使用C编程语言(C ++)编写和调试插件将是一项非常耗时的任务。
为了扩展功能,决定先为内部项目创建一个“奇迹”,然后将其放入公共领域:)
在长期阅读OpenVPN源代码和各种高度专业化的插件示例之后,编写了一个项目,该项目使用Python作为会话处理逻辑的编程语言。 该代码是使用C语言连接到OpenVPN的插件,该插件通过Python中的c-api参考将所有请求发送到该插件到模块。


OpenVPN插件python代理


为什么是Python模块?


直接使用python文件的Python c-api参考在加载python库时无法正常工作。


如何运作?


在OpenVPN中初始化插件后,插件会返回其可以提供的所有功能的屏蔽列表。 当下一个连接阶段或内部事件发生时,OpenVPN从插件调用相应的功能。 插件将环境变量和传递给函数的参数转换为结构,初始化python并将该结构传递给python模块的相应过程。 该过程返回插件的三个答案之一(0-成功,1-错误,2-延迟)。 响应由OpenVPN转换并返回。


请注意,所有模块调用都是“无状态”的,这意味着该过程将不记得也不知道其他调用之前发生了什么。 您只能关注从OpenVPN传递到插件的可变环境。


在python模块内部,您可以通过连接必要的库和资源来实现任何逻辑。 如果您不确定检查的速度,请使用“待定”确认。


通过使用连接到服务的用户分组,可以通过pf_file来微调用户和其他资源之间的网络交互。 反过来,通过连接用于监视的插件,始终可以通过OpenVPN管理界面管理客户端会话。


在项目测试期间,开发了一种密码生成机制,类似于jwt令牌,但大小较小。


重点很简单。 令牌包含客户端标识符和访问的到期日期。 要对令牌进行签名,将使用带有私钥的HMAC_SHA1。 在对令牌进行签名后,文本内容将被签名破坏并转换为base64。 因此,获得令牌的“密封”。 密封令牌用作用户密码。 如果发生未经授权的数据块更改,则xor中断,如果xor中断,则签名验证也将中断。 如果没有私钥,则无法更改签名。


如果您不想手动控制密码的时间,请生成这样的令牌,然后在插件内部检查其有效性,而无需调用外部服务。 此方案对于在一定时间内生成会话密码非常方便。 同时,您可以将令牌的内容传输到外部控制系统,它将配置为在令牌过期后自行断开与用户的连接。


希望本文中的信息对您有所帮助。
感谢您抽出宝贵的时间阅读它。
如果您有任何疑问,我将尽力回答。


©Aborche 2019
阿博什

Source: https://habr.com/ru/post/zh-CN435802/


All Articles