TCP/IP OPTION字段

0x01 簡介

 TCP頭部和IPV4頭部除了固定的20字節外,都設置了 OPTION 字段用於存儲自定義的數據,由於TCP頭部和IPV4的報文長度字段均爲4字節,所表示的最大值爲15, 乘4,報文頭部最大長度爲60字節,所以Option字段最大長度爲40字節,足夠存儲大量的報文控制信息。TCP和IPV4 OPTION的格式均爲(標識字段 - 長度 - 數據)格式,通常採起4字節對齊存儲。linux

目前 IP Option應用場景較少,且公網路由器對 IP Option的檢查較爲嚴格,通常都會直接丟棄帶有 IP Option 的報文。TCP Option 的應用場景則較爲普遍,常見的包括 TimeStamp(應用於時延測量), TCP_Window_Scalling(長肥網絡下,TCP接收窗口須要足夠大才能達到瓶頸帶寬,此時須要 Window_Scaling 來表示一個更大的接收窗口),TCP_SACK(選擇性確認,能夠大幅提升TCP在丟包時的性能)等等,這些選項通常都會默認開啓,路由器、端主機對這些選項的支持度也較高。本文主要介紹 TCP & IPV4 Option的處理邏輯,而後介紹一種經過 IP Option 字段在內網傳輸報文控制數據的方法。網絡

0x02 TCP OPTION Linux實現

步驟1: 構造TCP Option,計算存儲空間socket

 Linux把TCP選項的處理邏輯分爲了SYN報文的選項和普通報文的選項兩個部分,在TCP報文構造函數 static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_itgfp_t gfp_mask) 中有下面這段邏輯tcp

  1.  若是報文爲SYN報文,則調用 tcp_syn_options 函數處理握手期間的一些TCP Option,例如MSS協商,Window_Scaling等。
  2.  若是報文爲非SYN報文,則調用 TCP_established_options 函數處理包括TimeStamp,SACK等選項的構造。
  3. 構造好的TCP選項並非直接寫入TCP頭部,而是存儲在 struct tcp_out_options 類型的結構體變量 opts 中。

步驟2:分配 TCP 頭部須要的存儲空間,包括20個字節的標準頭部加上TCP Option的部分。ide

tcp_options_size 爲TCP選項部分的總長度,tcp_transmit_skb 接下來在 skb_push 中爲TCP頭部分配存儲空間。
函數

步驟3 : 向TCP頭部寫入構造好的TCP Option。  性能

tcp_transmit_skb 接下來經過 tcp_options_write() 函數把構造好的TCP Option 從 opts 中讀出並寫入TCP報文首部ui

  

步驟4 : TCP Option 的構造邏輯完成,報文進入IP層的處理邏輯。spa

步驟5:TCP Option 的解析在 tcp_parse_options() 函數 中完成,協議棧在接收到TCP報文後,會調用該函數完成報文頭部的OPTION字段的解析。3d


0x03 IP OPTION Linux實現

IP Option的構造與TCP  Option相似。

步驟1:分配存儲空間,在IP報文構造函數 ip_queue_xmit 中,有下面這一段邏輯,分配IP報文頭部空間和OPTION字段的存儲空間

      

步驟2 : 構造OPTION字段,具體邏輯在 ip_options_build 中,與 TCP Option的邏輯相似。

        

步驟3: 解析, IP Option的解析在 ip_options_compile 中完成

         

0x04 應用

在咱們的應用場景下,例如向路由器通告一些信息等,報文除了傳輸數據外,還要傳輸一些控制信息,咱們就是經過IP報頭的OPTION字段來攜帶這些控制信息。通常狀況下,帶有TCP選項的報文,即便TCP選項是自定義的,公網路由器也不會輕易丟包,但公網路由器對IP選項的審查要嚴格的多,帶有IP選項的報文。當報文從局域網轉發到公網的時候,Linux網關能夠在Qdisc中刪除該選項,並轉發到公網,Linux上發送一個帶有自定義IP選項的報文也很是容易,不須要修改內核,只須要在用戶態用 setsockopt() 調用即可以完成,下面是一個設置自定義IP 選項的Linux套接字客戶端程序示例。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 #include <arpa/inet.h>
 6 #include <sys/socket.h>
 7 #include <netinet/ip.h>
 8 
 9 #define SERV_PORT 1234
10 #define SERV_IP "127.0.0.1"
11 #define MAXLINE 4096
12 #define MAXSIZE 40
13 
14 #define IPOPT_TAG 0x21        //IP選項標誌字段
15 #define IPOPT_LEN 8            //IP選項長度字段
16 
17 int main(int argc,char *argv[])
18 {
19         int sockfd;
20         struct sockaddr_in servaddr;
21 
22         memset(&servaddr,0,sizeof(servaddr));
23         servaddr.sin_family = AF_INET;
24         servaddr.sin_addr.s_addr = inet_addr(SERV_IP);
25         servaddr.sin_port = htons(SERV_PORT);
26 
27         //構造自定義的TCP選項
28         unsigned char opt[MAXSIZE];
29         opt[0] = IPOPT_TAG;
30         opt[1] = IPOPT_LEN;
31         //寫入選項數據
32         *(int *)(opt + 4) = htonl(50000);        
33 
34         if((sockfd = socket(AF_INET,SOCK_STREAM,0)) <= 0){
35                 perror("socket error : ");
36                 exit(1);
37         }
38 
39         if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) < 0){
40                 perror("connect error ");
41                 exit(1);
42         }
43 
44         //設置套接字發送該選項
45         if(setsockopt(sockfd,IPPROTO_IP,IP_OPTIONS,(void *)opt,IPOPT_LEN) < 0){
46                 perror("setsockopt error ");
47                 exit(1);
48         }
49 
50         char buff[MAXLINE];
51 
52         while(fgets(buff,MAXLINE,stdin) != NULL){
53                 if(write(sockfd,buff,strlen(buff)) < strlen(buff)){
54                         perror("write error ");
55                         exit(1);
56                 }
57         }
58 
59         close(sockfd);
60 }

  

內核並無檢測 setsockopt() 的參數,直接將自定義的選項複製到了IP報文選項部分。

 

咱們能夠經過 getsockopt() 函數能夠直接讀取自定義的IP OPTION。

TCP自定義選項的設置和讀取相對於IP選項要麻煩一些,通常向TimeStamp,SACK等TCP選項並不須要用戶去讀取,所以也沒有開放用戶層訪問的接口,直接經過 getsockopt() 函數沒法讀取自定義的TCP 選項,但咱們能夠經過修改內核 getsockopt() 來實現自定義TCP選項的讀取,咱們知道內核 getsockopt()  函數底層是由 do_ip_getsockopt 和 do_tcp_getsockopt 等協議相關的接口組成的, 在 do_tcp_getsockopt 接口內咱們能夠添加用戶層訪問自定義TCP選項的接口,而後即可以在用戶層經過 getsockopt()  函數來訪問自定義的 TCP 選項了。

0x05 總結

TCP Option字段對於提高TCP性能有較大意義,所以須要瞭解常見的TCP Option字段的含義、開啓和關閉。IP Option字段通常來講不容易遇見,但在一些特殊的應用場景下,例如在局域網內捎帶報文控制數據仍是頗有用處的。

0x06 參考

Linux  Kernel  4.12.13     https://elixir.bootlin.com/linux/v4.12.13/source

相關文章
相關標籤/搜索