使用 iptables 和 NetworkManager 调度脚本的 vpn killswitch

使用 iptables 和 NetworkManager 调度脚本的 vpn killswitch

我认为这个方法可行如下:

  1. VPN 连接中断
  2. 然后,NetworkManager 在连接发生改变时运行调度脚本,并查看vpn-down操作。
  3. 脚本看到该vpn-down操作并设置 iptables 来阻止所有流量
  4. 我使用 NetworkManager 小程序选择 vpn 连接
  5. NetworkManager 在连接发生变化时运行调度脚本,查看pre-up操作。
  6. 脚本看到该pre-up操作并设置 iptables 以再次允许流量
  7. 现在 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'])

相关内容