Fuente: Cuenta oficial de DevOpSec
Autor: DevOpSec
Como técnico, tcpdump
esta herramienta sigue siendo necesaria para entender
Cuando se encuentra con problemas de protocolo de red y está perdido, a menudo puede ver tcpdump
lo que sucedió en el proceso de comunicación de la red para ayudar a localizar rápidamente el problema.
Este artículo solo presenta los problemas encontrados en el trabajo para su referencia. Su objetivo es proporcionar inspiración para resolver problemas similares en su trabajo. Cómo usar tcpdump específicamente google
.
Se introducen los tres casos siguientes:
Caso 1: flume
Escribir kafka
un registro y reportar un error
Caso 2: LB
(balanceo de carga) header
Después de aumentar la solicitud, nginx
no se puede obtener el registroheader
key
client_ip
Caso 3: consulta mysql
QPS
muy alta, pero mysql
no lenta, quiero saber topK
mysql
la declaración
Finalmente: la escena de la escena de captura del protocolo http
Caso 1: flume
Escribir kafka
un registro y reportar un error
flume
El registro está escrito kafka
de la siguiente manera y no hay otros errores. Mira el error de abajo, a kafka
push
los datosTimeoutException
Pero el puerto 9092 flume
de la máquina telnet
kafka
está conectado
¿Cuál es la razón para esto?
No tengo ninguna idea al mirar los registros, tcpdump
así que echa un vistazo a los paquetes.
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
Capturar paquetes en flume
la máquina
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.............................................................
................................................... ..........................................................................................................................................................................................................................................................................................................................................................................................................................
A partir de la información de captura de paquetes anterior, 192-168-160-10.kafka.release.svc.cluster.local.XmlIpcRegSvc
el contenido del paquete de retorno del nodo kafka eskafka-002..#.......kafka-003..#.......kafka-001..#.........log_flume_topic
kafka-002、kafka-003、kafka-001
Es kafka
el nombre del host. No es muy intuitivo verlo aquí. Guarde el paquete de datos en un archivo y whireshark
analícelo.
Ejecute , y luego abra tcpdump port 9092 -s 0 -w kafka_traffic.pcap
el archivo con [Falló la transferencia de imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leech, se recomienda guardar la imagen y cargarla directamente. Puede ver que el acuerdo tiene ywhireshark
kafka
Kafka Metadata v0 request
Kafka Metadata v0 Response
Haga clic en Kafka Metadata v0 request
el acuerdo para ver la información detallada
[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente
Haga clic en Kafka Metadata v0 Response
el acuerdo para ver la información detallada
[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente
en flume
la maquinaping kafka-002
ping kafka-002
ping: cannot resolve kafka-002: Unknown host
TimeoutException
Está claro que hay un problema aquí , flume client
antes de escribir , la dirección devuelta es el nombre de host más el puerto kafka
de la información kafka
obtenida kafka
.broker
kafka
broker
flume
kafka-002
Después de obtener , dns
el análisis falla, lo que resulta en push evet
una falla
Solución:
Después flume
de configurar en la máquina , el error desaparece y el problema se solucionakafka-002
hosts
flume
Hay algunas trampas en el registro aquí TimeoutException
, en lugar de kafka-002 name reslove failed
hacer que el problema de posicionamiento sea más difícil
Otra solución:
¿Por qué kakfa devuelve kafka-002
el nombre de host en lugar de la ip?
Echemos un vistazo al archivo de configuración de kafka y descubramos que advertised.listeners=PLAINTEXT://kafka-002:9092
advertised.listeners
la función de los parámetros es Broker
publicar Listener
la información en Zookeeper
el
Entonces , en lugar de obtener el nombre de host flume
desde allí , puede cambiar la configuración para reiniciar y resolver el problemakafka
ip
kafka
advertised.listeners
ip
kafka
Caso 2: LB
(balanceo de carga) header
Después de aumentar la solicitud, nginx
no se puede obtener el registroheader
key
client_ip
Déjame hablar sobre la escena primero.
Después de LB
hacer el equilibrio de carga de siete capas, remote_addr
lo que ve es LB ip
, así que agregue el del cliente ip
a la solicitud a cargo del equilibrio header
client_ip
.
nginx
Se agregó la impresión de registro y $http_client_ip
no se obtuvo header
el valor de esto.
¿Cuál es la razón?
¿ Será porque no ha aumentado el número de socios responsables de la operación y mantenimiento de LB client_ip
header
?
¿O header
se agrega pero el valor está vacío?
Esto requiere que tcpdump capture paquetes para verificar nuestra suposición.
Ejecute el siguiente comando en nginx:
tcpdump -s 0 -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'|grep client_ip
结果发现:
client_ip: 1.1.1.1
A partir de la información de captura de paquetes, se puede ver que el cliente ip
está configurado en header
el interior y LB
la configuración de la descripción no es un problema, por lo que el problema viene de nginx
este lado.
¿Por qué pasar el valor $http_client_ip
no obtenido header
?
Encuentre la configuración relevante a través nginx
del sitio web oficial header
http://nginx.org/en/docs/http/ngx_http_core_module.html encontrado
Syntax: underscores_in_headers on | off;
Default:
underscores_in_headers off;
Context: http, server
En este punto, se revela la verdad. nginx
De manera predeterminada, se ignorarán header
la evasión subrayada definida por el usuario y los conflictos nginx
integrados .header
key
Problema solucionado tras modificar nginx
ajustes de configuraciónunderscores_in_headers no;
Caso 3: consulta mysql
QPS
muy alta, pero mysql
no lenta, quiero saber topK
mysql
la declaración
mysql
La carga se vuelve alta y qps
extremadamente alta, pero no hay una consulta lenta, o puede ser que sql
query time
la consulta lenta no esté expuesta debido a una configuración irrazonable. Me preocupa que esto afecte el rendimiento de la base de datos durante mucho tiempo. Quiero para saber qué declaración lo causó?
No hay una auditoría habilitada aquí mysql
, y la persona que llama no registra registros, por lo que no es fácil de solucionar.
¿Como lidiar con? ¿Hay alguna forma de obtenerlo de forma no intrusiva y sin intervención de I+D topK
sql
?
Ahí es cuando el nuestro tcpdump
brilla
El script general para agarrar mysql es el siguiente:
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.=" $_";
}
}'
Ejecutar en la máquina mysql con alto qps
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
Si encuentra SQL de alta frecuencia, puede comunicarse con los desarrolladores, si hay nuevas funciones comerciales en línea y optimizar soluciones.
Desde este punto de vista, componentes similares también pueden capturar y localizar problemas de esta forma.
Aquí hay otra herramienta de captura de paquetes de red recomendada MySQL
https://github.com/40t/go-snifferRedis
MongoDB
http
Finalmente: la escena de la escena de captura del protocolo http
Obtenga solicitudes HTTP GET
tcpdump -i enp0s8 -s 0 -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'
explicar:
tcp\[((tcp\[12:1\] & 0xf0) >> 2):4\]
Los 4 bytes que definen la ubicación de la cadena que queremos interceptar (detrás del encabezado http).
0x47455420
es G E T
el código ASCII de .
Personaje | Valor ASCII |
---|---|
GRAMO | 47 |
mi | 45 |
T | 54 |
Espacio | 20 |
Obtenga solicitudes HTTP POST
tcpdump -i enp0s8 -s 0 -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504F5354
0x504F5354
Representa el código ASCII P O S T
de .
Solicitud HTTP GET con puerto de destino 80
tcpdump -i enp0s8 -s 0 -A 'tcp dst port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'
Solicitudes HTTP GET y POST con puerto de destino 80 o 443 (desde 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
Obtenga la solicitud y respuesta HTTP GET y POST
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'
El puerto de destino del filtro es 80, el host es 10.10.10.10, solicitud y respuesta de http get/post
0x3C21444F
Sí '<' 'D' 'O' 'C'
Código ASCII, como identificador para archivos html
0x48545450
Sí, 'H' 'T' 'T' 'P'
código ASCII, utilizado para captar la respuesta HTTP
Supervisar todas las URL de solicitud HTTP (GET/POST)
tcpdump -i enp0s8 -s 0 -v -n -l | egrep -i "POST /|GET /|Host:"
Obtenga la contraseña en la solicitud POST
tcpdump -i enp0s8 -s 0 -A -n -l | egrep -i "POST /|pwd=|passwd=|password=|Host:"
Tome las cookies en Solicitud y respuesta
tcpdump -i enp0s8 -nn -A -s0 -l | egrep -i 'Set-Cookie|Host:|Cookie:'
Filtrar encabezados HTTP
#从header里过滤出user-agent
tcpdump -vvAls0 | grep 'User-Agent:'