在有NAT的網路中如何實現P2P通訊(UDP打洞)

網路概論

網路上大多數的服務都是主從式架構

顧名思義就是會有台server一直listen著某個port

隨時準備好有client連進該ip該port來request他所要資源

 

可是萬一我今天想要的資源(e.g. 今天的課堂筆記)並不是在一台隨時待命的server上

而是我朋友的電腦裡,我想要與他通訊交換檔案呢(醒醒吧,我沒有朋友)

於是最簡單的peer-to-peer模型出現了

 

兩端直接在Public Network中

朋友跟我說他的ip以及socket監聽的port,等待我與他建立了一條socket連線

接著就可以把今天的課堂筆記拷貝回家了

        +------>>------------------------+
        |                                |
        |                                |
     我的電腦                          朋友的電腦
75.129.48.33:50001                75.129.48.50:50001

於是本文寫到這邊就可以結束了XDD

 

其中一端在NAT後面

當然現實總是沒有那麼美好

在日常的網路當中,網路設備通常是在防火牆或NAT後面

例如我的幻想朋友家族成員眾多

所以他在家裝分享器好讓爺爺奶奶外公外婆舅舅舅媽阿姨叔公伯伯…族繁不及備載,能同時間連上網

        +------>>------------------------+
        |                                |
        |                              NAT B
        |                           75.129.48.50
        |                                |
        |                                |
     我的電腦                          朋友的電腦
75.129.48.33:50001               192.168.1.3:50001

如果此時我一樣發送了建立socket連線請求的封包到朋友的外網ip(75.129.48.50:50001)

他家的分享器(NAT B)會很困惑這個封包應該轉發給內網的哪個設備

即便朋友的電腦正在監聽port 50001

接著就直接把封包給丟棄了(幫QQ)

如果送到192.168.1.3:50001更不可能會到,因為192.168.X.X是Class C網段的內網ip位址

 

為了能夠成功連線,我們把連線方式反過來

換我跟朋友說ip以及socket監聽的port,請朋友連過來

朋友的socket連線請求封包先經過了NAT B(分享器),NAT B再以自己的名義(75.129.48.50:33941)轉發到我的電腦(75.129.48.33)

        +------------------------<<------+
        |                                |
        |                              NAT B
        |                        75.129.48.50:33941
        |                                |
        |                                |
     我的電腦                          朋友的電腦
75.129.48.33:50001               192.168.1.3:50001

在這個轉發的過程中,NAT B不一定會使用與前一段相同的port

有可能這個port已經被其他應用程式佔用走了,像上圖一樣

封包從朋友的電腦port 50001發出,但在NAT B是以port 33941轉發給我的電腦

 

我的電腦因為是直接接到public network,所以封包可以順利的接收

站在我的電腦的觀點來看,封包是來自75.129.48.50:33941

因此,我的電腦會以為朋友的socket連線是在75.129.48.50:33941,而往後所有回覆的封包都會往75.129.48.50:33941送,實際上這是NAT B位址

        +------>>------------------------+
        |                                |
        |                              NAT B
        |                        75.129.48.50:33941
        |                                |
        |                                |
     我的電腦                          朋友的電腦
75.129.48.33:50001               192.168.1.3:50001

 

NAT B在收到封包後,因為曾經將來自內網192.168.1.3:50001的封包從75.129.48.50:33941轉發出去

所以在它的NAPT表(Network Address Port Translation Table)中會有一條這樣的forwarding rule

75.129.48.50:33941<-->192.168.1.3:50001

NAT B根據這個forwarding rule,知道送到75.129.48.50:33941的封包是屬於192.168.1.3的

最後將這個封包往內網的192.168.1.3:50001送

這樣就完成了一次封包來往的cycle

往後的封包也是這樣的原理在NAT之間穿越

我也就可以把今天的課堂筆記順利拷貝回家了,YA!!

 

兩端都在NAT後面

上述的情況還是太理想了,現實應該要更殘酷

如果今天我家跟我朋友家雙邊都有了NAT(分享器),難道就無解不能P2P通訊了嗎

        +--------------------------------+
        |                                |
      NAT A                            NAT B
   75.129.48.33                     75.129.48.50
        |                                |
        |                                |
     我的電腦                          朋友的電腦
192.168.1.3:50001                192.168.1.3:50001

這個例子應該是最接近現實狀況的,甚至現實中的NAT還不只一層

所以接下來要介紹現實中常用將雙方在NAT後的設備建立P2P連線的方式(好長的鋪陳)

 

UDP打洞 (UDP hole punching)

還記得在其中一端在NAT後面這段時有提到,NAT轉發時不一定會使用與前一段相同的port

為了解決雙方都使用NAT隨機分派的port去訪問對方而port對不上的問題

我們需要再引進第三方(暫名Server)協助記錄雙方對外的ip以及p2p連線用的port

然後使用UDP打洞的技術來協助在NAT後面的雙方建立起連線

                     Server
              122.116.185.28:50001
                        |
                        |
        +---------------+---------------+
        |                               |
      NAT A                           NAT B
75.129.48.33:63029              75.129.48.50:33941
        |                               |
        |                               |
     我的電腦                         朋友的電腦
192.168.1.3:50001               192.168.1.3:50001

 

UDP打洞的步驟是這樣的:

  1. 我的電腦以及朋友的電腦都先跟Server以UDP的方式回報自己的ip以及使用的port
    (由於雙方都在內網,所以雙方回傳的會是內網的ip以及port)
  1. Server記錄下「觀察到的」封包來源ip及port(所以會是雙方NAT對外的ip及port)

  2. Server告訴雙方 對方的ip及port

  • 由於雙方都已經跟Server用這個port通訊過,所以雙方NAT的NAPT表中已經有了forwarding rule
  1. 現在雙方就可以開始跟對方以UDP的方式通訊了,YA!!

One Comment

  1. 表示只要雙方NAT的ip與port是雙方互相都知道的就可以實現p2p嗎?
    那如果是這樣的話我直接透過通訊軟體轉達我和朋友雙方的ip與port,之後雙方都向對方NAT的ip與port傳送封包,也能達到一樣的效果嗎,這樣是不是就不一定要裝特定的程式(像是zerotier之類的)就能自己DIY P2P嗎?
    (雖然實際執行起來說不定比安裝zerotier更加複雜.. 哈哈)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *