* released 1.1.9 : SECURITY FIX

* don't use snprintf()'s return value as an end of message since it may
  be larger. This caused bus errors and segfaults in internal libc's
  getenv() during localtime() in send_log().
* removed dead insecure send_syslog() function and all references to it.
* fixed warnings on Solaris due to buggy implementation of isXXXX().
This commit is contained in:
willy tarreau 2005-12-17 13:10:27 +01:00
parent a159808bf2
commit c29948c439
3 changed files with 425 additions and 343 deletions

View File

@ -45,5 +45,5 @@ haproxy: haproxy.o
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -c -o $@ $<
clean: clean:
rm -vf *.[oas] *~ core haproxy test nohup.out gmon.out rm -f *.[oas] *~ core haproxy test nohup.out gmon.out

View File

@ -1,9 +1,9 @@
H A - P r o x y H A - P r o x y
--------------- ---------------
version 1.1.8 version 1.1.9
willy tarreau willy tarreau
2002/04/16 2002/05/02
================ ================
| Introduction | | Introduction |
@ -11,8 +11,8 @@
HA-Proxy est un relais TCP/HTTP offrant des facilités d'intégration en HA-Proxy est un relais TCP/HTTP offrant des facilités d'intégration en
environnement hautement disponible. En effet, il est capable de : environnement hautement disponible. En effet, il est capable de :
- assurer un aiguillage statique défini par des cookies ; - effectuer un aiguillage statique défini par des cookies ;
- assurer une répartition de charge avec création de cookies pour assurer la - effectuer une répartition de charge avec création de cookies pour assurer la
persistence de session ; persistence de session ;
- fournir une visibilité externe de son état de santé ; - fournir une visibilité externe de son état de santé ;
- s'arrêter en douceur sans perte brutale de service. - s'arrêter en douceur sans perte brutale de service.
@ -43,20 +43,28 @@ pour les proxies pour lesquels ce param
configuration. Il s'agit du paramètre 'maxconn' dans les sections 'listen'. configuration. Il s'agit du paramètre 'maxconn' dans les sections 'listen'.
Le nombre maximal total de connexions simultanées limite le nombre de connexions Le nombre maximal total de connexions simultanées limite le nombre de connexions
TCP utilisables à un instant par le processus, tous proxies confondus. Ce TCP utilisables à un instant donné par le processus, tous proxies confondus. Ce
paramètre remplace le paramètre 'maxconn' de la section 'global'. paramètre remplace le paramètre 'maxconn' de la section 'global'.
Le mode debug correspond à l'option 'debug' de la section 'global'. Dans ce
mode, toutes les connexions, déconnexions, et tous les échanges d'entêtes HTTP
sont affichés.
Les statistiques ne sont disponibles que si le programme a été compilé avec
l'option "STATTIME". Il s'agit principalement de données brutes n'ayant
d'utilité que lors de benchmarks par exemple.
============================ ============================
| Fichier de configuration | | Fichier de configuration |
============================ ============================
Commentaires Structure
============ =========
L'analyseur du fichier de configuration ignore des lignes vides, les espaces, L'analyseur du fichier de configuration ignore des lignes vides, les espaces,
les tabulations, et tout ce qui est compris entre le symbole '#' (s'il n'est pas les tabulations, et tout ce qui est compris entre le symbole '#' (s'il n'est pas
précédé d'un '\'), et la fin de la ligne. précédé d'un '\'), et la fin de la ligne, ce qui constitue un commentaire.
Le fichier de configuration est découpé en sections répérées par des mots clés Le fichier de configuration est découpé en sections répérées par des mots clés
tels que : tels que :
@ -68,8 +76,8 @@ Tous les param
reconnu. reconnu.
1) Paramètres généraux 1) Paramètres globaux
====================== =====================
Il s'agit des paramètres agissant sur le processus, ou bien sur l'ensemble des Il s'agit des paramètres agissant sur le processus, ou bien sur l'ensemble des
proxies. Ils sont tous spécifiés dans la section 'global'. Les paramètres proxies. Ils sont tous spécifiés dans la section 'global'. Les paramètres
@ -96,7 +104,7 @@ syslog vers un ou deux serveurs. La syntaxe est la suivante :
Les connexions sont envoyées en niveau "info". Les démarrages de service et de Les connexions sont envoyées en niveau "info". Les démarrages de service et de
serveurs seront envoyés en "notice", les signaux d'arrêts en "warning" et les serveurs seront envoyés en "notice", les signaux d'arrêts en "warning" et les
arrêts définitifs de services et de serveurs en "alert". Ceci est valable aussi arrêts définitifs de services et de serveurs en "alert". Ceci est valable aussi
bien pour les proxies que pour les serveurs testés au sein des proxies. bien pour les proxies que pour les serveurs testés par les proxies.
Les catégories possibles sont : Les catégories possibles sont :
kern, user, mail, daemon, auth, syslog, lpr, news, kern, user, mail, daemon, auth, syslog, lpr, news,
@ -121,56 +129,142 @@ de sockets n
- 1 socket par connexion sortante - 1 socket par connexion sortante
- 1 socket par proxy - 1 socket par proxy
- 1 socket pour chaque serveur en cours de health-check - 1 socket pour chaque serveur en cours de health-check
- 1 socket pour les logs - 1 socket pour les logs (tous serveurs confondus)
Positionner la limite du nombre de descripteurs de fichiers (ulimit -n) à Positionner la limite du nombre de descripteurs de fichiers (ulimit -n) à
2 * maxconn + nbproxy + nbserveurs + 1. 2 * maxconn + nbproxy + nbserveurs + 1. Dans une future version, haproxy sera
capable de positionner lui-même cette limite.
1.3) Changement d'uid et de gid 1.3) Diminution des privilèges
------------------------------- ------------------------------
Afin de réduire les risques d'attaques dans le cas où une faille non identifiée
serait exploitée, il est possible de diminuer les privilèges du processus, et
de le cloisonner.
Dans la section 'global', le paramètre 'uid' permet de spécifier un identifiant
numérique d'utilisateur. La valeur 0, correspondant normalement au super-
utilisateur, possède ici une signification particulière car elle indique que
l'on ne souhaite pas changer cet identifiant et conserver la valeur courante.
C'est la valeur par défaut. De la même manière, le paramètre 'gid' correspond à
un identifiant de groupe, et utilise par défaut la valeur 0 pour ne rien
changer. Il est particulièrement déconseillé d'utiliser des comptes génériques
tels que 'nobody' car cette pratique revient à utiliser 'root' si d'autres
processus utilisent les mêmes identifiants.
Le paramètre 'chroot' autorise à changer la racine du processus une fois le
programme lancé, de sorte que ni le processus, ni l'un de ses descendants ne
puisse remonter de nouveau à la racine. Ce type de cloisonnement (chroot) est
parfois contournable sur certains OS (Linux 2.2, Solaris), mais visiblement
fiable sur d'autres (Linux 2.4). Aussi, il est important d'utiliser un
répertoire spécifique au service pour cet usage, et de ne pas mutualiser un même
répertoire pour plusieurs services de nature différente.
Remarque: dans le cas où une telle faille serait mise en évidence, il est fort
probable que les premières tentatives de son exploitation provoquent un arrêt du
programme, à cause d'un signal de type 'Segmentation Fault', 'Bus Error' ou
encore 'Illegal Instruction'. Même s'il est vrai que faire tourner le serveur en
environnement limité réduit les risques d'intrusion, il est parfois bien utile
dans ces circonstances de connaître les conditions d'apparition du problème, via
l'obtention d'un fichier 'core'. La plupart des systèmes, pour des raisons de
sécurité, désactivent la génération du fichier 'core' après un changement
d'identifiant pour le processus. Il faudra donc soit lancer le processus à
partir d'un compte utilisateur aux droits réduits (mais ne pouvant pas effectuer
le chroot), ou bien le faire en root sans réduction des droits (uid 0). Dans ce
cas, le fichier se trouvera soit dans le répertoire de lancement, soit dans le
répertoire spécifié après l'option 'chroot'. Ne pas oublier la commande suivante
pour autoriser la génération du fichier avant de lancer le programme :
# ulimit -c unlimited
Exemple :
---------
global
uid 30000
gid 30000
chroot /var/chroot/haproxy
1.4) modes de fonctionnement
----------------------------
Le service peut fonctionner dans plusieurs modes :
- avant- / arrière-plan
- silencieux / normal / debug
Le mode par défaut est normal, avant-plan, c'est à dire que le programme ne rend
pas la main une fois lancé. Il ne faut surtout pas le lancer comme ceci dans un
script de démarrage du système, sinon le système ne finirait pas son
initialisation. Il faut le mettre en arrière-plan, de sorte qu'il rende la main
au processus appelant. C'est ce que fait l'option 'daemon' de la section
'global', et qui est l'équivalent du paramètre '-D' de la ligne de commande.
Par ailleurs, certains messages d'alerte sont toujours envoyés sur la sortie
standard, même en mode 'daemon'. Pour ne plus les voir ailleurs que dans les
logs, il suffit de passer en mode silencieux par l'ajout de l'option 'quiet'.
Cette option n'a pas d'équivalent en ligne de commande.
Enfin, le mode 'debug' permet de diagnostiquer les origines de certains
problèmes en affichant les connexions, déconnexions et échanges d'en-têtes HTTP
entre les clients et les serveurs. Ce mode est incompatible avec les options
'daemon' et 'quiet' pour des raisons de bon sens.
1.5) accroissement de la capacité de traitement
-----------------------------------------------
Sur des machines multi-processeurs, il peut sembler gâché de n'utiliser qu'un
processeur pour effectuer les tâches de relayage, même si les charges
nécessaires à saturer un processeur actuel sont bien au-delà des ordres de
grandeur couramment rencontrés. Cependant, pour des besoins particuliers, le
programme sait démarrer plusieurs processus se répartissant la charge de
travail. Ce nombre de processus est spécifié par le paramètre 'nbproc' de la
section 'global'. Sa valeur par défaut est naturellement 1. Ceci ne fonctionne
qu'en mode 'daemon'.
Exemple :
---------
global
daemon
quiet
nbproc 2
2) Définition d'un service en écoute
====================================
Serveur Les sections de service débutent par le mot clé "listen" :
=======
Le fichier de configuration contient des sections repérées par le mot
clé "listen" :
listen <nom_instance> <adresse_IP>:<port> listen <nom_instance> <adresse_IP>:<port>
<nom_instance> est le nom de l'instance décrite. Ce nom sera envoyé - <nom_instance> est le nom de l'instance décrite. Ce nom sera envoyé dans les
dans les logs, donc il est souhaitable d'utiliser un nom relatif au logs, donc il est souhaitable d'utiliser un nom relatif au service relayé. Aucun
service relayé. Aucun test n'est effectué concernant l'unicité de ce test n'est effectué concernant l'unicité de ce nom, qui n'est pas obligatoire,
nom, qui n'est pas obligatoire, mais fortement recommandée. mais fortement recommandée.
<adresse_IP> est l'adresse IP sur laquelle le relais attend ses - <adresse_IP> est l'adresse IP sur laquelle le relais attend ses
connexions. L'adresse 0.0.0.0 signifie que les connexions pourront connexions. L'adresse 0.0.0.0 signifie que les connexions pourront s'effectuer
s'effectuer sur toutes les adresses de la machine. sur toutes les adresses de la machine.
<port> est le numéro de port TCP sur lequel le relais attend ses - <port> est le numéro de port TCP sur lequel le relais attend ses
connexions. Le couple <adresse_IP>:<port> doit être unique pour toutes connexions. Le couple <adresse_IP>:<port> doit être unique pour toutes les
les instances d'une même machine. L'attachement à un port inférieur à instances d'une même machine. L'attachement à un port inférieur à 1024
1024 nécessite un niveau de privilège particulier. nécessite un niveau de privilège particulier lors du lancement du programme
(indépendamment du paramètre 'uid' de la section 'global').
Exemple : Exemple :
--------- ---------
listen http_proxy 127.0.0.1:80 listen http_proxy 127.0.0.1:80
Inhibition 2.1) Inhibition d'un service
========== ----------------------------
Un serveur peut être désactivé pour des besoins de maintenance, sans avoir à
Un serveur peut être désactivé pour des besoins de maintenance, sans commenter toute une partie du fichier. Il suffit de positionner le mot clé
avoir à commenter toute une partie du fichier. Il suffit de "disabled" dans sa section :
positionner le mot clé "disabled" dans sa section :
listen smtp_proxy 0.0.0.0:25 listen smtp_proxy 0.0.0.0:25
disabled disabled
Mode 2.2) Mode de fonctionnement
==== ---------------------------
Un serveur peut fonctionner dans trois modes différents : Un serveur peut fonctionner dans trois modes différents :
- TCP - TCP
- HTTP - HTTP
@ -178,86 +272,89 @@ Un serveur peut fonctionner dans trois modes diff
Mode TCP Mode TCP
-------- --------
Dans ce mode, le service relaye, dès leur établissement, les Dans ce mode, le service relaye, dès leur établissement, les connexions TCP vers
connexions TCP vers un ou plusieurs serveurs. Aucun traitement n'est un ou plusieurs serveurs. Aucun traitement n'est effectué sur le flux. Il s'agit
effectué sur le flux. Il s'agit simplement d'une association simplement d'une association source<adresse:port> -> destination<adresse:port>.
<adresse_source:port_source> <adresse_destination:port_destination>. Pour l'utiliser, préciser le mode TCP sous la déclaration du relais.
Pour l'utiliser, préciser le mode TCP sous la déclaration du relais :
Exemple :
---------
listen smtp_proxy 0.0.0.0:25 listen smtp_proxy 0.0.0.0:25
mode tcp mode tcp
Mode HTTP Mode HTTP
--------- ---------
Dans ce mode, le service relaye les connexions TCP vers un ou Dans ce mode, le service relaye les connexions TCP vers un ou plusieurs
plusieurs serveurs, une fois qu'il dispose d'assez d'informations pour serveurs, une fois qu'il dispose d'assez d'informations pour en prendre la
en prendre la décision. Les entêtes HTTP sont analysés pour y trouver décision. Les entêtes HTTP sont analysés pour y trouver un éventuel cookie, et
un éventuel cookie, et certains d'entre-eux peuvent être modifiés par certains d'entre-eux peuvent être modifiés par le biais d'expressions
le biais d'expressions régulières. Pour activer ce mode, préciser le régulières. Pour activer ce mode, préciser le mode HTTP sous la déclaration du
mode HTTP sous la déclaration du relais : relais.
Exemple :
---------
listen http_proxy 0.0.0.0:80 listen http_proxy 0.0.0.0:80
mode http mode http
Mode supervision Mode supervision
---------------- ----------------
Il s'agit d'un mode offrant à un composant externe une visibilité de Il s'agit d'un mode offrant à un composant externe une visibilité de l'état de
l'état de santé du service. Il se contente de retourner "OK" à tout santé du service. Il se contente de retourner "OK" à tout client se connectant
client se connectant sur son port. Il peut être utilisé avec des sur son port. Il peut être utilisé avec des répartiteurs de charge évolués pour
répartiteurs de charge évolués pour déterminer quels sont les services déterminer quels sont les services utilisables. Pour activer ce mode, préciser
utilisables. Pour activer ce mode, préciser le mode HEALTH sous la le mode HEALTH sous la déclaration du relais.
déclaration du relais :
Exemple :
---------
listen health_check 0.0.0.0:60000 listen health_check 0.0.0.0:60000
mode health mode health
Limitation du nombre de connexions simultanées 2.3) Limitation du nombre de connexions simultanées
============================================== ---------------------------------------------------
Le paramètre "maxconn" permet de fixer la limite acceptable en nombre de
Le paramètre "maxconn" permet de fixer la limite acceptable en nombre connexions simultanées par proxy. Chaque proxy qui atteint cette valeur cesse
de connexions simultanées par proxy. Chaque proxy qui atteint cette d'écouter jusqu'à libération d'une connexion. Voir plus loin concernant les
valeur cesse d'écouter jusqu'à libération d'une connexion. Voir plus limitations liées au système.
loin concernant les limitations liées au système. Exemple:
maxconn 16000
Arrêt en douceur
================
Il est possible d'arrêter les services en douceur en envoyant un
signal SIG_USR1 au processus relais. Tous les services seront alors
mis en phase d'arrêt, mais pourront continuer d'accepter des connexions
pendant un temps défini par le paramètre "grace" (en millisecondes).
Cela permet par exemple, de faire savoir rapidement à un répartiteur
de charge qu'il ne doit plus utiliser un relais, tout en continuant
d'assurer le service le temps qu'il s'en rende compte. Remarque : les
connexions actives ne sont jamais cassées. Dans le pire des cas, il
faudra attendre en plus leur expiration avant l'arrêt total du
processus. La valeur par défaut est 0 (pas de grâce).
Exemple : Exemple :
--------- ---------
listen tiny_server 0.0.0.0:80
maxconn 10
2.4) Arrêt en douceur
---------------------
Il est possible d'arrêter les services en douceur en envoyant un signal SIG_USR1
au processus relais. Tous les services seront alors mis en phase d'arrêt, mais
pourront continuer d'accepter des connexions pendant un temps défini par le
paramètre 'grace' (en millisecondes). Cela permet par exemple, de faire savoir
rapidement à un répartiteur de charge qu'il ne doit plus utiliser un relais,
tout en continuant d'assurer le service le temps qu'il s'en rende compte.
Remarque : les connexions actives ne sont jamais cassées. Dans le pire des cas,
il faudra attendre en plus leur expiration avant l'arrêt total du processus. La
valeur par défaut est 0 (pas de grâce, arrêt immédiat de l'écoute).
Exemple :
---------
# arrêter en douceur par 'killall -USR1 haproxy'
# le service tournera encore 10 secondes après la demande d'arrêt # le service tournera encore 10 secondes après la demande d'arrêt
listen http_proxy 0.0.0.0:80 listen http_proxy 0.0.0.0:80
mode http mode http
grace 10000 grace 10000
# ce port n'est testé que par un répartiteur de charge.
listen health_check 0.0.0.0:60000 listen health_check 0.0.0.0:60000
mode health mode health
grace 0 grace 0
Temps d'expiration des connexions 2.5) Temps d'expiration des connexions
================================= --------------------------------------
Il est possible de paramétrer certaines durées d'expiration au niveau des
Il est possible de paramétrer certaines durées d'expiration au niveau connexions TCP. Trois temps indépendants sont configurables et acceptent des
des connexions TCP. Trois temps indépendants sont configurables et valeurs en millisecondes. Si l'une de ces trois temporisations est dépassée, la
acceptent des valeurs en millisecondes. Si l'une de ces trois session est terminée à chaque extrémité.
temporisations est dépassée, la session est terminée à chaque
extrémité.
- temps d'attente d'une donnée de la part du client, ou de la - temps d'attente d'une donnée de la part du client, ou de la
possibilité de lui envoyer des données : "clitimeout" : possibilité de lui envoyer des données : "clitimeout" :
@ -268,91 +365,117 @@ extr
- temps d'attente d'une donnée de la part du serveur, ou de la - temps d'attente d'une donnée de la part du serveur, ou de la
possibilité de lui envoyer des données : "srvtimeout" : possibilité de lui envoyer des données : "srvtimeout" :
# time-out client à 30s. # time-out serveur à 30s.
srvtimeout 30000 srvtimeout 30000
- temps d'attente de l'établissement d'une connexion vers un serveur - temps d'attente de l'établissement d'une connexion vers un serveur
"contimeout" : "contimeout" :
# on abandonne si la connexion n'est pas établie après 3 secondes # on abandonne si la connexion n'est pas établie après 4 secondes
contimeout 3000 contimeout 4000
Remarque: "contimeout" et "srvtimeout" n'ont pas d'utilité dans le cas Remarques :
du serveur de type "health". -----------
- "contimeout" et "srvtimeout" n'ont pas d'utilité dans le cas du serveur de
Tentatives de reconnexion type "health".
========================= - sous de fortes charges, ou sur un réseau saturé ou défectueux, il est
possible de perdre des paquets. Du fait que la première retransmission TCP
n'ait lieu qu'au bout de 3 secoudes, fixer un timeout de connexion inférieur
à 3 secondes ne permet pas de se rattraper sur la perte de paquets car la
session aura été abandonnée avant la première retransmission. Une valeur de
4 secondes réduira considérablement le nombre d'échecs de connexion.
2.6) Tentatives de reconnexion
------------------------------
Lors d'un échec de connexion vers un serveur, il est possible de Lors d'un échec de connexion vers un serveur, il est possible de
retenter (potentiellement vers un autre serveur, en cas de répartition retenter (potentiellement vers un autre serveur, en cas de répartition
de charge). Le nombre de nouvelles tentatives infructueuses avant de charge). Le nombre de nouvelles tentatives infructueuses avant
abandon est fourni par le paramètre "retries" : abandon est fourni par le paramètre "retries".
Exemple :
---------
# on essaie encore trois fois maxi # on essaie encore trois fois maxi
retries 3 retries 3
Adresse du serveur
==================
Le serveur vers lequel sont redirigées les connexions est défini par 2.7) Adresse du serveur
le paramètre "dispatch" sous la forme <adresse_ip>:<port> : -----------------------
Le serveur vers lequel sont redirigées les nouvelles connexions est défini par
le paramètre "dispatch" sous la forme <adresse_ip>:<port>. Il correspond à un
serveur d'assignation de cookie dans le cas où le service consiste à assurer
uniquement une persistence HTTP, ou bien simplement au serveur destination dans
le cas de relayage TCP simple.
Exemple :
---------
# on envoie toutes les nouvelles connexions ici # on envoie toutes les nouvelles connexions ici
dispatch 192.168.1.2:80 dispatch 192.168.1.2:80
Remarque: ce paramètre n'a pas d'utilité pour un serveur en mode "health". Remarque :
----------
Ce paramètre n'a pas d'utilité pour un serveur en mode 'health', ni en mode
'balance'.
Définition du nom du cookie
===========================
En mode HTTP, il est possible de rechercher la valeur d'un cookie pour 2.8) Définition du nom du cookie
savoir vers quel serveur aiguiller la requête utilisateur. Le nom du --------------------------------
cookie est donné par le paramètre "cookie" : En mode HTTP, il est possible de rechercher la valeur d'un cookie pour savoir
vers quel serveur aiguiller la requête utilisateur. Le nom du cookie est donné
par le paramètre "cookie".
Exemple :
---------
listen http_proxy 0.0.0.0:80 listen http_proxy 0.0.0.0:80
mode http mode http
cookie SERVERID cookie SERVERID
On peut modifier l'utilisation du cookie pour la rendre plus On peut modifier l'utilisation du cookie pour la rendre plus intelligente
intelligente vis-à-vis des applications relayées. Il est possible,notamment vis-à-vis des applications relayées. Il est possible, notamment de supprimer ou
de supprimer ou réécrire un cookie retourné par un serveur accédé en direct, réécrire un cookie retourné par un serveur accédé en direct, et d'insérer un
et d'insérer un cookie dans une réponse HTTP orientée vers un serveur cookie dans une réponse HTTP adressée à un serveur sélectionné en répartition
sélectionné en répartition de charge. de charge.
Exemples :
----------
Pour ne conserver le cookie qu'en accès indirect, donc à travers le Pour ne conserver le cookie qu'en accès indirect, donc à travers le
dispatcheur, et le supprimer lors des accès directs : dispatcheur, et supprimer toutes ses éventuelles occurences lors des accès
directs :
cookie SERVERID indirect cookie SERVERID indirect
Pour réécrire le nom du serveur dans un cookie lors d'un accès direct : Pour remplacer la valeur d'un cookie existant par celle attribuée à un serveur,
lors d'un accès direct :
cookie SERVERID rewrite cookie SERVERID rewrite
Pour créer un cookie comportant le nom du serveur lors d'un accès en Pour créer un cookie comportant la valeur attribuée à un serveur lors d'un accès
répartition de charge interne. Dans ce cas, il est indispensable que tous les en répartition de charge interne. Dans ce cas, il est indispensable que tous les
serveurs aient un cookie renseigné. serveurs aient un cookie renseigné :
cookie SERVERID insert cookie SERVERID insert
Remarque: Il est possible de combiner 'insert' avec 'indirect' ou 'rewrite' Remarque :
pour s'adapter à des applications générant déjà le cookie, avec un contenu ----------
invalide. Il suffit pour cela de les spécifier sur la même ligne. Il est possible de combiner 'insert' avec 'indirect' ou 'rewrite' pour s'adapter
à des applications générant déjà le cookie, avec un contenu invalide. Il suffit
pour cela de les spécifier sur la même ligne.
Assignation d'un serveur à une valeur de cookie
===============================================
2.9) Assignation d'un serveur à une valeur de cookie
----------------------------------------------------
En mode HTTP, il est possible d'associer des serveurs à des valeurs de En mode HTTP, il est possible d'associer des serveurs à des valeurs de
cookie par le paramètre "server". La syntaxe est : cookie par le paramètre 'server'. La syntaxe est :
server <identifiant> <adresse_ip>:<port> cookie <valeur> server <identifiant> <adresse_ip>:<port> cookie <valeur>
<identifiant> est un nom quelconque de serveur utilisé pour - <identifiant> est un nom quelconque de serveur utilisé pour l'identifier dans la
l'identifier dans la configuration (erreurs...). configuration et les logs.
<adresse_ip>:<port> le couple adresse-port sur lequel le serveur écoute. - <adresse_ip>:<port> est le couple adresse-port sur lequel le serveur écoute.
<valeur> est la valeur trouvée dans le cookie, - <valeur> est la valeur à reconnaître ou positionner dans le cookie.
Exemple : le cookie SERVERID peut contenir server01 ou server02 Exemple : le cookie SERVERID peut contenir server01 ou server02
------- ---------
listen http_proxy 0.0.0.0:80 listen http_proxy 0.0.0.0:80
mode http mode http
cookie SERVERID cookie SERVERID
@ -361,22 +484,21 @@ Exemple : le cookie SERVERID peut contenir server01 ou server02
server web2 192.168.1.2:80 cookie server02 server web2 192.168.1.2:80 cookie server02
Attention : la syntaxe a changé depuis la version 1.0. Attention : la syntaxe a changé depuis la version 1.0.
--------- -----------
Répartiteur de charge interne 3) Répartiteur de charge interne
============================= =================================
Le relais peut effectuer lui-même la répartition de charge entre les Le relais peut effectuer lui-même la répartition de charge entre les différents
différents serveurs décrits pour un service donné, en mode TCP comme serveurs définis pour un service donné, en mode TCP comme en mode HTTP. Pour
en mode HTTP. Pour cela, on précise le mot clé 'balance' dans la cela, on précise le mot clé 'balance' dans la définition du service,
définition du service, éventuellement suivi du nom d'un algorithme de éventuellement suivi du nom d'un algorithme de répartition. En version 1.1.9,
répartition. En version 1.1.0, seul 'roundrobin' est géré, et c'est seul 'roundrobin' est géré, et c'est aussi la valeur implicite par défaut. Il
aussi la valeur implicite par défaut. Il est évident qu'en cas est évident qu'en cas d'utilisation du répartiteur interne, il ne faudra pas
d'utilisation du répartiteur interne, il ne faudra pas spécifier spécifier d'adresse de dispatch, et qu'il faudra au moins un serveur.
d'adresse de dispatch, et qu'il faudra au moins un serveur.
Exemple : même que précédemment en répartition interne Exemple : même que précédemment en répartition interne
------- ---------
listen http_proxy 0.0.0.0:80 listen http_proxy 0.0.0.0:80
mode http mode http
@ -386,46 +508,50 @@ Exemple : m
server web2 192.168.1.2:80 cookie server02 server web2 192.168.1.2:80 cookie server02
Surveillance des serveurs 3.1) Surveillance des serveurs
========================= ------------------------------
A cette date, l'état des serveurs n'est testé que par établissement de connexion
A cette date, l'état des serveurs n'est testé que par établissement TCP toutes les 2 secondes, avec 3 essais pour déclarer un serveur en panne, 2
de connexion TCP toutes les 2 secondes, avec 3 essais pour déclarer pour le déclarer utilisable. Un serveur hors d'usage ne sera pas utilisé dans le
un serveur en panne, 2 pour le déclarer utilisable. Un serveur hors processus de répartition de charge interne. Pour activer la surveillance,
d'usage ne sera pas utilisé dans le processus de répartition de charge ajouter le mot clé 'check' à la fin de la déclaration du serveur. Il est
interne. Pour activer la surveillance, ajouter le mot clé 'check' à la possible de spécifier l'intervalle (en millisecondes) séparant deux tests du
fin de la déclaration du serveur. Il est possible de spécifier serveur par le paramètre "inter", le nombre d'échecs acceptés par le paramètre
l'intervalle (en millisecondes) séparant deux tests du serveur par le "fall", et le nombre de succès avant reprise par le paramètre "rise". Les
paramètre "inter", le nombre d'échecs acceptés par le paramètre "fall", paramètres non précisés prennent les valeurs suivantes par défaut :
et le nombre de succès avant reprise par le paramètre "rise".
Les paramètres non précisés prennent les valeurs suivantes par défaut :
- inter : 2000 - inter : 2000
- rise : 2 - rise : 2
- fall : 3 - fall : 3
Exemple : même que précédemment avec surveillance Exemples :
------- ----------
# même que précédemment avec surveillance
listen http_proxy 0.0.0.0:80 listen http_proxy 0.0.0.0:80
mode http mode http
cookie SERVERID cookie SERVERID
balance roundrobin balance roundrobin
server web1 192.168.1.1:80 cookie server01 check server web1 192.168.1.1:80 cookie server01 check
server web2 192.168.1.2:80 cookie server02 check inter 500 rise 1 fall 2
# insertion automatique de cookie dans la réponse du serveur
listen web_appl 0.0.0.0:80
mode http
cookie SERVERID insert indirect
balance roundrobin
server web1 192.168.1.1:80 cookie server01 check
server web2 192.168.1.2:80 cookie server02 check server web2 192.168.1.2:80 cookie server02 check
Reconnexion vers un répartiteur en cas d'échec direct 3.2) Reconnexion vers un répartiteur en cas d'échec direct
===================================================== ----------------------------------------------------------
En mode HTTP, si un serveur défini par un cookie ne répond plus, les clients
En mode HTTP, si un serveur défini par un cookie ne répond plus, les seront définitivement aiguillés dessus à cause de leur cookie, et de ce fait,
clients seront définitivement aiguillés dessus à cause de leur cookie, définitivement privés de service. La spécification du paramètre 'redispatch'
et de ce fait, définitivement privés de service. La spécification du autorise dans ce cas à renvoyer les connexions échouées vers le répartiteur
paramètre "redispatch" autorise dans ce cas à renvoyer les connexions (externe ou interne) afin d'assigner un nouveau serveur à ces clients.
échouées vers le répartiteur (externe ou interne) afin d'assigner un
nouveau serveur à ces clients.
Exemple : Exemple :
------- ---------
listen http_proxy 0.0.0.0:80 listen http_proxy 0.0.0.0:80
mode http mode http
cookie SERVERID cookie SERVERID
@ -434,18 +560,24 @@ Exemple :
server web2 192.168.1.2:80 cookie server02 server web2 192.168.1.2:80 cookie server02
redispatch # renvoyer vers dispatch si serveur HS. redispatch # renvoyer vers dispatch si serveur HS.
Fonctionnement en mode transparent
==================================
En mode HTTP, le mot clé "transparent" permet d'intercepter des 4) Fonctionnalités additionnelles
sessions routées à travers la machine hébergeant le proxy. Dans =================================
ce mode, on ne précise pas l'adresse de répartition "dispatch",
car celle-ci est tirée de l'adresse destination de la session D'autres fonctionnalités d'usage moins courant sont disponibles. Il s'agit
détournée. Le système doit permettre de rediriger les paquets principalement du mode transparent, de la journalisation des connexions, et de
vers un processus local. la réécriture des entêtes.
4.1) Fonctionnement en mode transparent
---------------------------------------
En mode HTTP, le mot clé 'transparent' permet d'intercepter des sessions routées
à travers la machine hébergeant le proxy. Dans ce mode, on ne précise pas
l'adresse de répartition 'dispatch', car celle-ci est tirée de l'adresse
destination de la session détournée. Le système doit permettre de rediriger les
paquets vers un processus local.
Exemple : Exemple :
------- ---------
listen http_proxy 0.0.0.0:65000 listen http_proxy 0.0.0.0:65000
mode http mode http
transparent transparent
@ -456,17 +588,25 @@ Exemple :
# iptables -t nat -A PREROUTING -i eth0 -p tcp -d 192.168.1.100 \ # iptables -t nat -A PREROUTING -i eth0 -p tcp -d 192.168.1.100 \
--dport 80 -j REDIRECT --to-ports 65000 --dport 80 -j REDIRECT --to-ports 65000
Journalisation des connexions
=============================
Les connexions TCP et HTTP peuvent donner lieu à une journalisation 4.2) Journalisation des connexions
sommaire indiquant, pour chaque connexion, la date, l'heure, les adresses ----------------------------------
IP source et destination, et les ports source et destination qui la Les connexions TCP et HTTP peuvent donner lieu à une journalisation sommaire ou
caractérisent. Ultérieurement, les URLs seront loguées en mode HTTP, détaillée indiquant, pour chaque connexion, la date, l'heure, l'adresse IP
tout comme les arrêts de service. Tous les messages sont envoyés en source, le serveur destination, la durée de la connexion, les temps de réponse,
syslog vers un ou deux serveurs. La syntaxe est la suivante : la requête HTTP, le code de retour, la quantité de données transmise.
Tous les messages sont envoyés en syslog vers un ou deux serveurs. La syntaxe
est la suivante :
log <adresse_ip> <facility> log <adresse_ip> <facility>
log <adresse_ip> <facility>
ou
log global
Remarque :
----------
La syntaxe spécifique 'log global' indique que l'on souhaite utiliser les
paramètres de journalisation définis dans la section 'global'.
Exemple : Exemple :
--------- ---------
@ -475,34 +615,62 @@ Exemple :
log 192.168.2.200 local3 log 192.168.2.200 local3
log 192.168.2.201 local4 log 192.168.2.201 local4
Les connexions sont envoyées en niveau "info". Les démarrages de Les connexions sont envoyées en niveau "info". Les démarrages de service seront
service seront envoyés en "notice", les signaux d'arrêts en "warning" envoyés en "notice", les signaux d'arrêts en "warning" et les arrêts définitifs
et les arrêts définitifs en "alert". Ceci est valable aussi bien en "alert". Ceci est valable aussi bien pour les proxies que pour les serveurs
pour les proxies que pour les serveurs testés au sein des proxies. testés au sein des proxies. Les catégories possibles sont :
Les catégories possibles sont :
kern, user, mail, daemon, auth, syslog, lpr, news, kern, user, mail, daemon, auth, syslog, lpr, news,
uucp, cron, auth2, ftp, ntp, audit, alert, cron2, uucp, cron, auth2, ftp, ntp, audit, alert, cron2,
local0, local1, local2, local3, local4, local5, local6, local7 local0, local1, local2, local3, local4, local5, local6, local7
Par défaut, les informations contenues dans les logs se situent au niveau TCP
uniquement. Il faut préciser l'option 'httplog' pour obtenir les détails du
protocole HTTP. Dans les cas où un mécanisme de surveillance effectuant des
connexions et déconnexions fréquentes, polluerait les logs, il suffit d'ajouter
l'option 'dontlognull', pour ne plus obtenir une ligne de log pour les sessions
n'ayant pas donné lieu à un échange de données (requête ou réponse).
Modification des entêtes HTTP Enfin, l'option 'forwardfor' ajoute l'adresse IP du client dans un champ
============================= 'X-Forwarded-For' de la requête, ce qui permet à un serveur web final de
connaître l'adresse IP du client initial.
En mode HTTP uniquement, il est possible de remplacer certains entêtes Exemple :
dans la requête et/ou la réponse à partir d'expressions régulières. Une ---------
limitation cependant : les entêtes fournis au milieu de connexions listen http_proxy 0.0.0.0:80
persistentes (keep-alive) ne sont pas vus. Les données ne sont pas mode http
affectées, ceci ne s'applique qu'aux entêtes. log global
option httplog
option dontlognull
option forwardfor
4.3) Modification des entêtes HTTP
----------------------------------
En mode HTTP uniquement, il est possible de remplacer certains en-têtes dans la
requête et/ou la réponse à partir d'expressions régulières. Il est également
possible de bloquer certaines requêtes en fonction du contenu des en-têtes ou de
la requête. Une limitation cependant : les en-têtes fournis au milieu de
connexions persistentes (keep-alive) ne sont pas vus car ils sont considérés
comme faisant partie des échanges de données consécutifs à la première requête.
Les données ne sont pas affectées, ceci ne s'applique qu'aux en-têtes.
La syntaxe est : La syntaxe est :
reqadd <string> pour ajouter un entête dans la requête reqadd <string> pour ajouter un en-tête dans la requête
reqrep <search> <replace> pour modifier la requête reqrep <search> <replace> pour modifier la requête
reqrep <search> pour supprimer un entête dans la requête reqirep <search> <replace> idem sans distinction majuscules/minuscules
reqdel <search> pour supprimer un en-tête dans la requête
reqidel <search> idem sans distinction majuscules/minuscules
reqallow <search> autoriser une requête qui valide <search>
reqiallow <search> idem sans distinction majuscules/minuscules
reqdeny <search> interdire une requête qui valide <search>
reqdeny <search> idem sans distinction majuscules/minuscules
rspadd <string> pour ajouter un entête dans la réponse rspadd <string> pour ajouter un en-tête dans la réponse
rsprep <search> <replace> pour modifier la réponse rsprep <search> <replace> pour modifier la réponse
rsprep <search> pour supprimer un entête dans la réponse rspirep <search> <replace> idem sans distinction majuscules/minuscules
rspdel <search> pour supprimer un en-tête dans la réponse
rspidel <search> idem sans distinction majuscules/minuscules
<search> est une expression régulière compatible GNU regexp supportant <search> est une expression régulière compatible GNU regexp supportant
@ -529,12 +697,12 @@ imprimable (utile pour le saut de ligne) inscrivant '\x' suivi du code
hexadécimal de ce caractère (comme en C). hexadécimal de ce caractère (comme en C).
<string> représente une chaîne qui sera ajoutée systématiquement après la <string> représente une chaîne qui sera ajoutée systématiquement après la
dernière ligne d'entête. dernière ligne d'en-tête.
Remarques : Remarques :
--------- ---------
- la première ligne de la requête et celle de la réponse sont traitées comme - la première ligne de la requête et celle de la réponse sont traitées comme
des entêtes, ce qui permet de réécrire des URL et des codes d'erreur. des en-têtes, ce qui permet de réécrire des URL et des codes d'erreur.
- 'reqrep' est l'équivalent de 'cliexp' en version 1.0, et 'rsprep' celui de - 'reqrep' est l'équivalent de 'cliexp' en version 1.0, et 'rsprep' celui de
'srvexp'. Ces noms sont toujours supportés mais déconseillés. 'srvexp'. Ces noms sont toujours supportés mais déconseillés.
- pour des raisons de performances, le nombre total de caractères ajoutés sur - pour des raisons de performances, le nombre total de caractères ajoutés sur
@ -547,15 +715,15 @@ Exemples :
-------- --------
reqrep ^(GET.*)(.free.fr)(.*) \1.online.fr\3 reqrep ^(GET.*)(.free.fr)(.*) \1.online.fr\3
reqrep ^(POST.*)(.free.fr)(.*) \1.online.fr\3 reqrep ^(POST.*)(.free.fr)(.*) \1.online.fr\3
reqrep ^Proxy-Connection:.* Proxy-Connection:\ close reqirep ^Proxy-Connection:.* Proxy-Connection:\ close
rsprep ^Server:.* Server:\ Tux-2.0 rspirep ^Server:.* Server:\ Tux-2.0
rsprep ^(Location:\ )([^:]*://[^/]*)(.*) \1\3 rspirep ^(Location:\ )([^:]*://[^/]*)(.*) \1\3
rspdel ^Connection:.* rspidel ^Connection:
rspadd Connection:\ close rspadd Connection:\ close
Répartition avec persistence 4.4) Répartition avec persistence
============================ ---------------------------------
La combinaison de l'insertion de cookie avec la répartition de charge interne La combinaison de l'insertion de cookie avec la répartition de charge interne
permet d'assurer une persistence dans les sessions HTTP d'une manière permet d'assurer une persistence dans les sessions HTTP d'une manière
@ -563,6 +731,7 @@ pratiquement transparente pour les applications. Le principe est simple :
- assigner un cookie à chaque serveur - assigner un cookie à chaque serveur
- effectuer une répartition interne - effectuer une répartition interne
- insérer un cookie dans les réponses issues d'une répartition - insérer un cookie dans les réponses issues d'une répartition
- cacher ce cookie à l'application
Exemple : Exemple :
------- -------
@ -572,6 +741,7 @@ Exemple :
balance roundrobin balance roundrobin
server 192.168.1.1:80 cookie server01 check server 192.168.1.1:80 cookie server01 check
server 192.168.1.2:80 cookie server02 check server 192.168.1.2:80 cookie server02 check
reqidel ^Cookie:\ SERVERID=
======================= =======================
| Paramétrage système | | Paramétrage système |

170
haproxy.c
View File

@ -10,12 +10,19 @@
* Pending bugs : * Pending bugs :
* - solaris only : sometimes, an HTTP proxy with only a dispatch address causes * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
* the proxy to terminate (no core) if the client breaks the connection during * the proxy to terminate (no core) if the client breaks the connection during
* the response. Seen on 1.1.8pre4, but never reproduced. * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
* the snprintf() bug since requests we simple (GET / HTTP/1.0).
* - cookie in insert+indirect mode sometimes segfaults ! * - cookie in insert+indirect mode sometimes segfaults !
* - a proxy with an invalid config will prevent the startup even if disabled. * - a proxy with an invalid config will prevent the startup even if disabled.
* *
* ChangeLog : * ChangeLog :
* *
* 2002/04/19 : 1.1.9
* - don't use snprintf()'s return value as an end of message since it may
* be larger. This caused bus errors and segfaults in internal libc's
* getenv() during localtime() in send_log().
* - removed dead insecure send_syslog() function and all references to it.
* - fixed warnings on Solaris due to buggy implementation of isXXXX().
* 2002/04/18 : 1.1.8 * 2002/04/18 : 1.1.8
* - option "dontlognull" * - option "dontlognull"
* - fixed "double space" bug in config parser * - fixed "double space" bug in config parser
@ -134,8 +141,8 @@
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
#endif #endif
#define HAPROXY_VERSION "1.1.8" #define HAPROXY_VERSION "1.1.9"
#define HAPROXY_DATE "2002/04/18" #define HAPROXY_DATE "2002/04/19"
/* this is for libc5 for example */ /* this is for libc5 for example */
#ifndef TCP_NODELAY #ifndef TCP_NODELAY
@ -748,78 +755,12 @@ struct sockaddr_in *str2sa(char *str) {
return &sa; return &sa;
} }
/*
* This function tries to send a syslog message to the syslog server at
* address <sa>. It doesn't care about errors nor does it report them.
* WARNING! no check is made on the prog+hostname+date length, so the
* local hostname + the prog name must be shorter than MAX_SYSLOG_LEN-19.
* the message will be truncated to fit the maximum length.
*/
void send_syslog(struct sockaddr_in *sa,
int facility, int level, char *message)
{
static int logfd = -1; /* syslog UDP socket */
struct timeval tv;
struct tm *tm;
static char logmsg[MAX_SYSLOG_LEN];
char *p;
if (logfd < 0) {
if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
return;
}
if (facility < 0 || level < 0
|| sa == NULL || progname == NULL || message == NULL)
return;
gettimeofday(&tv, NULL);
tm = localtime(&tv.tv_sec);
p = logmsg;
//p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s %s[%d]: ",
// facility * 8 + level,
// monthname[tm->tm_mon],
// tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
// hostname, progname, pid);
/* 20011216/WT : other progs don't set the hostname, and syslogd
* systematically repeats it which is contrary to RFC3164.
*/
/*
* warning: buffer overflow possible on progname.
*/
p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s[%d]: ",
facility * 8 + level,
monthname[tm->tm_mon],
tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
progname, pid);
if (((char *)&logmsg - p + MAX_SYSLOG_LEN) > 0) {
int len = strlen(message);
if (len > ((char *)&logmsg + MAX_SYSLOG_LEN - p))
len = ((char *)&logmsg + MAX_SYSLOG_LEN - p);
memcpy(p, message, len);
p += len;
}
#ifndef MSG_NOSIGNAL
sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT,
(struct sockaddr *)sa, sizeof(*sa));
#else
sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT | MSG_NOSIGNAL,
(struct sockaddr *)sa, sizeof(*sa));
#endif
}
/* /*
* This function sends a syslog message to both log servers of a proxy, * This function sends a syslog message to both log servers of a proxy,
* or to global log servers if the proxy is NULL. * or to global log servers if the proxy is NULL.
* It also tries not to waste too much time computing the message header. * It also tries not to waste too much time computing the message header.
* It doesn't care about errors nor does it report them. * It doesn't care about errors nor does it report them.
* WARNING! no check is made on the prog+hostname+date length, so the
* local hostname + the prog name must be shorter than MAX_SYSLOG_LEN-19.
* the message will be truncated to fit the maximum length.
*/ */
void send_log(struct proxy *p, int level, char *message, ...) { void send_log(struct proxy *p, int level, char *message, ...) {
static int logfd = -1; /* syslog UDP socket */ static int logfd = -1; /* syslog UDP socket */
@ -844,25 +785,32 @@ void send_log(struct proxy *p, int level, char *message, ...) {
return; return;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
if (tv.tv_sec != tvsec) { if (tv.tv_sec != tvsec || dataptr == NULL) {
/* this string is rebuild only once a second */ /* this string is rebuild only once a second */
struct tm *tm = localtime(&tv.tv_sec); struct tm *tm = localtime(&tv.tv_sec);
tvsec = tv.tv_sec; tvsec = tv.tv_sec;
/* hdr_len = snprintf(logmsg, sizeof(logmsg),
* warning: buffer overflow possible on progname.
*/
dataptr = logmsg + snprintf(logmsg, sizeof(logmsg),
"<<<<>%s %2d %02d:%02d:%02d %s[%d]: ", "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
monthname[tm->tm_mon], monthname[tm->tm_mon],
tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
progname, pid); progname, pid);
/* WARNING: depending upon implementations, snprintf may return
* either -1 or the number of bytes that would be needed to store
* the total message. In both cases, we must adjust it.
*/
if (hdr_len < 0 || hdr_len > sizeof(logmsg))
hdr_len = sizeof(logmsg);
dataptr = logmsg + hdr_len;
} }
va_start(argp, message); va_start(argp, message);
data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp); data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */ if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
data_len = logmsg + sizeof(logmsg) - dataptr;
va_end(argp); va_end(argp);
dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
if (p == NULL) { if (p == NULL) {
if (global.logfac1 >= 0) { if (global.logfac1 >= 0) {
@ -889,7 +837,13 @@ void send_log(struct proxy *p, int level, char *message, ...) {
} }
while (nbloggers-- > 0) { while (nbloggers-- > 0) {
/* do this for each log target */ /* For each target, we may have a different facility.
* We can also have a different log level for each message.
* This induces variations in the message header length.
* Since we don't want to recompute it each time, nor copy it every
* time, we only change the facility in the pre-computed header,
* and we change the pointer to the header accordingly.
*/
fac_level = (facilities[nbloggers] << 3) + level; fac_level = (facilities[nbloggers] << 3) + level;
log_ptr = logmsg + 3; /* last digit of the log level */ log_ptr = logmsg + 3; /* last digit of the log level */
do { do {
@ -898,15 +852,14 @@ void send_log(struct proxy *p, int level, char *message, ...) {
log_ptr--; log_ptr--;
} while (fac_level && log_ptr > logmsg); } while (fac_level && log_ptr > logmsg);
*log_ptr = '<'; *log_ptr = '<';
hdr_len = dataptr - log_ptr;
/* the total syslog message now starts at p, for hdr_len+data_len */ /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
#ifndef MSG_NOSIGNAL #ifndef MSG_NOSIGNAL
sendto(logfd, log_ptr, hdr_len + data_len, MSG_DONTWAIT, sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
(struct sockaddr *)sa[nbloggers], sizeof(**sa)); (struct sockaddr *)sa[nbloggers], sizeof(**sa));
#else #else
sendto(logfd, log_ptr, hdr_len + data_len, MSG_DONTWAIT | MSG_NOSIGNAL, sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
(struct sockaddr *)sa[nbloggers], sizeof(**sa)); (struct sockaddr *)sa[nbloggers], sizeof(**sa));
#endif #endif
} }
@ -2096,7 +2049,7 @@ int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
while (*str) { while (*str) {
if (*str == '\\') { if (*str == '\\') {
str++; str++;
if (isdigit(*str)) { if (isdigit((int)*str)) {
int len, num; int len, num;
num = *str - '0'; num = *str - '0';
@ -2298,7 +2251,7 @@ int process_cli(struct session *t) {
p1 = req->h + 8; /* first char after 'Cookie: ' */ p1 = req->h + 8; /* first char after 'Cookie: ' */
while (p1 < ptr) { while (p1 < ptr) {
while (p1 < ptr && (isspace(*p1) || *p1 == ';')) while (p1 < ptr && (isspace((int)*p1) || *p1 == ';'))
p1++; p1++;
if (p1 == ptr) if (p1 == ptr)
@ -2326,7 +2279,7 @@ int process_cli(struct session *t) {
break; break;
p4=p3; p4=p3;
while (p4 < ptr && !isspace(*p4) && *p4 != ';') while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
p4++; p4++;
/* here, we have the cookie name between p1 and p2, /* here, we have the cookie name between p1 and p2,
@ -2776,7 +2729,7 @@ int process_srv(struct session *t) {
p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */ p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
while (p1 < ptr) { /* in fact, we'll break after the first cookie */ while (p1 < ptr) { /* in fact, we'll break after the first cookie */
while (p1 < ptr && (isspace(*p1))) while (p1 < ptr && (isspace((int)*p1)))
p1++; p1++;
if (p1 == ptr || *p1 == ';') /* end of cookie */ if (p1 == ptr || *p1 == ';') /* end of cookie */
@ -2796,7 +2749,7 @@ int process_srv(struct session *t) {
break; break;
p4 = p3; p4 = p3;
while (p4 < ptr && !isspace(*p4) && *p4 != ';') while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
p4++; p4++;
/* here, we have the cookie name between p1 and p2, /* here, we have the cookie name between p1 and p2,
@ -3167,13 +3120,6 @@ int process_chk(struct task *t) {
if (!(global.mode & MODE_QUIET)) if (!(global.mode & MODE_QUIET))
Warning("server %s DOWN.\n", s->id); Warning("server %s DOWN.\n", s->id);
// sprintf(trash, "Server %s/%s is DOWN.\n",
// s->proxy->id, s->id);
//
// if (s->proxy->logfac1 >= 0)
// send_syslog(&s->proxy->logsrv1, s->proxy->logfac1, LOG_ALERT, trash);
// if (s->proxy->logfac2 >= 0)
// send_syslog(&s->proxy->logsrv2, s->proxy->logfac2, LOG_ALERT, trash);
send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id); send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
} }
@ -3195,12 +3141,6 @@ int process_chk(struct task *t) {
if (s->health == s->rise) { if (s->health == s->rise) {
if (!(global.mode & MODE_QUIET)) if (!(global.mode & MODE_QUIET))
Warning("server %s UP.\n", s->id); Warning("server %s UP.\n", s->id);
// sprintf(trash, "Server %s/%s is UP.\n", s->proxy->id, s->id);
// if (s->proxy->logfac1 >= 0)
// send_syslog(&s->proxy->logsrv1, s->proxy->logfac1, LOG_NOTICE, trash);
// if (s->proxy->logfac2 >= 0)
// send_syslog(&s->proxy->logsrv2, s->proxy->logfac2, LOG_NOTICE, trash);
send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id); send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
} }
@ -3221,13 +3161,6 @@ int process_chk(struct task *t) {
if (s->health == s->rise) { if (s->health == s->rise) {
if (!(global.mode & MODE_QUIET)) if (!(global.mode & MODE_QUIET))
Warning("server %s DOWN.\n", s->id); Warning("server %s DOWN.\n", s->id);
// sprintf(trash, "Server %s/%s is DOWN.\n",
// s->proxy->id, s->id);
//
// if (s->proxy->logfac1 >= 0)
// send_syslog(&s->proxy->logsrv1, s->proxy->logfac1, LOG_ALERT, trash);
// if (s->proxy->logfac2 >= 0)
// send_syslog(&s->proxy->logsrv2, s->proxy->logfac2, LOG_ALERT, trash);
send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id); send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
} }
@ -3488,12 +3421,6 @@ static int maintain_proxies(void) {
t = tv_remain(&now, &p->stop_time); t = tv_remain(&now, &p->stop_time);
if (t == 0) { if (t == 0) {
Warning("Proxy %s stopped.\n", p->id); Warning("Proxy %s stopped.\n", p->id);
// sprintf(trash, "Proxy %s stopped.\n", p->id);
// if (p->logfac1 >= 0)
// send_syslog(&p->logsrv1, p->logfac1, LOG_WARNING, trash);
// if (p->logfac2 >= 0)
// send_syslog(&p->logsrv2, p->logfac2, LOG_WARNING, trash);
send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id); send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
fd_delete(p->listen_fd); fd_delete(p->listen_fd);
@ -3523,13 +3450,6 @@ static void soft_stop(void) {
while (p) { while (p) {
if (p->state != PR_STDISABLED) { if (p->state != PR_STDISABLED) {
Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace); Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
// sprintf(trash, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
// if (p->logfac1 >= 0)
// send_syslog(&p->logsrv1, p->logfac1, LOG_WARNING, trash);
// if (p->logfac2 >= 0)
// send_syslog(&p->logsrv2, p->logfac2, LOG_WARNING, trash);
send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace); send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
tv_delayfrom(&p->stop_time, &now, p->grace); tv_delayfrom(&p->stop_time, &now, p->grace);
} }
@ -4298,7 +4218,7 @@ int readcfgfile(char *file) {
end = line + strlen(line); end = line + strlen(line);
/* skip leading spaces */ /* skip leading spaces */
while (isspace(*line)) while (isspace((int)*line))
line++; line++;
arg = 0; arg = 0;
@ -4345,10 +4265,10 @@ int readcfgfile(char *file) {
*line = 0; *line = 0;
break; break;
} }
else if (isspace(*line)) { else if (isspace((int)*line)) {
/* a non-escaped space is an argument separator */ /* a non-escaped space is an argument separator */
*line++ = 0; *line++ = 0;
while (isspace(*line)) while (isspace((int)*line))
line++; line++;
args[++arg] = line; args[++arg] = line;
} }
@ -4658,14 +4578,6 @@ int start_proxies() {
FD_SET(fd, StaticReadEvent); FD_SET(fd, StaticReadEvent);
fd_insert(fd); fd_insert(fd);
listeners++; listeners++;
// fprintf(stderr,"Proxy %s : socket bound.\n", curproxy->id);
// sprintf(trash, "Proxy %s started.\n", curproxy->id);
//
// if (curproxy->logfac1 >= 0)
// send_syslog(&curproxy->logsrv1, curproxy->logfac1, LOG_INFO, trash);
// if (curproxy->logfac2 >= 0)
// send_syslog(&curproxy->logsrv2, curproxy->logfac2, LOG_INFO, trash);
send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id); send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);