blob: 53c900a697b1971af2c326d61503cb7f1df54ffb [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Configuration parser
3 *
Willy Tarreau0b4ed902007-03-26 00:18:40 +02004 * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <netdb.h>
17#include <ctype.h>
Willy Tarreau95c20ac2007-03-25 15:39:23 +020018#include <pwd.h>
19#include <grp.h>
Willy Tarreau0b4ed902007-03-26 00:18:40 +020020#include <errno.h>
Willy Tarreau3f49b302007-06-11 00:29:26 +020021#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24#include <unistd.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020025
Willy Tarreau2dd0d472006-06-29 17:53:05 +020026#include <common/cfgparse.h>
27#include <common/config.h>
28#include <common/memory.h>
29#include <common/standard.h>
30#include <common/time.h>
31#include <common/uri_auth.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020032
33#include <types/capture.h>
34#include <types/global.h>
Willy Tarreau0f772532006-12-23 20:51:41 +010035#include <types/httperr.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020036#include <types/polling.h>
37#include <types/proxy.h>
38#include <types/queue.h>
39
Willy Tarreaueb0c6142007-05-07 00:53:22 +020040#include <proto/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020041#include <proto/backend.h>
Willy Tarreau0f772532006-12-23 20:51:41 +010042#include <proto/buffers.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020043#include <proto/checks.h>
Willy Tarreau0f772532006-12-23 20:51:41 +010044#include <proto/httperr.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020045#include <proto/log.h>
Willy Tarreau2b5652f2006-12-31 17:46:05 +010046#include <proto/proxy.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020047#include <proto/server.h>
48#include <proto/task.h>
49
50
Willy Tarreauf3c69202006-07-09 16:42:34 +020051/* This is the SSLv3 CLIENT HELLO packet used in conjunction with the
52 * ssl-hello-chk option to ensure that the remote server speaks SSL.
53 *
54 * Check RFC 2246 (TLSv1.0) sections A.3 and A.4 for details.
55 */
56const char sslv3_client_hello_pkt[] = {
57 "\x16" /* ContentType : 0x16 = Hanshake */
58 "\x03\x00" /* ProtocolVersion : 0x0300 = SSLv3 */
59 "\x00\x79" /* ContentLength : 0x79 bytes after this one */
60 "\x01" /* HanshakeType : 0x01 = CLIENT HELLO */
61 "\x00\x00\x75" /* HandshakeLength : 0x75 bytes after this one */
62 "\x03\x00" /* Hello Version : 0x0300 = v3 */
63 "\x00\x00\x00\x00" /* Unix GMT Time (s) : filled with <now> (@0x0B) */
64 "HAPROXYSSLCHK\nHAPROXYSSLCHK\n" /* Random : must be exactly 28 bytes */
65 "\x00" /* Session ID length : empty (no session ID) */
66 "\x00\x4E" /* Cipher Suite Length : 78 bytes after this one */
67 "\x00\x01" "\x00\x02" "\x00\x03" "\x00\x04" /* 39 most common ciphers : */
68 "\x00\x05" "\x00\x06" "\x00\x07" "\x00\x08" /* 0x01...0x1B, 0x2F...0x3A */
69 "\x00\x09" "\x00\x0A" "\x00\x0B" "\x00\x0C" /* This covers RSA/DH, */
70 "\x00\x0D" "\x00\x0E" "\x00\x0F" "\x00\x10" /* various bit lengths, */
71 "\x00\x11" "\x00\x12" "\x00\x13" "\x00\x14" /* SHA1/MD5, DES/3DES/AES... */
72 "\x00\x15" "\x00\x16" "\x00\x17" "\x00\x18"
73 "\x00\x19" "\x00\x1A" "\x00\x1B" "\x00\x2F"
74 "\x00\x30" "\x00\x31" "\x00\x32" "\x00\x33"
75 "\x00\x34" "\x00\x35" "\x00\x36" "\x00\x37"
76 "\x00\x38" "\x00\x39" "\x00\x3A"
77 "\x01" /* Compression Length : 0x01 = 1 byte for types */
78 "\x00" /* Compression Type : 0x00 = NULL compression */
79};
80
Willy Tarreau13943ab2006-12-31 00:24:10 +010081/* some of the most common options which are also the easiest to handle */
82static const struct {
83 const char *name;
84 unsigned int val;
85 unsigned int cap;
Willy Tarreau4fee4e92007-01-06 21:09:17 +010086 unsigned int checks;
Willy Tarreau13943ab2006-12-31 00:24:10 +010087} cfg_opts[] =
88{
89#ifdef TPROXY
90 { "transparent", PR_O_TRANSP, PR_CAP_FE },
91#endif
Willy Tarreau4fee4e92007-01-06 21:09:17 +010092 { "redispatch", PR_O_REDISP, PR_CAP_BE, 0 },
93 { "keepalive", PR_O_KEEPALIVE, PR_CAP_NONE, 0 },
Willy Tarreau4fee4e92007-01-06 21:09:17 +010094 { "httpclose", PR_O_HTTP_CLOSE, PR_CAP_FE | PR_CAP_BE, 0 },
Alexandre Cassen87ea5482007-10-11 20:48:58 +020095 { "nolinger", PR_O_TCP_NOLING, PR_CAP_FE | PR_CAP_BE, 0 },
Willy Tarreau4fee4e92007-01-06 21:09:17 +010096 { "logasap", PR_O_LOGASAP, PR_CAP_FE, 0 },
97 { "abortonclose", PR_O_ABRT_CLOSE, PR_CAP_BE, 0 },
98 { "checkcache", PR_O_CHK_CACHE, PR_CAP_BE, 0 },
99 { "dontlognull", PR_O_NULLNOLOG, PR_CAP_FE, 0 },
100 { "clitcpka", PR_O_TCP_CLI_KA, PR_CAP_FE, 0 },
101 { "srvtcpka", PR_O_TCP_SRV_KA, PR_CAP_BE, 0 },
102 { "allbackups", PR_O_USE_ALL_BK, PR_CAP_BE, 0 },
103 { "persist", PR_O_PERSIST, PR_CAP_BE, 0 },
104 { "forceclose", PR_O_FORCE_CLO | PR_O_HTTP_CLOSE, PR_CAP_BE, 0 },
Willy Tarreau8f922fc2007-01-06 21:11:49 +0100105#ifdef CONFIG_HAP_TCPSPLICE
106 { "tcpsplice", PR_O_TCPSPLICE , PR_CAP_BE|PR_CAP_FE, LSTCHK_TCPSPLICE|LSTCHK_NETADM },
107#endif
108
Willy Tarreau13943ab2006-12-31 00:24:10 +0100109 { NULL, 0, 0 }
110};
111
Willy Tarreaubaaee002006-06-26 02:48:02 +0200112
113static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
114int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
115int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
116
117/*
118 * converts <str> to a list of listeners which are dynamically allocated.
119 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
120 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
121 * - <port> is a numerical port from 1 to 65535 ;
122 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
123 * This can be repeated as many times as necessary, separated by a coma.
124 * The <tail> argument is a pointer to a current list which should be appended
125 * to the tail of the new list. The pointer to the new list is returned.
126 */
127static struct listener *str2listener(char *str, struct listener *tail)
128{
129 struct listener *l;
130 char *c, *next, *range, *dupstr;
131 int port, end;
132
133 next = dupstr = strdup(str);
134
135 while (next && *next) {
136 struct sockaddr_storage ss;
137
138 str = next;
139 /* 1) look for the end of the first address */
140 if ((next = strrchr(str, ',')) != NULL) {
141 *next++ = 0;
142 }
143
144 /* 2) look for the addr/port delimiter, it's the last colon. */
145 if ((range = strrchr(str, ':')) == NULL) {
146 Alert("Missing port number: '%s'\n", str);
147 goto fail;
148 }
149
150 *range++ = 0;
151
152 if (strrchr(str, ':') != NULL) {
153 /* IPv6 address contains ':' */
154 memset(&ss, 0, sizeof(ss));
155 ss.ss_family = AF_INET6;
156
157 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
158 Alert("Invalid server address: '%s'\n", str);
159 goto fail;
160 }
161 }
162 else {
163 memset(&ss, 0, sizeof(ss));
164 ss.ss_family = AF_INET;
165
166 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
167 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
168 }
169 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
170 struct hostent *he;
171
172 if ((he = gethostbyname(str)) == NULL) {
173 Alert("Invalid server name: '%s'\n", str);
174 goto fail;
175 }
176 else
177 ((struct sockaddr_in *)&ss)->sin_addr =
178 *(struct in_addr *) *(he->h_addr_list);
179 }
180 }
181
182 /* 3) look for the port-end delimiter */
183 if ((c = strchr(range, '-')) != NULL) {
184 *c++ = 0;
185 end = atol(c);
186 }
187 else {
188 end = atol(range);
189 }
190
191 port = atol(range);
192
193 if (port < 1 || port > 65535) {
194 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
195 goto fail;
196 }
197
198 if (end < 1 || end > 65535) {
199 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
200 goto fail;
201 }
202
203 for (; port <= end; port++) {
204 l = (struct listener *)calloc(1, sizeof(struct listener));
205 l->next = tail;
206 tail = l;
207
208 l->fd = -1;
209 l->addr = ss;
210 if (ss.ss_family == AF_INET6)
211 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
212 else
213 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
214
215 } /* end for(port) */
216 } /* end while(next) */
217 free(dupstr);
218 return tail;
219 fail:
220 free(dupstr);
221 return NULL;
222}
223
Willy Tarreau977b8e42006-12-29 14:19:17 +0100224/*
225 * Sends a warning if proxy <proxy> does not have at least one of the
226 * capabilities in <cap>. An optionnal <hint> may be added at the end
227 * of the warning to help the user. Returns 1 if a warning was emitted
228 * or 0 if the condition is valid.
229 */
230int warnifnotcap(struct proxy *proxy, int cap, const char *file, int line, char *arg, char *hint)
231{
232 char *msg;
233
234 switch (cap) {
235 case PR_CAP_BE: msg = "no backend"; break;
236 case PR_CAP_FE: msg = "no frontend"; break;
237 case PR_CAP_RS: msg = "no ruleset"; break;
238 case PR_CAP_BE|PR_CAP_FE: msg = "neither frontend nor backend"; break;
239 default: msg = "not enough"; break;
240 }
241
242 if (!(proxy->cap & cap)) {
243 Warning("parsing [%s:%d] : '%s' ignored because %s '%s' has %s capability.%s\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +0100244 file, line, arg, proxy_type_str(proxy), proxy->id, msg, hint ? hint : "");
Willy Tarreau977b8e42006-12-29 14:19:17 +0100245 return 1;
246 }
247 return 0;
248}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200249
250/*
251 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
252 */
Willy Tarreaub17916e2006-10-15 15:17:57 +0200253int cfg_parse_global(const char *file, int linenum, char **args)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200254{
255
256 if (!strcmp(args[0], "global")) { /* new section */
257 /* no option, nothing special to do */
258 return 0;
259 }
260 else if (!strcmp(args[0], "daemon")) {
261 global.mode |= MODE_DAEMON;
262 }
263 else if (!strcmp(args[0], "debug")) {
264 global.mode |= MODE_DEBUG;
265 }
266 else if (!strcmp(args[0], "noepoll")) {
267 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
268 }
Willy Tarreaude99e992007-04-16 00:53:59 +0200269 else if (!strcmp(args[0], "nosepoll")) {
270 cfg_polling_mechanism &= ~POLL_USE_SEPOLL;
271 }
272 else if (!strcmp(args[0], "nokqueue")) {
273 cfg_polling_mechanism &= ~POLL_USE_KQUEUE;
274 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200275 else if (!strcmp(args[0], "nopoll")) {
276 cfg_polling_mechanism &= ~POLL_USE_POLL;
277 }
278 else if (!strcmp(args[0], "quiet")) {
279 global.mode |= MODE_QUIET;
280 }
281 else if (!strcmp(args[0], "stats")) {
282 global.mode |= MODE_STATS;
283 }
Willy Tarreau1db37712007-06-03 17:16:49 +0200284 else if (!strcmp(args[0], "tune.maxpollevents")) {
285 if (global.tune.maxpollevents != 0) {
286 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
287 return 0;
288 }
289 if (*(args[1]) == 0) {
290 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
291 return -1;
292 }
293 global.tune.maxpollevents = atol(args[1]);
294 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200295 else if (!strcmp(args[0], "uid")) {
296 if (global.uid != 0) {
Willy Tarreau95c20ac2007-03-25 15:39:23 +0200297 Alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200298 return 0;
299 }
300 if (*(args[1]) == 0) {
301 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
302 return -1;
303 }
304 global.uid = atol(args[1]);
305 }
306 else if (!strcmp(args[0], "gid")) {
307 if (global.gid != 0) {
Willy Tarreau95c20ac2007-03-25 15:39:23 +0200308 Alert("parsing [%s:%d] : group/gid already specified. Continuing.\n", file, linenum);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200309 return 0;
310 }
311 if (*(args[1]) == 0) {
312 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
313 return -1;
314 }
315 global.gid = atol(args[1]);
316 }
Willy Tarreau95c20ac2007-03-25 15:39:23 +0200317 /* user/group name handling */
318 else if (!strcmp(args[0], "user")) {
319 struct passwd *ha_user;
320 if (global.uid != 0) {
321 Alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum);
322 return 0;
323 }
324 errno = 0;
325 ha_user = getpwnam(args[1]);
326 if (ha_user != NULL) {
327 global.uid = (int)ha_user->pw_uid;
328 }
329 else {
330 Alert("parsing [%s:%d] : cannot find user id for '%s' (%d:%s)\n", file, linenum, args[1], errno, strerror(errno));
331 exit(1);
332 }
333 }
334 else if (!strcmp(args[0], "group")) {
335 struct group *ha_group;
336 if (global.gid != 0) {
337 Alert("parsing [%s:%d] : gid/group was already specified. Continuing.\n", file, linenum, args[0]);
338 return 0;
339 }
340 errno = 0;
341 ha_group = getgrnam(args[1]);
342 if (ha_group != NULL) {
343 global.gid = (int)ha_group->gr_gid;
344 }
345 else {
346 Alert("parsing [%s:%d] : cannot find group id for '%s' (%d:%s)\n", file, linenum, args[1], errno, strerror(errno));
347 exit(1);
348 }
349 }
350 /* end of user/group name handling*/
Willy Tarreaubaaee002006-06-26 02:48:02 +0200351 else if (!strcmp(args[0], "nbproc")) {
352 if (global.nbproc != 0) {
353 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
354 return 0;
355 }
356 if (*(args[1]) == 0) {
357 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
358 return -1;
359 }
360 global.nbproc = atol(args[1]);
361 }
362 else if (!strcmp(args[0], "maxconn")) {
363 if (global.maxconn != 0) {
364 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
365 return 0;
366 }
367 if (*(args[1]) == 0) {
368 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
369 return -1;
370 }
371 global.maxconn = atol(args[1]);
372#ifdef SYSTEM_MAXCONN
373 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
374 Alert("parsing [%s:%d] : maxconn value %d too high for this system.\nLimiting to %d. Please use '-n' to force the value.\n", file, linenum, global.maxconn, DEFAULT_MAXCONN);
375 global.maxconn = DEFAULT_MAXCONN;
376 }
377#endif /* SYSTEM_MAXCONN */
378 }
379 else if (!strcmp(args[0], "ulimit-n")) {
380 if (global.rlimit_nofile != 0) {
381 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
382 return 0;
383 }
384 if (*(args[1]) == 0) {
385 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
386 return -1;
387 }
388 global.rlimit_nofile = atol(args[1]);
389 }
390 else if (!strcmp(args[0], "chroot")) {
391 if (global.chroot != NULL) {
392 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
393 return 0;
394 }
395 if (*(args[1]) == 0) {
396 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
397 return -1;
398 }
399 global.chroot = strdup(args[1]);
400 }
401 else if (!strcmp(args[0], "pidfile")) {
402 if (global.pidfile != NULL) {
403 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
404 return 0;
405 }
406 if (*(args[1]) == 0) {
407 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
408 return -1;
409 }
410 global.pidfile = strdup(args[1]);
411 }
412 else if (!strcmp(args[0], "log")) { /* syslog server address */
413 struct sockaddr_in *sa;
414 int facility, level;
415
416 if (*(args[1]) == 0 || *(args[2]) == 0) {
417 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
418 return -1;
419 }
420
421 facility = get_log_facility(args[2]);
422 if (facility < 0) {
423 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
424 exit(1);
425 }
426
427 level = 7; /* max syslog level = debug */
428 if (*(args[3])) {
429 level = get_log_level(args[3]);
430 if (level < 0) {
431 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
432 exit(1);
433 }
434 }
435
436 sa = str2sa(args[1]);
437 if (!sa->sin_port)
438 sa->sin_port = htons(SYSLOG_PORT);
439
440 if (global.logfac1 == -1) {
441 global.logsrv1 = *sa;
442 global.logfac1 = facility;
443 global.loglev1 = level;
444 }
445 else if (global.logfac2 == -1) {
446 global.logsrv2 = *sa;
447 global.logfac2 = facility;
448 global.loglev2 = level;
449 }
450 else {
451 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
452 return -1;
453 }
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +0200454 }
455 else if (!strcmp(args[0], "spread-checks")) { /* random time between checks (0-50) */
456 if (global.spread_checks != 0) {
457 Alert("parsing [%s:%d]: spread-checks already specified. Continuing.\n", file, linenum);
458 return 0;
459 }
460 if (*(args[1]) == 0) {
461 Alert("parsing [%s:%d]: '%s' expects an integer argument (0..50).\n", file, linenum, args[0]);
462 return -1;
463 }
464 global.spread_checks = atol(args[1]);
465 if (global.spread_checks < 0 || global.spread_checks > 50) {
466 Alert("parsing [%s:%d]: 'spread-checks' needs a positive value in range 0..50.\n", file, linenum);
467 return -1;
468 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200469 }
470 else {
471 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
472 return -1;
473 }
474 return 0;
475}
476
477
478static void init_default_instance()
479{
480 memset(&defproxy, 0, sizeof(defproxy));
481 defproxy.mode = PR_MODE_TCP;
482 defproxy.state = PR_STNEW;
483 defproxy.maxconn = cfg_maxpconn;
484 defproxy.conn_retries = CONN_RETRIES;
485 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
Willy Tarreaufdd0f552007-09-17 11:12:40 +0200486 tv_eternity(&defproxy.clitimeout);
487 tv_eternity(&defproxy.contimeout);
488 tv_eternity(&defproxy.srvtimeout);
489 tv_eternity(&defproxy.appsession_timeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200490}
491
492/*
Willy Tarreau977b8e42006-12-29 14:19:17 +0100493 * Parse a line in a <listen>, <frontend>, <backend> or <ruleset> section.
494 * Returns 0 if OK, -1 if error.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200495 */
Willy Tarreaub17916e2006-10-15 15:17:57 +0200496int cfg_parse_listen(const char *file, int linenum, char **args)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200497{
498 static struct proxy *curproxy = NULL;
499 struct server *newsrv = NULL;
Willy Tarreaub17916e2006-10-15 15:17:57 +0200500 const char *err;
Willy Tarreauee991362007-05-14 14:37:50 +0200501 int rc, val;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200502
Willy Tarreau977b8e42006-12-29 14:19:17 +0100503 if (!strcmp(args[0], "listen"))
504 rc = PR_CAP_LISTEN;
505 else if (!strcmp(args[0], "frontend"))
506 rc = PR_CAP_FE | PR_CAP_RS;
507 else if (!strcmp(args[0], "backend"))
508 rc = PR_CAP_BE | PR_CAP_RS;
509 else if (!strcmp(args[0], "ruleset"))
510 rc = PR_CAP_RS;
511 else
512 rc = PR_CAP_NONE;
513
514 if (rc != PR_CAP_NONE) { /* new proxy */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200515 if (!*args[1]) {
516 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
517 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
518 file, linenum, args[0]);
519 return -1;
520 }
521
522 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
523 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
524 return -1;
525 }
526
527 curproxy->next = proxy;
528 proxy = curproxy;
529 LIST_INIT(&curproxy->pendconns);
Willy Tarreaueb0c6142007-05-07 00:53:22 +0200530 LIST_INIT(&curproxy->acl);
Willy Tarreau5c8e3e02007-05-07 00:58:25 +0200531 LIST_INIT(&curproxy->block_cond);
Willy Tarreau55ea7572007-06-17 19:56:27 +0200532 LIST_INIT(&curproxy->switching_rules);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200533
Willy Tarreauee991362007-05-14 14:37:50 +0200534 /* Timeouts are defined as -1, so we cannot use the zeroed area
535 * as a default value.
536 */
537 tv_eternity(&curproxy->clitimeout);
538 tv_eternity(&curproxy->srvtimeout);
539 tv_eternity(&curproxy->contimeout);
540 tv_eternity(&curproxy->appsession_timeout);
541
Willy Tarreaubaaee002006-06-26 02:48:02 +0200542 curproxy->id = strdup(args[1]);
Willy Tarreau977b8e42006-12-29 14:19:17 +0100543 curproxy->cap = rc;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200544
545 /* parse the listener address if any */
Willy Tarreau977b8e42006-12-29 14:19:17 +0100546 if ((curproxy->cap & PR_CAP_FE) && *args[2]) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200547 curproxy->listen = str2listener(args[2], curproxy->listen);
548 if (!curproxy->listen)
549 return -1;
550 global.maxsock++;
551 }
552
553 /* set default values */
554 curproxy->state = defproxy.state;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200555 curproxy->options = defproxy.options;
Willy Tarreau7ac51f62007-03-25 16:00:04 +0200556 curproxy->except_net = defproxy.except_net;
557 curproxy->except_mask = defproxy.except_mask;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200558
Willy Tarreau977b8e42006-12-29 14:19:17 +0100559 if (curproxy->cap & PR_CAP_FE) {
560 curproxy->maxconn = defproxy.maxconn;
561
562 /* initialize error relocations */
563 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
564 if (defproxy.errmsg[rc].str)
565 chunk_dup(&curproxy->errmsg[rc], &defproxy.errmsg[rc]);
566 }
567
568 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
569 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200570
Willy Tarreau977b8e42006-12-29 14:19:17 +0100571 if (curproxy->cap & PR_CAP_BE) {
572 curproxy->fullconn = defproxy.fullconn;
573 curproxy->conn_retries = defproxy.conn_retries;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200574
Willy Tarreau977b8e42006-12-29 14:19:17 +0100575 if (defproxy.check_req)
576 curproxy->check_req = strdup(defproxy.check_req);
577 curproxy->check_len = defproxy.check_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200578
Willy Tarreau977b8e42006-12-29 14:19:17 +0100579 if (defproxy.cookie_name)
580 curproxy->cookie_name = strdup(defproxy.cookie_name);
581 curproxy->cookie_len = defproxy.cookie_len;
582 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200583
Willy Tarreau977b8e42006-12-29 14:19:17 +0100584 if (curproxy->cap & PR_CAP_RS) {
585 if (defproxy.capture_name)
586 curproxy->capture_name = strdup(defproxy.capture_name);
587 curproxy->capture_namelen = defproxy.capture_namelen;
588 curproxy->capture_len = defproxy.capture_len;
Willy Tarreau0f772532006-12-23 20:51:41 +0100589 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200590
Willy Tarreau977b8e42006-12-29 14:19:17 +0100591 if (curproxy->cap & PR_CAP_FE) {
592 curproxy->clitimeout = defproxy.clitimeout;
593 curproxy->uri_auth = defproxy.uri_auth;
594 curproxy->mon_net = defproxy.mon_net;
595 curproxy->mon_mask = defproxy.mon_mask;
596 if (defproxy.monitor_uri)
597 curproxy->monitor_uri = strdup(defproxy.monitor_uri);
598 curproxy->monitor_uri_len = defproxy.monitor_uri_len;
Willy Tarreau5fdfb912007-01-01 23:11:07 +0100599 if (defproxy.defbe.name)
600 curproxy->defbe.name = strdup(defproxy.defbe.name);
Willy Tarreau977b8e42006-12-29 14:19:17 +0100601 }
602
603 if (curproxy->cap & PR_CAP_BE) {
604 curproxy->contimeout = defproxy.contimeout;
605 curproxy->srvtimeout = defproxy.srvtimeout;
606 curproxy->source_addr = defproxy.source_addr;
607 }
608
Willy Tarreaubaaee002006-06-26 02:48:02 +0200609 curproxy->mode = defproxy.mode;
610 curproxy->logfac1 = defproxy.logfac1;
611 curproxy->logsrv1 = defproxy.logsrv1;
612 curproxy->loglev1 = defproxy.loglev1;
613 curproxy->logfac2 = defproxy.logfac2;
614 curproxy->logsrv2 = defproxy.logsrv2;
615 curproxy->loglev2 = defproxy.loglev2;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200616 curproxy->grace = defproxy.grace;
Willy Tarreau1c47f852006-07-09 08:22:27 +0200617
Willy Tarreaubaaee002006-06-26 02:48:02 +0200618 return 0;
619 }
620 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
621 /* some variables may have already been initialized earlier */
Willy Tarreau5fdfb912007-01-01 23:11:07 +0100622 /* FIXME-20070101: we should do this too at the end of the
623 * config parsing to free all default values.
624 */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200625 if (defproxy.check_req) free(defproxy.check_req);
626 if (defproxy.cookie_name) free(defproxy.cookie_name);
627 if (defproxy.capture_name) free(defproxy.capture_name);
Willy Tarreau1c47f852006-07-09 08:22:27 +0200628 if (defproxy.monitor_uri) free(defproxy.monitor_uri);
Willy Tarreau5fdfb912007-01-01 23:11:07 +0100629 if (defproxy.defbe.name) free(defproxy.defbe.name);
Willy Tarreau0f772532006-12-23 20:51:41 +0100630
631 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
632 if (defproxy.errmsg[rc].len)
633 free(defproxy.errmsg[rc].str);
634 }
635
Willy Tarreaubaaee002006-06-26 02:48:02 +0200636 /* we cannot free uri_auth because it might already be used */
637 init_default_instance();
638 curproxy = &defproxy;
Willy Tarreau977b8e42006-12-29 14:19:17 +0100639 defproxy.cap = PR_CAP_LISTEN; /* all caps for now */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200640 return 0;
641 }
642 else if (curproxy == NULL) {
643 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
644 return -1;
645 }
646
Willy Tarreau977b8e42006-12-29 14:19:17 +0100647
648 /* Now let's parse the proxy-specific keywords */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200649 if (!strcmp(args[0], "bind")) { /* new listen addresses */
650 if (curproxy == &defproxy) {
651 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
652 return -1;
653 }
Willy Tarreau977b8e42006-12-29 14:19:17 +0100654 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
655 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200656
657 if (strchr(args[1], ':') == NULL) {
658 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
659 file, linenum, args[0]);
660 return -1;
661 }
662 curproxy->listen = str2listener(args[1], curproxy->listen);
663 if (!curproxy->listen)
664 return -1;
665 global.maxsock++;
666 return 0;
667 }
668 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
669 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
670 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
671 file, linenum, args[0]);
672 return -1;
673 }
Willy Tarreau977b8e42006-12-29 14:19:17 +0100674 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
675 return 0;
676
Willy Tarreaubaaee002006-06-26 02:48:02 +0200677 /* flush useless bits */
678 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
679 return 0;
680 }
Willy Tarreau1c47f852006-07-09 08:22:27 +0200681 else if (!strcmp(args[0], "monitor-uri")) { /* set the URI to intercept */
Willy Tarreau977b8e42006-12-29 14:19:17 +0100682 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
683 return 0;
684
Willy Tarreau1c47f852006-07-09 08:22:27 +0200685 if (!*args[1]) {
686 Alert("parsing [%s:%d] : '%s' expects an URI.\n",
687 file, linenum, args[0]);
688 return -1;
689 }
690
691 if (curproxy->monitor_uri != NULL)
692 free(curproxy->monitor_uri);
693
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100694 curproxy->monitor_uri_len = strlen(args[1]);
Willy Tarreau1c47f852006-07-09 08:22:27 +0200695 curproxy->monitor_uri = (char *)calloc(1, curproxy->monitor_uri_len + 1);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100696 memcpy(curproxy->monitor_uri, args[1], curproxy->monitor_uri_len);
Willy Tarreau1c47f852006-07-09 08:22:27 +0200697 curproxy->monitor_uri[curproxy->monitor_uri_len] = '\0';
698
699 return 0;
700 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200701 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
702 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
703 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
704 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
705 else {
706 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
707 return -1;
708 }
709 }
710 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
711 curproxy->state = PR_STSTOPPED;
712 }
713 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
714 curproxy->state = PR_STNEW;
715 }
Willy Tarreaueb0c6142007-05-07 00:53:22 +0200716 else if (!strcmp(args[0], "acl")) { /* add an ACL */
717 if (parse_acl((const char **)args + 1, &curproxy->acl) == NULL) {
718 Alert("parsing [%s:%d] : error detected while parsing ACL '%s'.\n",
719 file, linenum, args[1]);
720 return -1;
721 }
722 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200723 else if (!strcmp(args[0], "cookie")) { /* cookie name */
724 int cur_arg;
725 // if (curproxy == &defproxy) {
726 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
727 // return -1;
728 // }
729
Willy Tarreau977b8e42006-12-29 14:19:17 +0100730 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
731 return 0;
732
Willy Tarreaubaaee002006-06-26 02:48:02 +0200733 if (curproxy->cookie_name != NULL) {
734 // Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
735 // file, linenum);
736 // return 0;
737 free(curproxy->cookie_name);
738 }
739
740 if (*(args[1]) == 0) {
741 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
742 file, linenum, args[0]);
743 return -1;
744 }
745 curproxy->cookie_name = strdup(args[1]);
746 curproxy->cookie_len = strlen(curproxy->cookie_name);
747
748 cur_arg = 2;
749 while (*(args[cur_arg])) {
750 if (!strcmp(args[cur_arg], "rewrite")) {
751 curproxy->options |= PR_O_COOK_RW;
752 }
753 else if (!strcmp(args[cur_arg], "indirect")) {
754 curproxy->options |= PR_O_COOK_IND;
755 }
756 else if (!strcmp(args[cur_arg], "insert")) {
757 curproxy->options |= PR_O_COOK_INS;
758 }
759 else if (!strcmp(args[cur_arg], "nocache")) {
760 curproxy->options |= PR_O_COOK_NOC;
761 }
762 else if (!strcmp(args[cur_arg], "postonly")) {
763 curproxy->options |= PR_O_COOK_POST;
764 }
765 else if (!strcmp(args[cur_arg], "prefix")) {
766 curproxy->options |= PR_O_COOK_PFX;
767 }
768 else {
769 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
770 file, linenum, args[0]);
771 return -1;
772 }
773 cur_arg++;
774 }
775 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
776 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
777 file, linenum);
778 return -1;
779 }
780
781 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
782 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
783 file, linenum);
784 return -1;
785 }
786 }/* end else if (!strcmp(args[0], "cookie")) */
787 else if (!strcmp(args[0], "appsession")) { /* cookie name */
788 // if (curproxy == &defproxy) {
789 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
790 // return -1;
791 // }
792
Willy Tarreau977b8e42006-12-29 14:19:17 +0100793 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
794 return 0;
795
Willy Tarreaubaaee002006-06-26 02:48:02 +0200796 if (curproxy->appsession_name != NULL) {
797 // Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
798 // file, linenum);
799 // return 0;
800 free(curproxy->appsession_name);
801 }
802
803 if (*(args[5]) == 0) {
804 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
805 file, linenum, args[0]);
806 return -1;
807 }
808 have_appsession = 1;
809 curproxy->appsession_name = strdup(args[1]);
810 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
811 curproxy->appsession_len = atoi(args[3]);
Willy Tarreauee991362007-05-14 14:37:50 +0200812 val = atoi(args[5]);
813 if (val > 0)
814 __tv_from_ms(&curproxy->appsession_timeout, val);
815 else
816 tv_eternity(&curproxy->appsession_timeout);
817
Willy Tarreau51041c72007-09-09 21:56:53 +0200818 if (appsession_hash_init(&(curproxy->htbl_proxy), destroy) == 0) {
819 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200820 return -1;
821 }
822 } /* Url App Session */
823 else if (!strcmp(args[0], "capture")) {
Willy Tarreau977b8e42006-12-29 14:19:17 +0100824 if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
825 return 0;
826
Willy Tarreaubaaee002006-06-26 02:48:02 +0200827 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
828 // if (curproxy == &defproxy) {
829 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
830 // return -1;
831 // }
832
833 if (curproxy->capture_name != NULL) {
834 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
835 // file, linenum, args[0]);
836 // return 0;
837 free(curproxy->capture_name);
838 }
839
840 if (*(args[4]) == 0) {
841 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
842 file, linenum, args[0]);
843 return -1;
844 }
845 curproxy->capture_name = strdup(args[2]);
846 curproxy->capture_namelen = strlen(curproxy->capture_name);
847 curproxy->capture_len = atol(args[4]);
848 if (curproxy->capture_len >= CAPTURE_LEN) {
849 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
850 file, linenum, CAPTURE_LEN - 1);
851 curproxy->capture_len = CAPTURE_LEN - 1;
852 }
853 curproxy->to_log |= LW_COOKIE;
854 }
855 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
856 struct cap_hdr *hdr;
857
858 if (curproxy == &defproxy) {
859 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
860 return -1;
861 }
862
863 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
864 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
865 file, linenum, args[0], args[1]);
866 return -1;
867 }
868
869 hdr = calloc(sizeof(struct cap_hdr), 1);
870 hdr->next = curproxy->req_cap;
871 hdr->name = strdup(args[3]);
872 hdr->namelen = strlen(args[3]);
873 hdr->len = atol(args[5]);
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200874 hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200875 hdr->index = curproxy->nb_req_cap++;
876 curproxy->req_cap = hdr;
877 curproxy->to_log |= LW_REQHDR;
878 }
879 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
880 struct cap_hdr *hdr;
881
882 if (curproxy == &defproxy) {
883 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
884 return -1;
885 }
886
887 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
888 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
889 file, linenum, args[0], args[1]);
890 return -1;
891 }
892 hdr = calloc(sizeof(struct cap_hdr), 1);
893 hdr->next = curproxy->rsp_cap;
894 hdr->name = strdup(args[3]);
895 hdr->namelen = strlen(args[3]);
896 hdr->len = atol(args[5]);
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200897 hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200898 hdr->index = curproxy->nb_rsp_cap++;
899 curproxy->rsp_cap = hdr;
900 curproxy->to_log |= LW_RSPHDR;
901 }
902 else {
903 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
904 file, linenum, args[0]);
905 return -1;
906 }
907 }
908 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200909 if (!__tv_iseq(&curproxy->contimeout, &defproxy.contimeout)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200910 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
911 return 0;
912 }
Willy Tarreau977b8e42006-12-29 14:19:17 +0100913 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
914 return 0;
915
Willy Tarreaubaaee002006-06-26 02:48:02 +0200916 if (*(args[1]) == 0) {
917 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
918 file, linenum, args[0]);
919 return -1;
920 }
Willy Tarreauee991362007-05-14 14:37:50 +0200921 val = atoi(args[1]);
922 if (val > 0)
923 __tv_from_ms(&curproxy->contimeout, val);
924 else
925 tv_eternity(&curproxy->contimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200926 }
927 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200928 if (!__tv_iseq(&curproxy->clitimeout, &defproxy.clitimeout)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200929 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
930 file, linenum, args[0]);
931 return 0;
932 }
Willy Tarreau977b8e42006-12-29 14:19:17 +0100933 else if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
934 return 0;
935
Willy Tarreaubaaee002006-06-26 02:48:02 +0200936 if (*(args[1]) == 0) {
937 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
938 file, linenum, args[0]);
939 return -1;
940 }
Willy Tarreauee991362007-05-14 14:37:50 +0200941 val = atoi(args[1]);
942 if (val > 0)
943 __tv_from_ms(&curproxy->clitimeout, val);
944 else
945 tv_eternity(&curproxy->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200946 }
947 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200948 if (!__tv_iseq(&curproxy->srvtimeout, &defproxy.srvtimeout)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200949 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
950 return 0;
951 }
Willy Tarreau977b8e42006-12-29 14:19:17 +0100952 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
953 return 0;
954
Willy Tarreaubaaee002006-06-26 02:48:02 +0200955 if (*(args[1]) == 0) {
956 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
957 file, linenum, args[0]);
958 return -1;
959 }
Willy Tarreauee991362007-05-14 14:37:50 +0200960 val = atoi(args[1]);
961 if (val > 0)
962 __tv_from_ms(&curproxy->srvtimeout, val);
963 else
964 tv_eternity(&curproxy->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200965 }
966 else if (!strcmp(args[0], "retries")) { /* connection retries */
Willy Tarreau977b8e42006-12-29 14:19:17 +0100967 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
968 return 0;
969
Willy Tarreaubaaee002006-06-26 02:48:02 +0200970 if (*(args[1]) == 0) {
971 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
972 file, linenum, args[0]);
973 return -1;
974 }
975 curproxy->conn_retries = atol(args[1]);
976 }
Willy Tarreau5c8e3e02007-05-07 00:58:25 +0200977 else if (!strcmp(args[0], "block")) { /* early blocking based on ACLs */
978 int pol = ACL_COND_NONE;
979 struct acl_cond *cond;
980
981 if (!strcmp(args[1], "if"))
982 pol = ACL_COND_IF;
983 else if (!strcmp(args[1], "unless"))
984 pol = ACL_COND_UNLESS;
985
986 if (pol == ACL_COND_NONE) {
987 Alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
988 file, linenum, args[0]);
989 return -1;
990 }
991
992 if ((cond = parse_acl_cond((const char **)args + 2, &curproxy->acl, pol)) == NULL) {
993 Alert("parsing [%s:%d] : error detected while parsing blocking condition.\n",
994 file, linenum);
995 return -1;
996 }
997 LIST_ADDQ(&curproxy->block_cond, &cond->list);
998 }
Willy Tarreau55ea7572007-06-17 19:56:27 +0200999 else if (!strcmp(args[0], "use_backend")) { /* early blocking based on ACLs */
1000 int pol = ACL_COND_NONE;
1001 struct acl_cond *cond;
1002 struct switching_rule *rule;
1003
1004 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1005 return 0;
1006
1007 if (*(args[1]) == 0) {
1008 Alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
1009 return -1;
1010 }
1011
1012 if (!strcmp(args[2], "if"))
1013 pol = ACL_COND_IF;
1014 else if (!strcmp(args[2], "unless"))
1015 pol = ACL_COND_UNLESS;
1016
1017 if (pol == ACL_COND_NONE) {
1018 Alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1019 file, linenum, args[0]);
1020 return -1;
1021 }
1022
1023 if ((cond = parse_acl_cond((const char **)args + 3, &curproxy->acl, pol)) == NULL) {
1024 Alert("parsing [%s:%d] : error detected while parsing blocking condition.\n",
1025 file, linenum);
1026 return -1;
1027 }
1028
1029 rule = (struct switching_rule *)calloc(1, sizeof(*rule));
1030 rule->cond = cond;
1031 rule->be.name = strdup(args[1]);
1032 LIST_INIT(&rule->list);
1033 LIST_ADDQ(&curproxy->switching_rules, &rule->list);
1034 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001035 else if (!strcmp(args[0], "stats")) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01001036 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1037 return 0;
1038
Willy Tarreaubaaee002006-06-26 02:48:02 +02001039 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
1040 curproxy->uri_auth = NULL; /* we must detach from the default config */
1041
1042 if (*(args[1]) == 0) {
1043 Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable'.\n", file, linenum, args[0]);
1044 return -1;
1045 } else if (!strcmp(args[1], "uri")) {
1046 if (*(args[2]) == 0) {
1047 Alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
1048 return -1;
1049 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
1050 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1051 return -1;
1052 }
1053 } else if (!strcmp(args[1], "realm")) {
1054 if (*(args[2]) == 0) {
1055 Alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
1056 return -1;
1057 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
1058 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1059 return -1;
1060 }
Willy Tarreaubbd42122007-07-25 07:26:38 +02001061 } else if (!strcmp(args[1], "refresh")) {
1062 int interval = atoi(args[2]);
1063
1064 if (interval < 0) {
1065 Alert("parsing [%s:%d] : 'refresh' needs a positive interval in seconds.\n", file, linenum);
1066 return -1;
1067 } else if (!stats_set_refresh(&curproxy->uri_auth, interval)) {
1068 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1069 return -1;
1070 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001071 } else if (!strcmp(args[1], "auth")) {
1072 if (*(args[2]) == 0) {
1073 Alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
1074 return -1;
1075 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
1076 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1077 return -1;
1078 }
1079 } else if (!strcmp(args[1], "scope")) {
1080 if (*(args[2]) == 0) {
1081 Alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
1082 return -1;
1083 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
1084 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1085 return -1;
1086 }
1087 } else if (!strcmp(args[1], "enable")) {
1088 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1089 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1090 return -1;
1091 }
Krzysztof Oledzkid9db9272007-10-15 10:05:11 +02001092 } else if (!strcmp(args[1], "hide-version")) {
1093 if (!stats_set_flag(&curproxy->uri_auth, ST_HIDEVER)) {
1094 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1095 return -1;
1096 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001097 } else {
Krzysztof Oledzkid9db9272007-10-15 10:05:11 +02001098 Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'hide-version', 'uri', 'realm', 'auth' or 'enable').\n",
Willy Tarreaubaaee002006-06-26 02:48:02 +02001099 file, linenum, args[0]);
1100 return -1;
1101 }
1102 }
1103 else if (!strcmp(args[0], "option")) {
Willy Tarreau13943ab2006-12-31 00:24:10 +01001104 int optnum;
1105
Willy Tarreaubaaee002006-06-26 02:48:02 +02001106 if (*(args[1]) == 0) {
1107 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
1108 return -1;
1109 }
Willy Tarreau13943ab2006-12-31 00:24:10 +01001110
1111 for (optnum = 0; cfg_opts[optnum].name; optnum++) {
1112 if (!strcmp(args[1], cfg_opts[optnum].name)) {
1113 if (warnifnotcap(curproxy, cfg_opts[optnum].cap, file, linenum, args[1], NULL))
1114 return 0;
1115 curproxy->options |= cfg_opts[optnum].val;
Willy Tarreau4fee4e92007-01-06 21:09:17 +01001116 global.last_checks |= cfg_opts[optnum].checks;
Willy Tarreau13943ab2006-12-31 00:24:10 +01001117 return 0;
1118 }
1119 }
1120
1121 if (!strcmp(args[1], "httplog"))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001122 /* generate a complete HTTP log */
1123 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
1124 else if (!strcmp(args[1], "tcplog"))
1125 /* generate a detailed TCP log */
1126 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001127 else if (!strcmp(args[1], "tcpka")) {
1128 /* enable TCP keep-alives on client and server sessions */
Willy Tarreau13943ab2006-12-31 00:24:10 +01001129 if (warnifnotcap(curproxy, PR_CAP_BE | PR_CAP_FE, file, linenum, args[1], NULL))
1130 return 0;
1131
1132 if (curproxy->cap & PR_CAP_FE)
1133 curproxy->options |= PR_O_TCP_CLI_KA;
1134 if (curproxy->cap & PR_CAP_BE)
1135 curproxy->options |= PR_O_TCP_SRV_KA;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001136 }
1137 else if (!strcmp(args[1], "httpchk")) {
Willy Tarreau13943ab2006-12-31 00:24:10 +01001138 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
1139 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001140 /* use HTTP request to check servers' health */
1141 if (curproxy->check_req != NULL) {
1142 free(curproxy->check_req);
1143 }
Willy Tarreauf3c69202006-07-09 16:42:34 +02001144 curproxy->options &= ~PR_O_SSL3_CHK;
Willy Tarreau23677902007-05-08 23:50:35 +02001145 curproxy->options &= ~PR_O_SMTP_CHK;
1146 curproxy->options |= PR_O_HTTP_CHK;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001147 if (!*args[2]) { /* no argument */
1148 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
1149 curproxy->check_len = strlen(DEF_CHECK_REQ);
1150 } else if (!*args[3]) { /* one argument : URI */
Willy Tarreau23677902007-05-08 23:50:35 +02001151 int reqlen = strlen(args[2]) + strlen("OPTIONS HTTP/1.0\r\n\r\n") + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001152 curproxy->check_req = (char *)malloc(reqlen);
1153 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
1154 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
1155 } else { /* more arguments : METHOD URI [HTTP_VER] */
1156 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
1157 if (*args[4])
1158 reqlen += strlen(args[4]);
1159 else
1160 reqlen += strlen("HTTP/1.0");
1161
1162 curproxy->check_req = (char *)malloc(reqlen);
1163 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
1164 "%s %s %s\r\n\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
1165 }
Willy Tarreauf3c69202006-07-09 16:42:34 +02001166 }
1167 else if (!strcmp(args[1], "ssl-hello-chk")) {
1168 /* use SSLv3 CLIENT HELLO to check servers' health */
Willy Tarreau13943ab2006-12-31 00:24:10 +01001169 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
1170 return 0;
1171
Willy Tarreauf3c69202006-07-09 16:42:34 +02001172 if (curproxy->check_req != NULL) {
1173 free(curproxy->check_req);
1174 }
1175 curproxy->options &= ~PR_O_HTTP_CHK;
Willy Tarreau23677902007-05-08 23:50:35 +02001176 curproxy->options &= ~PR_O_SMTP_CHK;
Willy Tarreauf3c69202006-07-09 16:42:34 +02001177 curproxy->options |= PR_O_SSL3_CHK;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001178 }
Willy Tarreau23677902007-05-08 23:50:35 +02001179 else if (!strcmp(args[1], "smtpchk")) {
1180 /* use SMTP request to check servers' health */
1181 if (curproxy->check_req != NULL) {
1182 free(curproxy->check_req);
1183 }
1184 curproxy->options &= ~PR_O_HTTP_CHK;
1185 curproxy->options &= ~PR_O_SSL3_CHK;
1186 curproxy->options |= PR_O_SMTP_CHK;
1187
1188 if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */
1189 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
1190 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
1191 } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */
1192 if (!strcmp(args[2], "EHLO") || !strcmp(args[2], "HELO")) {
1193 int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" \r\n") + 1;
1194 curproxy->check_req = (char *)malloc(reqlen);
1195 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
1196 "%s %s\r\n", args[2], args[3]); /* HELO hostname */
1197 } else {
1198 /* this just hits the default for now, but you could potentially expand it to allow for other stuff
1199 though, it's unlikely you'd want to send anything other than an EHLO or HELO */
1200 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
1201 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
1202 }
1203 }
1204 }
Willy Tarreau7ac51f62007-03-25 16:00:04 +02001205 else if (!strcmp(args[1], "forwardfor")) {
1206 /* insert x-forwarded-for field, but not for the
1207 * IP address listed as an except.
1208 */
1209 if (*(args[2])) {
1210 if (!strcmp(args[2], "except")) {
1211 if (!*args[3] || !str2net(args[3], &curproxy->except_net, &curproxy->except_mask)) {
1212 Alert("parsing [%s:%d] : '%s' only supports optional 'except' address[/mask].\n",
1213 file, linenum, args[0]);
1214 return -1;
1215 }
1216 /* flush useless bits */
1217 curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
1218 } else {
1219 Alert("parsing [%s:%d] : '%s' only supports optional 'except' address[/mask].\n",
1220 file, linenum, args[0]);
1221 return -1;
1222 }
1223 }
1224 curproxy->options |= PR_O_FWDFOR;
1225 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001226 else {
1227 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
1228 return -1;
1229 }
1230 return 0;
1231 }
Willy Tarreau5fdfb912007-01-01 23:11:07 +01001232 else if (!strcmp(args[0], "default_backend")) {
1233 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1234 return 0;
1235
1236 if (*(args[1]) == 0) {
1237 Alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
1238 return -1;
1239 }
1240 if (curproxy->defbe.name)
1241 free(curproxy->defbe.name);
1242 curproxy->defbe.name = strdup(args[1]);
1243 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001244 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01001245 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1246 return 0;
1247
Willy Tarreaubaaee002006-06-26 02:48:02 +02001248 /* enable reconnections to dispatch */
1249 curproxy->options |= PR_O_REDISP;
1250 }
1251#ifdef TPROXY
1252 else if (!strcmp(args[0], "transparent")) {
1253 /* enable transparent proxy connections */
1254 curproxy->options |= PR_O_TRANSP;
1255 }
1256#endif
1257 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
Willy Tarreau977b8e42006-12-29 14:19:17 +01001258 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
1259 return 0;
1260
Willy Tarreaubaaee002006-06-26 02:48:02 +02001261 if (*(args[1]) == 0) {
1262 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
1263 return -1;
1264 }
1265 curproxy->maxconn = atol(args[1]);
1266 }
Willy Tarreau86034312006-12-29 00:10:33 +01001267 else if (!strcmp(args[0], "fullconn")) { /* fullconn */
Willy Tarreau977b8e42006-12-29 14:19:17 +01001268 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
1269 return 0;
1270
Willy Tarreau86034312006-12-29 00:10:33 +01001271 if (*(args[1]) == 0) {
1272 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
1273 return -1;
1274 }
1275 curproxy->fullconn = atol(args[1]);
1276 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001277 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
1278 if (*(args[1]) == 0) {
1279 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
1280 return -1;
1281 }
1282 curproxy->grace = atol(args[1]);
1283 }
1284 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
1285 if (curproxy == &defproxy) {
1286 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1287 return -1;
1288 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001289 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1290 return 0;
1291
Willy Tarreaubaaee002006-06-26 02:48:02 +02001292 if (strchr(args[1], ':') == NULL) {
1293 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
1294 return -1;
1295 }
1296 curproxy->dispatch_addr = *str2sa(args[1]);
1297 }
1298 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
Willy Tarreau977b8e42006-12-29 14:19:17 +01001299 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1300 return 0;
1301
Willy Tarreaubaaee002006-06-26 02:48:02 +02001302 if (*(args[1])) {
1303 if (!strcmp(args[1], "roundrobin")) {
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001304 curproxy->options &= ~PR_O_BALANCE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001305 curproxy->options |= PR_O_BALANCE_RR;
1306 }
1307 else if (!strcmp(args[1], "source")) {
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001308 curproxy->options &= ~PR_O_BALANCE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001309 curproxy->options |= PR_O_BALANCE_SH;
1310 }
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001311 else if (!strcmp(args[1], "uri")) {
1312 curproxy->options &= ~PR_O_BALANCE;
1313 curproxy->options |= PR_O_BALANCE_UH;
1314 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001315 else {
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001316 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin', 'source' and 'uri' options.\n", file, linenum, args[0]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001317 return -1;
1318 }
1319 }
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001320 else {/* if no option is set, use round-robin by default */
1321 curproxy->options &= ~PR_O_BALANCE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001322 curproxy->options |= PR_O_BALANCE_RR;
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001323 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001324 }
1325 else if (!strcmp(args[0], "server")) { /* server address */
1326 int cur_arg;
1327 char *rport;
1328 char *raddr;
1329 short realport;
1330 int do_check;
1331
1332 if (curproxy == &defproxy) {
1333 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1334 return -1;
1335 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001336 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1337 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001338
1339 if (!*args[2]) {
1340 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
1341 file, linenum, args[0]);
1342 return -1;
1343 }
1344 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
1345 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1346 return -1;
1347 }
1348
1349 /* the servers are linked backwards first */
1350 newsrv->next = curproxy->srv;
1351 curproxy->srv = newsrv;
1352 newsrv->proxy = curproxy;
1353
1354 LIST_INIT(&newsrv->pendconns);
1355 do_check = 0;
1356 newsrv->state = SRV_RUNNING; /* early server setup */
1357 newsrv->id = strdup(args[1]);
1358
1359 /* several ways to check the port component :
1360 * - IP => port=+0, relative
1361 * - IP: => port=+0, relative
1362 * - IP:N => port=N, absolute
1363 * - IP:+N => port=+N, relative
1364 * - IP:-N => port=-N, relative
1365 */
1366 raddr = strdup(args[2]);
1367 rport = strchr(raddr, ':');
1368 if (rport) {
1369 *rport++ = 0;
1370 realport = atol(rport);
Willy Tarreau8f8e6452007-06-17 21:51:38 +02001371 if (!isdigit((unsigned char)*rport))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001372 newsrv->state |= SRV_MAPPORTS;
1373 } else {
1374 realport = 0;
1375 newsrv->state |= SRV_MAPPORTS;
1376 }
1377
1378 newsrv->addr = *str2sa(raddr);
1379 newsrv->addr.sin_port = htons(realport);
1380 free(raddr);
1381
1382 newsrv->curfd = -1; /* no health-check in progress */
1383 newsrv->inter = DEF_CHKINTR;
1384 newsrv->rise = DEF_RISETIME;
1385 newsrv->fall = DEF_FALLTIME;
1386 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
Willy Tarreau417fae02007-03-25 21:16:40 +02001387 newsrv->uweight = 1;
Willy Tarreau0f03c6f2007-03-25 20:46:19 +02001388
Willy Tarreaubaaee002006-06-26 02:48:02 +02001389 cur_arg = 3;
1390 while (*args[cur_arg]) {
1391 if (!strcmp(args[cur_arg], "cookie")) {
1392 newsrv->cookie = strdup(args[cur_arg + 1]);
1393 newsrv->cklen = strlen(args[cur_arg + 1]);
1394 cur_arg += 2;
1395 }
1396 else if (!strcmp(args[cur_arg], "rise")) {
1397 newsrv->rise = atol(args[cur_arg + 1]);
1398 newsrv->health = newsrv->rise;
1399 cur_arg += 2;
1400 }
1401 else if (!strcmp(args[cur_arg], "fall")) {
1402 newsrv->fall = atol(args[cur_arg + 1]);
1403 cur_arg += 2;
1404 }
1405 else if (!strcmp(args[cur_arg], "inter")) {
1406 newsrv->inter = atol(args[cur_arg + 1]);
1407 cur_arg += 2;
1408 }
Willy Tarreau2ea3abb2007-03-25 16:45:16 +02001409 else if (!strcmp(args[cur_arg], "addr")) {
1410 newsrv->check_addr = *str2sa(args[cur_arg + 1]);
Willy Tarreau2ea3abb2007-03-25 16:45:16 +02001411 cur_arg += 2;
1412 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001413 else if (!strcmp(args[cur_arg], "port")) {
1414 newsrv->check_port = atol(args[cur_arg + 1]);
1415 cur_arg += 2;
1416 }
1417 else if (!strcmp(args[cur_arg], "backup")) {
1418 newsrv->state |= SRV_BACKUP;
1419 cur_arg ++;
1420 }
1421 else if (!strcmp(args[cur_arg], "weight")) {
1422 int w;
1423 w = atol(args[cur_arg + 1]);
1424 if (w < 1 || w > 256) {
1425 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
1426 file, linenum, newsrv->id, w);
1427 return -1;
1428 }
Willy Tarreau417fae02007-03-25 21:16:40 +02001429 newsrv->uweight = w;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001430 cur_arg += 2;
1431 }
1432 else if (!strcmp(args[cur_arg], "minconn")) {
1433 newsrv->minconn = atol(args[cur_arg + 1]);
1434 cur_arg += 2;
1435 }
1436 else if (!strcmp(args[cur_arg], "maxconn")) {
1437 newsrv->maxconn = atol(args[cur_arg + 1]);
1438 cur_arg += 2;
1439 }
1440 else if (!strcmp(args[cur_arg], "check")) {
1441 global.maxsock++;
1442 do_check = 1;
1443 cur_arg += 1;
1444 }
1445 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
1446 if (!*args[cur_arg + 1]) {
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001447#ifdef CONFIG_HAP_CTTPROXY
1448 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optional '%s' <addr> as argument.\n",
1449 file, linenum, "source", "usesrc");
1450#else
Willy Tarreaubaaee002006-06-26 02:48:02 +02001451 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
1452 file, linenum, "source");
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001453#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001454 return -1;
1455 }
1456 newsrv->state |= SRV_BIND_SRC;
1457 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
1458 cur_arg += 2;
Willy Tarreau77074d52006-11-12 23:57:19 +01001459 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001460#ifdef CONFIG_HAP_CTTPROXY
Willy Tarreau77074d52006-11-12 23:57:19 +01001461 if (newsrv->source_addr.sin_addr.s_addr == INADDR_ANY) {
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001462 Alert("parsing [%s:%d] : '%s' requires an explicit '%s' address.\n",
1463 file, linenum, "usesrc", "source");
Willy Tarreau77074d52006-11-12 23:57:19 +01001464 return -1;
1465 }
1466 if (!*args[cur_arg + 1]) {
1467 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
1468 file, linenum, "usesrc");
1469 return -1;
1470 }
1471 if (!strcmp(args[cur_arg + 1], "client")) {
1472 newsrv->state |= SRV_TPROXY_CLI;
1473 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
1474 newsrv->state |= SRV_TPROXY_CIP;
1475 } else {
1476 newsrv->state |= SRV_TPROXY_ADDR;
1477 newsrv->tproxy_addr = *str2sa(args[cur_arg + 1]);
1478 }
1479 global.last_checks |= LSTCHK_CTTPROXY | LSTCHK_NETADM;
1480 cur_arg += 2;
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001481#else /* no CTTPROXY support */
1482 Alert("parsing [%s:%d] : '%s' not allowed here because support for cttproxy was not compiled in.\n",
1483 file, linenum, "usesrc");
1484 return -1;
Willy Tarreau77074d52006-11-12 23:57:19 +01001485#endif
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001486 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001487 }
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001488#ifdef CONFIG_HAP_CTTPROXY
1489 else if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside: needs "source" first */
1490 Alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
1491 file, linenum, "usesrc", "source");
1492 return -1;
1493 }
1494#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001495 else {
Willy Tarreau0f03c6f2007-03-25 20:46:19 +02001496 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'addr', 'port', 'source', 'minconn', 'maxconn' and 'weight'.\n",
Willy Tarreaubaaee002006-06-26 02:48:02 +02001497 file, linenum, newsrv->id);
1498 return -1;
1499 }
1500 }
1501
1502 if (do_check) {
Willy Tarreau0f03c6f2007-03-25 20:46:19 +02001503 if (!newsrv->check_port && newsrv->check_addr.sin_port)
1504 newsrv->check_port = newsrv->check_addr.sin_port;
1505
Willy Tarreaubaaee002006-06-26 02:48:02 +02001506 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
1507 newsrv->check_port = realport; /* by default */
1508 if (!newsrv->check_port) {
Willy Tarreauef00b502007-01-07 02:40:09 +01001509 /* not yet valid, because no port was set on
1510 * the server either. We'll check if we have
1511 * a known port on the first listener.
1512 */
1513 struct listener *l;
1514 l = curproxy->listen;
1515 if (l) {
1516 int port;
1517 port = (l->addr.ss_family == AF_INET6)
1518 ? ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port)
1519 : ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
1520 newsrv->check_port = port;
1521 }
1522 }
1523 if (!newsrv->check_port) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001524 Alert("parsing [%s:%d] : server %s has neither service port nor check port. Check has been disabled.\n",
1525 file, linenum, newsrv->id);
1526 return -1;
1527 }
1528 newsrv->state |= SRV_CHECKED;
1529 }
1530
1531 if (newsrv->state & SRV_BACKUP)
1532 curproxy->srv_bck++;
1533 else
1534 curproxy->srv_act++;
1535 }
1536 else if (!strcmp(args[0], "log")) { /* syslog server address */
1537 struct sockaddr_in *sa;
1538 int facility;
1539
1540 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
1541 curproxy->logfac1 = global.logfac1;
1542 curproxy->logsrv1 = global.logsrv1;
1543 curproxy->loglev1 = global.loglev1;
1544 curproxy->logfac2 = global.logfac2;
1545 curproxy->logsrv2 = global.logsrv2;
1546 curproxy->loglev2 = global.loglev2;
1547 }
1548 else if (*(args[1]) && *(args[2])) {
1549 int level;
1550
1551 facility = get_log_facility(args[2]);
1552 if (facility < 0) {
1553 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
1554 exit(1);
1555 }
1556
1557 level = 7; /* max syslog level = debug */
1558 if (*(args[3])) {
1559 level = get_log_level(args[3]);
1560 if (level < 0) {
1561 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
1562 exit(1);
1563 }
1564 }
1565
1566 sa = str2sa(args[1]);
1567 if (!sa->sin_port)
1568 sa->sin_port = htons(SYSLOG_PORT);
1569
1570 if (curproxy->logfac1 == -1) {
1571 curproxy->logsrv1 = *sa;
1572 curproxy->logfac1 = facility;
1573 curproxy->loglev1 = level;
1574 }
1575 else if (curproxy->logfac2 == -1) {
1576 curproxy->logsrv2 = *sa;
1577 curproxy->logfac2 = facility;
1578 curproxy->loglev2 = level;
1579 }
1580 else {
1581 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
1582 return -1;
1583 }
1584 }
1585 else {
1586 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
1587 file, linenum);
1588 return -1;
1589 }
1590 }
1591 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
Willy Tarreau977b8e42006-12-29 14:19:17 +01001592 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1593 return 0;
1594
Willy Tarreaubaaee002006-06-26 02:48:02 +02001595 if (!*args[1]) {
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001596#ifdef CONFIG_HAP_CTTPROXY
1597 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optional '%s' <addr> as argument.\n",
1598 file, linenum, "source", "usesrc");
1599#else
Willy Tarreaubaaee002006-06-26 02:48:02 +02001600 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
1601 file, linenum, "source");
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001602#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001603 return -1;
1604 }
1605
1606 curproxy->source_addr = *str2sa(args[1]);
1607 curproxy->options |= PR_O_BIND_SRC;
Willy Tarreau77074d52006-11-12 23:57:19 +01001608 if (!strcmp(args[2], "usesrc")) { /* address to use outside */
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001609#ifdef CONFIG_HAP_CTTPROXY
Willy Tarreau77074d52006-11-12 23:57:19 +01001610 if (curproxy->source_addr.sin_addr.s_addr == INADDR_ANY) {
1611 Alert("parsing [%s:%d] : '%s' requires an explicit 'source' address.\n",
1612 file, linenum, "usesrc");
1613 return -1;
1614 }
1615 if (!*args[3]) {
1616 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
1617 file, linenum, "usesrc");
1618 return -1;
1619 }
1620
1621 if (!strcmp(args[3], "client")) {
1622 curproxy->options |= PR_O_TPXY_CLI;
1623 } else if (!strcmp(args[3], "clientip")) {
1624 curproxy->options |= PR_O_TPXY_CIP;
1625 } else {
1626 curproxy->options |= PR_O_TPXY_ADDR;
1627 curproxy->tproxy_addr = *str2sa(args[3]);
1628 }
1629 global.last_checks |= LSTCHK_CTTPROXY | LSTCHK_NETADM;
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001630#else /* no CTTPROXY support */
1631 Alert("parsing [%s:%d] : '%s' not allowed here because support for cttproxy was not compiled in.\n",
1632 file, linenum, "usesrc");
1633 return -1;
Willy Tarreau77074d52006-11-12 23:57:19 +01001634#endif
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001635 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001636 }
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001637#ifdef CONFIG_HAP_CTTPROXY
1638 else if (!strcmp(args[0], "usesrc")) { /* address to use outside: needs "source" first */
1639 Alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
1640 file, linenum, "usesrc", "source");
1641 return -1;
1642 }
1643#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001644 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
1645 regex_t *preg;
1646 if (curproxy == &defproxy) {
1647 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1648 return -1;
1649 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001650 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1651 return 0;
1652
Willy Tarreaubaaee002006-06-26 02:48:02 +02001653 if (*(args[1]) == 0 || *(args[2]) == 0) {
1654 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
1655 file, linenum, args[0]);
1656 return -1;
1657 }
1658
1659 preg = calloc(1, sizeof(regex_t));
1660 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1661 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1662 return -1;
1663 }
1664
1665 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
1666 if (err) {
1667 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1668 file, linenum, *err);
1669 return -1;
1670 }
1671 }
1672 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
1673 regex_t *preg;
1674 if (curproxy == &defproxy) {
1675 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1676 return -1;
1677 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001678 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1679 return 0;
1680
Willy Tarreaubaaee002006-06-26 02:48:02 +02001681 if (*(args[1]) == 0) {
1682 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1683 return -1;
1684 }
1685
1686 preg = calloc(1, sizeof(regex_t));
1687 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1688 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1689 return -1;
1690 }
1691
1692 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
1693 }
1694 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
1695 regex_t *preg;
1696 if (curproxy == &defproxy) {
1697 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1698 return -1;
1699 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001700 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1701 return 0;
1702
Willy Tarreaubaaee002006-06-26 02:48:02 +02001703 if (*(args[1]) == 0) {
1704 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1705 return -1;
1706 }
1707
1708 preg = calloc(1, sizeof(regex_t));
1709 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1710 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1711 return -1;
1712 }
1713
1714 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
1715 }
1716 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
1717 regex_t *preg;
1718 if (curproxy == &defproxy) {
1719 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1720 return -1;
1721 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001722 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1723 return 0;
1724
Willy Tarreaubaaee002006-06-26 02:48:02 +02001725 if (*(args[1]) == 0) {
1726 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1727 return -1;
1728 }
1729
1730 preg = calloc(1, sizeof(regex_t));
1731 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1732 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1733 return -1;
1734 }
1735
1736 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
1737 }
1738 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
1739 regex_t *preg;
1740 if (curproxy == &defproxy) {
1741 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1742 return -1;
1743 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001744 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1745 return 0;
1746
Willy Tarreaubaaee002006-06-26 02:48:02 +02001747 if (*(args[1]) == 0) {
1748 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1749 return -1;
1750 }
1751
1752 preg = calloc(1, sizeof(regex_t));
1753 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1754 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1755 return -1;
1756 }
1757
1758 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
1759 }
Willy Tarreaub8750a82006-09-03 09:56:00 +02001760 else if (!strcmp(args[0], "reqtarpit")) { /* tarpit a request if a header matches this regex */
1761 regex_t *preg;
1762 if (curproxy == &defproxy) {
1763 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1764 return -1;
1765 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001766 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1767 return 0;
1768
Willy Tarreaub8750a82006-09-03 09:56:00 +02001769 if (*(args[1]) == 0) {
1770 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1771 return -1;
1772 }
1773
1774 preg = calloc(1, sizeof(regex_t));
1775 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1776 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1777 return -1;
1778 }
1779
1780 chain_regex(&curproxy->req_exp, preg, ACT_TARPIT, NULL);
1781 }
Willy Tarreaua496b602006-12-17 23:15:24 +01001782 else if (!strcmp(args[0], "reqsetbe")) { /* switch the backend from a regex, respecting case */
1783 regex_t *preg;
Willy Tarreau977b8e42006-12-29 14:19:17 +01001784 if (curproxy == &defproxy) {
Willy Tarreaua496b602006-12-17 23:15:24 +01001785 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1786 return -1;
1787 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001788 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1789 return 0;
Willy Tarreaua496b602006-12-17 23:15:24 +01001790
Willy Tarreau977b8e42006-12-29 14:19:17 +01001791 if (*(args[1]) == 0 || *(args[2]) == 0) {
Willy Tarreaua496b602006-12-17 23:15:24 +01001792 Alert("parsing [%s:%d] : '%s' expects <search> and <target> as arguments.\n",
1793 file, linenum, args[0]);
1794 return -1;
1795 }
1796
1797 preg = calloc(1, sizeof(regex_t));
Willy Tarreau977b8e42006-12-29 14:19:17 +01001798 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
Willy Tarreaua496b602006-12-17 23:15:24 +01001799 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1800 }
1801
1802 chain_regex(&curproxy->req_exp, preg, ACT_SETBE, strdup(args[2]));
1803 }
1804 else if (!strcmp(args[0], "reqisetbe")) { /* switch the backend from a regex, ignoring case */
1805 regex_t *preg;
Willy Tarreau977b8e42006-12-29 14:19:17 +01001806 if (curproxy == &defproxy) {
Willy Tarreaua496b602006-12-17 23:15:24 +01001807 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1808 return -1;
1809 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001810 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1811 return 0;
Willy Tarreaua496b602006-12-17 23:15:24 +01001812
Willy Tarreau977b8e42006-12-29 14:19:17 +01001813 if (*(args[1]) == 0 || *(args[2]) == 0) {
Willy Tarreaua496b602006-12-17 23:15:24 +01001814 Alert("parsing [%s:%d] : '%s' expects <search> and <target> as arguments.\n",
1815 file, linenum, args[0]);
1816 return -1;
1817 }
1818
1819 preg = calloc(1, sizeof(regex_t));
Willy Tarreau977b8e42006-12-29 14:19:17 +01001820 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
Willy Tarreaua496b602006-12-17 23:15:24 +01001821 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1822 }
1823
1824 chain_regex(&curproxy->req_exp, preg, ACT_SETBE, strdup(args[2]));
1825 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001826 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
1827 regex_t *preg;
1828 if (curproxy == &defproxy) {
1829 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1830 return -1;
1831 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001832 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1833 return 0;
1834
Willy Tarreaubaaee002006-06-26 02:48:02 +02001835 if (*(args[1]) == 0 || *(args[2]) == 0) {
1836 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
1837 file, linenum, args[0]);
1838 return -1;
1839 }
1840
1841 preg = calloc(1, sizeof(regex_t));
1842 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1843 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1844 return -1;
1845 }
1846
1847 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
1848 if (err) {
1849 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1850 file, linenum, *err);
1851 return -1;
1852 }
1853 }
1854 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
1855 regex_t *preg;
1856 if (curproxy == &defproxy) {
1857 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1858 return -1;
1859 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001860 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1861 return 0;
1862
Willy Tarreaubaaee002006-06-26 02:48:02 +02001863 if (*(args[1]) == 0) {
1864 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1865 return -1;
1866 }
1867
1868 preg = calloc(1, sizeof(regex_t));
1869 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1870 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1871 return -1;
1872 }
1873
1874 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
1875 }
1876 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
1877 regex_t *preg;
1878 if (curproxy == &defproxy) {
1879 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1880 return -1;
1881 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001882 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1883 return 0;
1884
Willy Tarreaubaaee002006-06-26 02:48:02 +02001885 if (*(args[1]) == 0) {
1886 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1887 return -1;
1888 }
1889
1890 preg = calloc(1, sizeof(regex_t));
1891 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1892 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1893 return -1;
1894 }
1895
1896 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
1897 }
1898 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
1899 regex_t *preg;
1900 if (curproxy == &defproxy) {
1901 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1902 return -1;
1903 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001904 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1905 return 0;
1906
Willy Tarreaubaaee002006-06-26 02:48:02 +02001907 if (*(args[1]) == 0) {
1908 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1909 return -1;
1910 }
1911
1912 preg = calloc(1, sizeof(regex_t));
1913 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1914 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1915 return -1;
1916 }
1917
1918 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
1919 }
1920 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
1921 regex_t *preg;
1922 if (curproxy == &defproxy) {
1923 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1924 return -1;
1925 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001926 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1927 return 0;
1928
Willy Tarreaubaaee002006-06-26 02:48:02 +02001929 if (*(args[1]) == 0) {
1930 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1931 return -1;
1932 }
1933
1934 preg = calloc(1, sizeof(regex_t));
1935 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1936 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1937 return -1;
1938 }
1939
1940 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
1941 }
Willy Tarreaub8750a82006-09-03 09:56:00 +02001942 else if (!strcmp(args[0], "reqitarpit")) { /* tarpit a request if a header matches this regex ignoring case */
1943 regex_t *preg;
1944 if (curproxy == &defproxy) {
1945 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1946 return -1;
1947 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001948 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1949 return 0;
1950
Willy Tarreaub8750a82006-09-03 09:56:00 +02001951 if (*(args[1]) == 0) {
1952 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1953 return -1;
1954 }
1955
1956 preg = calloc(1, sizeof(regex_t));
1957 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1958 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1959 return -1;
1960 }
1961
1962 chain_regex(&curproxy->req_exp, preg, ACT_TARPIT, NULL);
1963 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001964 else if (!strcmp(args[0], "reqadd")) { /* add request header */
1965 if (curproxy == &defproxy) {
1966 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1967 return -1;
1968 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001969 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1970 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001971
1972 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
1973 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
1974 return 0;
1975 }
1976
1977 if (*(args[1]) == 0) {
1978 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
1979 return -1;
1980 }
1981
1982 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
1983 }
1984 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
1985 regex_t *preg;
1986
1987 if (*(args[1]) == 0 || *(args[2]) == 0) {
1988 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
1989 file, linenum, args[0]);
1990 return -1;
1991 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001992 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1993 return 0;
1994
Willy Tarreaubaaee002006-06-26 02:48:02 +02001995 preg = calloc(1, sizeof(regex_t));
1996 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1997 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1998 return -1;
1999 }
2000
2001 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
2002 if (err) {
2003 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
2004 file, linenum, *err);
2005 return -1;
2006 }
2007 }
2008 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
2009 regex_t *preg;
2010 if (curproxy == &defproxy) {
2011 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2012 return -1;
2013 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002014 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2015 return 0;
2016
Willy Tarreaubaaee002006-06-26 02:48:02 +02002017 if (*(args[1]) == 0) {
2018 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
2019 return -1;
2020 }
2021
2022 preg = calloc(1, sizeof(regex_t));
2023 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
2024 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2025 return -1;
2026 }
2027
2028 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
2029 if (err) {
2030 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
2031 file, linenum, *err);
2032 return -1;
2033 }
2034 }
2035 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
2036 regex_t *preg;
2037 if (curproxy == &defproxy) {
2038 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2039 return -1;
2040 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002041 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2042 return 0;
2043
Willy Tarreaubaaee002006-06-26 02:48:02 +02002044 if (*(args[1]) == 0) {
2045 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
2046 return -1;
2047 }
2048
2049 preg = calloc(1, sizeof(regex_t));
2050 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
2051 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2052 return -1;
2053 }
2054
2055 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
2056 if (err) {
2057 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
2058 file, linenum, *err);
2059 return -1;
2060 }
2061 }
2062 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
2063 regex_t *preg;
2064 if (curproxy == &defproxy) {
2065 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2066 return -1;
2067 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002068 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2069 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002070
2071 if (*(args[1]) == 0 || *(args[2]) == 0) {
2072 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
2073 file, linenum, args[0]);
2074 return -1;
2075 }
2076
2077 preg = calloc(1, sizeof(regex_t));
2078 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
2079 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2080 return -1;
2081 }
2082
2083 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
2084 if (err) {
2085 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
2086 file, linenum, *err);
2087 return -1;
2088 }
2089 }
2090 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
2091 regex_t *preg;
2092 if (curproxy == &defproxy) {
2093 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2094 return -1;
2095 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002096 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2097 return 0;
2098
Willy Tarreaubaaee002006-06-26 02:48:02 +02002099 if (*(args[1]) == 0) {
2100 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
2101 return -1;
2102 }
2103
2104 preg = calloc(1, sizeof(regex_t));
2105 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
2106 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2107 return -1;
2108 }
2109
2110 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
2111 if (err) {
2112 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
2113 file, linenum, *err);
2114 return -1;
2115 }
2116 }
2117 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
2118 regex_t *preg;
2119 if (curproxy == &defproxy) {
2120 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2121 return -1;
2122 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002123 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2124 return 0;
2125
Willy Tarreaubaaee002006-06-26 02:48:02 +02002126 if (*(args[1]) == 0) {
2127 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
2128 return -1;
2129 }
2130
2131 preg = calloc(1, sizeof(regex_t));
2132 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
2133 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2134 return -1;
2135 }
2136
2137 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
2138 if (err) {
2139 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
2140 file, linenum, *err);
2141 return -1;
2142 }
2143 }
2144 else if (!strcmp(args[0], "rspadd")) { /* add response header */
2145 if (curproxy == &defproxy) {
2146 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2147 return -1;
2148 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002149 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2150 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002151
2152 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
2153 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
2154 return 0;
2155 }
2156
2157 if (*(args[1]) == 0) {
2158 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
2159 return -1;
2160 }
2161
2162 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
2163 }
2164 else if (!strcmp(args[0], "errorloc") ||
2165 !strcmp(args[0], "errorloc302") ||
2166 !strcmp(args[0], "errorloc303")) { /* error location */
2167 int errnum, errlen;
2168 char *err;
2169
Willy Tarreau977b8e42006-12-29 14:19:17 +01002170 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
2171 return 0;
2172
Willy Tarreaubaaee002006-06-26 02:48:02 +02002173 if (*(args[2]) == 0) {
Willy Tarreau0f772532006-12-23 20:51:41 +01002174 Alert("parsing [%s:%d] : <%s> expects <status_code> and <url> as arguments.\n", file, linenum);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002175 return -1;
2176 }
2177
2178 errnum = atol(args[1]);
2179 if (!strcmp(args[0], "errorloc303")) {
2180 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
2181 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
2182 } else {
2183 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
2184 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
2185 }
2186
Willy Tarreau0f772532006-12-23 20:51:41 +01002187 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
2188 if (http_err_codes[rc] == errnum) {
2189 if (curproxy->errmsg[rc].str)
2190 free(curproxy->errmsg[rc].str);
2191 curproxy->errmsg[rc].str = err;
2192 curproxy->errmsg[rc].len = errlen;
2193 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002194 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002195 }
Willy Tarreau0f772532006-12-23 20:51:41 +01002196
2197 if (rc >= HTTP_ERR_SIZE) {
2198 Warning("parsing [%s:%d] : status code %d not handled, error relocation will be ignored.\n",
2199 file, linenum, errnum);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002200 free(err);
2201 }
2202 }
Willy Tarreau3f49b302007-06-11 00:29:26 +02002203 else if (!strcmp(args[0], "errorfile")) { /* error message from a file */
2204 int errnum, errlen, fd;
2205 char *err;
2206 struct stat stat;
2207
2208 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
2209 return 0;
2210
2211 if (*(args[2]) == 0) {
2212 Alert("parsing [%s:%d] : <%s> expects <status_code> and <file> as arguments.\n", file, linenum);
2213 return -1;
2214 }
2215
2216 fd = open(args[2], O_RDONLY);
2217 if ((fd < 0) || (fstat(fd, &stat) < 0)) {
2218 Alert("parsing [%s:%d] : error opening file <%s> for custom error message <%s>.\n",
2219 file, linenum, args[2], args[1]);
2220 if (fd >= 0)
2221 close(fd);
2222 return -1;
2223 }
2224
2225 if (stat.st_size <= BUFSIZE) {
2226 errlen = stat.st_size;
2227 } else {
2228 Warning("parsing [%s:%d] : custom error message file <%s> larger than %d bytes. Truncating.\n",
2229 file, linenum, args[2], BUFSIZE);
2230 errlen = BUFSIZE;
2231 }
2232
2233 err = malloc(errlen); /* malloc() must succeed during parsing */
2234 errnum = read(fd, err, errlen);
2235 if (errnum != errlen) {
2236 Alert("parsing [%s:%d] : error reading file <%s> for custom error message <%s>.\n",
2237 file, linenum, args[2], args[1]);
2238 close(fd);
2239 free(err);
2240 return -1;
2241 }
2242 close(fd);
2243
2244 errnum = atol(args[1]);
2245 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
2246 if (http_err_codes[rc] == errnum) {
2247 if (curproxy->errmsg[rc].str)
2248 free(curproxy->errmsg[rc].str);
2249 curproxy->errmsg[rc].str = err;
2250 curproxy->errmsg[rc].len = errlen;
2251 break;
2252 }
2253 }
2254
2255 if (rc >= HTTP_ERR_SIZE) {
2256 Warning("parsing [%s:%d] : status code %d not handled, error customization will be ignored.\n",
2257 file, linenum, errnum);
2258 free(err);
2259 }
2260 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002261 else {
2262 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
2263 return -1;
2264 }
2265 return 0;
2266}
2267
2268
2269/*
2270 * This function reads and parses the configuration file given in the argument.
2271 * returns 0 if OK, -1 if error.
2272 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02002273int readcfgfile(const char *file)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002274{
2275 char thisline[256];
2276 char *line;
2277 FILE *f;
2278 int linenum = 0;
2279 char *end;
Willy Tarreau540abe42007-05-02 20:50:16 +02002280 char *args[MAX_LINE_ARGS + 1];
Willy Tarreaubaaee002006-06-26 02:48:02 +02002281 int arg;
2282 int cfgerr = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002283 int confsect = CFG_NONE;
2284
2285 struct proxy *curproxy = NULL;
2286 struct server *newsrv = NULL;
2287
2288 if ((f=fopen(file,"r")) == NULL)
2289 return -1;
2290
2291 init_default_instance();
2292
2293 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
2294 linenum++;
2295
2296 end = line + strlen(line);
2297
2298 /* skip leading spaces */
Willy Tarreau8f8e6452007-06-17 21:51:38 +02002299 while (isspace((unsigned char)*line))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002300 line++;
2301
2302 arg = 0;
2303 args[arg] = line;
2304
2305 while (*line && arg < MAX_LINE_ARGS) {
2306 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
2307 * C equivalent value. Other combinations left unchanged (eg: \1).
2308 */
2309 if (*line == '\\') {
2310 int skip = 0;
2311 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
2312 *line = line[1];
2313 skip = 1;
2314 }
2315 else if (line[1] == 'r') {
2316 *line = '\r';
2317 skip = 1;
2318 }
2319 else if (line[1] == 'n') {
2320 *line = '\n';
2321 skip = 1;
2322 }
2323 else if (line[1] == 't') {
2324 *line = '\t';
2325 skip = 1;
2326 }
2327 else if (line[1] == 'x') {
2328 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
2329 unsigned char hex1, hex2;
2330 hex1 = toupper(line[2]) - '0';
2331 hex2 = toupper(line[3]) - '0';
2332 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2333 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2334 *line = (hex1<<4) + hex2;
2335 skip = 3;
2336 }
2337 else {
2338 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
2339 return -1;
2340 }
2341 }
2342 if (skip) {
2343 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
2344 end -= skip;
2345 }
2346 line++;
2347 }
2348 else if (*line == '#' || *line == '\n' || *line == '\r') {
2349 /* end of string, end of loop */
2350 *line = 0;
2351 break;
2352 }
Willy Tarreau8f8e6452007-06-17 21:51:38 +02002353 else if (isspace((unsigned char)*line)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002354 /* a non-escaped space is an argument separator */
2355 *line++ = 0;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02002356 while (isspace((unsigned char)*line))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002357 line++;
2358 args[++arg] = line;
2359 }
2360 else {
2361 line++;
2362 }
2363 }
2364
2365 /* empty line */
2366 if (!**args)
2367 continue;
2368
Willy Tarreau540abe42007-05-02 20:50:16 +02002369 /* zero out remaining args and ensure that at least one entry
2370 * is zeroed out.
2371 */
2372 while (++arg <= MAX_LINE_ARGS) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002373 args[arg] = line;
2374 }
2375
Willy Tarreau977b8e42006-12-29 14:19:17 +01002376 if (!strcmp(args[0], "listen") ||
2377 !strcmp(args[0], "frontend") ||
2378 !strcmp(args[0], "backend") ||
2379 !strcmp(args[0], "ruleset") ||
2380 !strcmp(args[0], "defaults")) /* new proxy */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002381 confsect = CFG_LISTEN;
2382 else if (!strcmp(args[0], "global")) /* global config */
2383 confsect = CFG_GLOBAL;
2384 /* else it's a section keyword */
2385
2386 switch (confsect) {
2387 case CFG_LISTEN:
2388 if (cfg_parse_listen(file, linenum, args) < 0)
2389 return -1;
2390 break;
2391 case CFG_GLOBAL:
2392 if (cfg_parse_global(file, linenum, args) < 0)
2393 return -1;
2394 break;
2395 default:
2396 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
2397 return -1;
2398 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002399 }
2400 fclose(f);
2401
2402 /*
2403 * Now, check for the integrity of all that we have collected.
2404 */
2405
2406 /* will be needed further to delay some tasks */
2407 tv_now(&now);
2408
2409 if ((curproxy = proxy) == NULL) {
2410 Alert("parsing %s : no <listen> line. Nothing to do !\n",
2411 file);
2412 return -1;
2413 }
2414
2415 while (curproxy != NULL) {
Willy Tarreau55ea7572007-06-17 19:56:27 +02002416 struct switching_rule *rule;
2417
Willy Tarreaubaaee002006-06-26 02:48:02 +02002418 if (curproxy->state == PR_STSTOPPED) {
2419 curproxy = curproxy->next;
2420 continue;
2421 }
2422
Willy Tarreau977b8e42006-12-29 14:19:17 +01002423 if (curproxy->cap & PR_CAP_FE && curproxy->listen == NULL) {
2424 Alert("parsing %s : %s '%s' has no listen address. Please either specify a valid address on the <listen> line, or use the <bind> keyword.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002425 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002426 cfgerr++;
2427 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002428 else if (curproxy->cap & PR_CAP_BE &&
2429 ((curproxy->mode != PR_MODE_HEALTH) &&
2430 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
2431 (*(int *)&curproxy->dispatch_addr.sin_addr == 0))) {
2432 Alert("parsing %s : %s '%s' has no dispatch address and is not in transparent or balance mode.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002433 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002434 cfgerr++;
2435 }
Willy Tarreau193cf932007-09-17 10:17:23 +02002436
2437 if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002438 if (curproxy->options & PR_O_TRANSP) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002439 Alert("parsing %s : %s '%s' cannot use both transparent and balance mode.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002440 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002441 cfgerr++;
2442 }
2443#ifdef WE_DONT_SUPPORT_SERVERLESS_LISTENERS
2444 else if (curproxy->srv == NULL) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002445 Alert("parsing %s : %s '%s' needs at least 1 server in balance mode.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002446 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002447 cfgerr++;
2448 }
2449#endif
2450 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002451 Warning("parsing %s : dispatch address of %s '%s' will be ignored in balance mode.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002452 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002453 }
2454 }
Willy Tarreau193cf932007-09-17 10:17:23 +02002455
2456 if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002457 if (curproxy->cookie_name != NULL) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002458 Warning("parsing %s : cookie will be ignored for %s '%s'.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002459 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002460 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002461 if (curproxy->rsp_exp != NULL) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002462 Warning("parsing %s : server regular expressions will be ignored for %s '%s'.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002463 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002464 }
2465 if (curproxy->req_exp != NULL) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002466 Warning("parsing %s : client regular expressions will be ignored for %s '%s'.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002467 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002468 }
Willy Tarreau1c47f852006-07-09 08:22:27 +02002469 if (curproxy->monitor_uri != NULL) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002470 Warning("parsing %s : monitor-uri will be ignored for %s '%s'.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002471 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreau1c47f852006-07-09 08:22:27 +02002472 }
Willy Tarreau2fcb5002007-05-08 13:35:26 +02002473 if (curproxy->options & PR_O_BALANCE_UH) {
2474 curproxy->options &= ~PR_O_BALANCE;
2475 curproxy->options |= PR_O_BALANCE_RR;
2476
2477 Warning("parsing %s : URI hash will be ignored for %s '%s'. Falling back to round robin.\n",
2478 file, proxy_type_str(curproxy), curproxy->id);
2479 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002480 }
Willy Tarreau193cf932007-09-17 10:17:23 +02002481
2482 if (curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
2483 if ((newsrv = curproxy->srv) != NULL) {
2484 Warning("parsing %s : servers will be ignored for %s '%s'.\n",
2485 file, proxy_type_str(curproxy), curproxy->id);
2486 }
2487 }
2488
2489 if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002490 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
2491 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
2492 file, curproxy->id);
2493 cfgerr++;
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002494 }
2495 }
2496
2497 /* if a default backend was specified, let's find it */
2498 if (curproxy->defbe.name) {
2499 struct proxy *target;
2500
2501 for (target = proxy; target != NULL; target = target->next) {
2502 if (strcmp(target->id, curproxy->defbe.name) == 0)
2503 break;
2504 }
2505 if (target == NULL) {
2506 Alert("parsing %s : default backend '%s' in HTTP %s '%s' was not found !\n",
2507 file, curproxy->defbe.name, proxy_type_str(curproxy), curproxy->id);
2508 cfgerr++;
2509 } else if (target == curproxy) {
2510 Alert("parsing %s : loop detected for default backend %s !\n", file, curproxy->defbe.name);
2511 cfgerr++;
2512 } else if (!(target->cap & PR_CAP_BE)) {
2513 Alert("parsing %s : default backend '%s' in HTTP %s '%s' has no backend capability !\n",
2514 file, curproxy->defbe.name, proxy_type_str(curproxy), curproxy->id);
2515 cfgerr++;
2516 } else if (target->mode != curproxy->mode) {
2517 Alert("parsing %s : default backend '%s' in HTTP %s '%s' is not of same mode (tcp/http) !\n",
2518 file, curproxy->defbe.name, proxy_type_str(curproxy), curproxy->id);
2519 cfgerr++;
2520 } else {
2521 free(curproxy->defbe.name);
2522 curproxy->defbe.be = target;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002523 }
2524 }
2525
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002526 /* find the target proxy in setbe */
Willy Tarreaua496b602006-12-17 23:15:24 +01002527 if (curproxy->mode == PR_MODE_HTTP && curproxy->req_exp != NULL) {
2528 /* map jump target for ACT_SETBE in req_rep chain */
2529 struct hdr_exp *exp;
2530 struct proxy *target;
2531 for (exp = curproxy->req_exp; exp != NULL; exp = exp->next) {
2532 if (exp->action != ACT_SETBE)
2533 continue;
2534 for (target = proxy; target != NULL; target = target->next) {
2535 if (strcmp(target->id, exp->replace) == 0)
2536 break;
2537 }
2538 if (target == NULL) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002539 Alert("parsing %s : backend '%s' in HTTP %s '%s' was not found !\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002540 file, exp->replace, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaua496b602006-12-17 23:15:24 +01002541 cfgerr++;
2542 } else if (target == curproxy) {
2543 Alert("parsing %s : loop detected for backend %s !\n", file, exp->replace);
2544 cfgerr++;
Willy Tarreau977b8e42006-12-29 14:19:17 +01002545 } else if (!(target->cap & PR_CAP_BE)) {
2546 Alert("parsing %s : target '%s' in HTTP %s '%s' has no backend capability !\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002547 file, exp->replace, proxy_type_str(curproxy), curproxy->id);
Willy Tarreau977b8e42006-12-29 14:19:17 +01002548 cfgerr++;
2549 } else if (target->mode != PR_MODE_HTTP) {
2550 Alert("parsing %s : backend '%s' in HTTP %s '%s' is not HTTP (use 'mode http') !\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002551 file, exp->replace, proxy_type_str(curproxy), curproxy->id);
Willy Tarreau977b8e42006-12-29 14:19:17 +01002552 cfgerr++;
Willy Tarreaua496b602006-12-17 23:15:24 +01002553 } else {
2554 free((void *)exp->replace);
2555 exp->replace = (const char *)target;
2556 }
2557 }
2558 }
Willy Tarreau55ea7572007-06-17 19:56:27 +02002559
2560 /* find the target proxy for 'use_backend' rules */
2561 list_for_each_entry(rule, &curproxy->switching_rules, list) {
2562 /* map jump target for ACT_SETBE in req_rep chain */
2563 struct proxy *target;
2564
2565 for (target = proxy; target != NULL; target = target->next) {
2566 if (strcmp(target->id, rule->be.name) == 0)
2567 break;
2568 }
2569
2570 if (target == NULL) {
2571 Alert("parsing %s : backend '%s' in HTTP %s '%s' was not found !\n",
2572 file, rule->be.name, proxy_type_str(curproxy), curproxy->id);
2573 cfgerr++;
2574 } else if (target == curproxy) {
2575 Alert("parsing %s : loop detected for backend %s !\n", file, rule->be.name);
2576 cfgerr++;
2577 } else if (!(target->cap & PR_CAP_BE)) {
2578 Alert("parsing %s : target '%s' in HTTP %s '%s' has no backend capability !\n",
2579 file, rule->be.name, proxy_type_str(curproxy), curproxy->id);
2580 cfgerr++;
2581 } else if (target->mode != curproxy->mode) {
2582 Alert("parsing %s : backend '%s' referenced in %s '%s' is of different mode !\n",
2583 file, rule->be.name, proxy_type_str(curproxy), curproxy->id);
2584 cfgerr++;
2585 } else {
2586 free((void *)rule->be.name);
2587 rule->be.backend = target;
2588 }
2589 }
2590
Willy Tarreau2738a142006-07-08 17:28:09 +02002591 if ((curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HTTP) &&
Willy Tarreaud825eef2007-05-12 22:35:00 +02002592 (((curproxy->cap & PR_CAP_FE) && !tv_isset(&curproxy->clitimeout)) ||
2593 ((curproxy->cap & PR_CAP_BE) && (curproxy->srv) &&
2594 (!tv_isset(&curproxy->contimeout) || !tv_isset(&curproxy->srvtimeout))))) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002595 Warning("parsing %s : missing timeouts for %s '%s'.\n"
Willy Tarreau2738a142006-07-08 17:28:09 +02002596 " | While not properly invalid, you will certainly encounter various problems\n"
2597 " | with such a configuration. To fix this, please ensure that all following\n"
2598 " | values are set to a non-zero value: clitimeout, contimeout, srvtimeout.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002599 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreau2738a142006-07-08 17:28:09 +02002600 }
Willy Tarreauf3c69202006-07-09 16:42:34 +02002601
2602 if (curproxy->options & PR_O_SSL3_CHK) {
2603 curproxy->check_len = sizeof(sslv3_client_hello_pkt);
2604 curproxy->check_req = (char *)malloc(sizeof(sslv3_client_hello_pkt));
2605 memcpy(curproxy->check_req, sslv3_client_hello_pkt, sizeof(sslv3_client_hello_pkt));
2606 }
2607
Willy Tarreaucf7f3202007-05-13 22:46:04 +02002608 /* The small pools required for the capture lists */
2609 if (curproxy->nb_req_cap)
2610 curproxy->req_cap_pool = create_pool("ptrcap",
2611 curproxy->nb_req_cap * sizeof(char *),
2612 MEM_F_SHARED);
2613 if (curproxy->nb_rsp_cap)
2614 curproxy->rsp_cap_pool = create_pool("ptrcap",
2615 curproxy->nb_rsp_cap * sizeof(char *),
2616 MEM_F_SHARED);
2617
Willy Tarreau1d4154a2007-05-13 22:57:02 +02002618 curproxy->hdr_idx_pool = create_pool("hdr_idx",
2619 MAX_HTTP_HDR * sizeof(struct hdr_idx_elem),
2620 MEM_F_SHARED);
2621
Willy Tarreau86034312006-12-29 00:10:33 +01002622 /* for backwards compatibility with "listen" instances, if
2623 * fullconn is not set but maxconn is set, then maxconn
2624 * is used.
2625 */
2626 if (!curproxy->fullconn)
2627 curproxy->fullconn = curproxy->maxconn;
2628
Willy Tarreaubaaee002006-06-26 02:48:02 +02002629 /* first, we will invert the servers list order */
2630 newsrv = NULL;
2631 while (curproxy->srv) {
2632 struct server *next;
2633
2634 next = curproxy->srv->next;
2635 curproxy->srv->next = newsrv;
2636 newsrv = curproxy->srv;
2637 if (!next)
2638 break;
2639 curproxy->srv = next;
2640 }
2641
2642 /* now, newsrv == curproxy->srv */
2643 if (newsrv) {
2644 struct server *srv;
2645 int pgcd;
2646 int act, bck;
2647
2648 /* We will factor the weights to reduce the table,
2649 * using Euclide's largest common divisor algorithm
2650 */
Willy Tarreau417fae02007-03-25 21:16:40 +02002651 pgcd = newsrv->uweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002652 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
2653 int t, w;
2654
Willy Tarreau417fae02007-03-25 21:16:40 +02002655 w = srv->uweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002656 while (w) {
2657 t = pgcd % w;
2658 pgcd = w;
2659 w = t;
2660 }
2661 }
2662
2663 act = bck = 0;
2664 for (srv = newsrv; srv; srv = srv->next) {
Willy Tarreau417fae02007-03-25 21:16:40 +02002665 srv->eweight = srv->uweight / pgcd;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002666 if (srv->state & SRV_BACKUP)
Willy Tarreau417fae02007-03-25 21:16:40 +02002667 bck += srv->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002668 else
Willy Tarreau417fae02007-03-25 21:16:40 +02002669 act += srv->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002670 }
2671
2672 /* this is the largest map we will ever need for this servers list */
2673 if (act < bck)
2674 act = bck;
2675
2676 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
2677 /* recounts servers and their weights */
Willy Tarreau5af3a692007-07-24 23:32:33 +02002678 curproxy->map_state = PR_MAP_RECALC;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002679 recount_servers(curproxy);
2680 recalc_server_map(curproxy);
2681 }
2682
2683 if (curproxy->options & PR_O_LOGASAP)
2684 curproxy->to_log &= ~LW_BYTES;
2685
Willy Tarreaubaaee002006-06-26 02:48:02 +02002686 /*
2687 * If this server supports a maxconn parameter, it needs a dedicated
2688 * tasks to fill the emptied slots when a connection leaves.
2689 */
2690 newsrv = curproxy->srv;
2691 while (newsrv != NULL) {
Willy Tarreau86034312006-12-29 00:10:33 +01002692 if (newsrv->minconn > newsrv->maxconn) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002693 /* Only 'minconn' was specified, or it was higher than or equal
2694 * to 'maxconn'. Let's turn this into maxconn and clean it, as
2695 * this will avoid further useless expensive computations.
2696 */
2697 newsrv->maxconn = newsrv->minconn;
Willy Tarreau86034312006-12-29 00:10:33 +01002698 } else if (newsrv->maxconn && !newsrv->minconn) {
2699 /* minconn was not specified, so we set it to maxconn */
2700 newsrv->minconn = newsrv->maxconn;
Willy Tarreau977b8e42006-12-29 14:19:17 +01002701 } else if (newsrv->minconn != newsrv->maxconn && !curproxy->fullconn) {
2702 Alert("parsing %s, %s '%s' : fullconn is mandatory when minconn is set on a server.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002703 file, proxy_type_str(curproxy), curproxy->id, linenum);
Willy Tarreau86034312006-12-29 00:10:33 +01002704 return -1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002705 }
2706
2707 if (newsrv->maxconn > 0) {
2708 struct task *t;
2709
Willy Tarreauc6ca1a02007-05-13 19:43:47 +02002710 if ((t = pool_alloc2(pool2_task)) == NULL) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002711 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2712 return -1;
2713 }
2714
Willy Tarreau96bcfd72007-04-29 10:41:56 +02002715 t->qlist.p = NULL;
Willy Tarreau964c9362007-01-07 00:38:00 +01002716 t->wq = NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002717 t->state = TASK_IDLE;
2718 t->process = process_srv_queue;
2719 t->context = newsrv;
2720 newsrv->queue_mgt = t;
2721
2722 /* never run it unless specifically woken up */
2723 tv_eternity(&t->expire);
2724 task_queue(t);
2725 }
2726 newsrv = newsrv->next;
2727 }
2728
Willy Tarreaubaaee002006-06-26 02:48:02 +02002729 curproxy = curproxy->next;
2730 }
2731 if (cfgerr > 0) {
2732 Alert("Errors found in configuration file, aborting.\n");
2733 return -1;
2734 }
2735 else
2736 return 0;
2737}
2738
2739
2740
2741/*
2742 * Local variables:
2743 * c-indent-level: 8
2744 * c-basic-offset: 8
2745 * End:
2746 */