Linux下的网络抓包工具tcpdump原理介绍

0    104    2

Tags:

👉 本文共约12207个字,系统预计阅读时间或需46分钟。

纸上得来终觉浅,绝知此事要躬行。

tcpdump 就是根据使用者的定义对网络上的数据包进行截获的包分析工具。tcpdump 可以将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供 andornot 等逻辑语句来帮助你去掉无用的信息。

Linux下的网络抓包工具tcpdump原理介绍


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

[3] 网络过滤

  • tcpdump -i eth1 net 192.168
  • tcpdump -i eth1 src net 192.168
  • tcpdump -i eth1 dst net 192.168

[4] 协议过滤

  • tcpdump -i eth1 arp
  • tcpdump -i eth1 ip
  • tcpdump -i eth1 tcp
  • tcpdump -i eth1 udp
  • tcpdump -i eth1 icmp

[5] 常用表达式

    • ! or not
    • && or and
    • || or or
  • 抓取所有经过 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)))'


2. 协议包头

介绍常见的,协议的包头定义格式!

  • IP 数据报格式

Linux下的网络抓包工具tcpdump原理介绍

  • 以太网帧格式

Linux下的网络抓包工具tcpdump原理介绍

  • TCP 头格式

Linux下的网络抓包工具tcpdump原理介绍

  • UDP 头格式

Linux下的网络抓包工具tcpdump原理介绍

  • HTTP 协议格式

Linux下的网络抓包工具tcpdump原理介绍

Linux下的网络抓包工具tcpdump原理介绍


3. 包头过滤

主要介绍 TCP 和 UDP 协议包头的各个字段的对应含义以及抓取方式!

首先了解如何从包头过滤信息

IP ==> 只针对IPv4

IP选项设置了吗?

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

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

    = 4 表示 IP 版本,

    = 5 表示 IP 头 32 bit 的块数

    • 4 x 5 = 20 bytes
    • 5 x 32 bits = 160 bits
    • 160 bits / 2 = 20 bytes
  • 如果第一字节第二部分的值大于 5,那么表示头有IP 选项,下面介绍两种过滤方法

分片标记

  • 当发送端的MTU大于到目的路径链路上的MTU时就会被分片,权威的请参考《TCP/IP 详解》
  • Fragment Offset字段只有在分片的时候才使用
  • 要抓Flags中带DF位标记的不分片的包,第七字节的值应该是:01000000 = 64
  • tcpdump -i eth1 'ip[6] = 64',从0开始编号

抓分片包

  • 匹配

    分片包,第七字节的值应该是:

    • tcpdump -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

  • 字段在第九字节,并且正好是完整的

    一个字节

    本人提供Oracle(OCP、OCM)、MySQL(OCP)、PostgreSQL(PGCA、PGCE、PGCM)等数据库的培训和考证业务,私聊QQ646634621或微信db_bao,谢谢!

    ,TTL 最大值是

    ,二进制为

    • 可以用下面的命令验证一下

    • ping -M want -s 3000 -t 256 192.168.1.200

    • ping: ttl 256 out of range

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

    • tcpdump -i eth1 'ip[8] < 5'

抓大于 X 字节的包

  • 大于 600 字节
    • tcpdump -i eth1 'ip[2:2] > 600'

更多的 IP 过滤

首先还是需要知道 TCP 基本结构,再次推荐《TCP/IP 详解》,卷一就够看的了

  • TCP 头

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

    • tcpdump -i eth1 'tcp[0:2] > 1024'
  • 匹配TCP数据包的特殊标记

  • TCP 三次握手

没女朋友的童鞋要学习一下:

  1. MM,你的手有空吗?--
  2. 有空,你呢?\~~
  3. 我也有空 _

失败的loser是酱紫的:

  1. MM,这是你掉的板砖吗?(SYN)  ̄▽ ̄
  2. 不是,找拍啊?(RST-ACK) ˋ﹏ˊ
  • 只抓 SYN 包,第十四字节是二进制的 00000010,也就是十进制的 2
    • tcpdump -i eth1 'tcp[13] = 2'
  • 抓 SYN, ACK (00010010 or 18)
    • tcpdump -i eth1 'tcp[13] = 18'
  • 抓 SYN 或者 SYN-ACK
    • tcpdump -i eth1 'tcp[13] & 2 = 2'
    • 用到了位操作,就是不管 ACK 位是啥。
  • 抓 PSH-ACK
    • tcpdump -i eth1 'tcp[13] = 24'
  • 抓所有包含 FIN 标记的包(FIN 通常和 ACK 一起,表示幽会完了,回见)
    • tcpdump -i eth1 'tcp[13] & 1 = 1'
  • 抓 RST(勾搭没成功,伟大的 greatwall 对她认为有敏感信息的连接发 RST 包,典型的棒打鸳鸯)
    • tcpdump -i eth1 'tcp[13] & 4 = 4'

TCP 各种状态的标记

Linux下的网络抓包工具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
  • 按照 TCP 标记位抓包
    • 只抓 SYN 包
    • tcpdump -i eth1 'tcp[tcpflags] = tcp-syn'
    • 抓 SYN, ACK
    • tcpdump -i eth1 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack != 0'
  • 抓 SMTP 数据
    • tcpdump -i eth1 '((port 25) and (tcp[(tcp[12]>>2):4] = 0x4d41494c))'
    • 抓取数据区开始为”MAIL”的包,”MAIL”的十六进制为 0x4d41494c。
  • 抓 HTTP GET 数据
    • tcpdump -i eth1 'tcp[(tcp[12]>>2):4] = 0x47455420'
    • “GET “的十六进制是 47455420
  • 抓 SSH 返回
    • tcpdump -i eth1 'tcp[(tcp[12]>>2):4] = 0x5353482D'
    • “SSH-“的十六进制是 0x5353482D
  • 抓老版本的 SSH 返回信息,如”SSH-1.99..”
    • tcpdump -i eth1 '(tcp[(tcp[12]>>2):4] = 0x5353482D) and (tcp[((tcp[12]>>2)+4):2] = 0x312E)'

4. 详细注解

分析对应协议头部的对应位置展示!

如果是为了查看数据内容,建议用tcpdump -s 0 -w filename把数据包都保存下来,然后用wiresharkFollow TCP Stream/Follow UDP Stream来查看整个会话的内容。

-s 0是抓取完整数据包,否则默认只抓 68 字节。另外,用tcpflow也可以方便的获取TCP 会话内容,支持tcpdump的各种表达式。

UDP 头

  • 抓 DNS 请求数据
    • tcpdump -i eth1 udp dst port 53

其他选项

-c参数对于运维人员来说也比较常用,因为流量比较大的服务器,靠人工CTRL+C还是抓的太多,甚至导致服务器宕机,于是可以用-c参数指定抓多少个包。

  • 上面的命令计算抓 10000 个 SYN 包花费多少时间,可以判断访问量大概是多少
    • time tcpdump -nn -i eth0 'tcp[tcpflags] = tcp-syn' -c 10000 > /dev/null

5. 常用选项

详细介绍几乎所有 Tcpdump 工具的使用参数和功能特点!

  • -i选项】- 指明网卡设备
    • interface的含义,是指我们有义务告诉tcpdump希望他去监听哪一个网卡。
    • 这个选项,在我们一台服务器有多块网卡时很有必要。
  • -nn选项】- 端口不转换
    • 意思是说当tcpdump遇到协议号或端口号时,不要将这些号码转换成对应的协议名称或端口名称。
    • 比如,众所周知21端口是FTP端口,我们希望显示 21,而非tcpdump自作聪明的将它显示成FTP
  • -X选项】- 显示原始数据
    • 告诉tcpdump命令,需要把协议头和包内容都原原本本的显示出来。(tcpdump 会以16进制ASCII的形式显示),这在进行协议分析时是绝对的利器。
  • -c选项】- 抓取数据数量
    • count的含义,这设置了我们希望tcpdump帮我们抓几个包。
    • 设置的是 1,所以tcpdump不会帮我再多抓那怕一个包回来。

  • -t选项】- 输出时不打印时间戳


  • -v选项】- 输出更详细的信息
    • 加了-v选项之后,在原有输出的基础之上,你还会看到tos值、ttl值、id值、len总长度、checknum校验值等。


  • -F选项】- 指定过滤表达式所在的文件
    • 还记得我们在第一招中所提到的命令么,我帮助大家回忆一下:
    • tcpdump -i eth0 -nn -X 'port 53' -c 1
    • 这里面的'port 53'便叫做过滤表达式,用于设置我们抓包的条件的,只有满足过滤条件的网络包,才会被抓过来。当这个过滤条件非常复杂,或者我们需要将一个过滤条件固化下来复用的时候,就会想到把它存到一个文本文件中。此时,-F选项就会派上用场。
    • 我们建立了一个filter.txt文本文件来存储过滤表达式,然后通过-F来指定filter.txt,这样tcpdump就会心知肚明地读取filter.txt中的内容作为过滤条件。


  • -w选项】- 将流量保存到文件中
    • 通过下面的例子可以看到,通过-w选项将流量都存储在了flowdata文件中了。大家是否有兴趣lessflowdata,看看里面都是什么东东?悲剧,原来都是二进制格式的,无法直接通过文本方式查看。
    • tcpdump-w方式是把raw packets(原始网络包)直接存储到文件中了,也就是存储的都是结构体形式,而非是分析之后的文本格式的信息,因此大家是无法直接通过less命令查看的。那么,怎么查看呢?大家想必也想到了,就是用-r选项。


  • -r选项】- 读取 raw packets 文件
    • 其实上面的命令就是在不知不觉中进行了流量回放,你会发现网络包被的速度都按照历史进行了回放,真像一个时光机 !
    • 由于是按raw packets来存储的,所以你完全可以使用-e-l过滤表达式来对输出信息进行控制,十分方便。

  • -e选项】- 增加以太网帧头部信息输出
    • 在刚才加-e选项的输出中,会发现有oui Unknown的字样,这oui是什么东东呢?
    • OUI,即Organizationally unique identifier,是组织唯一标识符。在任何一块网卡(NIC)中烧录的6字节MAC地址中,前 3 个字节体现了 OUI,其表明了 NIC 的制造组织。通常情况下,该标识符是唯一的。

  • 如果还是看不懂,说明你忘记了以太网协议的头格式,我再这里补充下,帮大家回忆回忆。


  • -l选项】- 使得输出变为行缓冲
    • 选项-l的作用就是将tcpdump的输出变为行缓冲方式,这样可以确保tcpdump遇到的内容一旦是换行符即将缓冲的内容输出到标准输出,以便于利用管道或重定向方式来进行后续处理。
    • 众所周知,Linux/UNIX的标准I/O提供了全缓冲行缓冲无缓冲三种缓冲方式。标准错误是不带缓冲的,终端设备常为行缓冲,而其他情况默认都是全缓冲的。
    • 大家在使用tcpdump时,有时会有这样的需求:对于 tcpdump 输出的内容,提取每一行的第一个域,即时间域,并输出出来,为后续统计所用,这种场景下,我们就需要使用到-l来将默认的全缓冲变为行缓冲了。
    • 如果不加-l选项,那么只有全缓冲区满,才会输出一次,这样不仅会导致输出是间隔不顺畅的,而且当你ctrl-c时,很可能会断到一行的半截,损坏统计数据的完整性。

6. 实例演示

展示一下使用的使用方式,以备即时即用!

这个 ftp、ftp-data 到底对应哪个端口?除了 ftp/ftp-data,还有哪些服务名称我可以直接用呢?在 Linux 系统中,/etc/services 这个文件里面,就存储着所有知名服务和传输层端口的对应关系。这个对应关系是由 IANA 组织(互联网数字分配机构)来全权负责的,你可以到这个链接互联网数字分配机构通过 Web 方式查到。如果你直接把/etc/services 里的 ftp 对应的端口值从 21 改为了 8888,那么 tcpdump 就会去抓端口含有 8888 的网络包了。

  • ip[0] & 0xf0 != 5
    • IP 协议的第 0-4 位表示 IP 版本号,可以是 IPv4(值为 0100)或者 IPv6(0110)。IP 协议的第 5-8 位表示首部长度,单位是 4 字节,如果首部长度为默认的 20 字节(4 * 5)的话,此值应为 5,即 0101。ip[0]则是取这两个域的合体。0xf 中的 0x 表示十六进制,f0 是十六进制数,转换成 8 位的二进制数是 0000 1111。而 5 是一个十进制数,它转换成 8 位二进制数为 0000 0101。有了上面这些分析很清楚的知道,语句中!=的左侧部分就是提取 IP 包首部长度域,如果首部长度不等于 5,就满足过滤条件。言下之意也就是说,要求 IP 包的首部中含有可选字段。
  • ip[0] & 0x0f == 4
    • 经过上述的例子很清楚的知道,这样例子是想判断 IP 版本号是否为 IPv4。大家可能已经有所体会,在写过滤表达式时,你需要把协议格式完全背在脑子里,才能把表达式写对。可这对大多数人来说,可能有些困难。为了让 tcpdump 工具更人性化一些,有一些常用的偏移量,可以通过一些名称来代替。比如 icmptype 表示 ICMP 协议的类型域、icmpcode 表示 ICMP 的 code 域,tcpflags 则表示 TCP 协议的标志字段域。如果一个过滤表达式有多个过滤条件,那么就需要使用逻辑符了,其中,!或 not 都可以表示否定,&&与 and 都可以表示与,而||与 or 都可以表示或。

7. 独门秘籍

独门秘籍,非你莫属!

  • 使用-A 选项,则 tcpdump 只会显示 ASCII 形式的数据包内容,不会再以十六进制形式显示
  • 使用-XX 选项,则 tcpdump 会从以太网部分就开始显示网络包内容,而不是仅从网络层协议开始显示
  • 使用-D 选项,则 tcpdump 会列出所有可以选择的抓包对象

  • 如果想查看哪些 ICMP 包中“目标不可达、主机不可达”的包,请使用这样的过滤表达式 icmp[0:2]==0x0301
  • 要提取 TCP 协议的 SYN、ACK、FIN 标识字段,请使用这样的过滤表达式

  • 要提取 TCP 协议里的 SYN-ACK 数据包,不但可以使用上面的方法,也可以直接使用最本质的方法 tcp[13]==18
  • 如果要抓取一个区间内的端口,可以使用 portrange 语法:tcpdump -i eth0 -nn 'portrange 52-55' -c 1 -XX

8. 输出分析

分析 Tcpdump 到底输入了些什么内容!

  • 现在,我们对于开头抓取的包进行彻底的剖析,来深入理解其内容。

  • 【第 1 行】

    • 这一行,简单易懂,就是说你的命令里没有用到-v 和-vv,如果希望看到更全的输出内容,可以使用这两个选项。如果你有兴趣,可以试试,看看加上-vv 后,到底输出内容里会多些什么。
  • 【第 2 行】

    • 这一句表示我们监听的是通过 eth0 这个 NIC 设备的网络包,且它的链路层是基于以太网的,要抓的包大小限制是 65535 字节。包大小限制值可以通过-s 选项来设置,如果你要追求高性能,建议把这个值调低,这样可以有效避免在大流量情况下的丢包现象。
  • 【第 3 行】

    • 19:48:33.285838 => 分别对应着这个包被抓到的时、分、秒、微妙
    • IP => 表示这个包在网络层是 IP 包
    • 116.255.245.206.47940 => 表示这个包的源 IP 为 116.255.245.206,源端口为 47940。
    • > => 这个大于号表示数据包的传输方向
    • 8.8.8.8.53 => 表示这个包要发向的目的端 IP 是 8.8.8.8,目标端口为 53,也就是我们熟知的 DNS 服务端口
    • 22768+ A? www.baidu.com. (31) => 这是 DNS 协议的内容,即请求 www.baidu.com 的 A 纪录
  • 【第 4/5/6/7 行】

    • 接下来便是 IP 包的内容了,是除去了以太网之后剩下的内容,其中左侧部分是十六进制内容,右侧部分是相应的 ASCII 码内容。
  • IP 协议的首部分析

最外层是 IP 数据包,最开始的 1 字节(8bit)中,前 4bit 表示 IP 的版本,此处为 4,表示这是一个 IPv4 版本的 IP 包
后 4bit 表示这 IP 包的首部长度,此处的数字是 5,由于单位是 4 字节,因此可以计算得出这个 IP 包的首部长度是固定的 20 字节

在 IP 版本和首部长度之后,接下来的 1 字节(8bit)是 00
这是 IP 协议的服务类型域(TOS),由于已经很少使用,因此此处被置为 00

后面的 2 字节(16bit)是 003b,表示整个 IP 包的总长度(首部长度+数据长度),单位是字节
因此可以知道这个 IP 包的总长度是 59 字节(0x3b 需要转换为十进制)

再向下的 2 字节(16bit)是标识域
如果 IP 包的大小超过了数据链路层的 MTU 限制,就需要对 IP 包进行分拆,此时就要用这个域来表示哪些包在分拆前是同一组的
此处的标识域值为 0xc341

再继续向向下看,便是 3bit 的标志位
最高位为保留位,中间一位为 DF(don’t fragment),最低位为 MF(more fragments)
可以看到这三位是用来控制 IP 拆包后的组装所用,由于此包没有拆包,因此这三位都被置为 0

与上面的标志位配合的是紧接着的 13bit 的片偏移,但由于本包没有拆包,因此此域也无用,因此为 0

紧接着是 8bit 的 TTL(Time To Live,即生存周期),此包的值为 0x40,换算成十进制是 64
这表明这个网络包,如果经过了超过 64 个中间路由节点,则认为目的地不可达,中间路由器会将此包抛弃掉

继续的 8bit 为协议域,用于指代上一层协议类型
此处的值为 0x11,对应十进制的 17,而 17 是 UDP 协议的代号,因此可以知道这个网络包所用的传输层协议是 UDP,而非 TCP
TCP 的协议号是 6,ICMP 的协议号是 1

接下来的 2 个字节表示 IP 首部校验和,此处计算出来的结果是 3c93

再往下就是大家非常熟悉的 4 字节的 IP 源地址,即 74 ff f5 ce,转换成 IP 地址则为 116.255.245.206

再下面的 4 字节则为 IP 目的地址,即 08 08 08 08,转换成 IP 地址则为 8.8.8.8,这是著名的 Google-DNS 服务器地址
至此,网络层 IP 协议的首部 20 字节已经分析完了,再向下我们即将进入传输层 UDP 协议的包分析阶段。


  • UDP 首部解析

相对于 TCP 包来说,UDP 包的首部还是比较简单的,总共只有 8 个字节,是 UDP 首部部分。UDP 首部的前 2 个字节为源端口,此处为 bb 44,即 47940,而接下来的 2 字节为目的端口,值为 00 35,即 53(DNS 服务)。

而接下来的 2 字节则表示 UDP 包的总长度(报头+数据部分)
此处的值为 00 27,这算成十进制则为 39
表示此 UDP 包的总长度为 39 字节,减去首部的 8 字节外,还有 31 字节来存储真正要传输的数据

而 UDP 首部的最后两个字节则是校验和部分,此处的值为 0xb457


  • 数据分析

再向下的部分,则是应用层协议的内容(本例中是 DNS 协议)了
如果你有兴趣,可以继续了解下 DNS 协议、HTTP 协议、FTP 协议等众多的应用层协议
这非常有利于大家在学习协议、追查网络问题时,透过现象看本质


9. 参考资料

送人玫瑰,手有余香!

Linux 大棚 > tcpdump advanced filters

参考

https://www.escapelife.site/posts/365ce3c5.html

标签:

头像

小麦苗

学习或考证,均可联系麦老师,请加微信db_bao或QQ646634621

您可能还喜欢...

发表回复

嘿,我是小麦,需要帮助随时找我哦
  • 18509239930
  • 个人微信

  • 麦老师QQ聊天
  • 个人邮箱
  • 点击加入QQ群
  • 个人微店

  • 回到顶部
返回顶部