码迷,mamicode.com
首页 > 其他好文 > 详细

TCP/IP OPTION字段

时间:2018-07-12 23:54:08      阅读:2860      评论:0      收藏:0      [点我收藏+]

标签:sock   ack   场景   解析   lan   span   ref   报文   分享   

0x01 简介

 TCP头部和IPV4头部除了固定的20字节外,都设置了 OPTION 字段用于存储自定义的数据,因为TCP头部和IPV4的报文长度字段均为4字节,所表示的最大值为15, 乘4,报文头部最大长度为60字节,因此Option字段最大长度为40字节,足够存储大量的报文控制信息。TCP和IPV4 OPTION的格式均为(标识字段 - 长度 - 数据)格式,一般采取4字节对齐存储。

目前 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,计算存储空间

      Linux把TCP选项的处理逻辑分为了SYN报文的选项和普通报文的选项两个部分,在TCP报文构造函数 static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_itgfp_t gfp_mask) 中有下面这段逻辑

技术分享图片

  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的部分。

      tcp_options_size 为TCP选项部分的总长度,tcp_transmit_skb 接下来在 skb_push 中为TCP头部分配存储空间。
技术分享图片

   步骤3 : 向TCP头部写入构造好的TCP Option。
tcp_transmit_skb 接下来通过 tcp_options_write 把构造好的TCP Option 从 opts 中读出并写入TCP报文首部

技术分享图片

步骤4 : TCP Option的构造逻辑完成,报文进入IP层的处理逻辑。

步骤5: 解析在 tcp_parse_options 中完成,协议栈在接收到TCP报文后,会调用该函数完成报文头部的OPTION字段的解析。

技术分享图片

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报文选项部分。

 

技术分享图片

0x05 总结

    TCP Option字段对于提升TCP性能有较大意义,因此需要了解常见的TCP Option字段的含义、开启和关闭。IP Option字段一般来说不容易碰见,但在一些特殊的应用场景下,例如在局域网内捎带报文控制数据还是很有用处的。

0x06 参考

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

TCP/IP OPTION字段

标签:sock   ack   场景   解析   lan   span   ref   报文   分享   

原文地址:https://www.cnblogs.com/codingMozart/p/9067552.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!