使用tcpdump过滤6379/5432端口含数据TCP数据包的技术咨询
关于tcpdump过滤带数据的6379/5432端口数据包的分析与优化
嘿,我来帮你捋捋这条tcpdump命令的细节和你遇到的问题~
你写的这条命令目标很明确:抓eth0网卡上6379(Redis)和5432(PostgreSQL)端口里带实际数据的TCP数据包,先把你用的完整命令贴出来方便参考:
sudo tcpdump -i eth0 -n -tt 'tcp port 6379 or port 5432 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
核心过滤逻辑拆解
那个看起来复杂的长表达式,其实是手动计算TCP数据包的有效载荷(payload)长度,判断它不为0就意味着包带了数据:
ip[2:2]:获取整个IP包的总字节数((ip[0]&0xf)<<2):计算IP头部的长度(IP头的IHL字段是前4位,乘以4才是实际字节数)- 两者相减得到TCP段的总长度(IP总长度减去IP头长度)
((tcp[12]&0xf0)>>2):计算TCP头部的长度(TCP头的Data Offset字段是第13字节的高4位,同样乘以4得字节数)- 最后用TCP段总长度减去TCP头长度,结果就是payload的长度,不等于0就说明包有实际数据。
关于你遇到的截断输出
你提到的输出1521257077.232079 IP 10.240.0.40.37978 > 10.240.明显是被截断了,大概率是这两个原因:
- 终端窗口宽度不够,导致长输出被截断换行或者显示不全,你可以拉大终端窗口后重新执行,或者加
-v/-vv参数让输出更详尽,也可以把抓包结果存到文件再分析:
之后用sudo tcpdump -i eth0 -n -tt 'tcp port 6379 or port 5432 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' -w redis_pg_capture.pcaptcpdump -r redis_pg_capture.pcap或者Wireshark打开文件,就能看到完整的数据包内容了。 - 极少数情况是抓包时没捕获到完整数据包,但这种概率很低,先优先排查终端显示问题。
命令优化建议
其实tcpdump本身有更简洁的方式过滤带payload的包,而且你要注意逻辑优先级的问题:
- 修正逻辑优先级:你的原始命令里
and的优先级比or高,所以实际逻辑是「捕获6379端口的所有TCP包,或者5432端口带数据的TCP包」,如果想让两个端口都应用“带数据”的过滤,必须加括号:sudo tcpdump -i eth0 -n -tt 'tcp (port 6379 or port 5432) and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' - 简化过滤条件:不用手动计算头长度,直接用tcpdump支持的
tcp payload(部分版本支持),或者用更直观的方式判断:
如果你的tcpdump版本不支持sudo tcpdump -i eth0 -n -tt 'tcp (port 6379 or port 5432) and tcp payload'tcp payload,也可以用这个等价的简化表达式:
这里sudo tcpdump -i eth0 -n -tt 'tcp (port 6379 or port 5432) and not tcp[12:1] = 0x50'0x50对应TCP头长度为20字节(Data Offset字段值为5,乘以4就是20),如果TCP头长度等于20且没有选项,同时IP包长度减去IP头和TCP头长度为0的话,就是空包,所以排除这种情况就能抓到带数据的包。
内容的提问来源于stack exchange,提问作者Ratatouille




