本篇介紹一個基礎的知識,關於數據包在路由器中是如何進行傳輸和交換的,只要明白這點,那麼對你配置出一個好的網絡環境會有很大的幫助。
一、輸入的問題
1、原始套接口可以接收到任何TCP或UDP報文。
2、要想接收到原始套接口,首先要接收的數據包必須有一個完整的、正確的IP頭,否則不能通過ip_rcv()中的包頭檢查和檢驗和驗證。
3、在原始套接口接收的數據包過程中,內核會對接收的IP包進行校驗和驗證,但不會對IP包以後的任何字段進行檢測和驗證。如,我們創建原始套接口時,所指定的protocol參數為IPPROTO_TCP,內核也不會進行TCP校驗和驗證,而是直接把IP頭中協議字段為TCP的所有數據包都復制一份,提交給該原始套接口。
4、用原始套接口接收到的TCP包都是進行了IP重組以後,TCP排序以前的報文。
5、如果在創建原始套接口時,所指定的protocol參數不為零,(socket的第三個參數),則接收到的數據報的協議字段應該與之匹配。否則該數據報不傳遞給該套接口。
6、如果此原始套接口上綁定了一個本地IP地址,那麼接收到的數據報的目的IP地址應該與該綁定的IP地址相匹配,否則該數據包將不傳遞到該套接口。
7、如果此原始套接口通過connect指定了一個對方IP地址,那麼接收到的數據包的源IP地址應與該以連接地址相匹配,否則該數據包不傳遞給該套接口。
8、如果一個原始套接口以protocol參數為0的方式創建,並且未調用connect或bind,那麼對於內核傳遞給原始套接口的每一個原始數據報,該套接口都會收到一份拷貝。
9、原始套接口接收不到任何的ARP或RARP協議類型的套接口,因為net_rx_action()會把ARP或RARP協議類型的數據包傳遞給ARP的接收函數類處理,不會傳遞給IP層的接收函數ip_rcv()。
10、原始套接口並不是可以接收到任何的ICMP類型的數據包,因為有些ICMP類型的數據包在傳遞給原始套接口之前已經被系統所響應,並不再向上層傳遞。
11、如果對方的數據包分片了,由於原始套接口的接收是在IP上層,所以會接收到重組以後的原始IP包。
二、輸出的問題
1、普通輸出通常通過sendto或sendmsg並指定目的IP地址來完成,如果套接口已經連接,也可以調用write、writev或send。
2、如果IP_HDRINCL選項未設置,則內核寫的數據起始地址是IP頭部之後的第一個字節。因為這種情況下,內核將構造IP頭部,並將它安在來自進程數據之前。內核將IPv4頭部的協議字段設置成用戶在調用socket函數時所給的第三個參數。
3、如果IP_HDRINCL選項已設置,則內核寫的數據其實地址是IP頭部的第一個字節。用戶所提供的數據必須包括IP頭部。此時進程構造除了以下兩項以外的整個IP頭部:IPv4標示字段可以設為0,要求內核設置該值。而且僅當該字段為0時,內核才為其設置,IPv4頭部校驗和由內核來計算和存儲。
4、如果創建原始套接口時指定了協議類型,即第三個參數protocol,那也並不是說只能發該類型的數據包。如,即使將protocol指定為 IPPROTO_TCP,也可以發送用戶自己組裝的UDP報文,不過此時如果IP_HDRINCL選項未設置,那麼內核將會在IP頭的協議字段指明後面的報文為TCP報文(不過此時卻為UDP報文)。
等數據包發送到對方TCP層,一般說來會因為找不到合適的TCP套接口接收該數據包而被丟棄。不過該包可以在目標主機的原始套接口上接收到。
5、正如前面所述,任何時候,IP頭的校驗和都是由內核來設置的。
6、內核任何時候那會都不會對IP包以後的字段進行校驗和驗證。如,即使我們指定第三個參數protocol為IPPROTO_TCP,在數據發送時內核也不會對進行TCP校驗和計算和驗證。
7、如果IP_HDRINCL選項已設置,按照常規,我們應該組建自己的IP頭,但是即使我們沒有組建IP頭,用sendto或sendmsg 並指定目的IP地址來發送數據是照樣可以完成的。但是這樣的數據包在目標機上用原始套接口是接收不到的,因為在ip_rcv()中要對IP頭進行驗證,並且要分析校驗和,所以該包會被丟棄,不過在鏈路層應該能夠接收到該數據包。
8、如果設置了IP_HDRINCL選項,並且數據包超長,那麼數據會被丟棄,並會返回出錯碼EMSGSIZE。如果未設置IP_HDRINCL選項,並且數據包超長,那麼數據包會被分片。
正是因為數據包具上述的結構,安裝了TCP/IP協議的電腦之間才能相互通信,在使用基於TCP/IP協議的網絡時,網絡中其實傳遞的就是數據包。