LINUX.ORG.RU
решено ФорумAdmin

Ограничить количество соединений (NAT) на каждый DST каждому пользователю

 


0

4

…не используя connlimit, или ускорив его работу.


Есть роутер, выполняющий NAT. К нему подключено, условно, сто пользователей. Предположим, что выходной IP-адрес один.

Задача: запретить устанавливать больше 50000 соединений любому из пользователей к одному и тому же IP-адресу.
Иными словами, не дать единственному пользователю исчерпать порты на конкретный dst.

С большим удивлением обнаружил, что iptables connlimit невероятно медленный, до невозможности его использования в реальных задачах: отправка 20000 SYN’ов за ~10 секунд положит маршрутизацию на мощном сервере на 15+ секунд, забив ядро 100% softinterrupts.

Других подходящий matcher’ов не нашел. Ничего другого, кроме как connlimit, в голову не приходит. Хоть пиши userspace + eBPF.

Обращаю внимание: мне нужно ограничить количество соединений от одного пользователя к любому IP-адресу в интернете, а не к какому-то конкретному. Не замедлить установку соединений во времени, не применить общий лимит ко всем пользователям разом.

★★★★★

Последнее исправление: ValdikSS (всего исправлений: 3)

Нет других.

Раз сервер мощный, значит ядер много, значит rps должен помочь :)

Если хочется быстро, то только в виде патча к ядру. В новых ядрах ( >=5.19 ) обрабатывать закрытие соединений может только «conntrack extension» которое не может быть модулем (для x86_64 можно воспользоваться livepatch).

Сомневаюсь, что eBPF чем-то будет лучше.

vel ★★★★★
()
Последнее исправление: vel (всего исправлений: 1)
Ответ на: комментарий от vel

Ну тогда nfqueue + отправка SYN’ов каждые random % 10 раз в юзерспейс. Наверное, это наиболее универсальное, что можно придумать (и пакет можно легко drop’нуть).

ValdikSS ★★★★★
() автор топика
Ответ на: комментарий от ValdikSS

Как вариант дублировать трафик в юзерспейс и какой-то коллбек на блокировку новых соединений. Ущерб в точности очевидный. С другой стороны conntrack уже содержит эту инофрмацию, просто прикрутить счетчики. Хз, можно ли такое модулем к nf приделать.

Anoxemian ★★★★★
()
Ответ на: комментарий от ValdikSS

Через userspace есть более простой способ.

Обработываем события от conntrack (создание/удаление соединения). Для тех, кто перебрал, через ipset блок на SYN.

libipset имеет достаточно простой интерфейс.

vel ★★★★★
()
Последнее исправление: vel (всего исправлений: 1)
Ответ на: комментарий от vel

Обработываем события от conntrack (создание/удаление соединения)

Вы предлагаете это делать через netlink? Или как их ещё получать? А как их недопускать тогда?

ValdikSS ★★★★★
() автор топика
Последнее исправление: ValdikSS (всего исправлений: 1)
Ответ на: комментарий от ValdikSS

Да, через netlink.

Там и список текущих соединений можно получить.

conntrack -L и conntrack -E умеют это делать, т.ч. есть где содрать код.

в libnetfilter_conntrack есть примеры

vel ★★★★★
()
Последнее исправление: vel (всего исправлений: 1)
Ответ на: комментарий от vel

А как недопустить установку соединения? Это же основная проблема. Мне ничего лучше nfqueue в голову не приходит.

ValdikSS ★★★★★
() автор топика
Последнее исправление: ValdikSS (всего исправлений: 1)
Ответ на: комментарий от ValdikSS

Если кто-то перебрал соединений, то его ip добавляем в ipset X.

Если число коннектов упало ниже порога, то удаляем из ipset X.

Для коннектов из локальной сети наружу:

iptables -A FORWARD -m conntrack --ctstate NEW -m ipset --match-set X src -j DROP

Для tcp можно/лучше дропать syn из iptables/raw/PREROUTING

vel ★★★★★
()
14 ноября 2024 г.
Ответ на: комментарий от ValdikSS

Как оказалось, статья на которую была ссылка СИЛЬНО устарела.

Начиная с 4.16 все изменилось коренным образом.

Появился файл net/netfilter/nf_conncount.c в котором есть rbtree для всех conntrack.

Если считать только для конкретного ip, то должно быть достаточно быстро.

vel ★★★★★
()