Como descobrir o PID do processo enviando pacotes (gerando tráfego de rede)?

4

Há algumas semanas, tive um problema em que alterei endereços DNS em uma grande rede de cerca de 300 nós. Depois disso, alguns dos nós continuaram a perguntar a antigos servidores DNS, embora o resolv.conf estivesse ok e o host / nslookup estivesse consultando novos servidores DNS.

Olhando para o tcpdump e tentando gravar pedidos com o log do iptables, eu confirmei que de fato alguns dos hosts ainda estavam enviando consultas para servidores de nomes antigos.

Eu tirei um dos hosts da produção e comecei a desligar os processos de serviços / stracing na tentativa de descobrir o culpado.

No final - era o daemon lldpd, que obviamente armazenava servidores de nomes na inicialização e nem notava alterações no resolv.conf.

Então, minha pergunta é: existe uma maneira mais inteligente de descobrir qual PId está gerando um tipo específico de tráfego? Eu tentei com auditctl mas sem muito sucesso. O CentOS 6 está em questão, mas se houver uma solução para qualquer distribuição Linux, eu agradeceria.

    
por Jakov Sosic 10.02.2015 / 16:10

6 respostas

3

Eu lutei com o mesmo problema alguns dias atrás, e desenvolvi um método muito simples. É baseado no fato de que o processo de envio estará aguardando uma resposta do DNS, na mesma porta em que enviou a solicitação de :

  1. Descubra a porta de origem da solicitação de DNS de saída, com iptables -j LOG
  2. Use lsof -i UDP:<source_port> para descobrir qual processo está aguardando resposta nessa porta.

É claro que, quando a resposta chega em milissegundos, você não pode fazer isso manualmente; Além disso, mesmo quando automatizado, não há garantia de que você será capaz de consultar o sistema antes que a resposta do DNS chegue e o processo de envio seja interrompido. É por isso que antes mesmo de executar as etapas acima, eu também configuro o Controlador de Tráfego do kernel para pacotes de saída delay direcionados para um ip / port específico (usando tc module netem ). Isso me permite controlar a janela de tempo que tenho para consultar o sistema sobre qual PID está aguardando a resposta do DNS, na porta UDP de origem obtida na etapa 1.

Eu automatizei as etapas acima, incluindo o tc delay, em um pequeno script chamado ptrap (que é um solução geral, não limitada a solicitações de DNS, portanto qualificada para detecção de processos usando qualquer protocolo baseado em TCP / UDP). Com a ajuda dele descobri que, no meu caso, o serviço que entrava em contato com o antigo servidor DNS era o sendmail.

    
por 10.06.2017 / 14:59
2

O que há de errado com o auditctl?

Você faria assim ...

1) Defina sua regra de auditoria para auditar sendmsg e enviar para as chamadas do sistema. Essas chamadas do sistema são usadas durante a resolução de nomes.

auditctl -a exit,always -F arch=b64 -S sendmsg -S sendto -k send

2) Agora procure seus registros de auditoria. Você pode fazer o grep com base no IP do DNS remoto aqui

ausearch -k send -i|grep -A2 "serv:53"

No exemplo abaixo, você pode ver que o aplicativo responsável pela chamada do sistema é chamado de dig

ausearch -k send -i|grep -A2 "serv:53"
type=SOCKADDR msg=audit(10/31/2016 15:24:56.264:176998) : saddr=inet host:172.16.0.23 serv:53 
type=SYSCALL msg=audit(10/31/2016 15:24:56.264:176998) : arch=x86_64 syscall=sendmsg success=yes exit=29 a0=14 a1=7fa1919f9ac0 a2=0 a3=7fa1919f9780 items=0 ppid=31729 pid=32047 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts5 ses=52 comm=dig exe=/usr/bin/dig subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=send


comm=dig exe=/usr/bin/dig

E a maneira de diferenciar a qual solicitação de DNS remoto é enviada está aqui. Então você teria apenas que grep para um host DNS específico.

saddr=inet host:172.16.0.23 serv:53 

Ou ainda melhor - veja quais hosts DNS são usados (eu tenho apenas um neste exemplo)

ausearch -k send -i|grep "serv:53"|awk '{print $6}'|sort|uniq -c
      3 host:172.16.0.23

Depois, reduza quais aplicativos estão usando esses hosts específicos.

Editar 1: Na verdade eu apenas fiz um simples ping para um host. Parece que o sendmsg nem sempre é usado. Aqui está o que eu vejo

socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 4
connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("172.16.0.23")}, 16) = 0
gettimeofday({1477929832, 712018}, NULL) = 0
poll([{fd=4, events=POLLOUT}], 1, 0)    = 1 ([{fd=4, revents=POLLOUT}])
sendto(4, "6
auditctl -a exit,always -F arch=b64 -S connect -k connect
ausearch -k connect -i|grep saddr|grep "serv:53"|awk '{print $6}'|sort|uniq -c
auditctl -a exit,always -F arch=b64 -S sendmsg -S sendto -k send
ausearch -k send -i|grep -A2 "serv:53"
ausearch -k send -i|grep -A2 "serv:53"
type=SOCKADDR msg=audit(10/31/2016 15:24:56.264:176998) : saddr=inet host:172.16.0.23 serv:53 
type=SYSCALL msg=audit(10/31/2016 15:24:56.264:176998) : arch=x86_64 syscall=sendmsg success=yes exit=29 a0=14 a1=7fa1919f9ac0 a2=0 a3=7fa1919f9780 items=0 ppid=31729 pid=32047 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts5 ses=52 comm=dig exe=/usr/bin/dig subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=send


comm=dig exe=/usr/bin/dig
saddr=inet host:172.16.0.23 serv:53 
ausearch -k send -i|grep "serv:53"|awk '{print $6}'|sort|uniq -c
      3 host:172.16.0.23
socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 4
connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("172.16.0.23")}, 16) = 0
gettimeofday({1477929832, 712018}, NULL) = 0
poll([{fd=4, events=POLLOUT}], 1, 0)    = 1 ([{fd=4, revents=POLLOUT}])
sendto(4, "6
auditctl -a exit,always -F arch=b64 -S connect -k connect
ausearch -k connect -i|grep saddr|grep "serv:53"|awk '{print $6}'|sort|uniq -c
%pre%%pre%%pre%%pre%%pre%%pre%\tvkontakteru%pre%%pre%%pre%", 30, MSG_NOSIGNAL, NULL, 0) = 30 poll([{fd=4, events=POLLIN}], 1, 5000) = 1 ([{fd=4, revents=POLLIN}]) ioctl(4, FIONREAD, [62]) = 0 recvfrom(4, "610%pre%%pre%%pre%%pre%%pre%%pre%\tvkontakteru%pre%%pre%%pre%0\f"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("172.16.0.23")}, [16]) = 62 close(4) = 0
\tvkontakteru%pre%%pre%%pre%", 30, MSG_NOSIGNAL, NULL, 0) = 30 poll([{fd=4, events=POLLIN}], 1, 5000) = 1 ([{fd=4, revents=POLLIN}]) ioctl(4, FIONREAD, [62]) = 0 recvfrom(4, "610%pre%%pre%%pre%%pre%%pre%%pre%\tvkontakteru%pre%%pre%%pre%0\f"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("172.16.0.23")}, [16]) = 62 close(4) = 0

Meu exemplo anterior foi baseado no aplicativo dig, que leva um caminho ligeiramente diferente em termos de chamadas do sistema. Então, parece que na maioria dos casos seria essa regra

%pre%

Seguido por ausearch

%pre%     
por 31.10.2016 / 16:37
1

Existem muitas opções para netstat que mostram combinações de escuta / open sockets em tcp / udp / both. Algo como:

$> sudo netstat -pan
Active Internet connections (servers and established)
Proto  Recv-Q Send-Q Local Addr            Foreign Addr           State       PID/Program name
...
tcp    0      1      192.168.66.1:39219    192.168.66.139:2003    SYN_SENT    2045/logstash-forwa

... teria dado a você muita saída, mas incluía a origem, o destino, os números de porta e o PID do processo que possui essas portas.

    
por 10.02.2015 / 16:20
1

+1 para a resposta de Dmitry acima; que funcionou bem para mim:

auditctl -a exit,always -F arch=b64 -F a0=2 -S socket -k SOCKET

Para ver as entradas resultantes, eu grep o arquivo de log para aquela string "-k"

grep SOCKET /var/log/audit/audit.log

Para obter apenas os campos interessantes,

grep SOCKET /var/log/audit/audit.log | \
  cut -d' ' -f 4- | \
  sed "s|^|@\n|g;s| |\n|g" | \
  grep -E "^((exe|uid|comm)=|@)" | \
  tr '\n@' ' \n' |\
  sort -u

(explicação: cut -d '' -f 4 - - > corte a linha em campos usando espaço (-d '') como delimitador, mostre os campos de quarto a último (4-) )

(explicação: sed "s | ^ | @ \ n | g; s | | \ n | g" - > edita linha, prefixar '@' char-plus-newline para iniciar de linha, mudar espaços para novas linhas)

(explicação: grep -E "^ ((uid | comm | exe) = | @)" - > como cada campo da linha original está agora em sua própria linha, escolha os campos interessantes: user-id, comando, executável - e o line-start '@' char.)

(explicação: tr '\ n @' '\ n' - > agora tendo apenas os campos desejados, transforme as novas linhas em espaços e o prefixo '@' em uma nova linha (que reúne os campos em uma linha)

(explicação: sort -u - > linhas de classificação, mostram apenas linhas exclusivas)

me dá:

uid=0 comm="atop" exe="/usr/bin/atop" 
uid=0 comm="http" exe="/usr/lib/apt/methods/http" 
uid=0 comm="links" exe="/usr/bin/links" 
uid=0 comm="ntpdate" exe="/usr/sbin/ntpdate" 
uid=0 comm="ufdbguardd" exe="/usr/local/ufdbguard/bin/ufdbguardd" 
uid=1000 comm=536F636B657420546872656164 exe="/usr/lib/firefox/firefox" 
uid=1000 comm="clock-applet" exe="/usr/lib/mate-panel/clock-applet" 
uid=1000 comm="pool" exe="/usr/lib/mate-panel/clock-applet" 
uid=105 comm="http" exe="/usr/lib/apt/methods/http" 
uid=105 comm="https" exe="/usr/lib/apt/methods/https" 
uid=135 comm="unbound" exe="/usr/sbin/unbound" 
uid=13 comm="squid" exe="/usr/src/squid-4-master/src/squid" 
uid=1 comm="debsecan" exe="/usr/bin/python2.7" 

Os comandos que contêm espaços são codificados no método ascii-to-hex simples (consulte audit_logging.c ). Para decodificar, substitua "FF" por "& #xFF;" e recode isso de html para ascii:

grep SOCKET /var/log/audit/audit.log | \
  cut -d' ' -f 4- | sed "s|^|@\n|g;s| |\n|g" | \
  grep -E "^((exe|uid|comm)=|@)" | tr '\n@' ' \n' | \
  sort -u  | sed "s|^[^=]*=||g;s| [^ ]*=| |g" | \
  while read U C E ; do \
    echo "$C" | grep -q '"' || \
      { C=\"'echo $C | sed "s|\(..\)|\&#x;|g" | recode h4..u8'\" ; } ; \
    echo "uid=$U comm=$C exe=$E" ; 
  done

(explicação: sed "s | ^ [^ =] = || g | s | [^] = | g" - > edita o nome 'xxx =' parte das linhas - primeiro: line-start (^) seguido por any-char-except - '=' é substituído por blank, espaço seguido por any-char-except- '' substituído por space

(explicação: durante a leitura de UCE; faça ... terminado - > faça um loop em cada linha, lendo cada um dos três bits de dados em U, C, E (userid, comando, executável))

(explicação: echo "$ C" | grep -q '"' || - > testa o campo de comando para ver se contém um doublequote - se não ('||') então faça o seguinte:)

(explicação: {C = \ " echo $C | sed "s|\(..\)|\&#x;|g" | recode h4..ascii \";} - > imprime a string de comando, edita cada par de caracteres 'FF' como '& #xFF;' , então passe pelo gnu 'recode' para transformá-los de entidades html em ascii chars.)

(explicação: echo "uid = $ U comm = $ C exe = $ E" - > imprime a linha modificada)

Isso me dá saída (apenas mostrando a linha decodificada):

uid=1000 comm="Socket Thread" exe="/usr/lib/firefox/firefox

/ j

    
por 21.07.2017 / 18:54
1

Existe atop . Existe um módulo do kernel ( netatop ) e daemon que fará com que atop rastreie o uso da rede por processo.

Você deve primeiro instalar o atop

Aqui está como você instala o módulo do kernel. Isso é válido quando a postagem foi escrita, mas pode ficar desatualizada:

sudo apt install linux-headers-$(uname -r) make zlib1g-dev
wget https://www.atoptool.nl/download/netatop-2.0.tar.gz
tar xvf netatop-2.0.tar.gz
cd netatop-2.0
make
sudo make install
sudo modprobe -v netatop

Se você tiver systemd, crie o arquivo de serviço netatopd.service file em /etc/systemd/system/ . Ele conteria:

[Unit]
Description=NetAtop Daemon

[Service]
Type=forking
ExecStart=/usr/sbin/netatopd

[Install]
WantedBy=multi-user.target

Agora você pode ativar o daemon:

sudo systemctl enable netatopd

Para ver o uso da rede ao vivo, por processo:

sudo atop -n

Para ver os três principais intensificadores de rede ao longo do dia:

atopsar -N

man atopsar para mais opções.

    
por 12.10.2018 / 00:13
0

lsof seria uma ferramenta apropriada para monitorar uma porta específica e determinar o PID que gera tráfego nela. Por exemplo, aqui estou monitorando em um servidor a porta TCP de domínio / DNS 53, para que eu possa determinar qual PID está causando a pesquisa de DNS:

$ lsof -PniTCP:53 -r 1 | grep :53

Agora, se eu enviar algum tráfego curl para o servidor DNS:

$ curl -v telnet://192.168.3.182:53
* About to connect() to 192.168.3.182 port 53 (#0)
*   Trying 192.168.3.182...
* Connected to 192.168.3.182 (192.168.3.182) port 53 (#0)

veremos esse tipo de saída do comando acima:

curl    4953 root    3u  IPv4 197807920      0t0  TCP 192.168.23.48:50688->192.168.3.182:53 (ESTABLISHED)
curl    4953 root    3u  IPv4 197807920      0t0  TCP 192.168.23.48:50688->192.168.3.182:53 (ESTABLISHED)
curl    4953 root    3u  IPv4 197807920      0t0  TCP 192.168.23.48:50688->192.168.3.182:53 (ESTABLISHED)

Como funciona

O comando acima que observa o tráfego da porta 53 funciona colocando lsof em um loop de repetição que é executado a cada 1 segundo, -r 1 . Em seguida, informamos lsof para informar somente o tráfego que usa a porta 53, iTCP:53 . O -Pn instrui lsof a exibir nomes de host e portas como números e não nomes reais.

Em seguida, usamos um grep para ler a saída proveniente de lsof e filtrar a saída para que possamos ver apenas :53 tráfego de porta.

O PID do processo que está enviando o tráfego está na saída mostrada por lsof também. A segunda coluna mostra o PID, 4953.

    
por 12.11.2018 / 03:43