Auteur Sujet: iptables connlimit: Limitation du nombre de connexion TCP simultanées par IP  (Lu 4719 fois)

0 Membres et 1 Invité sur ce sujet

vivien

  • Administrateur
  • *
  • Messages: 47 183
    • Twitter LaFibre.info
Limitation du nombre de connexion TCP simultanées par IP

Après plusieurs mois d’expérimentation avec différentes valeurs et en analysant les logs pour voir si j'ai bloqué du trafic légitime, je pense avoir trouvé la bonne valeur pour limiter les connexions abusives d'une même IP sur les serveurs que je gère.

Depuis ce matin, c'est voici les paramètres que j'ai mis en place :
- Serveurs de test de débit : Limitation à 50 connexions TCP ouvertes simultanément pour une même IPv4 ou un même bloc /64 en IPv6
- Serveurs web comme ce forum : Limitation à 100 connexions TCP ouvertes simultanément pour une même IPv4 ou un même bloc /64 en IPv6
- Serveur de mise à jour pour Ubuntu : Limitation à 600 connexions TCP ouvertes simultanément pour une même IPv4 ou un même bloc /64 en IPv6

Concrètement, j'ai pris en compte que des bugs peuvent engendrer des connexion inutiles lors du surf, cf Firerox (sous Ubuntu) ouvre des connexion TCP puis fait un reset. 100 connexion était insuffisant pour un serveur web.
Pour le serveur de mise à jour Ubuntu (utilisé par prés d'un million d'Ubuntu ou dérivé en France), on a des cas ou de nombreuses machines virtuelles toutes derrière la même IPv4 ou le même /64 vont faire des mises à jour. Les mises à jour sont normalement échelonnées dans le temps, mais j'ai préféré jouer la sécurité, quand les mises à jour sont de grande taille cela peut prendre du temps et j'ai préféré voir large.

Ce que j'ai mis en place, c'est un fichier iptables-rules.sh : (exemple ci-dessous pour une limitation à 100 connexions TCP par IPv4)

sudo nano /root/iptables-rules.sh

#!/bin/dash
# Limiter le nombre de sessions tcp par client (un client = une IPv4 ou un /64 en IPv6)
/sbin/iptables  -A INPUT -p tcp --syn -m connlimit --connlimit-above 100 -m limit --limit 30/hour --limit-burst 1 -j LOG --log-prefix="drop-c-"
/sbin/iptables  -A INPUT -p tcp --syn -m connlimit --connlimit-above 100 -j REJECT
/sbin/ip6tables -A INPUT -p tcp --syn -m connlimit --connlimit-above 100 --connlimit-mask 64 -m limit --limit 30/hour --limit-burst 1 -j LOG --log-prefix="drop-c-"
/sbin/ip6tables -A INPUT -p tcp --syn -m connlimit --connlimit-above 100 --connlimit-mask 64 -j REJECT

sudo chmod +x /root/iptables-rules.sh
sudo echo "# Application de la QoS au reboot" > /etc/cron.d/iptables-rules
sudo echo "@reboot         root    /root/iptables-rules.sh" >> /etc/cron.d/iptables-rules




Vérification après reboot : IPv4

iptables -L
# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
LOG        tcp  --  anywhere             anywhere             tcp flags:FIN,SYN,RST,ACK/SYN #conn src/32 > 100 limit: avg 30/hour burst 1 LOG level warning prefix "drop-c-"
REJECT     tcp  --  anywhere             anywhere             tcp flags:FIN,SYN,RST,ACK/SYN #conn src/32 > 100 reject-with icmp-port-unreachable
DROP       udp  --  anywhere             anywhere             udp dpts:5200:5209

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

IPv6 :
ip6tables -L
# ip6tables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
LOG        tcp      anywhere             anywhere             tcp flags:FIN,SYN,RST,ACK/SYN #conn src/64 > 100 limit: avg 30/hour burst 1 LOG level warning prefix "drop-c-"
REJECT     tcp      anywhere             anywhere             tcp flags:FIN,SYN,RST,ACK/SYN #conn src/64 > 100 reject-with icmp6-port-unreachable
DROP       udp      anywhere             anywhere             udp dpts:5200:5209

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

A noter que dans vos scripts, il faut bien préciser /sbin/iptables et pas uniquement iptables.
Le premier fonctionne systématiquement, le second ne fonctionnera quand dans un shell interactif, donc pas au reboot du serveur.
Si vous ne voyez pas la règles avec iptables -L, cela peut être la raison...

vivien

  • Administrateur
  • *
  • Messages: 47 183
    • Twitter LaFibre.info
Consulter les log iptables drop-c- :

Pour consulter les logs : journalctl -k | grep drop-c-

Voici ce que cela donne (j'ai juste remplacé le dernier octet du réseau IPv6 par x) :

$ journalctl -k | grep drop-c-
mai 23 07:17:05 lafibre kernel: drop-c-IN=em1.74 OUT= MAC=d4:ae:52:ce:c5:c7:74:8e:f8:63:5f:81:86:dd SRC=2a02:8428:0523:9xx1:0926:cb2a:55eb:aa00 DST=2a01:6e00:0010:0410:0000:0000:0000:0002 LEN=72 TC=0 HOPLIMIT=56 FLOWLBL=38539 PROTO=TCP SPT=57937 DPT=443 WINDOW=64800 RES=0x00 SYN URGP=0
mai 23 16:38:19 lafibre kernel: drop-c-IN=em1.74 OUT= MAC=d4:ae:52:ce:c5:c7:74:8e:f8:63:5f:81:86:dd SRC=2a01:cb10:02a3:fxx0:2c5d:5b4b:0793:e986 DST=2a01:6e00:0010:0410:0000:0000:0000:0002 LEN=72 TC=0 HOPLIMIT=54 FLOWLBL=495480 PROTO=TCP SPT=62926 DPT=443 WINDOW=64800 RES=0x00 SYN URGP=0



Consultation des stats (nombre de paquets) :

Consulter les stats IPv4 : iptables -n -v -L INPUT
# iptables -n -v -L INPUT
Chain INPUT (policy ACCEPT 1685M packets, 3081G bytes)
 pkts bytes target     prot opt in     out     source               destination         
  105  5672 LOG        tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp flags:0x17/0x02 #conn src/32 > 50 limit: avg 30/hour burst 1 LOG flags 0 level 4 prefix "drop-c-"
68052 3825K REJECT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp flags:0x17/0x02 #conn src/32 > 50 reject-with icmp-port-unreachable
   16   512 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpts:5200:5209

Consulter les stats IPv6 : ip6tables -n -v -L INPUT
# ip6tables -n -v -L INPUT
Chain INPUT (policy ACCEPT 162M packets, 2140G bytes)
 pkts bytes target     prot opt in     out     source               destination         
    1    80 LOG        tcp      *      *       ::/0                 ::/0                 tcp flags:0x17/0x02 #conn src/64 > 50 limit: avg 30/hour burst 1 LOG flags 0 level 4 prefix "drop-c-"
    7   560 REJECT     tcp      *      *       ::/0                 ::/0                 tcp flags:0x17/0x02 #conn src/64 > 50 reject-with icmp6-port-unreachable
    0     0 DROP       udp      *      *       ::/0                 ::/0                 udp dpts:5200:5209

vivien

  • Administrateur
  • *
  • Messages: 47 183
    • Twitter LaFibre.info
Avant j'ai fais des essais sur mon réseau local en limitant à 2 connections TCP sur la même IPv4
/sbin/iptables  -A INPUT -p tcp --syn -m connlimit --connlimit-above 2 -j REJECT

J'ai bien le comportement attendu : 2 connexions TCP ouvertes maximum, il faut attendre qu'une connexion se ferme pour pouvoir en ouvrir une autre.

Si la connexion TPC se ferme rapidement il est possible d'en ré-ouvrir une autre, donc cela protège pas contre le scan de port.

Sur le serveur de mise à jour Ubuntu on voit bien l'effet, l'activation a été fait à l'endroit où j'ai mis la barre rouge :


Quand vous dépasser le nombre de connexion, voici ce que cela donne dans Firefox :


vivien

  • Administrateur
  • *
  • Messages: 47 183
    • Twitter LaFibre.info
iptables connlimit: Limitation du nombre de connexion TCP simultanées par IP
« Réponse #3 le: 17 septembre 2020 à 15:29:36 »
Récemment passé à Ubuntu 20.04, j'ai été étonné par des occupation de plus de 3000 slots Apache :



Après vérifications, c'est du slow DDOS (connexion ouverte qui se termine par un Request Time-out, le time-out étant réduit à 30 secondes sur les serveurs que je gère). J'ai immédiatement augmenté le nombre de solts dans la configuration Apache, le serveur étant en mesure d'en gérer plus (32 Go de ram).

Mais dans les log, j'ai été étonné : il n'y avait que deux IP sources (Free et SFR, encore un bug dans un logiciel ?)

La raison est simple :
/sbin/iptables n'est plus le bon chemin pour appeler iptables : il a déménagé à /usr/sbin/iptables

Mon script avec iptables connlimit pour limiter le nombre de connexion TCP simultanées par IP ne lançait plus iptables.
En modifiant le script, tout refonctionne parfaitement.


A noter que c'est bpfilter qui est utilisé :
[453833.735271] bpfilter: Loaded bpfilter_umh pid 819018
[453833.735466] Started bpfilter



Ma question maintenant : dans un script faut-il appeler les logiciel avec leur chemin absolu ou n'indiquer que le nom du programme ?

J'avais compris qu'un intérêt de donner le chemin d’accès est d'éviter d'avoir un autre logiciel qui porterait le même nom mais qui serait plus tôt dans le path qui se lance à se place.
Toutefois, c'est une solution qui ne permet pas de fonctionner quand les binaires changent de chemin.