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

前言

网络编程 中,有两大抓包利器,就是 tcpdumpWireshark ,它们就好比《倚天屠龙记》里的 倚天剑屠龙刀 得之者得天下。在 网络编程 的世界中,可以说 『得 TcpdumpWireshark , 便可纵览网络协议,看穿一切』

前两篇文章我们用 Go 语言,实现了 Echo 客户端/服务器交互程序,带大家初步体验了一下 网络编程

题外话

还没有看的同学,强烈推荐看下,然后再来看这篇文章哦。

但俗话说得好『百闻不如一见』今天我们就要用 tcpdumpWireshark 揭开 Echo 客户端/服务器交互程序』 的神秘面纱,通过工具一窥网络数据包的交互细节。

那么 tcpdumpWireshark 到底是什么呢?下面我们一一揭晓。

目录

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 三部分组成。他们是通过 组合语句 ,只抓取 条件为真 的网络包,过滤无用的网络包,那么它们具体又是什么呢?

  1. 先说协议

协议就是我们所说的 ip , ip6 , arp , rarp , decnet , tcp , udp

协议紧跟在 选项 之后,同时还受之后的类型影响。

看看常用的组合 tcp port 21 , udp portrange 7000-7009 ,这里面的 tcp , udp 就是协议。

  1. 其次方向

方向定义了一个指定的网络包传输方向。比如 srcdstsrc or dstsrc 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
  1. 这里的 ip src host 127.0.0.1 and port 8888 就是所谓的 表达式 ,也就是这个条件为真,网络包才会被抓取,否则直接被过滤忽略。

  2. 其含义应该一目了然,因为使用 src host 127.0.0.1 ,所以我们必须指定协议为 ip ,因为只有 ip协议 中有 host ,其表示网络包的 主机IP 地址必须是 127.0.0.1 ,不用 tcp 是因为 tcp协议 中只有端口。 src 又把范围缩小到必须是 『 发送方的地址为 127.0.0.1 』。

  3. port 8888 表示网络包的 端口 必须是 8888

  4. 中间的 and 表示这是一个 的关系。

  5. 而这里的 -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 上边表格已经讲解过喽。

实践一下

  1. 起一个终端,启动我们的 echoServer 程序,在命令行键入 ./echoServer

  2. 再起一个终端,启动我们的 tcpdump , 在命令行键入 tcpdump -S -nn -i lo src host 127.0.0.1 and port 8888

  3. 再再起一个终端,启动我们的 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

通过三次数据收发,我们能够看到:

  1. 一次数据发送 PUSH , 必须要有一个 ACK

  2. 下次发送序列号是 本次序列号 + 数据长度

  3. 窗口大小每次都会上报

在客户端所在终端,键入 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
  1. 四次挥手,表示一个连接的终止。

  2. 第二次的 ACK 和第三次的 FIN 合并为一个数据包,所以我们看到的好像是 三次挥手

可是命令行里抓包终究不太直观,我们也没有看到详细的数据是什么样的。所以通常我们需要将 tcpdump 抓下来的网络包存储到以 .pacp 文件结尾的网络包文件中。然后通过 Wireshark 进行网络包的可视化分析。下面我们来看看 Wireshark 到底怎么用吧。

Wireshark 简析

Wireshark 是一个网络封包分析软件,可以直观的查看网络包的格式和内容,其图标是就是 鲨鱼鳞

分析一下我们的`echo`交互程序

  1. 如之前介绍的,我们在命令行启动我们的 echoServer程序

  2. 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

  3. 新起终端,启动客户端程序, ./echoClient

  4. 然后我们发送数据 hello-echo

  5. 键入 Ctrl+C ,结束客户端

  6. tcpdump 所在终端, Ctrl+C 结束 tcpdump 命令,我们就能看到 echo.pcap 文件了

  7. 将该文件用我们的 Wireshark 打开。

这时候我们会看到网络包的详细内容:

说说网络交互

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

数据包细节

通过包细节,我们可以看到基于 网络协议网络编程 是分层的。当我们的 echo 客户端向服务器发送 hello-echo ,可以通过 tcp segment 看到其中的细节信息,和我们大学学习的 TCP 协议格式也是吻合的。

写在最后

本文我们通过 tcpdumpWireshark 更加深刻的了解了我们的 echo客户端/服务器 交互程序。通过抓包,我们可以看到 socket API网络协议 是密切相关的,想要学好 网络编程 ,掌握 网络协议 也是必要的。之后蛇叔会把 TCPIP 协议拆解了,一步步带你理解它。为我们 看得见的网络编程 专栏打下坚实的理论基础,然后再进行下一步 非阻塞 网络编程学习。

有的朋友私信想要 echo客户端服务器 程序的源码,蛇叔已经打包源码,扫一扫下边的二维码,关注并回复 echo ,就可以得到 echo客户端服务器 程序源代码喽~~记得帮忙点下在看,非常感谢,有不足之处,欢迎留言讨论。

( 扫一扫,回复echo, 得echo程序源码 )

参考文献

  1. 《TCP/IP详解 卷1》

  2. 《Unix网络编程 卷1》

  3. 《计算机网络》

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

各位朋友,我们下期再见。