Как мне найти общее количество TCP-соединений для данного порта и периода времени по IP?

Вопрос или проблема

В системе Linux существует множество методов для отображения текущих TCP-соединений для заданного порта по соединяющему IP, но: как я могу посчитать общее количество соединений на порт по исходному IP за период времени?

Включите iptables и установите его на LOG для входящих соединений. Пример правила:

 -A INPUT --state NEW -p tcp --dport 4711 -j LOG

(где 4711 — это порт, который вы хотите отслеживать).

Затем пропустите полученный лог через любой скрипт, который вам по душе, чтобы сделать сводку.

Вы можете использовать tcpdump для логирования всех SYN (без ACK) пакетов:

tcpdump "dst port 4711 and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn"

или логировать все SYN+ACK пакеты (установленные соединения):

tcpdump "src port 4711 and tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)"

А затем соедините это с wc -l для подсчета всех строк

Вам также потребуется способ измерения фиксированных периодов времени (вы можете использовать cron для отправки SIGINT через регулярные интервалы времени, tcpdump будет считать байты и пакеты, но только логирует время)

Обновление: не обязательно говорить, взгляните на man-страницу tcpdump и рассмотрите использование таких опций, как: -i (слушать только один интерфейс), -p (отключить режим promiscuous; менее инвазивно) или некоторые опции вывода. Tcpdump требуется root-права, а вашему начальнику это может не понравиться, потому что это своего рода инструмент хакера. С другой стороны, вам не нужно трогать ничего в вашей системе, чтобы запустить его (в отличие от решения с iptables LOG)

Пожалуйста, обратите внимание на небольшую разницу src/dst в фильтре. Если вы ловите SYN+ACK пакеты и хотите подсчитать соединения к серверу на порту 4711, вам нужен src. Если вы ловите SYN+!ACK пакеты для того же результата, вам нужен dst. Если вы считаете соединения на самом сервере, всегда нужно использовать обратное.

Решение SystemTap

Скрипт, вдохновленный примером tcp_connections.stp:

#!/usr/bin/env stap
# Чтобы мониторить другой TCP порт, выполните:
#     stap -G port=80 tcp_connections.stp
# или
#     ./tcp_connections.stp -G port=80
global port = 22
global connections

function report() {
  foreach (addr in connections) {
    printf("%s: %d\n", addr, @count(connections[addr]))
  }
}

probe end {
  printf("\n=== Сводка ===\n")
  report()
}

probe kernel.function("tcp_accept").return?,
      kernel.function("inet_csk_accept").return? {
  sock = $return
  if (sock != 0) {
    local_port = inet_get_local_port(sock)
    if (local_port == port) {
      remote_addr = inet_get_ip_source(sock)
      connections[remote_addr] <<< 1
      printf("%s Новое соединение от %s\n", ctime(gettimeofday_s()), remote_addr)
    }
  }
}

Вывод:

[root@bubu ~]# ./tcp_connections.stp -G port=80
Пн Мар 17 04:13:03 2014 Новое соединение от 192.168.122.1
Пн Мар 17 04:13:04 2014 Новое соединение от 192.168.122.1
Пн Мар 17 04:13:08 2014 Новое соединение от 192.168.122.4
^C
=== Сводка ===
192.168.122.1: 2
192.168.122.4: 1

Решение strace

Либо запустить программу под strace:

strace -r -f -e trace=accept -o /tmp/strace ${PROGRAM} ${ARGS}

или отслеживать уже выполняющуюся программу:

strace -r -f -e trace=accept -o /tmp/strace -p ${PID_OF_PROGRAM}

-r выведет относительную метку времени при входе в каждый системный вызов, если это потребуется позже для дополнительного анализа производительности. -f будет отслеживать дочерние процессы и может не потребоваться.

Вывод выглядит примерно так:

999        0.000000 accept(3, {sa_family=AF_INET, sin_port=htons(34702), sin_addr=inet_addr("192.168.122.4")}, [16]) = 5
999        0.008079 --- SIGCHLD (Дочерний процесс завершен) @ 0 (0) ---
999        1.029846 accept(3, {sa_family=AF_INET, sin_port=htons(34703), sin_addr=inet_addr("192.168.122.4")}, [16]) = 5
999        0.008276 --- SIGCHLD (Дочерний процесс завершен) @ 0 (0) ---
999        3.580122 accept(3, {sa_family=AF_INET, sin_port=htons(50114), sin_addr=inet_addr("192.168.122.1")}, [16]) = 5

и может быть отсортирован с помощью:

# gawk 'match($0, /^([0-9]+)[[:space:]]+([0-9.]+)[[:space:]]+accept\(.*htons\(([^)]+)\),.*inet_addr\("([^"]+)"\).*[[:space:]]+=[[:space:]]+([1-9][0-9]*)/, m) {connections[m[4]]++} END {for (addr in connections) printf("%s: %d\n", addr, connections[addr]); }' /tmp/strace
192.168.122.4: 3
192.168.122.1: 2

Краткое объяснение однострочника AKW: m[1] — это PID, m[2] — временная метка, m[3] — удаленный порт, а m[4] — удаленный адрес.

Преимущество этого решения заключается в том, что root-права не требуются, если сервер работает под той же учетной записью пользователя. Недостаток заключается в том, что все соединения подсчитываются без фильтрации, поэтому это не сработает, если приложение слушает на нескольких портах.

Ваша система не будет запоминать количество предыдущих соединений, если вы специально не предусмотрите это, поэтому не ожидайте найти такие счетчики, как у вас для общего трафика через интерфейс, если вы не настроите что-то для подсчета.

Кроме того, в общем смысле, вы не можете осуществлять подсчет надежно по запросам, как предложил Яцек Лакомиец, так как некоторые соединения могут начаться и закончиться быстрее, чем период вашего запроса. Такой подход может быть приемлемым для некоторых ситуаций, в которых вы уверены, что время, в течение которого устанавливаются соединения, достаточно долгое, но я не могу придумать хороших причин предпочесть его.

Как предложили Дженни Д. и Даниэль Альдер, ваши варианты для подсчета соединений в процессе их возникновения — это в основном счетчики на основе брандмауэра и счетчики на основе захвата пакетов. Оба метода обычно работают хорошо, хотя если ваш процессор ограничен в ресурсах, вы можете не посчитать некоторые соединения, если используете метод на основе пакетов. Также это может потребовать больше системных ресурсов для подсчета. С другой стороны, подходы на основе захвата пакетов могут быть проще и безопаснее для настройки в случае внеплановых расследований.

Существует другой общий класс решения, который называется netflow. Его сложнее настроить, но если это сделано правильно, он особенно эффективен, и если вы занимаетесь крупномасштабным или постоянным мониторингом, я бы смотрел в эту сторону. Собирать сырые данные можно в вашем брандмауэре (например, с помощью fprobe-ulo) или с использованием libpcap, который медленнее (например, fprobeg). Система захвата отправляет данные о потоках через сеть на коллектор (например, nfdump), а затем у вас появляются различные инструменты для анализа этих данных (например, nfsen).

Некоторые маршрутизаторы (особенно оборудование от Cisco) поддерживают захват netflow, и его также можно настроить на других маршрутизаторах с помощью сторонней прошивки. Конечно, вы можете запустить его на вашей системе Linux. При желании многие точки сбора могут пересылать свои данные потока единому коллектору. Вы можете найти бесплатные программные опции, например, на http://www.networkuptime.com/tools/netflow/, а также существует множество коммерческих предложений.

Netflow предназначен для использования в промышленных масштабах, но я нашел его очень удобным для сбора данных об использовании моей домашней сети в коммунальной квартире, чтобы я мог определить, кто или что является причиной, когда использование трафика выше ожидаемого.

Будьте осторожны, когда вы изменяете правила брандмауэра на удаленном сервере, и, вообще говоря, я бы рекомендовал найти хороший интерфейс для настройки вашего брандмауэра, вместо того чтобы использовать команды iptables напрямую. (Мне нравится ferm, но есть много хороших опций).

Еще одно, о чем стоит подумать, – иногда вы не хотите делать это на сетевом уровне вообще. Иногда уместно мониторить системные вызовы процесса-демона с помощью strace или аналогичного инструмента. Это весьма ресурсоемко, и будьте осторожны, чтобы не замедлить процесс демона, но в некоторых обстоятельствах это может быть уместно, в зависимости от того, какую информацию вам также необходимо собрать или, возможно, если вам необходимо изолировать один форкованный дочерний процесс демона.

На данный момент наиболее работавшее для меня решение было просто считывать содержимое /proc/net/ip_conntrack каждые 20 секунд, логируя это в файл с именем, содержащим соответствующую временную метку, и используя их в качестве входных данных для любых фильтрующих скриптов или даже однострочников при необходимости. Чтобы сэкономить время, вы можете использовать мой скрипт. Я использую записи в crontab, чтобы убедиться, что скрипт запускается каждую минуту (он выполняется 60 секунд в текущей конфигурации, не стесняйтесь модифицировать его :-))

 cat conn_minute.sh
#!/bin/bash

function save_log {
LOG_DIR=/mnt/logs/ip_conntrack/`date +%Y%m%d`
TEMP_FILE=$LOG_DIR/`date +%Y%m%d_%H%M%S`.gz
LOG_FILE=$LOG_DIR/`date +%Y%m%d_%H`.tar
if [ ! -d $LOG_DIR ]
then
    mkdir $LOG_DIR
fi
gzip -c /proc/net/ip_conntrack > $TEMP_FILE
if [ -f $LOG_FILE ]; then
    tar -rf $LOG_FILE $TEMP_FILE 2> /dev/null
else
    tar -cf $LOG_FILE $TEMP_FILE 2> /dev/null
fi
rm $TEMP_FILE
}
function log_minute {
i=1;
LOOP_COUNTER=3
LOOP_TIME=20
while [ $i -le $LOOP_COUNTER ]; do
    save_log
    i=$[i+1]
    sleep $LOOP_TIME
done
}

log_minute

Вы можете настроить, как часто вы хотели бы выкладывать содержимое ip_conntrack, изменяя LOOP_COUNTER и LOOP_TIME соответствующим образом. Чтобы получать это каждые 5 секунд, это будет: LOOP_COUNTER=12, LOOP_TIME=5.

После этого вы можете использовать zcat для того, чтобы выводить файлы, которые вас интересуют, и использовать grep для фильтрации исходных IP/портов, которые вас интересуют (или просто использовать zgrep). grep -c подсчитает, что угодно, за чем вы охотитесь. Вы также можете использовать grep src=1.2.3.4 | grep dport=63793 | sort | uniq | wc -l.

Записывайте лог самостоятельно:

$> nohup netstat -c | grep -E "xxx|xxxx" >> netstat_log 2>&1 &

nohub перетаскивает этот процесс в фоновый режим, чтобы он пережил ваш выход

netstat -c заставит netstat выводить выбранную информацию каждую секунду, непрерывно, навсегда

grep -E “xxx|xxxx” перехватит ваш желаемый контент, например, порт и

>> netstat_log … запишет это в “./netstat_log” (используйте ваш желаемый файл журнала здесь)

Переадресация вывода в | wc -l будет считать (wc) строки (-l) этого.

Я думаю, что ответ Дженни Д. хороший, только он создает лог, который вы затем должны разобрать для даты и посчитать количество строк. Это может быть утомительным и долгим. Это также использует много места на диске.

Следующее правило (Дженни без -j):

-A INPUT --state NEW -p tcp --dport 4711

работает так же без логирования, но включает счетчик. Затем вы можете прочитать этот счетчик, чтобы получить необходимую информацию. Вы можете прочитать счетчик и сбросить его атомарным образом, предоставляя вам действительно точное количество за время. Тогда вы можете просто сохранить это количество.

Чтобы сделать проще чтение счетчика, вы, вероятно, захотите добавить правило в свою собственную цепочку. Таким образом, вы можете лучше контролировать позицию вашего правила.

-A counters --state NEW -p tcp --dport 4711

И в цепочке INPUT, вызовите цепочку counters:

-A INPUT -j counters

(Вы можете оптимизировать это, если у вас есть несколько счетчиков, и все они требуют состояния NEW, вас интересует только TCP, соединения должны быть на конкретном интерфейсе и т.д., добавив это в правило -A INPUT вместо каждого отдельного правила в цепочке counters.)

Вот команда, которую вам нужно запустить, чтобы получить и сбросить счетчик атомарно:

sudo iptables -nvx -L counters 1 -Z counters 1 | awk '{ print $1 }'

Если у вас есть несколько счетчиков, вы можете изменить две 1 для извлечения другого:

# извлеките счетчик 3
sudo iptables -nvx -L counters 3 -Z counters 3 | awk '{ print $1 }'

Опции -nvx важны:

  • -n предотвращает обратные DNS-запросы (что здесь было бы действительно бесполезно)
  • -v включает счетчики в вывод
  • -x выводит счетчик без округления до тысяч, миллионов, гигабайт…

Команда awk ... используется для извлечения самого первого слова, которое является вашим счетчиком.

Опция -Z очищает счетчик после вызова. Это означает, что он будет снова считать. Если, например, вы проверяете раз в час, вы получите количество всего, что ваше правило ловит за час. Вы можете последнюю команду iptables запускать через crontab или аналогичный планировщик (systemd предлагает таймерные единицы).

В случае, если у вас много счетчиков, вы можете заинтересоваться получением индекса каждого из них (или возможно вам нужны другие подцепочки…) и вы можете это сделать с помощью опции --line-numbers:

sudo iptables -nvx --line-numbers -L counters

(Здесь опции v и x не обязательны.)

Взгляните на

. Они все немного устарели, но писать скрипты, чтобы делать работу, которую другие сделали лучше, скучно. Некоторые дают вам красивые графики, некоторые более специализированы для судебного анализа и привязки плохих парней, некоторые (iplog) являются просто очень простыми счетчиками, которые логируют в базы данных, некоторые имеют блестящие интерфейсы, которые можно показать вашему начальнику.

Также существует множество инструментов для реализации бесплатного стека, совместимого с netflow, на linux. И множество людей пытаются продать поддержку вокруг этого. (Я не буду рекомендовать коммерческий продукт…) То, чего вы просите, намного проще, чем то, на что способны некоторые из этих инструментов.

На мой взгляд (Free|Net|Open)BSD значительно опередили в этом анализе годы назад. Брандмауэр pFsense предоставит вам по крайней мере 7 опций из коробки.

.

Ответ или решение

На вопрос о том, как найти общее количество TCP-соединений на определенном порту за указанный период времени по IP-адресу, существует несколько решений на Linux-системах. Давайте рассмотрим различные подходы и инструменты, которые помогут вам достичь этой цели.

1. Использование Iptables

Настройка логирования через Iptables

Первый метод заключается в использовании Iptables для отслеживания новых соединений. Создайте правило, которое будет логировать входящие соединения:

-A INPUT --state NEW -p tcp --dport 4711 -j LOG

В приведенной команде порт 4711 — это порт, который вы хотите отслеживать. После этого можно использовать скрипт для обработки логов, чтобы подсчитать количество соединений за определенный период времени.

Преимущества и недостатки

Иптеблс позволяет детально управлять сетевыми пакетами, и его правила могут быть адаптированы под ваши нужды. Однако, это может занимать много дискового пространства, и вам потребуется отдельный процесс для разбора логов.

2. Использование Tcpdump

Захват пакетов SYN

С помощью Tcpdump можно отфильтровать специфические пакеты, например SYN без ACK, которые обозначают установление нового соединения:

tcpdump "dst port 4711 and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn"

Подсчет с помощью wc -l

Объедините команду с wc -l, чтобы подсчитать количество записей в логе:

tcpdump "dst port 4711 and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn" | wc -l

Преимущества и недостатки

Tcpdump не требует изменений в настройках системы и может быть использован для ад-хок анализа. Однако, требует прав суперпользователя и может потребовать значительных системных ресурсов.

3. SystemTap

Используйте SystemTap для мониторинга TCP-соединений. Пример скрипта для мониторинга соединений на порту можно адаптировать под ваши нужды, предоставляя возможность детализированного анализа:

#!/usr/bin/env stap
global port = 4711
global connections

function report() {
  foreach (addr in connections) {
    printf("%s: %d\n", addr, @count(connections[addr]))
  }
}

probe kernel.function("tcp_accept").return?, kernel.function("inet_csk_accept").return? {
  sock = $return
  if (sock != 0) {
    local_port = inet_get_local_port(sock)
    if (local_port == port) {
      remote_addr = inet_get_ip_source(sock)
      connections[remote_addr] <<< 1
    }
  }
}

probe end {
  printf("\n=== Summary ===\n")
  report()
}

Преимущества включает в себя отсутствие необходимости модифицировать систему, но требует знаний SystemTap и наличия полезных инструментов.

4. NetFlow

NetFlow предоставляет промышленный подход для мониторинга сетевой активности. Если ваша задача — мониторинг в большом масштабе или на постоянной основе, стоит рассмотреть этот метод. Вы можете настроить отправку данных в удаленный сборщик для последующего анализа.

Заключение

Для выбора подходящего инструмента важно учитывать ваш контекст и требования. Iptables подходит для внутреннего контроля и мониторинга, Tcpdump — для быстрого анализа, SystemTap — для глубокой диагностики. Если вы находитесь в сложной экосистеме или управлении крупными сетями, NetFlow может быть предпочтительным решением.

Будьте осторожны при внедрении данных подходов на продуктивных серверах. Настройка инструментов мониторинга может потребовать административных прав и оказать влияние на производительность системы.

Оцените материал
Добавить комментарий

Капча загружается...