Linux下的网络抓包工具tcpdump原理介绍
纸上得来终觉浅,绝知此事要躬行。
tcpdump
就是根据使用者的定义对网络上的数据包进行截获的包分析工具。tcpdump
可以将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供 and
、or
、not
等逻辑语句来帮助你去掉无用的信息。
1. 基本语法
主要介绍一下使用 tcpdump 工具时经常会使用到的参数!
过滤表达式可以给 tcpdump
传送过滤表达式来起到网络包过滤的作用,而且可以支持传入单个或多个过滤表达式。当你传入的过滤表达式含有 shell
通配符时,别忘使用单引号把表达式括起来,以防 shell
自作主张的把含有通配符的表达式先进行了解释和通配。我们可以使用 man pcap-filter
命令来查看帮助信息,你会发现,过滤表达式大体可以分成三种过滤条件,类型、方向和协议,这三种条件的搭配组合就构成。
[1] 过滤主机
- 抓取所有经过 eth1,目的或源地址是 192.168.1.1 的网络数据
tcpdump -i eth1 host 192.168.1.1
- 指定源地址
tcpdump -i eth1 src host 192.168.1.1
- 指定目的地址
tcpdump -i eth1 dst host 192.168.1.1
[2] 过滤端口
- 抓取所有经过 eth1,目的或源端口是 25 的网络数据
tcpdump -i eth1 port 25
- 指定源端口
tcpdump -i eth1 src port 25
- 指定目的端口
tcpdump -i eth1 dst port 25
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # 只查目标机器端口是53或80的网络包 dst port 53 dst port 53 # tcpdump还支持如下的类型 host:指定主机名或IP地址 例如host roclinux.cn或host 202.112.18.34 net :指定网络段 例如arp net 128.3或dst net 128.3 portrange:指定端口区域 例如src or dst portrange 6000-6008 如果我们没有设置过滤类型,那么默认是host # tcpdump -i eth0 -c 3 'dst port 53 or dst port 53' tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 13:29:04.530130 IP 114.255.192.96.29832 > 116.255.245.206.http: Flags [S], seq 3169042560, win 5840, options [mss 1460,sackOK,TS val 2949111416 ecr 0], length 0 13:29:04.530660 IP 116.255.245.206.43211 > ns.sc.cninfo.net.domain: 40188+ PTR? 206.245.255.116.in-addr.arpa. (46) 13:29:04.548589 IP 114.255.192.96.29832 > 116.255.245.206.http: Flags [.], ack 3709396068, win 5840, options [nop,nop,TS val 2949111475 ecr 1601243970], length 0 3 packets captured 10 packets received by filter 0 packets dropped by kernel |
[3] 网络过滤
tcpdump -i eth1 net 192.168
tcpdump -i eth1 src net 192.168
tcpdump -i eth1 dst net 192.168
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # 想查看这个源机器和那个目的机器之间的网络包 设置src-source和dst-destination就好了,tcpdump还支持使用and和or来进行搭配组合呢! 如果没有设置的话,默认是src or dst。 # tcpdump -i eth0 'dst 8.8.8.8' tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 13:21:23.281978 IP 116.255.245.206 > google-public-dns-a.google.com: ICMP echo request, id 23081, seq 1, length 64 13:21:24.286663 IP 116.255.245.206 > google-public-dns-a.google.com: ICMP echo request, id 23081, seq 2, length 64 13:21:25.288612 IP 116.255.245.206 > google-public-dns-a.google.com: ICMP echo request, id 23081, seq 3, length 64 ^C 3 packets captured 5 packets received by filter 0 packets dropped by kernel |
[4] 协议过滤
tcpdump -i eth1 arp
tcpdump -i eth1 ip
tcpdump -i eth1 tcp
tcpdump -i eth1 udp
tcpdump -i eth1 icmp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 只想抓UDP的包,不被TCP的包打扰 可以把udp改为ether、ip、ip6、arp、tcp、rarp等等 # 为啥这些协议里没有应用层协议呢? 其实理由很简单,应用层协议非基础类网络协议,经常会新增或淘汰。 tcpdump不会深入到应用层部分去智能解析,所以你看到的tcpdump支持的protocol都是应用层以下的。 # tcpdump -i eth0 -c 10 'udp' tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 11:25:20.801612 IP 116.255.245.48.54808 > 229.111.112.12.csd-mgmt-port: UDP, length 4 11:25:20.802120 IP 116.255.245.206.54313 > ns.sc.cninfo.net.domain: 5256+ PTR? 12.112.111.229.in-addr.arpa. (45) 11:25:21.145126 IP ns.sc.cninfo.net.domain > 116.255.245.206.54313: 5256 NXDomain 0/0/0 (45) 11:25:21.145315 IP 116.255.245.206.46658 > ns.sc.cninfo.net.domain: 15551+ PTR? 48.245.255.116.in-addr.arpa. (45) 11:25:21.153966 IP 116.255.245.43.62220 > 229.111.112.12.csd-mgmt-port: UDP, length 4 11:25:21.180135 IP 116.255.245.61.hsrp > all-routers.mcast.net.hsrp: HSRPv0-hello 20: state=active group=21 addr=116.255.245.33 11:25:21.231151 IP ns.sc.cninfo.net.domain > 116.255.245.206.46658: 15551 NXDomain 0/0/0 (45) 7 packets captured 8 packets received by filter 0 packets dropped by kernel |
[5] 常用表达式
- 非
!
ornot
- 且
&&
orand
- 或
||
oror
- 抓取所有经过 eth1,目的地址是 192.168.1.254 或 192.168.1.200 端口是 80 的 TCP 数据
tcpdump -i eth1 '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.200)))'
- 抓取所有经过 eth1,目标 MAC 地址是 00:01:02:03:04:05 的 ICMP 数据
tcpdump -i eth1 '((icmp) and ((ether dst host 00:01:02:03:04:05)))'
- 抓取所有经过 eth1,目的网络是 192.168,但目的主机不是 192.168.1.200 的 TCP 数据
tcpdump -i eth1 '((tcp) and ((dst net 192.168) and (not dst host 192.168.1.200)))'
1 2 3 4 5 6 7 8 9 10 11 | # tcpdump -i eth0 -nn -X 'port 53' -c 1 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 19:48:33.285838 IP 116.255.245.206.47940 > 8.8.8.8.53: 22768+ A? www.baidu.com. (31) 0x0000: 4500 003b c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com..... 1 packets captured 1 packets received by filter 0 packets dropped by kernel |
2. 协议包头
介绍常见的,协议的包头定义格式!
- IP 数据报格式
- 以太网帧格式
- TCP 头格式
- UDP 头格式
- HTTP 协议格式
3. 包头过滤
主要介绍 TCP 和 UDP 协议包头的各个字段的对应含义以及抓取方式!
首先了解如何从包头过滤信息
1 2 3 4 5 6 | proto[x:y] : 过滤从x字节开始的y字节数。比如ip[2:2]过滤出3、4字节(第一字节从0开始排) 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 操作符 : >, <, >=, <=, =, != |
IP
头 ==> 只针对IPv4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 ... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
IP
选项设置了吗?
一般的
IP
头是20 字节,但 IP 头有选项设置,不能直接从偏移 21 字节处读取数据。IP 头有个长度字段可以知道头长度是否大于 20 字节。123+-+-+-+-+-+-+-+-+|Version| IHL |+-+-+-+-+-+-+-+-+通常第一个字节的二进制值是:
01000101
,分成两个部分- 10100
= 4 表示 IP 版本,
10101= 5 表示 IP 头 32 bit 的块数
- 4 x 5 = 20 bytes
- 5 x 32 bits = 160 bits
- 160 bits / 2 =
20 bytes
如果第一字节第二部分的值大于 5,那么表示头有IP 选项,下面介绍两种过滤方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 方法一 ==> 比较法 # 比较第一字节的值是否大于`01000101`,这可以判断IPv4带IP选项的数据和IPv6的数据。 # `01000101`十进制等于`69`,计算方法如下所示 # 如果设置了IP选项,那么第一字节是01000110(十进制70) # 过滤规则:`tcpdump -i eth1 'ip[0] > 69'`,IPv6的数据也会匹配 0 : 0 \ 1 : 2^6 = 64 \ 第一部分 (IP版本) 0 : 0 / 0 : 0 / - 0 : 0 \ 1 : 2^2 = 4 \ 第二部分 (头长度) 0 : 0 / 1 : 2^0 = 1 / 64 + 4 + 1 = 69 |
1 2 3 4 5 6 7 8 9 | 方法二 ==> 位操作 # 正确的过滤方法 # (1)tcpdump -i eth1 'ip[0] & 15 > 5' # (2)tcpdump -i eth1 'ip[0] & 0x0f > 5' 0100 0101 : 第一字节的二进制 0000 1111 : 与操作 <========= 0000 0101 : 结果 |
分片标记
- 当发送端的
MTU
大于到目的路径链路上的MTU
时就会被分片
,权威的请参考《TCP/IP 详解》 Fragment Offset
字段只有在分片的时候才使用- 要抓
Flags
中带DF
位标记的不分片的包,第七字节的值应该是:01000000 = 64
tcpdump -i eth1 'ip[6] = 64'
,从0
开始编号1234567分片信息在IP头的第七和第八字节+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|Flags| Fragment Offset |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+Bit 0: 保留,必须是0Bit 1: (DF) 0 = 可能分片, 1 = 不分片Bit 2: (MF) 0 = 最后的分片, 1 = 还有分片
抓分片包
匹配
1MF分片包,第七字节的值应该是:
100100000 = 32tcpdump -i eth1 'ip[6] = 32'
最后分片包的开始 3 位是 0,但是有
Fragment Offset
字段匹配分片
和
最后分片
tcpdump -i eth1 '((ip[6:2] > 0) and (not ip[6] = 64))'
测试分片可以用如下命令
ping -M want -s 3000 192.168.1.1
匹配小 TTL
- 1TTL
字段在第九字节,并且正好是完整的
一个字节
,TTL 最大值是
1255,二进制为
111111111本人提供Oracle(OCP、OCM)、MySQL(OCP)、PostgreSQL(PGCA、PGCE、PGCM)等数据库的培训和考证业务,私聊QQ646634621或微信db_bao,谢谢!