tcpdump解决运维生产中遇到问题

DevOpSec
• 阅读 205

来源: DevOpSec公众号 作者: DevOpSec

作为技术人员tcpdump这个工具还是有必要了解的

当你遇到网络协议问题一筹莫展的时候,这时候往往可以通过tcpdump来看网络的通讯过程中发生了什么事,帮助快速定位问题。

本文只介绍工作用遇到的问题供大家参考,旨在给你工作中遇到类似问题提供解决灵感,具体tcpdump怎么使用google吧。

下面通过三个案例进行介绍:

案例一:flumekafka日志报错

案例二:LB(负载均衡)增加请求header后,nginx日志获取不到header key client_ip

案例三:mysql QPS 特别高,但mysql并没有慢查询,想知道topK mysql语句

最后:场景的http协议抓包场景

案例一:flumekafka日志报错

flumekafka日志如下,没有其他报错。看下面报错,向kafka push数据TimeoutException

但在flume机器上telnet kafka 9092端口是通的

这是什么原因导致的呢?

看日志没有思路,tcpdump抓包看一下

13 May 2023 16:01:28,367 ERROR [SinkRunner-PollingRunner-DefaultSinkProcessor] (org.apache.flume.sink.kafka.KafkaSink.process:240)  - Failed to publish events
java.util.concurrent.ExecutionException: org.apache.kafka.common.errors.TimeoutException: Batch Expired
        at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.valueOrError(FutureRecordMetadata.java:56)
        at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.get(FutureRecordMetadata.java:43)
        at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.get(FutureRecordMetadata.java:25)
        at org.apache.flume.sink.kafka.KafkaSink.process(KafkaSink.java:229)
        at org.apache.flume.sink.DefaultSinkProcessor.process(DefaultSinkProcessor.java:67)
        at org.apache.flume.SinkRunner$PollingRunner.run(SinkRunner.java:145)
        at java.lang.Thread.run(Thread.java:748)
Caused by: org.apache.kafka.common.errors.TimeoutException: Batch Expired
13 May 2023 16:01:28,367 ERROR [SinkRunner-PollingRunner-DefaultSinkProcessor] (org.apache.flume.SinkRunner$PollingRunner.run:158)  - Unable to deliver event. Exception follows.
org.apache.flume.EventDeliveryException: Failed to publish events
        at org.apache.flume.sink.kafka.KafkaSink.process(KafkaSink.java:252)
        at org.apache.flume.sink.DefaultSinkProcessor.process(DefaultSinkProcessor.java:67)
        at org.apache.flume.SinkRunner$PollingRunner.run(SinkRunner.java:145)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.util.concurrent.ExecutionException: org.apache.kafka.common.errors.TimeoutException: Batch Expired
        at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.valueOrError(FutureRecordMetadata.java:56)
        at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.get(FutureRecordMetadata.java:43)
        at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.get(FutureRecordMetadata.java:25)
        at org.apache.flume.sink.kafka.KafkaSink.process(KafkaSink.java:229)
        ... 3 more

flume机器上抓包

tcpdump port 9092 -s 0 -A -e -vvv
16:46:31.324786 52:54:00:6f:bf:d2 (oui Unknown) > 98:f2:b3:2b:74:f0 (oui Unknown), ethertype IPv4 (0x0800), length 97: (tos 0x0, ttl 63, id 3722, offset 0,flags [DF], proto TCP (6), length 83)
    flume-001.28230 > 192-168-160-10.kafka.release.svc.cluster.local.XmlIpcRegSvc: Flags [P.], cksum 0xc1b4 (incorrect -> 0x3b21), seq 14182:14225, ack 6634, win 31200, length 43
E..S..@.?.k........
nF#...d.q#..P.y........'.........
producer-1......log_flume_topic

16:46:31.325436 98:f2:b3:2b:74:f0 (oui Unknown) > 52:54:00:6f:bf:d2 (oui Unknown), ethertype IPv4 (0x0800), length 704: (tos 0x0, ttl 64, id 39463, offset 0, flags [DF], proto TCP (6), length 690)
    192-168-160-10.kafka.release.svc.cluster.local.XmlIpcRegSvc > flume-001.28230: Flags [P.], cksum 0x4359 (correct), seq 6634:7284, ack 14225, win 50470, length 650
E....'@.@......
....#.nFq#....e.P..&CY....................kafka-002..#.......kafka-003..#.......kafka-001..#.........log_flume_topic.............................................................
...................................................     ..........................................................................................................................................................................................................................................................................................................................................................................................................................

从上面抓包信息看kafka节点192-168-160-10.kafka.release.svc.cluster.local.XmlIpcRegSvc 回包内容有kafka-002..#.......kafka-003..#.......kafka-001..#.........log_flume_topic

kafka-002、kafka-003、kafka-001kafka主机名,看到这里还是不是很直观,把数据包保存到文件通过whireshark分析一下

执行tcpdump port 9092 -s 0 -w kafka_traffic.pcap ,然后把文件用whireshark打开 tcpdump解决运维生产中遇到问题 可以看到kafka协议有Kafka Metadata v0 requestKafka Metadata v0 Response

点开Kafka Metadata v0 request协议看下详细信息 tcpdump解决运维生产中遇到问题

点开Kafka Metadata v0 Response协议看下详细信息 tcpdump解决运维生产中遇到问题

flume机器上ping kafka-002

ping kafka-002                                           
ping: cannot resolve kafka-002: Unknown host

到这里出现TimeoutException问题就清楚,flume client在写kafka之前,先从kafka拿到kafkabroker信息,kafka返回的broker 地址是主机名加端口

flume 拿到kafka-002 后通过dns解析失败,导致push evet失败

解决办法:

flume机器上配置上kafka-002hosts后,报错消失,问题解决

这里flume日志有些坑返回TimeoutException而非kafka-002 name reslove failed使定位问题增加难度

另一种解决办法:

为什么kakfa会返回kafka-002主机名而不是ip呢?

我们看一下kafka的配置文件,发现advertised.listeners=PLAINTEXT://kafka-002:9092 advertised.listeners参数的作用就是将BrokerListener信息发布到Zookeeper

所以flume从从kafka那里拿到的是主机名而不是ip,可以把kafka配置advertised.listeners改成ip重启kafka问题也能解决

案例二:LB(负载均衡)增加请求header后,nginx日志获取不到header key client_ip

先说一下场景

通过LB做七层负载均衡后remote_addr看到的是LB的ip,所以在负责均衡上把客户端的ip给增加到请求header client_ip 里。

nginx里增加日志打印$http_client_ip,并没有获取到此header 的值

这是什么原因呢?

是不是负责LB运维的小伙伴没有增加client_ip header

还是header加上了但值是空?

这就需要通过tcpdump抓包来验证一下我们的猜测。

在nginx上执行如下命令:

tcpdump -s 0 -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'|grep client_ip

结果发现:

client_ip: 1.1.1.1

由抓包信息看客户端的ip是设置到header里的,说明LB的配置没问题,那问题来到了nginx这一侧。

为什么通过$http_client_ip没有获取到header的值?

通过nginx官网找header相关配置 http://nginx.org/en/docs/http/ngx_http_core_module.html 发现

Syntax:    underscores_in_headers on | off;
Default:    
underscores_in_headers off;
Context:    http, server

到这里真相大白,nginx默认会忽略用户自定义带下划线的header避免和nginx自带的header key冲突

修改nginx配置设置underscores_in_headers no; 后问题解决

案例三:mysql QPS 特别高,但mysql并没有慢查询,想知道topK mysql语句

mysql 负载变高且qps也变的特别高,但没有慢查询,也可能是sql query time 设置的不合理导致慢查询没有暴露出来,担心长时间这样下去会影响数据库的性能,想知道是什么语句导致?

这里没有开启mysql的审计,调用方没有记录日志,也不好排查

那怎么处理呢?有没有非侵入且不需要研发干涉的情况下拿到topK sql

这时候我们的tcpdump就闪亮登场了

抓取mysql通用脚本如下:

cat /tmp/mdump.sh
tcpdump -i eth0 -s 0 -l -w - port 3306 | strings | perl -e '
while(<>) { chomp; next if /^[^ ]+[ ]*$/;
    if(/^(SELECT|UPDATE|DELETE|INSERT|SET|COMMIT|ROLLBACK|CREATE|DROP|ALTER|CALL)/i)
    {
        if (defined $q) { print "$q\n"; }
        $q=$_;
    } else {
        $_ =~ s/^[ \t]+//; $q.=" $_";
    }
}'

在qps高的mysql机器上执行

sh /tmp/mdump.sh > /tmp/m.sql
30s后ctrl + c
然后执行如下命令获取top 10 SQL

grep -i ' from ' /tmp/m.sql |grep -i ' where ' |awk -F'where|WHERE' '{print $1}'|sort|uniq -c |sort -rnk1|head -n 10

找到高频sql可以找开发沟通,是否有新业务功能上线,优化方案。

由此看类似的组件也能通过这种形式进行抓包定位问题

这里再推荐一个MySQLRedisMongoDBhttp网络抓包工具 https://github.com/40t/go-sniffer

最后:场景的http协议抓包场景

抓取HTTP GET 请求

tcpdump -i enp0s8 -s 0 -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'

解释:

tcp\[((tcp\[12:1\] & 0xf0) >> 2):4\]定义了我们所要截取的字符串的位置(http header的后面)的4 bytes。

0x47455420G E T 的ASCII码。

Character ASCII Value
G 47
E 45
T 54
Space 20

抓取HTTP POST 请求

tcpdump -i enp0s8 -s 0 -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504F5354

0x504F5354代表的是 P O S T的ASCII码.

目的端口为80的HTTP GET请求

tcpdump -i enp0s8 -s 0 -A 'tcp dst port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'

目的端口为80或443的HTTP GET 和POST请求(来自10.10.10.10)

tcpdump -i enp0s8 -s 0 -A 'tcp dst port 80 or tcp dst port 443 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420 or tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504F5354' and host 10.10.10.10

抓取HTTP GET和POST request和response

tcpdump -i enp0s8 -s 0 -A 'tcp dst port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420 or tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504F5354 or tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x48545450 or tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x3C21444F and host 10.10.10.10'

过滤目的端口为80,host为10.10.10.10,http get/post 的request和response

0x3C21444F'<' 'D' 'O' 'C'的ASCII码,作为html文件的标识符

0x48545450'H' 'T' 'T' 'P'的ASCII码,用来抓取HTTP response

监测所有的HTTP request URL(GET/POST)

tcpdump -i enp0s8 -s 0 -v -n -l | egrep -i "POST /|GET /|Host:"

抓取POST请求里的password

tcpdump -i enp0s8 -s 0 -A -n -l | egrep -i "POST /|pwd=|passwd=|password=|Host:"

抓取Request和response里的cookie

tcpdump -i enp0s8 -nn -A -s0 -l | egrep -i 'Set-Cookie|Host:|Cookie:'

过滤HTTP header

#从header里过滤出user-agent
tcpdump -vvAls0 | grep 'User-Agent:'
点赞
收藏
评论区
推荐文章
Irene181 Irene181
2年前
肝了三天,万字长文教你玩转 tcpdump,从此抓包不用愁
系列导读本文是【网络知识扫盲】专栏的第三篇。今天要给大家介绍的一个Unix下的一个网络数据采集分析工具\Tcpdump,也就是我们常说的抓包工具。与它功能类似的工具有wireshark,不同的是,wireshark有图形化界面,而tcpdump则只有命令行。由于我本人更习惯使用命令行的方式进行抓包,因此今天先跳过
Easter79 Easter79
2年前
tcpdump
TCPDUMPtcpdump是一个用于截取网络分组,并输出分组内容的工具。tcpdump凭借强大的功能和灵活的截取策略,使其成为类UNIX系统下用于网络分析和问题排查的首选工具。tcpdump可以将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not
Easter79 Easter79
2年前
tcpdump
环境:VMwareWorkstation12Pro,Windows10,CentOS6.9x86\_64,Xshell5基本介绍tcpdump是Linux自带的抓包工具,可以详细看到计算机通信中详细报文内容,如果读者熟悉另一款强大的抓包工具wireshark,tcpdump相当于是wireshark的命令行版本。dump这
Easter79 Easter79
2年前
sql注入
反引号是个比较特别的字符,下面记录下怎么利用0x00SQL注入反引号可利用在分隔符及注释作用,不过使用范围只于表名、数据库名、字段名、起别名这些场景,下面具体说下1)表名payload:select\from\users\whereuser\_id1limit0,1;!(https://o
Stella981 Stella981
2年前
Android 抓包的一些命令 及 adb使用的一些注意事项
ADB:adbdevices:失败时使用下一句查询5037端口被占用情况,netstatano|findstr5037:然后查看占用的PID,关闭占用程序。TCPDUMP抓包:1\.下载tcpdump  http://download.csdn.net/detail/happylisher/8
Wesley13 Wesley13
2年前
mysql配置调优
工作中,会遇到需要查看mysql的top20慢sql,逐个进行优化,加上必要的索引这种需求,这时就需要开启数据库的慢查询日志的功能1.查询当前慢查询日志的状态\默认为关闭状态mysqlshowvariableslike"
Wesley13 Wesley13
2年前
Linux服务器下的HTTP抓包分析
说到抓包分析,最简单的办法莫过于在客户端直接安装一个Wireshark或者Fiddler了,但是有时候由于客户端开发人员(可能是第三方)知识欠缺或者其它一些原因,无法顺利的在客户端进行抓包分析,这种情况下怎么办呢?本文中,我们将给大家介绍在服务端进行抓包分析的方法,使用tcpdump抓包,配合Wireshark对HTTP请求进行分析,非常简单有效。本
Wesley13 Wesley13
2年前
EFK实战二
前言在EFK基础架构中,我们需要在客户端部署Filebeat,通过Filebeat将日志收集并传到LogStash中。在LogStash中对日志进行解析后再将日志传输到ElasticSearch中,最后通过Kibana查看日志。上文已经搭建好了EFK的基础环境,本文我们通过真实案例打通三者之间的数据传输以及解决EFK在使用过程中的一些常见问题。
Stella981 Stella981
2年前
Linux日志安全分析技巧
0x00前言我正在整理一个项目,收集和汇总了一些应急响应案例(不断更新中)。GitHub地址:https://github.com/Bypass007/EmergencyResponseNotes本文主要介绍Linux日志分析的技巧,更多详细信息请访问Github地址,欢迎Star。0x01日志简介Lin
京东云开发者 京东云开发者
11个月前
线上问题处理案例:出乎意料的数据库连接池 | 京东云技术团队
本文是线上问题处理案例系列之一,旨在通过真实案例向读者介绍发现问题、定位问题、解决问题的方法。本文讲述了从垃圾回收耗时过长的表象,逐步定位到数据库连接池保活问题的全过程,并对其中用到的一些知识点进行了总结。