2017-05-16 96 views
2

自從我打孔打孔幾天後,爲了有一種可靠的行爲,但我現在處於死路一條。TCP打孔(旁路監聽插座)

UDP打孔的偉大工程只需先發送一個數據包到遠端,並獲得遠程發送一個數據包的otherway,因爲它會通過源NAT降落。它相當可靠從我嘗試

但現在來TCP ...我不明白。

現在,我可以建立通過NAT的,但的連接只連接插座

A.connect(B) -> Crash agains't B's NAT, but open a hole in A's NAT. 
B.connect(A) -> Get in A's NAT hole, reach A's connecting socket. 

但現在,這sended連接的SYN數據包的兩個插座連接。

你會認爲我會做到這一點,通過2 NAT的連接,萬歲。

但問題是,這不是一個正常的行爲,並給予本文:http://www.brynosaurus.com/pub/net/p2pnat/,我應該可以有一個監聽插座並聯到連接插座。

所以我確實綁定了一個監聽套接字,它可以接受入站連接。

但入站連接總是由一個傾聽的連接插座,而不是陷入...

如:

#!/usr/bin/env python3 
from socket import * 
from threading import Thread 
Socket = socket 

# The used endpoints: 
LOCAL = '0.0.0.0', 7000 
REMOTE = 'remote', 7000 

# Create the listening socket, bind it and make it listen: 
Listening = Socket(AF_INET, SOCK_STREAM) 
Listening.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 
Listening.bind(LOCAL) 
Listening.listen(5) 

# Just start in another thread some kind of debug: 
# Print the addr of any connecting client: 
def handle(): 
    while not Listening._closed: 
     client, addr = Listening.accept() 
     print('ACCEPTED', addr) 
Thread(target=handle).start() 

# Now creating the connecting socket: 
Connecting = Socket(AF_INET, SOCK_STREAM) 
Connecting.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 
Connecting.bind(LOCAL) 

# Now we can attempt a connection: 
try: 
    Connecting.connect(REMOTE) 
    print('CONNECTED', Connecting.getpeername()) 
except Exception as e: 
    print('TRIED', type(e), e) 

現在有了這個腳本,只是同意在端口上一個朋友或其他任何人,並執行它的一端,Connecting.connect(...)應運行一點點(等待超時,因爲SYN數據包墜毀到遠處的NAT,但幸運的是在他自己的NAT中打開了一個洞),同時執行腳本另一端,現在Connecting.connect(...)會返回因爲它會連接。

最奇怪的部分是:Listening插座從未觸發

爲什麼?如何讓偵聽套接字通過連接套接字捕獲入站連接?

注意:關閉連接插座確實會在網絡上發送一些立即關閉該孔的東西,至少它會在我的網絡上發生。

2nd-Note:我在窗戶上。

編輯:主要的問題是,在任何情況下,該腳本輸出CONNECTED [...]而不是CLIENT [...],其中給出了一些講座不應該發生。

+0

您是否試圖在偵聽端獲取數據包捕獲?你看到遠程端的SYN請求嗎? –

+0

是的,正如我所說,每個雙方插座(遠程/本地)做建立連接,但不是在'Listening'插座... – WKnight02

回答

1

於是,經過更多的測試和閱讀,這裏就是我來:

事實上,它是可能綁定偵聽套接字和套接字在同一地址(ip,端口)上建立出站連接。

但插槽的行爲在很大程度上取決於系統/ TCP協議棧的實現,在4.3節http://www.brynosaurus.com/pub/net/p2pnat/作爲mentionned:在TCP打洞什麼客戶端應用程序與觀察他們的插座發生

取決於所涉及的時間安排和TCP實施。假設一個的第一個外出的SYN包到的公共端點由NAT 下降,但的第一個後續SYN包到一個的公共端點獲得通過,以一個之前A的TCP重新傳輸其SYN。根據所涉及的操作系統上,兩件事情之一可能會發生:

,對於進入的SYN匹配的會話端點的出站會話的 一個試圖發起
  • 一個的TCP實施公告。 A的TCP堆棧因此將此新會話與本地應用程序連接()到B的公共端點的套接字相關聯。應用程序的異步connect()調用成功,並且應用程序的偵聽套接字沒有任何反應。
    由於所接收的SYN數據包不包括用於的ACK的早先出站SYN,的TCP回覆的帶有SYN-ACK分組公共端點,則SYN部分爲僅一個重播A的原始出站SYN,使用相同的序列號。一旦B的TCP接收到A的SYN-ACK,它以其自己的ACK作出響應,並且TCP會話在兩端都進入連接狀態。

  • 另外,一個的TCP實現可能,而不是發現一個有一個活躍的監聽套接字端口等待傳入的連接嘗試上。由於的SYN看起來像傳入的連接嘗試,一個的TCP創建與新的TCP會話關聯的新流套接字和手這個新的socket通過應用程序的下一個接受()調用的應用程序在它的聽筒上。 的TCP然後響應用SYN-ACK如上,和TCP連接建立進行照常爲客戶機/服務器式的連接。
    由於的現有的出站連接()嘗試使用)的源和目的地端點的組合,現在是使用由其他插座,即只是返回到應用程序通過接受(一個,的異步連接()嘗試必須在某個時候失敗,通常會出現「正在使用中的地址」錯誤。儘管如此,該應用程序仍需要與B進行通信所需的工作對等流套接字,因此它忽略了此故障。

第一行爲以上似乎是通常的基於BSD的操作系統,而第二行爲Linux和Windows下顯示更常見。

所以我實際上是在第一種情況。在我的Windows 10上。

這意味着爲了爲TCP打孔提供可靠的方法,我需要將偵聽套接字同時作爲連接套接字綁定,但後來我需要檢測哪一個觸發了(監聽或連接)並將其傳遞給應用程序的流程。

+0

困擾我的唯一情況是我只看到兩種行爲中的一種,但我想我會保留這段內容,並將採取相應行動。 – WKnight02

1

爲什麼監聽套接字不會被觸發

我想答案是這裏的某個地方。TCP連接是由四個元素的元組定義:

  • 本地地址
  • 本地端口
  • 遠程地址
  • 遠程端口

當你建立TCP連接您從這個多元組綁定到本地主機上的連接套接字。

當SYN經由NAT發送它創建綁定: - 本地地址/端口 - >公共地址/端口

當遠程側發送它的SYN到公共地址/端口這個地址被轉換爲本地地址/端口並交付給本地機器。在這臺機器上,該連接與初始連接無法區分,並且已成功建立(使用SYN/ACK)。

這意味着在本地沒有收到INITIAL SYN。

如何讓監聽套接字通過連接套接字來接收入站連接?

對於源NAT來說這是不可能的。要接受NAT後面新的連接,你需要的目的地NAT一些公共IP /端口映射到你的私有IP /端口

+0

再次感謝您對您的回答,它真是其樂融融單獨不是在這個問題上:) 現在,如果我得到你的權利,你說,我不能接受連接,因爲我的NAT還沒有任何重定向? 因爲它是我試圖解決衝孔的問題。 現在,在此基礎上,那麼我可以運行給出的例子用'REMOTE =「localhost」的劇本,7000'它應該工作打算的呢? 沒有更多的NAT,數據包在本地發送。 那麼,它實際上是做同樣的事情:連接套接字捕獲連接,監聽套接字不。 – WKnight02

+0

(順便說一句,我首先綁定哪個套接字無關緊要,連接套接字總是優先於收聽/接受套接字,嘆息) – WKnight02

+0

(可能我沒完全理解你) – WKnight02