![在 Mac OS X 上使用 pf.conf 阻止传出流量,除非 OpenVPN 连接处于活动状态](https://linux22.com/image/1327987/%E5%9C%A8%20Mac%20OS%20X%20%E4%B8%8A%E4%BD%BF%E7%94%A8%20pf.conf%20%E9%98%BB%E6%AD%A2%E4%BC%A0%E5%87%BA%E6%B5%81%E9%87%8F%EF%BC%8C%E9%99%A4%E9%9D%9E%20OpenVPN%20%E8%BF%9E%E6%8E%A5%E5%A4%84%E4%BA%8E%E6%B4%BB%E5%8A%A8%E7%8A%B6%E6%80%81.png)
我已经能够使用 pf.conf 拒绝所有与外部网络的连接,除非我的 OpenVPN 连接处于活动状态。但是,如果通过关闭和打开笔记本电脑盖或关闭和打开 Wi-Fi 来中断连接,我就会失去 Wi-Fi 连接。
- 我在使用 Mac OS 10.8.1。
- 我通过 Wi-Fi 连接到网络(从不同位置,包括公共 Wi-Fi)。
- OpenVPN 连接是使用 Viscosity 设置的。
我在以下位置设置了以下数据包过滤规则/etc/pf.conf
# Deny all packets unless they pass through the OpenVPN connection
wifi=en1
vpn=tun0
block all
set skip on lo
pass on $wifi proto udp to [OpenVPN server IP address] port 443
pass on $vpn
我使用 启动数据包过滤服务sudo pfctl -e
并使用 加载新规则sudo pfctl -f /etc/pf.conf
。
我还编辑/System/Library/LaunchDaemons/com.apple.pfctl.plist
并修改了该行<string>-f</string>
,<string>-ef</string>
以便数据包过滤器在系统启动时启动。
这一切一开始似乎都很顺利:只有 OpenVPN 连接处于活动状态,应用程序才能连接到网络,因此我永远不会通过不安全的连接泄露数据。
但是,如果我关闭并重新打开笔记本电脑盖或关闭 Wi-Fi 并再次打开,Wi-Fi 连接就会丢失,并且我会在状态栏中的 Wi-Fi 图标中看到一个感叹号。单击 Wi-Fi 图标会显示“警告:无互联网连接”消息:
为了重新连接,我必须断开并重新连接 Wi-Fi,有时要五六次,然后“警告:无互联网连接”消息才会消失,我才能再次打开 VPN 连接。其他时候,Wi-Fi 警报会自动消失,感叹号会消失,我就可以再次连接。无论哪种方式,重新连接可能需要五分钟或更长时间,这可能会令人沮丧。
删除该行block all
可以解决问题(但会允许不安全的连接),因此似乎我阻止了 Apple 需要的一项服务,以便重新获得并确认 Wi-Fi 连接。我尝试过:
pass on $wifi proto icmp all
通过添加到 pf.conf 来启用 icmp- 通过添加启用 DNS 解析
pass on $wifi proto udp from $wifi to any port 53
- 尝试通过记录被阻止的数据包(通过更改
block all
为block log all
)来了解更多信息,但 OS X 下的日志记录似乎被禁用,因为查看sudo tcpdump -n -e -ttt -i pflog0
日志的结果为“tcpdump:pflog0:不存在这样的设备”。
这些都无法帮助更快地重新建立 Wi-Fi 连接。
我还能做些什么来确定需要哪些服务才能重新获得 Wi-Fi 连接,或者我应该向 pf.conf 添加哪些规则以使 Wi-Fi 重新连接更加可靠?
答案1
通过使用 Little Snitch 监控网络连接,我发现 Apple 在后台使用 mDNSResponder 应用程序来检查 Wi-Fi 连接是否可用。mDNSResponder 向名称服务器发送 UDP 数据包以检查连接性并将主机名解析为 IP。
更改我之前允许的 UDP 规则全部通过 Wi-Fi 的 UDP 数据包允许 mDNSResponder 连接,这意味着 Wi-Fi 现在可以在断开连接后第一次重新连接。为了将来对其他人有所帮助,我最终的 pf.conf 包括 Apple 针对 Mountain Lion 的默认规则,如下所示:
#
# com.apple anchor point
#
scrub-anchor "com.apple/*"
nat-anchor "com.apple/*"
rdr-anchor "com.apple/*"as
dummynet-anchor "com.apple/*"
anchor "com.apple/*"
load anchor "com.apple" from "/etc/pf.anchors/com.apple"
#
# Allow connection via Viscosity only
#
wifi=en1 #change this to en0 on MacBook Airs and other Macs without ethernet ports
vpn=tun0
vpn2=tap0
block all
set skip on lo # allow local traffic
pass on p2p0 #allow AirDrop
pass on p2p1 #allow AirDrop
pass on p2p2 #allow AirDrop
pass quick proto tcp to any port 631 #allow AirPrint
pass on $wifi proto udp # allow only UDP packets over unprotected Wi-Fi
pass on $vpn # allow everything else through the VPN (tun interface)
pass on $vpn2 # allow everything else through the VPN (tap interface)
不幸的是,这意味着少数使用 UDP 协议的应用程序现在可以在 Wi-Fi 上泄露数据,例如 ntpd(用于时间同步)和 mDNSResponder。但这似乎仍然比允许数据在不受保护的情况下通过 TCP 传输要好,而大多数应用程序都使用 TCP。如果有人对改进此设置有任何建议,欢迎发表评论或进一步回答。
答案2
你不需要允许全部UDP。mDNS 中的“m”表示“多播”,它使用称为“链路本地多播地址”的特定多播目标 IP 地址和UDP
端口号5353
。
这意味着,在上述解决方案中,您不必要地允许所有 65535 个 UDP 端口的流量绕过 VPN,从而绕过全球所有 37 亿个可路由 IP 地址。您会惊讶于有多少应用程序使用 UDP,因此您大大违背了当 VPN 中断时阻止传出流量的初衷。
为什么不使用这个规则呢:
pass on $wifi proto udp to 224.0.0.251 port 5353
防火墙配置的一个非常重要的经验法则是,当通过防火墙设置例外时,始终尝试使用尽可能最具体的规则。有时,这种具体性是以牺牲便利性和易用性为代价的,例如,您可能会发现还有其他一些需要通过的本地链路协议,因此又添加了另一条特定规则。
如果您替换上述规则并发现原来的 wifi 问题再次出现,那么您的 PF 可能阻止了 DHCP,即用于自动配置网络设备 IP 地址的协议。(在家庭网络中,通常您的宽带路由器将是您的 DHCP 服务器)。您需要允许 DHCP 的规则将是:
pass on $wifi proto udp from 0.0.0.0 port 68 to 255.255.255.255 port 67
*注意:您可能需要替换0.0.0.0
。any
您DHCPREQUEST
的计算机首次发送的数据包具有源地址,0.0.0.0
因为在那个阶段,您的计算机还没有 IP 地址。
老实说,我更倾向于使用any
。另一个选择是删除任何源规范,即pass on $wifi proto udp to 255.255.255.255 port 67
,但这意味着我们丢失了规则的源端口部分,尽可能具体始终是最安全的选择。
希望对您有所帮助。以下是一些有用的链接:
移动DNS:http://en.wikipedia.org/wiki/Multicast_DNS#Packet_structure
DHSP:http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol#DHCP_discovery
答案3
为了创造PF 规则 以一种“简单”的方式,识别现有的活动接口,包括当前的(vpn)接口这么小终止开关可以使用程序,
仍在进行中,但可以成为识别外部 IP 和活动接口以便正确创建防火墙规则的一个良好开端。
-i
使用(info) 选项的示例或输出:
$ killswitch -i
Interface MAC address IP
en1 bc:57:36:d1:82:ba 192.168.1.7
ppp0 10.10.1.3
public IP address: 93.117.82.123
传递服务器 ip -ip
:
# --------------------------------------------------------------
# Sat, 19 Nov 2016 12:37:24 +0100
# sudo pfctl -Fa -f ~/.killswitch.pf.conf -e
# --------------------------------------------------------------
int_en1 = "en1"
vpn_ppp0 = "ppp0"
vpn_ip = "93.117.82.123"
set block-policy drop
set ruleset-optimization basic
set skip on lo0
block all
pass on $int_en1 proto udp to 224.0.0.251 port 5353
pass on $int_en1 proto udp from any port 67 to any port 68
pass on $int_en1 inet proto icmp all icmp-type 8 code 0
pass on $int_en1 proto {tcp, udp} from any to $vpn_ip
pass on $vpn_ppp0 all
远非完美,但工作正在进行中,更多信息/代码可以在这里找到:https://github.com/vpn-kill-switch/killswitch
答案4
-- 作为补充 --
您可能需要添加以下行:
pass on $wifi inet6 proto udp from any to FF02:0000:0000:0000:0000:0000:0000:00FB port 5353
允许 mDNS 在 ipv6 上运行