Mac OS X上的奇怪防火墙相关套接字泄漏

时间:2014-08-30 20:09:25

标签: macos sockets resource-leak

我在Mac OS X中遇到了一个奇怪的套接字泄漏问题我无法解释。我有一个开源守护进程(olad),在其他端口之间侦听9010(tcp),9090(tcp)和6454(udp)。当守护进程退出时,netstat显示端口6454仍然打开并正在侦听:

$ netstat -f inet -n | grep 6454
<nothing>
$ olad/olad 
<exit server>
$ netstat -f inet -n | grep 6454
udp4       0      0  *.6454                 *.* 

但是,lsof没有显示套接字:

$ lsof -i 4 -P | grep 6454
<nothing>

一旦系统处于此状态,通过向端口发送数据包,我可以看到队列数增加:

$ netstat -f inet -n | grep 6454
udp4     612      0  *.6454                 *.*  

仅当首选项中启用了应用程序防火墙时才会发生这种情况 - &gt;安全与安全隐私它是第一次运行二进制文件。也就是说,如果我禁用防火墙,则不会发生泄漏。或者,如果防火墙已启用,则在弹出对话框的第一次运行后,我单击“接受”,则问题不再出现。

套接字泄漏后,禁用防火墙无法释放它。

我已经确认我在程序退出之前在所有套接字上调用close()并且没有调用fork()或新线程。

我一直试图缩小bug案例,但似乎是pipe(),socket(),bind(),listen(),ioctl(),fnctl()之间相当复杂的交互。选择()。更改呼叫顺序并删除端口9010和9090上的侦听会导致问题消失。

有没有人建议如何继续调试此内容,或者有关Mac应用程序防火墙内部如何工作的指南?

2 个答案:

答案 0 :(得分:1)

事实证明,即使在使用它的进程关闭后,防火墙也会“记住”先前绑定的UDP端口的套接字选项。这导致UDP端口由“netstat -n -f inet”列出,而没有任何进程从中接收。从那时起,任何将套接字绑定到该端口的尝试都将如预期的那样,当防火墙关闭时一切正常。

正如您已经发现的那样,OS-X需要SO_REUSEPORT而不是SO_REUSEADDR来避免防火墙出现这种奇怪的状态问题。此外,刷新防火墙状态的唯一方法是重新启动。有趣的是,你需要在重启后启动服务器之前通过几分钟。出于某种原因,我不想进一步研究,如果你在防火墙完成初始化之前启动服务器,你就不会得到防火墙弹出窗口,要求你允许访问,你的服务器仍然“永远”(即直到下次重新启动)或直到你重建服务器二进制文件)被防火墙阻止。

答案 1 :(得分:1)

我们在Mac OS 10.14上的支持网络的应用程序中也遇到了该问题。经过调查的结果是一个Python脚本,很好地重现了该问题。

import socket

udpsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udpsock.bind(("0.0.0.0", 7744))

tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpsock.bind(("0.0.0.0", 17744))
tcpsock.listen()

print("Listening ...")

while True:
    data, addr = udpsock.recvfrom(16)
    print("Received data: ", data)

在启用应用程序防火墙并将发送方发送数据到UDP端口7744的情况下,操作系统会在首次启动时提示用户接受传入的网络流量,并且一旦允许,脚本将接收数据包。但是,在停止脚本之后,套接字将保持打开状态,而没有使用该套接字的用户空间任务,并且随后尝试bind()再次尝试将导致Address already in use,无论是否SO_REUSE_PORT和/或设置了SO_REUSE_ADDR。此后,必须重新启动计算机,以使侦听器再次访问该UDP端口。

$ netstat -an -pudp | grep 7744
udp4     0      0  *.7744                 *.*

请注意,这仅在还注册了TCP侦听器以及脚本运行时正在接收UDP数据包时发生。这也可能是由其他情况引起的,但以上是我们可以将问题归结为最简化的示例。

因此,这是Mac OS中已经存在至少4年的内核错误,显然会影响同时具有UDP和TCP侦听器的所有任务。在解决此问题之前,要求用户禁用防火墙选项。