Proxy Squid : Améliorez les performances de votre réseau

En dépit de nombreux progrès techniques, l'infrastructure Internet absorbe difficilement un trafic de plus en plus dense. Les proxies cache offrent une alternative séduisante à l'augmentation du débit des liaisons. Nous vous présentons Squid, une solution Open Source de qualité.

Principe

Protocole http

Détaillons les mécanismes mis en jeu lors d'une navigation sur la toile. Le protocole HTTP fixe des conventions d'échange d'objets entre serveurs et clients. Ces objets possèdent un type. Nous retrouvons les pages HTML et leurs éléments : images GIF, TIF, JPG... Une URL (Universal Ressource Locator) identifie le nom et l'emplacement d'une ressource ainsi que le protocole à respecter pour la consulter. Une URL s'écrit :

<proto>://<objet>

Squid gère les protocoles suivants (plus une ou deux antiquités) :

HTTP      Hyper Text Transfer Protocol
FTP       File Transfer Protocol
SSL       Secure Socket Layer
WAIS      Wide Area Information Service

Squid ne gère pas les protocoles en mode non connecté, très répandus dans le domaine du multimédia (flux audio et vidéo). Dans le cas du protocole HTTP, une URL s'écrit :

http://<serveur>{:<port>}/<objet>

Ainsi, pour récupérer le contenu d'une page HTML, un client appliquera l'algorithme suivant :

Recherche de l'adresse IP de <serveur>
Connexion TCP sur le port 80 ou <port> si indiqué
Requêté de <objet>
Itérer sur les éléments décrits dans <objet>

Prenons l'exemple de la page d'accueil du site officiel Squid. Son URL est http://www.squid-cache.org. Une simple session telnet donne accès au code HTML de cette page. Voici la requête :

telnet www.squid-cache.org 80
GET /index.html HTTP/1.0
Accept: text/html
<CRLF>

Et la réponse du serveur :

HTTP/1.0 200 OK
Date: Thu, 13 Jul 2000 22:12:15 GMT
Server: Apache/1.3.3 (Unix)
Expires: Fri, 14 Jul 2000 22:12:15 GMT
Last-Modified: Wed, 05 Jul 2000 03:47:58 GMT
Content-Length: 4128
Content-Type: text/html
<CRLF>
<HTML>
<HEAD><TITLE>Squid Web Proxy Cache</TITLE></HEAD>
...

Performances

L'efficacité est moyenne. Chaque serveur est soumis à de multiples requêtes d'objets de petite taille. Dans le pire des cas, deux requêtes portant sur un même objet aboutissent à deux transferts de données. Une situation pénalisante si vous disposez d'une liaison à faible débit.

Caches locaux

Les navigateurs maintiennent une copie des objets récemment consultés dans un cache propriétaire. Cette solution n'est pas optimale. Un cache générique conçu sur un modèle client / serveur doit permettre le partage des données collectées indépendamment des applications ou des utilisateurs.

Proxies

Un proxy cache relaie les requêtes des clients. Les objets sont cachés au passage, ce qui limite le trafic.

L'exemple

Voici les caractéristiques d'Altair, le petit réseau privé de classe C ayant servi aux tests. Altair est composé de PC sous Linux équipés de cartes Ethernet à 10 Mb/s. Nous lui affectons la plage d'adresses 192.168.0.*. La passerelle se nomme Vortex. Elle possède l'adresse 192.168.0.1 et dispose d'un lien point à point intermittent vers l'Internet partagé grâce à une technique de translation d'adresses. Elle héberge également notre proxy. Nous avons opté pour une distribution Caldera Open Linux 2.3.

Compilation

Récupérez l'archive de la dernière version stable de Squid (notée x). Décompressez-la : tar -xvzf squid-x.tar.gz. Déplacez-vous dans le répertoire des sources : cd squid-x. Compilez Squid :

./configure --enable-err-language=French
make all

Installation

Procédez à l'installation :

make install

L'arborescence par défaut est la suivante :

/---usr---local---squid-+-bin
                             |-cache
                             |-etc
                             |-logs

Configuration

Les fichiers de configuration sont rassemblés dans le répertoire /usr/local/squid/etc. Les options par défaut assurent généralement un fonctionnement correct.

Utilisateur et groupe effectifs

Les sockets liés à des ports de numéros inférieurs à 1024 doivent être initialisés par des processus de propriétaire root. Pour des raisons de sécurité, Squid modifie ensuite utilisateur et groupe effectifs. Ajoutez les entrées suivantes au fichier squid.conf :

cache_effective_user squid
cache_effective_group squid

Créez un utilisateur et un groupe squid :

groupadd -g 999 squid
useradd -g squid -d /usr/local/squid squid

Port

Par défaut, Squid écoute les requêtes HTTP sur le port 3128. De nombreux FAI placent leurs proxies en écoute sur le port 8080, plus facile à mémoriser. Ajoutez éventuellement une entrée :

http_port 8080

Répertoire du cache

Les documents cachés seront stockés dans une arborescence de racine cache_dir

cache_dir ufs /usr/local/squid/cache 1024 16 256

La première constante indique la taille maximale du cache en Mo. Nous allouons 1 Go, un espace suffisant pour cacher de l'ordre de 100000 objets. Ces derniers seront stockés dans 4096 répertoires répartis sur deux niveaux. Une fonction de hachage garantit une répartition équitable des objets. Créez la racine de l'arborescence.

mkdir -m 700 /usr/local/squid/cache
chown squid /usr/local/squid/cache
chgrp squid /usr/local/squid/cache

Créez finalement l'arborescence :

/usr/local/squid/bin/squid -z

Les répertoires sont nommés de 00 à 0F et de 00 à FF.

Adresse de l'administrateur Squid

L'option cache_mgr précise l'adresse électronique de l'administrateur Squid. Cette personne recevra une notification en cas d'arrêt du démon. L'adresse figurera également sur les pages d'erreurs retournées aux clients.

cache_mgr squidadmin@altair.net

Adresse pour le ftp anonyme

Nous communiquerons également une adresse valide lors du téléchargement FTP sous compte anonymous.

ftp_user squidadmin@altair.net

Audit

Squid rend compte de son état dans divers fichiers placés sous /usr/local/squid/logs. Rectifiez les droits de ce répertoire.

chmod 700 /usr/local/squid/logs
chown squid /usr/local/squid/logs
chgrp squid /usr/local/squid/logs

L'option -k de Squid combinée au mot clé rotate force l'archivage des fichiers. Squid doit être actif au moment de l'appel :

/usr/local/squid/bin/squid -k rotate

L'option logfile_rotate définit le nombre maximum de versions archivées. Pour une sauvegarde sur un mois, à raison d'une rotation par jour :

logfile_rotate 30

Le plus simple est d'automatiser la rotation grâce au démon Cron. Voici un exemple de fichier /etc/crontab correspondant à une invocation de la commande de rotation tous les jours à deux heures du matin :

SHELL=/bin/sh
MAILTO=root
0 2 * * *   squid   /usr/local/squid/bin/squid -k rotate

Tests

Tout est prêt pour un premier test :

/usr/local/squid/bin/squid -N -D -d 2

Le démon s'exécute normalement en tâche de fond. L'option -N interdit le passage en arrière-plan. Les sorties seront visibles de la console. L'option -D évite un test du service DNS. L'option -d fixe le niveau de détail des comptes-rendus. Voici la sortie obtenue :

2000/10/18 05:14:25| Starting Squid Cache...
2000/10/18 05:14:25| Swap maxSize 1048576 KB, estimated 7876 objects
2000/10/18 05:14:25| Target number of buckets: 157
2000/10/18 05:14:25| Using 8192 Store buckets
2000/10/18 05:14:25| Max Mem  size: 8192 KB
2000/10/18 05:14:25| Max Swap size: 102400 KB
2000/10/18 05:14:25| Rebuilding storage in Cache Dir #0 (DIRTY)
2000/10/18 05:14:25| Set Current Directory to /var/spool/squid
2000/10/18 05:14:25| Loaded Icons.
2000/10/18 05:14:27| Accepting HTTP connections on port 3128, FD 35.
2000/10/18 05:14:27| Accepting ICP messages on port 3130, FD 36.
2000/10/18 05:14:27| Accepting SNMP messages on port 3401, FD 37.
2000/10/18 05:14:27| Ready to serve requests.
2000/10/18 05:14:28| storeRebuildFromDirectory: DIR #0 done!
2000/10/18 05:14:28| Finished rebuilding storage from disk.
2000/10/18 05:14:28|         0 Entries read from previous logfile.
2000/10/18 05:14:28|         0 Entries scanned from swap files.
2000/10/18 05:14:28|         0 Invalid entries.
2000/10/18 05:14:28|         0 With invalid flags.
2000/10/18 05:14:28|         0 Objects loaded.
2000/10/18 05:14:28|         0 Objects expired.
2000/10/18 05:14:28|         0 Objects cancelled.
2000/10/18 05:14:28|         0 Duplicate URLs purged.
2000/10/18 05:14:28|         0 Swapfile clashes avoided.
2000/10/18 05:14:28|   Took 36 seconds (   0.0 objects/sec).
2000/10/18 05:14:28| Beginning Validation Procedure
2000/10/18 05:14:29| storeLateRelease: released 0 objects
2000/10/18 05:14:28|   Completed Validation Procedure
2000/10/18 05:14:28|   Validated 0 Entries
2000/10/18 05:14:28|   store_swap_size = 21k

Le démon est actif. Squid est fourni avec un client en mode texte. Connectez-vous à Internet et lancez depuis la passerelle :

/usr/local/squid/bin/client http://www.squid-cache.org

Testez ensuite une requête identique depuis une machine quelconque du réseau :

/usr/local/squid/bin/client -h 192.168.0.1 http://www.squid-cache.org

Ajoutez éventuellement l'option -p 8080.

Configuration détaillée

A partir d'ici les choses se compliquent légèrement ;-)

Taille maximale des objets en cache

Squid ne stocke les objets sur disque que si leur taille entre dans un intervalle fixé par l'administrateur :

minimum_object_size 0 KB
maximum_object_size 1024 KB

Délais

Squid se connecte aux serveurs selon l'algorithme présenté dans la section précédente. Il est nécessaire d'établir des délais au delà desquels Squid considérera qu'une transaction a échoué. Ceci vaut pour l'établissement des connexions, l'envoi des requêtes et la réception des résultats.

connect_timeout 30 seconds
request_timeout 30 seconds
read_timeout 2 minutes

Complétez éventuellement les requêtes interrompues par les utilisateurs. Fixez les seuils en fonction du débit de votre réseau :

quick_abort_min 10 KB
quick_abort_max 10 KB
quick_abort_pct 90

Résolution DNS

Des processus spécifiques assurent la traduction noms de serveurs <-> adresse IP. Leur nombre est à choisir en fonction de la charge en pointe de votre réseau :

dns_children 10

Ces processus ne traitent pas directement les délais d'expiration (TTL) fournis par les serveurs de noms. Les correspondances sont stockées dans deux caches. Des constantes précisent quand ces données deviennent obsolètes :

positive_dns_ttl 24 hours
negative_dns_ttl 5 minutes

Sécurité

Il est recommandé de limiter l'accès du proxy aux machines de votre réseau. A cet effet, Squid propose les ACL (Access Classes Lists) et les ACO (Access Classes Operators). Une liste regroupe un ensemble de propriétés des requêtes :

acl manager proto cache_object
acl src_localhost src 127.0.0.1/255.255.255.255
acl src_reseau_altair src 192.168.0.0/255.255.255.0
acl all src 0.0.0.0/0.0.0.0

Nous décrivons ici les machines du réseau Altair et le gestionnaire du cache. Lors du test d'une règle A/M, on opère un ET logique entre l'adresse candidate C et le masque M puis on compare le résultat et A. Le résultat est positif si A = C . M. Reste à définir les droits d'accès à appliquer aux listes précédentes :

http_acces allow manager localhost
http_acces deny manager
http_acces allow src_localhost
http_acces allow src_reseau_altair
icp_access deny all

Attention : Les éléments d'une liste sont combinés avec des OU logiques, les prémisses d'une règle avec des ET logiques. Les règles sont lues en séquence. L'accès est autorisé par défaut. Une règle *au plus* est appliquée pour chaque type de contrôle (http_access, ftp_access ...). Si aucune règle ne s'applique à un candidat, l'action *opposée* à celle de la *dernière* règle lue s'impose. Par exemple :

A allow X    A deny Y    A deny X    A allow Y
Z -> allow    Z -> deny

En étudiant le fichier de configuration, vous constaterez la présence des règles supplémentaires :

acl SSL_ports port 443 563
acl Safe_ports port 21 70 80 210 280 443 488 563 591 777 1025-65535
acl CONNECT method CONNECT
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports

Ces règles évitent qu'un utilisateur mal intentionné n'exploite votre proxy à la manière d'un tunnel pour requérir des services interdits. Limitez la taille des requêtes pour restreindre les risques d'attaques de type "refus de service".

request_header_max_size 10 KB
request_body_max_size 64 KB

Anonymat

Préservez l'anonymat des utilisateurs en masquant une partie des adresses source des requêtes :

client_netmask 255.255.255.0

Ici, nous masquons la section machine des adresses IP de notre réseau de classe C. De plus, vous pouvez filtrer certains champs des en-têtes de requêtes générés par les clients :

anomyze_headers deny Referer Server From User-Agent

Ici, nous masquons l'adresse électronique et la description du client. Nous masquons également la ressource URL à partir de laquelle l'utilisateur a sélectionné la ressource interrogée. Certains serveurs réclamant l'identification du programme client, nous ajoutons l'option :

fake_user_agent Nutscrape/1.0 (CP/M; 8-bit)

L'option strip_query_terms activée par défaut évite que les paramètres des requêtes adressées par exemple à un moteur de recherche ne soient archivés.

Filtrage

Un filtrage judicieux garantit une bonne répartition du trafic, ce en accord avec la politique d'administration de votre serveur. Les ACO permettent un filtrage sur la base d'expressions rationnelles appliquées aux URL. Par exemple, pour interdire le chargement de fichiers MP3 :

acl url_mp3 url_regex -i \.mp3$
http_access deny url_mp3

Pour limiter la taille des objets importés à 1 Mo :

reply_body_max_size 1024 KB

Plus radicalement, vous pouvez filtrer un protocole ou un domaine entier :

acl proto_ftp proto ftp
acl dom_tucows dstdom_regex -i tucows
http_access deny proto_ftp
http_access deny dom_tucows

Hiérarchie des fichiers

Plusieurs caches peuvent collaborer. Ainsi, Renater, organisme fédérant les réseaux des universités dispose d'un cache national hébergé sur le campus de Jussieu et de caches régionaux. Cette hiérarchie augmente le nombre de documents cachés. Squid intègre des mécanismes autorisant une telle collaboration. Le protocole ICP (Inter-Cache Protocol) permet d'interroger un cache sur la présence d'un objet particulier (HIT / MISS). Ces requêtes se font généralement sur le port 3130. Les résumés de caches (cache digests) permettent l'échange d'index entiers. Deux caches voisins (sibling caches) n'échangent que les objets qu'ils possèdent. Un cache père (parent cache) accepte de récupérer un objet qu'il ne possède pas pour un de ses caches fils. Nous allons envisager deux cas d'école.

Raccordement au cache d'un FAI

Dans ce cas, toute requête aboutissant à un échec au niveau du cache local est adressée à un cache père.

cache_peer proxy.fai.fr parent 8080 0 default no-query
prefer_direct off

Nous correspondons avec un proxy.fai.fr sur le port 8080 (default). Nous n'utilisons pas ICP (no-query) et souhaitons contacter prioritairement le proxy père (prefer_direct off). Pour obtenir "proxy.fai.fr" vous pouvez faire un nslookup fai.fr puis ensuite utiliser la commande dig @ip_du_ns_du_fai fai.fr AXFR | less. Restera plus qu'a choisir un proxy ou cache proche de chez vous.

Collaboration des deux caches

Si votre réseau est de taille importante, vous pouvez répartir la charge entre plusieurs proxies. Cette technique nécessite la configuration d'un serveur de noms. Supposons que notre second cache soit hébergé par la machine Krell d'adresse 192.168.0.2. Nous ajoutons deux enregistrements à la zone altair.net.

proxy A 192.168.0.1
proxy A 192.168.0.2

Les navigateurs pointent vers proxy.altair.net. Lors d'une résolution de noms, la librairie Resolver retournera alternativement l'une des deux adresses. Nous installons Squid sur Krell et créons les entrées :

cache_peer vortex.altair.net sibling 3128 3130 proxy-only
acl src_vortex src 192.168.0.1/255.255.255.255
icp_access allow src_vortex

Et sur Vortex :

cache_peer krell.altair.net sibling 3128 3130 proxy-only
acl src_krell src 192.168.0.2/255.255.255.255
icp_access allow src_krell

L'option proxy-only bloque le stockage en cache local d'un résultat récupéré depuis un cache frère. Nous augmentons ainsi le nombre total d'objets stockés.

Serveur http local

Supposons que notre réseau dispose d'un serveur Web hébergé localement. Il serait inefficace de relayer des requêtes HTTP ou CGI destinées à ce serveur vers un proxy extérieur.

acl dst_localhost dst 127.0.0.1/255.255.255.255
acl dst_reseau_altair dst 192.168.0.0/255.255.255.0
always_direct allow dst_localhost
always_direct allow dst_reseau_altair
hierarchy_stoplist cgi-bin ?

De plus nous ne souhaitons pas cacher ces documents :

acl cgi urlpath_regex cgi-bin \?
no_cache deny cgi
no_cache deny dst_localhost
no_cache deny dst_reseau_altair

Matériel

Se pose la question des caractéristiques de la machine hébergeant le cache :

- Puissance processeur
- Capacité, temps d'accès et débit disque

Supposons par exemple que vous disposiez d'une liaison ISDN à 64 kb/s. Cette ligne est utilisée une dizaine d'heures par jour, soit un transfert théorique d'environ 200 Mo/j. Un disque de 1 Go stockera les données sur 5 jours. Ceci est une estimation au pire, le cache ayant pour fonction de limiter le recours à la liaison Internet. Un objet pèse en moyenne 10 ko. Le cache stockera donc environ 100 000 objets. Chaque objet occupe 75 octets de RAM dans l'index de Squid, soit 6 Mo. Multiplions cette valeur par 3 pour tenir compte des caches dédiés aux objets en transit et aux correspondances nom <-> adresse IP de serveurs. Un total de 16 Mo devrait éviter le recours au swap.

cache_mem 16 MB

Estimons à 10 requêtes par seconde la charge de Squid en pic. Un Pentium à 133 MHz devrait suffire à satisfaire cette demande. Concernant le disque, le débit est moins primordial que le temps d'accès. Avec un temps d'accès de 12 ms, vous pouvez servir de l'ordre de 100 requêtes par seconde.

Statistiques

Un script CGI nommé cachemgr.cgi retourne des statistiques sur l'activité de Squid. Vous pouvez l'activer en installant un serveur Web de type Apache. Typiquement, le script sera copié ici :

cp /usr/local/squid/bin/cachemgr.cgi /home/httpd/cgi-bin

Et accessible à l'adresse http://localhost/cgi-bin/cachemgr.cgi. Définissez un mot de passe pour en protéger l'accès :

cachemgr_passwd ****** all

Lancement automatique

Une simple ligne dans le fichier /etc/rc.d/rc.local suffit.

/usr/local/squid/bin/squid -D

Squid crée deux processus. Le processus fils gère le cache. Le processus père surveille l'activité du processus fils et le relance si nécessaire.

pstree
init-+-booter
      .
      .
       -squid---squid---unlinkd

L'interruption du démon pour maintenance se fera proprement par un appel /usr/local/squid/bin/squid -k shutdown

Configuration des navigateurs

La configuration des navigateurs est triviale.

Netscape navigator & Communicator

Ouvrez le menu "Edit / Preferences", Développez le menu "Advanced". Sélectionnez l'entrée "Proxies". Activez le bouton radio "Manual proxy configuration" puis "View". Renseignez les champs "FTP Proxy" et "HTTP Proxy". Le nom est du type proxy.mon.fail. A défaut, indiquez son adresse IP. Le numéro de port est probablement le 8080. Sélectionnez l'entrée Cache. Passez la capacité "Disk Cache" à 0. Cliquez le bouton "Clear Disk Cache".

Lynx

Sous Bourne Again Shell, exportez les variables

export ftp_proxy="http://proxy.mon.fai:8080/"
export http_proxy="http://proxy.mon.fai:8080/"

Conclusion

Squid est un logiciel proposant des fonctionnalités nombreuses et configurables dans leurs moindres détails. Consultez la documentation en ligne pour une étude approfondie. Vous apprendrez à moduler la charge supportée par vos proxies, fixer des priorités par type de trafic, modifier l'algorithme de stockage des objets en cache, etc.

Questions, commentaires cyril.nocton@bigfoot.com
Linux Magazine France n° 20 - Septembre 00