blob: 091f6d98f48b4e661aa74bff1afb8fbfb6e81a70 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Configuration parser
3 *
4 * Copyright 2000-2006 Willy Tarreau <w@1wt.eu>
5 *
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>
18
Willy Tarreau2dd0d472006-06-29 17:53:05 +020019#include <common/cfgparse.h>
20#include <common/config.h>
21#include <common/memory.h>
22#include <common/standard.h>
23#include <common/time.h>
24#include <common/uri_auth.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020025
26#include <types/capture.h>
27#include <types/global.h>
28#include <types/polling.h>
29#include <types/proxy.h>
30#include <types/queue.h>
31
32#include <proto/backend.h>
33#include <proto/checks.h>
34#include <proto/log.h>
35#include <proto/server.h>
36#include <proto/task.h>
37
38
39const char *HTTP_302 =
40 "HTTP/1.0 302 Found\r\n"
41 "Cache-Control: no-cache\r\n"
42 "Connection: close\r\n"
43 "Location: "; /* not terminated since it will be concatenated with the URL */
44
45/* same as 302 except that the browser MUST retry with the GET method */
46const char *HTTP_303 =
47 "HTTP/1.0 303 See Other\r\n"
48 "Cache-Control: no-cache\r\n"
49 "Connection: close\r\n"
50 "Location: "; /* not terminated since it will be concatenated with the URL */
51
52const char *HTTP_400 =
53 "HTTP/1.0 400 Bad request\r\n"
54 "Cache-Control: no-cache\r\n"
55 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +020056 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +020057 "\r\n"
58 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
59
60const char *HTTP_403 =
61 "HTTP/1.0 403 Forbidden\r\n"
62 "Cache-Control: no-cache\r\n"
63 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +020064 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +020065 "\r\n"
66 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
67
68const char *HTTP_408 =
69 "HTTP/1.0 408 Request Time-out\r\n"
70 "Cache-Control: no-cache\r\n"
71 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +020072 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +020073 "\r\n"
74 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
75
76const char *HTTP_500 =
77 "HTTP/1.0 500 Server Error\r\n"
78 "Cache-Control: no-cache\r\n"
79 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +020080 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +020081 "\r\n"
82 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
83
84const char *HTTP_502 =
85 "HTTP/1.0 502 Bad Gateway\r\n"
86 "Cache-Control: no-cache\r\n"
87 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +020088 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +020089 "\r\n"
90 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
91
92const char *HTTP_503 =
93 "HTTP/1.0 503 Service Unavailable\r\n"
94 "Cache-Control: no-cache\r\n"
95 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +020096 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +020097 "\r\n"
98 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
99
100const char *HTTP_504 =
101 "HTTP/1.0 504 Gateway Time-out\r\n"
102 "Cache-Control: no-cache\r\n"
103 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +0200104 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200105 "\r\n"
106 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n";
107
108
109static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
110int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
111int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
112
113/*
114 * converts <str> to a list of listeners which are dynamically allocated.
115 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
116 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
117 * - <port> is a numerical port from 1 to 65535 ;
118 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
119 * This can be repeated as many times as necessary, separated by a coma.
120 * The <tail> argument is a pointer to a current list which should be appended
121 * to the tail of the new list. The pointer to the new list is returned.
122 */
123static struct listener *str2listener(char *str, struct listener *tail)
124{
125 struct listener *l;
126 char *c, *next, *range, *dupstr;
127 int port, end;
128
129 next = dupstr = strdup(str);
130
131 while (next && *next) {
132 struct sockaddr_storage ss;
133
134 str = next;
135 /* 1) look for the end of the first address */
136 if ((next = strrchr(str, ',')) != NULL) {
137 *next++ = 0;
138 }
139
140 /* 2) look for the addr/port delimiter, it's the last colon. */
141 if ((range = strrchr(str, ':')) == NULL) {
142 Alert("Missing port number: '%s'\n", str);
143 goto fail;
144 }
145
146 *range++ = 0;
147
148 if (strrchr(str, ':') != NULL) {
149 /* IPv6 address contains ':' */
150 memset(&ss, 0, sizeof(ss));
151 ss.ss_family = AF_INET6;
152
153 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
154 Alert("Invalid server address: '%s'\n", str);
155 goto fail;
156 }
157 }
158 else {
159 memset(&ss, 0, sizeof(ss));
160 ss.ss_family = AF_INET;
161
162 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
163 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
164 }
165 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
166 struct hostent *he;
167
168 if ((he = gethostbyname(str)) == NULL) {
169 Alert("Invalid server name: '%s'\n", str);
170 goto fail;
171 }
172 else
173 ((struct sockaddr_in *)&ss)->sin_addr =
174 *(struct in_addr *) *(he->h_addr_list);
175 }
176 }
177
178 /* 3) look for the port-end delimiter */
179 if ((c = strchr(range, '-')) != NULL) {
180 *c++ = 0;
181 end = atol(c);
182 }
183 else {
184 end = atol(range);
185 }
186
187 port = atol(range);
188
189 if (port < 1 || port > 65535) {
190 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
191 goto fail;
192 }
193
194 if (end < 1 || end > 65535) {
195 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
196 goto fail;
197 }
198
199 for (; port <= end; port++) {
200 l = (struct listener *)calloc(1, sizeof(struct listener));
201 l->next = tail;
202 tail = l;
203
204 l->fd = -1;
205 l->addr = ss;
206 if (ss.ss_family == AF_INET6)
207 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
208 else
209 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
210
211 } /* end for(port) */
212 } /* end while(next) */
213 free(dupstr);
214 return tail;
215 fail:
216 free(dupstr);
217 return NULL;
218}
219
220
221/*
222 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
223 */
224int cfg_parse_global(char *file, int linenum, char **args)
225{
226
227 if (!strcmp(args[0], "global")) { /* new section */
228 /* no option, nothing special to do */
229 return 0;
230 }
231 else if (!strcmp(args[0], "daemon")) {
232 global.mode |= MODE_DAEMON;
233 }
234 else if (!strcmp(args[0], "debug")) {
235 global.mode |= MODE_DEBUG;
236 }
237 else if (!strcmp(args[0], "noepoll")) {
238 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
239 }
240 else if (!strcmp(args[0], "nopoll")) {
241 cfg_polling_mechanism &= ~POLL_USE_POLL;
242 }
243 else if (!strcmp(args[0], "quiet")) {
244 global.mode |= MODE_QUIET;
245 }
246 else if (!strcmp(args[0], "stats")) {
247 global.mode |= MODE_STATS;
248 }
249 else if (!strcmp(args[0], "uid")) {
250 if (global.uid != 0) {
251 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
252 return 0;
253 }
254 if (*(args[1]) == 0) {
255 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
256 return -1;
257 }
258 global.uid = atol(args[1]);
259 }
260 else if (!strcmp(args[0], "gid")) {
261 if (global.gid != 0) {
262 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
263 return 0;
264 }
265 if (*(args[1]) == 0) {
266 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
267 return -1;
268 }
269 global.gid = atol(args[1]);
270 }
271 else if (!strcmp(args[0], "nbproc")) {
272 if (global.nbproc != 0) {
273 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
274 return 0;
275 }
276 if (*(args[1]) == 0) {
277 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
278 return -1;
279 }
280 global.nbproc = atol(args[1]);
281 }
282 else if (!strcmp(args[0], "maxconn")) {
283 if (global.maxconn != 0) {
284 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
285 return 0;
286 }
287 if (*(args[1]) == 0) {
288 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
289 return -1;
290 }
291 global.maxconn = atol(args[1]);
292#ifdef SYSTEM_MAXCONN
293 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
294 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);
295 global.maxconn = DEFAULT_MAXCONN;
296 }
297#endif /* SYSTEM_MAXCONN */
298 }
299 else if (!strcmp(args[0], "ulimit-n")) {
300 if (global.rlimit_nofile != 0) {
301 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
302 return 0;
303 }
304 if (*(args[1]) == 0) {
305 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
306 return -1;
307 }
308 global.rlimit_nofile = atol(args[1]);
309 }
310 else if (!strcmp(args[0], "chroot")) {
311 if (global.chroot != NULL) {
312 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
313 return 0;
314 }
315 if (*(args[1]) == 0) {
316 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
317 return -1;
318 }
319 global.chroot = strdup(args[1]);
320 }
321 else if (!strcmp(args[0], "pidfile")) {
322 if (global.pidfile != NULL) {
323 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
324 return 0;
325 }
326 if (*(args[1]) == 0) {
327 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
328 return -1;
329 }
330 global.pidfile = strdup(args[1]);
331 }
332 else if (!strcmp(args[0], "log")) { /* syslog server address */
333 struct sockaddr_in *sa;
334 int facility, level;
335
336 if (*(args[1]) == 0 || *(args[2]) == 0) {
337 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
338 return -1;
339 }
340
341 facility = get_log_facility(args[2]);
342 if (facility < 0) {
343 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
344 exit(1);
345 }
346
347 level = 7; /* max syslog level = debug */
348 if (*(args[3])) {
349 level = get_log_level(args[3]);
350 if (level < 0) {
351 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
352 exit(1);
353 }
354 }
355
356 sa = str2sa(args[1]);
357 if (!sa->sin_port)
358 sa->sin_port = htons(SYSLOG_PORT);
359
360 if (global.logfac1 == -1) {
361 global.logsrv1 = *sa;
362 global.logfac1 = facility;
363 global.loglev1 = level;
364 }
365 else if (global.logfac2 == -1) {
366 global.logsrv2 = *sa;
367 global.logfac2 = facility;
368 global.loglev2 = level;
369 }
370 else {
371 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
372 return -1;
373 }
374
375 }
376 else {
377 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
378 return -1;
379 }
380 return 0;
381}
382
383
384static void init_default_instance()
385{
386 memset(&defproxy, 0, sizeof(defproxy));
387 defproxy.mode = PR_MODE_TCP;
388 defproxy.state = PR_STNEW;
389 defproxy.maxconn = cfg_maxpconn;
390 defproxy.conn_retries = CONN_RETRIES;
391 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
392}
393
394/*
395 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
396 */
397int cfg_parse_listen(char *file, int linenum, char **args)
398{
399 static struct proxy *curproxy = NULL;
400 struct server *newsrv = NULL;
401 char *err;
402 int rc;
403
404 if (!strcmp(args[0], "listen")) { /* new proxy */
405 if (!*args[1]) {
406 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
407 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
408 file, linenum, args[0]);
409 return -1;
410 }
411
412 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
413 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
414 return -1;
415 }
416
417 curproxy->next = proxy;
418 proxy = curproxy;
419 LIST_INIT(&curproxy->pendconns);
420
421 curproxy->id = strdup(args[1]);
422
423 /* parse the listener address if any */
424 if (*args[2]) {
425 curproxy->listen = str2listener(args[2], curproxy->listen);
426 if (!curproxy->listen)
427 return -1;
428 global.maxsock++;
429 }
430
431 /* set default values */
432 curproxy->state = defproxy.state;
433 curproxy->maxconn = defproxy.maxconn;
434 curproxy->conn_retries = defproxy.conn_retries;
435 curproxy->options = defproxy.options;
436
437 if (defproxy.check_req)
438 curproxy->check_req = strdup(defproxy.check_req);
439 curproxy->check_len = defproxy.check_len;
440
441 if (defproxy.cookie_name)
442 curproxy->cookie_name = strdup(defproxy.cookie_name);
443 curproxy->cookie_len = defproxy.cookie_len;
444
445 if (defproxy.capture_name)
446 curproxy->capture_name = strdup(defproxy.capture_name);
447 curproxy->capture_namelen = defproxy.capture_namelen;
448 curproxy->capture_len = defproxy.capture_len;
449
450 if (defproxy.errmsg.msg400)
451 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
452 curproxy->errmsg.len400 = defproxy.errmsg.len400;
453
454 if (defproxy.errmsg.msg403)
455 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
456 curproxy->errmsg.len403 = defproxy.errmsg.len403;
457
458 if (defproxy.errmsg.msg408)
459 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
460 curproxy->errmsg.len408 = defproxy.errmsg.len408;
461
462 if (defproxy.errmsg.msg500)
463 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
464 curproxy->errmsg.len500 = defproxy.errmsg.len500;
465
466 if (defproxy.errmsg.msg502)
467 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
468 curproxy->errmsg.len502 = defproxy.errmsg.len502;
469
470 if (defproxy.errmsg.msg503)
471 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
472 curproxy->errmsg.len503 = defproxy.errmsg.len503;
473
474 if (defproxy.errmsg.msg504)
475 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
476 curproxy->errmsg.len504 = defproxy.errmsg.len504;
477
478 curproxy->clitimeout = defproxy.clitimeout;
479 curproxy->contimeout = defproxy.contimeout;
480 curproxy->srvtimeout = defproxy.srvtimeout;
481 curproxy->mode = defproxy.mode;
482 curproxy->logfac1 = defproxy.logfac1;
483 curproxy->logsrv1 = defproxy.logsrv1;
484 curproxy->loglev1 = defproxy.loglev1;
485 curproxy->logfac2 = defproxy.logfac2;
486 curproxy->logsrv2 = defproxy.logsrv2;
487 curproxy->loglev2 = defproxy.loglev2;
488 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
489 curproxy->grace = defproxy.grace;
490 curproxy->uri_auth = defproxy.uri_auth;
491 curproxy->source_addr = defproxy.source_addr;
492 curproxy->mon_net = defproxy.mon_net;
493 curproxy->mon_mask = defproxy.mon_mask;
494 return 0;
495 }
496 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
497 /* some variables may have already been initialized earlier */
498 if (defproxy.check_req) free(defproxy.check_req);
499 if (defproxy.cookie_name) free(defproxy.cookie_name);
500 if (defproxy.capture_name) free(defproxy.capture_name);
501 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
502 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
503 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
504 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
505 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
506 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
507 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
508 /* we cannot free uri_auth because it might already be used */
509 init_default_instance();
510 curproxy = &defproxy;
511 return 0;
512 }
513 else if (curproxy == NULL) {
514 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
515 return -1;
516 }
517
518 if (!strcmp(args[0], "bind")) { /* new listen addresses */
519 if (curproxy == &defproxy) {
520 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
521 return -1;
522 }
523
524 if (strchr(args[1], ':') == NULL) {
525 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
526 file, linenum, args[0]);
527 return -1;
528 }
529 curproxy->listen = str2listener(args[1], curproxy->listen);
530 if (!curproxy->listen)
531 return -1;
532 global.maxsock++;
533 return 0;
534 }
535 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
536 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
537 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
538 file, linenum, args[0]);
539 return -1;
540 }
541 /* flush useless bits */
542 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
543 return 0;
544 }
545 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
546 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
547 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
548 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
549 else {
550 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
551 return -1;
552 }
553 }
554 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
555 curproxy->state = PR_STSTOPPED;
556 }
557 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
558 curproxy->state = PR_STNEW;
559 }
560 else if (!strcmp(args[0], "cookie")) { /* cookie name */
561 int cur_arg;
562 // if (curproxy == &defproxy) {
563 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
564 // return -1;
565 // }
566
567 if (curproxy->cookie_name != NULL) {
568 // Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
569 // file, linenum);
570 // return 0;
571 free(curproxy->cookie_name);
572 }
573
574 if (*(args[1]) == 0) {
575 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
576 file, linenum, args[0]);
577 return -1;
578 }
579 curproxy->cookie_name = strdup(args[1]);
580 curproxy->cookie_len = strlen(curproxy->cookie_name);
581
582 cur_arg = 2;
583 while (*(args[cur_arg])) {
584 if (!strcmp(args[cur_arg], "rewrite")) {
585 curproxy->options |= PR_O_COOK_RW;
586 }
587 else if (!strcmp(args[cur_arg], "indirect")) {
588 curproxy->options |= PR_O_COOK_IND;
589 }
590 else if (!strcmp(args[cur_arg], "insert")) {
591 curproxy->options |= PR_O_COOK_INS;
592 }
593 else if (!strcmp(args[cur_arg], "nocache")) {
594 curproxy->options |= PR_O_COOK_NOC;
595 }
596 else if (!strcmp(args[cur_arg], "postonly")) {
597 curproxy->options |= PR_O_COOK_POST;
598 }
599 else if (!strcmp(args[cur_arg], "prefix")) {
600 curproxy->options |= PR_O_COOK_PFX;
601 }
602 else {
603 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
604 file, linenum, args[0]);
605 return -1;
606 }
607 cur_arg++;
608 }
609 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
610 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
611 file, linenum);
612 return -1;
613 }
614
615 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
616 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
617 file, linenum);
618 return -1;
619 }
620 }/* end else if (!strcmp(args[0], "cookie")) */
621 else if (!strcmp(args[0], "appsession")) { /* cookie name */
622 // if (curproxy == &defproxy) {
623 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
624 // return -1;
625 // }
626
627 if (curproxy->appsession_name != NULL) {
628 // Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
629 // file, linenum);
630 // return 0;
631 free(curproxy->appsession_name);
632 }
633
634 if (*(args[5]) == 0) {
635 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
636 file, linenum, args[0]);
637 return -1;
638 }
639 have_appsession = 1;
640 curproxy->appsession_name = strdup(args[1]);
641 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
642 curproxy->appsession_len = atoi(args[3]);
643 curproxy->appsession_timeout = atoi(args[5]);
644 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
645 if (rc) {
646 Alert("Error Init Appsession Hashtable.\n");
647 return -1;
648 }
649 } /* Url App Session */
650 else if (!strcmp(args[0], "capture")) {
651 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
652 // if (curproxy == &defproxy) {
653 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
654 // return -1;
655 // }
656
657 if (curproxy->capture_name != NULL) {
658 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
659 // file, linenum, args[0]);
660 // return 0;
661 free(curproxy->capture_name);
662 }
663
664 if (*(args[4]) == 0) {
665 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
666 file, linenum, args[0]);
667 return -1;
668 }
669 curproxy->capture_name = strdup(args[2]);
670 curproxy->capture_namelen = strlen(curproxy->capture_name);
671 curproxy->capture_len = atol(args[4]);
672 if (curproxy->capture_len >= CAPTURE_LEN) {
673 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
674 file, linenum, CAPTURE_LEN - 1);
675 curproxy->capture_len = CAPTURE_LEN - 1;
676 }
677 curproxy->to_log |= LW_COOKIE;
678 }
679 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
680 struct cap_hdr *hdr;
681
682 if (curproxy == &defproxy) {
683 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
684 return -1;
685 }
686
687 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
688 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
689 file, linenum, args[0], args[1]);
690 return -1;
691 }
692
693 hdr = calloc(sizeof(struct cap_hdr), 1);
694 hdr->next = curproxy->req_cap;
695 hdr->name = strdup(args[3]);
696 hdr->namelen = strlen(args[3]);
697 hdr->len = atol(args[5]);
698 hdr->index = curproxy->nb_req_cap++;
699 curproxy->req_cap = hdr;
700 curproxy->to_log |= LW_REQHDR;
701 }
702 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
703 struct cap_hdr *hdr;
704
705 if (curproxy == &defproxy) {
706 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
707 return -1;
708 }
709
710 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
711 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
712 file, linenum, args[0], args[1]);
713 return -1;
714 }
715 hdr = calloc(sizeof(struct cap_hdr), 1);
716 hdr->next = curproxy->rsp_cap;
717 hdr->name = strdup(args[3]);
718 hdr->namelen = strlen(args[3]);
719 hdr->len = atol(args[5]);
720 hdr->index = curproxy->nb_rsp_cap++;
721 curproxy->rsp_cap = hdr;
722 curproxy->to_log |= LW_RSPHDR;
723 }
724 else {
725 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
726 file, linenum, args[0]);
727 return -1;
728 }
729 }
730 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
731 if (curproxy->contimeout != defproxy.contimeout) {
732 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
733 return 0;
734 }
735 if (*(args[1]) == 0) {
736 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
737 file, linenum, args[0]);
738 return -1;
739 }
740 curproxy->contimeout = atol(args[1]);
741 }
742 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
743 if (curproxy->clitimeout != defproxy.clitimeout) {
744 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
745 file, linenum, args[0]);
746 return 0;
747 }
748 if (*(args[1]) == 0) {
749 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
750 file, linenum, args[0]);
751 return -1;
752 }
753 curproxy->clitimeout = atol(args[1]);
754 }
755 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
756 if (curproxy->srvtimeout != defproxy.srvtimeout) {
757 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
758 return 0;
759 }
760 if (*(args[1]) == 0) {
761 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
762 file, linenum, args[0]);
763 return -1;
764 }
765 curproxy->srvtimeout = atol(args[1]);
766 }
767 else if (!strcmp(args[0], "retries")) { /* connection retries */
768 if (*(args[1]) == 0) {
769 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
770 file, linenum, args[0]);
771 return -1;
772 }
773 curproxy->conn_retries = atol(args[1]);
774 }
775 else if (!strcmp(args[0], "stats")) {
776 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
777 curproxy->uri_auth = NULL; /* we must detach from the default config */
778
779 if (*(args[1]) == 0) {
780 Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable'.\n", file, linenum, args[0]);
781 return -1;
782 } else if (!strcmp(args[1], "uri")) {
783 if (*(args[2]) == 0) {
784 Alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
785 return -1;
786 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
787 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
788 return -1;
789 }
790 } else if (!strcmp(args[1], "realm")) {
791 if (*(args[2]) == 0) {
792 Alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
793 return -1;
794 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
795 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
796 return -1;
797 }
798 } else if (!strcmp(args[1], "auth")) {
799 if (*(args[2]) == 0) {
800 Alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
801 return -1;
802 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
803 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
804 return -1;
805 }
806 } else if (!strcmp(args[1], "scope")) {
807 if (*(args[2]) == 0) {
808 Alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
809 return -1;
810 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
811 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
812 return -1;
813 }
814 } else if (!strcmp(args[1], "enable")) {
815 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
816 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
817 return -1;
818 }
819 } else {
820 Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'uri', 'realm', 'auth' or 'enable').\n",
821 file, linenum, args[0]);
822 return -1;
823 }
824 }
825 else if (!strcmp(args[0], "option")) {
826 if (*(args[1]) == 0) {
827 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
828 return -1;
829 }
830 if (!strcmp(args[1], "redispatch"))
831 /* enable reconnections to dispatch */
832 curproxy->options |= PR_O_REDISP;
833#ifdef TPROXY
834 else if (!strcmp(args[1], "transparent"))
835 /* enable transparent proxy connections */
836 curproxy->options |= PR_O_TRANSP;
837#endif
838 else if (!strcmp(args[1], "keepalive"))
839 /* enable keep-alive */
840 curproxy->options |= PR_O_KEEPALIVE;
841 else if (!strcmp(args[1], "forwardfor"))
842 /* insert x-forwarded-for field */
843 curproxy->options |= PR_O_FWDFOR;
844 else if (!strcmp(args[1], "logasap"))
845 /* log as soon as possible, without waiting for the session to complete */
846 curproxy->options |= PR_O_LOGASAP;
847 else if (!strcmp(args[1], "abortonclose"))
848 /* abort connection if client closes during queue or connect() */
849 curproxy->options |= PR_O_ABRT_CLOSE;
850 else if (!strcmp(args[1], "httpclose"))
851 /* force connection: close in both directions in HTTP mode */
852 curproxy->options |= PR_O_HTTP_CLOSE;
853 else if (!strcmp(args[1], "forceclose"))
854 /* force connection: close in both directions in HTTP mode and enforce end of session */
855 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
856 else if (!strcmp(args[1], "checkcache"))
857 /* require examination of cacheability of the 'set-cookie' field */
858 curproxy->options |= PR_O_CHK_CACHE;
859 else if (!strcmp(args[1], "httplog"))
860 /* generate a complete HTTP log */
861 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
862 else if (!strcmp(args[1], "tcplog"))
863 /* generate a detailed TCP log */
864 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
865 else if (!strcmp(args[1], "dontlognull")) {
866 /* don't log empty requests */
867 curproxy->options |= PR_O_NULLNOLOG;
868 }
869 else if (!strcmp(args[1], "tcpka")) {
870 /* enable TCP keep-alives on client and server sessions */
871 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
872 }
873 else if (!strcmp(args[1], "clitcpka")) {
874 /* enable TCP keep-alives on client sessions */
875 curproxy->options |= PR_O_TCP_CLI_KA;
876 }
877 else if (!strcmp(args[1], "srvtcpka")) {
878 /* enable TCP keep-alives on server sessions */
879 curproxy->options |= PR_O_TCP_SRV_KA;
880 }
881 else if (!strcmp(args[1], "allbackups")) {
882 /* Use all backup servers simultaneously */
883 curproxy->options |= PR_O_USE_ALL_BK;
884 }
885 else if (!strcmp(args[1], "httpchk")) {
886 /* use HTTP request to check servers' health */
887 if (curproxy->check_req != NULL) {
888 free(curproxy->check_req);
889 }
890 curproxy->options |= PR_O_HTTP_CHK;
891 if (!*args[2]) { /* no argument */
892 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
893 curproxy->check_len = strlen(DEF_CHECK_REQ);
894 } else if (!*args[3]) { /* one argument : URI */
895 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
896 curproxy->check_req = (char *)malloc(reqlen);
897 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
898 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
899 } else { /* more arguments : METHOD URI [HTTP_VER] */
900 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
901 if (*args[4])
902 reqlen += strlen(args[4]);
903 else
904 reqlen += strlen("HTTP/1.0");
905
906 curproxy->check_req = (char *)malloc(reqlen);
907 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
908 "%s %s %s\r\n\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
909 }
910 }
911 else if (!strcmp(args[1], "persist")) {
912 /* persist on using the server specified by the cookie, even when it's down */
913 curproxy->options |= PR_O_PERSIST;
914 }
915 else {
916 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
917 return -1;
918 }
919 return 0;
920 }
921 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
922 /* enable reconnections to dispatch */
923 curproxy->options |= PR_O_REDISP;
924 }
925#ifdef TPROXY
926 else if (!strcmp(args[0], "transparent")) {
927 /* enable transparent proxy connections */
928 curproxy->options |= PR_O_TRANSP;
929 }
930#endif
931 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
932 if (*(args[1]) == 0) {
933 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
934 return -1;
935 }
936 curproxy->maxconn = atol(args[1]);
937 }
938 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
939 if (*(args[1]) == 0) {
940 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
941 return -1;
942 }
943 curproxy->grace = atol(args[1]);
944 }
945 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
946 if (curproxy == &defproxy) {
947 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
948 return -1;
949 }
950 if (strchr(args[1], ':') == NULL) {
951 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
952 return -1;
953 }
954 curproxy->dispatch_addr = *str2sa(args[1]);
955 }
956 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
957 if (*(args[1])) {
958 if (!strcmp(args[1], "roundrobin")) {
959 curproxy->options |= PR_O_BALANCE_RR;
960 }
961 else if (!strcmp(args[1], "source")) {
962 curproxy->options |= PR_O_BALANCE_SH;
963 }
964 else {
965 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
966 return -1;
967 }
968 }
969 else /* if no option is set, use round-robin by default */
970 curproxy->options |= PR_O_BALANCE_RR;
971 }
972 else if (!strcmp(args[0], "server")) { /* server address */
973 int cur_arg;
974 char *rport;
975 char *raddr;
976 short realport;
977 int do_check;
978
979 if (curproxy == &defproxy) {
980 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
981 return -1;
982 }
983
984 if (!*args[2]) {
985 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
986 file, linenum, args[0]);
987 return -1;
988 }
989 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
990 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
991 return -1;
992 }
993
994 /* the servers are linked backwards first */
995 newsrv->next = curproxy->srv;
996 curproxy->srv = newsrv;
997 newsrv->proxy = curproxy;
998
999 LIST_INIT(&newsrv->pendconns);
1000 do_check = 0;
1001 newsrv->state = SRV_RUNNING; /* early server setup */
1002 newsrv->id = strdup(args[1]);
1003
1004 /* several ways to check the port component :
1005 * - IP => port=+0, relative
1006 * - IP: => port=+0, relative
1007 * - IP:N => port=N, absolute
1008 * - IP:+N => port=+N, relative
1009 * - IP:-N => port=-N, relative
1010 */
1011 raddr = strdup(args[2]);
1012 rport = strchr(raddr, ':');
1013 if (rport) {
1014 *rport++ = 0;
1015 realport = atol(rport);
1016 if (!isdigit((int)*rport))
1017 newsrv->state |= SRV_MAPPORTS;
1018 } else {
1019 realport = 0;
1020 newsrv->state |= SRV_MAPPORTS;
1021 }
1022
1023 newsrv->addr = *str2sa(raddr);
1024 newsrv->addr.sin_port = htons(realport);
1025 free(raddr);
1026
1027 newsrv->curfd = -1; /* no health-check in progress */
1028 newsrv->inter = DEF_CHKINTR;
1029 newsrv->rise = DEF_RISETIME;
1030 newsrv->fall = DEF_FALLTIME;
1031 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
1032 cur_arg = 3;
1033 while (*args[cur_arg]) {
1034 if (!strcmp(args[cur_arg], "cookie")) {
1035 newsrv->cookie = strdup(args[cur_arg + 1]);
1036 newsrv->cklen = strlen(args[cur_arg + 1]);
1037 cur_arg += 2;
1038 }
1039 else if (!strcmp(args[cur_arg], "rise")) {
1040 newsrv->rise = atol(args[cur_arg + 1]);
1041 newsrv->health = newsrv->rise;
1042 cur_arg += 2;
1043 }
1044 else if (!strcmp(args[cur_arg], "fall")) {
1045 newsrv->fall = atol(args[cur_arg + 1]);
1046 cur_arg += 2;
1047 }
1048 else if (!strcmp(args[cur_arg], "inter")) {
1049 newsrv->inter = atol(args[cur_arg + 1]);
1050 cur_arg += 2;
1051 }
1052 else if (!strcmp(args[cur_arg], "port")) {
1053 newsrv->check_port = atol(args[cur_arg + 1]);
1054 cur_arg += 2;
1055 }
1056 else if (!strcmp(args[cur_arg], "backup")) {
1057 newsrv->state |= SRV_BACKUP;
1058 cur_arg ++;
1059 }
1060 else if (!strcmp(args[cur_arg], "weight")) {
1061 int w;
1062 w = atol(args[cur_arg + 1]);
1063 if (w < 1 || w > 256) {
1064 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
1065 file, linenum, newsrv->id, w);
1066 return -1;
1067 }
1068 newsrv->uweight = w - 1;
1069 cur_arg += 2;
1070 }
1071 else if (!strcmp(args[cur_arg], "minconn")) {
1072 newsrv->minconn = atol(args[cur_arg + 1]);
1073 cur_arg += 2;
1074 }
1075 else if (!strcmp(args[cur_arg], "maxconn")) {
1076 newsrv->maxconn = atol(args[cur_arg + 1]);
1077 cur_arg += 2;
1078 }
1079 else if (!strcmp(args[cur_arg], "check")) {
1080 global.maxsock++;
1081 do_check = 1;
1082 cur_arg += 1;
1083 }
1084 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
1085 if (!*args[cur_arg + 1]) {
1086 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
1087 file, linenum, "source");
1088 return -1;
1089 }
1090 newsrv->state |= SRV_BIND_SRC;
1091 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
1092 cur_arg += 2;
1093 }
1094 else {
1095 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port', 'source', 'minconn', 'maxconn' and 'weight'.\n",
1096 file, linenum, newsrv->id);
1097 return -1;
1098 }
1099 }
1100
1101 if (do_check) {
1102 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
1103 newsrv->check_port = realport; /* by default */
1104 if (!newsrv->check_port) {
1105 Alert("parsing [%s:%d] : server %s has neither service port nor check port. Check has been disabled.\n",
1106 file, linenum, newsrv->id);
1107 return -1;
1108 }
1109 newsrv->state |= SRV_CHECKED;
1110 }
1111
1112 if (newsrv->state & SRV_BACKUP)
1113 curproxy->srv_bck++;
1114 else
1115 curproxy->srv_act++;
1116 }
1117 else if (!strcmp(args[0], "log")) { /* syslog server address */
1118 struct sockaddr_in *sa;
1119 int facility;
1120
1121 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
1122 curproxy->logfac1 = global.logfac1;
1123 curproxy->logsrv1 = global.logsrv1;
1124 curproxy->loglev1 = global.loglev1;
1125 curproxy->logfac2 = global.logfac2;
1126 curproxy->logsrv2 = global.logsrv2;
1127 curproxy->loglev2 = global.loglev2;
1128 }
1129 else if (*(args[1]) && *(args[2])) {
1130 int level;
1131
1132 facility = get_log_facility(args[2]);
1133 if (facility < 0) {
1134 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
1135 exit(1);
1136 }
1137
1138 level = 7; /* max syslog level = debug */
1139 if (*(args[3])) {
1140 level = get_log_level(args[3]);
1141 if (level < 0) {
1142 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
1143 exit(1);
1144 }
1145 }
1146
1147 sa = str2sa(args[1]);
1148 if (!sa->sin_port)
1149 sa->sin_port = htons(SYSLOG_PORT);
1150
1151 if (curproxy->logfac1 == -1) {
1152 curproxy->logsrv1 = *sa;
1153 curproxy->logfac1 = facility;
1154 curproxy->loglev1 = level;
1155 }
1156 else if (curproxy->logfac2 == -1) {
1157 curproxy->logsrv2 = *sa;
1158 curproxy->logfac2 = facility;
1159 curproxy->loglev2 = level;
1160 }
1161 else {
1162 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
1163 return -1;
1164 }
1165 }
1166 else {
1167 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
1168 file, linenum);
1169 return -1;
1170 }
1171 }
1172 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
1173 if (!*args[1]) {
1174 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
1175 file, linenum, "source");
1176 return -1;
1177 }
1178
1179 curproxy->source_addr = *str2sa(args[1]);
1180 curproxy->options |= PR_O_BIND_SRC;
1181 }
1182 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
1183 regex_t *preg;
1184 if (curproxy == &defproxy) {
1185 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1186 return -1;
1187 }
1188
1189 if (*(args[1]) == 0 || *(args[2]) == 0) {
1190 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
1191 file, linenum, args[0]);
1192 return -1;
1193 }
1194
1195 preg = calloc(1, sizeof(regex_t));
1196 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1197 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1198 return -1;
1199 }
1200
1201 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
1202 if (err) {
1203 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1204 file, linenum, *err);
1205 return -1;
1206 }
1207 }
1208 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
1209 regex_t *preg;
1210 if (curproxy == &defproxy) {
1211 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1212 return -1;
1213 }
1214
1215 if (*(args[1]) == 0) {
1216 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1217 return -1;
1218 }
1219
1220 preg = calloc(1, sizeof(regex_t));
1221 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1222 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1223 return -1;
1224 }
1225
1226 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
1227 }
1228 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
1229 regex_t *preg;
1230 if (curproxy == &defproxy) {
1231 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1232 return -1;
1233 }
1234
1235 if (*(args[1]) == 0) {
1236 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1237 return -1;
1238 }
1239
1240 preg = calloc(1, sizeof(regex_t));
1241 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1242 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1243 return -1;
1244 }
1245
1246 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
1247 }
1248 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
1249 regex_t *preg;
1250 if (curproxy == &defproxy) {
1251 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1252 return -1;
1253 }
1254
1255 if (*(args[1]) == 0) {
1256 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1257 return -1;
1258 }
1259
1260 preg = calloc(1, sizeof(regex_t));
1261 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1262 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1263 return -1;
1264 }
1265
1266 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
1267 }
1268 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
1269 regex_t *preg;
1270 if (curproxy == &defproxy) {
1271 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1272 return -1;
1273 }
1274
1275 if (*(args[1]) == 0) {
1276 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1277 return -1;
1278 }
1279
1280 preg = calloc(1, sizeof(regex_t));
1281 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1282 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1283 return -1;
1284 }
1285
1286 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
1287 }
1288 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
1289 regex_t *preg;
1290 if (curproxy == &defproxy) {
1291 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1292 return -1;
1293 }
1294
1295 if (*(args[1]) == 0 || *(args[2]) == 0) {
1296 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
1297 file, linenum, args[0]);
1298 return -1;
1299 }
1300
1301 preg = calloc(1, sizeof(regex_t));
1302 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1303 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1304 return -1;
1305 }
1306
1307 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
1308 if (err) {
1309 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1310 file, linenum, *err);
1311 return -1;
1312 }
1313 }
1314 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
1315 regex_t *preg;
1316 if (curproxy == &defproxy) {
1317 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1318 return -1;
1319 }
1320
1321 if (*(args[1]) == 0) {
1322 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1323 return -1;
1324 }
1325
1326 preg = calloc(1, sizeof(regex_t));
1327 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1328 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1329 return -1;
1330 }
1331
1332 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
1333 }
1334 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
1335 regex_t *preg;
1336 if (curproxy == &defproxy) {
1337 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1338 return -1;
1339 }
1340
1341 if (*(args[1]) == 0) {
1342 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1343 return -1;
1344 }
1345
1346 preg = calloc(1, sizeof(regex_t));
1347 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1348 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1349 return -1;
1350 }
1351
1352 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
1353 }
1354 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
1355 regex_t *preg;
1356 if (curproxy == &defproxy) {
1357 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1358 return -1;
1359 }
1360
1361 if (*(args[1]) == 0) {
1362 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1363 return -1;
1364 }
1365
1366 preg = calloc(1, sizeof(regex_t));
1367 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1368 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1369 return -1;
1370 }
1371
1372 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
1373 }
1374 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
1375 regex_t *preg;
1376 if (curproxy == &defproxy) {
1377 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1378 return -1;
1379 }
1380
1381 if (*(args[1]) == 0) {
1382 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
1383 return -1;
1384 }
1385
1386 preg = calloc(1, sizeof(regex_t));
1387 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1388 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1389 return -1;
1390 }
1391
1392 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
1393 }
1394 else if (!strcmp(args[0], "reqadd")) { /* add request header */
1395 if (curproxy == &defproxy) {
1396 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1397 return -1;
1398 }
1399
1400 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
1401 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
1402 return 0;
1403 }
1404
1405 if (*(args[1]) == 0) {
1406 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
1407 return -1;
1408 }
1409
1410 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
1411 }
1412 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
1413 regex_t *preg;
1414
1415 if (*(args[1]) == 0 || *(args[2]) == 0) {
1416 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
1417 file, linenum, args[0]);
1418 return -1;
1419 }
1420
1421 preg = calloc(1, sizeof(regex_t));
1422 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1423 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1424 return -1;
1425 }
1426
1427 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
1428 if (err) {
1429 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1430 file, linenum, *err);
1431 return -1;
1432 }
1433 }
1434 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
1435 regex_t *preg;
1436 if (curproxy == &defproxy) {
1437 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1438 return -1;
1439 }
1440
1441 if (*(args[1]) == 0) {
1442 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
1443 return -1;
1444 }
1445
1446 preg = calloc(1, sizeof(regex_t));
1447 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1448 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1449 return -1;
1450 }
1451
1452 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
1453 if (err) {
1454 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1455 file, linenum, *err);
1456 return -1;
1457 }
1458 }
1459 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
1460 regex_t *preg;
1461 if (curproxy == &defproxy) {
1462 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1463 return -1;
1464 }
1465
1466 if (*(args[1]) == 0) {
1467 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
1468 return -1;
1469 }
1470
1471 preg = calloc(1, sizeof(regex_t));
1472 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
1473 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1474 return -1;
1475 }
1476
1477 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
1478 if (err) {
1479 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1480 file, linenum, *err);
1481 return -1;
1482 }
1483 }
1484 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
1485 regex_t *preg;
1486 if (curproxy == &defproxy) {
1487 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1488 return -1;
1489 }
1490
1491 if (*(args[1]) == 0 || *(args[2]) == 0) {
1492 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
1493 file, linenum, args[0]);
1494 return -1;
1495 }
1496
1497 preg = calloc(1, sizeof(regex_t));
1498 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1499 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1500 return -1;
1501 }
1502
1503 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
1504 if (err) {
1505 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1506 file, linenum, *err);
1507 return -1;
1508 }
1509 }
1510 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
1511 regex_t *preg;
1512 if (curproxy == &defproxy) {
1513 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1514 return -1;
1515 }
1516
1517 if (*(args[1]) == 0) {
1518 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
1519 return -1;
1520 }
1521
1522 preg = calloc(1, sizeof(regex_t));
1523 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1524 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1525 return -1;
1526 }
1527
1528 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
1529 if (err) {
1530 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1531 file, linenum, *err);
1532 return -1;
1533 }
1534 }
1535 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
1536 regex_t *preg;
1537 if (curproxy == &defproxy) {
1538 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1539 return -1;
1540 }
1541
1542 if (*(args[1]) == 0) {
1543 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
1544 return -1;
1545 }
1546
1547 preg = calloc(1, sizeof(regex_t));
1548 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
1549 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
1550 return -1;
1551 }
1552
1553 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
1554 if (err) {
1555 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
1556 file, linenum, *err);
1557 return -1;
1558 }
1559 }
1560 else if (!strcmp(args[0], "rspadd")) { /* add response header */
1561 if (curproxy == &defproxy) {
1562 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1563 return -1;
1564 }
1565
1566 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
1567 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
1568 return 0;
1569 }
1570
1571 if (*(args[1]) == 0) {
1572 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
1573 return -1;
1574 }
1575
1576 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
1577 }
1578 else if (!strcmp(args[0], "errorloc") ||
1579 !strcmp(args[0], "errorloc302") ||
1580 !strcmp(args[0], "errorloc303")) { /* error location */
1581 int errnum, errlen;
1582 char *err;
1583
1584 // if (curproxy == &defproxy) {
1585 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1586 // return -1;
1587 // }
1588
1589 if (*(args[2]) == 0) {
1590 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
1591 return -1;
1592 }
1593
1594 errnum = atol(args[1]);
1595 if (!strcmp(args[0], "errorloc303")) {
1596 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
1597 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
1598 } else {
1599 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
1600 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
1601 }
1602
1603 if (errnum == 400) {
1604 if (curproxy->errmsg.msg400) {
1605 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
1606 free(curproxy->errmsg.msg400);
1607 }
1608 curproxy->errmsg.msg400 = err;
1609 curproxy->errmsg.len400 = errlen;
1610 }
1611 else if (errnum == 403) {
1612 if (curproxy->errmsg.msg403) {
1613 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
1614 free(curproxy->errmsg.msg403);
1615 }
1616 curproxy->errmsg.msg403 = err;
1617 curproxy->errmsg.len403 = errlen;
1618 }
1619 else if (errnum == 408) {
1620 if (curproxy->errmsg.msg408) {
1621 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
1622 free(curproxy->errmsg.msg408);
1623 }
1624 curproxy->errmsg.msg408 = err;
1625 curproxy->errmsg.len408 = errlen;
1626 }
1627 else if (errnum == 500) {
1628 if (curproxy->errmsg.msg500) {
1629 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
1630 free(curproxy->errmsg.msg500);
1631 }
1632 curproxy->errmsg.msg500 = err;
1633 curproxy->errmsg.len500 = errlen;
1634 }
1635 else if (errnum == 502) {
1636 if (curproxy->errmsg.msg502) {
1637 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
1638 free(curproxy->errmsg.msg502);
1639 }
1640 curproxy->errmsg.msg502 = err;
1641 curproxy->errmsg.len502 = errlen;
1642 }
1643 else if (errnum == 503) {
1644 if (curproxy->errmsg.msg503) {
1645 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
1646 free(curproxy->errmsg.msg503);
1647 }
1648 curproxy->errmsg.msg503 = err;
1649 curproxy->errmsg.len503 = errlen;
1650 }
1651 else if (errnum == 504) {
1652 if (curproxy->errmsg.msg504) {
1653 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
1654 free(curproxy->errmsg.msg504);
1655 }
1656 curproxy->errmsg.msg504 = err;
1657 curproxy->errmsg.len504 = errlen;
1658 }
1659 else {
1660 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
1661 free(err);
1662 }
1663 }
1664 else {
1665 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
1666 return -1;
1667 }
1668 return 0;
1669}
1670
1671
1672/*
1673 * This function reads and parses the configuration file given in the argument.
1674 * returns 0 if OK, -1 if error.
1675 */
1676int readcfgfile(char *file)
1677{
1678 char thisline[256];
1679 char *line;
1680 FILE *f;
1681 int linenum = 0;
1682 char *end;
1683 char *args[MAX_LINE_ARGS];
1684 int arg;
1685 int cfgerr = 0;
1686 int nbchk, mininter;
1687 int confsect = CFG_NONE;
1688
1689 struct proxy *curproxy = NULL;
1690 struct server *newsrv = NULL;
1691
1692 if ((f=fopen(file,"r")) == NULL)
1693 return -1;
1694
1695 init_default_instance();
1696
1697 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
1698 linenum++;
1699
1700 end = line + strlen(line);
1701
1702 /* skip leading spaces */
1703 while (isspace((int)*line))
1704 line++;
1705
1706 arg = 0;
1707 args[arg] = line;
1708
1709 while (*line && arg < MAX_LINE_ARGS) {
1710 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
1711 * C equivalent value. Other combinations left unchanged (eg: \1).
1712 */
1713 if (*line == '\\') {
1714 int skip = 0;
1715 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
1716 *line = line[1];
1717 skip = 1;
1718 }
1719 else if (line[1] == 'r') {
1720 *line = '\r';
1721 skip = 1;
1722 }
1723 else if (line[1] == 'n') {
1724 *line = '\n';
1725 skip = 1;
1726 }
1727 else if (line[1] == 't') {
1728 *line = '\t';
1729 skip = 1;
1730 }
1731 else if (line[1] == 'x') {
1732 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
1733 unsigned char hex1, hex2;
1734 hex1 = toupper(line[2]) - '0';
1735 hex2 = toupper(line[3]) - '0';
1736 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
1737 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
1738 *line = (hex1<<4) + hex2;
1739 skip = 3;
1740 }
1741 else {
1742 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
1743 return -1;
1744 }
1745 }
1746 if (skip) {
1747 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
1748 end -= skip;
1749 }
1750 line++;
1751 }
1752 else if (*line == '#' || *line == '\n' || *line == '\r') {
1753 /* end of string, end of loop */
1754 *line = 0;
1755 break;
1756 }
1757 else if (isspace((int)*line)) {
1758 /* a non-escaped space is an argument separator */
1759 *line++ = 0;
1760 while (isspace((int)*line))
1761 line++;
1762 args[++arg] = line;
1763 }
1764 else {
1765 line++;
1766 }
1767 }
1768
1769 /* empty line */
1770 if (!**args)
1771 continue;
1772
1773 /* zero out remaining args */
1774 while (++arg < MAX_LINE_ARGS) {
1775 args[arg] = line;
1776 }
1777
1778 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
1779 confsect = CFG_LISTEN;
1780 else if (!strcmp(args[0], "global")) /* global config */
1781 confsect = CFG_GLOBAL;
1782 /* else it's a section keyword */
1783
1784 switch (confsect) {
1785 case CFG_LISTEN:
1786 if (cfg_parse_listen(file, linenum, args) < 0)
1787 return -1;
1788 break;
1789 case CFG_GLOBAL:
1790 if (cfg_parse_global(file, linenum, args) < 0)
1791 return -1;
1792 break;
1793 default:
1794 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
1795 return -1;
1796 }
1797
1798
1799 }
1800 fclose(f);
1801
1802 /*
1803 * Now, check for the integrity of all that we have collected.
1804 */
1805
1806 /* will be needed further to delay some tasks */
1807 tv_now(&now);
1808
1809 if ((curproxy = proxy) == NULL) {
1810 Alert("parsing %s : no <listen> line. Nothing to do !\n",
1811 file);
1812 return -1;
1813 }
1814
1815 while (curproxy != NULL) {
1816 if (curproxy->state == PR_STSTOPPED) {
1817 curproxy = curproxy->next;
1818 continue;
1819 }
1820
1821 if (curproxy->listen == NULL) {
1822 Alert("parsing %s : listener %s has no listen address. Please either specify a valid address on the <listen> line, or use the <bind> keyword.\n", file, curproxy->id);
1823 cfgerr++;
1824 }
1825 else if ((curproxy->mode != PR_MODE_HEALTH) &&
1826 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
1827 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
1828 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
1829 file, curproxy->id);
1830 cfgerr++;
1831 }
1832 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
1833 if (curproxy->options & PR_O_TRANSP) {
1834 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
1835 file, curproxy->id);
1836 cfgerr++;
1837 }
1838#ifdef WE_DONT_SUPPORT_SERVERLESS_LISTENERS
1839 else if (curproxy->srv == NULL) {
1840 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
1841 file, curproxy->id);
1842 cfgerr++;
1843 }
1844#endif
1845 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
1846 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
1847 file, curproxy->id);
1848 }
1849 }
1850 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
1851 if (curproxy->cookie_name != NULL) {
1852 Warning("parsing %s : cookie will be ignored for listener %s.\n",
1853 file, curproxy->id);
1854 }
1855 if ((newsrv = curproxy->srv) != NULL) {
1856 Warning("parsing %s : servers will be ignored for listener %s.\n",
1857 file, curproxy->id);
1858 }
1859 if (curproxy->rsp_exp != NULL) {
1860 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
1861 file, curproxy->id);
1862 }
1863 if (curproxy->req_exp != NULL) {
1864 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
1865 file, curproxy->id);
1866 }
1867 }
1868 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
1869 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
1870 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
1871 file, curproxy->id);
1872 cfgerr++;
1873 }
1874 }
1875
Willy Tarreau2738a142006-07-08 17:28:09 +02001876 if ((curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HTTP) &&
1877 (!curproxy->clitimeout || !curproxy->contimeout || !curproxy->srvtimeout)) {
1878 Warning("parsing %s : missing timeouts for listener '%s'.\n"
1879 " | While not properly invalid, you will certainly encounter various problems\n"
1880 " | with such a configuration. To fix this, please ensure that all following\n"
1881 " | values are set to a non-zero value: clitimeout, contimeout, srvtimeout.\n",
1882 file, curproxy->id);
1883 }
1884
Willy Tarreaubaaee002006-06-26 02:48:02 +02001885 /* first, we will invert the servers list order */
1886 newsrv = NULL;
1887 while (curproxy->srv) {
1888 struct server *next;
1889
1890 next = curproxy->srv->next;
1891 curproxy->srv->next = newsrv;
1892 newsrv = curproxy->srv;
1893 if (!next)
1894 break;
1895 curproxy->srv = next;
1896 }
1897
1898 /* now, newsrv == curproxy->srv */
1899 if (newsrv) {
1900 struct server *srv;
1901 int pgcd;
1902 int act, bck;
1903
1904 /* We will factor the weights to reduce the table,
1905 * using Euclide's largest common divisor algorithm
1906 */
1907 pgcd = newsrv->uweight + 1;
1908 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
1909 int t, w;
1910
1911 w = srv->uweight + 1;
1912 while (w) {
1913 t = pgcd % w;
1914 pgcd = w;
1915 w = t;
1916 }
1917 }
1918
1919 act = bck = 0;
1920 for (srv = newsrv; srv; srv = srv->next) {
1921 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
1922 if (srv->state & SRV_BACKUP)
1923 bck += srv->eweight + 1;
1924 else
1925 act += srv->eweight + 1;
1926 }
1927
1928 /* this is the largest map we will ever need for this servers list */
1929 if (act < bck)
1930 act = bck;
1931
1932 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
1933 /* recounts servers and their weights */
1934 recount_servers(curproxy);
1935 recalc_server_map(curproxy);
1936 }
1937
1938 if (curproxy->options & PR_O_LOGASAP)
1939 curproxy->to_log &= ~LW_BYTES;
1940
1941 if (curproxy->errmsg.msg400 == NULL) {
1942 curproxy->errmsg.msg400 = (char *)HTTP_400;
1943 curproxy->errmsg.len400 = strlen(HTTP_400);
1944 }
1945 if (curproxy->errmsg.msg403 == NULL) {
1946 curproxy->errmsg.msg403 = (char *)HTTP_403;
1947 curproxy->errmsg.len403 = strlen(HTTP_403);
1948 }
1949 if (curproxy->errmsg.msg408 == NULL) {
1950 curproxy->errmsg.msg408 = (char *)HTTP_408;
1951 curproxy->errmsg.len408 = strlen(HTTP_408);
1952 }
1953 if (curproxy->errmsg.msg500 == NULL) {
1954 curproxy->errmsg.msg500 = (char *)HTTP_500;
1955 curproxy->errmsg.len500 = strlen(HTTP_500);
1956 }
1957 if (curproxy->errmsg.msg502 == NULL) {
1958 curproxy->errmsg.msg502 = (char *)HTTP_502;
1959 curproxy->errmsg.len502 = strlen(HTTP_502);
1960 }
1961 if (curproxy->errmsg.msg503 == NULL) {
1962 curproxy->errmsg.msg503 = (char *)HTTP_503;
1963 curproxy->errmsg.len503 = strlen(HTTP_503);
1964 }
1965 if (curproxy->errmsg.msg504 == NULL) {
1966 curproxy->errmsg.msg504 = (char *)HTTP_504;
1967 curproxy->errmsg.len504 = strlen(HTTP_504);
1968 }
1969
1970 /*
1971 * If this server supports a maxconn parameter, it needs a dedicated
1972 * tasks to fill the emptied slots when a connection leaves.
1973 */
1974 newsrv = curproxy->srv;
1975 while (newsrv != NULL) {
1976 if (newsrv->minconn >= newsrv->maxconn) {
1977 /* Only 'minconn' was specified, or it was higher than or equal
1978 * to 'maxconn'. Let's turn this into maxconn and clean it, as
1979 * this will avoid further useless expensive computations.
1980 */
1981 newsrv->maxconn = newsrv->minconn;
1982 newsrv->minconn = 0;
1983 }
1984
1985 if (newsrv->maxconn > 0) {
1986 struct task *t;
1987
1988 if ((t = pool_alloc(task)) == NULL) {
1989 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1990 return -1;
1991 }
1992
1993 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1994 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
1995 t->state = TASK_IDLE;
1996 t->process = process_srv_queue;
1997 t->context = newsrv;
1998 newsrv->queue_mgt = t;
1999
2000 /* never run it unless specifically woken up */
2001 tv_eternity(&t->expire);
2002 task_queue(t);
2003 }
2004 newsrv = newsrv->next;
2005 }
2006
2007 /* now we'll start this proxy's health checks if any */
2008 /* 1- count the checkers to run simultaneously */
2009 nbchk = 0;
2010 mininter = 0;
2011 newsrv = curproxy->srv;
2012 while (newsrv != NULL) {
2013 if (newsrv->state & SRV_CHECKED) {
2014 if (!mininter || mininter > newsrv->inter)
2015 mininter = newsrv->inter;
2016 nbchk++;
2017 }
2018 newsrv = newsrv->next;
2019 }
2020
2021 /* 2- start them as far as possible from each others while respecting
2022 * their own intervals. For this, we will start them after their own
2023 * interval added to the min interval divided by the number of servers,
2024 * weighted by the server's position in the list.
2025 */
2026 if (nbchk > 0) {
2027 struct task *t;
2028 int srvpos;
2029
2030 newsrv = curproxy->srv;
2031 srvpos = 0;
2032 while (newsrv != NULL) {
2033 /* should this server be checked ? */
2034 if (newsrv->state & SRV_CHECKED) {
2035 if ((t = pool_alloc(task)) == NULL) {
2036 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2037 return -1;
2038 }
2039
2040 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2041 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
2042 t->state = TASK_IDLE;
2043 t->process = process_chk;
2044 t->context = newsrv;
2045
2046 /* check this every ms */
2047 tv_delayfrom(&t->expire, &now,
2048 newsrv->inter + mininter * srvpos / nbchk);
2049 task_queue(t);
2050 //task_wakeup(&rq, t);
2051 srvpos++;
2052 }
2053 newsrv = newsrv->next;
2054 }
2055 }
2056
2057 curproxy = curproxy->next;
2058 }
2059 if (cfgerr > 0) {
2060 Alert("Errors found in configuration file, aborting.\n");
2061 return -1;
2062 }
2063 else
2064 return 0;
2065}
2066
2067
2068
2069/*
2070 * Local variables:
2071 * c-indent-level: 8
2072 * c-basic-offset: 8
2073 * End:
2074 */