Maintenant, une question se pose naturellement, si l'on peut réaliser toutes ces astucieuses manœuvres pour rediriger les connexions HTTP vers des ports locaux, ne pourrait-on pas faire la même chose mais vers une machine distante (par exemple, dans le cas où la machine qui exécute Squid n'est pas la même que celle qui fait tourner iptables). La réponse est oui, mais cela demandes des mots magiques un peu différents. Si vous souhaitez uniquement une redirection vers la machine locale, ce qui est la cas habituel, vous pouvez ignorer ce chapitre.
Pour les besoins de l'exemple, supposons que nous ayons deux machines nommées machine-squid et machine-iptables, et qu'elles soient sur le réseau réseau-local. Dans les commandes ci-dessous, remplacez ces chaînes par les adresses ou les noms réels de vos réseau et machines.
Je présenterai ici deux approches différentes.
Sur laquelle tournera Squid, machine-squid, vous n'avez ni besoin d'iptables, ni d'indiquer au noyau une option spécifique. La seule chose nécessaire est Squid. Vous aurez en revanche besoin[1] d'indiquer à Squid l'option http_accel telle qu'elle est décrite ci-dessus.
Sur la machine sur laquelle tournera iptables, machine-iptables, vous devrez configurer le noyau comme décrit dans Section 3 ci-dessus, à une exception près : vous n'avez pas besoin de l'option « REDIRECT target support ». Pour ce qui est des commandes iptables, vous aurez besoin de trois d'entre elles :
iptables -t nat -A PREROUTING -i eth0 -s !machine-squid \ -p tcp --dport 80 -j DNAT --to machine-squid:3128 iptables -t nat -A POSTROUTING -o eth0 -s réseau-local \ -d machine-squid -j SNAT --to machine-iptables iptables -A FORWARD -i eth0 -o eth0 -s réseau-local \ -d machine-squid -p tcp --dport 3128 -j ACCEPT |
La première envoie les paquets de machine-iptables vers machine-squid. La seconde s'assure que la réponse soit renvoyée via machine-iptables, plutôt que directement au client (c'est très important !). La dernière s'assure que machine-iptables redirigera les paquets appropriés vers machine-squid. Il est possible qu'elle ne soit pas nécessaire. À vous de voir. Remarquez que nous avons spécifié -i eth0 puis -o eth0, ce qui veut dire que nous utilisons eth0 comme interface d'entrée (-i) et de sortie (-o). Si vos paquets entrent et sortent par des interfaces différentes, vous devrez ajuster ces commandes en conséquence.
Ajoutez ces commandes aux scripts de démarrage appropriés sous /etc/rc.d/
(Merci à Giles Coochey d'avoir aidé à l'écriture de cette section).
Notre première tentative marche bien, mais a un petit inconvénient : elle ne permet pas de gérer correctement les connexions HTTP/1.0 sans en-tête Host. Les connexions partiellement ou complètement compatibles HTTP/1.1, elles, marchent bien. En général, cela ne pose pas de problème, car la majorité des navigateurs modernes envoient l'en-tête Host. Cela pose problème dans le cas de certains petits programmes ou appareils embarqués, car ceux-ci n'émettent que des requêtes HTTP/1.0 très simples. Pour être capable de gérer correctement ce cas de figure, il faut en faire un peu plus.
Sur machine-iptables, il est nécessaire d'activer les options suivantes du noyau :
IP: advanced router IP: policy routing IP: use netfilter MARK value as routing key IP: Netfilter Configuration -> Packet mangling IP: Netfilter Configuration -> MARK target support |
Vous aurez également besoin des utilitaires iproute2. Votre distribution les a probablement déjà installés mais, dans le cas contraire, jetez un coup d'œil à ftp://ftp.inr.ac.ru/ip-routing/
La configuration de la machine nécessitera les commandes suivantes :
iptables -t mangle -A PREROUTING -j ACCEPT -p tcp --dport 80 -s machine-squid iptables -t mangle -A PREROUTING -j MARK --set-mark 3 -p tcp --dport 80 ip rule add fwmark 3 table 2 ip route add default via squid-box dev eth1 table 2 |
Notez que les numéros choisis pour la marque de pare-feu (3) et pour la table de routage (2) sont complètement arbitraires. Si vous utilisez déjà un routage dirigé (policy routing) ou un marquage de pare-feu pour d'autres besoins, assurez-vous que vous choisissez ici des numéros non utilisés.
Passons à machine-squid. Utilisez la commande suivante, qui devrait vous sembler remarquablement similaire à une commande vue précédemment.
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3128 |
Comme précédemment, ajoutez toutes ces commandes aux scripts de démarrage appropriés.
Voici une explication succincte de la façon dont cette seconde méthode fonctionne : dans la première méthode, nous avons utilisé la traduction d'adresse pour diriger les paquets vers l'autre machine. Ce qui implique une modification des paquets. Cette altération est la cause des défaillances mentionnés plus haut pour certains types de clients. Dans la méthode deux, nous utilisons un truc magique appelé routage dirigé (policy routing). Il faut tout d'abord sélectionner les paquets que l'on veut. Pour ce faire, nous marquons (via la cible MARK) tous les paquets destinés au port 80, excepté ceux provenant de machine-squid elle-même. Habituellement, lorsque le noyau doit décider du routage des paquets, il utilise la table de routage consultable via la commande route. Pour le routage des paquets marqués, il utilisera une table spéciale ne comportant qu'une seule entrée, une passerelle par défaut pointant vers machine-squid. Les paquets visés seront donc joyeusement envoyés vers leur destin, sans subir aucune modification. Ce qui permettra de gérer correctement toutes les connexions, y compris les connexions HTTP/1.0. (Merci à Michal Svoboda d'avoir suggéré cette section et aidé à sa rédaction).
Si machine-iptables a une adresse IP dynamique (par exemple dans le cas d'une connexion ppp téléphonique ou d'une adresse assignée par DHCP sur un modem-câble), vous devrez alors apporter une légère modification aux commandes ci-dessus. Remplacez la seconde commande par celle-ci :
iptable -t nat -A POSTROUTING -o eth0 -s réseau-local \ -d machine-squid -j MASQUERADE |
Cette modification évite d'avoir à spécifier l'adresse IP de machine-iptables dans la commande. Dans la mesure où celle-ci change souvent, vous devriez modifier la commande à chaque fois. Cette modification vous épargnera donc beaucoup de travail.
[1] Les versions précédentes de ce petit guide suggéraient que tel n'était pas le cas. C'était une erreur. Désolé d'avoir créé cette confusion.