C’est exact, et tu mets le doigt sur un point important : nous raisonnons plus volontiers en termes de connexions, alors que les règles iptables s’appliquent à des paquets. La difficulté consiste souvent à faire le lien entre les connexions et les paquets. C’est pourquoi les gestionnaires de pare-feu, surcouches à iptables, permettent de manipuler des abstractions que sont les connexions en cachant le traitement des paquets individuels.
Exact encore, la symétrie que tu évoques existe bien entre les paquets émis et reçus d’une même connexion. Mais tes paires de règles INPUT et OUTPUT n’étaient pas symétriques puisque les deux se basaient sur la condition --dport donc le port destination. La symétrie aurait voulu qu’une se base sur --dport et l’autre sur --sport.
Un paquet TCP a deux ports, source et destination. En effet une connexion TCP met en oeuvre deux ports : un côté client et un côté serveur. Généralement, le port côté serveur est fixe (80 pour HTTP, 25 pour SMTP…) et le port côté client est variable (c’est pourquoi généralement les règles iptables ne s’en occupent pas). Les paquets émis par le client (reçus par le serveur) ont pour port source le port client et pour port destination le port serveur. Symétriquement, les paquets émis par le serveur (reçus par le client) ont pour port source le port serveur et pour port destination le port client. Le même raisonnement s’applique aux adresses source et destination.
Pour autoriser une connexion HTTPS, il faut accepter les paquets dans la direction initiale (INPUT ou OUTPUT selon que la connexion est entrante ou sortante) qui ont le port destination (–dport) 443. Cela est généralement bien compris. Il faut aussi accepter les paquets de réponse dans la direction opposée, qui ont le port source (–sport) 443. Mais rien ne garantit qu’un paquet ayant le port source 443 est une réponse légitime à un paquet ayant le port destination 443. C’est pourquoi on utilise l’état de suivi de connexion (-m conntrack ou -m state) ESTABLISHED qui vérifie cela automatiquement en surveillant tous les paquets émis et reçus. Au lieu de créer une règle symétrique distincte pour les paquets retour de chaque type de connexion, il est plus simple de créer une seule règle globale dans chaque direction qui accepte tous les paquets dans l’état ESTABLISHED. On en profite pour accepter aussi les paquets dans l’état RELATED, ce qui est souhaitable (à quelques exceptions près mais je ne souhaite pas entrer dans des détails compliqués).
En procédant ainsi, on se retrouve avec des règles génériques autorisant les paquets des connexions existantes dans chaque direction, et on n’a plus qu’à ajouter des règles spécifiques autorisant le premier paquet de chaque type de connexion voulu. Au final, c’est un peu comme si on n’avait à s’occuper que des connexions et pas des paquets individuels. Je suppose que c’est la simplification que tu évoquais.
Mais il reste encore une tâche non négligeable : déterminer de quelles connexions on a besoin dans chaque direction. Si on pense facilement aux protocoles applicatifs comme HTTP, on oublie plus souvent les protocoles “utilitaires” comme DNS. Dans l’absolu HTTP n’a pas besoin de DNS, mais on en besoin si les noms des sites sont résolus par DNS ; on n’en a pas besoin si on accède uniquement à des sites par adresse IP ou si tous les noms sont connus en local dans /etc/hosts.