Собираем TCP|UDP сессии в Linux
Photo by Hans-Peter Gauster on Unsplash
Приветствую тебя мой дорогой друг!
Как говорится “назвался компьютерщиком, полезай в ИТ отдел”.
Преамбула
Попался мне как то на глаза скрипт, для сбора всех соединений на сервере, ну что идея хорошая, добавили в zabbix, ждем… 5 минут… 10 минут… Нет значений.
Ошибка поразила, скрипт не смог уложится в отведенные, 30 секунд.
Тут по идее должна быть картинка типа: “30 секунд, Карл!!!”.
Не буду описывать свое удивление когда я прочитал скрипт, вкратце это кровь из
глаз, куча матерных слов и истеричный смех, так как использовалось куча внешних
утилит, это все прогонялось через grep
, накладывались regexp и так далее и тому подобное.
И это все на Linux, где получить любое значение можно просто прочитав файл!!!
Начнем…
Как я написал выше, для получения значений нам нужно прочитать файл, но какой!? Идем искать ответ.
- Читаем Техническое Задание, нам нужно:
IP|PORT источника и IP|PORT назначения для TCP|UDP сессий
Процесс, который создал это подключение
Отображать нужно только LISTEN и ESTABLISHED
Отлично, можно начинать.
Список TCP|UDP
- За что я люблю Linux системы, это за то что в нем все, это “Файл”:
Файл -> Файл
Директория -> Файл
Устройство -> Файл
Сокет -> Файл
…
Информация о всех TCP/UDP сессиях так находится в файлах в /proc/net/tcp[6] и /proc/net/udp[6].
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode 0: 0100007F:1B1E 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 53620300 1 0000000000000000 100 0 0 10 0 1: 0100007F:DFFF 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 46149718 1 0000000000000000 100 0 0 10 0 2: 0100007F:77CA 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 52642353 1 0000000000000000 100 0 0 10 0
По структуре данного формата можно обратится к документации по ядру linux
В данной структуре есть практически все, кроме принадлежности к процессу, чего нам не хватает для реализации технического задания.
Процессы
Всю информацию о процессе, где можно получить… Правильно из файлов :)
В том числе и об открытых сокетах, которая хранится в /proc/PID/fd/.
Вот к примеру:
sergey@steel /proc/16381/fd $ for i in $(ls); do readlink $i;done /dev/null /dev/null socket:[49244920] /dev/urandom socket:[49244917] socket:[49245354] socket:[49244939] socket:[49244941] socket:[49234589] pipe:[49245313] pipe:[49244937] pipe:[49244937]
То есть из данного списка мы можем спокойно забрать только socket, где числовое значение будет значение inode.
Информацию об имени и PID можно получить из /proc/PID/status.
Итого
Прочитав несколько файлов и объединив информацию, о сессиях и процессах, по ключу inode, мы получаем всю нужную информацию.
Так как файловая система proc
располагается в RAM, то мы не упираемся в очереди
блочных устройств, и получаем информацию максимально быстро.
Получившийся скрипт можно взять в pyTcpProcess
Что удалось добиться, увеличение скорости с 32 секунд, до 0,3 секунд. Что я считаю хорошим показателем.
Спасибо за внимание.