---
title: "iptables & nftables — Firewall Linux"
domain: network
subdomain: firewall
type: snippet
tags: [iptables, nftables, linux, firewall, nat, masquerade, netfilter]
difficulty: intermediate
status: stable
updated: "2025-05-14"
---
## Concepts — iptables

```
Netfilter = framework kernel Linux pour filtrage de paquets
iptables  = interface userspace vers Netfilter (IPv4)
ip6tables = équivalent IPv6

Tables :
  filter  : filtrage standard (INPUT, OUTPUT, FORWARD)
  nat     : translation d'adresses (PREROUTING, POSTROUTING, OUTPUT)
  mangle  : modification de paquets (TTL, TOS, MARK)
  raw     : bypass connection tracking (PREROUTING, OUTPUT)

Chaînes :
  INPUT      : paquets destinés au routeur/host local
  OUTPUT     : paquets générés par le routeur/host local
  FORWARD    : paquets en transit (routage)
  PREROUTING : avant décision de routage (DNAT)
  POSTROUTING: après décision de routage (SNAT/Masquerade)

Cibles courantes :
  ACCEPT   : laisser passer
  DROP     : jeter silencieusement
  REJECT   : jeter avec message ICMP
  LOG      : journaliser puis continuer
  DNAT     : changer l'adresse destination
  SNAT     : changer l'adresse source
  MASQUERADE : SNAT dynamique (IP d'interface variable — ex: PPPoE)
```

## iptables — Commandes de base

```bash
# Lister les règles avec numéros de ligne
iptables -L -n -v --line-numbers
iptables -L INPUT -n -v --line-numbers
iptables -t nat -L -n -v --line-numbers

# Vider toutes les règles (ATTENTION : coupe toutes les connexions si pas de règle ACCEPT)
iptables -F           # flush toutes les chaînes
iptables -X           # supprimer les chaînes custom
iptables -t nat -F    # flush la table nat

# Ajouter une règle (append = en bas, insert = en haut)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT   # insérer en position 1

# Supprimer une règle par numéro de ligne
iptables -D INPUT 3
```

## iptables — Politique sécurisée (drop all)

```bash
#!/bin/bash
# Script de configuration firewall — exécuter en root

# 1. Vider les règles existantes
iptables -F
iptables -X
iptables -t nat -F
iptables -t mangle -F

# 2. Politique par défaut : DROP tout
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT      # sortie permise par défaut

# 3. Loopback toujours autorisé
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# 4. CRITIQUE : autoriser les connexions établies et related
#    → sans ça, les sessions actives seront coupées après le DROP
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 5. SSH (limité à un réseau admin)
iptables -A INPUT -p tcp --dport 22 -s {{ADMIN_SUBNET}}/{{ADMIN_PREFIX}} -m state --state NEW -j ACCEPT

# 6. HTTP/HTTPS
iptables -A INPUT -p tcp -m multiport --dports 80,443 -m state --state NEW -j ACCEPT

# 7. ICMP (ping — limité en rate)
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT

# 8. Log les paquets droppés (avant la règle DROP finale)
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables-dropped: " --log-level 4

# Vérifier
iptables -L -n -v --line-numbers
```

## iptables — NAT & Masquerade

```bash
# Activer le forwarding IP (kernel)
echo 1 > /proc/sys/net/ipv4/ip_forward
# Persistant : /etc/sysctl.conf
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

# Masquerade (SNAT dynamique — partage de connexion internet)
# Tout le trafic sortant sur l'interface WAN sera NATé
iptables -t nat -A POSTROUTING -o {{WAN_IFACE}} -j MASQUERADE

# Ou SNAT statique (IP fixe sur le WAN — plus performant que MASQUERADE)
iptables -t nat -A POSTROUTING -o {{WAN_IFACE}} -j SNAT --to-source {{WAN_IP}}

# Autoriser le FORWARD pour les clients LAN vers WAN
iptables -A FORWARD -i {{LAN_IFACE}} -o {{WAN_IFACE}} -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i {{WAN_IFACE}} -o {{LAN_IFACE}} -m state --state ESTABLISHED,RELATED -j ACCEPT
```

## iptables — DNAT (Port Forwarding)

```bash
# Rediriger le port 80 WAN vers un serveur interne
iptables -t nat -A PREROUTING -i {{WAN_IFACE}} -p tcp --dport 80 -j DNAT --to-destination {{INTERNAL_IP}}:80

# Port forwarding SSH externe (port 2222) → serveur interne (port 22)
iptables -t nat -A PREROUTING -i {{WAN_IFACE}} -p tcp --dport 2222 -j DNAT --to-destination {{INTERNAL_IP}}:22

# Autoriser le FORWARD vers le serveur interne
iptables -A FORWARD -p tcp -d {{INTERNAL_IP}} --dport 80 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
```

## Persistance iptables

```bash
# Debian/Ubuntu
apt install iptables-persistent

# Sauvegarder les règles actuelles
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6

# Restaurer manuellement
iptables-restore < /etc/iptables/rules.v4

# RHEL/CentOS
service iptables save           # sauvegarde dans /etc/sysconfig/iptables
systemctl enable iptables
```

## nftables — Concepts

```
nftables = successeur de iptables (depuis kernel 3.13, défaut sur Debian 10+)
Syntaxe plus propre, performances supérieures, tables/chaînes flexibles

nft list ruleset          → voir toute la configuration
nft flush ruleset         → vider toute la configuration
```

## nftables — Configuration complète

```bash
# Fichier /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;

        # Loopback
        iif "lo" accept

        # Connexions établies/related
        ct state established,related accept

        # Drop connexions invalides
        ct state invalid drop

        # SSH (réseau admin uniquement)
        ip saddr {{ADMIN_SUBNET}}/{{ADMIN_PREFIX}} tcp dport 22 ct state new accept

        # HTTP/HTTPS
        tcp dport { 80, 443 } ct state new accept

        # ICMP / ICMPv6
        icmp type echo-request limit rate 1/second accept
        icmpv6 type { echo-request, nd-neighbor-solicit, nd-router-advert } accept

        # Log et drop du reste
        limit rate 5/minute log prefix "nft-dropped: " level info
    }

    chain forward {
        type filter hook forward priority 0; policy drop;

        # Permettre forward LAN → WAN
        iif "{{LAN_IFACE}}" oif "{{WAN_IFACE}}" ct state new,established,related accept
        iif "{{WAN_IFACE}}" oif "{{LAN_IFACE}}" ct state established,related accept
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

table ip nat {
    chain postrouting {
        type nat hook postrouting priority 100;

        # Masquerade sortie WAN
        oif "{{WAN_IFACE}}" masquerade
    }

    chain prerouting {
        type nat hook prerouting priority -100;

        # Port forwarding HTTP vers serveur interne
        iif "{{WAN_IFACE}}" tcp dport 80 dnat to {{INTERNAL_IP}}:80
    }
}
```

```bash
# Appliquer
nft -f /etc/nftables.conf

# Activer au démarrage
systemctl enable nftables
systemctl start nftables

# Commandes utiles nft
nft list ruleset
nft list tables
nft list chain inet filter input
nft add rule inet filter input tcp dport 8080 accept    # ajouter une règle
nft delete rule inet filter input handle 5              # supprimer par handle
nft list ruleset | nft -f /dev/stdin                    # recharger
```

## UFW — Abstraction Ubuntu/Debian

```bash
# Activer UFW
ufw enable
ufw status verbose
ufw status numbered

# Règles de base
ufw default deny incoming
ufw default allow outgoing

# Autoriser des services
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow from {{ADMIN_IP}} to any port 22

# Refuser
ufw deny from {{BLOCKED_IP}}
ufw deny 3306/tcp

# Supprimer une règle
ufw delete allow 80/tcp
ufw delete 3             # par numéro (show numbered)

# Logging
ufw logging on
ufw logging high
```

## firewalld — RHEL/CentOS/Rocky

```bash
# État et zones
firewall-cmd --state
firewall-cmd --get-active-zones
firewall-cmd --list-all
firewall-cmd --list-all --zone=public

# Ajouter des services (temporaire — perd au reload)
firewall-cmd --add-service=http
firewall-cmd --add-service=https
firewall-cmd --add-port=8080/tcp

# Permanent (persiste après reload)
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --reload

# Rich rules (règles avancées)
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="{{ADMIN_IP}}/32" port protocol="tcp" port="22" accept'

# NAT/Masquerade
firewall-cmd --permanent --add-masquerade
firewall-cmd --permanent --zone=public --add-masquerade

# Port forwarding
firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toaddr={{INTERNAL_IP}}:toport=80
firewall-cmd --reload
```

<Tip>
Toujours commencer par une règle `ESTABLISHED,RELATED` avant d'appliquer une politique DROP sur INPUT. Sans cette règle, dès que vous passez à `iptables -P INPUT DROP` ou `nftables policy drop`, toutes les sessions SSH actives (et autres connexions établies) seront immédiatement coupées — y compris celle que vous utilisez pour configurer le serveur.
</Tip>
