Пару недель назад у меня возникла проблема, из-за которой я изменил адреса DNS в большой сети, насчитывающей около 300 узлов. После этого некоторые узлы по-прежнему продолжали запрашивать старые DNS-серверы, хотя resolv.conf был в порядке, а host / nslookup запрашивал новые DNS-серверы.
Посмотрев на tcpdump и попытавшись записывать запросы с помощью протоколирования iptables, я подтвердил, что действительно некоторые хосты все еще отправляли запросы на старые серверы имен.
Я снял с производства один из хостов и начал отключать сервисы / процессы проверки, пытаясь найти виновника.
В конце концов, это был демон lldpd, который явно кешировал серверы имён при запуске и даже не заметил изменений в resolv.conf.
Итак, мой вопрос: есть ли более разумный способ узнать, какой PId генерирует определенный тип трафика? Я пробовал с auditctl, но без особого успеха. Под вопросом стоит CentOS 6, но если есть решение для любого дистрибутива Linux, я был бы признателен.
Несколько дней назад я боролся с той же проблемой и придумал очень простой метод. Он основан на том, что отправляющий процесс будет ждать ответа DNS, на том же порту, с которого он отправил запрос:
iptables -j LOG
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.