簡體   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