Блокировка трафика из определенных стран. Как убить существующее соединение?

Блокировка трафика из определенных стран. Как убить существующее соединение?

Использую Linux Debian Bookworm.

Проблема

Я хочу заблокировать все входящие соединения с моим сервером из определенных стран.

Редактировать

Как кто-то указал в комментариях, мне действительно не следует делать это с iptables, поскольку это остановит мой сервер, как только список заблокированных IP-адресов вырастет до неуправляемого размера (например, тысячи IP-адресов). Вместо этого мне следует использовать ipset(для блокировки целых диапазонов). Проблема в том, что это зависит от списков, которые мне нужно загружать на регулярной основе. Я хочу что-то, что я устанавливаю один раз (предпочтительно).

Как же мне остановить подключения из определенных стран?Трафик (а иногда и атаки методом подбора) из Китая и России выходит из-под контроля. Они регулярно ставят мой сервер на колени. Они не придерживаются файла robots.txt и очень агрессивно сканируют сайт (сотнями, иногда тысячами подключений одновременно). Мне действительно нужно это прекратить. По моим подсчетам, более 90% всего трафика, который обрабатывает мой сервер, вредоносный/неправильно сформированный.

Редактировать 2

Я нашел несколько онлайн-уроков (как этот) как это сделать, но, похоже, эти руководства довольно старые. Кроме того, для этого требуется загрузка и компиляция/установка некоторых модулей. Я беспокоюсь, что это может сломаться в будущем (при обновлении/модернизации других пакетов или даже дистрибутива) или может стать угрозой безопасности в будущем. Я поддерживаю свой сервер в актуальном состоянии (регулярно запуская apt-get update / apt-get upgrade / apt-get dist-upgrade).

Исходное сообщение

Я нашел в сети скрипт, который (в двух словах) получает список IP-адресов установленных соединений каждую секунду, затем использует geoiplookup для получения страны IP-адреса. Если страна есть в списке стран, которые вы хотели бы заблокировать, он добавляет IP-адрес в фильтр вашего брандмауэра с помощью iptables. Я внес несколько небольших изменений в скрипт (сделав его более читабельным и потому что мне не было интересно, чтобы этот скрипт отправлял мне письмо каждый раз, когда он блокирует IP-адрес). Затем этот скрипт запускается каждую минуту через crontab:

#!/bin/bash
# Script found on lautenbacher.io"

end=$((SECONDS+55))

while [ $SECONDS -lt $end ]; do
  echo $SECONDS
  netstat -ant | egrep ':.*ESTABLISHED' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c > testcc.txt
  sed 's/^[ t]*//' -i testcc.txt
  sed '/^$/d' -i testcc.txt

  while read c d; do

    if [[ $c > "0" ]]; then
      bGF1dGVuYmFjaGVyLmlv=$(geoiplookup $d | awk -v ip="$d" '{FS=" "} {if($4 == "RU," || $4 == "CN," || $4 == "BLR,") {print 1}}')

      if [[ $bGF1dGVuYmFjaGVyLmlv = "1" ]]; then
        echo "running geolookup"
        echo checking ip $d
        geoiplookup $d

        isCloudflare=0
        # The original script made an exception for CLOUDFLARE. I don't want that exception
        # bGF1dGVuYmFjaGVyLmlX=$(whois $d)
        # if [[ "$bGF1dGVuYmFjaGVyLmlX" == *"CLOUDFLARE "* ]]; then
        #  isCloudflare=1
        #  echo Cloudflare detected
        # fi

        if [[ "$isCloudflare" != 1 ]]; then
          echo try to add ip $d to blocklist
          sudo iptables -I INPUT -s $d -j DROP
          ### I would like to sever the connection here ###
        fi

      fi

    fi
  done < testcc.txt

  sleep 1
    :
done

Кстати, я понятия не имею, почему автор скрипта использует такие странные имена переменных («bGF1dGVuYmFjaGVyLmlv»).

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

sudo iptables -I INPUT -s $d -j DROP

на ip-адресе. Это все нормально, но большинство этих соединений довольно устойчивы, то есть через секунду тот же ip-адрес находится и снова добавляется с помощью iptables. Я не уверен, что происходит (создает ли это дублирующие правила?), но я хотел бы немедленно разорвать соединение после того, как ip-адрес был добавлен с помощью iptables.

Итак, вкратце: как я могу завершить все соединения с IP-адресом?

решение1

Уже несколько лет ядро ​​Linux имеет API для принудительного уничтожения существующих IP-сокетов независимо от их состояния. Это можно сделать с помощьюssКоманда и синтаксис ее фильтра:

-K,--kill

Пытается принудительно закрыть сокеты. Эта опция отображает сокеты, которые успешно закрыты, и молча пропускает сокеты, которые ядро ​​не поддерживает закрытие. Поддерживает только сокеты IPv4 и IPv6.

Вы можете заменить:

### I would like to sever the connection here ###

с:

ss --kill -n dst = "$d"

Theфильтр( dst = ...) необходимо, поскольку команда уничтожит любой отображаемый сокет. Без фильтра это было бы более чем запрошено. Локальный процесс может получить в противном случае редкую ошибку на своем сокете, например ECONNABORTED. Удаленный узел, вероятно, будет уведомлен с помощью TCP RST, если только правило OUTPUT также (временно) не будет добавлено для предотвращения этого.

См. также этот вопрос/ответ (где я дал ответ):Отключите ВСЕ TCP-соединения (УСТАНОВЛЕННЫЕ,СВЯЗАННЫЕ) в Ubuntu, где OP пытается защитить от атак с помощьюipset(а также имеет проблемы с устаревшими соединениями и межсетевым экраном с отслеживанием состояния).

Связанный контент