介绍

tcpdump是一款强大的网络抓包工具,运行在 linux 平台上。熟悉tcpdump的使用能够帮助分析、调试网络问题, 本文将对网络数据包格式和tcpdump工具的使用进行介绍。

数据包格式

TCP

TCP是一种可靠的、面向连接的字节流服务。源主机在传送数据前需要先和目标主机建立连接, 然后在此连接上,被编号的数据段按序收发。 同时,要求对每个数据段进行确认,从而保证了可靠性。TCP头部结构如下:

TCP段首部的定长部分为20个字节:

  • 16 位源端口与目标端口号: 用于标识发送端应用程序和接收端应用程序
  • 32 位序号: 用来标识从TC 发送端向TC 接收端发送的数据字节流,表示在这个报文段中的的第一个数据字节
  • 32 位确认序号: 用于表示期望收到的下一个序号,ACK=1 时有效。
  • 4 位置首部长度: 计量单位为32bit
  • 6 位保留字段
  • 6 位控制字段:
    • URG: 紧急标志,和紧急指针配合使用,当其为1时表示,此报文要尽快传送
    • ACK: 确认标志,和确认号字段配合使用,当ACK位置1时,确认号字段有效
    • PSH: 推送标志,置1时,发送方将立即发送缓冲区中的数据
    • RST: 复位标志,置1时,表明有严重差错,必须释放连接重新建立
    • SYN: 同步标志,置1时,表示请求建立连接
    • FIN: 终止标志,置1时,表明数据已经发送完,请求释放连接
  • 16 位窗口字段: 与TCP 的滑动窗口流量控制有关
  • 16 位校验和: 覆盖了整个的TCP 报文段,包括首部和数据
  • 16 位紧急指针: 和序号字段中的值相加表示紧急数据最后一个字节的序号
  • 选项字段: 最常见的可选字段是MSS(Maximum Segment Size)最长报文大小, 指明本端所能接收的最大长度的报文段

UDP

UDP是一种不可靠的、无连接的数据报服务。源主机在传送数据前不需要和目标主机建立连接。数据被冠以源、目标端口号等UDP报头字段后直接发往目的主机, 每个数据段的可靠性依靠上层协议来保证。在传送数据较小的情况下,UDP比TCP更加高效。UDP头部结构如下:

说明:

  • 源/目标端口号字段:占16位,作用与TCP数据段中的端口号字段相同,用来标识源端和目标端的应用进程
  • 长度字段:占16位,标明UDP头部和UDP数据的总长度字节
  • 校验和字段:占16位,用来对UDP头部和UDP数据进行校验

IP

IP协议处于TCP/IP四层模型的第二层(网络层), 与ICMP/ARP/RARP处于同一层(但其数据是封装在IP数据包中的),IP头部结构结构如下:

说明:

  • 4位版本号: 指协议版本号,值为4代表 IPv4,下一代IP 协议的版本号为6
  • 4位首部长度: 指的是包括选项字段在内的 IP 首部长度,由于是 4bit,所以 IP 首部最长只能是 60 字节(15 * 4)。
  • 8位服务类型: 包括一个3 位的优先权字段(COS,Class of Service),4 位TOS 字段和1 位未用位。4 位TOS 分别代表:
    • 最小时延(D)
    • 最大吞吐量(T)
    • 最高可靠性(R)
    • 最小费用(C)
  • 16位IP数据包长度: 包括首部和数据部分, 能表示的最大长度为65535,当IP数据包小于46字节时在以太网帧中数据将会被填充到46字节
  • 16位标识字段: 是数据包的唯一标识,通常主机每发送一个数据包就会+1 ,在分片时会被复制到每一个分片中
  • 3位标志字段和13位(片)偏移字段: 用于数据包分片和重组, 13 位(片)偏移字段,指示了这个分片在所属数据包中的位置, 3 位标志字段:
    • 0bit 保留
    • 1bit 为 DF: 0表示可以分片,1表示不能分片
    • 2bit 为 MF: 0表示最后一个分片,1表示还有分片。
  • 8位生存时间(TTL): 设置了数据包可以经过的最多路由器数量
  • 8位协议字段: 确定在数据包内传送的上层协议,1表示为ICMP,2表示为IGMP,6表示为TCP, 17表示为UDP
  • 16位首部校验和: 根据IP首部计算的检验和码,它不对首部后面的数据进行计算
  • 32位源/目标IP地址: 标识数据包的源端设备和目的端设备
  • IP选项字段: 以32bit作为计量单位,不满32bit需要填充0, 最大值为40字节

以太网帧

在网络上传输的数据格式是以太网帧,其格式如下:

数据封装

应用程序使用TCP/IP协议传输应用数据时候,数据要被送入协议栈经过逐层封装,最终作为比特流在媒体上传送出去, 其过程如下所示:

  • 以太网帧中的数据长度规定最小46 字节,最大1500 字节,ARP 和RARP 数据包的长度不够46 字节,要在后面补填充位
  • 最大值1500 称为以太网的最大传输单元(MTU), 当IP数据包长度大于 MTU 时会被拆成多个帧传输,称为”IP分片”

tcpdump使用

常用选项

序号 选项 说明
1 -i 指定监听的网络接口
2 -n 不解析域名,直接显示ip
3 -nn 不解析协议和端口号到名称,直接使用数字
4 -c number 截取 number 个报文,然后结束
5 -w filename 写入文件
6 -r filename 读取文件
7 -t 不显示时间戳
8 -s 设置捕捉每个数据包的长度
9 -A 使用ascii显示报文的内容
10 -X 同时用 hex 和 ascii 显 示报文的内容
11 -S 显示绝对的序列号,而不是相对编号
12 -e 打印出数据链路层的头部信息,包括源mac和目的mac
13 -l 使标准输出变为缓冲行形式
14 -v 显示详细信息
15 -D 显示可监听的网络接口

过滤器

网络数据包异常的多,绝大多时候,只需要获取所关心的数据包,可使用过滤器获取指定的数据包, 过滤器分为多种:

  • 类型: host, net, port, portrange
  • 方向:src, dst
  • 协议:tcp, udp, icmp, ssh
  • 表达式: and 或者 &&, or 或者 ||, not 或者 !
  • 数据包大小:greater, less

理解输出信息

[renyl@localhost ~]$ sudo tcpdump -nnnSv
tcpdump: listening on wlp3s0, link-type EN10MB (Ethernet), capture size 262144 bytes
10:13:07.137518 IP (tos 0x0, ttl 63, id 37929, offset 0, flags [DF], proto TCP (6), length 89)
    192.168.20.30.8065 > 192.168.31.60.42426: Flags [P.], cksum 0x601c (correct), seq 216738098:216738135, ack 2219416544, win 403, options [nop,nop,TS val 408252304 ecr 1132601724], length 37
10:13:07.177754 IP (tos 0x0, ttl 64, id 14462, offset 0, flags [DF], proto TCP (6), length 52)
    192.168.31.60.42426 > 192.168.20.30.8065: Flags [.], cksum 0x8e52 (correct), ack 216738135, win 647, options [nop,nop,TS val 1132612137 ecr 408252304], length 0
10:13:07.819779 IP (tos 0x0, ttl 64, id 14463, offset 0, flags [DF], proto TCP (6), length 95)

说明:

  • 在时间点10:13:07.137518发送IP数据包
  • 源IP地址192.168.20.30,端口号8065,向目标IP地址192.168.31.60,端口号42426发送数据包
  • Flag的含义:
    • [S]: SYN(开始连接)
    • [S.]: SYN-ACK
    • [.]: No Flag Set
    • [P]: PSH(推送数据)
    • [F]: FIN (结束连接)
    • [R]: RST(重置连接)

实例

注: 需要具有root权限才可以运行tcpdump命令

  • 监视所有网络接口上流过的数据包
tcpdump -i any

注:默认只会选择机器上的一块网卡进行监听

  • 监视指定网络接口的数据包
tcpdump -i eth1
  • 显示完整的时间戳
tcpdump -ttttnnv
  • 截获主机192.168.60.10和主机192.168.60.11或192.168.60.12的通信
tcpdump host 192.168.60.10 and \(192.168.60.11 or 192.168.60.12\)
  • 打印allen与任何其他主机之间通信的IP数据包, 但不包括与lucky之间的数据包
tcpdump ip host allen and not lucky
  • 抓取包含192.168.60.10的数据包
# tcpdump -i eth0 -vnn host 192.168.60.10
  • 抓取包含192.168.60.0/24网段的数据包
# tcpdump -i eth0 -vnn net 192.168.60.0/24
  • 抓取包含端口22的数据包
# tcpdump -i eth0 -vnn port 22
  • 抓取包含端口22-125的数据包
# tcpdump -i eth0 -vnn portrange 22-125
  • 抓取udp协议的数据包
# tcpdump -i eth0 -vnn  udp
  • 抓取icmp协议的数据包
# tcpdump -i eth0 -vnn icmp
  • 抓取ssh协议的数据包
# tcpdump ssh
  • 抓取arp协议的数据包
# tcpdump -i eth0 -vnn arp
  • 抓取ip协议的数据包
# tcpdump -i eth0 -vnn ip
  • 抓取源ip是192.168.60.12数据包。
# tcpdump -i eth0 -vnn src host 192.168.60.12
  • 抓取目的ip是192.168.60.12数据包
# tcpdump -i eth0 -vnn dst host 192.168.60.12
  • 抓取源ip是192.168.60.13且目的ip是22的数据包
# tcpdump -i eth0 -vnn src host 192.168.60.13 and dst port 22
  • 抓取源ip是192.168.60.12且端口不是22的数据包
# tcpdump -i eth0 -vnn src host 192.168.60.12 and not port 22
  • 抓取源ip是192.168.60.11且目的端口是22,或源ip是192.168.60.12且目的端口是80的数据包
# tcpdump -i eth0 -vnn 'src host 192.168.60.11 and dst port 22 ' or 'src host 192.168.60.12 and dst port 80'
  • 把抓取的数据包记录存到/tmp/tcpdump文件中,当抓取100个数据包后就退出程序
# tcpdump –i eth0 -vnn -w /tmp/tcpdump -c 100
  • 从/tmp/tcpdump记录中读取tcp协议的数据包
# tcpdump –i eth0 -vnn -r /tmp/tcpdump tcp
  • 从/tmp/tcpdump记录中读取包含192.168.60.12的数据包
# tcpdump –i eth0 -vnn -r  /tmp/tcpdump host 192.168.60.12
  • 获取数据包大小大于128字节的
# tcpdump -nnvS greater 128
  • 获取数据包大小小于128字节的
# tcpdump -nnvS less 128
  • 获取所有URGENT(URG)数据包
# tcpdump 'tcp[13] & 32!=0'
  • 获取所有ACKNOWLEDGE(ACK)数据包
# tcpdump 'tcp[13] & 16!=0'
  • 获取HTTP User Agent来自HTTP请求包
tcpdump -nn -A -s1500 -l | grep "User-Agent:"
  • 获取密码来自HTTP POST数据
tcpdump -s 0 -A -n -l | egrep -i "POST /|pwd=|passwd=|password=|Host:"

参考