blob: c1eec25ccbc9ba138e05dcbfc074bcfb1e9b178a [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 },
95 { "logasap", PR_O_LOGASAP, PR_CAP_FE, 0 },
96 { "abortonclose", PR_O_ABRT_CLOSE, PR_CAP_BE, 0 },
97 { "checkcache", PR_O_CHK_CACHE, PR_CAP_BE, 0 },
98 { "dontlognull", PR_O_NULLNOLOG, PR_CAP_FE, 0 },
99 { "clitcpka", PR_O_TCP_CLI_KA, PR_CAP_FE, 0 },
100 { "srvtcpka", PR_O_TCP_SRV_KA, PR_CAP_BE, 0 },
101 { "allbackups", PR_O_USE_ALL_BK, PR_CAP_BE, 0 },
102 { "persist", PR_O_PERSIST, PR_CAP_BE, 0 },
103 { "forceclose", PR_O_FORCE_CLO | PR_O_HTTP_CLOSE, PR_CAP_BE, 0 },
Willy Tarreau8f922fc2007-01-06 21:11:49 +0100104#ifdef CONFIG_HAP_TCPSPLICE
105 { "tcpsplice", PR_O_TCPSPLICE , PR_CAP_BE|PR_CAP_FE, LSTCHK_TCPSPLICE|LSTCHK_NETADM },
106#endif
107
Willy Tarreau13943ab2006-12-31 00:24:10 +0100108 { NULL, 0, 0 }
109};
110
Willy Tarreaubaaee002006-06-26 02:48:02 +0200111
112static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
113int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
114int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
115
116/*
117 * converts <str> to a list of listeners which are dynamically allocated.
118 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
119 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
120 * - <port> is a numerical port from 1 to 65535 ;
121 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
122 * This can be repeated as many times as necessary, separated by a coma.
123 * The <tail> argument is a pointer to a current list which should be appended
124 * to the tail of the new list. The pointer to the new list is returned.
125 */
126static struct listener *str2listener(char *str, struct listener *tail)
127{
128 struct listener *l;
129 char *c, *next, *range, *dupstr;
130 int port, end;
131
132 next = dupstr = strdup(str);
133
134 while (next && *next) {
135 struct sockaddr_storage ss;
136
137 str = next;
138 /* 1) look for the end of the first address */
139 if ((next = strrchr(str, ',')) != NULL) {
140 *next++ = 0;
141 }
142
143 /* 2) look for the addr/port delimiter, it's the last colon. */
144 if ((range = strrchr(str, ':')) == NULL) {
145 Alert("Missing port number: '%s'\n", str);
146 goto fail;
147 }
148
149 *range++ = 0;
150
151 if (strrchr(str, ':') != NULL) {
152 /* IPv6 address contains ':' */
153 memset(&ss, 0, sizeof(ss));
154 ss.ss_family = AF_INET6;
155
156 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
157 Alert("Invalid server address: '%s'\n", str);
158 goto fail;
159 }
160 }
161 else {
162 memset(&ss, 0, sizeof(ss));
163 ss.ss_family = AF_INET;
164
165 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
166 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
167 }
168 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
169 struct hostent *he;
170
171 if ((he = gethostbyname(str)) == NULL) {
172 Alert("Invalid server name: '%s'\n", str);
173 goto fail;
174 }
175 else
176 ((struct sockaddr_in *)&ss)->sin_addr =
177 *(struct in_addr *) *(he->h_addr_list);
178 }
179 }
180
181 /* 3) look for the port-end delimiter */
182 if ((c = strchr(range, '-')) != NULL) {
183 *c++ = 0;
184 end = atol(c);
185 }
186 else {
187 end = atol(range);
188 }
189
190 port = atol(range);
191
192 if (port < 1 || port > 65535) {
193 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
194 goto fail;
195 }
196
197 if (end < 1 || end > 65535) {
198 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
199 goto fail;
200 }
201
202 for (; port <= end; port++) {
203 l = (struct listener *)calloc(1, sizeof(struct listener));
204 l->next = tail;
205 tail = l;
206
207 l->fd = -1;
208 l->addr = ss;
209 if (ss.ss_family == AF_INET6)
210 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
211 else
212 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
213
214 } /* end for(port) */
215 } /* end while(next) */
216 free(dupstr);
217 return tail;
218 fail:
219 free(dupstr);
220 return NULL;
221}
222
Willy Tarreau977b8e42006-12-29 14:19:17 +0100223/*
224 * Sends a warning if proxy <proxy> does not have at least one of the
225 * capabilities in <cap>. An optionnal <hint> may be added at the end
226 * of the warning to help the user. Returns 1 if a warning was emitted
227 * or 0 if the condition is valid.
228 */
229int warnifnotcap(struct proxy *proxy, int cap, const char *file, int line, char *arg, char *hint)
230{
231 char *msg;
232
233 switch (cap) {
234 case PR_CAP_BE: msg = "no backend"; break;
235 case PR_CAP_FE: msg = "no frontend"; break;
236 case PR_CAP_RS: msg = "no ruleset"; break;
237 case PR_CAP_BE|PR_CAP_FE: msg = "neither frontend nor backend"; break;
238 default: msg = "not enough"; break;
239 }
240
241 if (!(proxy->cap & cap)) {
242 Warning("parsing [%s:%d] : '%s' ignored because %s '%s' has %s capability.%s\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +0100243 file, line, arg, proxy_type_str(proxy), proxy->id, msg, hint ? hint : "");
Willy Tarreau977b8e42006-12-29 14:19:17 +0100244 return 1;
245 }
246 return 0;
247}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200248
249/*
250 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
251 */
Willy Tarreaub17916e2006-10-15 15:17:57 +0200252int cfg_parse_global(const char *file, int linenum, char **args)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200253{
254
255 if (!strcmp(args[0], "global")) { /* new section */
256 /* no option, nothing special to do */
257 return 0;
258 }
259 else if (!strcmp(args[0], "daemon")) {
260 global.mode |= MODE_DAEMON;
261 }
262 else if (!strcmp(args[0], "debug")) {
263 global.mode |= MODE_DEBUG;
264 }
265 else if (!strcmp(args[0], "noepoll")) {
266 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
267 }
Willy Tarreaude99e992007-04-16 00:53:59 +0200268 else if (!strcmp(args[0], "nosepoll")) {
269 cfg_polling_mechanism &= ~POLL_USE_SEPOLL;
270 }
271 else if (!strcmp(args[0], "nokqueue")) {
272 cfg_polling_mechanism &= ~POLL_USE_KQUEUE;
273 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200274 else if (!strcmp(args[0], "nopoll")) {
275 cfg_polling_mechanism &= ~POLL_USE_POLL;
276 }
277 else if (!strcmp(args[0], "quiet")) {
278 global.mode |= MODE_QUIET;
279 }
280 else if (!strcmp(args[0], "stats")) {
281 global.mode |= MODE_STATS;
282 }
Willy Tarreau1db37712007-06-03 17:16:49 +0200283 else if (!strcmp(args[0], "tune.maxpollevents")) {
284 if (global.tune.maxpollevents != 0) {
285 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
286 return 0;
287 }
288 if (*(args[1]) == 0) {
289 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
290 return -1;
291 }
292 global.tune.maxpollevents = atol(args[1]);
293 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200294 else if (!strcmp(args[0], "uid")) {
295 if (global.uid != 0) {
Willy Tarreau95c20ac2007-03-25 15:39:23 +0200296 Alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200297 return 0;
298 }
299 if (*(args[1]) == 0) {
300 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
301 return -1;
302 }
303 global.uid = atol(args[1]);
304 }
305 else if (!strcmp(args[0], "gid")) {
306 if (global.gid != 0) {
Willy Tarreau95c20ac2007-03-25 15:39:23 +0200307 Alert("parsing [%s:%d] : group/gid already specified. Continuing.\n", file, linenum);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200308 return 0;
309 }
310 if (*(args[1]) == 0) {
311 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
312 return -1;
313 }
314 global.gid = atol(args[1]);
315 }
Willy Tarreau95c20ac2007-03-25 15:39:23 +0200316 /* user/group name handling */
317 else if (!strcmp(args[0], "user")) {
318 struct passwd *ha_user;
319 if (global.uid != 0) {
320 Alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum);
321 return 0;
322 }
323 errno = 0;
324 ha_user = getpwnam(args[1]);
325 if (ha_user != NULL) {
326 global.uid = (int)ha_user->pw_uid;
327 }
328 else {
329 Alert("parsing [%s:%d] : cannot find user id for '%s' (%d:%s)\n", file, linenum, args[1], errno, strerror(errno));
330 exit(1);
331 }
332 }
333 else if (!strcmp(args[0], "group")) {
334 struct group *ha_group;
335 if (global.gid != 0) {
336 Alert("parsing [%s:%d] : gid/group was already specified. Continuing.\n", file, linenum, args[0]);
337 return 0;
338 }
339 errno = 0;
340 ha_group = getgrnam(args[1]);
341 if (ha_group != NULL) {
342 global.gid = (int)ha_group->gr_gid;
343 }
344 else {
345 Alert("parsing [%s:%d] : cannot find group id for '%s' (%d:%s)\n", file, linenum, args[1], errno, strerror(errno));
346 exit(1);
347 }
348 }
349 /* end of user/group name handling*/
Willy Tarreaubaaee002006-06-26 02:48:02 +0200350 else if (!strcmp(args[0], "nbproc")) {
351 if (global.nbproc != 0) {
352 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
353 return 0;
354 }
355 if (*(args[1]) == 0) {
356 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
357 return -1;
358 }
359 global.nbproc = atol(args[1]);
360 }
361 else if (!strcmp(args[0], "maxconn")) {
362 if (global.maxconn != 0) {
363 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
364 return 0;
365 }
366 if (*(args[1]) == 0) {
367 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
368 return -1;
369 }
370 global.maxconn = atol(args[1]);
371#ifdef SYSTEM_MAXCONN
372 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
373 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);
374 global.maxconn = DEFAULT_MAXCONN;
375 }
376#endif /* SYSTEM_MAXCONN */
377 }
378 else if (!strcmp(args[0], "ulimit-n")) {
379 if (global.rlimit_nofile != 0) {
380 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
381 return 0;
382 }
383 if (*(args[1]) == 0) {
384 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
385 return -1;
386 }
387 global.rlimit_nofile = atol(args[1]);
388 }
389 else if (!strcmp(args[0], "chroot")) {
390 if (global.chroot != NULL) {
391 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
392 return 0;
393 }
394 if (*(args[1]) == 0) {
395 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
396 return -1;
397 }
398 global.chroot = strdup(args[1]);
399 }
400 else if (!strcmp(args[0], "pidfile")) {
401 if (global.pidfile != NULL) {
402 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
403 return 0;
404 }
405 if (*(args[1]) == 0) {
406 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
407 return -1;
408 }
409 global.pidfile = strdup(args[1]);
410 }
411 else if (!strcmp(args[0], "log")) { /* syslog server address */
412 struct sockaddr_in *sa;
413 int facility, level;
414
415 if (*(args[1]) == 0 || *(args[2]) == 0) {
416 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
417 return -1;
418 }
419
420 facility = get_log_facility(args[2]);
421 if (facility < 0) {
422 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
423 exit(1);
424 }
425
426 level = 7; /* max syslog level = debug */
427 if (*(args[3])) {
428 level = get_log_level(args[3]);
429 if (level < 0) {
430 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
431 exit(1);
432 }
433 }
434
435 sa = str2sa(args[1]);
436 if (!sa->sin_port)
437 sa->sin_port = htons(SYSLOG_PORT);
438
439 if (global.logfac1 == -1) {
440 global.logsrv1 = *sa;
441 global.logfac1 = facility;
442 global.loglev1 = level;
443 }
444 else if (global.logfac2 == -1) {
445 global.logsrv2 = *sa;
446 global.logfac2 = facility;
447 global.loglev2 = level;
448 }
449 else {
450 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
451 return -1;
452 }
453
454 }
455 else {
456 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
457 return -1;
458 }
459 return 0;
460}
461
462
463static void init_default_instance()
464{
465 memset(&defproxy, 0, sizeof(defproxy));
466 defproxy.mode = PR_MODE_TCP;
467 defproxy.state = PR_STNEW;
468 defproxy.maxconn = cfg_maxpconn;
469 defproxy.conn_retries = CONN_RETRIES;
470 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
471}
472
473/*
Willy Tarreau977b8e42006-12-29 14:19:17 +0100474 * Parse a line in a <listen>, <frontend>, <backend> or <ruleset> section.
475 * Returns 0 if OK, -1 if error.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200476 */
Willy Tarreaub17916e2006-10-15 15:17:57 +0200477int cfg_parse_listen(const char *file, int linenum, char **args)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200478{
479 static struct proxy *curproxy = NULL;
480 struct server *newsrv = NULL;
Willy Tarreaub17916e2006-10-15 15:17:57 +0200481 const char *err;
Willy Tarreauee991362007-05-14 14:37:50 +0200482 int rc, val;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200483
Willy Tarreau977b8e42006-12-29 14:19:17 +0100484 if (!strcmp(args[0], "listen"))
485 rc = PR_CAP_LISTEN;
486 else if (!strcmp(args[0], "frontend"))
487 rc = PR_CAP_FE | PR_CAP_RS;
488 else if (!strcmp(args[0], "backend"))
489 rc = PR_CAP_BE | PR_CAP_RS;
490 else if (!strcmp(args[0], "ruleset"))
491 rc = PR_CAP_RS;
492 else
493 rc = PR_CAP_NONE;
494
495 if (rc != PR_CAP_NONE) { /* new proxy */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200496 if (!*args[1]) {
497 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
498 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
499 file, linenum, args[0]);
500 return -1;
501 }
502
503 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
504 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
505 return -1;
506 }
507
508 curproxy->next = proxy;
509 proxy = curproxy;
510 LIST_INIT(&curproxy->pendconns);
Willy Tarreaueb0c6142007-05-07 00:53:22 +0200511 LIST_INIT(&curproxy->acl);
Willy Tarreau5c8e3e02007-05-07 00:58:25 +0200512 LIST_INIT(&curproxy->block_cond);
Willy Tarreau55ea7572007-06-17 19:56:27 +0200513 LIST_INIT(&curproxy->switching_rules);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200514
Willy Tarreauee991362007-05-14 14:37:50 +0200515 /* Timeouts are defined as -1, so we cannot use the zeroed area
516 * as a default value.
517 */
518 tv_eternity(&curproxy->clitimeout);
519 tv_eternity(&curproxy->srvtimeout);
520 tv_eternity(&curproxy->contimeout);
521 tv_eternity(&curproxy->appsession_timeout);
522
Willy Tarreaubaaee002006-06-26 02:48:02 +0200523 curproxy->id = strdup(args[1]);
Willy Tarreau977b8e42006-12-29 14:19:17 +0100524 curproxy->cap = rc;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200525
526 /* parse the listener address if any */
Willy Tarreau977b8e42006-12-29 14:19:17 +0100527 if ((curproxy->cap & PR_CAP_FE) && *args[2]) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200528 curproxy->listen = str2listener(args[2], curproxy->listen);
529 if (!curproxy->listen)
530 return -1;
531 global.maxsock++;
532 }
533
534 /* set default values */
535 curproxy->state = defproxy.state;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200536 curproxy->options = defproxy.options;
Willy Tarreau7ac51f62007-03-25 16:00:04 +0200537 curproxy->except_net = defproxy.except_net;
538 curproxy->except_mask = defproxy.except_mask;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200539
Willy Tarreau977b8e42006-12-29 14:19:17 +0100540 if (curproxy->cap & PR_CAP_FE) {
541 curproxy->maxconn = defproxy.maxconn;
542
543 /* initialize error relocations */
544 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
545 if (defproxy.errmsg[rc].str)
546 chunk_dup(&curproxy->errmsg[rc], &defproxy.errmsg[rc]);
547 }
548
549 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
550 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200551
Willy Tarreau977b8e42006-12-29 14:19:17 +0100552 if (curproxy->cap & PR_CAP_BE) {
553 curproxy->fullconn = defproxy.fullconn;
554 curproxy->conn_retries = defproxy.conn_retries;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200555
Willy Tarreau977b8e42006-12-29 14:19:17 +0100556 if (defproxy.check_req)
557 curproxy->check_req = strdup(defproxy.check_req);
558 curproxy->check_len = defproxy.check_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200559
Willy Tarreau977b8e42006-12-29 14:19:17 +0100560 if (defproxy.cookie_name)
561 curproxy->cookie_name = strdup(defproxy.cookie_name);
562 curproxy->cookie_len = defproxy.cookie_len;
563 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200564
Willy Tarreau977b8e42006-12-29 14:19:17 +0100565 if (curproxy->cap & PR_CAP_RS) {
566 if (defproxy.capture_name)
567 curproxy->capture_name = strdup(defproxy.capture_name);
568 curproxy->capture_namelen = defproxy.capture_namelen;
569 curproxy->capture_len = defproxy.capture_len;
Willy Tarreau0f772532006-12-23 20:51:41 +0100570 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200571
Willy Tarreau977b8e42006-12-29 14:19:17 +0100572 if (curproxy->cap & PR_CAP_FE) {
573 curproxy->clitimeout = defproxy.clitimeout;
574 curproxy->uri_auth = defproxy.uri_auth;
575 curproxy->mon_net = defproxy.mon_net;
576 curproxy->mon_mask = defproxy.mon_mask;
577 if (defproxy.monitor_uri)
578 curproxy->monitor_uri = strdup(defproxy.monitor_uri);
579 curproxy->monitor_uri_len = defproxy.monitor_uri_len;
Willy Tarreau5fdfb912007-01-01 23:11:07 +0100580 if (defproxy.defbe.name)
581 curproxy->defbe.name = strdup(defproxy.defbe.name);
Willy Tarreau977b8e42006-12-29 14:19:17 +0100582 }
583
584 if (curproxy->cap & PR_CAP_BE) {
585 curproxy->contimeout = defproxy.contimeout;
586 curproxy->srvtimeout = defproxy.srvtimeout;
587 curproxy->source_addr = defproxy.source_addr;
588 }
589
Willy Tarreaubaaee002006-06-26 02:48:02 +0200590 curproxy->mode = defproxy.mode;
591 curproxy->logfac1 = defproxy.logfac1;
592 curproxy->logsrv1 = defproxy.logsrv1;
593 curproxy->loglev1 = defproxy.loglev1;
594 curproxy->logfac2 = defproxy.logfac2;
595 curproxy->logsrv2 = defproxy.logsrv2;
596 curproxy->loglev2 = defproxy.loglev2;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200597 curproxy->grace = defproxy.grace;
Willy Tarreau1c47f852006-07-09 08:22:27 +0200598
Willy Tarreaubaaee002006-06-26 02:48:02 +0200599 return 0;
600 }
601 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
602 /* some variables may have already been initialized earlier */
Willy Tarreau5fdfb912007-01-01 23:11:07 +0100603 /* FIXME-20070101: we should do this too at the end of the
604 * config parsing to free all default values.
605 */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200606 if (defproxy.check_req) free(defproxy.check_req);
607 if (defproxy.cookie_name) free(defproxy.cookie_name);
608 if (defproxy.capture_name) free(defproxy.capture_name);
Willy Tarreau1c47f852006-07-09 08:22:27 +0200609 if (defproxy.monitor_uri) free(defproxy.monitor_uri);
Willy Tarreau5fdfb912007-01-01 23:11:07 +0100610 if (defproxy.defbe.name) free(defproxy.defbe.name);
Willy Tarreau0f772532006-12-23 20:51:41 +0100611
612 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
613 if (defproxy.errmsg[rc].len)
614 free(defproxy.errmsg[rc].str);
615 }
616
Willy Tarreaubaaee002006-06-26 02:48:02 +0200617 /* we cannot free uri_auth because it might already be used */
618 init_default_instance();
619 curproxy = &defproxy;
Willy Tarreau977b8e42006-12-29 14:19:17 +0100620 defproxy.cap = PR_CAP_LISTEN; /* all caps for now */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200621 return 0;
622 }
623 else if (curproxy == NULL) {
624 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
625 return -1;
626 }
627
Willy Tarreau977b8e42006-12-29 14:19:17 +0100628
629 /* Now let's parse the proxy-specific keywords */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200630 if (!strcmp(args[0], "bind")) { /* new listen addresses */
631 if (curproxy == &defproxy) {
632 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
633 return -1;
634 }
Willy Tarreau977b8e42006-12-29 14:19:17 +0100635 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
636 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200637
638 if (strchr(args[1], ':') == NULL) {
639 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
640 file, linenum, args[0]);
641 return -1;
642 }
643 curproxy->listen = str2listener(args[1], curproxy->listen);
644 if (!curproxy->listen)
645 return -1;
646 global.maxsock++;
647 return 0;
648 }
649 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
650 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
651 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
652 file, linenum, args[0]);
653 return -1;
654 }
Willy Tarreau977b8e42006-12-29 14:19:17 +0100655 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
656 return 0;
657
Willy Tarreaubaaee002006-06-26 02:48:02 +0200658 /* flush useless bits */
659 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
660 return 0;
661 }
Willy Tarreau1c47f852006-07-09 08:22:27 +0200662 else if (!strcmp(args[0], "monitor-uri")) { /* set the URI to intercept */
Willy Tarreau977b8e42006-12-29 14:19:17 +0100663 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
664 return 0;
665
Willy Tarreau1c47f852006-07-09 08:22:27 +0200666 if (!*args[1]) {
667 Alert("parsing [%s:%d] : '%s' expects an URI.\n",
668 file, linenum, args[0]);
669 return -1;
670 }
671
672 if (curproxy->monitor_uri != NULL)
673 free(curproxy->monitor_uri);
674
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100675 curproxy->monitor_uri_len = strlen(args[1]);
Willy Tarreau1c47f852006-07-09 08:22:27 +0200676 curproxy->monitor_uri = (char *)calloc(1, curproxy->monitor_uri_len + 1);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100677 memcpy(curproxy->monitor_uri, args[1], curproxy->monitor_uri_len);
Willy Tarreau1c47f852006-07-09 08:22:27 +0200678 curproxy->monitor_uri[curproxy->monitor_uri_len] = '\0';
679
680 return 0;
681 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200682 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
683 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
684 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
685 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
686 else {
687 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
688 return -1;
689 }
690 }
691 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
692 curproxy->state = PR_STSTOPPED;
693 }
694 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
695 curproxy->state = PR_STNEW;
696 }
Willy Tarreaueb0c6142007-05-07 00:53:22 +0200697 else if (!strcmp(args[0], "acl")) { /* add an ACL */
698 if (parse_acl((const char **)args + 1, &curproxy->acl) == NULL) {
699 Alert("parsing [%s:%d] : error detected while parsing ACL '%s'.\n",
700 file, linenum, args[1]);
701 return -1;
702 }
703 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200704 else if (!strcmp(args[0], "cookie")) { /* cookie name */
705 int cur_arg;
706 // if (curproxy == &defproxy) {
707 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
708 // return -1;
709 // }
710
Willy Tarreau977b8e42006-12-29 14:19:17 +0100711 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
712 return 0;
713
Willy Tarreaubaaee002006-06-26 02:48:02 +0200714 if (curproxy->cookie_name != NULL) {
715 // Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
716 // file, linenum);
717 // return 0;
718 free(curproxy->cookie_name);
719 }
720
721 if (*(args[1]) == 0) {
722 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
723 file, linenum, args[0]);
724 return -1;
725 }
726 curproxy->cookie_name = strdup(args[1]);
727 curproxy->cookie_len = strlen(curproxy->cookie_name);
728
729 cur_arg = 2;
730 while (*(args[cur_arg])) {
731 if (!strcmp(args[cur_arg], "rewrite")) {
732 curproxy->options |= PR_O_COOK_RW;
733 }
734 else if (!strcmp(args[cur_arg], "indirect")) {
735 curproxy->options |= PR_O_COOK_IND;
736 }
737 else if (!strcmp(args[cur_arg], "insert")) {
738 curproxy->options |= PR_O_COOK_INS;
739 }
740 else if (!strcmp(args[cur_arg], "nocache")) {
741 curproxy->options |= PR_O_COOK_NOC;
742 }
743 else if (!strcmp(args[cur_arg], "postonly")) {
744 curproxy->options |= PR_O_COOK_POST;
745 }
746 else if (!strcmp(args[cur_arg], "prefix")) {
747 curproxy->options |= PR_O_COOK_PFX;
748 }
749 else {
750 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
751 file, linenum, args[0]);
752 return -1;
753 }
754 cur_arg++;
755 }
756 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
757 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
758 file, linenum);
759 return -1;
760 }
761
762 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
763 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
764 file, linenum);
765 return -1;
766 }
767 }/* end else if (!strcmp(args[0], "cookie")) */
768 else if (!strcmp(args[0], "appsession")) { /* cookie name */
769 // if (curproxy == &defproxy) {
770 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
771 // return -1;
772 // }
773
Willy Tarreau977b8e42006-12-29 14:19:17 +0100774 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
775 return 0;
776
Willy Tarreaubaaee002006-06-26 02:48:02 +0200777 if (curproxy->appsession_name != NULL) {
778 // Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
779 // file, linenum);
780 // return 0;
781 free(curproxy->appsession_name);
782 }
783
784 if (*(args[5]) == 0) {
785 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
786 file, linenum, args[0]);
787 return -1;
788 }
789 have_appsession = 1;
790 curproxy->appsession_name = strdup(args[1]);
791 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
792 curproxy->appsession_len = atoi(args[3]);
Willy Tarreauee991362007-05-14 14:37:50 +0200793 val = atoi(args[5]);
794 if (val > 0)
795 __tv_from_ms(&curproxy->appsession_timeout, val);
796 else
797 tv_eternity(&curproxy->appsession_timeout);
798
Willy Tarreau51041c72007-09-09 21:56:53 +0200799 if (appsession_hash_init(&(curproxy->htbl_proxy), destroy) == 0) {
800 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200801 return -1;
802 }
803 } /* Url App Session */
804 else if (!strcmp(args[0], "capture")) {
Willy Tarreau977b8e42006-12-29 14:19:17 +0100805 if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
806 return 0;
807
Willy Tarreaubaaee002006-06-26 02:48:02 +0200808 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
809 // if (curproxy == &defproxy) {
810 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
811 // return -1;
812 // }
813
814 if (curproxy->capture_name != NULL) {
815 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
816 // file, linenum, args[0]);
817 // return 0;
818 free(curproxy->capture_name);
819 }
820
821 if (*(args[4]) == 0) {
822 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
823 file, linenum, args[0]);
824 return -1;
825 }
826 curproxy->capture_name = strdup(args[2]);
827 curproxy->capture_namelen = strlen(curproxy->capture_name);
828 curproxy->capture_len = atol(args[4]);
829 if (curproxy->capture_len >= CAPTURE_LEN) {
830 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
831 file, linenum, CAPTURE_LEN - 1);
832 curproxy->capture_len = CAPTURE_LEN - 1;
833 }
834 curproxy->to_log |= LW_COOKIE;
835 }
836 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
837 struct cap_hdr *hdr;
838
839 if (curproxy == &defproxy) {
840 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
841 return -1;
842 }
843
844 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
845 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
846 file, linenum, args[0], args[1]);
847 return -1;
848 }
849
850 hdr = calloc(sizeof(struct cap_hdr), 1);
851 hdr->next = curproxy->req_cap;
852 hdr->name = strdup(args[3]);
853 hdr->namelen = strlen(args[3]);
854 hdr->len = atol(args[5]);
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200855 hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200856 hdr->index = curproxy->nb_req_cap++;
857 curproxy->req_cap = hdr;
858 curproxy->to_log |= LW_REQHDR;
859 }
860 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
861 struct cap_hdr *hdr;
862
863 if (curproxy == &defproxy) {
864 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
865 return -1;
866 }
867
868 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
869 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
870 file, linenum, args[0], args[1]);
871 return -1;
872 }
873 hdr = calloc(sizeof(struct cap_hdr), 1);
874 hdr->next = curproxy->rsp_cap;
875 hdr->name = strdup(args[3]);
876 hdr->namelen = strlen(args[3]);
877 hdr->len = atol(args[5]);
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200878 hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200879 hdr->index = curproxy->nb_rsp_cap++;
880 curproxy->rsp_cap = hdr;
881 curproxy->to_log |= LW_RSPHDR;
882 }
883 else {
884 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
885 file, linenum, args[0]);
886 return -1;
887 }
888 }
889 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200890 if (!__tv_iseq(&curproxy->contimeout, &defproxy.contimeout)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200891 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
892 return 0;
893 }
Willy Tarreau977b8e42006-12-29 14:19:17 +0100894 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
895 return 0;
896
Willy Tarreaubaaee002006-06-26 02:48:02 +0200897 if (*(args[1]) == 0) {
898 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
899 file, linenum, args[0]);
900 return -1;
901 }
Willy Tarreauee991362007-05-14 14:37:50 +0200902 val = atoi(args[1]);
903 if (val > 0)
904 __tv_from_ms(&curproxy->contimeout, val);
905 else
906 tv_eternity(&curproxy->contimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200907 }
908 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200909 if (!__tv_iseq(&curproxy->clitimeout, &defproxy.clitimeout)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200910 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
911 file, linenum, args[0]);
912 return 0;
913 }
Willy Tarreau977b8e42006-12-29 14:19:17 +0100914 else if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
915 return 0;
916
Willy Tarreaubaaee002006-06-26 02:48:02 +0200917 if (*(args[1]) == 0) {
918 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
919 file, linenum, args[0]);
920 return -1;
921 }
Willy Tarreauee991362007-05-14 14:37:50 +0200922 val = atoi(args[1]);
923 if (val > 0)
924 __tv_from_ms(&curproxy->clitimeout, val);
925 else
926 tv_eternity(&curproxy->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200927 }
928 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200929 if (!__tv_iseq(&curproxy->srvtimeout, &defproxy.srvtimeout)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200930 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
931 return 0;
932 }
Willy Tarreau977b8e42006-12-29 14:19:17 +0100933 else if (warnifnotcap(curproxy, PR_CAP_BE, 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->srvtimeout, val);
944 else
945 tv_eternity(&curproxy->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200946 }
947 else if (!strcmp(args[0], "retries")) { /* connection retries */
Willy Tarreau977b8e42006-12-29 14:19:17 +0100948 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
949 return 0;
950
Willy Tarreaubaaee002006-06-26 02:48:02 +0200951 if (*(args[1]) == 0) {
952 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
953 file, linenum, args[0]);
954 return -1;
955 }
956 curproxy->conn_retries = atol(args[1]);
957 }
Willy Tarreau5c8e3e02007-05-07 00:58:25 +0200958 else if (!strcmp(args[0], "block")) { /* early blocking based on ACLs */
959 int pol = ACL_COND_NONE;
960 struct acl_cond *cond;
961
962 if (!strcmp(args[1], "if"))
963 pol = ACL_COND_IF;
964 else if (!strcmp(args[1], "unless"))
965 pol = ACL_COND_UNLESS;
966
967 if (pol == ACL_COND_NONE) {
968 Alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
969 file, linenum, args[0]);
970 return -1;
971 }
972
973 if ((cond = parse_acl_cond((const char **)args + 2, &curproxy->acl, pol)) == NULL) {
974 Alert("parsing [%s:%d] : error detected while parsing blocking condition.\n",
975 file, linenum);
976 return -1;
977 }
978 LIST_ADDQ(&curproxy->block_cond, &cond->list);
979 }
Willy Tarreau55ea7572007-06-17 19:56:27 +0200980 else if (!strcmp(args[0], "use_backend")) { /* early blocking based on ACLs */
981 int pol = ACL_COND_NONE;
982 struct acl_cond *cond;
983 struct switching_rule *rule;
984
985 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
986 return 0;
987
988 if (*(args[1]) == 0) {
989 Alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
990 return -1;
991 }
992
993 if (!strcmp(args[2], "if"))
994 pol = ACL_COND_IF;
995 else if (!strcmp(args[2], "unless"))
996 pol = ACL_COND_UNLESS;
997
998 if (pol == ACL_COND_NONE) {
999 Alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1000 file, linenum, args[0]);
1001 return -1;
1002 }
1003
1004 if ((cond = parse_acl_cond((const char **)args + 3, &curproxy->acl, pol)) == NULL) {
1005 Alert("parsing [%s:%d] : error detected while parsing blocking condition.\n",
1006 file, linenum);
1007 return -1;
1008 }
1009
1010 rule = (struct switching_rule *)calloc(1, sizeof(*rule));
1011 rule->cond = cond;
1012 rule->be.name = strdup(args[1]);
1013 LIST_INIT(&rule->list);
1014 LIST_ADDQ(&curproxy->switching_rules, &rule->list);
1015 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001016 else if (!strcmp(args[0], "stats")) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01001017 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1018 return 0;
1019
Willy Tarreaubaaee002006-06-26 02:48:02 +02001020 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
1021 curproxy->uri_auth = NULL; /* we must detach from the default config */
1022
1023 if (*(args[1]) == 0) {
1024 Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable'.\n", file, linenum, args[0]);
1025 return -1;
1026 } else if (!strcmp(args[1], "uri")) {
1027 if (*(args[2]) == 0) {
1028 Alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
1029 return -1;
1030 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
1031 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1032 return -1;
1033 }
1034 } else if (!strcmp(args[1], "realm")) {
1035 if (*(args[2]) == 0) {
1036 Alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
1037 return -1;
1038 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
1039 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1040 return -1;
1041 }
Willy Tarreaubbd42122007-07-25 07:26:38 +02001042 } else if (!strcmp(args[1], "refresh")) {
1043 int interval = atoi(args[2]);
1044
1045 if (interval < 0) {
1046 Alert("parsing [%s:%d] : 'refresh' needs a positive interval in seconds.\n", file, linenum);
1047 return -1;
1048 } else if (!stats_set_refresh(&curproxy->uri_auth, interval)) {
1049 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1050 return -1;
1051 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001052 } else if (!strcmp(args[1], "auth")) {
1053 if (*(args[2]) == 0) {
1054 Alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
1055 return -1;
1056 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
1057 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1058 return -1;
1059 }
1060 } else if (!strcmp(args[1], "scope")) {
1061 if (*(args[2]) == 0) {
1062 Alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
1063 return -1;
1064 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
1065 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1066 return -1;
1067 }
1068 } else if (!strcmp(args[1], "enable")) {
1069 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1070 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1071 return -1;
1072 }
1073 } else {
1074 Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'uri', 'realm', 'auth' or 'enable').\n",
1075 file, linenum, args[0]);
1076 return -1;
1077 }
1078 }
1079 else if (!strcmp(args[0], "option")) {
Willy Tarreau13943ab2006-12-31 00:24:10 +01001080 int optnum;
1081
Willy Tarreaubaaee002006-06-26 02:48:02 +02001082 if (*(args[1]) == 0) {
1083 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
1084 return -1;
1085 }
Willy Tarreau13943ab2006-12-31 00:24:10 +01001086
1087 for (optnum = 0; cfg_opts[optnum].name; optnum++) {
1088 if (!strcmp(args[1], cfg_opts[optnum].name)) {
1089 if (warnifnotcap(curproxy, cfg_opts[optnum].cap, file, linenum, args[1], NULL))
1090 return 0;
1091 curproxy->options |= cfg_opts[optnum].val;
Willy Tarreau4fee4e92007-01-06 21:09:17 +01001092 global.last_checks |= cfg_opts[optnum].checks;
Willy Tarreau13943ab2006-12-31 00:24:10 +01001093 return 0;
1094 }
1095 }
1096
1097 if (!strcmp(args[1], "httplog"))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001098 /* generate a complete HTTP log */
1099 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
1100 else if (!strcmp(args[1], "tcplog"))
1101 /* generate a detailed TCP log */
1102 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001103 else if (!strcmp(args[1], "tcpka")) {
1104 /* enable TCP keep-alives on client and server sessions */
Willy Tarreau13943ab2006-12-31 00:24:10 +01001105 if (warnifnotcap(curproxy, PR_CAP_BE | PR_CAP_FE, file, linenum, args[1], NULL))
1106 return 0;
1107
1108 if (curproxy->cap & PR_CAP_FE)
1109 curproxy->options |= PR_O_TCP_CLI_KA;
1110 if (curproxy->cap & PR_CAP_BE)
1111 curproxy->options |= PR_O_TCP_SRV_KA;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001112 }
1113 else if (!strcmp(args[1], "httpchk")) {
Willy Tarreau13943ab2006-12-31 00:24:10 +01001114 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
1115 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001116 /* use HTTP request to check servers' health */
1117 if (curproxy->check_req != NULL) {
1118 free(curproxy->check_req);
1119 }
Willy Tarreauf3c69202006-07-09 16:42:34 +02001120 curproxy->options &= ~PR_O_SSL3_CHK;
Willy Tarreau23677902007-05-08 23:50:35 +02001121 curproxy->options &= ~PR_O_SMTP_CHK;
1122 curproxy->options |= PR_O_HTTP_CHK;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001123 if (!*args[2]) { /* no argument */
1124 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
1125 curproxy->check_len = strlen(DEF_CHECK_REQ);
1126 } else if (!*args[3]) { /* one argument : URI */
Willy Tarreau23677902007-05-08 23:50:35 +02001127 int reqlen = strlen(args[2]) + strlen("OPTIONS HTTP/1.0\r\n\r\n") + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001128 curproxy->check_req = (char *)malloc(reqlen);
1129 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
1130 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
1131 } else { /* more arguments : METHOD URI [HTTP_VER] */
1132 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
1133 if (*args[4])
1134 reqlen += strlen(args[4]);
1135 else
1136 reqlen += strlen("HTTP/1.0");
1137
1138 curproxy->check_req = (char *)malloc(reqlen);
1139 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
1140 "%s %s %s\r\n\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
1141 }
Willy Tarreauf3c69202006-07-09 16:42:34 +02001142 }
1143 else if (!strcmp(args[1], "ssl-hello-chk")) {
1144 /* use SSLv3 CLIENT HELLO to check servers' health */
Willy Tarreau13943ab2006-12-31 00:24:10 +01001145 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
1146 return 0;
1147
Willy Tarreauf3c69202006-07-09 16:42:34 +02001148 if (curproxy->check_req != NULL) {
1149 free(curproxy->check_req);
1150 }
1151 curproxy->options &= ~PR_O_HTTP_CHK;
Willy Tarreau23677902007-05-08 23:50:35 +02001152 curproxy->options &= ~PR_O_SMTP_CHK;
Willy Tarreauf3c69202006-07-09 16:42:34 +02001153 curproxy->options |= PR_O_SSL3_CHK;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001154 }
Willy Tarreau23677902007-05-08 23:50:35 +02001155 else if (!strcmp(args[1], "smtpchk")) {
1156 /* use SMTP request to check servers' health */
1157 if (curproxy->check_req != NULL) {
1158 free(curproxy->check_req);
1159 }
1160 curproxy->options &= ~PR_O_HTTP_CHK;
1161 curproxy->options &= ~PR_O_SSL3_CHK;
1162 curproxy->options |= PR_O_SMTP_CHK;
1163
1164 if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */
1165 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
1166 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
1167 } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */
1168 if (!strcmp(args[2], "EHLO") || !strcmp(args[2], "HELO")) {
1169 int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" \r\n") + 1;
1170 curproxy->check_req = (char *)malloc(reqlen);
1171 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
1172 "%s %s\r\n", args[2], args[3]); /* HELO hostname */
1173 } else {
1174 /* this just hits the default for now, but you could potentially expand it to allow for other stuff
1175 though, it's unlikely you'd want to send anything other than an EHLO or HELO */
1176 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
1177 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
1178 }
1179 }
1180 }
Willy Tarreau7ac51f62007-03-25 16:00:04 +02001181 else if (!strcmp(args[1], "forwardfor")) {
1182 /* insert x-forwarded-for field, but not for the
1183 * IP address listed as an except.
1184 */
1185 if (*(args[2])) {
1186 if (!strcmp(args[2], "except")) {
1187 if (!*args[3] || !str2net(args[3], &curproxy->except_net, &curproxy->except_mask)) {
1188 Alert("parsing [%s:%d] : '%s' only supports optional 'except' address[/mask].\n",
1189 file, linenum, args[0]);
1190 return -1;
1191 }
1192 /* flush useless bits */
1193 curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
1194 } else {
1195 Alert("parsing [%s:%d] : '%s' only supports optional 'except' address[/mask].\n",
1196 file, linenum, args[0]);
1197 return -1;
1198 }
1199 }
1200 curproxy->options |= PR_O_FWDFOR;
1201 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001202 else {
1203 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
1204 return -1;
1205 }
1206 return 0;
1207 }
Willy Tarreau5fdfb912007-01-01 23:11:07 +01001208 else if (!strcmp(args[0], "default_backend")) {
1209 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1210 return 0;
1211
1212 if (*(args[1]) == 0) {
1213 Alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
1214 return -1;
1215 }
1216 if (curproxy->defbe.name)
1217 free(curproxy->defbe.name);
1218 curproxy->defbe.name = strdup(args[1]);
1219 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001220 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01001221 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1222 return 0;
1223
Willy Tarreaubaaee002006-06-26 02:48:02 +02001224 /* enable reconnections to dispatch */
1225 curproxy->options |= PR_O_REDISP;
1226 }
1227#ifdef TPROXY
1228 else if (!strcmp(args[0], "transparent")) {
1229 /* enable transparent proxy connections */
1230 curproxy->options |= PR_O_TRANSP;
1231 }
1232#endif
1233 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
Willy Tarreau977b8e42006-12-29 14:19:17 +01001234 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
1235 return 0;
1236
Willy Tarreaubaaee002006-06-26 02:48:02 +02001237 if (*(args[1]) == 0) {
1238 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
1239 return -1;
1240 }
1241 curproxy->maxconn = atol(args[1]);
1242 }
Willy Tarreau86034312006-12-29 00:10:33 +01001243 else if (!strcmp(args[0], "fullconn")) { /* fullconn */
Willy Tarreau977b8e42006-12-29 14:19:17 +01001244 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
1245 return 0;
1246
Willy Tarreau86034312006-12-29 00:10:33 +01001247 if (*(args[1]) == 0) {
1248 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
1249 return -1;
1250 }
1251 curproxy->fullconn = atol(args[1]);
1252 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001253 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
1254 if (*(args[1]) == 0) {
1255 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
1256 return -1;
1257 }
1258 curproxy->grace = atol(args[1]);
1259 }
1260 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
1261 if (curproxy == &defproxy) {
1262 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1263 return -1;
1264 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001265 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1266 return 0;
1267
Willy Tarreaubaaee002006-06-26 02:48:02 +02001268 if (strchr(args[1], ':') == NULL) {
1269 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
1270 return -1;
1271 }
1272 curproxy->dispatch_addr = *str2sa(args[1]);
1273 }
1274 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
Willy Tarreau977b8e42006-12-29 14:19:17 +01001275 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1276 return 0;
1277
Willy Tarreaubaaee002006-06-26 02:48:02 +02001278 if (*(args[1])) {
1279 if (!strcmp(args[1], "roundrobin")) {
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001280 curproxy->options &= ~PR_O_BALANCE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001281 curproxy->options |= PR_O_BALANCE_RR;
1282 }
1283 else if (!strcmp(args[1], "source")) {
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001284 curproxy->options &= ~PR_O_BALANCE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001285 curproxy->options |= PR_O_BALANCE_SH;
1286 }
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001287 else if (!strcmp(args[1], "uri")) {
1288 curproxy->options &= ~PR_O_BALANCE;
1289 curproxy->options |= PR_O_BALANCE_UH;
1290 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001291 else {
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001292 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin', 'source' and 'uri' options.\n", file, linenum, args[0]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001293 return -1;
1294 }
1295 }
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001296 else {/* if no option is set, use round-robin by default */
1297 curproxy->options &= ~PR_O_BALANCE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001298 curproxy->options |= PR_O_BALANCE_RR;
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001299 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001300 }
1301 else if (!strcmp(args[0], "server")) { /* server address */
1302 int cur_arg;
1303 char *rport;
1304 char *raddr;
1305 short realport;
1306 int do_check;
1307
1308 if (curproxy == &defproxy) {
1309 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1310 return -1;
1311 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001312 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1313 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001314
1315 if (!*args[2]) {
1316 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
1317 file, linenum, args[0]);
1318 return -1;
1319 }
1320 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
1321 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1322 return -1;
1323 }
1324
1325 /* the servers are linked backwards first */
1326 newsrv->next = curproxy->srv;
1327 curproxy->srv = newsrv;
1328 newsrv->proxy = curproxy;
1329
1330 LIST_INIT(&newsrv->pendconns);
1331 do_check = 0;
1332 newsrv->state = SRV_RUNNING; /* early server setup */
1333 newsrv->id = strdup(args[1]);
1334
1335 /* several ways to check the port component :
1336 * - IP => port=+0, relative
1337 * - IP: => port=+0, relative
1338 * - IP:N => port=N, absolute
1339 * - IP:+N => port=+N, relative
1340 * - IP:-N => port=-N, relative
1341 */
1342 raddr = strdup(args[2]);
1343 rport = strchr(raddr, ':');
1344 if (rport) {
1345 *rport++ = 0;
1346 realport = atol(rport);
Willy Tarreau8f8e6452007-06-17 21:51:38 +02001347 if (!isdigit((unsigned char)*rport))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001348 newsrv->state |= SRV_MAPPORTS;
1349 } else {
1350 realport = 0;
1351 newsrv->state |= SRV_MAPPORTS;
1352 }
1353
1354 newsrv->addr = *str2sa(raddr);
1355 newsrv->addr.sin_port = htons(realport);
1356 free(raddr);
1357
1358 newsrv->curfd = -1; /* no health-check in progress */
1359 newsrv->inter = DEF_CHKINTR;
1360 newsrv->rise = DEF_RISETIME;
1361 newsrv->fall = DEF_FALLTIME;
1362 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
Willy Tarreau417fae02007-03-25 21:16:40 +02001363 newsrv->uweight = 1;
Willy Tarreau0f03c6f2007-03-25 20:46:19 +02001364
Willy Tarreaubaaee002006-06-26 02:48:02 +02001365 cur_arg = 3;
1366 while (*args[cur_arg]) {
1367 if (!strcmp(args[cur_arg], "cookie")) {
1368 newsrv->cookie = strdup(args[cur_arg + 1]);
1369 newsrv->cklen = strlen(args[cur_arg + 1]);
1370 cur_arg += 2;
1371 }
1372 else if (!strcmp(args[cur_arg], "rise")) {
1373 newsrv->rise = atol(args[cur_arg + 1]);
1374 newsrv->health = newsrv->rise;
1375 cur_arg += 2;
1376 }
1377 else if (!strcmp(args[cur_arg], "fall")) {
1378 newsrv->fall = atol(args[cur_arg + 1]);
1379 cur_arg += 2;
1380 }
1381 else if (!strcmp(args[cur_arg], "inter")) {
1382 newsrv->inter = atol(args[cur_arg + 1]);
1383 cur_arg += 2;
1384 }
Willy Tarreau2ea3abb2007-03-25 16:45:16 +02001385 else if (!strcmp(args[cur_arg], "addr")) {
1386 newsrv->check_addr = *str2sa(args[cur_arg + 1]);
Willy Tarreau2ea3abb2007-03-25 16:45:16 +02001387 cur_arg += 2;
1388 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001389 else if (!strcmp(args[cur_arg], "port")) {
1390 newsrv->check_port = atol(args[cur_arg + 1]);
1391 cur_arg += 2;
1392 }
1393 else if (!strcmp(args[cur_arg], "backup")) {
1394 newsrv->state |= SRV_BACKUP;
1395 cur_arg ++;
1396 }
1397 else if (!strcmp(args[cur_arg], "weight")) {
1398 int w;
1399 w = atol(args[cur_arg + 1]);
1400 if (w < 1 || w > 256) {
1401 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
1402 file, linenum, newsrv->id, w);
1403 return -1;
1404 }
Willy Tarreau417fae02007-03-25 21:16:40 +02001405 newsrv->uweight = w;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001406 cur_arg += 2;
1407 }
1408 else if (!strcmp(args[cur_arg], "minconn")) {
1409 newsrv->minconn = atol(args[cur_arg + 1]);
1410 cur_arg += 2;
1411 }
1412 else if (!strcmp(args[cur_arg], "maxconn")) {
1413 newsrv->maxconn = atol(args[cur_arg + 1]);
1414 cur_arg += 2;
1415 }
1416 else if (!strcmp(args[cur_arg], "check")) {
1417 global.maxsock++;
1418 do_check = 1;
1419 cur_arg += 1;
1420 }
1421 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
1422 if (!*args[cur_arg + 1]) {
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001423#ifdef CONFIG_HAP_CTTPROXY
1424 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optional '%s' <addr> as argument.\n",
1425 file, linenum, "source", "usesrc");
1426#else
Willy Tarreaubaaee002006-06-26 02:48:02 +02001427 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
1428 file, linenum, "source");
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001429#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001430 return -1;
1431 }
1432 newsrv->state |= SRV_BIND_SRC;
1433 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
1434 cur_arg += 2;
Willy Tarreau77074d52006-11-12 23:57:19 +01001435 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001436#ifdef CONFIG_HAP_CTTPROXY
Willy Tarreau77074d52006-11-12 23:57:19 +01001437 if (newsrv->source_addr.sin_addr.s_addr == INADDR_ANY) {
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001438 Alert("parsing [%s:%d] : '%s' requires an explicit '%s' address.\n",
1439 file, linenum, "usesrc", "source");
Willy Tarreau77074d52006-11-12 23:57:19 +01001440 return -1;
1441 }
1442 if (!*args[cur_arg + 1]) {
1443 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
1444 file, linenum, "usesrc");
1445 return -1;
1446 }
1447 if (!strcmp(args[cur_arg + 1], "client")) {
1448 newsrv->state |= SRV_TPROXY_CLI;
1449 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
1450 newsrv->state |= SRV_TPROXY_CIP;
1451 } else {
1452 newsrv->state |= SRV_TPROXY_ADDR;
1453 newsrv->tproxy_addr = *str2sa(args[cur_arg + 1]);
1454 }
1455 global.last_checks |= LSTCHK_CTTPROXY | LSTCHK_NETADM;
1456 cur_arg += 2;
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001457#else /* no CTTPROXY support */
1458 Alert("parsing [%s:%d] : '%s' not allowed here because support for cttproxy was not compiled in.\n",
1459 file, linenum, "usesrc");
1460 return -1;
Willy Tarreau77074d52006-11-12 23:57:19 +01001461#endif
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001462 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001463 }
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001464#ifdef CONFIG_HAP_CTTPROXY
1465 else if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside: needs "source" first */
1466 Alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
1467 file, linenum, "usesrc", "source");
1468 return -1;
1469 }
1470#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001471 else {
Willy Tarreau0f03c6f2007-03-25 20:46:19 +02001472 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 +02001473 file, linenum, newsrv->id);
1474 return -1;
1475 }
1476 }
1477
1478 if (do_check) {
Willy Tarreau0f03c6f2007-03-25 20:46:19 +02001479 if (!newsrv->check_port && newsrv->check_addr.sin_port)
1480 newsrv->check_port = newsrv->check_addr.sin_port;
1481
Willy Tarreaubaaee002006-06-26 02:48:02 +02001482 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
1483 newsrv->check_port = realport; /* by default */
1484 if (!newsrv->check_port) {
Willy Tarreauef00b502007-01-07 02:40:09 +01001485 /* not yet valid, because no port was set on
1486 * the server either. We'll check if we have
1487 * a known port on the first listener.
1488 */
1489 struct listener *l;
1490 l = curproxy->listen;
1491 if (l) {
1492 int port;
1493 port = (l->addr.ss_family == AF_INET6)
1494 ? ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port)
1495 : ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
1496 newsrv->check_port = port;
1497 }
1498 }
1499 if (!newsrv->check_port) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001500 Alert("parsing [%s:%d] : server %s has neither service port nor check port. Check has been disabled.\n",
1501 file, linenum, newsrv->id);
1502 return -1;
1503 }
1504 newsrv->state |= SRV_CHECKED;
1505 }
1506
1507 if (newsrv->state & SRV_BACKUP)
1508 curproxy->srv_bck++;
1509 else
1510 curproxy->srv_act++;
1511 }
1512 else if (!strcmp(args[0], "log")) { /* syslog server address */
1513 struct sockaddr_in *sa;
1514 int facility;
1515
1516 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
1517 curproxy->logfac1 = global.logfac1;
1518 curproxy->logsrv1 = global.logsrv1;
1519 curproxy->loglev1 = global.loglev1;
1520 curproxy->logfac2 = global.logfac2;
1521 curproxy->logsrv2 = global.logsrv2;
1522 curproxy->loglev2 = global.loglev2;
1523 }
1524 else if (*(args[1]) && *(args[2])) {
1525 int level;
1526
1527 facility = get_log_facility(args[2]);
1528 if (facility < 0) {
1529 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
1530 exit(1);
1531 }
1532
1533 level = 7; /* max syslog level = debug */
1534 if (*(args[3])) {
1535 level = get_log_level(args[3]);
1536 if (level < 0) {
1537 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
1538 exit(1);
1539 }
1540 }
1541
1542 sa = str2sa(args[1]);
1543 if (!sa->sin_port)
1544 sa->sin_port = htons(SYSLOG_PORT);
1545
1546 if (curproxy->logfac1 == -1) {
1547 curproxy->logsrv1 = *sa;
1548 curproxy->logfac1 = facility;
1549 curproxy->loglev1 = level;
1550 }
1551 else if (curproxy->logfac2 == -1) {
1552 curproxy->logsrv2 = *sa;
1553 curproxy->logfac2 = facility;
1554 curproxy->loglev2 = level;
1555 }
1556 else {
1557 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
1558 return -1;
1559 }
1560 }
1561 else {
1562 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
1563 file, linenum);
1564 return -1;
1565 }
1566 }
1567 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
Willy Tarreau977b8e42006-12-29 14:19:17 +01001568 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1569 return 0;
1570
Willy Tarreaubaaee002006-06-26 02:48:02 +02001571 if (!*args[1]) {
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001572#ifdef CONFIG_HAP_CTTPROXY
1573 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optional '%s' <addr> as argument.\n",
1574 file, linenum, "source", "usesrc");
1575#else
Willy Tarreaubaaee002006-06-26 02:48:02 +02001576 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
1577 file, linenum, "source");
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001578#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001579 return -1;
1580 }
1581
1582 curproxy->source_addr = *str2sa(args[1]);
1583 curproxy->options |= PR_O_BIND_SRC;
Willy Tarreau77074d52006-11-12 23:57:19 +01001584 if (!strcmp(args[2], "usesrc")) { /* address to use outside */
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001585#ifdef CONFIG_HAP_CTTPROXY
Willy Tarreau77074d52006-11-12 23:57:19 +01001586 if (curproxy->source_addr.sin_addr.s_addr == INADDR_ANY) {
1587 Alert("parsing [%s:%d] : '%s' requires an explicit 'source' address.\n",
1588 file, linenum, "usesrc");
1589 return -1;
1590 }
1591 if (!*args[3]) {
1592 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
1593 file, linenum, "usesrc");
1594 return -1;
1595 }
1596
1597 if (!strcmp(args[3], "client")) {
1598 curproxy->options |= PR_O_TPXY_CLI;
1599 } else if (!strcmp(args[3], "clientip")) {
1600 curproxy->options |= PR_O_TPXY_CIP;
1601 } else {
1602 curproxy->options |= PR_O_TPXY_ADDR;
1603 curproxy->tproxy_addr = *str2sa(args[3]);
1604 }
1605 global.last_checks |= LSTCHK_CTTPROXY | LSTCHK_NETADM;
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001606#else /* no CTTPROXY support */
1607 Alert("parsing [%s:%d] : '%s' not allowed here because support for cttproxy was not compiled in.\n",
1608 file, linenum, "usesrc");
1609 return -1;
Willy Tarreau77074d52006-11-12 23:57:19 +01001610#endif
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001611 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001612 }
Willy Tarreau8d9246d2007-03-24 12:47:24 +01001613#ifdef CONFIG_HAP_CTTPROXY
1614 else if (!strcmp(args[0], "usesrc")) { /* address to use outside: needs "source" first */
1615 Alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
1616 file, linenum, "usesrc", "source");
1617 return -1;
1618 }
1619#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001620 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
1621 regex_t *preg;
1622 if (curproxy == &defproxy) {
1623 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1624 return -1;
1625 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001626 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1627 return 0;
1628
Willy Tarreaubaaee002006-06-26 02:48:02 +02001629 if (*(args[1]) == 0 || *(args[2]) == 0) {
1630 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
1631 file, linenum, args[0]);
1632 return -1;
1633 }
1634
1635 preg = calloc(1, sizeof(regex_t));
1636 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1637 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1638 return -1;
1639 }
1640
1641 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
1642 if (err) {
1643 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1644 file, linenum, *err);
1645 return -1;
1646 }
1647 }
1648 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
1649 regex_t *preg;
1650 if (curproxy == &defproxy) {
1651 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1652 return -1;
1653 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001654 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1655 return 0;
1656
Willy Tarreaubaaee002006-06-26 02:48:02 +02001657 if (*(args[1]) == 0) {
1658 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1659 return -1;
1660 }
1661
1662 preg = calloc(1, sizeof(regex_t));
1663 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1664 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1665 return -1;
1666 }
1667
1668 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
1669 }
1670 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
1671 regex_t *preg;
1672 if (curproxy == &defproxy) {
1673 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1674 return -1;
1675 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001676 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1677 return 0;
1678
Willy Tarreaubaaee002006-06-26 02:48:02 +02001679 if (*(args[1]) == 0) {
1680 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1681 return -1;
1682 }
1683
1684 preg = calloc(1, sizeof(regex_t));
1685 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1686 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1687 return -1;
1688 }
1689
1690 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
1691 }
1692 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
1693 regex_t *preg;
1694 if (curproxy == &defproxy) {
1695 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1696 return -1;
1697 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001698 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1699 return 0;
1700
Willy Tarreaubaaee002006-06-26 02:48:02 +02001701 if (*(args[1]) == 0) {
1702 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1703 return -1;
1704 }
1705
1706 preg = calloc(1, sizeof(regex_t));
1707 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1708 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1709 return -1;
1710 }
1711
1712 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
1713 }
1714 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
1715 regex_t *preg;
1716 if (curproxy == &defproxy) {
1717 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1718 return -1;
1719 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001720 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1721 return 0;
1722
Willy Tarreaubaaee002006-06-26 02:48:02 +02001723 if (*(args[1]) == 0) {
1724 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1725 return -1;
1726 }
1727
1728 preg = calloc(1, sizeof(regex_t));
1729 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1730 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1731 return -1;
1732 }
1733
1734 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
1735 }
Willy Tarreaub8750a82006-09-03 09:56:00 +02001736 else if (!strcmp(args[0], "reqtarpit")) { /* tarpit a request if a header matches this regex */
1737 regex_t *preg;
1738 if (curproxy == &defproxy) {
1739 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1740 return -1;
1741 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001742 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1743 return 0;
1744
Willy Tarreaub8750a82006-09-03 09:56:00 +02001745 if (*(args[1]) == 0) {
1746 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1747 return -1;
1748 }
1749
1750 preg = calloc(1, sizeof(regex_t));
1751 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1752 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1753 return -1;
1754 }
1755
1756 chain_regex(&curproxy->req_exp, preg, ACT_TARPIT, NULL);
1757 }
Willy Tarreaua496b602006-12-17 23:15:24 +01001758 else if (!strcmp(args[0], "reqsetbe")) { /* switch the backend from a regex, respecting case */
1759 regex_t *preg;
Willy Tarreau977b8e42006-12-29 14:19:17 +01001760 if (curproxy == &defproxy) {
Willy Tarreaua496b602006-12-17 23:15:24 +01001761 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1762 return -1;
1763 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001764 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1765 return 0;
Willy Tarreaua496b602006-12-17 23:15:24 +01001766
Willy Tarreau977b8e42006-12-29 14:19:17 +01001767 if (*(args[1]) == 0 || *(args[2]) == 0) {
Willy Tarreaua496b602006-12-17 23:15:24 +01001768 Alert("parsing [%s:%d] : '%s' expects <search> and <target> as arguments.\n",
1769 file, linenum, args[0]);
1770 return -1;
1771 }
1772
1773 preg = calloc(1, sizeof(regex_t));
Willy Tarreau977b8e42006-12-29 14:19:17 +01001774 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
Willy Tarreaua496b602006-12-17 23:15:24 +01001775 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1776 }
1777
1778 chain_regex(&curproxy->req_exp, preg, ACT_SETBE, strdup(args[2]));
1779 }
1780 else if (!strcmp(args[0], "reqisetbe")) { /* switch the backend from a regex, ignoring case */
1781 regex_t *preg;
Willy Tarreau977b8e42006-12-29 14:19:17 +01001782 if (curproxy == &defproxy) {
Willy Tarreaua496b602006-12-17 23:15:24 +01001783 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1784 return -1;
1785 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001786 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1787 return 0;
Willy Tarreaua496b602006-12-17 23:15:24 +01001788
Willy Tarreau977b8e42006-12-29 14:19:17 +01001789 if (*(args[1]) == 0 || *(args[2]) == 0) {
Willy Tarreaua496b602006-12-17 23:15:24 +01001790 Alert("parsing [%s:%d] : '%s' expects <search> and <target> as arguments.\n",
1791 file, linenum, args[0]);
1792 return -1;
1793 }
1794
1795 preg = calloc(1, sizeof(regex_t));
Willy Tarreau977b8e42006-12-29 14:19:17 +01001796 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
Willy Tarreaua496b602006-12-17 23:15:24 +01001797 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1798 }
1799
1800 chain_regex(&curproxy->req_exp, preg, ACT_SETBE, strdup(args[2]));
1801 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001802 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
1803 regex_t *preg;
1804 if (curproxy == &defproxy) {
1805 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1806 return -1;
1807 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001808 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1809 return 0;
1810
Willy Tarreaubaaee002006-06-26 02:48:02 +02001811 if (*(args[1]) == 0 || *(args[2]) == 0) {
1812 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
1813 file, linenum, args[0]);
1814 return -1;
1815 }
1816
1817 preg = calloc(1, sizeof(regex_t));
1818 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1819 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1820 return -1;
1821 }
1822
1823 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
1824 if (err) {
1825 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1826 file, linenum, *err);
1827 return -1;
1828 }
1829 }
1830 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
1831 regex_t *preg;
1832 if (curproxy == &defproxy) {
1833 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1834 return -1;
1835 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001836 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1837 return 0;
1838
Willy Tarreaubaaee002006-06-26 02:48:02 +02001839 if (*(args[1]) == 0) {
1840 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1841 return -1;
1842 }
1843
1844 preg = calloc(1, sizeof(regex_t));
1845 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1846 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1847 return -1;
1848 }
1849
1850 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
1851 }
1852 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
1853 regex_t *preg;
1854 if (curproxy == &defproxy) {
1855 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1856 return -1;
1857 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001858 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1859 return 0;
1860
Willy Tarreaubaaee002006-06-26 02:48:02 +02001861 if (*(args[1]) == 0) {
1862 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1863 return -1;
1864 }
1865
1866 preg = calloc(1, sizeof(regex_t));
1867 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1868 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1869 return -1;
1870 }
1871
1872 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
1873 }
1874 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
1875 regex_t *preg;
1876 if (curproxy == &defproxy) {
1877 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1878 return -1;
1879 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001880 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1881 return 0;
1882
Willy Tarreaubaaee002006-06-26 02:48:02 +02001883 if (*(args[1]) == 0) {
1884 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1885 return -1;
1886 }
1887
1888 preg = calloc(1, sizeof(regex_t));
1889 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1890 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1891 return -1;
1892 }
1893
1894 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
1895 }
1896 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
1897 regex_t *preg;
1898 if (curproxy == &defproxy) {
1899 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1900 return -1;
1901 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001902 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1903 return 0;
1904
Willy Tarreaubaaee002006-06-26 02:48:02 +02001905 if (*(args[1]) == 0) {
1906 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1907 return -1;
1908 }
1909
1910 preg = calloc(1, sizeof(regex_t));
1911 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1912 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1913 return -1;
1914 }
1915
1916 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
1917 }
Willy Tarreaub8750a82006-09-03 09:56:00 +02001918 else if (!strcmp(args[0], "reqitarpit")) { /* tarpit a request if a header matches this regex ignoring case */
1919 regex_t *preg;
1920 if (curproxy == &defproxy) {
1921 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1922 return -1;
1923 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001924 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1925 return 0;
1926
Willy Tarreaub8750a82006-09-03 09:56:00 +02001927 if (*(args[1]) == 0) {
1928 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1929 return -1;
1930 }
1931
1932 preg = calloc(1, sizeof(regex_t));
1933 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1934 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1935 return -1;
1936 }
1937
1938 chain_regex(&curproxy->req_exp, preg, ACT_TARPIT, NULL);
1939 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001940 else if (!strcmp(args[0], "reqadd")) { /* add request header */
1941 if (curproxy == &defproxy) {
1942 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1943 return -1;
1944 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001945 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1946 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001947
1948 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
1949 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
1950 return 0;
1951 }
1952
1953 if (*(args[1]) == 0) {
1954 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
1955 return -1;
1956 }
1957
1958 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
1959 }
1960 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
1961 regex_t *preg;
1962
1963 if (*(args[1]) == 0 || *(args[2]) == 0) {
1964 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
1965 file, linenum, args[0]);
1966 return -1;
1967 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001968 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1969 return 0;
1970
Willy Tarreaubaaee002006-06-26 02:48:02 +02001971 preg = calloc(1, sizeof(regex_t));
1972 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1973 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1974 return -1;
1975 }
1976
1977 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
1978 if (err) {
1979 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1980 file, linenum, *err);
1981 return -1;
1982 }
1983 }
1984 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
1985 regex_t *preg;
1986 if (curproxy == &defproxy) {
1987 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1988 return -1;
1989 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01001990 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
1991 return 0;
1992
Willy Tarreaubaaee002006-06-26 02:48:02 +02001993 if (*(args[1]) == 0) {
1994 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
1995 return -1;
1996 }
1997
1998 preg = calloc(1, sizeof(regex_t));
1999 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
2000 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2001 return -1;
2002 }
2003
2004 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
2005 if (err) {
2006 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
2007 file, linenum, *err);
2008 return -1;
2009 }
2010 }
2011 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
2012 regex_t *preg;
2013 if (curproxy == &defproxy) {
2014 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2015 return -1;
2016 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002017 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2018 return 0;
2019
Willy Tarreaubaaee002006-06-26 02:48:02 +02002020 if (*(args[1]) == 0) {
2021 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
2022 return -1;
2023 }
2024
2025 preg = calloc(1, sizeof(regex_t));
2026 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
2027 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2028 return -1;
2029 }
2030
2031 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
2032 if (err) {
2033 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
2034 file, linenum, *err);
2035 return -1;
2036 }
2037 }
2038 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
2039 regex_t *preg;
2040 if (curproxy == &defproxy) {
2041 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2042 return -1;
2043 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002044 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2045 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002046
2047 if (*(args[1]) == 0 || *(args[2]) == 0) {
2048 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
2049 file, linenum, args[0]);
2050 return -1;
2051 }
2052
2053 preg = calloc(1, sizeof(regex_t));
2054 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
2055 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2056 return -1;
2057 }
2058
2059 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
2060 if (err) {
2061 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
2062 file, linenum, *err);
2063 return -1;
2064 }
2065 }
2066 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
2067 regex_t *preg;
2068 if (curproxy == &defproxy) {
2069 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2070 return -1;
2071 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002072 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2073 return 0;
2074
Willy Tarreaubaaee002006-06-26 02:48:02 +02002075 if (*(args[1]) == 0) {
2076 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
2077 return -1;
2078 }
2079
2080 preg = calloc(1, sizeof(regex_t));
2081 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
2082 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2083 return -1;
2084 }
2085
2086 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
2087 if (err) {
2088 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
2089 file, linenum, *err);
2090 return -1;
2091 }
2092 }
2093 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
2094 regex_t *preg;
2095 if (curproxy == &defproxy) {
2096 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2097 return -1;
2098 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002099 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2100 return 0;
2101
Willy Tarreaubaaee002006-06-26 02:48:02 +02002102 if (*(args[1]) == 0) {
2103 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
2104 return -1;
2105 }
2106
2107 preg = calloc(1, sizeof(regex_t));
2108 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
2109 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2110 return -1;
2111 }
2112
2113 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
2114 if (err) {
2115 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
2116 file, linenum, *err);
2117 return -1;
2118 }
2119 }
2120 else if (!strcmp(args[0], "rspadd")) { /* add response header */
2121 if (curproxy == &defproxy) {
2122 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2123 return -1;
2124 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002125 else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2126 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002127
2128 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
2129 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
2130 return 0;
2131 }
2132
2133 if (*(args[1]) == 0) {
2134 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
2135 return -1;
2136 }
2137
2138 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
2139 }
2140 else if (!strcmp(args[0], "errorloc") ||
2141 !strcmp(args[0], "errorloc302") ||
2142 !strcmp(args[0], "errorloc303")) { /* error location */
2143 int errnum, errlen;
2144 char *err;
2145
Willy Tarreau977b8e42006-12-29 14:19:17 +01002146 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
2147 return 0;
2148
Willy Tarreaubaaee002006-06-26 02:48:02 +02002149 if (*(args[2]) == 0) {
Willy Tarreau0f772532006-12-23 20:51:41 +01002150 Alert("parsing [%s:%d] : <%s> expects <status_code> and <url> as arguments.\n", file, linenum);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002151 return -1;
2152 }
2153
2154 errnum = atol(args[1]);
2155 if (!strcmp(args[0], "errorloc303")) {
2156 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
2157 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
2158 } else {
2159 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
2160 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
2161 }
2162
Willy Tarreau0f772532006-12-23 20:51:41 +01002163 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
2164 if (http_err_codes[rc] == errnum) {
2165 if (curproxy->errmsg[rc].str)
2166 free(curproxy->errmsg[rc].str);
2167 curproxy->errmsg[rc].str = err;
2168 curproxy->errmsg[rc].len = errlen;
2169 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002170 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002171 }
Willy Tarreau0f772532006-12-23 20:51:41 +01002172
2173 if (rc >= HTTP_ERR_SIZE) {
2174 Warning("parsing [%s:%d] : status code %d not handled, error relocation will be ignored.\n",
2175 file, linenum, errnum);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002176 free(err);
2177 }
2178 }
Willy Tarreau3f49b302007-06-11 00:29:26 +02002179 else if (!strcmp(args[0], "errorfile")) { /* error message from a file */
2180 int errnum, errlen, fd;
2181 char *err;
2182 struct stat stat;
2183
2184 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
2185 return 0;
2186
2187 if (*(args[2]) == 0) {
2188 Alert("parsing [%s:%d] : <%s> expects <status_code> and <file> as arguments.\n", file, linenum);
2189 return -1;
2190 }
2191
2192 fd = open(args[2], O_RDONLY);
2193 if ((fd < 0) || (fstat(fd, &stat) < 0)) {
2194 Alert("parsing [%s:%d] : error opening file <%s> for custom error message <%s>.\n",
2195 file, linenum, args[2], args[1]);
2196 if (fd >= 0)
2197 close(fd);
2198 return -1;
2199 }
2200
2201 if (stat.st_size <= BUFSIZE) {
2202 errlen = stat.st_size;
2203 } else {
2204 Warning("parsing [%s:%d] : custom error message file <%s> larger than %d bytes. Truncating.\n",
2205 file, linenum, args[2], BUFSIZE);
2206 errlen = BUFSIZE;
2207 }
2208
2209 err = malloc(errlen); /* malloc() must succeed during parsing */
2210 errnum = read(fd, err, errlen);
2211 if (errnum != errlen) {
2212 Alert("parsing [%s:%d] : error reading file <%s> for custom error message <%s>.\n",
2213 file, linenum, args[2], args[1]);
2214 close(fd);
2215 free(err);
2216 return -1;
2217 }
2218 close(fd);
2219
2220 errnum = atol(args[1]);
2221 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
2222 if (http_err_codes[rc] == errnum) {
2223 if (curproxy->errmsg[rc].str)
2224 free(curproxy->errmsg[rc].str);
2225 curproxy->errmsg[rc].str = err;
2226 curproxy->errmsg[rc].len = errlen;
2227 break;
2228 }
2229 }
2230
2231 if (rc >= HTTP_ERR_SIZE) {
2232 Warning("parsing [%s:%d] : status code %d not handled, error customization will be ignored.\n",
2233 file, linenum, errnum);
2234 free(err);
2235 }
2236 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002237 else {
2238 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
2239 return -1;
2240 }
2241 return 0;
2242}
2243
2244
2245/*
2246 * This function reads and parses the configuration file given in the argument.
2247 * returns 0 if OK, -1 if error.
2248 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02002249int readcfgfile(const char *file)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002250{
2251 char thisline[256];
2252 char *line;
2253 FILE *f;
2254 int linenum = 0;
2255 char *end;
Willy Tarreau540abe42007-05-02 20:50:16 +02002256 char *args[MAX_LINE_ARGS + 1];
Willy Tarreaubaaee002006-06-26 02:48:02 +02002257 int arg;
2258 int cfgerr = 0;
Willy Tarreau80587432006-12-24 17:47:20 +01002259 int nbchk, mininter;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002260 int confsect = CFG_NONE;
2261
2262 struct proxy *curproxy = NULL;
2263 struct server *newsrv = NULL;
2264
2265 if ((f=fopen(file,"r")) == NULL)
2266 return -1;
2267
2268 init_default_instance();
2269
2270 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
2271 linenum++;
2272
2273 end = line + strlen(line);
2274
2275 /* skip leading spaces */
Willy Tarreau8f8e6452007-06-17 21:51:38 +02002276 while (isspace((unsigned char)*line))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002277 line++;
2278
2279 arg = 0;
2280 args[arg] = line;
2281
2282 while (*line && arg < MAX_LINE_ARGS) {
2283 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
2284 * C equivalent value. Other combinations left unchanged (eg: \1).
2285 */
2286 if (*line == '\\') {
2287 int skip = 0;
2288 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
2289 *line = line[1];
2290 skip = 1;
2291 }
2292 else if (line[1] == 'r') {
2293 *line = '\r';
2294 skip = 1;
2295 }
2296 else if (line[1] == 'n') {
2297 *line = '\n';
2298 skip = 1;
2299 }
2300 else if (line[1] == 't') {
2301 *line = '\t';
2302 skip = 1;
2303 }
2304 else if (line[1] == 'x') {
2305 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
2306 unsigned char hex1, hex2;
2307 hex1 = toupper(line[2]) - '0';
2308 hex2 = toupper(line[3]) - '0';
2309 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2310 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2311 *line = (hex1<<4) + hex2;
2312 skip = 3;
2313 }
2314 else {
2315 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
2316 return -1;
2317 }
2318 }
2319 if (skip) {
2320 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
2321 end -= skip;
2322 }
2323 line++;
2324 }
2325 else if (*line == '#' || *line == '\n' || *line == '\r') {
2326 /* end of string, end of loop */
2327 *line = 0;
2328 break;
2329 }
Willy Tarreau8f8e6452007-06-17 21:51:38 +02002330 else if (isspace((unsigned char)*line)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002331 /* a non-escaped space is an argument separator */
2332 *line++ = 0;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02002333 while (isspace((unsigned char)*line))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002334 line++;
2335 args[++arg] = line;
2336 }
2337 else {
2338 line++;
2339 }
2340 }
2341
2342 /* empty line */
2343 if (!**args)
2344 continue;
2345
Willy Tarreau540abe42007-05-02 20:50:16 +02002346 /* zero out remaining args and ensure that at least one entry
2347 * is zeroed out.
2348 */
2349 while (++arg <= MAX_LINE_ARGS) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002350 args[arg] = line;
2351 }
2352
Willy Tarreau977b8e42006-12-29 14:19:17 +01002353 if (!strcmp(args[0], "listen") ||
2354 !strcmp(args[0], "frontend") ||
2355 !strcmp(args[0], "backend") ||
2356 !strcmp(args[0], "ruleset") ||
2357 !strcmp(args[0], "defaults")) /* new proxy */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002358 confsect = CFG_LISTEN;
2359 else if (!strcmp(args[0], "global")) /* global config */
2360 confsect = CFG_GLOBAL;
2361 /* else it's a section keyword */
2362
2363 switch (confsect) {
2364 case CFG_LISTEN:
2365 if (cfg_parse_listen(file, linenum, args) < 0)
2366 return -1;
2367 break;
2368 case CFG_GLOBAL:
2369 if (cfg_parse_global(file, linenum, args) < 0)
2370 return -1;
2371 break;
2372 default:
2373 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
2374 return -1;
2375 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002376 }
2377 fclose(f);
2378
2379 /*
2380 * Now, check for the integrity of all that we have collected.
2381 */
2382
2383 /* will be needed further to delay some tasks */
2384 tv_now(&now);
2385
2386 if ((curproxy = proxy) == NULL) {
2387 Alert("parsing %s : no <listen> line. Nothing to do !\n",
2388 file);
2389 return -1;
2390 }
2391
2392 while (curproxy != NULL) {
Willy Tarreau55ea7572007-06-17 19:56:27 +02002393 struct switching_rule *rule;
2394
Willy Tarreaubaaee002006-06-26 02:48:02 +02002395 if (curproxy->state == PR_STSTOPPED) {
2396 curproxy = curproxy->next;
2397 continue;
2398 }
2399
Willy Tarreau977b8e42006-12-29 14:19:17 +01002400 if (curproxy->cap & PR_CAP_FE && curproxy->listen == NULL) {
2401 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 +01002402 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002403 cfgerr++;
2404 }
Willy Tarreau977b8e42006-12-29 14:19:17 +01002405 else if (curproxy->cap & PR_CAP_BE &&
2406 ((curproxy->mode != PR_MODE_HEALTH) &&
2407 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
2408 (*(int *)&curproxy->dispatch_addr.sin_addr == 0))) {
2409 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 +01002410 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002411 cfgerr++;
2412 }
Willy Tarreau193cf932007-09-17 10:17:23 +02002413
2414 if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002415 if (curproxy->options & PR_O_TRANSP) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002416 Alert("parsing %s : %s '%s' cannot use both transparent and balance mode.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002417 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002418 cfgerr++;
2419 }
2420#ifdef WE_DONT_SUPPORT_SERVERLESS_LISTENERS
2421 else if (curproxy->srv == NULL) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002422 Alert("parsing %s : %s '%s' needs at least 1 server in balance mode.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002423 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002424 cfgerr++;
2425 }
2426#endif
2427 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002428 Warning("parsing %s : dispatch address of %s '%s' will be ignored in balance mode.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002429 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002430 }
2431 }
Willy Tarreau193cf932007-09-17 10:17:23 +02002432
2433 if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002434 if (curproxy->cookie_name != NULL) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002435 Warning("parsing %s : cookie will be ignored for %s '%s'.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002436 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002437 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002438 if (curproxy->rsp_exp != NULL) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002439 Warning("parsing %s : server regular expressions will be ignored for %s '%s'.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002440 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002441 }
2442 if (curproxy->req_exp != NULL) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002443 Warning("parsing %s : client regular expressions will be ignored for %s '%s'.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002444 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002445 }
Willy Tarreau1c47f852006-07-09 08:22:27 +02002446 if (curproxy->monitor_uri != NULL) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002447 Warning("parsing %s : monitor-uri will be ignored for %s '%s'.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002448 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreau1c47f852006-07-09 08:22:27 +02002449 }
Willy Tarreau2fcb5002007-05-08 13:35:26 +02002450 if (curproxy->options & PR_O_BALANCE_UH) {
2451 curproxy->options &= ~PR_O_BALANCE;
2452 curproxy->options |= PR_O_BALANCE_RR;
2453
2454 Warning("parsing %s : URI hash will be ignored for %s '%s'. Falling back to round robin.\n",
2455 file, proxy_type_str(curproxy), curproxy->id);
2456 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002457 }
Willy Tarreau193cf932007-09-17 10:17:23 +02002458
2459 if (curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
2460 if ((newsrv = curproxy->srv) != NULL) {
2461 Warning("parsing %s : servers will be ignored for %s '%s'.\n",
2462 file, proxy_type_str(curproxy), curproxy->id);
2463 }
2464 }
2465
2466 if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002467 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
2468 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
2469 file, curproxy->id);
2470 cfgerr++;
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002471 }
2472 }
2473
2474 /* if a default backend was specified, let's find it */
2475 if (curproxy->defbe.name) {
2476 struct proxy *target;
2477
2478 for (target = proxy; target != NULL; target = target->next) {
2479 if (strcmp(target->id, curproxy->defbe.name) == 0)
2480 break;
2481 }
2482 if (target == NULL) {
2483 Alert("parsing %s : default backend '%s' in HTTP %s '%s' was not found !\n",
2484 file, curproxy->defbe.name, proxy_type_str(curproxy), curproxy->id);
2485 cfgerr++;
2486 } else if (target == curproxy) {
2487 Alert("parsing %s : loop detected for default backend %s !\n", file, curproxy->defbe.name);
2488 cfgerr++;
2489 } else if (!(target->cap & PR_CAP_BE)) {
2490 Alert("parsing %s : default backend '%s' in HTTP %s '%s' has no backend capability !\n",
2491 file, curproxy->defbe.name, proxy_type_str(curproxy), curproxy->id);
2492 cfgerr++;
2493 } else if (target->mode != curproxy->mode) {
2494 Alert("parsing %s : default backend '%s' in HTTP %s '%s' is not of same mode (tcp/http) !\n",
2495 file, curproxy->defbe.name, proxy_type_str(curproxy), curproxy->id);
2496 cfgerr++;
2497 } else {
2498 free(curproxy->defbe.name);
2499 curproxy->defbe.be = target;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002500 }
2501 }
2502
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002503 /* find the target proxy in setbe */
Willy Tarreaua496b602006-12-17 23:15:24 +01002504 if (curproxy->mode == PR_MODE_HTTP && curproxy->req_exp != NULL) {
2505 /* map jump target for ACT_SETBE in req_rep chain */
2506 struct hdr_exp *exp;
2507 struct proxy *target;
2508 for (exp = curproxy->req_exp; exp != NULL; exp = exp->next) {
2509 if (exp->action != ACT_SETBE)
2510 continue;
2511 for (target = proxy; target != NULL; target = target->next) {
2512 if (strcmp(target->id, exp->replace) == 0)
2513 break;
2514 }
2515 if (target == NULL) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002516 Alert("parsing %s : backend '%s' in HTTP %s '%s' was not found !\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002517 file, exp->replace, proxy_type_str(curproxy), curproxy->id);
Willy Tarreaua496b602006-12-17 23:15:24 +01002518 cfgerr++;
2519 } else if (target == curproxy) {
2520 Alert("parsing %s : loop detected for backend %s !\n", file, exp->replace);
2521 cfgerr++;
Willy Tarreau977b8e42006-12-29 14:19:17 +01002522 } else if (!(target->cap & PR_CAP_BE)) {
2523 Alert("parsing %s : target '%s' in HTTP %s '%s' has no backend capability !\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002524 file, exp->replace, proxy_type_str(curproxy), curproxy->id);
Willy Tarreau977b8e42006-12-29 14:19:17 +01002525 cfgerr++;
2526 } else if (target->mode != PR_MODE_HTTP) {
2527 Alert("parsing %s : backend '%s' in HTTP %s '%s' is not HTTP (use 'mode http') !\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002528 file, exp->replace, proxy_type_str(curproxy), curproxy->id);
Willy Tarreau977b8e42006-12-29 14:19:17 +01002529 cfgerr++;
Willy Tarreaua496b602006-12-17 23:15:24 +01002530 } else {
2531 free((void *)exp->replace);
2532 exp->replace = (const char *)target;
2533 }
2534 }
2535 }
Willy Tarreau55ea7572007-06-17 19:56:27 +02002536
2537 /* find the target proxy for 'use_backend' rules */
2538 list_for_each_entry(rule, &curproxy->switching_rules, list) {
2539 /* map jump target for ACT_SETBE in req_rep chain */
2540 struct proxy *target;
2541
2542 for (target = proxy; target != NULL; target = target->next) {
2543 if (strcmp(target->id, rule->be.name) == 0)
2544 break;
2545 }
2546
2547 if (target == NULL) {
2548 Alert("parsing %s : backend '%s' in HTTP %s '%s' was not found !\n",
2549 file, rule->be.name, proxy_type_str(curproxy), curproxy->id);
2550 cfgerr++;
2551 } else if (target == curproxy) {
2552 Alert("parsing %s : loop detected for backend %s !\n", file, rule->be.name);
2553 cfgerr++;
2554 } else if (!(target->cap & PR_CAP_BE)) {
2555 Alert("parsing %s : target '%s' in HTTP %s '%s' has no backend capability !\n",
2556 file, rule->be.name, proxy_type_str(curproxy), curproxy->id);
2557 cfgerr++;
2558 } else if (target->mode != curproxy->mode) {
2559 Alert("parsing %s : backend '%s' referenced in %s '%s' is of different mode !\n",
2560 file, rule->be.name, proxy_type_str(curproxy), curproxy->id);
2561 cfgerr++;
2562 } else {
2563 free((void *)rule->be.name);
2564 rule->be.backend = target;
2565 }
2566 }
2567
Willy Tarreau2738a142006-07-08 17:28:09 +02002568 if ((curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HTTP) &&
Willy Tarreaud825eef2007-05-12 22:35:00 +02002569 (((curproxy->cap & PR_CAP_FE) && !tv_isset(&curproxy->clitimeout)) ||
2570 ((curproxy->cap & PR_CAP_BE) && (curproxy->srv) &&
2571 (!tv_isset(&curproxy->contimeout) || !tv_isset(&curproxy->srvtimeout))))) {
Willy Tarreau977b8e42006-12-29 14:19:17 +01002572 Warning("parsing %s : missing timeouts for %s '%s'.\n"
Willy Tarreau2738a142006-07-08 17:28:09 +02002573 " | While not properly invalid, you will certainly encounter various problems\n"
2574 " | with such a configuration. To fix this, please ensure that all following\n"
2575 " | values are set to a non-zero value: clitimeout, contimeout, srvtimeout.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002576 file, proxy_type_str(curproxy), curproxy->id);
Willy Tarreau2738a142006-07-08 17:28:09 +02002577 }
Willy Tarreauf3c69202006-07-09 16:42:34 +02002578
2579 if (curproxy->options & PR_O_SSL3_CHK) {
2580 curproxy->check_len = sizeof(sslv3_client_hello_pkt);
2581 curproxy->check_req = (char *)malloc(sizeof(sslv3_client_hello_pkt));
2582 memcpy(curproxy->check_req, sslv3_client_hello_pkt, sizeof(sslv3_client_hello_pkt));
2583 }
2584
Willy Tarreaucf7f3202007-05-13 22:46:04 +02002585 /* The small pools required for the capture lists */
2586 if (curproxy->nb_req_cap)
2587 curproxy->req_cap_pool = create_pool("ptrcap",
2588 curproxy->nb_req_cap * sizeof(char *),
2589 MEM_F_SHARED);
2590 if (curproxy->nb_rsp_cap)
2591 curproxy->rsp_cap_pool = create_pool("ptrcap",
2592 curproxy->nb_rsp_cap * sizeof(char *),
2593 MEM_F_SHARED);
2594
Willy Tarreau1d4154a2007-05-13 22:57:02 +02002595 curproxy->hdr_idx_pool = create_pool("hdr_idx",
2596 MAX_HTTP_HDR * sizeof(struct hdr_idx_elem),
2597 MEM_F_SHARED);
2598
Willy Tarreau86034312006-12-29 00:10:33 +01002599 /* for backwards compatibility with "listen" instances, if
2600 * fullconn is not set but maxconn is set, then maxconn
2601 * is used.
2602 */
2603 if (!curproxy->fullconn)
2604 curproxy->fullconn = curproxy->maxconn;
2605
Willy Tarreaubaaee002006-06-26 02:48:02 +02002606 /* first, we will invert the servers list order */
2607 newsrv = NULL;
2608 while (curproxy->srv) {
2609 struct server *next;
2610
2611 next = curproxy->srv->next;
2612 curproxy->srv->next = newsrv;
2613 newsrv = curproxy->srv;
2614 if (!next)
2615 break;
2616 curproxy->srv = next;
2617 }
2618
2619 /* now, newsrv == curproxy->srv */
2620 if (newsrv) {
2621 struct server *srv;
2622 int pgcd;
2623 int act, bck;
2624
2625 /* We will factor the weights to reduce the table,
2626 * using Euclide's largest common divisor algorithm
2627 */
Willy Tarreau417fae02007-03-25 21:16:40 +02002628 pgcd = newsrv->uweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002629 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
2630 int t, w;
2631
Willy Tarreau417fae02007-03-25 21:16:40 +02002632 w = srv->uweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002633 while (w) {
2634 t = pgcd % w;
2635 pgcd = w;
2636 w = t;
2637 }
2638 }
2639
2640 act = bck = 0;
2641 for (srv = newsrv; srv; srv = srv->next) {
Willy Tarreau417fae02007-03-25 21:16:40 +02002642 srv->eweight = srv->uweight / pgcd;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002643 if (srv->state & SRV_BACKUP)
Willy Tarreau417fae02007-03-25 21:16:40 +02002644 bck += srv->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002645 else
Willy Tarreau417fae02007-03-25 21:16:40 +02002646 act += srv->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002647 }
2648
2649 /* this is the largest map we will ever need for this servers list */
2650 if (act < bck)
2651 act = bck;
2652
2653 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
2654 /* recounts servers and their weights */
Willy Tarreau5af3a692007-07-24 23:32:33 +02002655 curproxy->map_state = PR_MAP_RECALC;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002656 recount_servers(curproxy);
2657 recalc_server_map(curproxy);
2658 }
2659
2660 if (curproxy->options & PR_O_LOGASAP)
2661 curproxy->to_log &= ~LW_BYTES;
2662
Willy Tarreaubaaee002006-06-26 02:48:02 +02002663 /*
2664 * If this server supports a maxconn parameter, it needs a dedicated
2665 * tasks to fill the emptied slots when a connection leaves.
2666 */
2667 newsrv = curproxy->srv;
2668 while (newsrv != NULL) {
Willy Tarreau86034312006-12-29 00:10:33 +01002669 if (newsrv->minconn > newsrv->maxconn) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002670 /* Only 'minconn' was specified, or it was higher than or equal
2671 * to 'maxconn'. Let's turn this into maxconn and clean it, as
2672 * this will avoid further useless expensive computations.
2673 */
2674 newsrv->maxconn = newsrv->minconn;
Willy Tarreau86034312006-12-29 00:10:33 +01002675 } else if (newsrv->maxconn && !newsrv->minconn) {
2676 /* minconn was not specified, so we set it to maxconn */
2677 newsrv->minconn = newsrv->maxconn;
Willy Tarreau977b8e42006-12-29 14:19:17 +01002678 } else if (newsrv->minconn != newsrv->maxconn && !curproxy->fullconn) {
2679 Alert("parsing %s, %s '%s' : fullconn is mandatory when minconn is set on a server.\n",
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002680 file, proxy_type_str(curproxy), curproxy->id, linenum);
Willy Tarreau86034312006-12-29 00:10:33 +01002681 return -1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002682 }
2683
2684 if (newsrv->maxconn > 0) {
2685 struct task *t;
2686
Willy Tarreauc6ca1a02007-05-13 19:43:47 +02002687 if ((t = pool_alloc2(pool2_task)) == NULL) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002688 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2689 return -1;
2690 }
2691
Willy Tarreau96bcfd72007-04-29 10:41:56 +02002692 t->qlist.p = NULL;
Willy Tarreau964c9362007-01-07 00:38:00 +01002693 t->wq = NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002694 t->state = TASK_IDLE;
2695 t->process = process_srv_queue;
2696 t->context = newsrv;
2697 newsrv->queue_mgt = t;
2698
2699 /* never run it unless specifically woken up */
2700 tv_eternity(&t->expire);
2701 task_queue(t);
2702 }
2703 newsrv = newsrv->next;
2704 }
2705
2706 /* now we'll start this proxy's health checks if any */
2707 /* 1- count the checkers to run simultaneously */
2708 nbchk = 0;
2709 mininter = 0;
2710 newsrv = curproxy->srv;
2711 while (newsrv != NULL) {
2712 if (newsrv->state & SRV_CHECKED) {
2713 if (!mininter || mininter > newsrv->inter)
2714 mininter = newsrv->inter;
2715 nbchk++;
2716 }
2717 newsrv = newsrv->next;
2718 }
2719
2720 /* 2- start them as far as possible from each others while respecting
2721 * their own intervals. For this, we will start them after their own
2722 * interval added to the min interval divided by the number of servers,
2723 * weighted by the server's position in the list.
2724 */
2725 if (nbchk > 0) {
2726 struct task *t;
2727 int srvpos;
2728
2729 newsrv = curproxy->srv;
2730 srvpos = 0;
2731 while (newsrv != NULL) {
2732 /* should this server be checked ? */
2733 if (newsrv->state & SRV_CHECKED) {
Willy Tarreauc6ca1a02007-05-13 19:43:47 +02002734 if ((t = pool_alloc2(pool2_task)) == NULL) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002735 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2736 return -1;
2737 }
2738
Willy Tarreau964c9362007-01-07 00:38:00 +01002739 t->wq = NULL;
Willy Tarreau96bcfd72007-04-29 10:41:56 +02002740 t->qlist.p = NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002741 t->state = TASK_IDLE;
2742 t->process = process_chk;
2743 t->context = newsrv;
2744
2745 /* check this every ms */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002746 tv_ms_add(&t->expire, &now,
2747 newsrv->inter + mininter * srvpos / nbchk);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002748 task_queue(t);
2749 //task_wakeup(&rq, t);
2750 srvpos++;
2751 }
2752 newsrv = newsrv->next;
2753 }
2754 }
2755
2756 curproxy = curproxy->next;
2757 }
2758 if (cfgerr > 0) {
2759 Alert("Errors found in configuration file, aborting.\n");
2760 return -1;
2761 }
2762 else
2763 return 0;
2764}
2765
2766
2767
2768/*
2769 * Local variables:
2770 * c-indent-level: 8
2771 * c-basic-offset: 8
2772 * End:
2773 */