--- categories: linux network firewall minifirewall title: Howto netfilter ... * Documentation : [netfilter](https://netfilter.org/) est la couche de firewalling sous Linux, contrôlable via les commandes `iptables` et `ip6tables`, ou plus récemment avec la commande `nft` (que nous n'utilisons pas encore). Sur les serveurs, nous utilisons notre script [minifirewall](https://gitea.evolix.org/evolix/minifirewall/) permettant une gestion simple d'un firewall local. ## Installation ~~~ # apt install iptables ~~~ ~~~ # iptables --version iptables v1.8.9 (nf_tables) # modinfo iptable_filter filename: /lib/modules/6.1.0-18-cloud-amd64/kernel/net/ipv4/netfilter/iptable_filter.ko description: iptables filter table author: Netfilter Core Team license: GPL depends: ip_tables,x_tables retpoline: Y intree: Y name: iptable_filter vermagic: 6.1.0-18-cloud-amd64 SMP preempt mod_unload modversions sig_id: PKCS#7 signer: Debian Secure Boot CA sig_key: 32:A0:28:7F:84:1A:03:6F:A3:93:C1:E0:65:C4:3A:E6:B2:42:26:43 sig_hashalgo: sha256 signature: 71:F7:F9:B6:38:B0:B8:63:41:D6:DA:39:41:2B:AD:EB:E4:5A:05:36: AF:9E:55:6F:CF:39:E2:D9:CD:23:7B:49:B0:C6:4D:BE:1F:A5:68:F2: 6D:EA:88:A1:CD:B5:4F:CE:3B:A2:10:3D:74:E7:DB:29:31:00:AF:81: CD:EA:31:BC:6D:68:F2:5B:1B:3B:85:6E:2C:52:B5:B7:14:44:62:C8: B9:2F:89:5A:E0:3A:9B:D9:89:48:A0:E1:F3:92:B7:B8:C2:C2:F4:6D: 34:95:4D:0A:2F:15:E9:F4:1D:3B:07:49:7B:8C:AB:56:58:18:C8:8D: 67:70:D7:D5:60:07:33:86:39:DA:5A:D0:6C:F3:37:F4:0A:84:A9:AF: FE:AC:8F:ED:C9:CA:C6:A6:DA:4B:23:AA:4F:7D:F0:37:90:AF:1C:EC: 73:F7:71:E2:50:42:48:0D:8A:7D:61:D4:F3:E2:FC:77:CF:96:0F:4D: 96:7D:85:A2:EC:7D:A9:A6:2E:41:58:DB:B3:72:A2:02:39:6C:B9:6A: 02:47:F2:DB:9B:AD:77:D9:04:8E:F8:42:D4:BA:40:D1:CE:3D:36:CB: 4B:18:C6:CC:4A:09:4A:7C:95:AF:4B:8B:04:83:13:3A:6C:DA:A0:BD: CB:D9:74:5E:8C:76:CF:03:CB:D2:E5:4B:F4:10:FB:E5 parm: forward:bool ~~~ ## Utilisation basique Lister les règles dans les 3 tables filter/nat/mangle : ~~~ # iptables -L -nvt filter --line-number # iptables -L -nvt nat --line-number # iptables -L -nvt mangle --line-number # ip6tables -L -nvt filter --line-number # ip6tables -L -nvt nat --line-number # ip6tables -L -nvt mangle --line-number ~~~ Interdire toutes les connexions venant de l'IP 192.0.2.66 : ~~~ # iptables -I INPUT -s 192.0.2.66 -j DROP ~~~ Renvoyer les connexions extérieures vers un port à un autre port (avec 192.0.2.42 l'IP du serveur local) : ~~~ /sbin/iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to 192.0.2.42:22 ~~~ Désactiver toutes les règles et laisser tout passer : ~~~ # iptables -P INPUT ACCEPT # iptables -P OUTPUT ACCEPT # iptables -P FORWARD ACCEPT # iptables -F -t filter # iptables -F -t nat # iptables -F -t mangle ~~~ Sauvegarder les règles courantes dans un fichier, réinitialiser les règles à partir d'un fichier : ~~~ # iptables-save > /tmp/IPT # ip6tables-save > /tmp/IP6T # iptables-restore /tmp/IPT # ip6tables-restore /tmp/IP6T ~~~ ## minifirewall [minifirewall](https://gitea.evolix.org/evolix/minifirewall/) est un script Shell permettant une gestion simple d'un firewall local, idéal pour un serveur dédié (virtualisé ou non). À partir de la version `22.03`, minifirewall dispose d'une configuration principale `/etc/default/minifirewall` uniquement déclarative et d'un système d'inclusion automatique de ce qui est dans `/etc/minifirewall.d/` ### Installation minifirewall ~~~ # [ -e /etc/default/minifirewall ] && cp /etc/default/minifirewall /etc/default/minifirewall.old # wget https://gitea.evolix.org/evolix/minifirewall/raw/branch/master/minifirewall.conf -O /etc/default/minifirewall # wget https://gitea.evolix.org/evolix/minifirewall/raw/branch/master/minifirewall -O /etc/init.d/minifirewall # chmod 700 /etc/init.d/minifirewall # chmod 600 /etc/default/minifirewall # mkdir /etc/minifirewall.d # chmod 700 /etc/minifirewall.d # insserv /etc/init.d/minifirewall ~~~ ### Configuration déclarative On peut gérer la configuration via le fichier `/etc/default/minifirewall`. * Il faut adapter la variable `INT` avec l'interface réseau principale Pour les règles en entrée, tout est coupé et il faut définir : * les variables `SERVICESTCP1` et `SERVICESUDP1` pour les ports publics en IPv4 et IPv6 * 2 catégories d'adresses IPv4 : les adresses de confiance `TRUSTEDIPS` et les adresses privilégiées `PRIVILEGIEDIPS` * pour les ports semi-publics, on utilise `SERVICESTCP2` et `SERVICESUDP2` ouverts aux adresses `PRIVILEGIEDIPS` * pour les ports privés, on utilise `SERVICESTCP3` et `SERVICESUDP3` ouverts aux adresses `TRUSTEDIPS` * les variables `SERVICESTCP1p` et `SERVICESUDP1p` ne servent pas, sauf si on a créé une chaîne IPTables spécifique `NEEDRESTRICT` Pour les règles en sortie, tout est coupé et on peut autoriser facilement les ports les plus classiques : * `DNSSERVEURS='0.0.0.0/0 ::/0'` pour autoriser toutes les requêtes DNS (en IPv4 et IPv6) * `HTTPSITES='0.0.0.0/0 ::/0'` pour autoriser toutes les requêtes en sortie vers le port 80 (en IPv4 et IPv6) * … Il est possible de configurer un proxy http sortant (par exemple Squid). La variable `PROXY` active ou désactibe le mécanisme depuis le firewall. `PROXYPORT` indique le port à utiliser pour le forward des paquets. `PROXYBYPASS` indique la liste des IP de destination pour lesquelles on ne passe pas par le proxy. ~~~{.bash} # Proxy (Squid) PROXY='on' # (proxy port) PROXYPORT='8888' # (destinations that bypass the proxy) PROXYBYPASS="${INTLAN} 127.0.0.0/8" ~~~ Il est possible de configurer les autorisations pour les serveurs de backup, en ajoutant des couples `IP:PORT` dans la variable `BACKUPSERVERS`. ~~~{.bash} # Backup servers BACKUPSERVERS='192.0.2.123:1234 203.0.113.42:5678' ~~~ Plusieurs autres variables sont disponibles pour affiner la configuration kernel (via `sysctl`) : ~~~{.bash} # In most cases, the default values set by minifirewall are good. # If you really know what you are doing, # you can uncomment some lines and customize the value. # Set 1 to ignore broadcast pings (default) # SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS='1' # Set 1 to ignore bogus ICMP responses (default) # SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES='1' # Set 0 to disable source routing (default) # SYSCTL_ACCEPT_SOURCE_ROUTE='0' # Set 1 to enable TCP SYN cookies (default) # SYSCTL_TCP_SYNCOOKIES='1' # Set 0 to disable ICMP redirects # SYSCTL_ACCEPT_REDIRECTS='0' # SYSCTL_SEND_REDIRECTS='0' # Set 1 to enable Reverse Path filtering (default) # Set 0 if VRRP is used # SYSCTL_RP_FILTER='1' # Set 1 to log packets with inconsistent address (default) # SYSCTL_LOG_MARTIANS='1' ~~~ Ces variables sont en général à laisser telles-quelles. Attention cependant à `SYSCTL_RP_FILTER` qu'il faut mettre à `0` lorsqu'on utilise VRRP. ### Configuration par inclusion Tous les fichiers présents dans `/etc/minifirewall.d` sont automatiquement inclus et exécutés au démarrage de minifirewall, par ordre alphanumérique, en excluant les fichiers contenant des points dans leur nom. On peut y mettre des commandes shell arbitraires pour appliquer des règles spécifiques. Quelques fonctions shell sont disponibles : ~~~ # Within included files, you can use those helper functions : # * is_ipv6_enabled: returns true if IPv6 is enabled, or false # * is_docker_enabled: returns true if Docker mode is eabled, or false # * is_proxy_enabled: returns true if Proxy mode is enabled , or false ~~~ * Pour autoriser toutes les requêtes en sortie vers le port 80 en IPv6 : `ip6tables -A INPUT -i $INT -p tcp --sport 80 --match state --state ESTABLISHED,RELATED -j ACCEPT` * Pour autoriser en sortie vers le port 636 d'un serveur extérieur : `iptables -A INPUT -p tcp --sport 636 --dport 1024:65535 -s ssl.evolix.net -m state --state ESTABLISHED,RELATED -j ACCEPT` > *Note* : pour autoriser un port en entrée, on n'utilisera pas de règle spécifique mais les variables dédiées dans la configuration principale > *Note* : pour autoriser un port en sortie, la règle à ajouter paraît contre-intuitive car les paquets en sortie sont déjà tous autorisés (sauf en UDP) : on autorise en fait les paquets de retour (`INPUT`) qui correspondent à des paquets déjà émis en sortie (`--state ESTABLISHED,RELATED`) ### IPv6 Si on souhaite désactiver le support IPv6, ça se fait via la variable `IPv6=off` Dans tous les cas il est conseillé de mettre les IPv4 et IPv6 dans les variables concernées. Les IPv6 seront ignorées si c'est désactivé. En IPv4, l'autorisation globale est `0.0.0.0/0`. l'équivalent en IPv6 est `::/0`. ### Docker #### Général La variable générale `DOCKER` permet de définir si minifirewall doit tenir compte de Docker. C'est surtout pour éviter de purger les règles injectées par Docker lors de l'arrêt ou du redémarrage de minifirewall. #### Docker → host Si on souhaite autoriser des conteneurs à communiquer via le réseau avec d'autres processus hors Docker sur le serveur, il faut autorise ces communications de manière explicite. _TODO: documenter avec des exemples et explications._ #### Docker Swarm Si on utilise Docker Swarm sur plusieurs serveurs, il faut une configuration particulière pour que la communication inter-nœuds se fasse bien. ~~~{.bash} # interface par laquelle les nœuds communiquent SWARM_INT=eno10 ## Pour chaque autre serveur de la Swarm (192.0.2.11, 192.0.2.12…) : NODE_IP=192.0.2.11 /sbin/iptables -I INPUT -i ${SWARM_INT} -p tcp -s ${NODE_IP} --dport 2377 -m comment --comment "Allow incomming docker swarm (management TCP) from ${NODE_IP}" -j ACCEPT /sbin/iptables -I INPUT -i ${SWARM_INT} -p tcp -s ${NODE_IP} --sport 2377 -m state --state ESTABLISHED,RELATED -m comment --comment "Allow outgoing docker swarm (management TCP) to ${NODE_IP}" -j ACCEPT /sbin/iptables -I INPUT -i ${SWARM_INT} -p tcp -s ${NODE_IP} --dport 7946 -m comment --comment "Allow incomming docker swarm (inter-node TCP) from ${NODE_IP}" -j ACCEPT /sbin/iptables -I INPUT -i ${SWARM_INT} -p tcp -s ${NODE_IP} --sport 7946 -m state --state ESTABLISHED,RELATED -m comment --comment "Allow outgoing docker swarm (inter-node TCP) to ${NODE_IP}" -j ACCEPT /sbin/iptables -I INPUT -i ${SWARM_INT} -p udp -s ${NODE_IP} --dport 7946 -m comment --comment "Allow incomming docker swarm (inter-node UDP) from ${NODE_IP}" -j ACCEPT /sbin/iptables -I INPUT -i ${SWARM_INT} -p udp -s ${NODE_IP} --sport 7946 -m state --state ESTABLISHED,RELATED -m comment --comment "Allow outgoing docker swarm (inter-node UDP) to ${NODE_IP}" -j ACCEPT /sbin/iptables -I INPUT -i ${SWARM_INT} -p udp -s ${NODE_IP} --dport 4789 -m comment --comment "Allow incomming docker swarm (network UDP) from ${NODE_IP}" -j ACCEPT /sbin/iptables -I INPUT -i ${SWARM_INT} -p udp -s ${NODE_IP} --sport 4789 -m state --state ESTABLISHED,RELATED -m comment --comment "Allow outgoing docker swarm (network UDP) to ${NODE_IP}" -j ACCEPT ## Une seule fois /sbin/iptables -I OUTPUT -o ${SWARM_INT} -p udp --dport 4789 -m comment --comment "Allow outgoing docker swarm (network UDP)" -j ACCEPT /sbin/iptables -I OUTPUT -o ${SWARM_INT} -p udp --dport 7946 -m comment --comment "Allow outgoing docker swarm (inter-node UDP)" -j ACCEPT ~~~ ### Commandes (start, stop…) ~~~ # /etc/init.d/minifirewall help minifirewall Firewall designed for standalone server Usage: minifirewall [COMMAND] Commands start Start minifirewall safe-start Start minifirewall, with baground safety checks stop Stop minifirewall restart Stop then start minifirewall safe-restart Restart minifirewall, with background safety checks status Print minifirewall status reset Reset iptables tables check-active-config Check if active config is up-to-date with stored config version Print version and exit help Print this message and exit ~~~ Il est possible de redémarrer le firewall en mode interactif avec une protection contre le blocage : ~~~ # /etc/init.d/minifirewall safe-restart sourcing `/etc/default/minifirewall' WARNING: current state is different than persisted state, check /var/run/minifirewall_state_diff minifirewall stopping flushing all rules and accepting everything minifirewall stopped minifirewall starting sourcing `/etc/minifirewall.d/zzz-custom' sourcing `/etc/minifirewall.d/zzzz-ban' minifirewall started INFO: rules have changed since latest start, check /var/run/minifirewall_state_diff Minifirewall will be stopped in 30 seconds if you do nothing. Remove `/var/run/minifirewall_safety.lock' or type anything to keep minifirewall started: ~~~ Il faut alors aller retirer le fichier de lock (par n'importe quel moyen) ou saisir et valider n'importe quoi au clavier. Si on ne le fait pas dans les 30 secondes, le firewall sera stoppé pour redonner la main à l'utilisateur. ## FAQ ### Bannir une adresse IP En cas de besoin de bannir temporairement une adresse IP 192.0.2.66 : ~~~ # iptables -I INPUT -s 192.0.2.66 -j DROP ~~~ ### NAT bidirectionnel ~~~ # iptables -t nat -A PREROUTING -i eth0 -d IP_publique -j DNAT --to-destination 192.0.2.1 # iptables -t nat -A POSTROUTING -o eth0 -s 192.0.2.1 -j SNAT --to-source IP_publique ~~~ ### Autoriser toute une interface Lorsqu'un serveur dispose de plusieurs interfaces, dont une pour un réseau local privé, on peut autoriser tout le trafic sur cette interface (ici "eth1") : ~~~ # iptables -A INPUT -i eth1 -j ACCEPT ~~~ ### Autoriser la sortie sur un port Exemple si on a un serveur Munin centralisé, il a besoin de joindre les _munin-node_ : ~~~ # iptables -A INPUT -p tcp --sport 4949 --dport 1024:65535 -m state --state ESTABLISHED,RELATED -j ACCEPT ~~~ ### Redirection du port 80 en sortie vers un proxy local ~~~ # iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT # iptables -t nat -A OUTPUT -p tcp --dport 80 -d 192.0.2.42 -j ACCEPT # iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.1 -j ACCEPT # iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 3128 ~~~ ### FTP Passif ~~~ # iptables -A INPUT -p tcp --dport 60000:61000 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT ~~~ ### Test des ports TCP Pour tester l'ouverture d'un port TCP en sortie, on peut utiliser qui écoute sur tous les ports TCP possibles : ~~~ $ telnet portquiz.net 42 Trying 52.47.209.216... Connected to portquiz.net. Escape character is '^]'. ~~~ ### Tout autoriser en sortie (IPv4) Si l'on veut tout autoriser en sortie (TCP, UDP), voici la règle à ajouter : ~~~ # iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT ~~~