网络协议分析神器 – tcpdump 简介及抓取 HTTP Header 实战

简介

t cpdump 网络嗅探器,将强大和简单结合到一个单一的命令行界面中,能够将网络中的报文抓取,输出到屏幕或者记录到文件中。

原理

了解 tcpdump 抓包原理

张彦飞allen,公众号:开发内功修炼用户态 tcpdump 如何实现抓到内核网络包的?

基本参数

参数 说明
-i [interface] 指定网卡(network interface)
-w [flle] 第一个 n 表示将地址解析为数字格式而不是主机名,第二个 N 表示将端口解析为数字格式而不是服务名
-n 不显示 IP 地址
-X hex and ASCII
-A ASCII(实际上是以人类可读懂的包进行显示)
-XX
-v 详细信息
-r 读取文件而不是实时抓包
关键字
type host(主机名,域名,IP 地址), net, port, portrange
direction src, dst, src or dst , src and ds
protocol ether, ip,arp, tcp, udp, wlan

捕获所有网络接口

tcpdump -D

按 IP 查找流量

最常见的查询之一 host,可以看到来往于 1.1.1.1 的流量。

tcpdump host 1.1.1.1

按源 / 目的 地址过滤

如果只想查看来自 / 向某方向流量,可以使用 src dst

tcpdump src|dst 1.1.1.1

通过网络查找数据包

使用 net 选项,来要查找出 / 入某个网络或子网的数据包。

tcpdump net 1.2.3.0/24

使用十六进制输出数据包内容

hex 可以以 16 进制输出包的内容

tcpdump -c 1 -X icmp

查看特定端口的流量

使用 port 选项来查找特定的端口流量。

tcpdump port 3389 
tcpdump src port 1025

查找端口范围的流量

tcpdump portrange 21-23

过滤包的大小

如果需要查找特定大小的数据包,可以使用以下选项。你可以使用 lessgreater

tcpdump less 32 
tcpdump greater 64 
tcpdump <= 128

捕获流量输出为文件

-w 可以将数据包捕获保存到一个文件中以便将来进行分析。这些文件称为 PCAP(PEE-cap)文件,它们可以由不同的工具处理,包括 Wireshark

tcpdump port 80 -w capture_file

组合条件

tcpdump 也可以结合逻辑运算符进行组合条件查询

  • **AND:**and or &&
  • **OR:**or or ||
  • **EXCEPT:**not or !
    tcpdump -i eth0 -nn host 220.181.57.216 and 10.0.0.1  # 主机之间的通讯 
    tcpdump -i eth0 -nn host 220.181.57.216 or 10.0.0.1 
    # 获取10.0.0.1与 10.0.0.9或 10.0.0.1 与10.0.0.3之间的通讯 
    tcpdump -i eth0 -nn host 10.0.0.1 and (10.0.0.9 or 10.0.0.3)

    原始输出

并显示人类可读的内容进行输出包(不包含内容)。

tcpdump -ttnnvvS -i eth0 
tcpdump -ttnnvvS -i eth0

IP 到端口

让我们查找从某个 IP 到端口任何主机的某个端口所有流量。

tcpdump -nnvvS src 10.5.2.3 and dst port 3389

去除特定流量

可以将指定的流量排除,如这显示所有到 192.168.0.2 的 非 ICMP 的流量。

tcpdump dst 192.168.0.2 and src net and not icmp

来自非指定端口的流量,如,显示来自不是 SSH 流量的主机的所有流量。

tcpdump -vv src mars and not dst port 22

选项分组

在构建复杂查询时,必须使用单引号 '。单引号用于忽略特殊符号 () ,以便于使用其他表达式(如 host, port, net 等)进行分组。

tcpdump 'src 10.0.2.4 and (dst port 3389 or 22)'

过滤 TCP 标记位

TCP RST

The filters below find these various packets because tcp[13] looks at offset 13 in the TCP header, the number represents the location within the byte, and the !=0 means that the flag in question is set to 1, i.e. it’s on.

tcpdump 'tcp[13] & 4!=0' 
tcpdump 'tcp[tcpflags] == tcp-rst'

TCP SYN

tcpdump 'tcp[13] & 2!=0' 
tcpdump 'tcp[tcpflags] == tcp-syn'

同时忽略 SYN 和 ACK 标志的数据包

tcpdump 'tcp[13]=18'

TCP URG

tcpdump 'tcp[13] & 32!=0' 
tcpdump 'tcp[tcpflags] == tcp-urg'

TCP ACK

tcpdump 'tcp[13] & 16!=0' 
tcpdump 'tcp[tcpflags] == tcp-ack'

TCP PSH

tcpdump 'tcp[13] & 8!=0' 
tcpdump 'tcp[tcpflags] == tcp-push'

TCP FIN

tcpdump 'tcp[13] & 1!=0' 
tcpdump 'tcp[tcpflags] == tcp-fin'

查找 http 包

查找 user-agent 信息

tcpdump -vvAls0 | grep 'User-Agent:'

查找只是 GET 请求的流量

tcpdump -vvAls0 | grep 'GET'

查找 http 客户端 IP

tcpdump -vvAls0 | grep 'Host:

查询客户端 cookie

tcpdump -vvAls0 | grep 'Set-Cookie|Host:|Cookie:'

查找 DNS 流量

tcpdump -vvAs0 port 53

查找对应流量的明文密码

tcpdump port http or port ftp or port smtp or port imap or port pop3 or port telnet -lA | egrep -i -B5 'pass=|pwd=|log=|login=|user=|username=|pw=|passw=|passwd= |password=|pass:|user:|username:|password:|login:|pass |user '

关于抓包节点和抓包设备

如何抓取有用的包,以及如何找到对应的接口,有以下建议:

  • 抓包节点:通常情况下会在源端和目的端两端同时抓包,观察数据包是否从源端正常发出,目的端是否接收到数据包并给源端回包,以及源端是否正常接收到回包。如果有丢包现象,则沿网络链路上各节点抓包排查。例如,A 节点经过 c 节点到 B 节点,先在 AB 两端同时抓包,如果 B 节点未收到 A 节点的包,则在 c 节点同时抓包。
  • 抓包设备:对于 Kubernetes 集群中的 Pod,由于容器内不便于抓包,通常视情况在 Pod 数据包经过的 veth 设备,docker0 网桥,CNI 插件设备(如 cni0,flannel.1 etc..)及 Pod 所在节点的网卡设备上指定 Pod IP 进行抓包。选取的设备根据怀疑导致网络问题的原因而定,比如范围由大缩小,从源端逐渐靠近目的端,比如怀疑是 CNI 插件导致,则在 CNI 插件设备上抓包。从 pod 发出的包逐一经过 veth 设备,cni0 设备,flannel0,宿主机网卡,到达对端,抓包时可按顺序逐一抓包,定位问题节点。

    实战

容器环境中,有某个 http 服务无法正常访问,需要定位在 ingress 转发请求的时候,是否带上了指定 “X-Spa-Base-Path: xxxx” 的 header。

准备

安装 tcpdump

yum install -y tcpdump

确认抓取的 pod 和网卡信息


先获取 ingress 的的 ip 地址(建议先改成1副本)

kubectl -n kube-system get pod  -o wide |grep ingress-controllerbr

假设我们获取到的 IP 是:192.168.1.1

获取业务 Pod 所在的节点和名称

假设我们获取到的节点是 node-1,名称是 portal-service-abcd。

进入到 Pod 的命名空间

在 node-1 节点执行如下命令进 入pod,此种方法可以使用宿主机的命令,所以可以直接调用之前安装好的 tcpdump(具体可以参考:Linxu 小技巧 – 使用 nsenter 在主机上调试容器)。

NAME=portal-service-abcd; PID=`docker ps  | grep $NAME | grep pause | awk '{print $1}' | xargs docker inspect -f {{.State.Pid}}`; nsenter -n --target $PID

获取网卡名称

一般容器网络生成的网卡名称基本上是固定的,例如 eth0。

抓包

先执行以下命令开始抓包:

tcpdump -i eth0 -s 0 -A "tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420" and host 192.168.1.1

参数解析

参数 含义 详细说明
-i eth0 指定网卡接口 捕获通过接口 eth0 的流量。
-s 0 设置捕获数据包大小为无限制 捕获完整的数据包,而不是默认的 68 字节。
-A 以 ASCII 格式显示数据包内容 便于查看文本内容,适用于分析 HTTP 流量等。
"tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420" 过滤包含 "GET " 的 TCP 数据包 详细说明: 1. tcp[12:1] 读取 TCP 头部的第 12 字节(数据偏移字段)。 2. & 0xf0 提取高 4 位,表示 TCP 头长度。 3. >> 2 转为字节偏移量。 4. = 0x47455420 匹配 ASCII "GET " 的十六进制编码。
and host 192.168.1.1 限定流量的来源或目的 IP 为 192.168.1.1 捕获与指定主机通信的流量,进一步缩小分析范围。

访问服务,然后对抓到的包进行分析。

9