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_it, gfp_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 Option 的解析在 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套接字客户端程序示例。

 #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/ip.h> #define SERV_PORT 1234
#define SERV_IP "127.0.0.1"
#define MAXLINE 4096
#define MAXSIZE 40 #define IPOPT_TAG 0x21 //IP选项标志字段
#define IPOPT_LEN 8 //IP选项长度字段 int main(int argc,char *argv[])
{
int sockfd;
struct sockaddr_in servaddr; memset(&servaddr,,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(SERV_IP);
servaddr.sin_port = htons(SERV_PORT); //构造自定义的TCP选项
unsigned char opt[MAXSIZE];
opt[] = IPOPT_TAG;
opt[] = IPOPT_LEN;
//写入选项数据
*(int *)(opt + ) = htonl(); if((sockfd = socket(AF_INET,SOCK_STREAM,)) <= ){
perror("socket error : ");
exit();
} if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) < ){
perror("connect error ");
exit();
} //设置套接字发送该选项
if(setsockopt(sockfd,IPPROTO_IP,IP_OPTIONS,(void *)opt,IPOPT_LEN) < ){
perror("setsockopt error ");
exit();
} char buff[MAXLINE]; while(fgets(buff,MAXLINE,stdin) != NULL){
if(write(sockfd,buff,strlen(buff)) < strlen(buff)){
perror("write error ");
exit();
}
} close(sockfd);
}

内核并没有检测 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

TCP/IP OPTION字段的更多相关文章

  1. TCP/IP option data aligement issue cause system broken

    1      Problem Description The field reports show that xxx panel will lockup and then reboot while d ...

  2. TCP/IP协议栈--IP首部选项字段的分析

    IP输入函数(ipintr)将在验证分组格式(检验和,长度等)之后.确定分组是否到达目的地之前,对选项进行处理. 这表明分组所 遇到的每一个路由器以及终于的目的主机都对要分组的选项进行处理. IP分组 ...

  3. TCP/IP Four Layer Protocol Format Learning

    相关学习资料 tcp-ip详解卷1:协议.pdf 目录 . 引言 . 应用层 . 传输层 . 网络层 0. 引言 协议中的网络字节序问题 在学习协议格式之前,有一点必须明白,否则我们在观察抓包数据的时 ...

  4. 计算机网络及TCP/IP知识点(全面,慢慢看)

    TCP/IP网络知识点总结 一.总述 1.定义:计算机网络是一些互相连接的.自治的计算机的集合.因特网是网络的网络. 2.分类: 根据作用范围分类: 广域网 WAN (Wide Area Networ ...

  5. TCP/IP协议头部结构体(网摘小结)(转)

    源:TCP/IP协议头部结构体(网摘小结) TCP/IP协议头部结构体(转) 网络协议结构体定义 // i386 is little_endian. #ifndef LITTLE_ENDIAN #de ...

  6. TCP/IP 笔记 - 防火墙和网络地址转换

    防火墙是位于内部网和外部网之间的屏障,是系统的第一套防线,作用是防止非法用户的进入. 网络地址转换是一种IP数据包通过路由器或防火墙时通过重写来源IP地址或目的地址的技术,可以用来隐藏或保护内部网络, ...

  7. TCP/IP网络知识点总结

    学完了计算机网络是时候整理一篇总结了,温故知新.注意:这篇博客很长长长(2.5万字+50图). TCP/IP网络知识点总结 一.总述 1.定义:计算机网络是一些互相连接的.自治的计算机的集合.因特网是 ...

  8. 《TCP/IP 详解 卷1:协议》第 5 章:Internet 协议

    IP 是 TCPIP 协议族中的核心协议.所有 TCP.UDP.ICMP.IGMP 数据都通过 IP 数据包(又称为 packet)来传输.IP 的英文名为 Internet Protocol,是互联 ...

  9. TCP/IP协议的三次握手及实现原理

    TCP/IP是很多的不同的协议组成,实际上是一个协议组,TCP用户数据报表协议(也称作TCP传输控制协议,Transport Control Protocol.可靠的主机到主机层协议.这里要先强调一下 ...

随机推荐

  1. mfc双缓冲绘图

    1.要求 在界面加载本地图片并显示,每过100ms改变一张图片显示 2.现象 通过定时器控制CImage,Load,Draw,Destroy,会非常的卡顿.因为Load图片时,会是非常大的数据[所有C ...

  2. Session &cookie introduction,usage

    Cookie 1)什么是Cookie?      服务器为了识别用户身份而临时存放在浏览器端的少量数据.     2)工作原理         浏览器访问服务器时,服务器将一些数据以set-cooki ...

  3. Oracle错误——ORA-39002:操作无效、ORA-39070:无法打开日志文件、ORA-06512:在“SYS.UTL_FILE”,line

    错误 在使用数据泵impdp导入文件时,出现错误,无法导入数据 Next 问题原因 初步猜测,应该是Oracle用户权限出现问题,是对Directory目录无操作权限所致,经过一番修改和测试,发现使用 ...

  4. windows服务加定时器实现

    首先在项目中添加windows服务 然后双击“MainService.cs”,在上面点右键“打开代码” 以下是我的实例代码 partial class MainService : ServiceBas ...

  5. Python3 tkinter基础 Radiobutton variable 默认选中的按钮

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  6. Java 基础知识点小结

    小知识点 所有的程序,都要定义在类里面: 异常 定义方法时,使用 throws 可以用来捕获方法体内没有捕获的异常,然后以 SomeException 抛出异常 java是解释型语言.java虚拟机能 ...

  7. mybatis之Mybatis_demo

    这篇博文通过简单的CRUD案例,让大家能够快速的上手,使用mybatis.   1,在eclipse中新建java project项目 mybatis_demo 2,在mybatis_demo项目中建 ...

  8. 论文阅读:Siam-RPN

    摘要 Siam-RPN提出了一种基于RPN的孪生网络结构.由孪生子网络和RPN网络组成,它抛弃了传统的多尺度测试和在线跟踪,从而使得跟踪速度非常快.在VOT实时跟踪挑战上达到了最好的效果,速度最高16 ...

  9. bug日记之---------js中调用另一个js中的有ajax的方法, 返回值为undefind

    今天做一个OCR授权的需求, 需要开发一个OCR弹框, 让用户选择是否授权给第三方识别公司(旷世科技)保存和识别用户个人信息, 照片等. 其中用到了在一个js的方法中调用另外一个js的方法, 其中有一 ...

  10. transform:rotate3d/tranlate3d

    transform:rotate3d(x,y,z,angle); rotate3d 代表 在3D空间,元素沿着 经过原点(0,0,0) 和 三维坐标(x,y,z) 2点的直线进行旋转.其中: x:是一 ...