繁体   English   中英

connect() 与 unix 域套接字和完整的积压

[英]connect() with unix-domain socket and full backlog

当 STREAM unix 域套接字的侦听积压已满时, connect(2)在大多数带有 ECONNREFUSED 的系统上失败。 它最好返回 EAGAIN。

原因是能够区分死套接字(节点存在于文件系统中,但不再有进程侦听)和完全积压的两种情况非常有用。 我在移植一些 Linux 软件时遇到了这个问题,这些软件有一些代码来清理死套接字,但如果代码可以通过向它们发送垃圾邮件来填充它们的积压来欺骗它们删除套接字,那么这是一个安全漏洞。

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

POSIX 没有将 EAGAIN 列为 connect() ( link ) 的可能返回码,因此此处可能存在一些合规性问题。

让每个人都适应 Linux 的最佳途径是什么? 我可以去向 Oracle、Apple 和 FreeBSD PR 提交错误报告,并在每个组织的邮件列表上进行斗争。 或者我应该在标准机构(奥斯汀小组)中纠缠某人? 即使优势很明显,尝试让每个人都改变这里是否可取?

无论您是否尝试更改标准,或者更改供应商实现connect() ,我认为从软件的角度来看,都没有任何区别。 ECONNREFUSEDEAGAIN都应视为重试。

区分这两种情况可能会让您在客户端编写更具体的诊断消息,但重试逻辑应该是相同的。 即使侦听器当前不存在,它也可能最终存在,因此应尝试重试。

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);

与大多数事情一样,如果您可以说服消息来源采取行动,那么所有用户都必须遵守。 所以让 POSIX解决这个问题当然是最好的。 那么所有的实现都必须遵守。

另一种解决方案是使用它工作的系统。 即只使用 Linux 机器(在这种情况下)。 同样使用 Linux,您可以调整内核并使其以一种或另一种方式工作(这在 BSD 中也是可行的)。

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

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

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

最后,如果另一个软件能够打开那个AF_UNIX套接字,我认为无论如何你都会遇到麻烦,因为你的服务可以在流氓软件(1)删除你的套接字时运行,(2) bind()重新启动,( 3)您的新客户现在正在与该流氓软件对话,而不是您的服务,即使您仍在运行并侦听连接......在隐藏的文件套接字上。 (请注意,旧客户端将继续与您的服务对话,任何重新连接的客户端都将与流氓软件对话)。

所以……你的问题在哪里?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM