Назад | Перейти на главную страницу

Как узнать PID процесса, отправляющего пакеты (генерирующего сетевой трафик)?

Пару недель назад у меня возникла проблема, из-за которой я изменил адреса DNS в большой сети, насчитывающей около 300 узлов. После этого некоторые узлы по-прежнему продолжали запрашивать старые DNS-серверы, хотя resolv.conf был в порядке, а host / nslookup запрашивал новые DNS-серверы.

Посмотрев на tcpdump и попытавшись записывать запросы с помощью протоколирования iptables, я подтвердил, что действительно некоторые хосты все еще отправляли запросы на старые серверы имен.

Я снял с производства один из хостов и начал отключать сервисы / процессы проверки, пытаясь найти виновника.

В конце концов, это был демон lldpd, который явно кешировал серверы имён при запуске и даже не заметил изменений в resolv.conf.

Итак, мой вопрос: есть ли более разумный способ узнать, какой PId генерирует определенный тип трафика? Я пробовал с auditctl, но без особого успеха. Под вопросом стоит CentOS 6, но если есть решение для любого дистрибутива Linux, я был бы признателен.

Несколько дней назад я боролся с той же проблемой и придумал очень простой метод. Он основан на том, что отправляющий процесс будет ждать ответа DNS, на том же порту, с которого он отправил запрос:

  1. Узнайте порт источника исходящего DNS-запроса с помощью iptables -j LOG
  2. Использовать lsof -i UDP:<source_port> чтобы узнать, какой процесс ожидает ответа на этом порту.

Конечно, поскольку ответ приходит в течение миллисекунд, вы не можете сделать это вручную; более того, даже в автоматическом режиме нет гарантии, что вы сможете запросить систему до того, как придет ответ DNS и процесс отправки завершится. Вот почему, прежде чем даже выполнить вышеуказанные шаги, я также настраиваю контроллер трафика ядра на задержка исходящие пакеты, направленные на определенный IP / порт (с использованием tc модуль netem). Это позволяет мне контролировать временное окно, в котором я должен запрашивать систему о том, какой PID ожидает ответа DNS на исходном UDP-порту, полученном на шаге 1.

Я автоматизировал вышеуказанные шаги, включая tc задержка в небольшом скрипте под названием ловушка (что является более общим решением, не ограничиваясь DNS-запросами, что позволяет обнаруживать процессы, использующие любой протокол на основе TCP / UDP). С его помощью я узнал, что в моем случае сервис, связывающийся со старым DNS-сервером, был sendmail.

Что не так с auditctl?

Вы бы сделали это так

1) Определите правило аудита для аудита системных вызовов sendmsg и sendto. Эти системные вызовы используются при разрешении имен.

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

2) Теперь найдите свои записи аудита. Вы можете использовать grep на основе удаленного IP-адреса DNS здесь

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

В приведенном ниже примере вы можете увидеть, что приложение, которое отвечало за системный вызов, называется 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

И способ различить, на какой удаленный DNS-запрос отправлен, находится здесь. Таким образом, вам просто нужно будет найти конкретный DNS-хост с помощью grep.

saddr=inet host:172.16.0.23 serv:53 

Или даже лучше - посмотрите, какие DNS-хосты используются (в этом примере у меня только один)

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

А затем сузьте список приложений, использующих именно эти хосты.

Изменить 1: На самом деле я просто выполнил простой пинг для хоста. Похоже, sendmsg не всегда используется. Вот что я вижу

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, "\3\326\1\0\0\1\0\0\0\0\0\0\tvkontakte\2ru\0\0\1\0\1", 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, "\3\326\201\200\0\1\0\2\0\0\0\0\tvkontakte\2ru\0\0\1\0\1\300\f"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("172.16.0.23")}, [16]) = 62
close(4)                                = 0

Мой предыдущий пример был основан на приложении dig, которое использует несколько иной маршрут с точки зрения системных вызовов.
Похоже, что в большинстве случаев это правило

auditctl -a exit,always -F arch=b64 -S connect -k connect

Далее следуют ausearch

ausearch -k connect -i|grep saddr|grep "serv:53"|awk '{print $6}'|sort|uniq -c

Есть много вариантов netstat которые показывают комбинации прослушивающих / открытых сокетов через tcp / udp / both. Что-то вроде:

$> 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

... дал бы вам много вывода, но включал источник, назначение, номера портов и PID процесса, владеющего этими портами.

Там есть atop. Есть модуль ядра (netatop) и демон, который сделает atop отслеживать использование сети по процессам.

Вы должны сначала установить atop

Вот как вы устанавливаете модуль ядра. Это действительно на момент написания сообщения, но оно может устареть:

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

Если у вас есть systemd, создайте служебный файл netatopd.service файл в /etc/systemd/system/. Он будет содержать:

[Unit]
Description=NetAtop Daemon

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

[Install]
WantedBy=multi-user.target

Теперь вы можете включить демон:

sudo systemctl enable netatopd

Чтобы увидеть использование сети в реальном времени для каждого процесса:

sudo atop -n

Чтобы увидеть топ-3 наиболее загруженных сети в течение дня:

atopsar -N

man atopsar для дополнительных опций.

lsof будет подходящим инструментом для мониторинга определенного порта и определения PID, который генерирует на нем трафик. Например, здесь я отслеживаю на сервере TCP-порт 53 DNS / домена, чтобы определить, какой PID вызывает поиск DNS:

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

Теперь, если я пришлю немного curl трафик на 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)

мы бы увидели такой вывод из приведенной выше команды:

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)

Как это устроено

Приведенная выше команда, которая отслеживает трафик порта 53, работает, помещая lsof в повторяющийся цикл, который выполняется каждые 1 секунду, -r 1. Затем мы говорим lsof чтобы сообщить только о трафике, который использует порт 53, iTCP:53. В -Pn инструктирует lsof для отображения имен хостов и портов в виде чисел, а не фактических имен.

Затем мы используем grep читать вывод, исходящий из lsof и фильтруем вывод так, чтобы мы видели только :53 портовый трафик.

PID процесса, отправляющего трафик, находится в выходных данных, отображаемых lsof также. 2-й столбец показывает PID, 4953.