Erreur de proxy entre Apache et Microsoft IIS


HTTP
Voici un bug Apache assez étrange. Celui-ci intervient lorsque vous avez un frontal Apache et que vous faites du proxy HTTP vers un serveur en backend sous Microsoft IIS. De façon assez aléatoire, les utilisateurs rencontrent régulièrement des erreurs de proxy dans leur navigateur (message "502 Proxy Error" généralement).

Le premier réflexe est donc de passer le log du serveur frontal en mode Debug et de regarder ce qui se passe :

...
[debug] mod_proxy_http.c(56): proxy: HTTP: canonicalising URL //xxx.fr/news.php
[debug] proxy_util.c(1506): [client 192.168.xxx.xxx] proxy: http: found worker http://xxx.fr/
[debug] mod_proxy.c(1020): Running scheme http handler (attempt 0)
[debug] mod_proxy_http.c(1973): proxy: HTTP: serving URL http://xxx.fr/news.php
[debug] proxy_util.c(2011): proxy: HTTP: has acquired connection for (xxx.fr)
[debug] proxy_util.c(2067): proxy: connecting http://xxx.fr/news.php to xxx.fr:80
[debug] proxy_util.c(2193): proxy: connected /news.php to xxx.fr:80
[error] [client 192.168.xxx.xxx] (104)Connection reset by peer: proxy: error reading status line 
from remote server xxx.fr:80
[debug] mod_proxy_http.c(1466): [client 192.168.xxx.xxx] proxy: NOT Closing connection to 
client although reading from backend server xxx.fr:80 failed.
[error] [client 192.168.xxx.xxx] proxy: Error reading from remote server returned by /news.php
[debug] proxy_util.c(2029): proxy: HTTP: has released connection for (xxx.fr)
...

Si on analyse rapidement la transaction, on obtient ceci : un client demande au serveur Apache le contenu de la page news.php. Ce dernier effectue la même demande auprès du serveur Microsoft IIS et se met en attente d'une réponse. Le serveur backend renvoie ensuite une information que mod_proxy ne comprend pas trop (message "proxy: error reading status line from remote server").

Le log étant déjà en mode débug, on ne peut pas en savoir plus de ce côté là. On va donc se lancer dans un tcpdump entre le frontal Apache et le serveur IIS pour tenter de mieux comprendre la situation (ici, xx.xx.xx.xx est l'adresse IP du serveur Microsoft) :

tcpdump -w /tmp/debug.pcap -XX -s0 host xx.xx.xx.xx and port 80

On analyse ensuite le fichier de sortie pcap avec Wireshark (cf. les deux dernières lignes dans la capture) :

Analyse de trafic avec Wireshark

Et on retrouve à peu près la même chose que précédement. Le serveur Apache demande la page news.php avec un GET via le protocole HTTP, le serveur Microsoft IIS répond qu'il faut fermer la connexion TCP (message RST).

Plutôt étrange comme comportement, même si ici, on est en face d'un serveur Microsoft... On fait quelques recherches sur Internet pour y voir plus clair. Un rapport de bug, qui date de 2005, décrit un comportement similaire :

The problem also only occurs for us when we use an IIS backend device, with an apache its ok. From a tcpdump the only diff I can see between the two sessions is that the IIS closes the connection when the keep-alive time out is reached with a TCP RST packet, while the apache does a Fin/Ack handshake. When IIS sends this RST packet the next request to the mod_proxy device that's hits the worker with the RST connection returns the 502 error msg.

Visiblement, il y a bien un malentendu entre Apache et IIS. Les solutions proposées sont de mettre un timeout très long entre les deux serveurs (ex : 24 heures), ou alors de patcher le code d'Apache.

Il existe également une autre méthode, qui est simple à mettre en oeuvre si l'on possède déjà mod_env. Il suffit d'ajouter ces deux lignes au niveau du virtualhost, pour résoudre le problème une fois pour toute :

SetEnv force-proxy-request-1.0 1
SetEnv proxy-nokeepalive 1

Exemple :

<VirtualHost *:80>
    ServerName www.example.fr
    VirtualDocumentRoot /dev/null
    # Correction bug entre Apache et IIS
    SetEnv force-proxy-request-1.0 1
    SetEnv proxy-nokeepalive 1
    # Proxy vers le serveur IIS
    ProxyPass / http://xxx.fr
    ProxyPassReverse / http://xxx.fr/
</VirtualHost>

La commande qui permet de savoir si on possède mod_env :

$ /usr/sbin/httpd -l | grep env.c
mod_env.c

Ces deux lignes permettent de forcer les requêtes à utiliser le protocole HTTP/1.0 avec les connexions non persistantes. Leur utilisation est légèrement détaillée dans la documentation d'Apache à cette adresse.


1 Commentaires pour "Erreur de proxy entre Apache et Microsoft IIS"

Flux des commentaires de cet article Ajouter un commentaire
  •  

    Je ne vois pas pourquoi il faudrait patcher Apache pour ça, sachant que le workaround consiste a forcer le HTTP/1.0 qui ne permet pas le pipelining de connexions et donc peut dégrader les performances côté client.

    Il suffit de lire la doc et les bugtrackers pour trouver le problème et son contournement, appliquer la configuration et râler sur IIS. Devoir s'interfacer avec un serveur HTTP au comportement notoirement étrange c'est assumer aussi qu'il y aie parfois des bugs, comme par exemple interroger Active Directory via LDAP.

    RépondreRépondre
    Kegeruneku , le 13 juillet 2012 à 14:34
 

Ajouter un commentaire

actualité android apache apple astuce astuces bash bilboblog blog boot chrome clavier commande commandes conky date debian Desktop développement elementary exploit faille fedora firefox flash gimp gnome google graphique Graphisme hack hacking Hardware humour intel internet iphone jailbreak Jeux Kde kernel libre Linux log logiciels Logiciels Libres lucid lynx maemo mail maquette metasploit microsoft mobile mockup monitoring mozilla multi-touch musique mysql n900 nautilus nokia noyau openoffice open source password photos php Planet publicité redhat red hat rpm réseau screenshot script serveur serveurs shell sql ssh statistiques sysadmin system Sécurité thème tux-planet tv twitter ubuntu unity vidéo vidéos vlc voyage wallpaper windows wordpress yum