ljzsdut
GitHubToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

02 Tcpdump高级过滤

理论

OSI七层参考模型

up-8f894980b3afbdfe8c273b157e4ab5fa787-1619057726873

链路层Header

参考链接:http://blog.chinaunix.net/uid-20530497-id-2878069.html

Ethernet帧

3lKDxc-1636336119672

以太帧有好多种,我们最常用到的是Ethernet II,Ethernet II即DIX 2.0:Xerox与DEC、Intel在1982年制定的以太网标准帧格式。Cisco名称为:ARPA。

Ethernet II类型以太网帧的最小长度为64字节(6+6+2+46+4),最大长度为1518字节(6+6+2+1500+4)。

其中前12字节分别标识出发送数据帧的源节点MAC地址和接收数据帧的目标节点MAC地址。(注:ISL封装后可达1548字节,802.1Q封装后可达1522字节)

接下来的2个字节标识出以太网帧所携带的上层数据类型,如下:

类型
IPv40x0800
ARP0x0806
PPPoE0x8864
802.1Q tag0x8100
IPV60x86DD
MPLS Label0x8847

在不定长的数据字段后是4个字节的帧校验序列(Frame. Check Sequence,FCS)

ARP帧

img

硬件类型:1 表示以太网

协议类型:和Ethernet数据帧中类型字段相同

OP操作字段:

OP值操作类型
1表示ARP请求
2表示ARP应答
3表示RARP请求
4表示RARP应答

802.1q VLAN数据帧(4字节)

img

  • Type:长度为2字节,取值为0x8100,表示此帧的类型为802.1Q Tag帧。
  • PRI:长度为3比特,可取0~7之间的值,表示帧的优先级,值越大优先级越高。该优先级主要为QoS差分服务提供参考依据(COS)。
  • VLAN Identifier (VID) : 长度12bits,可配置的VLAN ID取值范围为1~4094。通常vlan 0和vlan 4095预留,vlan1为缺省vlan,一般用于网管。

IPv4 Header

参考:

https://blog.csdn.net/lqrensn/article/details/5134408

http://blog.itpub.net/15480802/viewspace-1334334/

Pz46TI-1635491312915

xQtzt1-1635490633696

名称作用说明
IP Version4 bits , 一般的值为0100(IPv4),IPv6的值(0110)。总共有2^4 变化, 可以表示的数值 0~15 , 因此 IP Version最多可以标识 16种版本 ,ipv4 版本中 IP Version 的值为4,ipv6版本中 IP Version的值为6 , 已经被使用的版本:0,1,2,3,4,5,6,7,8 ,9 , 因此 下一个IP版本应该是IPv10
IHL(Internet Header Length)4bits ,总共有2^4 变化, 可以表示的数值 0~15, 该字段用于声明IPv4包的Header长度,以4字节(32bit)为单位,因为在IP包头中有变长的可选Options部分。该字段值有个范围: 5~15。IHL = 5: 表示无Options字段 ,即Header长度为20Bytes;IHL=15:表示含Options字段, 且Options字段长度为最大长度,是40Bytes ,因此IPV4包的Header长度最大也就60Bytes。所以只要带有Options字段,那么IHL字段的值一般都大于5。
因此,一个IP包头的长度最长为“1111”(2进制),即15*4=60个字节。IP包头最小长度为20字节(标准ipv4报头)。对于标准ipv4报头,这个字段的值肯定是20/4=5(10进制)=0101(2进制)。
如果是IMCPv4或者传输头,那么数据包的开头会跳过前32位,从Fragment ID开始
**TOS (Type of Service) **8bits , 用于描述数据包的优先级,从而确定服务的优先级,在RFC 2474中有相关的定义和说明:http://www.ietf.org/rfc/rfc2474.txt,http://www.ietf.org/rfc/rfc2475.txt,这个是用来实现一个简单的QoS (Quality of Service) , 通过 协议 、 发送方、 接收方来管理带宽,例如,您可能想要给你的网络电话连接优先级高于你的视频下载,或从你的老板网络通信更高的优先级比你的同事的网络通信,那么,就得使用Qos来定义你这个连接的优先级了,如果没有QoS,带宽是先到先得,就是无论什么连接,都得排轮子,但是,8位不够真正做好QoS,和DiffServ,所以目前TOS位 并没有被广泛使用在IPv4网络中 , 然而QoS在IPv6得到了很大的提升。TOS位描述的是一个数据包的优先级——实际上路由器在决定数据包如何排队等待重传时,就是已经在使用 TOS位来判断优先级了,如果一个数据包无法提供请求的服务水平,那么 路由器会把数据包的TOS位标记为:undeliverable。
这个子段可以拆分成两个部分:Precedence和TOS。TOS目前不太使用。而Precedence则用于QOS(“Quality of Service”,中文名为"服务质量")应用。(TOS字段的详细描述RFC 1340 1349)。
Total Length16 bits,用于描述报文的总长度,以字节为单位。肯定也包含报头长度,理论上最小长度是20(20字节的头加上+0字节的Options+ 0字节的数据),最大是65535个字节(2^16)。实际上所有网络设备所能处理的数据包的长度各不一样,一般而言网络设备至少具有处理数据包的长度是576 字节,但一个更典型的包的大小是1508字节 , 所以一个数据包极有可能遇到一个包处理长度低于被传输包长度的设备(该包的大小 大于该设备的最大包长度处理能力) 此时数据包就需要分片然后传输, 最后到达目的地进行重组。分片和重组使得IPv4变得复杂,也容易混乱,IPv6中针对对此有很大改善。(当发送端的MTU大于到目的路径链路上的MTU时就会被分片)
Identification16 bits,数据包被切片后的ID,即Fragment ID,有65535个ID可用。该字段和Flag、Fragment Offest字段联合使用,对大的上层数据包进行分段(fragment)操作。
Flag+空bitFlag共3 bits。该字段第一位不使用即空bit,一个保留位,必须为0。第二位是DF位,第三位是MF位。
DF1bit , (Don’t Fragment) flag 。 DF位设为1时标示数据包不允许切分(路由器不能对该上层数据包分段), 如果该包的长度超出了网络设备的处理能力(即上层数据包无法在不分段的情况下进行转发),并且又打上的DF标签,那么该网络设备(路由器)会丢弃掉该数据包并返回一个错误信息。
MF1bit, (More Fragments) flag 。用于表示数据包是否被分片了,如果被分片了该位为1,如果没被分片那么该位为0。(当路由器对一个上层数据包分段,则路由器会在最后一个分段的IP包的包头中将MF位设为0,其余IP包的包头中将MF设为1。)
Fragment Offset13bits,分片的偏移量,用于决定分片重组时的顺序。该字段对包含分段的上层数据包的IP包赋予序号。由于IP包在网络上传送的时候不一定能按顺序到达,这个字段保证了目标路由器在接受到IP包之后能够还原分段的上层数据包。到某个包含分段的上层数据包的IP包在传送是丢失,则整个一系列包含分段的上层数据包的IP包都会被要求重传。
Time-to-live(TTL)8bits,用于防止网络中数据包被无限期的循环路由。最初想用秒数来设定TTL,但是没能实现,最后以跳数实现了,所以TTL的值描述的是包所能剩下的跳数(路由次数)。当IP包进行传送时,先会对该字段赋予某个特定的值。当IP包经过每一个沿途的路由器的时候(每跳一次),每个沿途的路由器会将IP包的TTL值减少1,如果TTL减少为0 ,此时路由设备会丢弃此包;如果包被路由设备Dropped,那么该路由设备会以返回给包发送者一条ICMPv4的不被路由的信息 (“time exceeded”),Traceroute就是利用此原理来得到每一跳的路由设备的IP地址的。
Protocol8bits,用于定义IPv4 Header过后的下一个Header协议类型。即标识了上层(内层)报文所使用的协议。取值如下表:
Protocol有如下取值:
1		ICMPv4		Internet Control Message Protocol for IPv4 ([RFC 792](http://tools.ietf.org/html/rfc792))
2		IGMP			Internet Group Management Protocol (RFCs [1112](http://tools.ietf.org/html/rfc1112), [2236](http://tools.ietf.org/html/rfc2236) and [3376)](http://tools.ietf.org/html/rfc3376)
4		IPv4			IPv4 in IPv4 encapsulation, IP in IP tunneling ([RFC 2003)](http://tools.ietf.org/html/rfc2003)
6		TCP				Transmission Control Protocol ([RFC 793](http://tools.ietf.org/html/rfc793))
8		EGP				Exterior Gatgeway Protocol ([RFC 888](http://tools.ietf.org/html/rfc888))
17	UDP				User Datagram Protocol ([RFC 768](http://tools.ietf.org/html/rfc768))
41	IPv6			IPv6 tunneled over IPv4, 6in4 tunneling ([RFC 2473](http://tools.ietf.org/html/rfc2473))
50	IPSec			ESP Header ([RFC 2406](http://tools.ietf.org/html/rfc2406))
51	IPSec			AH Header ([RFC 2402](http://tools.ietf.org/html/rfc2402))
89	OSPF			Open Shortest Path First routing ([RFC 1583](http://tools.ietf.org/html/rfc1583))
132	SCTP			Streams Control Transmission Protocol ([RFC 4960](http://tools.ietf.org/html/rfc4960))
名称作用说明
Header ChecksumIPv4 Header校验码,由于IP包头是变长的,所以提供一个头部校验来保证IP包头中信息的正确性。一共16bits,2个字节。当计算校验码时,本字段(Header CheckSum)会被置0,所以Header Checksum字段是不参与 校验的,因此Header的20字节里面参与校验的仅有18个字节,又因为TTL每一跳都要减一,所以Header的Checksum计算每跳都要进行
**Source Address **4字节,标识了这个IP包的源IP地址。
Destination Address4字节,标识了这个IP包的目的IP地址。
Options很少使用,可选,最大40字节,具体参考RFC791

TCP Header

jG8yR8-1635490866196

名称作用说明
Source Port Number源端口号, 16bits ,能表示的数值范围 0~65535, 对于linux 系统而言, 1024 以下的端口是特权端口,仅能root使用
Destination Port Number目标端口号, 16bits ,也能表示 0~65535
Sequence Number32bits, TCP报文的序列号
Acknowledgement Number32bits, 确认Sequence Number的确认号 , 一般确认号的表示方式是 : 被确认的Sequence Numbe + 1, 比如要确认对方100号报文(seq=100),那么确认号就是101(ack=101)。
Header Length4bits, TCP Header的长度,以4字节(32bit)为单位。最小20字节, 最大60字节 , 因为Options最大40bytes。
Reserved4bits, 保留位
CWR1bit, Congestion Window Reduced
ECN1bit, Explicit Congestion Notice
URG1bit, Urgent的缩写, 紧急位,大部分报文会在TCP/IP协议栈的内核缓存区等待处理, URG的意思就是 把这个请求插入到内核缓存区的前面,让报文尽快被处理。
ACK1bit, Acknowledgement的缩写, 确认位, 将该位设置1即可开启此位, 开启此位表示此报文为确认报文,Acknowledgement Number才会有效,因此仅当3次握手的第一次时ACK为0, 其他时候都为1。
PSH1bit,推送位,不经过内核缓存区,直接接收处理。
RST1bit,重置位, 用于重置TCP 连接。
SYN1bit,请求位,synchronization的缩写, 用于发起TCP连接请求, 将该位设置1即可开启此位, 表示这是一条TCP请求建立连接报文,因此 ,3次握手过程中仅有第一次SYN位才为1,其他时候都为0。
FIN1bit,结束位,finish的缩写, 用于结束TCP连接请求,将该位设置1即可开启此位, 4次挥手中, Initiator请求断开时FIN为1 ,Receiver 处理完请求,也请求断开时FIN为1。
Window Size16bits,滑动窗口,根据接收缓冲进行调整,为了提高效率, 报文不会1个1个的发送,而是一批一批的发送, 确认也是 一批一批的进行确认(及延迟确认), 那么一批发送多少个报文合适呢?这个值是根据对方的发送缓冲、线路容纳、 自己接收缓冲 这3个条件, 取最小的那个作为批量发送的报文数,当这一批报文到达自己的接收缓冲过后, 如果接收缓冲还有空间缓冲报文, 就会以 Window Size 这个字段告诉发送方,下次可以一批发多少个报文过来因此,这个Window Size是动态变化的。
TCP ChecksumTCP 报文校验码

UDP Header

sNalST-1636276671769

UDP首部有8个字节,由4个字段构成,每个字段都是两个字节。

  • 源端口: 主机的应用程序使用的端口号。

  • 目的端口:目的主机的应用程序使用的端口号。

  • 长度:是指UDP头部和UDP数据的字节长度。因为UDP头 部长度为8字节,所以该字段的最小值为8。

  • 校验和:检测UDP数据报在传输中是否有错,有错则丢弃。

ICMP Header

img

ICMP报文的各种状态:

目的不可达报文

image-20211029150526436

源端抑制报文

image-20211029150539355

超时报文

image-20211029150604699

参数问题

image-20211029150615978

改变路由

image-20211029150626791

回送请求和回答

image-20211029150636394

时间戳请求和回答

image-20211029150646283

地址掩码请求和回答

image-20211029150657264

路由询问和通告

image-20211029150729414

image-20211029150740583

VXlan Header

KvsOP5-1636277271083

1DQAr7-1635492004316

名称作用说明
Outer MAC Header封装外层以太头,14字节,如果有VLAN TAG则为18字节。其中,源MAC地址(Outer Source MAC Address)为源VM所属VTEP的MAC地址,目的MAC地址(Outer Destination MAC Address)为到达目的VTEP的路径上下一跳设备的MAC地址。类型字段为0x0800,指示内层封装的是IP报文。
Outer IP Header封装外层IP头,20字节。其中,源IP地址(Outer Source IP Address)为源VM所属VTEP的IP地址,目的IP地址(Outer Destination IP Address)为目的VM所属VTEP的IP地址。协议字段为0x11,指示内层封装的是UDP报文。
UDP HeaderUDP报文头,8字节。其中,UDP目的端口号(UDP Destination Port)固定为4789,指示内层封装报文为VXLAN报文。UDP源端口号(UDP Source Port)为随机任意值,可以用于VTEP之间多路径负载分担的计算。
VXLAN HeaderVXLAN协议新定义的VXLAN头,8字节。
Flags8 bit,RRRRIRRR。“I”位为1时,表示VXLAN头中的VXLAN ID有效;为0,表示VXLAN ID无效。“R”位保留未用,设置为0。
VXLAN ID(VNI)24 bit,用于标识一个单独的VXLAN网络。
Reserved分别为24 bit和8 bit。保留位。
Original L2 Frame原始以太网报文。

从报文的封装可以看出,VXLAN头和原始二层报文是作为UDP报文的载荷存在的。在VTEP之间的网络设备,只需要根据Outer MAC Header和Outer IP Header进行转发,利用UDP Source Port进行负载分担,这一过程,与转发普通的IP报文完全相同。这样,除了VTEP设备,现网的大量设备无需更换或升级即可支持VXLAN网络。

不过,新增加的VXLAN报文封装也引入了一个问题,即MTU值的设置。一般来说,虚拟机的默认MTU为1500 Bytes,也就是说原始以太网报文最大为1500字节。这个报文在经过VTEP时,会封装上50字节的新报文头(VXLAN头8字节+UDP头8字节+外部IP头20字节+外部MAC头14字节),这样一来,整个报文长度达到了1550字节。而现有的VTEP设备,一般在解封装VXLAN报文时,要求VXLAN报文不能被分片,否则无法正确解封装。这就要求VTEP之间的所有网络设备的MTU最小为 1550字节。如果中间设备的MTU值不方便进行更改,那么设置虚拟机的MTU值为1450,也可以暂时解决这个问题。

高级用法

其他参考:

https://www.cnblogs.com/lvdongjie/p/10911564.html

https://www.cnblogs.com/jiujuan/p/9017495.html#2460449143

高级过滤语法

proto[x:y]          : 过滤从x字节开始的y字节数。比如ip[2:2]过滤出3、4字节(第一字节从0开始排。x表示跳过x个字节;y缺省值为1)
proto[x:y] & z = 0  : proto[x:y]和z的与操作为0
proto[x:y] & z !=0  : proto[x:y]和z的与操作不为0
proto[x:y] & z = z  : proto[x:y]和z的与操作为z
proto[x:y] = z      : proto[x:y]等于z

#对于小于1字节的数据截取,可以使用&操作实现。

操作符:

> : greater 大于
<  : lower 小于
= : greater or equal 大于或者等于
<= : lower or equal 小于或者等于
=  : equal  等于
!= : different  不等于

IP头过滤

IP头部:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    | <-- optional
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            DATA ...                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

我们只考虑IPv4协议

位操作方式判断是否带有选项段

“一般”的IP头是20字节,但IP头有选项设置,不能直接从偏移21字节处读取数据。IP头有个长度字段可以知道头长度是否大于20字节。

+-+-+-+-+-+-+-+-+
|Version|  IHL  |
+-+-+-+-+-+-+-+-+

通常第一个字节的二进制值是:01000101,分成两个部分:

  • 0100 = 4 表示IP版本

  • 0101 = 5 表示IP头中大小为32 bit的块的个数,5 x 32 bits = 160 bits or 20 bytes

如果第一字节第二部分的值大于5,那么表示头有OPTION选项。

位操作

0100 0101 : 第一字节的二进制
0000 1111 : 与操作
<=========
0000 0101 : 结果

正确的过滤方法:
tcpdump  'ip[0] & 15 > 5'  #表示IP报文有OPTION
或者
tcpdump  'ip[0] & 0x0f > 5'

我用了16进制掩码:

That’s rather simple, if you want to:

  • keep the last 4 bits intact, use 0xf (binary 00001111)

  • keep the first 4 bits intact, use 0xf0 (binary 11110000)

分片标记(DF)及抓包

当发送端的MTU大于到目的路径链路上的MTU时就会被分片,分片信息在IP头的第7和第8字节:

如果想知道数据报中是否有碎片, 可以抓取 IP 首部中的 Flags 字段, bit 0 必须为 0, bit 1 为 0 表示可能有碎片, bit 2 为 0 表示最后一个碎片. 所以如果我们可以使用规则匹配:

Bit 0: 保留,必须是0
Bit 1: (DF) 0 = 可能分片, 1 = 不分片
Bit 2: (MF) 0 = 最后的分片, 1 = 还有分片(非最好的切片)

Fragment Offset字段只有在分片的时候才使用(此时该bit上不为0)。

要抓带DF位标记的不分片的包,第七字节的值应该是:
01000000 = 64
tcpdump 'ip[6] = 64'

抓分片包

a:匹配MF,分片包

tcpdump  'ip[6] = 32'  ## 有碎片, 但不匹配最后的碎片

b:匹配分片和最后分片

tcpdump  '((ip[6:2] > 0) and (not ip[6] = 64))'  # 匹配最后的碎片

测试分片可以用下面命令:

ping -M want -s 3000 192.168.1.101

TTL抓包

TTL 字段:

+-+-+-+-+-+-+-+-+
|  Time to Live |
+-+-+-+-+-+-+-+-+

TTL字段在第九字节,并且正好是完整的一个字节,TTL最大值是255,二进制为11111111。

可以来验证下,我们试着制定一个特需的ttl长度为 256

$ ping -M want -s 3000 -t 256 192.168.1.200
ping: ttl 256 out of range

示例:匹配小于ttl的数据报

在网关可以用下面的命令看看网络中谁在使用traceroute

tcpdump 'ip[8] < 5'  # 我们机器的网络访问在 5 跳以内

ip报文大小过滤

ip[2:2] 对应 IP 首部的 total length, 比如以下可以抓取大于 600 字节的数据报:

tcpdump -i eth1 'ip[2:2] > 600'

TCP头过滤

tcp报文的基本结构

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Acknowledgment Number                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data |       |C|E|U|A|P|R|S|F|                               |
| Offset|  Res. |W|C|R|C|S|S|Y|I|            Window             |
|       |       |R|E|G|K|H|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum            |         Urgent Pointer        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             data                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

端口过滤

抓取源端口大于1024的TCP数据包

tcpdump 'tcp[0:2] > 1024'
or
tcpdump 'tcp src portrange 1025-65535'

匹配TCP数据包的特殊标记

TCP标记定义在TCP头的第14个字节

+-+-+-+-+-+-+-+-+
|C|E|U|A|P|R|S|F|
|W|C|R|C|S|S|Y|I|
|R|E|G|K|H|T|N|N|
+-+-+-+-+-+-+-+-+

在TCP 3次握手中,两个主机是如何交换数据

1、源端发送 SYN 2、目标端口应答 SYN,ACK 3、源端发送 ACK

  • 只抓取SYN包,第十四字节是二进制的00000010,也就是十进制的2
tcpdump 'tcp[13] = 2'
  • 抓取 SYN+ACK (00010010 or 18)
tcpdump 'tcp[13] = 18'
  • 抓取SYN或者SYN-ACK
tcpdump 'tcp[13] & 2 = 2'

我们使用了掩码,它会返回任何事情,当ACK是二进制设置时候 让我们看看下面的例子(SYN-ACK)

00010010 : SYN-ACK packet
00000010 : mask (2 in decimal)
==========
00000010 : result (2 in decimal)
  • 抓取PSH-ACK
tcpdump 'tcp[13] = 24'
  • 抓所有包含FIN标记的包(FIN通常和ACK一起,表示幽会完了,回头见)
tcpdump 'tcp[13] & 1 = 1'
  • 抓取RST
tcpdump 'tcp[13] & 4 = 4'

类似的:

要抓取 FIN 报文, 使用规则 ‘tcp[13] & 1 = 1’,

抓取 RST 复位报文, 使用规则 ‘tcp[13] & 4 = 4’,

字段偏移名字

tcpdump 提供了常用的字段偏移名字:

  • icmptype (ICMP类型字段)
  • icmpcode (ICMP符号字段)
  • tcpflags (TCP标记字段)

ICMP类型值有:

icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo, icmp-routeradvert, icmp-routersolicit,
icmp-timxceed, icmp-paramprob, icmp-tstamp, icmp-tstampreply, icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreply

TCP标记值:

tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-push, tcp-ack, tcp-urg

实际上有一个很简单的方法过滤 flags(man pcap-filter and look for tcpflags)

TCP标记值:tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-push, tcp-ack, tcp-urg

tcpdump 'tcp[tcpflags] == tcp-ack'
  • 抓取所有的包,用TCP-SYN 或者 TCP-FIN 设置
tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0

下图表示了TCP各状态转换的标记

img

UDP头

0      7 8     15 16    23 24    31  
+--------+--------+--------+--------+
|     Source      |   Destination   |
|      Port       |      Port       |
+--------+--------+--------+--------+
|                 |                 |
|     Length      |    Checksum     |
+--------+--------+--------+--------+
|                                   |
|              DATA ...             |
+-----------------------------------+

如果我们想要过滤,我们可以用下面的方法

tcpdump udp dst port 53
udp[0:2]    source port
udp[2:2]    destination port
udp[4:2]    datagram length
udp[6:2]    UDP checksum

更多规则可参考 http://www.packetlevel.ch/html/tcpdumpf.html

ICMP头

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type      |     Code      |          Checksum             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             unused                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Internet Header + 64 bits of Original Data Datagram      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

在ICMP报文中,我们经常过滤 type(1 byte)和code(1 byte)

下图是ICMP报文中 Type ,我们经常用到的几个值:

0    Echo Reply                [RFC792]   回显应答报文
3    Destination Unreachable   [RFC792]   目的不可达
4    Source Quench             [RFC792]   源冷却报文
5    Redirect                  [RFC792]   重定向报文
8    Echo                      [RFC792]   请求回显报文
11   Time Exceeded             [RFC792]   超时报文

如果我们要过滤报文 type = 4

tcpdump 'icmp[0] = 4'

如我我们仅仅是要找到ICMP的回显应答报文,同时ID是500。

# python -c 'print hex(500)'
0x1f4
# python -c 'print "0x{0:X}".format(500)'
0x1F4
tcpdump -i eth0 '(icmp[0] = 0) and (icmp[4:2] = 0x1f4)'
或
tcpdump -i eth0 '(icmp[0] = 0) and (icmp[4:2] = 500)'

抓取VXLAN包

虚机(172.31.2.16)执行ping命令:ping 172.31.3.211
抓包命令,红色为vxlan 内部IP,1为icmp协议

tcpdump -env -i data "ip[50+9:1]=1 and ((ip[50+12:1]=172 and ip[50+13:1]=31 and ip[50+14:1]=2 and ip[50+15:1]=16) and (ip[50+16:1]=172 and ip[50+17:1]=31 and ip[50+18:1]=3 and ip[50+19:1]=211) )"

tcpdump -env -i data "ip[50+9:1]=1"

ip[50+9:1]=1  表示overlay报文的内层报文的协议(Protocol)。有如下取值:
1	ICMPv4	Internet Control Message Protocol for IPv4 ([RFC 792](http://tools.ietf.org/html/rfc792))
2	IGMP	Internet Group Management Protocol (RFCs [1112](http://tools.ietf.org/html/rfc1112), [2236](http://tools.ietf.org/html/rfc2236) and [3376)](http://tools.ietf.org/html/rfc3376)
4	IPv4	IPv4 in IPv4 encapsulation, “IP in IP” tunneling ([RFC 2003)](http://tools.ietf.org/html/rfc2003)
6	TCP	Transmission Control Protocol ([RFC 793](http://tools.ietf.org/html/rfc793))
8	EGP	Exterior Gatgeway Protocol ([RFC 888](http://tools.ietf.org/html/rfc888))
17	UDP	User Datagram Protocol ([RFC 768](http://tools.ietf.org/html/rfc768))
41	IPv6	IPv6 tunneled over IPv4, “6in4” tunneling ([RFC 2473](http://tools.ietf.org/html/rfc2473))
47  GRE
50	IPSec	ESP Header ([RFC 2406](http://tools.ietf.org/html/rfc2406))
51	IPSec	AH Header ([RFC 2402](http://tools.ietf.org/html/rfc2402))
89	OSPF	Open Shortest Path First routing ([RFC 1583](http://tools.ietf.org/html/rfc1583))
112 VRRP
132	SCTP	Streams Control Transmission Protocol ([RFC 4960](http://tools.ietf.org/html/rfc4960))

其他取值可参考:https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml


(ip[50+12:1]=172 and ip[50+13:1]=31 and ip[50+14:1]=2 and ip[50+15:1]=16)  表示overlay报文的内层报文的源IP

(ip[50+16:1]=172 and ip[50+17:1]=31 and ip[50+18:1]=3 and ip[50+19:1]=211)  表示overlay报文的内层报文的目标IP




tcpdump -env -i data "ip[50+9:1]=1 and ( \
    ((ip[50+12:1]=172 and ip[50+13:1]=31 and ip[50+14:1]=2 and ip[50+15:1]=16) and (ip[50+16:1]=100 and ip[50+17:1]=111 and ip[50+18:1]=0 and ip[50+19:1]=75)) \
    or \
    ((ip[50+12:1]=100 and ip[50+13:1]=111 and ip[50+14:1]=0 and ip[50+15:1]=75) and (ip[50+16:1]=172 and ip[50+17:1]=31 and ip[50+18:1]=2 and ip[50+19:1]=16)) \
)"

上述十进制表示可以转换为十六进制:
tcpdump -env -i data "ip[50+9:1]=1 and ( \
    (ip[50+12:4]=0xAC1F0210 and ip[50+16:4]=0x646F004B) \
    or \
    (ip[50+12:4]=0x646F004B and ip[50+16:4]=0xAC1F0210) \
)"

补充:使用python将ip转换为十六进制数字
ip="172.31.2.16" ; python -c "print '0x{0[0]:02X}{0[1]:02X}{0[2]:02X}{0[3]:02X}'.format([int(i) for i in '${ip}'.split('.')])"



s_ip=$(python -c "print '0x{0[0]:02X}{0[1]:02X}{0[2]:02X}{0[3]:02X}'.format([int(i) for i in '172.31.2.16'.split('.')])")
d_ip=$(python -c "print '0x{0[0]:02X}{0[1]:02X}{0[2]:02X}{0[3]:02X}'.format([int(i) for i in '100.111.0.75'.split('.')])")
tcpdump -env -i data "ip[50+9:1]=1 and ( (ip[50+12:4]=${s_ip} and ip[50+16:4]=${d_ip}) \
    or \
    (ip[50+12:4]=${d_ip} and ip[50+16:4]=${s_ip}) \
)"

mac地址过滤vxlan:

                    ICMP           目的MAC后4byte    snat/sg        目的MAC        VM(tap-xx)
tcpdump -i data "ip[50+9:1]=1 and (ether[50+2:4] = 0x3e4dbf50 or ether[50+2:4] = 0x3e6502c9)"

1、0x3e4dbf50之所以写后4byte,是因为tcpdump指定值只能是报1,2,4字节。“tcpdump: data size must be 1, 2, or 4”,所以需要把6bytes的MAC地址拆分成2+4byte
2、openstack中ovs桥实现的vxlan隧道,br-tun桥会修改源mac地址,所以源mac不容易获取,但是目标mac地址一般是固定的。

SMTP数据过滤

我们将弄一个匹配任意包的过滤,这个包包括 “MAIL”。

你可以用网址 http://www.easycalculation.com/ascii-hex.php 把ASCII转化为 十六进制, 也可以用python来转化

$ python -c 'print "MAIL".encode("hex")'
4d41494c

所以 “MAIL” 的十六进制是:0x4d41494c,那么规则就是

tcpdump '((port 25) and (tcp[20:4] = 0x4d41494c))'

这是一个包的例子

# tshark -V -i eth0 '((port 25) and (tcp[20:4] = 0x4d41494c))'
Capturing on eth0
Frame 1 (92 bytes on wire, 92 bytes captured)
    Arrival Time: Sep 25, 2007 00:06:10.875424000
    [Time delta from previous packet: 0.000000000 seconds]
    [Time since reference or first frame: 0.000000000 seconds]
    Frame Number: 1
    Packet Length: 92 bytes
    Capture Length: 92 bytes
    [Frame is marked: False]
    [Protocols in frame: eth:ip:tcp:smtp]
Ethernet II, Src: Cisco_X (00:11:5c:X), Dst: 3Com_X (00:04:75:X)
    Destination: 3Com_X (00:04:75:X)
        Address: 3Com_X (00:04:75:X)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
    Source: Cisco_X (00:11:5c:X)
        Address: Cisco_X (00:11:5c:X)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
    Type: IP (0x0800)
Internet Protocol, Src: 62.163.X (62.163.X), Dst: 192.168.X (192.168.X)
    Version: 4
    Header length: 20 bytes
    Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)
        0000 00.. = Differentiated Services Codepoint: Default (0x00)
        .... ..0. = ECN-Capable Transport (ECT): 0
        .... ...0 = ECN-CE: 0
    Total Length: 78
    Identification: 0x4078 (16504)
    Flags: 0x04 (Don't Fragment)
        0... = Reserved bit: Not set
        .1.. = Don't fragment: Set
        ..0. = More fragments: Not set
    Fragment offset: 0
    Time to live: 118
    Protocol: TCP (0x06)
    Header checksum: 0x08cb [correct]
        [Good: True]
        [Bad : False]
    Source: 62.163.X (62.163.X)
    Destination: 192.168.X (192.168.XX)
Transmission Control Protocol, Src Port: 4760 (4760), Dst Port: smtp (25), Seq: 0, Ack: 0, Len: 38
    Source port: 4760 (4760)
    Destination port: smtp (25)
    Sequence number: 0    (relative sequence number)
    [Next sequence number: 38    (relative sequence number)]
    Acknowledgement number: 0    (relative ack number)
    Header length: 20 bytes
    Flags: 0x18 (PSH, ACK)
        0... .... = Congestion Window Reduced (CWR): Not set
        .0.. .... = ECN-Echo: Not set
        ..0. .... = Urgent: Not set
        ...1 .... = Acknowledgment: Set
        .... 1... = Push: Set
        .... .0.. = Reset: Not set
        .... ..0. = Syn: Not set
        .... ...0 = Fin: Not set
    Window size: 17375
    Checksum: 0x6320 [correct]
        [Good Checksum: True]
        [Bad Checksum: False]
Simple Mail Transfer Protocol
    Command: MAIL FROM:<wguthrie_at_mysickworld--dot--com>\r\n
        Command: MAIL
        Request parameter: FROM:<wguthrie_at_mysickworld--dot--com>

HTTP数据过滤

http请求开始格式:GET / HTTP/1.1\r\n (16 bytes counting the carriage return but not the backslashes !)

“GET ” 十六进制是 47455420

# python -c 'print "GET ".encode("hex")'
47455420
tcpdump 'tcp[32:4] = 0x47455420'

HTTP数据(从man tcpdump 看到的例子)

示例:打印所有源或目的端口是80, 网络层协议为IPv4, 并且含有数据,而不是SYN,FIN以及ACK-only等不含数据的数据包.(ipv6的版本的表达式可做练习)

tcpdump 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

分析:

          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ip[2:2] = |          Total Length         |
          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

        +-+-+-+-+-+-+-+-+
ip[0] = |Version|  IHL  |
        +-+-+-+-+-+-+-+-+

            +-+-+-+-+-+-+-+-+
ip[0]&0xf = |# # # #|  IHL  | <-- that's right, we masked the version bits
            +-+-+-+-+-+-+-+-+     with 0xf or 00001111 in binary

          +-+-+-+-+
          |  Data |
tcp[12] = | Offset|
          |       |
          +-+-+-+-+

如果要抓取数据相关的报文, 比如 HTTP 的 “GET " 请求, 则需要在 TCP 首部中找到数据部分, 再匹配 ‘G’, ‘E’, ‘T’ 和 ’ ‘, 分别对应十六进制 0x47455420, ’tcp[12:1] & 0xf0 » 4’ 得到的结果是 1000, 对应 TCP 首部中的 Data offset 4bit 信息, 即可以得到 TCP 首部长度, 4位信息是表示 32 bit 的数目, 换成字节的话应该是 1000 « 2, 所以’tcp[12:1] & 0xf0) » 4’ 等同 TCP 报文中数据的起始位置, 最后要抓取 HTTP GET请求的规则应该是:

# tcpdump -i eth1 'port 80 and tcp[((tcp[12:1] & 0xf0) >> 4):4] = 0x47455420'

SSH过滤

我们看看ssh server OpenSSH 常常应答一些内容,比如"SSH-2.0-OpenSSH_3.6.1p2”, 这第一个4 bytes (SSH-)的十六进制值是 0x5353482D

# python -c 'print "SSH-".encode("hex")'
5353482d
tcpdump 'tcp[(tcp[12]>>2):4] = 0x5353482D'

如果我们想要找到老版本的OpenSSH的任意链接,这时候OpenSSH服务器应答的内容:比如 “SSH-1.99..”

tcpdump '(tcp[(tcp[12]>>2):4] = 0x5353482D) and (tcp[((tcp[12]>>2)+4):2] = 0x312E)'

MAC地址过滤

2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether ac:de:48:38:2b:5b brd ff:ff:ff:ff:ff:ff
    inet 10.110.68.31/24 brd 10.110.68.255 scope global ens3
       valid_lft forever preferred_lft forever
    inet6 fe80::aede:48ff:fe38:2b5b/64 scope link
       valid_lft forever preferred_lft forever

如果要抓取过滤源MAC地址为ac:de:48:38:2b:5b的帧:

tcpdump -i ens3 "ether[6:6] = 0xacde48382b5b"  #报错“tcpdump: data size must be 1, 2, or 4”,所以需要把6bytes的MAC地址拆分成4+2byte
修改为:
tcpdump -i data "ether[6:4] = 0xfa163e65 and ether[10:2] = 0x02c9"
tcpdump -i ens3 ether src ac:de:48:38:2b:5b

参考资料

wireshark分析vxlan包:vxlan/gre包分析_西邮记的专栏-CSDN博客_gre包头大小

tcpdump man page : http://www.tcpdump.org/tcpdump_man.html

Conversions: http://easycalculation.com/hex-converter.php

Filtering HTTP requests: http://www.wireshark.org/tools/string-cf.html

Filtering data regardless of TCP options: http://www.wireshark.org/lists/wireshark-users/201003/msg00024.html

转自:https://blog.wains.be/2007/2007-10-01-tcpdump-advanced-filters/