大家好,我是小林。
最近有個同學(xué)問了我這么一個問題:大概就是他的云服務(wù)器,為什么ping 不通他的電腦。這次我們就來說說原因。
IPv4地址有限,最大42億個。為了更好的利用這有限的IP數(shù)量,網(wǎng)絡(luò)分為局域網(wǎng)和廣域網(wǎng),將IP分為了私有IP和公網(wǎng)IP,一個局域網(wǎng)里的N多臺機(jī)器都可以共用一個公網(wǎng)IP,從而大大增加了"可用IP數(shù)量"。
收發(fā)數(shù)據(jù)就像收發(fā)快遞
當(dāng)我們需要發(fā)送網(wǎng)絡(luò)包的時(shí)候,在IP層,需要填入源IP地址,和目的IP地址,也就是對應(yīng)快遞的發(fā)貨地址和收貨地址。
IP報(bào)頭里含有發(fā)送和接收IP地址
但是我們家里的局域網(wǎng)內(nèi),基本上都用192.168.xx.xx這樣的私有IP。
如果我們在發(fā)送網(wǎng)絡(luò)包的時(shí)候,這么填。對方在回?cái)?shù)據(jù)包的時(shí)候該怎么回?畢竟千家萬戶人用的都是192.168.0.1,網(wǎng)絡(luò)怎么知道該發(fā)給誰?
所以肯定需要將這個192.168.xx私有IP轉(zhuǎn)換成公有IP。
因此在上篇文章最后,留了這么個問題。局域網(wǎng)內(nèi)用的是私有IP,公網(wǎng)用的都是公有IP。一個局域網(wǎng)里的私有IP想訪問局域網(wǎng)外的公有IP,必然要做個IP轉(zhuǎn)換,這是在哪里做的轉(zhuǎn)換呢?
私有IP和公有IP在哪進(jìn)行轉(zhuǎn)換
答案是NAT設(shè)備,全稱Network Address Translation,網(wǎng)絡(luò)地址轉(zhuǎn)換。基本上家用路由器都支持這功能。
我們來聊下它是怎么工作的。
NAT的工作原理
為了簡單,我們假設(shè)你很富,你家里分到了一個公網(wǎng)IP地址 20.20.20.20,對應(yīng)配到了你家自帶NAT功能的家用路由器上,你家里需要上網(wǎng)的設(shè)備有很多,比如你的手機(jī),電腦都需要上網(wǎng),他們構(gòu)成了一個局域網(wǎng),用的都是私有IP,比如192.168.xx。其中你在電腦上執(zhí)行ifconfig命令,發(fā)現(xiàn)家里的電腦IP是192.168.30.5。你要訪問的公網(wǎng)IP地址是30.30.30.30。
于是就有下面這樣一張圖
內(nèi)網(wǎng)IP訪問公網(wǎng)IP
當(dāng)你準(zhǔn)備發(fā)送數(shù)據(jù)包的時(shí)候,你的電腦內(nèi)核協(xié)議棧就會構(gòu)造一個IP數(shù)據(jù)包。這個IP數(shù)據(jù)包報(bào)頭里的發(fā)送端IP地址填的就是192.168.30.5,接收端IP地址就是30.30.30.30。將數(shù)據(jù)包發(fā)到NAT路由器中。
此時(shí)NAT路由器會將IP數(shù)據(jù)包里的源IP地址修改一下,私有IP地址192.168.30.5改寫為公網(wǎng)IP地址20.20.20.20,這叫SNAT(Source Network Address Translation,源地址轉(zhuǎn)換)。并且還會在NAT路由器內(nèi)部留下一條 192.168.30.5 -> 20.20.20.20的映射記錄,這個信息會在后面用到。之后IP數(shù)據(jù)包經(jīng)過公網(wǎng)里各個路由器的轉(zhuǎn)發(fā),發(fā)到了接收端30.30.30.30,到這里發(fā)送流程結(jié)束。
SNAT
如果接收端處理完數(shù)據(jù)了,需要發(fā)一個響應(yīng)給你的電腦,那就需要將發(fā)送端IP地址填上自己的30.30.30.30,將接收端地址填為你的公網(wǎng)IP地址20.20.20.20,發(fā)往NAT路由器。NAT路由器收到公網(wǎng)來的消息之后,會檢查下自己之前留下的映射信息,發(fā)現(xiàn)之前留下了這么一條 192.168.30.5 -> 20.20.20.20記錄,就會將這個數(shù)據(jù)包的目的IP地址修改一下,變成內(nèi)網(wǎng)IP地址192.168.30.5, 這也叫DNAT(Destination Network Address Translation,目的地址轉(zhuǎn)換)。之后將其轉(zhuǎn)發(fā)給你的電腦上。
DNAT
整個過程下來,NAT悄悄的改了IP數(shù)據(jù)包的發(fā)送和接收端IP地址,但對真正的發(fā)送方和接收方來說,他們卻對這件事情,一無所知。
這就是NAT的工作原理。
NAPT的原理
到這里,相信大家都有一個很大的疑問。
局域網(wǎng)里并不只有一臺機(jī)器,局域網(wǎng)內(nèi) 每臺機(jī)器都在NAT下留下的映射信息都會是 192.168.xx.xx -> 20.20.20.20,發(fā)送消息是沒啥事,但接收消息的時(shí)候就不知道該回給誰了。
NAT的問題
這問題相當(dāng)致命,因此實(shí)際上大部分時(shí)候不會使用普通的NAT。
那怎么辦呢?
問題出在我們沒辦法區(qū)分內(nèi)網(wǎng)里的多個網(wǎng)絡(luò)連接。
于是乎。
我們可以加入其他信息去區(qū)分內(nèi)網(wǎng)里的各個網(wǎng)絡(luò)連接,很自然就能想到端口。
但I(xiàn)P數(shù)據(jù)包(網(wǎng)絡(luò)層)本身是沒有端口信息的。常見的傳輸層協(xié)議TCP和UDP數(shù)據(jù)報(bào)文里才有端口的信息。
TCP報(bào)頭有端口號
UDP報(bào)頭也有端口號
于是流程就變成了下面這樣子。
當(dāng)你準(zhǔn)備發(fā)送數(shù)據(jù)包的時(shí)候,你的電腦內(nèi)核協(xié)議棧就會先構(gòu)造一個TCP或者UDP數(shù)據(jù)報(bào)頭,里面寫入端口號,比如發(fā)送端口是5000,接收端口是3000,然后在這個基礎(chǔ)上,加入IP數(shù)據(jù)報(bào)頭,填入發(fā)送端和接收端的IP地址。
那數(shù)據(jù)包長這樣。
數(shù)據(jù)包的構(gòu)成
假設(shè),發(fā)送端IP地址填的就是192.168.30.5,接收端IP地址就是30.30.30.30。
將數(shù)據(jù)包發(fā)到NAT路由器中。
此時(shí)NAT路由器會將IP數(shù)據(jù)包里的源IP地址和端口號修改一下,從192.168.30.5:5000改寫成20.20.20.20:6000。并且還會在NAT路由器內(nèi)部留下一條 192.168.30.5:5000 -> 20.20.20.20:6000的映射記錄。之后數(shù)據(jù)包經(jīng)過公網(wǎng)里各個路由器的轉(zhuǎn)發(fā),發(fā)到了接收端30.30.30.30:3000,到這里發(fā)送流程結(jié)束。
NAPT發(fā)送數(shù)據(jù)
接收端響應(yīng)時(shí),就會在數(shù)據(jù)包里填入發(fā)送端地址是30.30.30.30:3000,將接收端是20.20.20.20:6000,發(fā)往NAT路由器。NAT路由器發(fā)現(xiàn)下自己之前留下過這么一條 192.168.30.5:5000 -> 20.20.20.20:6000的記錄,就會將這個數(shù)據(jù)包的目的IP地址和端口修改一下,變回原來的192.168.30.5:5000。之后將其轉(zhuǎn)發(fā)給你的電腦上。
NAPT接收數(shù)據(jù)
如果局域網(wǎng)內(nèi)有多個設(shè)備,他們就會映射到不同的公網(wǎng)端口上,畢竟端口最大可達(dá)65535,完全夠用。這樣大家都可以相安無事。
像這種同時(shí)轉(zhuǎn)換IP和端口的技術(shù),就是NAPT(Network Address Port Transfer , 網(wǎng)絡(luò)地址端口轉(zhuǎn)換 )。
看到這里,問題就來了。
那這么說只有用到端口的網(wǎng)絡(luò)協(xié)議才能被NAT識別出來并轉(zhuǎn)發(fā)?
但這怎么解釋ping命令?ping基于ICMP協(xié)議,而ICMP協(xié)議報(bào)文里并不帶端口信息。我依然可以正常的ping通公網(wǎng)機(jī)器并收到回包。
ping報(bào)頭
事實(shí)上針對ICMP協(xié)議,NAT路由器做了特殊處理。ping報(bào)文頭里有個Identifier的信息,它其實(shí)指的是放出ping命令的進(jìn)程id。
對NAT路由器來說,這個Identifier的作用就跟端口一樣。
另外,當(dāng)我們?nèi)プグ臅r(shí)候,就會發(fā)現(xiàn)有兩個Identifier,一個后面帶個BE(Big Endian),另一個帶個LE(Little Endian)。
其實(shí)他們都是同一個數(shù)值,只不過大小端不同,讀出來的值不一樣。就好像同樣的數(shù)字345,反著讀就成了543。這是為了兼容不同操作系統(tǒng)(比如linux和Windows)下大小端不同的情況。
內(nèi)網(wǎng)穿透是什么
看到這里,我們大概也發(fā)現(xiàn)了。使用了NAT上網(wǎng)的話,前提得內(nèi)網(wǎng)機(jī)器主動請求公網(wǎng)IP,這樣NAT才能將內(nèi)網(wǎng)的IP端口轉(zhuǎn)成外網(wǎng)IP端口。
反過來公網(wǎng)的機(jī)器想主動請求內(nèi)網(wǎng)機(jī)器,就會被攔在NAT路由器上,此時(shí)由于NAT路由器并沒有任何相關(guān)的IP端口的映射記錄,因此也就不會轉(zhuǎn)發(fā)數(shù)據(jù)給內(nèi)網(wǎng)里的任何一臺機(jī)器。
舉個現(xiàn)實(shí)中的場景就是,你在你家里的電腦上啟動了一個HTTP服務(wù),地址是192.168.30.5:5000,此時(shí)你在公司辦公室里想通過手機(jī)去訪問一下,卻發(fā)現(xiàn)訪問不了。
那問題就來了,有沒有辦法讓外網(wǎng)機(jī)器訪問到內(nèi)網(wǎng)的服務(wù)?
有。
大家應(yīng)該聽過一句話叫,"沒有什么是加中間層不能解決的,如果有,那就再加一層"。
放在這里,依然適用。
說到底,因?yàn)镹AT的存在,我們只能從內(nèi)網(wǎng)主動發(fā)起連接,否則NAT設(shè)備不會記錄相應(yīng)的映射關(guān)系,沒有映射關(guān)系也就不能轉(zhuǎn)發(fā)數(shù)據(jù)。
所以我們就在公網(wǎng)上加一臺服務(wù)器x,并暴露一個訪問域名,再讓內(nèi)網(wǎng)的服務(wù)主動連接服務(wù)器x,這樣NAT路由器上就有對應(yīng)的映射關(guān)系。接著,所有人都去訪問服務(wù)器x,服務(wù)器x將數(shù)據(jù)轉(zhuǎn)發(fā)給內(nèi)網(wǎng)機(jī)器,再原路返回響應(yīng),這樣數(shù)據(jù)就都通了。這就是所謂的內(nèi)網(wǎng)穿透。
像上面提到的服務(wù)器x,你也不需要自己去搭,已經(jīng)有很多現(xiàn)成的方案,花錢就完事了,比如花某殼。
內(nèi)網(wǎng)穿透
到這里,我們就可以回答文章標(biāo)題的問題。
為什么我在公司里訪問不了家里的電腦?
那是因?yàn)榧依锏碾娔X在局域網(wǎng)內(nèi),局域網(wǎng)和廣域網(wǎng)之間有個NAT路由器。由于NAT路由器的存在,外網(wǎng)服務(wù)無法主動連通局域網(wǎng)內(nèi)的電腦。
兩個內(nèi)網(wǎng)的聊天軟件如何建立通訊
好了,問題就叒來了。
我家機(jī)子是在我們小區(qū)的局域網(wǎng)里,班花家的機(jī)子也是在她們小區(qū)的局域網(wǎng)里。都在局域網(wǎng)里,且NAT只能從內(nèi)網(wǎng)連到外網(wǎng),那我電腦上登錄的QQ是怎么和班花電腦里的QQ連上的呢?
兩個局域網(wǎng)內(nèi)的服務(wù)無法直接連通
上面這個問法其實(shí)是存在個誤解,誤以為兩個qq客戶端應(yīng)用是直接建立連接的。
然而實(shí)際上并不是,兩個qq客戶端之間還隔了一個服務(wù)器。
聊天軟件會主動與公網(wǎng)服務(wù)器建立連接
也就是說,兩個在內(nèi)網(wǎng)的客戶端登錄qq時(shí)都會主動向公網(wǎng)的聊天服務(wù)器建立連接,這時(shí)兩方的NAT路由器中都會記錄有相應(yīng)的映射關(guān)系。當(dāng)在其中一個qq上發(fā)送消息時(shí),數(shù)據(jù)會先到服務(wù)器,再通過服務(wù)器轉(zhuǎn)發(fā)到另外一個客戶端上。反過來也一樣,通過這個方式讓兩臺內(nèi)網(wǎng)的機(jī)子進(jìn)行數(shù)據(jù)傳輸。
兩個內(nèi)網(wǎng)的應(yīng)用如何直接建立連接
上面的情況,是兩個客戶端通過第三方服務(wù)器進(jìn)行通訊,但有些場景就是要拋開第三端,直接進(jìn)行兩端通信,比如P2P下載,這種該怎么辦呢?
這種情況下,其實(shí)也還是離不開第三方服務(wù)器的幫助。
假設(shè)還是A和B兩個局域網(wǎng)內(nèi)的機(jī)子,A內(nèi)網(wǎng)對應(yīng)的NAT設(shè)備叫NAT_A,B內(nèi)網(wǎng)里的NAT設(shè)備叫NAT_B,和一個第三方服務(wù)器server。
流程如下。
step1和2: A主動去連server,此時(shí)A對應(yīng)的NAT_A就會留下A的內(nèi)網(wǎng)地址和外網(wǎng)地址的映射關(guān)系,server也拿到了A對應(yīng)的外網(wǎng)IP地址和端口。
step3和4: B的操作和A一樣,主動連第三方server,NAT_B內(nèi)留下B的內(nèi)網(wǎng)地址和外網(wǎng)地址的映射關(guān)系,然后server也拿到了B對應(yīng)的外網(wǎng)IP地址和端口。
step5和step6以及step7: 重點(diǎn)來了。此時(shí)server發(fā)消息給A,讓A主動發(fā)UDP消息到B的外網(wǎng)IP地址和端口。此時(shí)NAT_B收到這個A的UDP數(shù)據(jù)包時(shí),這時(shí)候根據(jù)NAT_B的設(shè)置不同,導(dǎo)致這時(shí)候有可能NAT_B能直接轉(zhuǎn)發(fā)數(shù)據(jù)到B,那此時(shí)A和B就通了。但也有可能不通,直接丟包,不過丟包沒關(guān)系,這個操作的目的是給NAT_A上留下有關(guān)B的映射關(guān)系。
step8和step9以及step10: 跟step5一樣熟悉的配方,此時(shí)server再發(fā)消息給B,讓B主動發(fā)UDP消息到A的外網(wǎng)IP地址和端口。NAT_B上也留下了關(guān)于A到映射關(guān)系,這時(shí)候由于之前NAT_A上有過關(guān)于B的映射關(guān)系,此時(shí)NAT_A就能正常接受B的數(shù)據(jù)包,并將其轉(zhuǎn)發(fā)給A。到這里A和B就能正常進(jìn)行數(shù)據(jù)通信了。這就是所謂的NAT打洞。
step11: 注意,之前我們都是用的UDP數(shù)據(jù)包,目的只是為了在兩個局域網(wǎng)的NAT上打個洞出來,實(shí)際上大部分應(yīng)用用的都是TCP連接,所以,這時(shí)候我們還需要在A主動向B發(fā)起TCP連接。到此,我們就完成了兩端之間的通信。
NAT打洞
這里估計(jì)大家會有疑惑。
端口已經(jīng)被udp用過了,TCP再用,那豈不是端口重復(fù)占用(address already in use)?
其實(shí)并不會,端口重復(fù)占用的報(bào)錯常見于兩個TCP連接在不使用SO_REUSEADDR的情況下,重復(fù)使用了某個IP端口。而UDP和TCP之間卻不會報(bào)這個錯。之所以會有這個錯,主要是因?yàn)樵谝粋€linux內(nèi)核中,內(nèi)核收到網(wǎng)絡(luò)數(shù)據(jù)時(shí),會通過五元組(傳輸協(xié)議,源IP,目的IP,源端口,目的端口)去唯一確定數(shù)據(jù)接受者。當(dāng)五元組都一模一樣的時(shí)候,內(nèi)核就不知道該把數(shù)據(jù)發(fā)給誰。而UDP和TCP之間"傳輸協(xié)議"不同,因此五元組也不同,所以也就不會有上面的問題。
五元組
NAPT還分為好多種類型,上面的nat打洞方案,都能成功嗎?
關(guān)于NAPT,確實(shí)還細(xì)分為好幾種類型,比如完全錐形NAT和限制型NAT啥的,但這并不是本文的重點(diǎn)。所以我就略過了。我們現(xiàn)在常見的都是錐形NAT。上面的打洞方案適用于大部分場景,這其中包括限制最多的端口受限錐形NAT。
null
總結(jié)
? IPV4地址有限,但通過NAT路由器,可以使得整個內(nèi)網(wǎng)N多臺機(jī)器,對外只使用一個公網(wǎng)IP,大大節(jié)省了IP資源。
? 內(nèi)網(wǎng)機(jī)子主動連接公網(wǎng)IP,中間的NAT會將內(nèi)網(wǎng)機(jī)子的內(nèi)網(wǎng)IP轉(zhuǎn)換為公網(wǎng)IP,從而實(shí)現(xiàn)內(nèi)網(wǎng)和外網(wǎng)的數(shù)據(jù)交互。
? 普通的NAT技術(shù),只會修改網(wǎng)絡(luò)包中的發(fā)送端和接收端IP地址,當(dāng)內(nèi)網(wǎng)設(shè)備較多時(shí),將有可能導(dǎo)致沖突。因此一般都會使用NAPT技術(shù),同時(shí)修改發(fā)送端和接收端的IP地址和端口。
? 由于NAT的存在,公網(wǎng)IP是無法訪問內(nèi)網(wǎng)服務(wù)的,但通過內(nèi)網(wǎng)穿透技術(shù),就可以讓公網(wǎng)IP訪問內(nèi)網(wǎng)服務(wù)。一波操作下來,就可以在公司的網(wǎng)絡(luò)里訪問家里的電腦。
審核編輯:黃飛
?
評論
查看更多