linux抓目标服务器的包,服务端的抓包

如果不会在Linux命令行方式下抓包,永远不会成为服务端开发的高手;

当一个技术系统变得越来越庞大复杂的时候,用抓包的方式来掌握和理解其中的网络交互,就变得尤为重要;

抓包是掌握生产系统的一种方式,这种方式不依赖于具体的业务逻辑

最近发现身边很多Java程序员和PHP程序员不会在服务器上抓包,还是蛮吃惊的,这里结合多年的经验,讲解如何在服务器上抓包

1. Problem

这里列举几个典型的技术问题,这些问题使用其他方法比较难以解决,或者解决的效率比较低,但是使用抓包的方式就可以很好的处理。

1.1 后端系统间的通讯可靠性

假设两个后端系统A和B,A发了一个请求给B,但是B没有收到。A系统的业务日志显示已经发送请求,但是B系统的业务日志却没有收到相关请求的日志,如何定位问题

假如这个问题不是必现,而是偶尔出现,又该如何解决

1.2 如何确定请求方

有的时候,一个技术系统会突然收到很多莫名的请求,这些请求占用了蛮多的服务器资源,如何确定请求来自于哪里

2. Solution

在服务器上抓包,观察网络流可以解决上述问题,常用的抓包命令如下:

root@:~# tcpdump -iany -Xn -s0 port 443

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes

17:04:11.888152 IP 36.24.158.122.27603 > 10.133.206.234.https: Flags [S], seq 608876073, win 65535, options [mss 1412,nop,wscale 6,nop,nop,TS val 286050563 ecr 0,sackOK,eol], length 0

0x0000: 4500 0040 0000 4000 3306 abb6 2418 9e7a E..@..@.3...$..z

0x0010: 0a85 ceea 6bd3 01bb 244a b629 0000 0000 ....k...$J.)....

0x0020: b002 ffff 7918 0000 0204 0584 0103 0306 ....y...........

0x0030: 0101 080a 110c c903 0000 0000 0402 0000 ................

0x0040: 0000 0000 0000 0000 0000 0000 0000 0000 ................

17:04:11.888235 IP 10.133.206.234.https > 36.24.158.122.27603: Flags [S.], seq 539909370, ack 608876074, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0

0x0000: 4500 0034 0000 4000 4006 9ec2 0a85 ceea E..4..@.@.......

0x0010: 2418 9e7a 01bb 6bd3 202e 5cfa 244a b62a $..z..k...\.$J.*

0x0020: 8012 7210 9c28 0000 0204 05b4 0101 0402 ..r..(..........

0x0030: 0103 0307 0000 0000 0000 0000 0000 0000 ................

0x0040: 0000 0000 ....

2.1 tcpdump的工作原理

当网卡收到一个网络报文后,会将该报文发给所有能处理该报文的网络协议模块来进行解析处理。tcpdump通过注册一种虚拟的底层网络协议来获得对相关报文的处理权,同时将报文完整的复制一份,根据用户的过滤条件和展示选项进行报文的处理。

2.2 tcpdump常用选项

-i: 选定网卡的interface进行抓包,可取值为any(所有接口)、eth0(eth0接口)等

-n: 不要对主机名进行解析,即直接显示IP地址

-nn: 不要对主机名和端口进行解析,即直接显示IP地址和数字形式的端口号

-X: 抓到的包展示内容的时候,既包括Hex的样式,也包括ASCII码的样式

-s: 对每一个抓到的包,限制包的大小(以字节为单位):-s0表示不限制大小,全部抓取和展示,-s 128 表示展示128个字节

2.3 tcpdump常用的过滤表达式

在一个繁忙的服务器上抓包的时候,会有大量的traffic,为了过滤出来你关心的报文,经常使用Expression进行过滤。

host: 对主机进行过滤,host后面跟服务器的IP,比如host 192.168.100.1表示只抓取源IP或者目的IP为192.168.100.1的报文

port: 对端口进行过滤,port后面跟服务器的端口号,比如port 80表示只抓取源端口号或者目的端口号为80的报文

src和dst: 这两个用户控制网络流的方向过滤,比如dst port 80表示只抓取目的端口号为80的报文,src ip 192.168.100.1表示只抓取源IP为192.168.100.1的报文

将过滤条件进行组合

可以使用and or not和小括号(需要\来转义)来组合过滤条件,如下所示:

tcpdump -iany -Xn -s0 port 443 and \( not host 192.168.100.1 or host 192.168.100.2 \)

2.4 将tcpdump抓到的包保存到文件上

可以将tcpdump抓到的包保存到文件上,格式可以是二进制的(PCAP格式,可以下载到Windows用wireshark打卡),也可以是文本格式。

举例A. 将tcpdump抓到的包以二进制形式保存到文件上,使用-w选项

tcpdump -iany -Xn -s0 port 443 -w /tmp/aaa.pcap

举例B. 将tcpdump抓到的包以文本形式保存到文件上,使用重定向

tcpdump -iany -Xn -s0 port 443 > /tmp/aaa.txt 2>&1

3. Discussion

3.1 TCP的连接建立

TCP的连接建立是通过收发双方的三次握手进行的

每个packet第一行里的Flags [S]中表示握手阶段(S为synchronize的缩写),双方握手主要是在交换收发双方当前的序列号、窗口大小和其他TCP的选项;每个packet第一行里的ack 2335101116表示接收方对发送方内容的ack,以序列号为标志。

14:26:52.511678 IP 10.133.206.234.36018 > 10.66.149.55.3306: Flags [S.], seq 2335101115, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0

0x0000: 4500 0034 e5e4 4000 4006 dbf6 0a85 ceea E..4..@.@.......

0x0010: 0a42 9537 8cb2 0cea 8b2e d0bb 0000 0000 .B.7............

0x0020: 8002 7210 790f 0000 0204 05b4 0101 0402 ..r.y...........

0x0030: 0103 0307 0000 0000 6f6d 2060 745f 7573 ........om.`t_us

0x0040: 725f 7072 r_pr

14:26:52.511960 IP 10.66.149.55.3306 > 10.133.206.234.36018: Flags [S.], seq 3990271169, ack 2335101116, win 5760, options [mss 1404,nop,nop,sackOK,nop,wscale 7], length 0

0x0000: 4500 0034 0000 4000 3f06 c2db 0a42 9537 E..4..@.?....B.7

0x0010: 0a85 ceea 0cea 8cb2 edd6 b4c1 8b2e d0bc ................

0x0020: 8012 1680 47b0 0000 0204 057c 0101 0402 ....G......|....

0x0030: 0103 0307 7369 6f6e 2073 716c 5f6d 6f64 ....sion.sql_mod

0x0040: 653d 274f e='O

14:26:52.511991 IP 10.133.206.234.36018 > 10.66.149.55.3306: Flags [.], ack 1, win 229, length 0

0x0000: 4500 0028 e5e5 4000 4006 dc01 0a85 ceea E..(..@.@.......

0x0010: 0a42 9537 8cb2 0cea 8b2e d0bc edd6 b4c2 .B.7............

0x0020: 5010 00e5 7903 0000 0100 0001 1944 0000 P...y........D..

0x0030: 0203 6465 6608 6175 ..def.au

3.2 TCP的连接释放

TCP的连接释放是通过收发双方的四次释放完成的

每个packet第一行里的Flags [F]中表示开始释放(F表示Finish)。

下述抓包是端口为20103的进程,主动关闭MySQL(端口号为3306):

20103的进程首先发送Fin包给MySQL

MySQL对此Fin包进行ack

MySQL再对20103的进程发Fin包

20103的进程对MySQL的Fin包进行确认

10:10:06.468550 IP 10.133.206.234.20103 > 10.66.149.55.3306: Flags [F.], seq 604, ack 4107, win 318, length 0

0x0000: 4500 0028 db7d 4000 4006 e669 0a85 ceea E..(.}@.@..i....

0x0010: 0a42 9537 4e87 0cea 35e7 a877 21a4 a45e .B.7N...5..w!..^

0x0020: 5011 013e 7903 0000 0204 057c 0101 0402 P..>y......|....

0x0030: 0103 0307 0000 0072 .......r

10:10:06.468853 IP 10.66.149.55.3306 > 10.133.206.234.20103: Flags [.], ack 604, win 62, length 0

0x0000: 4508 0028 b918 4000 3f06 09c7 0a42 9537 E..(..@.?....B.7

0x0010: 0a85 ceea 0cea 4e87 21a4 a45e 35e7 a877 ......N.!..^5..w

0x0020: 5010 003e 36db 0000 1000 0000 0375 7365 P..>6........use

0x0030: 2060 6175 6374 696f .`auctio

10:10:06.468856 IP 10.66.149.55.3306 > 10.133.206.234.20103: Flags [F.], seq 4107, ack 604, win 62, length 0

0x0000: 4508 0028 b919 4000 3f06 09c6 0a42 9537 E..(..@.?....B.7

0x0010: 0a85 ceea 0cea 4e87 21a4 a45e 35e7 a877 ......N.!..^5..w

0x0020: 5011 003e 36da 0000 5800 0000 0a35 2e35 P..>6...X....5.5

0x0030: 2e32 342d 4344 422d .24-CDB-

10:10:06.468886 IP 10.133.206.234.20103 > 10.66.149.55.3306: Flags [.], ack 4108, win 318, length 0

0x0000: 4500 0028 db7e 4000 4006 e668 0a85 ceea E..(.~@.@..h....

0x0010: 0a42 9537 4e87 0cea 35e7 a878 21a4 a45f .B.7N...5..x!.._

0x0020: 5010 013e 7903 0000 3100 0000 1673 6574 P..>y...1....set

0x0030: 206e 616d 6573 2027 .names.'

3.3 TCP的数据传输

一般而言,TCP建立连接后开始进行数据传输,第一行里的length字段表示传输的payload的长度。

Flags [P.]表示发送方已经将当前发送buffer里的所有数据发给接收方,接收方需要尽快将此数据上报给顶层应用,P表示Push。如果没有Flags [P.],则表示此packet发完之后,发送buffer里还有待发送的数据。

示例A:MySQL应答了1424字节的数据,但是MySQL对应的tcp里的发送buffer,还有数据。

10:10:06.458574 IP 10.66.149.55.3306 > 10.133.206.234.20103: Flags [.], seq 169:1593, ack 522, win 62, length 1424

0x0000: 4508 05b8 b914 4000 3f06 043b 0a42 9537 E.....@.?..;.B.7

0x0010: 0a85 ceea 0cea 4e87 21a4 94fc 35e7 a825 ......N.!...5..%

......

示例B:MySQL应答了618字节的数据,MySQL对应的tcp里的发送buffer里已经没有数据,接收方需要尽快将此数据上浮给高层应用。

10:10:06.458574 IP 10.66.149.55.3306 > 10.133.206.234.20103: Flags [P.], seq 1593:2211, ack 522, win 62, length 618

0x0000: 4508 0292 b915 4000 3f06 0760 0a42 9537 E.....@.?..`.B.7

0x0010: 0a85 ceea 0cea 4e87 21a4 9a8c 35e7 a825 ......N.!...5..%

0x0020: 5018 003e 4bc7 0000 725f 6e61 6d65 0e64 P..>K...r_name.d

0x0030: 6561 6c5f 6164 6472 5f6e 616d 650c e000 eal_addr_name...

3.4 TCP的包头格式

58eb20a1d535

1530845376699.jpg

常见标记:

S ( SYN synchronize ):Synchronize sequence numbers to initiate a connection

A ( ACK acknowledgement ): Acknowledge sender packet with sequence number

F ( FIN finish ):The sender of the segment is finished sending data to its peer

R ( RST reset ): Reset the connection (connection abort, usually because of an error)

P ( PSH push ): The receiver should pass this data to the application as soon as possible

备注:R标记的包,在网络排故的时候很有用,如果tcpdump抓出来的包有大量的reset标记,大概率意味着连接请求被防火墙或者其他安全措施挡住啦。

3.5 二进制协议

TCP/IP协议族中的大部分协议,其Header都组织为二进制格式,即每个bit或者bit串需要当成数值直接定义;另外很多Application也将自己的协议(例如PC QQ)组织为二进制的格式,二进制协议不易读,但是占用空间小,因而传输效率高。

下图为一个应用程序发起连接MySQL的请求,报文里0x0012字节的值为0x4e87 = 20103,即为发送方的端口号;报文里0x0013字节的值为0x0cea = 3306,即为服务方的端口号。

58eb20a1d535

WechatIMG642.jpeg

对于二进制协议,经常接合包里某个偏移位置上的内容进行抓包,比如下边的命令可以抓取所有和MySQL交互的报文:

root@:~# tcpdump -iany -Xn -nn -s0 ip[0x0014:2] = 0x0cea or ip[0x0016:2] = 0x0cea

3.6 字符串协议

包括MySQL、RabbitMQ在内,很多Application也会将自己的协议组织为字符串的格式,字符串格式的协议比较human-readable,可以对抓到的报文做很多二次操作。

对SQL(select * from t_usr_profile where mobile_phone = '13155668877')的抓包结果如下:

11:34:38.933455 IP 10.133.206.234.33166 > 10.66.149.55.3306: Flags [P.], seq 2397:2488, ack 148577, win 1475, length 91

0x0000: 4500 0083 bdf5 4000 4006 0397 0a85 ceea E.....@.@.......

0x0010: 0a42 9537 818e 0cea daa3 0567 8b16 d9f5 .B.7.......g....

0x0020: 5018 05c3 795e 0000 5400 0000 0000 0050 P...y^..T......P

0x0030: 0000 0003 5345 4c45 4354 202a 2046 524f ....SELECT.*.FRO

0x0040: 4d20 6074 5f75 7372 5f70 726f 6669 6c65 M.`t_usr_profile

0x0050: 6020 5748 4552 4520 606d 6f62 696c 655f `.WHERE.`mobile_

0x0060: 7068 6f6e 6560 203d 2027 3133 3135 3536 phone`.=.'131556

0x0070: 3638 3837 3727 204c 494d 4954 2030 2c31 68877'.LIMIT.0,1

0x0080: 3030 3041 5445 2c45 5252 4f52 5f46 4f52 000ATE,ERROR_FOR

0x0090: 5f44 49 _DI

我们可以把这类抓包保存到文本文件上,结合Linux的搜索命令,快速定位出操作手机号131556的请求(主要是搜索抓包结果最右侧的文本内容,因此注意折行)

3.7 其他方式的抓包

HTTPS的抓包:HTTPS因为加密的缘由,已经无法查看抓到的包的内容啦,如果大伙有高招(服务端),请告诉我。

另外,tcpdump的兄弟工具,wireshark以插件的形式对外提供了很多parse包的定制化能力,结合Lua语言可以构建出强大的二次分析能力。

4. Answer

4.1 请求的不可达(必现)

假设两个后端系统A和B,A发了一个请求给B,但是B没有收到。A系统的业务日志显示已经发送请求,但是B系统的业务日志却没有收到相关请求的日志,如何定位问题

在B的服务器上抓包,过滤主机A的IP,观察相关的报文是否达到服务器B上

tcpdump -iany -Xn -s0 host 192.168.100.1

4.2 请求的不可达(不是必现)

假如4.1的问题不是必现,而是偶尔出现,又该如何解决

在后台抓一段时间的包,之后再分析抓包的结果(特别注意:如果抓包量比较大的话,一定要避免把磁盘打满,此时需要增加更多的过滤表达式)

//将抓到的包输出到/tmp/1里,并且在后台运行

root@:~# nohup tcpdump -iany -Xn -nn -s0 host 10.66.149.55 > /tmp/1 2>&1 &

//可以看到存储包的文件大小在不断的涨

root@:~# ls -lh /tmp/1

-rw-r--r-- 1 root root 2.4M 7月 6 17:05 /tmp/1

//查看后台运行的job

root@:~# jobs

[2]+ 运行中 nohup tcpdump -iany -Xn -nn -s0 host 10.66.149.55 > /tmp/1 2>&1 &

//将后台运行的job切换到前台

root@:~# fg 2

nohup tcpdump -iany -Xn -nn -s0 host 10.66.149.55 > /tmp/1 2>&1

//结束抓包 Ctrl + C

//用其他命令来分析抓包结果,进而判断究竟是包没有达到B,还是A没有发出,还是被防火墙拦住啦

root@:~# ls -lh /tmp/1

-rw-r--r-- 1 root root 11M 7月 6 17:08 /tmp/1

4.3 确定请求方

有的时候,一个技术系统会突然收到很多莫名的请求,这些请求占用了蛮多的服务器资源,如何确定请求来自于哪里。

假设这个请求有固定的特征,比如说有固定的订单号或其他标识串,这个特征可以在抓包结果的最右侧捕获到。

解决这类问题的总思路是分析请求方服务器IP的分布,根据IP分布确定原因,一般而言原因分为几类:

服务方系统自身的bug,导致了ping-pang(A系统发请求给B,B请求了C,C又请求了A,也就是说同一个请求在系统间不停的路由转发而不总结),ping-pang是最为严重的bug,很容易把系统压瘫痪

系统配置有误,导致请求方不断在重试该请求

请求方底层依赖的框架或组件有bug(重发策略或路由分发策略等),导致不断重发一些过期的请求

下面以MySQL不断收到如下SQL的查询为例,列举一些思路和使用到的命令,这里的核心是熟练掌握Linux的常用命令。

select * from `t_usr_profile` where `mobile_phone` = '13155668877'

在服务方的机器上根据服务端口抓一段时间包,假设服务端是MySQL,则使用dst port 3306来过滤抓到的包,将抓到的包重定向到临时文件上(aaa),形如:

nohup tcpdump -iany -Xn -s0 dst port 3306 > /tmp/aaa 2>&1 &

; /tmp/aaa内容如下:

11:34:38.933455 IP 10.133.206.234.33166 > 10.66.149.55.3306: Flags [P.], seq 2397:2488, ack 148577, win 1475, length 91

0x0000: 4500 0083 bdf5 4000 4006 0397 0a85 ceea E.....@.@.......

0x0010: 0a42 9537 818e 0cea daa3 0567 8b16 d9f5 .B.7.......g....

0x0020: 5018 05c3 795e 0000 5400 0000 0000 0050 P...y^..T......P

0x0030: 0000 0003 5345 4c45 4354 202a 2046 524f ....SELECT.*.FRO

0x0040: 4d20 6074 5f75 7372 5f70 726f 6669 6c65 M.`t_usr_profile

0x0050: 6020 5748 4552 4520 606d 6f62 696c 655f `.WHERE.`mobile_

0x0060: 7068 6f6e 6560 203d 2027 3133 3135 3536 phone`.=.'131556

0x0070: 3638 3837 3727 204c 494d 4954 2030 2c31 68877'.LIMIT.0,1

0x0080: 3030 3041 5445 2c45 5252 4f52 5f46 4f52 000ATE,ERROR_FOR

0x0090: 5f44 49 _DI

搜索标识串(标识串为131556),并将所抓包的摘要行一起展示。注意grep命令的-B选项

root@:/tmp# grep "131556" aaa -B7

aaa-10:44:03.460160 IP 10.133.206.234.62790 > 10.66.149.55.mysql: Flags [P.], seq 514:580, ack 329, win 237, length 66

aaa- 0x0000: 4500 006a 3705 4000 4006 8aa0 0a85 ceea E..j7.@.@.......

aaa- 0x0010: 0a42 9537 f546 0cea f4ed dac4 03dc 4e32 .B.7.F........N2

aaa- 0x0020: 5018 00ed 7945 0000 3e00 0000 1703 0000 P...yE..>.......

aaa- 0x0030: 0000 0100 0000 0001 0800 0800 0800 0800 ................

aaa- 0x0040: 0800 0200 0000 0000 0000 f328 405b 0000 ...........(@[..

aaa- 0x0050: 0000 0092 3f5b 0000 0000 f328 405b 0000 ....?[.....(@[..

aaa: 0x0060: 0000 0000 0000 0000 0000 3133 3135 3536 ..........131556

--

将抓到的包的首行grep出来:grep " > "

root@:/tmp# grep "131556" aaa -B7 | grep " >"

10:43:17.476791 IP 10.133.206.234.62672 > 10.66.149.55.mysql: Flags [P.], seq 2208:2286, ack 10677, win 1030, length 78

10:43:17.642296 IP 10.133.206.234.62672 > 10.66.149.55.mysql: Flags [P.], seq 2286:2364, ack 11057, win 1052, length 78

10:43:17.808716 IP 10.133.206.234.62672 > 10.66.149.55.mysql: Flags [P.], seq 2364:2442, ack 11437, win 1074, length 78

10:43:17.935525 IP 10.133.206.234.62672 > 10.66.149.55.mysql: Flags [P.], seq 2442:2520, ack 11817, win 1096, length 78

10:43:18.077713 IP 10.133.206.234.62672 > 10.66.149.55.mysql: Flags [P.], seq 2520:2598, ack 12197, win 1119, length 78

10:43:18.264376 IP 10.133.206.234.62672 > 10.66.149.55.mysql: Flags [P.], seq 2598:2676, ack 12577, win 1141, length 78

10:43:18.396421 IP 10.133.206.234.62672 > 10.66.149.55.mysql: Flags [P.], seq 2676:2754, ack 12957, win 1163, length 78

10:43:18.555735 IP 10.133.206.234.62672 > 10.66.149.55.mysql: Flags [P.], seq 2754:2832, ack 13337, win 1185, length 78

将请求方IP列出来: awk '{print $3}'

root@:/tmp# grep "131556" aaa -B7 | grep " >" | awk '{print $3}'

10.133.206.234.62672

10.133.206.234.62672

10.133.206.234.62672

10.133.206.234.62672

10.133.206.234.62672

10.133.206.234.62672

10.133.206.234.62672

10.133.206.234.62672

10.133.206.234.62672

去掉端口号:使用cut命令,-d .标识以.进行分割,-f 1,2,3,4表示显示1 2 3 4四列

root@:/tmp# grep "131556" aaa -B7 | grep " >" | awk '{print $3}' | cut -d . -f 1,2,3,4

10.133.206.234

10.133.206.234

10.133.206.234

10.133.206.234

10.133.206.234

10.133.206.234

10.133.206.234

10.133.206.234

10.133.206.234

10.133.206.234

将请求方IP的排序: sort

root@:/tmp# grep "131556" aaa -B7 | grep " >" | awk '{print $3}' | cut -d . -f 1,2,3,4 | sort

10.133.206.234

10.133.206.234

10.133.206.234

10.133.206.234

统计请求方IP的出现次数: uniq -c

root@:/tmp# grep "131556" aaa -B7 | grep " >" | awk '{print $3}' | cut -d . -f 1,2,3,4 | sort | uniq -c

61 10.133.206.234

说明10.133.206.234请求了61次

依据出现次数排序: sort -n

root@:/tmp# grep "131556" aaa -B7 | grep " >" | awk '{print $3}' | cut -d . -f 1,2,3,4 | sort | uniq -c | sort -n

61 10.133.206.234

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值