网络抓包大法好,tcpdump 和 Wireshark 少不了

前言
在 网络编程
中,有两大抓包利器,就是 tcpdump
和 Wireshark
,它们就好比《倚天屠龙记》里的 倚天剑
和 屠龙刀
得之者得天下。在 网络编程
的世界中,可以说 『得 Tcpdump
和 Wireshark
, 便可纵览网络协议,看穿一切』 。
前两篇文章我们用 Go
语言,实现了 Echo
客户端/服务器交互程序,带大家初步体验了一下 网络编程
。
题外话
还没有看的同学,强烈推荐看下,然后再来看这篇文章哦。
但俗话说得好『百闻不如一见』今天我们就要用 tcpdump
和 Wireshark
揭开 『 Echo
客户端/服务器交互程序』 的神秘面纱,通过工具一窥网络数据包的交互细节。
那么 tcpdump
和 Wireshark
到底是什么呢?下面我们一一揭晓。
目录

tcpdump 简析
tcpdump
简单来说就是 dump traffic on a network
,通过匹配 bool表达式
来跟踪网络接口上的网络数据包,并打印出相关的详细内容描述信息。
tcpdump
是一个命令行网络抓包工具,其语法格式是 『 tcpdump 选项 布尔表达式 』。这里所谓的 布尔表达式
指的是 条件表达式 ,又称为 表达式 ,英文 expression
,它由三部分组成,分别是:
proto dir type
画一张图

-
关于选项
这一张图片清晰地列出了 tcpdump
的语法结构,平时我们在 linux
终端,敲下 man tcpdump
,首先看到的便是各种各样的 option
。

这里我们只讲几个常用的选项,其他选项,大家平时可以用 man tcpdump
来查看。

-
关于表达式
上文我们已经说过,表达式 expression 由 协议proto
, 方向dir
, 类型type
三部分组成。他们是通过 组合语句 ,只抓取 条件为真 的网络包,过滤无用的网络包,那么它们具体又是什么呢?
-
先说协议
协议就是我们所说的 ip
, ip6
, arp
, rarp
, decnet
, tcp
, udp
等
协议紧跟在 选项 之后,同时还受之后的类型影响。
看看常用的组合 tcp port 21
, udp portrange 7000-7009
,这里面的 tcp , udp 就是协议。
-
其次方向
方向定义了一个指定的网络包传输方向。比如 src
, dst
, src or dst
, src and dst
等。
-
src
: 表示发送者 -
dst
: 表示接收者 -
src or dst
表示发送者或者接收者 -
src and dst
表示发送者并且接收者
3. 最后 类型
类型限定的是关注哪些网络包,可能的类型有 host
, net
, port
, portrange
常用的组合有 host foo
表示主机名是foo的网络包, port 20
表示端口是20的网络包。
举个 栗子
tcpdump -S -nn -i lo ip src host 127.0.0.1 and port 8888
-
这里的
ip src host 127.0.0.1 and port 8888
就是所谓的表达式
,也就是这个条件为真,网络包才会被抓取,否则直接被过滤忽略。 -
其含义应该一目了然,因为使用
src host 127.0.0.1
,所以我们必须指定协议为 ip ,因为只有ip协议
中有host
,其表示网络包的 主机IP 地址必须是127.0.0.1
,不用tcp
是因为tcp协议
中只有端口。src
又把范围缩小到必须是 『 发送方的地址为127.0.0.1
』。 -
port 8888
表示网络包的 端口 必须是8888
。 -
中间的
and
表示这是一个 且 的关系。 -
而这里的
-S
,-nn
和-i lo
是 选项『option』 。-nn
表示使用原始的ip地址和端口号,不使用命名方式。-i lo
表示我们捕获的是哪个 网络接口 的数据包。
那我们的机器又有哪些网络接口呢?
我们使用 ip add
便能查看本机网络接口,也就是有几张网卡。
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 52:54:00:8f:10:b9 brd ff:ff:ff:ff:ff:ff inet 191.168.9.2/20 brd 172.21.31.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::5034:ff:fe8f:50a9/64 scope link valid_lft forever preferred_lft forever
-
lo表示这是一个 回环地址 ,它不属于任何一个有类别地址类。它代表设备的本地虚拟接口,所以默认被看作是永远不会宕掉的接口。
-
eth0表示这是一个真实的网卡接口。
因为我们的 Echo客户端/服务器
交互程序,是使用的 ip
地址 127.0.0.1
, 所以这里当然要用 -i lo
喽,置于 -S
, -nn
上边表格已经讲解过喽。
实践一下
-
起一个终端,启动我们的
echoServer
程序,在命令行键入./echoServer
。 -
再起一个终端,启动我们的
tcpdump
, 在命令行键入tcpdump -S -nn -i lo src host 127.0.0.1 and port 8888
。 -
再再起一个终端,启动我们的
echoClient
程序,在命令行键入./echoClient
。
这时候我们观察一下 tcpdump
所在的终端,会打印出以下信息。
# 三次握手 14:50:19.383814 IP 127.0.0.1.34372 > 127.0.0.1.8888: Flags [S], seq 3494436218, win 43690, options [mss 65495,sackOK,TS val 2254490385 ecr 0,nop,wscale 7], length 0 14:50:19.383822 IP 127.0.0.1.8888 > 127.0.0.1.34372: Flags [S.], seq 3120187972, ack 3494436219, win 43690, options [mss 65495,sackOK,TS val 2254490385 ecr 2254490385,nop,wscale 7], length 0 14:50:19.383830 IP 127.0.0.1.34372 > 127.0.0.1.8888: Flags [.], ack 3120187973, win 342, options [nop,nop,TS val 2254490385 ecr 2254490385], length 0
首先我们看一下输出格式:
其中这里的 Flags
,表示的是 TcpFlag
。枚举如下:
-
S
: 表示SYN
-
F
: 表示FIN
-
P
: 表示PUSH
-
R
: 表示RST
-
U
: 表示URG
, 紧急数据 -
W
: 表示ECN CWR
-
E
: 表示ECN-Echo
-
.
: 表示ACK
这里大家简单了解一下 我们三次握手成功了 ,协商了 发送序列号
和 窗口大小
。
下一篇文章会拆解 TCP协议
哦,麻烦大家 关注 , 点赞 ,静待下篇再详细讲解这块。
在客户端所在的终端,键入 hello-echo
,我们再看看 tcpdump
输出如下
14:50:22.316984 IP 127.0.0.1.34372 > 127.0.0.1.8888: Flags [P.], seq 3494436219:3494436229, ack 3120187973, win 342, options [nop,nop,TS val 2254493318 ecr 2254490385], length 10 14:50:22.317044 IP 127.0.0.1.8888 > 127.0.0.1.34372: Flags [.], ack 3494436229, win 342, options [nop,nop,TS val 2254493318 ecr 2254493318], length 0 14:50:22.317059 IP 127.0.0.1.8888 > 127.0.0.1.34372: Flags [P.], seq 3120187973:3120187983, ack 3494436229, win 342, options [nop,nop,TS val 2254493318 ecr 2254493318], length 10 14:50:22.317113 IP 127.0.0.1.34372 > 127.0.0.1.8888: Flags [.], ack 3120187983, win 342, options [nop,nop,TS val 2254493318 ecr 2254493318], length 0
客户端发送第二次数据,内容为 echo
14:50:24.485114 IP 127.0.0.1.34372 > 127.0.0.1.8888: Flags [P.], seq 3494436229:3494436233, ack 3120187983, win 342, options [nop,nop,TS val 2254495486 ecr 2254493318], length 4 14:50:24.485246 IP 127.0.0.1.8888 > 127.0.0.1.34372: Flags [P.], seq 3120187983:3120187987, ack 3494436233, win 342, options [nop,nop,TS val 2254495486 ecr 2254495486], length 4 14:50:24.485343 IP 127.0.0.1.34372 > 127.0.0.1.8888: Flags [.], ack 3120187987, win 342, options [nop,nop,TS val 2254495487 ecr 2254495486], length 0
客户端发送第三次数据,内容为 hello
14:50:26.437130 IP 127.0.0.1.34372 > 127.0.0.1.8888: Flags [P.], seq 3494436233:3494436238, ack 3120187987, win 342, options [nop,nop,TS val 2254497438 ecr 2254495486], length 5 14:50:26.437198 IP 127.0.0.1.8888 > 127.0.0.1.34372: Flags [P.], seq 3120187987:3120187992, ack 3494436238, win 342, options [nop,nop,TS val 2254497438 ecr 2254497438], length 5 14:50:26.437309 IP 127.0.0.1.34372 > 127.0.0.1.8888: Flags [.], ack 3120187992, win 342, options [nop,nop,TS val 2254497439 ecr 2254497438], length 0
通过三次数据收发,我们能够看到:
-
一次数据发送
PUSH
, 必须要有一个ACK
-
下次发送序列号是
本次序列号
+数据长度
-
窗口大小每次都会上报
在客户端所在终端,键入 Ctrl+C
# 四次挥手 14:50:27.607016 IP 127.0.0.1.34372 > 127.0.0.1.8888: Flags [F.], seq 3494436238, ack 3120187992, win 342, options [nop,nop,TS val 2254498608 ecr 2254497438], length 0 14:50:27.607125 IP 127.0.0.1.8888 > 127.0.0.1.34372: Flags [F.], seq 3120187992, ack 3494436239, win 342, options [nop,nop,TS val 2254498608 ecr 2254498608], length 0 14:50:27.607130 IP 127.0.0.1.34372 > 127.0.0.1.8888: Flags [.], ack 3120187993, win 342, options [nop,nop,TS val 2254498608 ecr 2254498608], length 0
-
四次挥手,表示一个连接的终止。
-
第二次的
ACK
和第三次的FIN
合并为一个数据包,所以我们看到的好像是三次挥手
。
可是命令行里抓包终究不太直观,我们也没有看到详细的数据是什么样的。所以通常我们需要将 tcpdump
抓下来的网络包存储到以 .pacp
文件结尾的网络包文件中。然后通过 Wireshark
进行网络包的可视化分析。下面我们来看看 Wireshark 到底怎么用吧。
Wireshark 简析

Wireshark
是一个网络封包分析软件,可以直观的查看网络包的格式和内容,其图标是就是 鲨鱼鳞
。
分析一下我们的`echo`交互程序
-
如之前介绍的,我们在命令行启动我们的
echoServer程序
。 -
在
tcpdump -S -nn -i lo ip src host 127.0.0.1 and port 8888
命令中加入-w echo.pcap
选项也就是tcpdump -S -nn -w echo.pcap -i lo ip src host 127.0.0.1 and port 8888
。 -
新起终端,启动客户端程序,
./echoClient
。 -
然后我们发送数据 hello-echo
-
键入
Ctrl+C
,结束客户端 -
在
tcpdump
所在终端,Ctrl+C
结束tcpdump
命令,我们就能看到echo.pcap
文件了 -
将该文件用我们的
Wireshark
打开。
这时候我们会看到网络包的详细内容:

说说网络交互

通过 Wireshark
我们能够清晰得看到 echo
客户端程序的交互过程,通过颜色区分不同的数据包,当我们选中一个数据包,该行会变为蓝色背景,起到了 集中视觉 的效果。
数据包细节

通过包细节,我们可以看到基于 网络协议
的 网络编程 是分层的。当我们的 echo
客户端向服务器发送 hello-echo
,可以通过 tcp segment
看到其中的细节信息,和我们大学学习的 TCP
协议格式也是吻合的。
写在最后
本文我们通过 tcpdump
和 Wireshark
更加深刻的了解了我们的 echo客户端/服务器
交互程序。通过抓包,我们可以看到 socket API
和 网络协议
是密切相关的,想要学好 网络编程 ,掌握 网络协议
也是必要的。之后蛇叔会把 TCP
, IP
协议拆解了,一步步带你理解它。为我们 看得见的网络编程
专栏打下坚实的理论基础,然后再进行下一步 非阻塞
网络编程学习。
有的朋友私信想要 echo客户端服务器
程序的源码,蛇叔已经打包源码,扫一扫下边的二维码,关注并回复 echo
,就可以得到 echo客户端服务器
程序源代码喽~~记得帮忙点下在看,非常感谢,有不足之处,欢迎留言讨论。

( 扫一扫,回复echo, 得echo程序源码 )
参考文献
-
《TCP/IP详解 卷1》
-
《Unix网络编程 卷1》
-
《计算机网络》

希望大家喜欢,原创文章不易,麻烦大家 关注
, 在看
, 转发
一键三连,谢谢大家。希望通过 代码+图片 的方式,教大家学 看得见的网络编程 。做不了火影主角,做个掌握核心科技的“蛇叔”也不错哈 。
各位朋友,我们下期再见。