Шейпинг исходящего трафика для TCP порта в Linux

Материал из Википедия MyArena.ru
Версия от 15:25, 23 июля 2026; Ykpon (обсуждение | вклад) (Новая страница: «== Шейпинг исходящего трафика для TCP порта в Linux == Инструкция описывает, как ограничить (ш…»)

(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Шейпинг исходящего трафика для TCP порта в Linux

Инструкция описывает, как ограничить (шейпить) исходящую полосу пропускания для конкретного TCP-порта в зависимости от гео-принадлежности IP-адреса клиента (страны), используя nftables и tc/HTB.

Описание

Готовый скрипт geo-shaper.sh делает следующее:

  • скачивает базу MaxMind GeoLite2-Country (CSV) и строит из неё списки подсетей (CIDR) по странам;
  • через nftables помечает (fwmark) исходящие TCP-пакеты с заданного порта в зависимости от того, к какой группе стран относится IP-адрес назначения;
  • через tc (HTB) создаёт по одному классу на каждую группу и ограничивает скорость каждой группы своим значением.

Важно: шейпинг применяется к исходящему (исходящему от сервера) трафику на указанном сетевом интерфейсе, для TCP-пакетов с source port, равным указанному порту.

Схема поддерживает три группы (тарифа) по полосе пропускания:

  • группа 1 - свой список стран, свой лимит;
  • группа 2 - свой список стран, свой лимит;
  • группа 3 - всегда catch-all, то есть ловит весь трафик на этом порту, который не попал в группы 1 и 2 (даже если для неё указан непустой список стран - она всё равно работает как «всё остальное», см. раздел «Параметры» ниже).

Требования

Пример установки приведён для Ubuntu 22.04 LTS / 24.04 LTS (для Debian 11/12 команды идентичны, пакет-менеджер тот же - apt).

Необходимые пакеты:

Пакет Назначение
nftables классификация трафика (fwmark) по подсетям стран
iproute2 утилита tc - собственно шейпинг (HTB)
curl загрузка скрипта и базы GeoIP
unzip распаковка архива с базой MaxMind GeoLite2-Country CSV
gawk разбор и объединение CSV-файлов базы GeoIP

Установка пакетов

sudo apt update
sudo apt install -y nftables iproute2 curl unzip gawk
sudo systemctl enable --now nftables

Загрузка скрипта

Скрипт можно скачать по прямой ссылке и сохранить, например, в /opt/geo-shaper.sh:

sudo curl -fsSL -o /opt/geo-shaper.sh \
  https://wiki.myarena.ru/soft/geo-shaper.sh

sudo chmod +x /opt/geo-shaper.sh

Как узнать имя сетевого интерфейса

Перед запуском скрипта нужно знать имя интерфейса (например, eth1, enp1s0), через который сервер отдаёт трафик наружу.

Способ 1: автоматически, только имя

Команда определяет, через какой интерфейс реально уходит трафик в интернет, и выводит только его имя:

ip route get 1.1.1.1 | grep -oP 'dev \K\S+'

Пример вывода:

eth1

Способ 2: список всех интерфейсов и как выбрать нужный

ip -br addr show

Пример вывода:

lo               UNKNOWN        127.0.0.1/8 ::1/128
eth0             UP             10.0.0.5/24 fe80::a00:27ff:fe.../64
eth1             UP             203.0.113.10/24 fe80::a00:27ff:fe.../64
docker0          DOWN           172.17.0.1/16

Как понять, какой интерфейс нужен:

  • lo (loopback) - всегда игнорировать, это не сетевая карта.
  • Виртуальные интерфейсы вроде docker0, br-*, veth*, tun*, tap* обычно тоже не нужны, если только вы не шейпите именно докер-сеть.
  • Нужен интерфейс в состоянии UP.
  • Выбирайте интерфейс, у которого назначен публичный/внешний IP-адрес сервера - тот, на который клиенты подключаются к вашему сервису. В примере выше это eth1 с адресом 203.0.113.10.
  • Если сомневаетесь - сверьте с выводом команды из способа 1 (ip route get 1.1.1.1), она укажет ровно тот интерфейс, что смотрит в интернет.

Более подробная информация (MAC-адрес, MTU, статистика) - ip addr show или классический ifconfig -a (если установлен пакет net-tools).

Синтаксис запуска

sudo ./geo-shaper.sh <интерфейс> <порт> <лимит1_bps> <страны1> <лимит2_bps> <страны2> <лимит3_bps> <страны3>

Параметры

  • интерфейс - сетевой интерфейс, на котором шейпится исходящий трафик (например, eth1, enp1s0).
  • порт - TCP-порт (source port), для которого применяется шейпинг, например 443 или 80.
  • лимит1_bps / лимит2_bps / лимит3_bps - лимит полосы в битах в секунду (не байтах), например 700000000 = 700 Мбит/с.
  • страны1 / страны2 - список ISO-кодов стран через запятую в кавычках, например "RU,UA,KZ,BY". Для этих стран действует свой лимит.
  • страны3 - список стран для третьей группы. Группа 3 всегда работает как «все остальные страны» - то есть ловит весь трафик на данном порту, не попавший в группы 1 и 2, независимо от того, что указано в этом параметре. Обычно сюда передают просто пустую строку "".

Скрипт сам скачивает и кэширует базу MaxMind GeoLite2-Country (обновляется раз в 7 дней), поэтому первый запуск может занять чуть больше времени, чем последующие.

Пример: лимит для стран СНГ 700 Мбит/с, для остальных - 200 Мбит/с

В этом сценарии нужны фактически только два тарифа, поэтому вторая группа оставляется с пустым списком стран (не используется), а вся «остальная» полоса (третья группа) ограничивается 200 Мбит/с.

sudo /opt/geo-shaper.sh eth1 80 \
  700000000 "RU,BY,KZ,KG,TJ,TM,UZ,MD,AM,AZ,UA" \
  200000000 "" \
  200000000 ""

Что при этом происходит:

  • 700 Мбит/с - суммарный лимит для трафика в адрес IP из стран СНГ: RU, BY, KZ, KG, TJ, TM, UZ, MD, AM, AZ, UA (список условный, набор стран можно скорректировать под свои задачи);
  • вторая группа не используется (пустой список стран, никакой трафик под неё не попадёт);
  • 200 Мбит/с - лимит для всего остального трафика на порту 80 (все страны, не вошедшие в список выше).

Замените eth1 на свой интерфейс и 80 на реальный порт сервиса.

Проверка работы

Убедиться, что правила загружены и трафик классифицируется:

nft list table inet geoshaper
tc -s class show dev eth1
tc -s qdisc show dev eth1

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

Автозагрузка (запуск при старте сервера)

Правила tc и nftables, которые создаёт скрипт, не сохраняются при перезагрузке сервера - после ребута их нужно применить заново. Проще всего сделать это через systemd-сервис, который будет запускать geo-shaper.sh автоматически после старта сети.

1. Создать unit-файл

sudo nano /etc/systemd/system/geo-shaper.service

Содержимое файла (замените интерфейс, порт и параметры на свои - в примере используются значения из раздела «Пример» выше):

[Unit]
Description=GEO-based TCP traffic shaping (geo-shaper.sh)
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c '/opt/geo-shaper.sh eth1 80 700000000 "RU,BY,KZ,KG,TJ,TM,UZ,MD,AM,AZ,UA" 200000000 "" 200000000 ""'

[Install]
WantedBy=multi-user.target

Пояснения:

  • After=network-online.target / Wants=network-online.target - гарантирует, что сервис стартует только после того, как сеть реально поднята (интерфейс существует, есть доступ в интернет для загрузки базы GeoIP).
  • Type=oneshot + RemainAfterExit=yes - скрипт не "висит" в фоне, а один раз настраивает nftables/tc и завершается; при этом systemd считает сервис активным (не упавшим).
  • Команда обёрнута в /bin/bash -c '...' - это надёжнее, чем передавать аргументы напрямую в ExecStart, особенно из-за пустых строк "" в параметрах стран, которые старые версии systemd могут разобрать некорректно без обёртки в bash.

2. Включить и запустить сервис

sudo systemctl daemon-reload
sudo systemctl enable --now geo-shaper.service

3. Проверить статус

systemctl status geo-shaper.service

Должно быть видно active (exited) - это нормальное конечное состояние для Type=oneshot с RemainAfterExit=yes.

Изменение параметров в будущем

Если нужно поменять лимиты или списки стран - отредактируйте строку ExecStart в файле /etc/systemd/system/geo-shaper.service, затем примените изменения:

sudo systemctl daemon-reload
sudo systemctl restart geo-shaper.service