Давний читатель, первый плакат .. Яда, яда, яда ..
В любом случае, я надеюсь, что у кого-то есть обширный опыт работы с модулями iptables / netfilter LIMIT или HASHLIMIT и он объяснит поведение, которое я наблюдаю.
Задний план: У нас есть веб-сервер, и мы хотим ограничить количество подключений, которые клиент может иметь в течение месяца (кстати, HTTP-сообщения поддержки активности отключены). Итак, я пытаюсь использовать модуль iptables LIMIT, чтобы ограничить количество их новых подключений заданным числом в месяц (скажем, 500). Модуль iptables LIMIT использует алгоритм «token bucket», поэтому я должен иметь возможность установить limit-burst (размер корзины) на 500 и limit (скорость пополнения) на 500, разделенные на 28 дней или около 18 / день. Это гарантирует, что ведро будет наполнено через месяц (4 недели), если оно будет каждый раз полностью опорожняться. (Я понимаю, что на самом деле это будет более 500, но этого должно быть достаточно для наших нужд).
Вот мои правила iptables (мы группируем IP-адреса с помощью ipset. LimBurTest4 содержит мои исходные тестовые машины)
Chain INPUT (policy DROP 2316 packets, 186K bytes)
pkts bytes target prot opt in out source destination
2952K 626M ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED /* Accept outgoing return traffic */
379 13702 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8 state NEW limit: avg 1/sec burst 1
377 30868 DROP icmp -- * * 0.0.0.0/0 0.0.0.0/0
0 0 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp flags:0x3F/0x00 /* Block NULL packets */
73 14728 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp flags:!0x17/0x02 state NEW /* Block SYN flood */
0 0 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp flags:0x3F/0x3F /* Block XMAS packets */
24 120 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 match-set LimBurTest4 src tcp dpt:443 limit: avg 18/day burst 500 /* LimitBurst Test */
76 30180 LOG tcp -- * * 0.0.0.0/0 0.0.0.0/0 match-set LimBurTest4 src tcp dpt:443 /* LimitBurst Testing */ LOG flags 0 level 4 prefix "LimBurTest Over Quota "
2522 138K REJECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 /* Reject queries */ reject-with tcp-reset
Я добавляю правило LIMIT следующим образом:
iptables -I INPUT 7 -m set --match-set LimBurTest4 src -p tcp --dport 443 -m limit --limit 18/day --limit-burst 500 -m comment --comment "Limit Burst Test" -j ACCEPT
Тестирование: Затем я создал простой сценарий оболочки, чтобы делать запросы к моему веб-серверу один за другим, используя curl. Каждый успешный запрос занимает около 0,20 мс. Вывод скрипта выглядит так:
./limBurTest.sh
1 - 200 - 0.257 ms
2 - 200 - 0.193 ms
3 - 200 - 0.155 ms
etc.
etc.
Итог: Я ожидал, что эта конфигурация быстро (за пару секунд) израсходует все 500 соединений, прежде чем я начну видеть отклоненные соединения. Однако этого совсем не происходит. Вместо этого мой тестовый сценарий установил 24 успешных соединения, а остальные были отклонены. Например, в приведенном выше выводе iptables я запускал свой сценарий оболочки в цикле 100 раз, и вы можете увидеть 24 совпадения правила ACCEPT и 76 совпадений правила LOG после правила ACCEPT. Я тестировал это на CentOS 6.8 и Ubuntu 16.04, и оба ведут себя таким образом, но это кажется противоречащим документации. Почему я не могу использовать все 500 подключений, указанных в limit-burst?
И, да, конечно, я много погуглил и видел множество примеров, когда люди говорили, что модуль LIMIT должен работать именно так, как я описал. И я много раз читал документацию по netfilter.
Что мне здесь не хватает?
Заранее спасибо.
Модуль ограничения не ограничивает количество подключений, а количество IP-пакетов (даже jumbo-пакетов). Таким образом, если одно соединение принимает примерно 20,8 пакетов, вы увидите всплеск 500/20.8~=24
соединения.
см. вывод команды man 8 iptables-extensions|grep -e '^ *limit$' -A 18
для получения дополнительной информации, в частности фразы "Максимальный начальный количество пакеты для соответствия: [...] ".