Understanding ngrep

抓包

一般都有 tcpdump/ngrep,tcpdump 可读性比较差,一般只有在怀疑 tcp 连接出现问题,会用 tcpdump 去查看 tcp 的连接状态。ngrep 对比之下,使用比较方便,基本能满足一般需求。

ngrep tcpdump
过滤规则 支持 host\port\net\proc 支持 host\port\net\proc
易读性 较高(http 协议等很清晰) 较低
过滤字符串 支持 不支持

ngrep

ngrep 方便的数据包匹配和显示工具,可以过滤网络数据包并搜索字符串,是grep(在文本中搜索字符串的工具)的网络版。

输出内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
interface: any
filter: ( port 8083 ) and (ip || ip6)
match: /withdra(.+)?/wechat
#
T 127.0.0.1:4108 -> 127.0.0.1:8083 [AP] #1
POST /station/withdraw/wechat HTTP/1.0.
Host: internal-bytepower-station-private-alb-1244500456.cn-northwest-1.elb.amazonaws.com.cn.
X-Real-IP: 172.31.73.171.
X-Forwarded-For: 172.31.48.224, 172.31.73.171.
X-Forwarded-Proto: http.
Content-Length: 411.
X-Forwarded-Port: 80.
X-Amzn-Trace-Id: Root=1-61b7089b-56e72bb92639c4ff7962f8c6.
User-Agent: Go-http-client/1.1.
Content-Type: application/json.
Accept-Encoding: gzip.
.
{"app_id":"APPERXW6VEMRTM5P","app_metric_name":"010.RunFast03_K","cash_num":0.3,"cuid":"e419e36a533c6545","desc":".................................","timezone":28800,"user_id":"UUCG5AOFGFABJ","wechat_app_id":"wx8efbae40ad0b8de5","wechat_merchant_id_list":["1605715141","1560154181"],"wechat_open_id":"o3HRV647ucInh5T1mVtn8gRKNwks","wechat_union_id":"oydXy0x1bft35XV-qwyH-0qnb3g4","withdraw_id":"WCHHX5Y2R7GYIA"}
#####
T 127.0.0.1:8083 -> 127.0.0.1:4108 [AP] #6
HTTP/1.0 200 OK.
Content-Length: 210.
Date: Mon, 13 Dec 2021 08:47:23 GMT.
Content-Type: application/json; charset=utf-8.
.
{"withdraw":{"cash_num":0.3,"reason":"","status":"WITHDRAW_SUCCESS","wechat_merchant_id":"1605715141","wechat_err_code":"","withdraw_id":"WCHHX5Y2R7GYIA","withdraw_time":"2021-12-13T16:47:23.647956966+08:00"}}
########
  • 第一行是网卡
  • 第二行是过滤的规则
  • 第三行#,未匹配的数据包都以“#”显示
  • 第四行监听到的 http 请求协议,请求 url,请求头和请求的参数内容。
  • 第9行未匹配的数据包都以“#”显示。
  • 第19行是 http 返回值

参数说明

  • 过滤指定网卡的数据包
    -d 要查看所有网卡,可以 -d any
  • 查看内容
    -W: 一般为了可读性使用 byline。有4种格式 normal, byline, single, none。
    -n 仅捕获指定数目的数据包进行查看
    -A 匹配到数据包后dump随后的指定数目的数据包
    -T 显示上一个匹配的数据包之间的时间间隔
  • 二进制查看
    -xX 左边会显示16进制格式,右边显示可读字符
  • 输出或读取文件
    -O 将匹配的数据保存到.dump文件
    -I 从.dump文件中读取数据进行匹配
  • 其它
    -q 静默模式,如果没有此开关,未匹配的数据包都以“#”显示
    -t 显示匹配到数据包的时间

语法

1
2
3
ngrep <-LhNXViwqpevxlDtTRM><-IO pcap_dump><-n num><-d dev><-A num>
<-s snaplen><-S limitlen><-w normal|byline|single|none><-c cols>
<-P char><-F file><match expression><bpf filter>

简化
ngrep -W byline -d any '过滤字符串,支持表达式' '过滤规则'
在实际使用中,没有过滤字符串最好也加上'',因为过滤规则可能被这个影响。所以如果发现输出都是 ##### 且不符合预期,最好先检查一下自己的命令,过滤字符串和过滤规则格式是否正确。

过滤规则

  • 基于地址过滤:host

    1
    sudo ngrep -W byline -d any '' 'host 127.0.0.1'

    数据包的 ip 可以再细分为源ip和目标ip两种

    1
    2
    3
    4
    5
    # 根据源ip进行过滤
    sudo ngrep -W byline -d any '' 'src host 127.0.0.1'

    # 根据目标ip进行过滤
    sudo ngrep -W byline -d any '' 'dst host 127.0.0.1'

    支持域名

  • 基于端口过滤:port
    使用 port 就可以指定特定端口进行过滤

    1
    sudo ngrep -W byline -d any '' 'port 8083'

    端口同样可以再细分为源端口,目标端口

    1
    2
    3
    4
    5
    # 根据源端口进行过滤
    sudo ngrep -W byline -d any '' 'src port 8083'

    # 根据目标端口进行过滤
    sudo ngrep -W byline -d any '' 'dst port 8083'

    也可以指定一个端口段

    1
    sudo ngrep -W byline -d any '' 'portrange 80-8082'
  • 其它
    能识别TCP、UDP和ICMP包,使用 tcptdpicmp
    tcp 里面 ip 和 ip6 区分,使用ipip6
    支持网段过滤,使用示例 net 172.17.0.0/24,支持源和目标网段。

  • 过滤规则组合
    支持 and、or、not。

    1
    2
    3
    and:所有的条件都需要满足,也可以表示为 &&
    or:只要有一个条件满足就可以,也可以表示为 ||
    not:取反,也可以使用 !

    也有可能需要用到括号()

场景

基础

  • 指定 port
    查看请求,监听相应端口即可,以 station 举例,端口是 8083,示例如下:
    sudo ngrep -W byline -d any '' 'port 8083'

sudo ngrep -W byline -d any port 8083 这样写有没有问题?sudo ngrep -W byline -d any src port 8083 这样写会不会有问题?

PostgreSQL 默认端口是 5432
sudo ngrep -W byline -d any '' 'port 5432'

Redis 默认端口是 6379
sudo ngrep -W byline -d any '' port 6379'

  • 指定 host
    需要过滤对应的 host 和 port,比如过滤出某个数据库的请求。可以使用域名
    sudo ngrep -W byline -d any '' 'host 172.17.20.138'
    sudo ngrep -W byline -d any '' 'host bytepower-station-db.cluster-cv0oenksk2p5.rds.cn-northwest-1.amazonaws.com.cn'

  • 正则过滤
    过滤请求的 url
    sudo ngrep -W byline -d any '/withdra(.+)?/wechat' 'port 8083'

  • 查看二进制
    sudo ngrep -xX -W byline -d any '/withdra(.+)?/wechat' 'port 8083'

  • udp
    sudo ngrep -d any '' 'udp'

进阶

  • 分析
    排查问题的时候,很多时候我们需要对一份数据反复分析查看。
    这种情况下:

    • 先收集导出到文件,这个时候过滤条件可以比较少甚至不设置。
      sudo ngrep -W byline -O /tmp/check_1.dump -d any -t
    • 退出后,针对这个文件进行搜索分析。
      sudo ngrep -W byline -I /tmp/check_1.dump '^GET' 'port 8083'
      sudo ngrep -W byline -I /tmp/check_1.dump 'app_id=APPIFP5WATVLJAZ3' 'port 8083'
      如何看到这个请求后面的一系列操作,可以使用 -A 来过滤出匹配到数据包后面的数据包
      sudo ngrep -W byline -I /tmp/check_1.dump -A 10 'app_id=APPIFP5WATVLJAZ3' 'port 8083'
      通过做这种途径可以看到后续的 sql 和 redis 相关操作。还是难以分析?可以循环上面的操作,过滤导出文件在分析
      sudo ngrep -W byline -I /tmp/check_1.dump -O /tmp/check_2.dump -A 10 'user_id=UUCGNNN7KAXGQ'
      这是一种分析的思路。当然你要是正则够厉害,可以一个复杂的正则搞定。
  • 实际使用
    在测试部署到机器上后,通过 ngrep 来查看请求发起了多少次数据库查询、redis 操作。这在和产品组联调的时候很有用。
    sudo ngrep -W byline '' 'not port 22'
    sudo ngrep -d any '' 'portrange 5000-8082'
    线上的时候,因为每秒数百上千个请求,这个时候就结合

组合使用

可以对结果使用 awk 或者 grep 过滤
sudo ngrep -W byline -d any '' 'port 8083' |grep 10 '/withdraw'

tcpdump

tcpdump是一个对网络上的数据包进行截获的包分析工具。它允许用户截获和显示发送或收到通过网络连接到该计算机的TCP/IP和其他数据包。

输出内容

1
08:31:54.674766 IP ip-172-30-1-113.cn-northwest-1.compute.internal.http > ip-172-31-48-163.cn-northwest-1.compute.internal.64372: Flags [P.], seq 619:14807, ack 1313, win 285, options [nop,nop,TS val 3247021864 ecr 577459112], length 14188: HTTP: HTTP/1.1 200 OK
  • 第一列:时分秒毫秒 21:26:49.013621
  • 第二列:网络协议 IP
  • 第三列:发送方的地址+端口号,其中172.20.20.1是 ip,而15605 是端口号
  • 第四列:箭头 >, 表示数据流向
  • 第五列:接收方的ip地址+端口号,其中 172.20.20.2 是 ip,而5920 是端口号
  • 第六列:冒号
  • 第七列:数据包内容,包括Flags 标识符,seq 号,ack 号,win 窗口,数据长度 length,其中 [P.] 表示 PUSH 标志位为 1,更多标识符见下面

参数说明

  • 控制详细内容的输出
    一般 -v 就足够使用了
    -v 产生详细的输出. 比如包的TTL,id标识,数据包长度,以及IP包的一些选项
    -vv 产生比-v更详细的输出。比如NFS回应包中的附加域
    -vvv 产生比-vv更详细的输出。比如 telent 时所使用的SB
  • 过滤指定网卡的数据包
    -i 要查看所有网卡,可以 -i any
  • 过滤特定流向的数据包
    -Q: 选择是入方向还是出方向的数据,可选项有:in, out, inout
  • 输出或读取文件
    -w 后接一个以 .pcap 后缀命令的文件名
    -r 从 .pcap 文件读取
  • 其它
    -n 不把ip转化成域名,直接显示 ip
    -nn 不把协议和端口号转化成名字
    -s number,number 是 0 的话,表示截取报文全部内容
    -l 基于行的输出,便于你保存查看,或者交给其它工具分析

场景

  • 查看请求
    我们一般使用 nginx 中转,因为 nginx 转到 127.0.0.1,需要指定 interface
    sudo tcpdump port 8083 -i lo

  • 查看完整的请求
    默认的话 tcpdump 只显示部分数据包,默认68字节。
    sudo tcpdump -s 0 -v -n -l

  • 图形化查看
    通过ssh传到本地 Wireshark ,查看内容
    ssh bytepower-appserver-tasklet 'sudo tcpdump -s 0 -c 1000 -nn -w - not port 22' | /Applications/Wireshark.app/Contents/MacOS/Wireshark -k -i -

附录

ngrep 使用官方文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
ngrep: invalid option -- '-'
usage: ngrep <-hNXViwqpevxlDtTRM> <-IO pcap_dump> <-n num> <-d dev> <-A num>
<-s snaplen> <-S limitlen> <-W normal|byline|single|none> <-c cols>
<-P char> <-F file> <-K count>
<match expression> <bpf filter>
-h is help/usage
-V is version information
-q is be quiet (don't print packet reception hash marks)
-e is show empty packets
-i is ignore case
-v is invert match
-R is don't do privilege revocation logic
-x is print in alternate hexdump format
-X is interpret match expression as hexadecimal
-w is word-regex (expression must match as a word)
-p is don't go into promiscuous mode
-l is make stdout line buffered
-D is replay pcap_dumps with their recorded time intervals
-t is print timestamp every time a packet is matched
-T is print delta timestamp every time a packet is matched
specify twice for delta from first match
-M is don't do multi-line match (do single-line match instead)
-I is read packet stream from pcap format file pcap_dump
-O is dump matched packets in pcap format to pcap_dump
-n is look at only num packets
-A is dump num packets after a match
-s is set the bpf caplen
-S is set the limitlen on matched packets
-W is set the dump format (normal, byline, single, none)
-c is force the column width to the specified size
-P is set the non-printable display char to what is specified
-F is read the bpf filter from the specified file
-N is show sub protocol number
-d is use specified device instead of the pcap default
-K is send N packets to kill observed connections