tcpdump的高级用法

tcpdump是linux平台的,基于bpf的抓包工具。
比较常见的用法是: tcpdump -i eth1 tcp port 80

前几天在工作中遇到一个问题:线上的redis库,因为HGET命令中包含特殊字符报错。
不能确定是哪个模块引入的问题。

问题描述: tcp 7700 端口接收外部的查询命令, 同时包含多个redis命令字。
当前:只有 HGET 命令字有问题,且出错的字符串多是 a 域名。

抓全部的包去找有问题的场景简直大海捞针,因此让我们见识下tcpdump的新魔法:

tcpdump -i any 'tcp port 7700 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0) 
and (tcp[25] == 0x34) 
and (tcp[28] == 0x48) and (tcp[29] == 0x47) and (tcp[30] == 0x45) and (tcp[31] == 0x54)'
-nnn -vvv -w 49.7700.pcap

====基础知识:
ip[2:2] 以2起,2个字节表示包长度
(ip[0]&0xf)<<2  第一个字节 前4bit是协议 后4bit 乘以4 是ip包头大小。

tcp[12]&0xf0>>2 高位4bit是长度
tcp[0-19]表示包头,自tcp 20个字节起是 payload.

redis的tcp命令是:
*3
$4
HGET
$99
PLAN_...
$10
abcdef.com....

(ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0 
保证tcp的包大小大于0, 把握手包这种就过滤了。

tcp[25] == 0x34 检查$4的4 , 只要4个字符的命令字。
28,29,30,31 对应的就是 H G E T

为什么是25:
因为redis命令字后跟着2个字节额 0d 0a。 

本身思路出来就可以,再具体的可以: