如何使用tcpdump捕获tcp有效载荷数据大于0的数据包
先看下ip报文组成部分:
分析:
先获取ip数据包总长度,再减去ip头部长度,再减去tcp头部长度,就可以获取到tcp有效载荷数据长度了
即:ip数据包总长度 - ip头部长度 - tcp头部长度 = tcp有效载荷数据长度
使用man tcpdump查看手册:
To print all IPv4 HTTP packets to and from port 80, i.e. print only packets that contain data, not, for example, SYN and FIN packets and ACK-only packets. (IPv6 is left as an exercise for the reader.)
捕获所有端口号为80 ipv4 HTTP包 ,并且所有数据包都包含数据,不会捕获三次握手和四次挥手的数据包。
tcpdump 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
- ip[2:2] 表示偏移量为2,从第3个字节开始,获取2个字节
- ip[0] 表示偏移量为0,从第1个字节开始,获取一个字节,等价于:ip[0:1]
- tcp[12] 表示偏移量为12,从第13个字节开始,获取一个字节,等价于tcp[12:1]
1.获取ip报文的总长度和报文头长度
下面是ipv4报文格式图:
首先获取ip报文的总长度:
从上图可以看出版本、首部长度、区分服务占了2个字节,所以截取报文偏移量就是2字节,ip报文总长度占两个字节所以截取长度也是2个字节,这就是ip[2:2]的由来。
再获取ip报文头长度:
同理:版本占了4bit,首部长度占4个bit,它们共同组成一个字节,所以偏移量是0个字节,取低四位即可。若想取低四位需要逻辑与上0000 1111,换算成十六进制即:0x0f,这就是ip[0] & 0x0f 的由来。
单位换算:
(ip[0]&0xf)<<2,得到ip头部长度后需要左移两位,即乘以4,是因为报文中首部长度这里单位是32个bit,即4个字节,所以需要乘以4。而ip报文总长度的单位是字节,故不需要单位进行换算。
首部长度占4位,可表示的最大十进制数值是15。首部长度字段所表示的单位是32位(4字节,与TCP首部中长度字端单位一致)。因为IP首部的固定长度是20字节,因此首部长度字段的最小值为5(0101)。当首部长度为15(1111)时,表示的报文头长度为60字节当IP分组的首部长度不是4的整数倍时,必须利用最后的填充字段加以填充达到4的整数倍。
总长度占2字节,指首部和数据之和的长度,单位为字节。能表示的最大长度为65535字节。在IP层下面的链路层协议规定了一个数据帧的数据字段的最大长度,这称为最大传输单元MTU(maximum transfer unit)。当一个IP数据报封装成链路层的帧时,此数据报的总长度(即首部加上数据部分)一定不能超过下面的链路层所规定的的MTU值。
2.获取tcp报文头长度
我们已经拿到了ip报文的总长度和ip报文头的长度,接下来便是获取tcp报文头的长度了
先看下tcp报文格式:
从上图能看出来,源端口号、目标端口号、序号和确认号共占了12个字节,tcp的首部长度占4bit,所以要从第13个字节开始取数,即偏移量为12,共取一个字节 即:tcp[12]。
由于首部长度和保留位共占一个字节,首部长度取高四位就可以了,所以要逻辑与上1111 0000(0xf0)即:tcp[12]& 0xf0。
因为tcp首位长度单位也是32bit(4字节) ,所以tcp[12]&0xf0 要左移两位(乘以4) ,即(tcp[12]&0xf0) << 2
因为首部长度取的是高四位,所以需要右移四位,即((tcp[12]&0xf0) << 2) >> 4,简化后:((tcp[12]&0xf0) >>2)