---
categories: linux network firewall minifirewall
title: Howto netfilter
...

* Documentation : <https://netfilter.org/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 <coreteam@netfilter.org>
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 <http://portquiz.net/> 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
~~~

