OpenVPN连接成功后,我该如何运行脚本?

如何将脚本与OpenVPN关联,以便在VPN成功连接时运行?

你是说客户的情况吗?你使用的是什么软件?OpenVPN还是一个封装(如NetworkManager)? - Lekensteyn
@Lekensteyn,包装器network-manager-openvpn - Oxwivi
7个回答

network-manager-openvpn不提供此功能,您必须直接使用openvpn

连接时传递--script-security 2 --up /path/to/your/script给它。如果您正在使用位于/etc/openvpn/的配置文件,请将以下行追加到您的配置文件中:

script-security 2
# run /etc/openvpn/up.sh when the connection is set up
up /etc/openvpn/up.sh

OpenVPN manpage中:

--script-security level [method] 这个指令提供了对OpenVPN使用外部程序和脚本的策略级别控制。较低的级别值表示更严格的限制,较高的级别值表示更宽松的限制。级别的设置如下:
0 -- 严格禁止调用外部程序。 1 -- (默认)只调用内置的可执行文件,如ifconfig、ip、route或netsh。 2 -- 允许调用内置的可执行文件和用户定义的脚本。 3 -- 允许通过环境变量将密码传递给脚本(可能不安全)。
--up cmd 在成功打开TUN/TAP设备(pre --user UID更改)后运行的Shell命令。up脚本非常有用,可以指定路由命令,将目标为私有子网的IP流量路由到VPN连接的另一端。
脚本执行顺序 --up 在TCP/UDP套接字绑定和TUN/TAP打开之后执行。 --down 在TCP/UDP和TUN/TAP关闭之后执行。

脚本执行有更多的事件,可以在手册页面中找到。

创建/etc/openvpn/up.sh并赋予执行权限(例如755或700)。以下是添加IPv6地址和路由的示例内容(仅用于教育目的,请勿直接复制):

#!/bin/sh
# add an IPv6 address to device $dev (environment variable)
ip -6 addr add 2001:db8::1:2/112 dev $dev
# and the IPv6 route for this net using gateway 2001:db8::1
ip -6 route add 2001:db8::1:0/112 via 2001:db8::1 dev $dev

请注意,此 up 脚本是以 root 用户身份运行的。如果您没有指定 UserGroup 设置,OpenVPN 将以 root 用户身份运行像 down 这样的脚本。

如果您不知道如何直接使用OpenVPN,请添加您当前的配置细节:连接类型(例如X509证书),网关端口,LZO压缩,TCP强制性,tap设备的使用,密码,HMAC和TLS。如果IP设置不是自动的,请提及它们。为了保护您的隐私,请勿提供实际地址。 - Lekensteyn
好的,我决定直接使用OpenVPN(是的,我有.conf文件),但如果连接丢失,它会自动重新连接吗?我如何让它在有网络连接时自动连接?最后,我不明白你在答案中提到的行应该添加在哪里。 - Oxwivi
我已经扩展了答案,直接使用 openvpn。在设置服务器时,我注意到当服务器宕机时,OpenVPN会尝试重新连接。不确定当你的网络接口断开时,OpenVPN是否会继续尝试连接。 - Lekensteyn
我的问题不是当网络接口断开时 - 当互联网连接丢失和恢复时,它确实会尝试重新连接。我只是希望在获得互联网连接时能够连接到VPN。 - Oxwivi
哦,这个脚本适用于所有的VPN连接吗?还有,请在回复时标记@Oxwivi,否则我将无法收到通知。 - Oxwivi
@Oxwivi:我刚刚测试了一下:如果网络管理器重新连接到互联网,服务器的路由会被删除,这导致OpenVPN无法连接到服务器(可能是因为我配置了OpenVPN来加密所有流量)。手动添加路由后,它又可以正常工作了。我认为你可以为网络管理器编写一个触发器。要添加路由,请运行:sudo ip route add <server-ip>/32 via <local-gateway> dev <device><local-gateway>是本地网关的IP地址,例如192.168.1.1<device>是你的网卡,例如eth0wlan0 - Lekensteyn
@Oxwivi:如果你指的是/etc/openvpn/up.sh脚本,不是的。它只适用于在/etc/openvpn/client.conf中定义的VPN。其他VPN(例如/etc/openvpn/company.conf)不受影响。 - Lekensteyn
为什么我要添加路由? - Oxwivi
@Oxwivi:如果你没有完全加密的连接,你就不必担心路由问题。否则,如果你不添加这个路由,你的电脑将不知道如何到达服务器,并会返回一个“无法到达主机”的错误。正如我在回答中所示,你可以使用up指定一个脚本(在建立连接后运行)。 - Lekensteyn
@Lekensteyn,所提到的VPN是一项商业服务 - 我正在使用免费版本。我不太了解OpenVPN配置文件的细节 - 你愿意帮我看一下吗?而且我不理解“script-security 2”,“up”和“down”等内容。 - Oxwivi
这里有一个RTFMman openvpn。我在我的回答中添加了更多细节。 - Lekensteyn
我需要使用这个答案中的第一个脚本:http://askubuntu.com/questions/26870/exempt-programs-from-using-active-vpn-connection/27735#27735 我应该使用 up 还是 down - Oxwivi
好的,你提到了“以便在VPN成功连接时运行”,所以我猜应该是启动 - Lekensteyn
谢谢!在可能的时候(24小时后)我会给你奖励,感谢你的辛苦。虽然在现实生活中这并不重要...无论如何,还有两件事情,我希望OpenVPN在我启动电脑并建立互联网连接后自动启动,并且这个VPN需要用户名和密码进行身份验证,我该如何设置? - Oxwivi
请阅读手册。您可以通过两种方式传递密码,一种是将明文密码放在命令中,另一种是让OpenVPN从文件中读取密码。我推荐使用后者。在您的配置文件中添加auth-user-pass /etc/openvpn/credentials.txt,并创建/etc/openvpn/credentials.txt文件,其中第一行为用户名,第二行为密码。(我之前不知道这个,是在手册中看到的 :) ) - Lekensteyn
我的问题是,如果VPN将自动连接,我就没有机会在命令行中手动输入身份验证。感谢您的所有帮助! - Oxwivi
只是让你知道,使用 up,我根本无法使其工作,它显示脚本无法执行外部程序或类似的错误信息。 - Oxwivi
确保脚本可执行:chmod +x script。请注意,除了0以外的退出代码表示失败。 - Lekensteyn
它在“down”这个方面运行正常,所以我就保持了这样的状态。 - Oxwivi
@Oxwivi:当连接丢失时,会调用down函数。手册中描述了这些事件的顺序。 - Lekensteyn
啊,我明白了...我的无能的限度还有待观察... - Oxwivi

关于问题:“如何将脚本与OpenVPN关联,以便在VPN成功连接时运行?”我想指出Lekensteyn提供了一个很好的答案。但是,在他回答这个问题的时候,对于如何在Ubuntu机器上提供openvpn命令行参数以启动openvpn,特别是在重启后仍然能够正常工作方面,还有一点不够清晰。

Ubuntu上的Openvpn命令行参数:

当然,可以使用任何可用的合法选项从命令行启动openvpn。但是,在Ubuntu机器上,如果想在重启后使用相同的命令行参数启动openvpn,应考虑编辑文件/etc/default/openvpn。请查看以下行:

# Optional arguments to openvpn's command line
OPTARGS="" 

community openvpn man page上的--script-security指令
--script-security level 该指令提供了对OpenVPN使用外部程序和脚本的策略级别控制。较低的级别值更为严格,较高的级别值更为宽松。级别的设置如下: 0 -- 严禁调用外部程序。 1 -- (默认)只调用内置的可执行文件,如ifconfig、ip、route或netsh。 2 -- 允许调用内置的可执行文件和用户定义的脚本。 3 -- 允许通过环境变量将密码传递给脚本(可能不安全)。
OpenVPN v2.3之前的版本还支持一个方法标志,指示OpenVPN应如何调用外部命令和脚本。这可以是execve或system。从OpenVPN v2.3开始,不再接受此标志。在大多数*nix环境中,已经使用execve()方法而没有任何问题。
一些指令(如--up)允许将选项传递给外部脚本。在这些情况下,请确保脚本名称不包含任何空格,否则配置解析器会因无法确定脚本名称的结束位置和脚本选项的开始位置而出错。

结合关于--up的简化部分

--up cmd
    在成功打开TUN/TAP设备(在--user UID更改之前)后运行命令cmd。
    cmd由脚本(或可执行程序)的路径组成,可选择跟随参数。
    路径和参数可以用单引号、双引号和/或反斜杠进行转义,并且应该用一个或多个空格分隔。

示例:

在我的机器上,使用openpvn server.conf配置文件,在我的/etc/default/openvpn文件中有以下行:

OPTARGS="
    --script-security 2
    --up /etc/openvpn/nat.sh
" 

顺便提一句,nat.sh专门用于为openvpn客户端设置网络地址转换,以便将私有网络流量路由到公共互联网上;这对于不信任公共WiFi接入点的情况非常有用。
除了在重新启动后能够正常重新开始之外,当/etc/openvpn/[client or server].conf/etc/default/openvpn文件正确配置后,可以使用以下命令启动或停止openvpn:
sudo service openvpn start
sudo service openvpn stop

其他可用于service openvpn的有用选项包括cond-restart,force-reload,reload, restart,soft-restart, start, status, stop

由于这是一个相当旧的帖子,我不确定是否仍然有兴趣。如果您仍然想使用NetworkManager连接到VPN,您可以添加一个简单的udev规则,如下所示:
KERNEL=="vpn0", RUN+="/PATH_TO_THE_SCRIPT/SCRIPT_NAME"
这将在创建VPN后运行任何脚本。

我在研究中偶然发现了解决这个问题的答案,我发现最好的解决方案是(使用openvpn服务器),具体如下:
创建一个要执行的脚本:
# nano /etc/openvpn/up.sh
<file:contents>
#!/bin/sh

# export >> /var/log/openvpn/openvpn-up.log
D=`date "+%Y-%m-%d %H:%M"`
echo "[$D] ($local_port_1:$proto_1) $X509_0_CN: $trusted_ip => $ifconfig_pool_remote_ip" >> /var/log/openvpn/openvpn-up.log
</file>

将以下行添加到openvpn配置文件中(通常为/etc/openvpn/server.conf)。在上面的答案中使用了up和down,这些是在服务器启动(重新启动)时使用的。指令client-connect(和client-disconnect)用于客户端连接(断开连接)时使用。
# nano /etc/openvpn/server.conf
<file:add>
script-security 2
client-connect /etc/openvpn/up.sh
</file>

如何在日志文件中包含客户端配置名称? - callisto

以下是OpenVPN的配置,用于在成功连接后发送邮件:
  1. 创建一个目录

    mkdir /mailOpenVPN
    
  2. 使其全球访问

    chmod 777 /mailOpenVPN
    
  3. vim /etc/openvpn/up.sh

    #! /bin/sh
    python3 /mailOpenVPN/sendMail.py $X509_0_CN $trusted_ip $ifconfig_pool_remote_ip
    
  4. 使 up.sh 可执行

    chmod +x /etc/openvpn/up.sh
    
  5. /etc/openvpn/server.conf 中添加

    script-security 2
    client-connect /etc/openvpn/up.sh
    
  6. 重新启动 OpenVPN 服务

    service openvpn restart
    
  7. vim /mailOpenVPN/sendMail.py

    import sys
    import smtplib
    import datetime
    
    
    smtp_user = "SENDER MAIL"
    smtp_pass = "PASS"
    recipients = "DEST MAIL"
    smtp_server = "smtp.gmail.com" # 这是我的情况,因为发件人是 Gmail
    
    try:
      now = str(datetime.datetime.now())
      subject = "家庭 VPN 的新连接"
      msg = "您好,主管:\n\n"
      msg += "检测到新的连接:\n"
      msg += "用户:" + str(sys.argv[1]) + "\n"
      msg += "公共 IP:" + str(sys.argv[2]) + "\n"
      msg += "分配的 IP:" + str(sys.argv[3]) + "\n"
      msg += "时间戳:" + str(now) + "\n\n"
      msg += "此致敬礼,\n"
      msg += "您的谦卑 Pi"
    
      sender = "OpenVPN Home"
      message = "From: OpenVPN Home\nSubject: {0}\n\n{1}".format(subject, msg)
    
      server = smtplib.SMTP_SSL(smtp_server, 465)
      server.ehlo()
      server.login(smtp_user, smtp_pass)
      server.sendmail(sender, recipients, message)
      server.close()
    except:
      pass
    

在跟随多个建议后,我遇到的一个问题是,在整个"Initialization Sequence Completed"之前执行了"--up"和"--route-up"。
对我来说,我必须在完全初始化之后打开端口。所以我按照以下步骤进行操作:
#1) 创建一个up.sh脚本,异步启动打开端口的脚本(proxyports.sh)。
#2) 创建一个down.sh脚本,在proxyports.sh中异步关闭已打开的端口。 up.sh的内容...
#!/bin/bash
( ( sleep 1 ; ~/proxyports.sh) & echo "Open the ports" )

proxyports.sh内容...

#!/bin/bash
HOME=/home/venkatdesu
PID=$(/usr/sbin/lsof -i :1080 | grep LISTEN|awk '{print $2}'|sort|uniq);
if [[ ! -z "$PID" ]]; then
  echo "SSH Socks Process $PID running with " $(ps "$PID");
  kill -9 $PID;
  sleep 1;
fi;
ssh -D 1080 -Nf iamdvr@10.0.0.94 
PID=$(/usr/sbin/lsof -i :1080 | grep LISTEN|awk '{print $2}'|sort|uniq);
echo "Socks running at $PID"

下降.sh内容...

#!/bin/bash
PID=$(/usr/sbin/lsof -i :1080 | grep LISTEN|awk '{print $2}'|sort|uniq);
if [[ ! -z "$PID" ]]; then
 echo "SSH Socks Process $PID running with " $(ps "$PID");
 kill -9 $PID;
fi;

正如@Lekensteyn所说,network-manager-openvpn不支持--up--down脚本。这在2011年是事实,可悲的是在2023年仍然如此。当我尝试配置处理推送的DNS服务器时,这对我来说是一个阻碍。
所以我在这里提交了一个问题。对于未来的读者:您可能希望检查此问题以了解进展情况。