![使用 iptables 和 NetworkManager 调度脚本的 vpn killswitch](https://linux22.com/image/901949/%E4%BD%BF%E7%94%A8%20iptables%20%E5%92%8C%20NetworkManager%20%E8%B0%83%E5%BA%A6%E8%84%9A%E6%9C%AC%E7%9A%84%20vpn%20killswitch.png)
我认为这个方法可行如下:
- VPN 连接中断
- 然后,NetworkManager 在连接发生改变时运行调度脚本,并查看
vpn-down
操作。 - 脚本看到该
vpn-down
操作并设置 iptables 来阻止所有流量 - 我使用 NetworkManager 小程序选择 vpn 连接
- NetworkManager 在连接发生变化时运行调度脚本,查看
pre-up
操作。 - 脚本看到该
pre-up
操作并设置 iptables 以再次允许流量 - 现在 iptables 已恢复以允许流量,vpn 连接已建立。
但在第 5 步时,事情就出问题了。NetworkManager 并没有运行目录中的脚本/etc/NetworkManager/dispatcher.d/pre-up.d
,而是一直转来转去,直到我收到网络连接失败通知(因为 iptables 规则在第 3 步被更改为阻止所有内容——请参阅下文了解具体规则)。事实上,pre-up.d 中的脚本似乎根本没有运行(我让它将收到的参数记录到 /tmp 中的文件中,但什么都没有记录下来。)
所以我的问题是,为什么 iptables 会阻止调度程序脚本运行(或者换句话说,为什么当 iptables 设置为阻止除 lo 之外的所有内容时,NetworkManager 不会运行这些脚本),以及如何配置 iptables 以阻止所有流量,但也允许 NetworkManager 有足够的余地来运行pre-up
调度程序脚本(这样,在尝试重新连接到 vpn 时,调度程序可以恢复允许的 iptables 规则)?
(注意:第 3 步中的脚本将 iptables 设置为:
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
)
编辑:这是脚本中的全部pre-up.d
内容。它被精简了,因为我试图查看它是否正在运行(它没有运行)。我希望它做的只是将它获得的参数输出到日志中,但是当 iptables 受到限制时,我什么也没得到:
#!/usr/bin/env python3
import sys
import logging
from time import gmtime, strftime
logging.basicConfig(filename='/tmp/10test.log', filemode='a', level=logging.DEBUG)
logger = logging.getLogger(name)
iface = sys.argv[1]
action = sys.argv[2]
now = strftime('%Y-%m-%d %H:%M:%S', gmtime())
logging.info(f'time is {now}')
logging.info(f'interface is {iface}')
logging.info(f'action is {action}')
edit2:这是在步骤 #3 中成功执行的脚本。请注意,两个脚本具有相同的权限:
#!/usr/bin/env python3
import sys
import subprocess
import logging
import os
logging.basicConfig(filename='/tmp/pypia.log', filemode='a', level=logging.DEBUG)
logger = logging.getLogger(__name__)
config_dir = '/etc/pypia'
if not os.path.isdir(config_dir):
logging.debug('making pypia config directory in /etc')
os.mkdir(config_dir)
action = sys.argv[2]
logging.debug(f'action is {action}')
if not os.path.isfile('/tmp/pia_ks_status.conf'):
logging.info('kill switch status file not found. exiting.')
sys.exit(0)
with open('/tmp/pia_ks_status.conf', 'r') as f:
logging.debug('loading kill switch status file from /tmp')
status = f.readline().strip()
logging.info(f'status is {status}')
if (status == 'active') and (action == 'vpn-down'):
logging.debug('writing iptables backup file...')
with open(os.path.join(config_dir, 'iptables.bak'), 'w') as f:
subprocess.call(['iptables-save'], stdout=f)
logging.debug('using nmcli to shut off all connected devices...')
subprocess.call(['iptables', '-A', 'INPUT', '-i', 'lo', '-j', 'ACCEPT'])
subprocess.call(['iptables', '-A', 'OUTPUT', '-o', 'lo', '-j', 'ACCEPT'])
subprocess.call(['iptables', '-P', 'INPUT', 'DROP'])
subprocess.call(['iptables', '-P', 'OUTPUT', 'DROP'])
subprocess.call(['iptables', '-P', 'FORWARD', 'DROP'])