* released 1.2.1 (1.1.28)
* added the '-V' command line option to verbosely report errors even though
the -q or 'quiet' options are specified. This is useful with '-c'.
* added a Red Hat init script and a .spec from Simon Matter <simon.matter@invoca.ch>
* added 'rspdeny' and 'rspideny' to block certain responses to avoid sensible
information leak from servers.
* more examples added into the configuration
diff --git a/CHANGELOG b/CHANGELOG
index b2c11ee..0c2140a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,13 +1,19 @@
ChangeLog :
===========
+2004/06/06 : 1.2.1 (1.1.28)
+ - added the '-V' command line option to verbosely report errors even though
+ the -q or 'quiet' options are specified. This is useful with '-c'.
+ - added a Red Hat init script and a .spec from Simon Matter <simon.matter@invoca.ch>
-2004/06/05 : 1.2.1 (1.1.28)
- - added the "logasap" option which produces a log without waiting for
- the data to be transferred from the server to the client.
- - added the "httpclose" option which removes any "connection:" header
- and adds "Connection: close" in both direction.
+2004/06/05 :
+ - added the "logasap" option which produces a log without waiting for the data
+ to be transferred from the server to the client.
+ - added the "httpclose" option which removes any "connection:" header and adds
+ "Connection: close" in both direction.
- added the 'checkcache' option which blocks cacheable responses containing
dangerous headers, such as 'set-cookie'.
+ - added 'rspdeny' and 'rspideny' to block certain responses to avoid sensible
+ information leak from servers.
2004/04/18 :
- send an EMERG log when no server is available for a given proxy
diff --git a/doc/haproxy-en.txt b/doc/haproxy-en.txt
index ad82521..115be18 100644
--- a/doc/haproxy-en.txt
+++ b/doc/haproxy-en.txt
@@ -1,9 +1,9 @@
H A - P r o x y
---------------
- version 1.1.27
+ version 1.2.1
willy tarreau
- 2003/10/27
+ 2004/06/06
============
| Abstract |
@@ -35,6 +35,10 @@
-N <high limit for the per-proxy number of simultaneous connections>
-d starts in foregreound with debugging mode enabled
-D starts in daemon mode
+ -q disable messages on output
+ -V displays messages on output even when -q or 'quiet' are specified.
+ -c only checks config file and exits with code 0 if no error was found, or
+ exits with code 1 if a syntax error was found.
-p <pidfile> asks the process to write down each of its children's
pids to this file in daemon mode.
-s shows statistics (only if compiled in)
@@ -219,7 +223,7 @@
1.5) Increasing the overall processing power
--------------------------------------------
On multi-processor systems, it may seem to be a shame to use only one processor,
-eventhough the load needed to saturate a recent processor are far above common
+eventhough the load needed to saturate a recent processor is far above common
usage. Anyway, for very specific needs, the proxy can start several processes
between which the operating system will spread the incoming connections. The
number of processes is controlled by the 'nbproc' parameter in the 'global'
@@ -379,7 +383,7 @@
The 'maxconn' parameter allows a proxy to refuse connections above a certain
amount of simultaneous ones. When the limit is reached, it simply stops
listening, but the system may still be accepting them because of the back log
-queue. These connections will be processed further when other ones have freed
+queue. These connections will be processed later when other ones have freed
some slots. This provides a serialization effect which helps very fragile
servers resist to high loads. Se further for system limitations.
@@ -733,6 +737,11 @@
as on <stderr> if not closed. For this reason, it's always a good idea to have
one local log server at the 'notice' level.
+Since version 1.1.28 and 1.2.1, if an instance loses all its servers, an
+emergency mesasge will be sent in the logs to inform the administator that an
+immediate action must be taken.
+
+
Examples :
----------
# same setup as in paragraph 3) with TCP monitoring
@@ -917,6 +926,15 @@
containing more information such as session duration and its state during the
disconnection.
+Example :
+---------
+ listen relais-tcp 0.0.0.0:8000
+ mode tcp
+ option tcplog
+ log 192.168.2.200 local3
+
+>>> haproxy[18989]: 127.0.0.1:34550 [15/Oct/2003:15:24:28] relais-tcp Srv1 0/5007 0 --
+
Another option, 'httplog', provides more detailed information about HTTP
contents, such as the request and some cookies. In the event where an external
component would establish frequent connections to check the service, logs may be
@@ -932,6 +950,34 @@
option dontlognull
log 192.168.2.200 local3
+>>> haproxy[674]: 127.0.0.1:33319 [15/Oct/2003:08:31:57] relais-http Srv1 9/7/147/723 200 243 - - ---- "HEAD / HTTP/1.0"
+
+The problem when logging at end of connection is that you have no clue about
+what is happening during very long sessions. To workaround this problem, a
+new option 'logasap' has been introduced in 1.1.28/1.2.1. When specified, the
+proxy will log as soon as possible, just before data transfer begins. This means
+that in case of TCP, it will still log the connection status to the server, and
+in case of HTTP, it will log just after processing the server headers. In this
+case, the number of bytes reported is the number of header bytes sent to the
+client.
+
+In order to avoid confusion with normal logs, the total time field and the
+number of bytes are prefixed with a '+' sign which mean that real numbers are
+certainly bigger.
+
+Example :
+---------
+
+ listen http_proxy 0.0.0.0:80
+ mode http
+ option httplog
+ option dontlognull
+ option logasap
+ log 192.168.2.200 local3
+
+>>> haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17] relais-http Srv1 9/7/14/+30 200 +243 - - ---- "GET /image.iso HTTP/1.0"
+
+
4.2.3) Timing events
--------------------
Timers provide a great help in trouble shooting network problems. All values
@@ -956,8 +1002,10 @@
means that the last the response header (empty line) was never seen.
- Tt: total session duration time, between the moment the proxy accepted it
- and the moment both ends were closed. From this one, we can deduce Td,
- the data transmission time, by substracting other timers when valid :
+ and the moment both ends were closed. The exception is when the 'logasap'
+ option is specified. In this case, it only equals (Tq+Tc+Tr), and is
+ prefixed with a '+' sign. From this field, we can deduce Td, the data
+ transmission time, by substracting other timers when valid :
Td = Tt - (Tq + Tc + Tr)
@@ -1005,7 +1053,9 @@
C : the TCP session was aborted by the client.
S : the TCP session was aborted by the server, or the server refused it.
P : the session was abordted prematurely by the proxy, either because of
- an internal error, or because a DENY filter was matched.
+ an internal error, because a DENY filter was matched, or because of
+ a security check which detected a dangerous error in server
+ response.
c : the client time-out expired first.
s : the server time-out expired first.
- : normal session completion.
@@ -1014,7 +1064,7 @@
R : waiting for complete REQUEST from the client
C : waiting for CONNECTION to establish on the server
- H : waiting for complete HEADERS from the server
+ H : processing server HEADERS
D : the session was in the DATA phase
L : the proxy was still transmitting LAST data to the client while the
server had already finished.
@@ -1073,6 +1123,18 @@
=> long request (6.5s) entered by hand through 'telnet'. The server replied
in 147 ms, and the session ended normally ('----')
+- haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17] relais-http Srv1 9/7/14/+30 200 +243 - - ---- "GET /image.iso HTTP/1.0"
+ => request for a long data transfer. The 'logasap' option was specified, so
+ the log was produced just before transfering data. The server replied in
+ 14 ms, 243 bytes of headers were sent to the client, and total time from
+ accept to first data byte is 30 ms.
+
+- haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17] relais-http Srv1 9/7/14/30 502 243 - - PH-- "GET /cgi-bin/bug.cgi? HTTP/1.0"
+ => the proxy blocked a server response either because of an 'rspdeny' or
+ 'rspideny' filter, or because it blocked sensible information which risked
+ being cached. In this case, the response is replaced with a '502 bad
+ gateway'.
+
- haproxy[18113]: 127.0.0.1:34548 [15/Oct/2003:15:18:55] relais-http <NOSRV> -1/-1/-1/8490 -1 0 - - CR-- ""
=> the client never completed its request and aborted itself ('C---') after
8.5s, while the proxy was waiting for the request headers ('-R--').
@@ -1122,6 +1184,8 @@
rspirep <search> <replace> same, but ignoring the case
rspdel <search> to delete the response
rspidel <search> same, but ignoring the case
+ rspdeny <search> replaces a response with a HTTP 502 if a header matches <search>
+ rspideny <search> same, but ignoring the case
<search> is a POSIX regular expression (regex) which supports grouping through
@@ -1160,6 +1224,9 @@
value is easy to modify in the code if needed (#define). If it is too short
on occasional uses, it is possible to gain some space by removing some
useless headers before adding new ones.
+ - a denied request will generate an "HTTP 403 forbidden" response, while a
+ denied response will generate an "HTTP 502 Bad gateway" response.
+
Examples :
----------
@@ -1195,20 +1262,21 @@
reqideny ^[^:\ ]*\
# force connection:close, thus disabling HTTP keep-alive
- reqidel ^Connection:
- rspidel ^Connection:
- reqadd Connection:\ close
- rspadd Connection:\ close
+ option httpclose
# change the server name
rspidel ^Server:\
rspadd Server:\ Formilux/0.1.8
-Last, the 'forwardfor' option creates an HTTP 'X-Forwarded-For' header which
+Also, the 'forwardfor' option creates an HTTP 'X-Forwarded-For' header which
contains the client's IP address. This is useful to let the final web server
know what the client address was (eg for statistics on domains).
+Last, the 'httpclose' option removes any 'Connection' header both ways, and
+adds a 'Connection: close' header in each direction. This makes it easier to
+disable HTTP keep-alive than the previous 4-rules block..
+
Example :
---------
listen http_proxy 0.0.0.0:80
@@ -1217,10 +1285,10 @@
option httplog
option dontlognull
option forwardfor
+ option httpclose
4.4) Load balancing with persistence
------------------------------------
-
Combining cookie insertion with internal load balancing allows to transparently
bring persistence to applications. The principle is quite simple :
- assign a cookie value to each server
@@ -1239,9 +1307,35 @@
server 192.168.1.1:80 cookie server01 check
server 192.168.1.2:80 cookie server02 check
-4.5) Customizing errors
------------------------
+4.5) Protection against information leak from the servers
+---------------------------------------------------------
+In versions 1.1.28/1.2.1, a new option 'checkcache' was created. It carefully
+checks 'Cache-control', 'Pragma' and 'Set-cookie' headers in server response
+to check if there's a risk of caching a cookie on a client-side proxy. When this
+option is enabled, the only responses which can be delivered to the client are :
+ - all those without 'Set-Cookie' header ;
+ - all those with a return code other than 200, 203, 206, 300, 301, 410,
+ provided that the server has not set a 'Cache-control: public' header ;
+ - all those that come from a POST request, provided that the server has not
+ set a 'Cache-Control: public' header ;
+ - those with a 'Pragma: no-cache' header
+ - those with a 'Cache-control: private' header
+ - those with a 'Cache-control: no-store' header
+ - those with a 'Cache-control: max-age=0' header
+ - those with a 'Cache-control: s-maxage=0' header
+ - those with a 'Cache-control: no-cache' header
+ - those with a 'Cache-control: no-cache="set-cookie"' header
+ - those with a 'Cache-control: no-cache="set-cookie,' header
+ (allowing other fields after set-cookie)
+If a response doesn't respect these requirements, then it will be blocked just
+as if it was from an 'rspdeny' filter, with an "HTTP 502 bad gateway". The
+session state shows "PH--" meaning that the proxy blocked the response during
+headers processing. Additionnaly, an alert will be sent in the logs so that
+admins are told that there's something to be done.
+
+4.6) Customizing errors
+-----------------------
Some situations can make haproxy return an HTTP error code to the client :
- invalid or too long request => HTTP 400
- request not completely sent in time => HTTP 408
@@ -1275,9 +1369,8 @@
errorloc 503 http://192.168.114.58/error50x.html
errorloc 504 http://192.168.114.58/error50x.html
-4.6) Modifying default values
+4.7) Modifying default values
-----------------------------
-
Version 1.1.22 introduced the notion of default values, which eliminates the
pain of often repeating common parameters between many instances, such as
logs, timeouts, modes, etc...
@@ -1290,7 +1383,7 @@
everything on its command line, so that fake instance names can be specified
there for better clarity.
-In version 1.1.23, only those parameters can be preset in the 'default'
+In version 1.1.28/1.2.1, only those parameters can be preset in the 'default'
section :
- log (the first and second one)
- mode { tcp, http, health }
@@ -1298,8 +1391,8 @@
- disabled (to disable every further instances)
- enabled (to enable every further instances, this is the default)
- contimeout, clitimeout, srvtimeout, grace, retries, maxconn
- - option { redispatch, transparent, keepalive, forwardfor, httplog,
- dontlognull, persist, httpchk }
+ - option { redispatch, transparent, keepalive, forwardfor, logasap, httpclose,
+ checkcache, httplog, tcplog, dontlognull, persist, httpchk }
- redispatch, redisp, transparent, source { addr:port }
- cookie, capture
- errorloc
diff --git a/doc/haproxy-fr.txt b/doc/haproxy-fr.txt
index f1b08e8..8416ccb 100644
--- a/doc/haproxy-fr.txt
+++ b/doc/haproxy-fr.txt
@@ -1,9 +1,9 @@
H A - P r o x y
---------------
- version 1.1.27
+ version 1.2.1
willy tarreau
- 2003/10/27
+ 2004/06/06
================
| Introduction |
@@ -37,6 +37,12 @@
-N <nombre maximal de connexions simultanées par proxy>
-d active le mode debug
-D passe en daemon
+ -q désactive l'affichage de messages sur la sortie standard.
+ -V affiche les messages sur la sortie standard, même si -q ou 'quiet' sont
+ spécifiés.
+ -c vérifie le fichier de configuration puis quitte avec un code de retour 0
+ si aucune erreur n'a été trouvée, ou 1 si une erreur de syntaxe a été
+ détectée.
-p <fichier> indique au processus père qu'il doit écrire les PIDs de ses
fils dans ce fichier en mode démon.
-s affiche les statistiques (si option compilée)
@@ -754,6 +760,10 @@
active. C'est une bonne raison pour avoir au moins un serveur de logs local en
niveau notice.
+Depuis la version 1.1.18 (et 1.2.1), un message d'urgence est envoyé dans les
+logs en niveau 'emerg' si tous les serveurs d'une même instance sont tombés,
+afin de notifier l'administrateur qu'il faut prendre une action immédiate.
+
Exemples :
----------
# conf du paragraphe 3) avec surveillance TCP
@@ -937,6 +947,15 @@
sur son état lors de la déconnexion, ainsi que le temps de connexion et la
durée totale de la session.
+Exemple :
+---------
+ listen relais-tcp 0.0.0.0:8000
+ mode tcp
+ option tcplog
+ log 192.168.2.200 local3
+
+>>> haproxy[18989]: 127.0.0.1:34550 [15/Oct/2003:15:24:28] relais-tcp Srv1 0/5007 0 --
+
Une autre option, 'httplog', fournit plus de détails sur le protocole HTTP,
notamment la requête et l'état des cookies. Dans les cas où un mécanisme de
surveillance effectuant des connexions et déconnexions fréquentes, polluerait
@@ -952,6 +971,35 @@
option dontlognull
log 192.168.2.200 local3
+>>> haproxy[674]: 127.0.0.1:33319 [15/Oct/2003:08:31:57] relais-http Srv1 9/7/147/723 200 243 - - ---- "HEAD / HTTP/1.0"
+
+Le problème de loguer uniquement en fin de session, c'est qu'il est impossible
+de savoir ce qui se passe durant de gros transferts ou des sessions longues.
+Pour pallier à ce problème, une nouvelle option 'logasap' a été introduite dans
+la version 1.1.28 (1.2.1). Lorsqu'elle est activée, le proxy loguera le plus tôt
+possible, c'est à dire juste avant que ne débutent les transferts de données.
+Cela signifie, dans le cas du TCP, qu'il loguera toujours le résultat de la
+connexion vers le serveur, et dans le cas HTTP, qu'il loguera en fin de
+traitement des entêtes de la réponse du serveur, auquel cas le nombre d'octets
+représentera la taille des entêtes retournés au client.
+
+Afin d'éviter toute confusion avec les logs normaux, le temps total de transfert
+et le nombre d'octets transférés sont préfixés d'un signe '+' rappeleant que les
+valeurs réelles sont certainement plus élevées.
+
+Exemple :
+---------
+
+ listen http_proxy 0.0.0.0:80
+ mode http
+ option httplog
+ option dontlognull
+ option logasap
+ log 192.168.2.200 local3
+
+>>> haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17] relais-http Srv1 9/7/14/+30 200 +243 - - ---- "GET /image.iso HTTP/1.0"
+
+
4.2.3) Chronométrage des événements
-----------------------------------
Pour déceler des problèmes réseau, les mesures du temps écoulé entre certains
@@ -980,8 +1028,11 @@
- Tt: durée de vie totale de la session, entre le moment où la demande de
connexion du client a été acquittée et le moment où la connexion a été
- refermée aux deux extrémités (client et serveur). On peut donc en déduire
- Td, le temps de transfert des données, en excluant les autres temps :
+ refermée aux deux extrémités (client et serveur). La signification change
+ un peu si l'option 'logasap' est présente. Dans ce cas, le temps correspond
+ uniquement à (Tq + Tc + Tr), et se trouve préfixé d'un signe '+'. On peut
+ donc déduire Td, le temps de transfert des données, en excluant les autres
+ temps :
Td = Tt - (Tq + Tc + Tr)
@@ -1032,7 +1083,9 @@
C : fermeture de la session TCP de la part du client
S : fermeture de la session TCP de la part du serveur, ou refus de connexion
P : terminaison prématurée des sessions par le proxy, pour cas d'erreur
- interne ou de configuration (ex: filtre d'URL)
+ interne, de configuration (ex: filtre d'URL), ou parce qu'un
+ contrôle de sécurité a détecté une anomalie dans la réponse du
+ serveur.
c : expiration du délai d'attente côté client : clitimeout
s : expiration du délai d'attente côté serveur: srvtimeout et contimeout
- : terminaison normale.
@@ -1042,7 +1095,7 @@
R : terminaison en attendant la réception totale de la requête du client
C : terminaison en attendant la connexion vers le serveur
- H : terminaison en attendant la réception totale des entêtes du serveur
+ H : terminaison en traitant les entêtes du serveur
D : terminaison durant le transfert des données du serveur vers le client
L : terminaison durant le transfert des dernières données du proxy vers
le client, alors que le serveur a déjà fini.
@@ -1107,6 +1160,18 @@
=> requête longue (6.5s) saisie à la main avec un client telnet. Le serveur a
répondu en 147 ms et la session s'est terminée normalement ('----')
+- haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17] relais-http Srv1 9/7/14/+30 200 +243 - - ---- "GET /image.iso HTTP/1.0"
+ => requête pour un long transfert. L'option 'logasap' était spécifiée donc le
+ log a été généré juste avant le transfert de données. Le serveur a répondu
+ en 14 ms, 243 octets d'entêtes ont été transférés au client, et le temps
+ total entre l'accept() et le premier octet de donnée est de 30 ms.
+
+- haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17] relais-http Srv1 9/7/14/30 502 243 - - PH-- "GET /cgi-bin/bug.cgi? HTTP/1.0"
+ => le proxy a bloqué une réponse du serveur soit à cause d'un filtre 'rspdeny'
+ ou 'rspideny', soit parce qu'il a détecté un risque de fuite sensible
+ d'informations risquant d'être cachées. Dans ce cas, la réponse est
+ remplacée par '502 bad gateway'.
+
- haproxy[18113]: 127.0.0.1:34548 [15/Oct/2003:15:18:55] relais-http <NOSRV> -1/-1/-1/8490 -1 0 - - CR-- ""
=> Le client n'a pas envoyé sa requête et a refermé la connexion lui-même
('C---') au bout de 8.5s, alors que le relais attendait l'entête ('-R--').
@@ -1155,6 +1220,9 @@
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
+ rspdeny <search> remplace la réponse par un HTTP 502 si un
+ entête valide <search>
+ rspideny <search> idem sans distinction majuscules/minuscules
<search> est une expression régulière compatible POSIX regexp supportant le
@@ -1195,6 +1263,8 @@
limite était à 256 auparavant). Cette valeur est modifiable dans le code.
Pour un usage temporaire, on peut gagner de la place en supprimant quelques
entêtes inutiles avant les ajouts.
+ - une requête bloquée produira une réponse "HTTP 403 forbidden" tandis qu'une
+ réponse bloquée produira une réponse "HTTP 502 Bad gateway".
Exemples :
----------
@@ -1230,20 +1300,22 @@
reqideny ^[^:\ ]*\
# force connection:close, thus disabling HTTP keep-alive
- reqidel ^Connection:
- rspidel ^Connection:
- reqadd Connection:\ close
- rspadd Connection:\ close
+ option httpclos
# change the server name
rspidel ^Server:\
rspadd Server:\ Formilux/0.1.8
-Enfin, l'option 'forwardfor' ajoute l'adresse IP du client dans un champ
+De plus, 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.
+Enfin, l'option 'httpclose' apparue dans la version 1.1.28/1.2.1 supprime tout
+entête de type 'Connection:' et ajoute 'Connection: close' dans les deux sens.
+Ceci simplifie la désactivation du keep-alive HTTP par rapport à l'ancienne
+méthode impliquant 4 règles.
+
Exemple :
---------
listen http_proxy 0.0.0.0:80
@@ -1252,10 +1324,10 @@
option httplog
option dontlognull
option forwardfor
+ option httpclose
4.4) Répartition avec persistence
---------------------------------
-
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
pratiquement transparente pour les applications. Le principe est simple :
@@ -1274,9 +1346,37 @@
server 192.168.1.1:80 cookie server01 check
server 192.168.1.2:80 cookie server02 check
-4.5) Personalisation des erreurs
---------------------------------
+4.5) Protection contre les fuites d'informations du serveur
+-----------------------------------------------------------
+Dans les versions 1.1.28 et 1.2.1, une nouvelle option 'checkcache' a été créée.
+Elle sert à inspecter minutieusement les entêtes 'Cache-control', 'Pragma', et
+'Set-cookie' dans les réponses serveur pour déterminer s'il y a un risque de
+cacher un cookie sur un proxy côté client. Quand cette option est activée, les
+seules réponses qui peuvent être retournées au client sont :
+ - toutes celles qui n'ont pas d'entête 'Set-cookie' ;
+ - toutes celles qui ont un code de retour autre que 200, 203, 206, 300, 301,
+ 410, sauf si le server a positionné un entête 'Cache-control: public' ;
+ - celles qui font suite à une requête POST, sauf si le serveur a positionné
+ un entête 'Cache-control: public' ;
+ - celles qui ont un entête 'Pragma: no-cache' ;
+ - celles qui ont un entête 'Cache-control: private' ;
+ - celles qui ont un entête 'Cache-control: no-store' ;
+ - celles qui ont un entête 'Cache-control: max-age=0' ;
+ - celles qui ont un entête 'Cache-control: s-maxage=0' ;
+ - celles qui ont un entête 'Cache-control: no-cache' ;
+ - celles qui ont un entête 'Cache-control: no-cache="set-cookie"' ;
+ - celles qui ont un entête 'Cache-control: no-cache="set-cookie,'
+ (autorisant d'autres champs après set-cookie).
+Si une réponse ne respecte pas ces pré-requis, alors elle sera bloquée de la
+même manière que s'il s'agissait d'un filtre 'rspdeny', avec en retour un
+message "HTTP 502 bad gateway". L'état de session montre "PH--" ce qui veut
+dire que c'est le proxy qui a bloqué la réponse durant le traitement des
+entêtes. De plus, un message d'alerte sera envoyé dans les logs de sorte que
+l'administrateur sache qu'il y a une action correctrice à entreprendre.
+
+4.6) Personalisation des erreurs
+--------------------------------
Certaines situations conduisent à retourner une erreur HTTP au client :
- requête invalide ou trop longue => code HTTP 400
- requête mettant trop de temps à venir => code HTTP 408
@@ -1309,9 +1409,8 @@
errorloc 503 http://192.168.114.58/error50x.html
errorloc 504 http://192.168.114.58/error50x.html
-4.6) Changement des valeurs par défaut
+4.7) Changement des valeurs par défaut
--------------------------------------
-
Dans la version 1.1.22 est apparue la notion de valeurs par défaut, ce qui évite
de répéter des paramètres communs à toutes les instances, tels que les timeouts,
adresses de log, modes de fonctionnement, etc.
@@ -1326,16 +1425,16 @@
paramètres près qui ne sont pas supportés. Le mot clé 'defaults' peut accepter
un commentaire en guise paramètre.
-Dans la version 1.1.23, seuls les paramètres suivants peuvent être positionnés
-dans une section 'defaults' :
+Dans la version 1.1.28/1.2.1, seuls les paramètres suivants peuvent être
+positionnés dans une section 'defaults' :
- log (le premier et le second)
- mode { tcp, http, health }
- balance { roundrobin }
- disabled (pour désactiver toutes les instances qui suivent)
- enabled (pour faire l'opération inverse, mais c'est le cas par défaut)
- contimeout, clitimeout, srvtimeout, grace, retries, maxconn
- - option { redispatch, transparent, keepalive, forwardfor, httplog,
- dontlognull, persist, httpchk }
+ - option { redispatch, transparent, keepalive, forwardfor, logasap, httpclose,
+ checkcache, httplog, tcplog, dontlognull, persist, httpchk }
- redispatch, redisp, transparent, source { addr:port }
- cookie, capture
- errorloc
diff --git a/examples/haproxy.cfg b/examples/haproxy.cfg
index 705c93e..ae72150 100644
--- a/examples/haproxy.cfg
+++ b/examples/haproxy.cfg
@@ -1,13 +1,13 @@
-# this config needs haproxy-1.1.23
+# this config needs haproxy-1.1.28 or haproxy-1.2.1
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
#log loghost local0 info
maxconn 4096
- chroot /tmp
- uid 11
- gid 2
+ chroot /usr/share/haproxy
+ uid 99
+ gid 99
daemon
#debug
#quiet
@@ -40,10 +40,7 @@
server inst2 192.168.114.56:81 cookie server02 check inter 2000 fall 3
capture cookie vgnvisitor= len 32
- reqidel ^Connection: # disable keep-alive
- reqadd Connection:\ close
- rspidel ^Connection:
- rspadd Connection:\ close
+ option httpclose # disable keep-alive
rspidel ^Set-cookie:\ IP= # do not let this cookie tell our internal IP address
listen appli3-relais 0.0.0.0:10003
@@ -66,10 +63,9 @@
capture cookie ASPSESSION len 32
srvtimeout 20000
- reqidel ^Connection: # disable keep-alive
- reqadd Connection:\ close
- rspidel ^Connection:
- rspadd Connection:\ close
+ option httpclose # disable keep-alive
+ option checkcache # block response if set-cookie & cacheable
+
rspidel ^Set-cookie:\ IP= # do not let this cookie tell our internal IP address
errorloc 502 http://192.168.114.58/error502.html
diff --git a/examples/haproxy.init b/examples/haproxy.init
new file mode 100644
index 0000000..55caa25
--- /dev/null
+++ b/examples/haproxy.init
@@ -0,0 +1,114 @@
+#!/bin/sh
+#
+# chkconfig: - 85 15
+# description: HA-Proxy is a TCP/HTTP reverse proxy which is particularly suited \
+# for high availability environments.
+# processname: haproxy
+# config: /etc/haproxy/haproxy.cfg
+# pidfile: /var/run/haproxy.pid
+
+# Script Author: Simon Matter <simon.matter@invoca.ch>
+# Version: 2004060600
+
+# Source function library.
+if [ -f /etc/init.d/functions ]; then
+ . /etc/init.d/functions
+elif [ -f /etc/rc.d/init.d/functions ] ; then
+ . /etc/rc.d/init.d/functions
+else
+ exit 0
+fi
+
+# Source networking configuration.
+. /etc/sysconfig/network
+
+# Check that networking is up.
+[ ${NETWORKING} = "no" ] && exit 0
+
+# This is our service name
+BASENAME=`basename $0`
+if [ -L $0 ]; then
+ BASENAME=`find $0 -name $BASENAME -printf %l`
+ BASENAME=`basename $BASENAME`
+fi
+
+[ -f /etc/$BASENAME/$BASENAME.cfg ] || exit 1
+
+RETVAL=0
+
+start() {
+ /usr/sbin/$BASENAME -c -q -f /etc/$BASENAME/$BASENAME.cfg
+ if [ $? -ne 0 ]; then
+ echo "Errors found in configuration file, check it with '$BASENAME check'."
+ return 1
+ fi
+
+ echo -n "Starting $BASENAME: "
+ daemon /usr/sbin/$BASENAME -D -f /etc/$BASENAME/$BASENAME.cfg -p /var/run/$BASENAME.pid
+ RETVAL=$?
+ echo
+ [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$BASENAME
+ return $RETVAL
+}
+
+stop() {
+ echo -n "Shutting down $BASENAME: "
+ killproc $BASENAME -USR1
+ RETVAL=$?
+ echo
+ [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$BASENAME
+ [ $RETVAL -eq 0 ] && rm -f /var/run/$BASENAME.pid
+ return $RETVAL
+}
+
+restart() {
+ /usr/sbin/$BASENAME -c -q -f /etc/$BASENAME/$BASENAME.cfg
+ if [ $? -ne 0 ]; then
+ echo "Errors found in configuration file, check it with '$BASENAME check'."
+ return 1
+ fi
+ stop
+ start
+}
+
+check() {
+ /usr/sbin/$BASENAME -c -q -V -f /etc/$BASENAME/$BASENAME.cfg
+}
+
+rhstatus() {
+ status $BASENAME
+}
+
+condrestart() {
+ [ -e /var/lock/subsys/$BASENAME ] && restart || :
+}
+
+# See how we were called.
+case "$1" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart)
+ restart
+ ;;
+ reload)
+ restart
+ ;;
+ condrestart)
+ condrestart
+ ;;
+ status)
+ rhstatus
+ ;;
+ check)
+ check
+ ;;
+ *)
+ echo $"Usage: $BASENAME {start|stop|restart|reload|condrestart|status|check}"
+ RETVAL=1
+esac
+
+exit $RETVAL
diff --git a/examples/haproxy.spec b/examples/haproxy.spec
new file mode 100644
index 0000000..63ef708
--- /dev/null
+++ b/examples/haproxy.spec
@@ -0,0 +1,92 @@
+Summary: HA-Proxy is a TCP/HTTP reverse proxy for high availability environments
+Name: haproxy
+Version: 1.2.1
+Release: 1
+License: GPL
+Group: System Environment/Daemons
+URL: http://w.ods.org/tools/%{name}/
+Packager: Simon Matter <simon.matter@invoca.ch>
+Vendor: Invoca Systems
+Distribution: Invoca Linux Server
+Source0: http://w.ods.org/tools/%{name}/%{name}-%{version}.tar.gz
+Source1: %{name}.cfg
+Source2: %{name}.init
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+BuildRequires: pcre-devel
+Prereq: /sbin/chkconfig
+
+%description
+HA-Proxy is a TCP/HTTP reverse proxy which is particularly suited for high
+availability environments. Indeed, it can:
+- route HTTP requests depending on statically assigned cookies
+- spread the load among several servers while assuring server persistence
+ through the use of HTTP cookies
+- switch to backup servers in the event a main one fails
+- accept connections to special ports dedicated to service monitoring
+- stop accepting connections without breaking existing ones
+- add/modify/delete HTTP headers both ways
+- block requests matching a particular pattern
+
+It needs very little resource. Its event-driven architecture allows it to easily
+handle thousands of simultaneous connections on hundreds of instances without
+risking the system's stability.
+
+%prep
+%setup -q
+
+%build
+%{__make} REGEX=pcre DEBUG=""
+
+%install
+[ "%{buildroot}" != "/" ] && %{__rm} -rf %{buildroot}
+
+%{__install} -d %{buildroot}%{_sbindir}
+%{__install} -d %{buildroot}%{_sysconfdir}/rc.d/init.d
+%{__install} -d %{buildroot}%{_sysconfdir}/logrotate.d
+%{__install} -d %{buildroot}%{_sysconfdir}/%{name}
+%{__install} -d %{buildroot}%{_datadir}/%{name}
+
+%{__install} -s %{name} %{buildroot}%{_sbindir}/
+%{__install} -c -m 644 %{SOURCE1} %{buildroot}%{_sysconfdir}/%{name}/
+%{__install} -c -m 755 %{SOURCE2} %{buildroot}%{_sysconfdir}/rc.d/init.d/%{name}
+
+%clean
+[ "%{buildroot}" != "/" ] && %{__rm} -rf %{buildroot}
+
+%post
+/sbin/chkconfig --add %{name}
+
+%preun
+if [ $1 = 0 ]; then
+ /sbin/service %{name} stop >/dev/null 2>&1 || :
+ /sbin/chkconfig --del %{name}
+fi
+
+%postun
+if [ "$1" -ge "1" ]; then
+ /sbin/service %{name} condrestart >/dev/null 2>&1 || :
+fi
+
+%files
+%defattr(-,root,root)
+%doc CHANGELOG TODO examples
+%attr(0755,root,root) %{_sbindir}/%{name}
+%dir %{_sysconfdir}/%{name}
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/%{name}/%{name}.cfg
+%attr(0755,root,root) %config %{_sysconfdir}/rc.d/init.d/%{name}
+%dir %{_datadir}/%{name}
+
+%changelog
+* Sun Jun 6 2004 Willy Tarreau <willy@w.ods.org>
+- updated to 1.1.28
+- added config check support to the init script
+
+* Tue Oct 28 2003 Simon Matter <simon.matter@invoca.ch>
+- updated to 1.1.27
+- added pid support to the init script
+
+* Wed Oct 22 2003 Simon Matter <simon.matter@invoca.ch>
+- updated to 1.1.26
+
+* Thu Oct 16 2003 Simon Matter <simon.matter@invoca.ch>
+- initial build
diff --git a/examples/init.haproxy.flx0 b/examples/init.haproxy.flx0
index 4b73bd8..a7edd9c 100644
--- a/examples/init.haproxy.flx0
+++ b/examples/init.haproxy.flx0
@@ -7,7 +7,7 @@
option cmdline reserved_option '$bin -f ${opt_config} -p ${pidfile} -D -q'
function do_help {
- echo "Usage: ${0##*/} <status|start|stop|help>"
+ echo "Usage: ${0##*/} <status|start|stop|help|conf>"
echo "List of config.rc options (name, type, default value, current value) :"
echo
echo " - config ; def=/etc/haproxy/haproxy.cfg ; cur=$opt_confdir"
@@ -15,6 +15,11 @@
exit 1
}
+# reads the configuration file and checks its syntax.
+function do_conf {
+ $bin -c -V -q -f ${opt_config}
+}
+
# assign default values to options and variables before parsing the cfg file
function fct_begin_section {
pidfile="/var/run/haproxy${2:+-$2}.pid"
diff --git a/haproxy.c b/haproxy.c
index 63e0b79..c96aae4 100644
--- a/haproxy.c
+++ b/haproxy.c
@@ -8,7 +8,10 @@
* 2 of the License, or (at your option) any later version.
*
* Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
- * RFC2965 for informations about cookies usage.
+ * RFC2965 for informations about cookies usage. More generally, the IETF HTTP
+ * Working Group's web site should be consulted for protocol related changes :
+ *
+ * http://ftp.ics.uci.edu/pub/ietf/http/
*
* Pending bugs (may be not fixed because never reproduced) :
* - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
@@ -54,7 +57,7 @@
#endif
#define HAPROXY_VERSION "1.2.1"
-#define HAPROXY_DATE "2004/06/05"
+#define HAPROXY_DATE "2004/06/06"
/* this is for libc5 for example */
#ifndef TCP_NODELAY
@@ -300,6 +303,7 @@
#define MODE_DAEMON 8
#define MODE_QUIET 16
#define MODE_CHECK 32
+#define MODE_VERBOSE 64
/* server flags */
#define SRV_RUNNING 1 /* the server is UP */
@@ -684,13 +688,14 @@
void usage(char *name) {
display_version();
fprintf(stderr,
- "Usage : %s -f <cfgfile> [ -vd"
+ "Usage : %s -f <cfgfile> [ -vdV"
#if STATTIME > 0
"sl"
#endif
"D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
" -v displays version\n"
" -d enters debug mode\n"
+ " -V enters verbose mode (disables quiet mode)\n"
#if STATTIME > 0
" -s enables statistics output\n"
" -l enables long statistics format\n"
@@ -714,7 +719,7 @@
struct timeval tv;
struct tm *tm;
- if (!(global.mode & MODE_QUIET)) {
+ if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
va_start(argp, fmt);
gettimeofday(&tv, NULL);
@@ -736,7 +741,7 @@
struct timeval tv;
struct tm *tm;
- if (!(global.mode & MODE_QUIET)) {
+ if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
va_start(argp, fmt);
gettimeofday(&tv, NULL);
@@ -755,7 +760,7 @@
void qfprintf(FILE *out, char *fmt, ...) {
va_list argp;
- if (!(global.mode & MODE_QUIET)) {
+ if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
va_start(argp, fmt);
vfprintf(out, fmt, argp);
fflush(out);
@@ -2100,9 +2105,6 @@
s->req = s->rep = NULL; /* will be allocated later */
s->flags = 0;
- if (p->options & PR_O_CHK_CACHE)
- s->flags |= SN_CACHEABLE | SN_CACHE_COOK;
-
s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
s->cli_fd = cfd;
s->srv_fd = -1;
@@ -2165,7 +2167,7 @@
}
}
- if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
+ if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
struct sockaddr_in sockname;
int namelen;
int len;
@@ -2525,8 +2527,10 @@
if (t->proxy->options & PR_O_HTTP_CLOSE)
buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
- if (!memcmp(req->data, "POST ", 5))
- t->flags |= SN_POST; /* this is a POST request */
+ if (!memcmp(req->data, "POST ", 5)) {
+ /* this is a POST request, which is not cacheable by default */
+ t->flags |= SN_POST;
+ }
t->cli_state = CL_STDATA;
req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
@@ -2608,7 +2612,7 @@
delete_header = 0;
- if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
+ if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
int len, max;
len = sprintf(trash, "%08x:%s.clihdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
max = ptr - req->h;
@@ -3085,7 +3089,7 @@
return 0;
}
else { /* CL_STCLOSE: nothing to do */
- if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
+ if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
int len;
len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
write(1, trash, len);
@@ -3288,6 +3292,21 @@
}
}
+ /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
+ if (t->flags & SN_SVDENY) {
+ tv_eternity(&t->srexpire);
+ tv_eternity(&t->swexpire);
+ fd_delete(t->srv_fd);
+ t->srv_state = SV_STCLOSE;
+ t->logs.status = 502;
+ client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
+ if (!(t->flags & SN_ERR_MASK))
+ t->flags |= SN_ERR_PRXCOND;
+ if (!(t->flags & SN_FINST_MASK))
+ t->flags |= SN_FINST_H;
+ return 1;
+ }
+
/* we'll have something else to do here : add new headers ... */
if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
@@ -3366,14 +3385,38 @@
*/
- if (t->logs.logwait & LW_RESP) {
+ if (t->logs.status == -1) {
t->logs.logwait &= ~LW_RESP;
t->logs.status = atoi(rep->h + 9);
+ switch (t->logs.status) {
+ case 200:
+ case 203:
+ case 206:
+ case 300:
+ case 301:
+ case 410:
+ /* RFC2616 @13.4:
+ * "A response received with a status code of
+ * 200, 203, 206, 300, 301 or 410 MAY be stored
+ * by a cache (...) unless a cache-control
+ * directive prohibits caching."
+ *
+ * RFC2616 @9.5: POST method :
+ * "Responses to this method are not cacheable,
+ * unless the response includes appropriate
+ * Cache-Control or Expires header fields."
+ */
+ if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
+ t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
+ break;
+ default:
+ break;
+ }
}
delete_header = 0;
- if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
+ if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
int len, max;
len = sprintf(trash, "%08x:%s.srvhdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
max = ptr - rep->h;
@@ -3434,21 +3477,27 @@
t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
- if (rep->h + 23 == ptr || rep->h[23] == ';')
+ if (rep->h + 23 == ptr || rep->h[23] == ',')
t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
else {
if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
- && (rep->h[35] == '"' || rep->h[35] == ';'))
+ && (rep->h[35] == '"' || rep->h[35] == ','))
t->flags &= ~SN_CACHE_COOK;
}
} else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
- (rep->h + 22 == ptr || rep->h[22] == ';'))
+ (rep->h + 22 == ptr || rep->h[22] == ','))
|| (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
- (rep->h + 23 == ptr || rep->h[23] == ';'))) {
+ (rep->h + 23 == ptr || rep->h[23] == ','))) {
t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
} else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
- (rep->h + 24 == ptr || rep->h[24] == ';')) {
+ (rep->h + 24 == ptr || rep->h[24] == ',')) {
t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
+ } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
+ (rep->h + 25 == ptr || rep->h[25] == ',')) {
+ t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
+ } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
+ (rep->h + 21 == ptr || rep->h[21] == ',')) {
+ t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
}
}
}
@@ -3869,7 +3918,7 @@
return 0;
}
else { /* SV_STCLOSE : nothing to do */
- if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
+ if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
int len;
len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
write(1, trash, len);
@@ -3916,7 +3965,7 @@
s->proxy->nbconn--;
actconn--;
- if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
+ if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
int len;
len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n", s->uniq_id, s->proxy->id, (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
write(1, trash, len);
@@ -5436,6 +5485,26 @@
chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
}
+ else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
+ regex_t *preg;
+ if (curproxy == &defproxy) {
+ Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
+ return -1;
+ }
+
+ if (*(args[1]) == 0) {
+ Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
+ return -1;
+ }
+
+ preg = calloc(1, sizeof(regex_t));
+ if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
+ Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
+ return -1;
+ }
+
+ chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
+ }
else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
regex_t *preg;
if (curproxy == &defproxy) {
@@ -5477,6 +5546,26 @@
chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
}
+ else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
+ regex_t *preg;
+ if (curproxy == &defproxy) {
+ Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
+ return -1;
+ }
+
+ if (*(args[1]) == 0) {
+ Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
+ return -1;
+ }
+
+ preg = calloc(1, sizeof(regex_t));
+ if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
+ Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
+ return -1;
+ }
+
+ chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
+ }
else if (!strcmp(args[0], "rspadd")) { /* add response header */
if (curproxy == &defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@@ -5830,7 +5919,7 @@
if (1<<INTBITS != sizeof(int)*8) {
fprintf(stderr,
"Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
- sizeof(int)*8);
+ (int)(sizeof(int)*8));
exit(1);
}
@@ -5851,6 +5940,8 @@
display_version();
exit(0);
}
+ else if (*flag == 'V')
+ arg_mode |= MODE_VERBOSE;
else if (*flag == 'd')
arg_mode |= MODE_DEBUG;
else if (*flag == 'c')
@@ -5884,7 +5975,7 @@
argv++; argc--;
}
- global.mode = (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG));
+ global.mode = (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
if (!cfg_cfgfile)
usage(old_argv);
@@ -5896,7 +5987,7 @@
exit(1);
}
- if (arg_mode & MODE_CHECK) {
+ if (global.mode & MODE_CHECK) {
qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
exit(0);
}
@@ -5919,7 +6010,8 @@
/* command line debug mode inhibits configuration mode */
global.mode &= ~(MODE_DAEMON | MODE_QUIET);
}
- global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
+ global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
+ | MODE_DEBUG | MODE_STATS | MODE_LOG));
if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");