使用Unix域套接字连接()和完整的backlog

12

当UNIX域套接字的监听队列已满时,大多数系统上的connect(2)会失败并返回ECONNREFUSED。最好能够返回EAGAIN。

原因是能够区分死套接字(节点在文件系统中存在但没有进程再监听)和队列已满两种情况非常有用。当移植一些Linux软件时,我遇到了这个问题,其中有一些代码用于清除无效的套接字,但如果可以通过垃圾邮件来填充它们的后备队列以使代码被欺骗而删除套接字,那么这就是一个安全漏洞。

只有Linux返回EAGAIN;AIX、Solaris和Darwin遵循BSD的行为(在每个系统上进行了测试)。

POSIX并没有将EAGAIN作为connect()的可能返回代码之一,(链接),所以这里可能存在某些符合性问题。

要让所有人与Linux保持一致,最好的方法是什么?我可以向Oracle、Apple、FreeBSD提交错误报告,并在每个组织的邮件列表上争论。还是应该纠缠标准机构(Austin group)的某个人?即使优点是显而易见的,试图让每个人都改变这里的做法是否明智?


3
我投票关闭这个问题,因为它似乎涉及申请更改 POSIX 标准的流程,而不是关于编程的内容。我认为此问题不适合讨论。 - Useless
2个回答

2
无论您尝试更改标准还是更改供应商实现的connect()方式,我认为从软件的角度来看,这都不会有任何区别。ECONNREFUSED和EAGAIN都应被视为重试。区分这两种情况可能允许您在客户端上编写更具体的诊断消息,但重试逻辑应该相同。即使侦听器当前不存在,它也可能最终存在,因此应尝试重试。
try_again:
    rc = connect(s, (void *)&addr, sizeof(addr));
    if (rc == 0) return connect_succeeded(s, &addr);
    switch (errno) {
    case EAGAIN:
    case ECONNREFUSED:
        if (should_try_again(retries++)) {
            goto try_again;
        }
        break;
    case EINTR:
        goto try_again;
    default:        
        break;
    }
    return connect_failed(s, errno);

1
从客户端的角度来看,返回哪个并没有什么区别...但对于服务器来说,这是一个很大的区别!在启动时,您需要检测死亡套接字文件(其中侦听进程已经消失),以便您可以删除套接字,这依赖于能够检测进程当前是否正在运行。 一个锁定文件可能是更好的方法 - 但这是一些遗留软件(不幸的是),所以我们需要一种方法来检测套接字是否死亡。 在这种情况下,更详细的错误信息会有所帮助。 - Nicholas Wilson
1
@NicholasWilson 我之所以回答是针对特定客户端的,是因为问题聚焦于“connect”行为,这通常是一个客户端API。在Linux系统上,我避免使用基于文件系统的套接字,而使用抽象套接字。在非Linux POSIX系统上,我可能会选择在内部接口(回环)上使用TCP。也就是说,我的服务器隐式地避免了这个问题。如果我必须处理路径名套接字,我会使用父进程启动服务器,并根据子进程寿命管理路径名套接字寿命。 - jxh

0

像大多数事情一样,如果您能说服源头进行移动,那么所有用户都必须遵守。因此,让POSIX 修复问题 当然是最好的。然后所有实现都必须遵守。

另一个解决方案是使用其正常工作的系统,例如仅使用Linux机器(在这种情况下)。此外,在Linux上,您可以调整内核并使其以某种方式工作(这也适用于BSD)。

现在,我对此问题的看法是,主要问题似乎是一个流氓进程试图打开套接字来接收消息,而不是预期服务。我的问题是:这种情况经常发生吗?

如果您使用类似于systemctl的系统,则将只有一个服务实例正在运行。如果您尝试在服务的该点打开AF_UNIX套接字,则确实只有您自己在尝试这样做。因此,删除文件不是问题。

如果允许流氓软件在您的系统上运行(即它是公共的,并且您有许多用户可以访问,就像旧时代人们会telnet到服务器一样),则也许您需要改用TCP或UDP连接。

最后,如果另一个软件能够打开那个AF_UNIX套接字,那么我认为无论如何你都会遇到麻烦,因为在那个流氓软件存在的情况下,你的服务可能正在运行,而这个流氓软件 (1) 删除了你的套接字,(2) bind() 了一个新的套接字,(3) 你的 新客户现在正在与那个流氓软件交互,而不是与你的服务交互,尽管你仍在运行并侦听连接... 在一个隐藏的文件套接字上。(请注意,旧的客户端将继续与您的服务交流,但任何重新连接的客户端都将与那个流氓软件交流)。

所以...你的问题出在哪里?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接