Правила написаны для цепочки INPUT, адаптируйте для своих нужд, если Вы хотите, например, фильтровать транзитный или исходящий трафик.
Приведу два варианта использования, для ограничения доступа к сервису ssh.
Перед тем, как выполнять команды из этих примеров, убедитесь, что установленные соединения пропускаются, иначе каждый (а не только инициирующий) пакет в tcp-соединении будет проходить через эти цепочки правил и вы потеряете контроль над своей текущей ssh-сессией)
iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m recent --name ssh --update --seconds 3600 --hitcount 5 -j REJECT iptables -A INPUT -p tcp --dport 22 -m recent --name ssh --set -j ACCEPT
При прохождении цепочки предпринимаются следующие действия:
Входящий TCP трафик на порт 22 проверяется модулем recent. ЕСЛИ за последние 3600 секунд прошло 5 или более пакетов, то перейти к цели REJECT, при этом добавить последнее время попытки подключения на этот порт. Если же первое правило не сработало, то вторым правилом добавляется или обновляется последняя запись о входящем пакете и пакет пропускается внутрь. Такие правила наиболее подходят для публичных сервисов. Например, защита dns или ntp демонов от последствий деятельности вирусов на клиентских машинах.
iptables -A INPUT -p tcp --dport 22 -m recent --name ssh --update --seconds 3600 --hitcount 8 -j REJECT iptables -A INPUT -p tcp --dport 22 -m recent --name ssh --set iptables -A INPUT -p tcp --dport 22 -m recent --name ssh ! --rcheck --seconds 15 --hitcount 2 -j REJECT iptables -A INPUT -p tcp --dport 22 -j ACCEPT
Как это работает? Последнее правило: если ни одно из предшествующих правил не сработало, то принимать пакет. Второе правило безусловно создает или обновляет запись о последнем пакете. Третье правило отвергает пакеты, если за последние 15 секунд было менее 2-х попыток подключения. Первое правило отвергает, если за последние 3600 секунд было 8 или более пакетов.
Первая попытка подключения: пакет не соответствует правилу 1, второе правило добавляет его в таблицу последних попыток подключения. У второго правила нет цели, поэтому пакет идет дальше по цепочке. Третье правило проверяет, есть запись в таблице недавних подключений. Да, пакет занесен в таблицу предыдущим правилом, но всего один, а требуется 2. Правило не сработало бы, но установлено отрицание правила (!), значит правило срабатывает и первый пакет отвергается целью REJECT. Если вторая попытка соединения будет предпринята в течении 15 секунд после первой, то третье правило не сработает, и пакеты будут пропускаться 4-м правилом. При этом каждый такой пакет будет заноситься в таблицу недавних вторым правилом. При превышении лимита 8 подключений в час все пакеты будут блокироваться первым правилом, при этом каждый раз обновляя последнюю запись.
Т.е. первое соединение отвергается. Второе, если оно сделано не позднее чем 15 секунд после предыдущего - принимается. И так до 8 соединений, затем все блокируется. Т.е. если вас будут сканировать на предмет открытых портов для атаки, то порт окажется закрытым. Если вторая попытка просмотра портов с того же адреса позднее чем 15 секунд - то тоже все закрыто.
Текущее состояние таблиц можно посмотреть в каталоге
/proc/net/xt_recent/
# из локалки пускаем без проверки /sbin/iptables -A INPUT -p tcp --dport 22 -i eth0 -j ACCEPT # 4 за 10 минут /sbin/iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 600 --hitcount 5 --name ssh_1 -j LOG --log-level info --log-prefix "Annoying-SSH2: " /sbin/iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 600 --hitcount 5 --name ssh_1 -j REJECT --reject-with icmp-host-prohibited # 1 раз в минуту /sbin/iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 2 --name ssh_1 -j LOG --log-level info --log-prefix "Annoying-SSH1: " /sbin/iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 2 --name ssh_1 -j REJECT --reject-with icmp-host-prohibited /sbin/iptables -A INPUT -p tcp --dport 22 -j LOG --log-level info --log-prefix "Accept-SSH: " /sbin/iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name ssh_1 /sbin/iptables -A INPUT -p tcp --dport 22 -j ACCEPT