blob: aa082be75e84c12b402a955f1031e5ea9f68844f [file] [log] [blame]
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <netdb.h>
5#include <ctype.h>
6#include <pwd.h>
7#include <grp.h>
8#include <errno.h>
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <fcntl.h>
12#include <unistd.h>
13
14#include <common/cfgparse.h>
15#include <common/uri_auth.h>
16
17#include <types/capture.h>
18#include <types/compression.h>
19
20#include <proto/acl.h>
21#include <proto/checks.h>
22#include <proto/connection.h>
23#include <proto/http_rules.h>
24#include <proto/listener.h>
25#include <proto/protocol.h>
26#include <proto/proxy.h>
27#include <proto/server.h>
28
29/* Report a warning if a rule is placed after a 'tcp-request session' rule.
30 * Return 1 if the warning has been emitted, otherwise 0.
31 */
32int warnif_rule_after_tcp_sess(struct proxy *proxy, const char *file, int line, const char *arg)
33{
34 if (!LIST_ISEMPTY(&proxy->tcp_req.l5_rules)) {
35 ha_warning("parsing [%s:%d] : a '%s' rule placed after a 'tcp-request session' rule will still be processed before.\n",
36 file, line, arg);
37 return 1;
38 }
39 return 0;
40}
41
42/* Report a warning if a rule is placed after a 'tcp-request content' rule.
43 * Return 1 if the warning has been emitted, otherwise 0.
44 */
45int warnif_rule_after_tcp_cont(struct proxy *proxy, const char *file, int line, const char *arg)
46{
47 if (!LIST_ISEMPTY(&proxy->tcp_req.inspect_rules)) {
48 ha_warning("parsing [%s:%d] : a '%s' rule placed after a 'tcp-request content' rule will still be processed before.\n",
49 file, line, arg);
50 return 1;
51 }
52 return 0;
53}
54
55/* Report a warning if a rule is placed after a 'monitor fail' rule.
56 * Return 1 if the warning has been emitted, otherwise 0.
57 */
58int warnif_rule_after_monitor(struct proxy *proxy, const char *file, int line, const char *arg)
59{
60 if (!LIST_ISEMPTY(&proxy->mon_fail_cond)) {
61 ha_warning("parsing [%s:%d] : a '%s' rule placed after a 'monitor fail' rule will still be processed before.\n",
62 file, line, arg);
63 return 1;
64 }
65 return 0;
66}
67
68/* Report a warning if a rule is placed after a 'block' rule.
69 * Return 1 if the warning has been emitted, otherwise 0.
70 */
71int warnif_rule_after_block(struct proxy *proxy, const char *file, int line, const char *arg)
72{
73 if (!LIST_ISEMPTY(&proxy->block_rules)) {
74 ha_warning("parsing [%s:%d] : a '%s' rule placed after a 'block' rule will still be processed before.\n",
75 file, line, arg);
76 return 1;
77 }
78 return 0;
79}
80
81/* Report a warning if a rule is placed after an 'http_request' rule.
82 * Return 1 if the warning has been emitted, otherwise 0.
83 */
84int warnif_rule_after_http_req(struct proxy *proxy, const char *file, int line, const char *arg)
85{
86 if (!LIST_ISEMPTY(&proxy->http_req_rules)) {
87 ha_warning("parsing [%s:%d] : a '%s' rule placed after an 'http-request' rule will still be processed before.\n",
88 file, line, arg);
89 return 1;
90 }
91 return 0;
92}
93
94/* Report a warning if a rule is placed after a reqrewrite rule.
95 * Return 1 if the warning has been emitted, otherwise 0.
96 */
97int warnif_rule_after_reqxxx(struct proxy *proxy, const char *file, int line, const char *arg)
98{
99 if (proxy->req_exp) {
100 ha_warning("parsing [%s:%d] : a '%s' rule placed after a 'reqxxx' rule will still be processed before.\n",
101 file, line, arg);
102 return 1;
103 }
104 return 0;
105}
106
107/* Report a warning if a rule is placed after a reqadd rule.
108 * Return 1 if the warning has been emitted, otherwise 0.
109 */
110int warnif_rule_after_reqadd(struct proxy *proxy, const char *file, int line, const char *arg)
111{
112 if (!LIST_ISEMPTY(&proxy->req_add)) {
113 ha_warning("parsing [%s:%d] : a '%s' rule placed after a 'reqadd' rule will still be processed before.\n",
114 file, line, arg);
115 return 1;
116 }
117 return 0;
118}
119
120/* Report a warning if a rule is placed after a redirect rule.
121 * Return 1 if the warning has been emitted, otherwise 0.
122 */
123int warnif_rule_after_redirect(struct proxy *proxy, const char *file, int line, const char *arg)
124{
125 if (!LIST_ISEMPTY(&proxy->redirect_rules)) {
126 ha_warning("parsing [%s:%d] : a '%s' rule placed after a 'redirect' rule will still be processed before.\n",
127 file, line, arg);
128 return 1;
129 }
130 return 0;
131}
132
133/* Report a warning if a rule is placed after a 'use_backend' rule.
134 * Return 1 if the warning has been emitted, otherwise 0.
135 */
136int warnif_rule_after_use_backend(struct proxy *proxy, const char *file, int line, const char *arg)
137{
138 if (!LIST_ISEMPTY(&proxy->switching_rules)) {
139 ha_warning("parsing [%s:%d] : a '%s' rule placed after a 'use_backend' rule will still be processed before.\n",
140 file, line, arg);
141 return 1;
142 }
143 return 0;
144}
145
146/* Report a warning if a rule is placed after a 'use-server' rule.
147 * Return 1 if the warning has been emitted, otherwise 0.
148 */
149int warnif_rule_after_use_server(struct proxy *proxy, const char *file, int line, const char *arg)
150{
151 if (!LIST_ISEMPTY(&proxy->server_rules)) {
152 ha_warning("parsing [%s:%d] : a '%s' rule placed after a 'use-server' rule will still be processed before.\n",
153 file, line, arg);
154 return 1;
155 }
156 return 0;
157}
158
159/* report a warning if a redirect rule is dangerously placed */
160int warnif_misplaced_redirect(struct proxy *proxy, const char *file, int line, const char *arg)
161{
162 return warnif_rule_after_use_backend(proxy, file, line, arg) ||
163 warnif_rule_after_use_server(proxy, file, line, arg);
164}
165
166/* report a warning if a reqadd rule is dangerously placed */
167int warnif_misplaced_reqadd(struct proxy *proxy, const char *file, int line, const char *arg)
168{
169 return warnif_rule_after_redirect(proxy, file, line, arg) ||
170 warnif_misplaced_redirect(proxy, file, line, arg);
171}
172
173/* report a warning if a reqxxx rule is dangerously placed */
174int warnif_misplaced_reqxxx(struct proxy *proxy, const char *file, int line, const char *arg)
175{
176 return warnif_rule_after_reqadd(proxy, file, line, arg) ||
177 warnif_misplaced_reqadd(proxy, file, line, arg);
178}
179
180/* report a warning if an http-request rule is dangerously placed */
181int warnif_misplaced_http_req(struct proxy *proxy, const char *file, int line, const char *arg)
182{
183 return warnif_rule_after_reqxxx(proxy, file, line, arg) ||
184 warnif_misplaced_reqxxx(proxy, file, line, arg);;
185}
186
187/* report a warning if a block rule is dangerously placed */
188int warnif_misplaced_block(struct proxy *proxy, const char *file, int line, const char *arg)
189{
190 return warnif_rule_after_http_req(proxy, file, line, arg) ||
191 warnif_misplaced_http_req(proxy, file, line, arg);
192}
193
194/* report a warning if a block rule is dangerously placed */
195int warnif_misplaced_monitor(struct proxy *proxy, const char *file, int line, const char *arg)
196{
197 return warnif_rule_after_block(proxy, file, line, arg) ||
198 warnif_misplaced_block(proxy, file, line, arg);
199}
200
201/* report a warning if a "tcp request content" rule is dangerously placed */
202int warnif_misplaced_tcp_cont(struct proxy *proxy, const char *file, int line, const char *arg)
203{
204 return warnif_rule_after_monitor(proxy, file, line, arg) ||
205 warnif_misplaced_monitor(proxy, file, line, arg);
206}
207
208/* report a warning if a "tcp request session" rule is dangerously placed */
209int warnif_misplaced_tcp_sess(struct proxy *proxy, const char *file, int line, const char *arg)
210{
211 return warnif_rule_after_tcp_cont(proxy, file, line, arg) ||
212 warnif_misplaced_tcp_cont(proxy, file, line, arg);
213}
214
215/* report a warning if a "tcp request connection" rule is dangerously placed */
216int warnif_misplaced_tcp_conn(struct proxy *proxy, const char *file, int line, const char *arg)
217{
218 return warnif_rule_after_tcp_sess(proxy, file, line, arg) ||
219 warnif_misplaced_tcp_sess(proxy, file, line, arg);
220}
221
222/* This function createss a new req* or rsp* rule to the proxy. It compiles the
223 * regex and may return the ERR_WARN bit, and error bits such as ERR_ALERT and
224 * ERR_FATAL in case of error.
225 */
226static int create_cond_regex_rule(const char *file, int line,
227 struct proxy *px, int dir, int action, int flags,
228 const char *cmd, const char *reg, const char *repl,
229 const char **cond_start)
230{
231 struct my_regex *preg = NULL;
232 char *errmsg = NULL;
233 const char *err;
234 char *error;
235 int ret_code = 0;
236 struct acl_cond *cond = NULL;
237 int cs;
238 int cap;
239
240 if (px == &defproxy) {
241 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, line, cmd);
242 ret_code |= ERR_ALERT | ERR_FATAL;
243 goto err;
244 }
245
246 if (*reg == 0) {
247 ha_alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, line, cmd);
248 ret_code |= ERR_ALERT | ERR_FATAL;
249 goto err;
250 }
251
252 if (warnifnotcap(px, PR_CAP_FE | PR_CAP_BE, file, line, cmd, NULL))
253 ret_code |= ERR_WARN;
254
255 if (cond_start &&
256 (strcmp(*cond_start, "if") == 0 || strcmp(*cond_start, "unless") == 0)) {
257 if ((cond = build_acl_cond(file, line, &px->acl, px, cond_start, &errmsg)) == NULL) {
258 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
259 file, line, cmd, errmsg);
260 ret_code |= ERR_ALERT | ERR_FATAL;
261 goto err;
262 }
263 }
264 else if (cond_start && **cond_start) {
265 ha_alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
266 file, line, cmd, *cond_start);
267 ret_code |= ERR_ALERT | ERR_FATAL;
268 goto err;
269 }
270
271 ret_code |= warnif_cond_conflicts(cond,
272 (dir == SMP_OPT_DIR_REQ) ?
273 ((px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR) :
274 ((px->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR),
275 file, line);
276
277 preg = calloc(1, sizeof(*preg));
278 if (!preg) {
279 ha_alert("parsing [%s:%d] : '%s' : not enough memory to build regex.\n", file, line, cmd);
280 ret_code = ERR_ALERT | ERR_FATAL;
281 goto err;
282 }
283
284 cs = !(flags & REG_ICASE);
285 cap = !(flags & REG_NOSUB);
286 error = NULL;
287 if (!regex_comp(reg, preg, cs, cap, &error)) {
288 ha_alert("parsing [%s:%d] : '%s' : regular expression '%s' : %s\n", file, line, cmd, reg, error);
289 free(error);
290 ret_code = ERR_ALERT | ERR_FATAL;
291 goto err;
292 }
293
294 err = chain_regex((dir == SMP_OPT_DIR_REQ) ? &px->req_exp : &px->rsp_exp,
295 preg, action, repl ? strdup(repl) : NULL, cond);
296 if (repl && err) {
297 ha_alert("parsing [%s:%d] : '%s' : invalid character or unterminated sequence in replacement string near '%c'.\n",
298 file, line, cmd, *err);
299 ret_code |= ERR_ALERT | ERR_FATAL;
300 goto err_free;
301 }
302
303 if (dir == SMP_OPT_DIR_REQ && warnif_misplaced_reqxxx(px, file, line, cmd))
304 ret_code |= ERR_WARN;
305
306 return ret_code;
307
308 err_free:
309 regex_free(preg);
310 err:
311 free(preg);
312 free(errmsg);
313 return ret_code;
314}
315
316int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
317{
318 static struct proxy *curproxy = NULL;
319 const char *err;
320 char *error;
321 int rc;
322 unsigned val;
323 int err_code = 0;
324 struct acl_cond *cond = NULL;
325 struct logsrv *tmplogsrv;
326 char *errmsg = NULL;
327 struct bind_conf *bind_conf;
328
329 if (!strcmp(args[0], "listen"))
330 rc = PR_CAP_LISTEN;
331 else if (!strcmp(args[0], "frontend"))
332 rc = PR_CAP_FE;
333 else if (!strcmp(args[0], "backend"))
334 rc = PR_CAP_BE;
335 else
336 rc = PR_CAP_NONE;
337
338 if (rc != PR_CAP_NONE) { /* new proxy */
339 if (!*args[1]) {
340 ha_alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
341 " optionally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
342 file, linenum, args[0]);
343 err_code |= ERR_ALERT | ERR_ABORT;
344 goto out;
345 }
346
347 err = invalid_char(args[1]);
348 if (err) {
349 ha_alert("parsing [%s:%d] : character '%c' is not permitted in '%s' name '%s'.\n",
350 file, linenum, *err, args[0], args[1]);
351 err_code |= ERR_ALERT | ERR_FATAL;
352 }
353
354 curproxy = (rc & PR_CAP_FE) ? proxy_fe_by_name(args[1]) : proxy_be_by_name(args[1]);
355 if (curproxy) {
356 ha_alert("Parsing [%s:%d]: %s '%s' has the same name as %s '%s' declared at %s:%d.\n",
357 file, linenum, proxy_cap_str(rc), args[1], proxy_type_str(curproxy),
358 curproxy->id, curproxy->conf.file, curproxy->conf.line);
359 err_code |= ERR_ALERT | ERR_FATAL;
360 }
361
362 if ((curproxy = calloc(1, sizeof(*curproxy))) == NULL) {
363 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
364 err_code |= ERR_ALERT | ERR_ABORT;
365 goto out;
366 }
367
368 init_new_proxy(curproxy);
369 curproxy->next = proxies_list;
370 proxies_list = curproxy;
371 curproxy->conf.args.file = curproxy->conf.file = strdup(file);
372 curproxy->conf.args.line = curproxy->conf.line = linenum;
373 curproxy->last_change = now.tv_sec;
374 curproxy->id = strdup(args[1]);
375 curproxy->cap = rc;
376 proxy_store_name(curproxy);
377
378 if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
379 if (curproxy->cap & PR_CAP_FE)
380 ha_alert("parsing [%s:%d] : please use the 'bind' keyword for listening addresses.\n", file, linenum);
381 goto out;
382 }
383
384 /* set default values */
385 memcpy(&curproxy->defsrv, &defproxy.defsrv, sizeof(curproxy->defsrv));
386 curproxy->defsrv.id = "default-server";
387
388 curproxy->state = defproxy.state;
389 curproxy->options = defproxy.options;
390 curproxy->options2 = defproxy.options2;
391 curproxy->no_options = defproxy.no_options;
392 curproxy->no_options2 = defproxy.no_options2;
393 curproxy->bind_proc = defproxy.bind_proc;
394 curproxy->except_net = defproxy.except_net;
395 curproxy->except_mask = defproxy.except_mask;
396 curproxy->except_to = defproxy.except_to;
397 curproxy->except_mask_to = defproxy.except_mask_to;
398
399 if (defproxy.fwdfor_hdr_len) {
400 curproxy->fwdfor_hdr_len = defproxy.fwdfor_hdr_len;
401 curproxy->fwdfor_hdr_name = strdup(defproxy.fwdfor_hdr_name);
402 }
403
404 if (defproxy.orgto_hdr_len) {
405 curproxy->orgto_hdr_len = defproxy.orgto_hdr_len;
406 curproxy->orgto_hdr_name = strdup(defproxy.orgto_hdr_name);
407 }
408
409 if (defproxy.server_id_hdr_len) {
410 curproxy->server_id_hdr_len = defproxy.server_id_hdr_len;
411 curproxy->server_id_hdr_name = strdup(defproxy.server_id_hdr_name);
412 }
413
414 /* initialize error relocations */
415 for (rc = 0; rc < HTTP_ERR_SIZE; rc++)
416 chunk_dup(&curproxy->errmsg[rc], &defproxy.errmsg[rc]);
417
418 if (curproxy->cap & PR_CAP_FE) {
419 curproxy->maxconn = defproxy.maxconn;
420 curproxy->backlog = defproxy.backlog;
421 curproxy->fe_sps_lim = defproxy.fe_sps_lim;
422
423 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
424 }
425
426 if (curproxy->cap & PR_CAP_BE) {
427 curproxy->lbprm.algo = defproxy.lbprm.algo;
428 curproxy->lbprm.chash.balance_factor = defproxy.lbprm.chash.balance_factor;
429 curproxy->fullconn = defproxy.fullconn;
430 curproxy->conn_retries = defproxy.conn_retries;
431 curproxy->redispatch_after = defproxy.redispatch_after;
432 curproxy->max_ka_queue = defproxy.max_ka_queue;
433
434 if (defproxy.check_req) {
435 curproxy->check_req = calloc(1, defproxy.check_len);
436 memcpy(curproxy->check_req, defproxy.check_req, defproxy.check_len);
437 }
438 curproxy->check_len = defproxy.check_len;
439
440 if (defproxy.expect_str) {
441 curproxy->expect_str = strdup(defproxy.expect_str);
442 if (defproxy.expect_regex) {
443 /* note: this regex is known to be valid */
444 curproxy->expect_regex = calloc(1, sizeof(*curproxy->expect_regex));
445 regex_comp(defproxy.expect_str, curproxy->expect_regex, 1, 1, NULL);
446 }
447 }
448
449 curproxy->ck_opts = defproxy.ck_opts;
450 if (defproxy.cookie_name)
451 curproxy->cookie_name = strdup(defproxy.cookie_name);
452 curproxy->cookie_len = defproxy.cookie_len;
453
454 if (defproxy.dyncookie_key)
455 curproxy->dyncookie_key = strdup(defproxy.dyncookie_key);
456 if (defproxy.cookie_domain)
457 curproxy->cookie_domain = strdup(defproxy.cookie_domain);
458
459 if (defproxy.cookie_maxidle)
460 curproxy->cookie_maxidle = defproxy.cookie_maxidle;
461
462 if (defproxy.cookie_maxlife)
463 curproxy->cookie_maxlife = defproxy.cookie_maxlife;
464
465 if (defproxy.rdp_cookie_name)
466 curproxy->rdp_cookie_name = strdup(defproxy.rdp_cookie_name);
467 curproxy->rdp_cookie_len = defproxy.rdp_cookie_len;
468
469 if (defproxy.url_param_name)
470 curproxy->url_param_name = strdup(defproxy.url_param_name);
471 curproxy->url_param_len = defproxy.url_param_len;
472
473 if (defproxy.hh_name)
474 curproxy->hh_name = strdup(defproxy.hh_name);
475 curproxy->hh_len = defproxy.hh_len;
476 curproxy->hh_match_domain = defproxy.hh_match_domain;
477
478 if (defproxy.conn_src.iface_name)
479 curproxy->conn_src.iface_name = strdup(defproxy.conn_src.iface_name);
480 curproxy->conn_src.iface_len = defproxy.conn_src.iface_len;
481 curproxy->conn_src.opts = defproxy.conn_src.opts;
482#if defined(CONFIG_HAP_TRANSPARENT)
483 curproxy->conn_src.tproxy_addr = defproxy.conn_src.tproxy_addr;
484#endif
485 curproxy->load_server_state_from_file = defproxy.load_server_state_from_file;
486 }
487
488 if (curproxy->cap & PR_CAP_FE) {
489 if (defproxy.capture_name)
490 curproxy->capture_name = strdup(defproxy.capture_name);
491 curproxy->capture_namelen = defproxy.capture_namelen;
492 curproxy->capture_len = defproxy.capture_len;
493 }
494
495 if (curproxy->cap & PR_CAP_FE) {
496 curproxy->timeout.client = defproxy.timeout.client;
497 curproxy->timeout.clientfin = defproxy.timeout.clientfin;
498 curproxy->timeout.tarpit = defproxy.timeout.tarpit;
499 curproxy->timeout.httpreq = defproxy.timeout.httpreq;
500 curproxy->timeout.httpka = defproxy.timeout.httpka;
501 curproxy->mon_net = defproxy.mon_net;
502 curproxy->mon_mask = defproxy.mon_mask;
503 if (defproxy.monitor_uri)
504 curproxy->monitor_uri = strdup(defproxy.monitor_uri);
505 curproxy->monitor_uri_len = defproxy.monitor_uri_len;
506 if (defproxy.defbe.name)
507 curproxy->defbe.name = strdup(defproxy.defbe.name);
508
509 /* get either a pointer to the logformat string or a copy of it */
510 curproxy->conf.logformat_string = defproxy.conf.logformat_string;
511 if (curproxy->conf.logformat_string &&
512 curproxy->conf.logformat_string != default_http_log_format &&
513 curproxy->conf.logformat_string != default_tcp_log_format &&
514 curproxy->conf.logformat_string != clf_http_log_format)
515 curproxy->conf.logformat_string = strdup(curproxy->conf.logformat_string);
516
517 if (defproxy.conf.lfs_file) {
518 curproxy->conf.lfs_file = strdup(defproxy.conf.lfs_file);
519 curproxy->conf.lfs_line = defproxy.conf.lfs_line;
520 }
521
522 /* get either a pointer to the logformat string for RFC5424 structured-data or a copy of it */
523 curproxy->conf.logformat_sd_string = defproxy.conf.logformat_sd_string;
524 if (curproxy->conf.logformat_sd_string &&
525 curproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
526 curproxy->conf.logformat_sd_string = strdup(curproxy->conf.logformat_sd_string);
527
528 if (defproxy.conf.lfsd_file) {
529 curproxy->conf.lfsd_file = strdup(defproxy.conf.lfsd_file);
530 curproxy->conf.lfsd_line = defproxy.conf.lfsd_line;
531 }
532 }
533
534 if (curproxy->cap & PR_CAP_BE) {
535 curproxy->timeout.connect = defproxy.timeout.connect;
536 curproxy->timeout.server = defproxy.timeout.server;
537 curproxy->timeout.serverfin = defproxy.timeout.serverfin;
538 curproxy->timeout.check = defproxy.timeout.check;
539 curproxy->timeout.queue = defproxy.timeout.queue;
540 curproxy->timeout.tarpit = defproxy.timeout.tarpit;
541 curproxy->timeout.httpreq = defproxy.timeout.httpreq;
542 curproxy->timeout.httpka = defproxy.timeout.httpka;
543 curproxy->timeout.tunnel = defproxy.timeout.tunnel;
544 curproxy->conn_src.source_addr = defproxy.conn_src.source_addr;
545 }
546
547 curproxy->mode = defproxy.mode;
548 curproxy->uri_auth = defproxy.uri_auth; /* for stats */
549
550 /* copy default logsrvs to curproxy */
551 list_for_each_entry(tmplogsrv, &defproxy.logsrvs, list) {
552 struct logsrv *node = malloc(sizeof(*node));
553 memcpy(node, tmplogsrv, sizeof(struct logsrv));
554 node->ref = tmplogsrv->ref;
555 LIST_INIT(&node->list);
556 LIST_ADDQ(&curproxy->logsrvs, &node->list);
557 }
558
559 curproxy->conf.uniqueid_format_string = defproxy.conf.uniqueid_format_string;
560 if (curproxy->conf.uniqueid_format_string)
561 curproxy->conf.uniqueid_format_string = strdup(curproxy->conf.uniqueid_format_string);
562
563 chunk_dup(&curproxy->log_tag, &defproxy.log_tag);
564
565 if (defproxy.conf.uif_file) {
566 curproxy->conf.uif_file = strdup(defproxy.conf.uif_file);
567 curproxy->conf.uif_line = defproxy.conf.uif_line;
568 }
569
570 /* copy default header unique id */
571 if (defproxy.header_unique_id)
572 curproxy->header_unique_id = strdup(defproxy.header_unique_id);
573
574 /* default compression options */
575 if (defproxy.comp != NULL) {
576 curproxy->comp = calloc(1, sizeof(struct comp));
577 curproxy->comp->algos = defproxy.comp->algos;
578 curproxy->comp->types = defproxy.comp->types;
579 }
580
581 curproxy->grace = defproxy.grace;
582 curproxy->conf.used_listener_id = EB_ROOT;
583 curproxy->conf.used_server_id = EB_ROOT;
584
585 if (defproxy.check_path)
586 curproxy->check_path = strdup(defproxy.check_path);
587 if (defproxy.check_command)
588 curproxy->check_command = strdup(defproxy.check_command);
589
590 if (defproxy.email_alert.mailers.name)
591 curproxy->email_alert.mailers.name = strdup(defproxy.email_alert.mailers.name);
592 if (defproxy.email_alert.from)
593 curproxy->email_alert.from = strdup(defproxy.email_alert.from);
594 if (defproxy.email_alert.to)
595 curproxy->email_alert.to = strdup(defproxy.email_alert.to);
596 if (defproxy.email_alert.myhostname)
597 curproxy->email_alert.myhostname = strdup(defproxy.email_alert.myhostname);
598 curproxy->email_alert.level = defproxy.email_alert.level;
599 curproxy->email_alert.set = defproxy.email_alert.set;
600
601 goto out;
602 }
603 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
604 /* some variables may have already been initialized earlier */
605 /* FIXME-20070101: we should do this too at the end of the
606 * config parsing to free all default values.
607 */
608 if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
609 err_code |= ERR_ABORT;
610 goto out;
611 }
612
613 free(defproxy.check_req);
614 free(defproxy.check_command);
615 free(defproxy.check_path);
616 free(defproxy.cookie_name);
617 free(defproxy.rdp_cookie_name);
618 free(defproxy.dyncookie_key);
619 free(defproxy.cookie_domain);
620 free(defproxy.url_param_name);
621 free(defproxy.hh_name);
622 free(defproxy.capture_name);
623 free(defproxy.monitor_uri);
624 free(defproxy.defbe.name);
625 free(defproxy.conn_src.iface_name);
626 free(defproxy.fwdfor_hdr_name);
627 defproxy.fwdfor_hdr_len = 0;
628 free(defproxy.orgto_hdr_name);
629 defproxy.orgto_hdr_len = 0;
630 free(defproxy.server_id_hdr_name);
631 defproxy.server_id_hdr_len = 0;
632 free(defproxy.expect_str);
633 if (defproxy.expect_regex) {
634 regex_free(defproxy.expect_regex);
635 free(defproxy.expect_regex);
636 defproxy.expect_regex = NULL;
637 }
638
639 if (defproxy.conf.logformat_string != default_http_log_format &&
640 defproxy.conf.logformat_string != default_tcp_log_format &&
641 defproxy.conf.logformat_string != clf_http_log_format)
642 free(defproxy.conf.logformat_string);
643
644 free(defproxy.conf.uniqueid_format_string);
645 free(defproxy.conf.lfs_file);
646 free(defproxy.conf.uif_file);
647 chunk_destroy(&defproxy.log_tag);
648 free_email_alert(&defproxy);
649
650 if (defproxy.conf.logformat_sd_string != default_rfc5424_sd_log_format)
651 free(defproxy.conf.logformat_sd_string);
652 free(defproxy.conf.lfsd_file);
653
654 for (rc = 0; rc < HTTP_ERR_SIZE; rc++)
655 chunk_destroy(&defproxy.errmsg[rc]);
656
657 /* we cannot free uri_auth because it might already be used */
658 init_default_instance();
659 curproxy = &defproxy;
660 curproxy->conf.args.file = curproxy->conf.file = strdup(file);
661 curproxy->conf.args.line = curproxy->conf.line = linenum;
662 defproxy.cap = PR_CAP_LISTEN; /* all caps for now */
663 goto out;
664 }
665 else if (curproxy == NULL) {
666 ha_alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
667 err_code |= ERR_ALERT | ERR_FATAL;
668 goto out;
669 }
670
671 /* update the current file and line being parsed */
672 curproxy->conf.args.file = curproxy->conf.file;
673 curproxy->conf.args.line = linenum;
674
675 /* Now let's parse the proxy-specific keywords */
676 if (!strcmp(args[0], "server") ||
677 !strcmp(args[0], "default-server") ||
678 !strcmp(args[0], "server-template")) {
679 err_code |= parse_server(file, linenum, args, curproxy, &defproxy);
680 if (err_code & ERR_FATAL)
681 goto out;
682 }
683 else if (!strcmp(args[0], "bind")) { /* new listen addresses */
684 struct listener *l;
685 int cur_arg;
686
687 if (curproxy == &defproxy) {
688 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
689 err_code |= ERR_ALERT | ERR_FATAL;
690 goto out;
691 }
692 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
693 err_code |= ERR_WARN;
694
695 if (!*(args[1])) {
696 ha_alert("parsing [%s:%d] : '%s' expects {<path>|[addr1]:port1[-end1]}{,[addr]:port[-end]}... as arguments.\n",
697 file, linenum, args[0]);
698 err_code |= ERR_ALERT | ERR_FATAL;
699 goto out;
700 }
701
702 bind_conf = bind_conf_alloc(curproxy, file, linenum, args[1], xprt_get(XPRT_RAW));
703
704 /* use default settings for unix sockets */
705 bind_conf->ux.uid = global.unix_bind.ux.uid;
706 bind_conf->ux.gid = global.unix_bind.ux.gid;
707 bind_conf->ux.mode = global.unix_bind.ux.mode;
708
709 /* NOTE: the following line might create several listeners if there
710 * are comma-separated IPs or port ranges. So all further processing
711 * will have to be applied to all listeners created after last_listen.
712 */
713 if (!str2listener(args[1], curproxy, bind_conf, file, linenum, &errmsg)) {
714 if (errmsg && *errmsg) {
715 indent_msg(&errmsg, 2);
716 ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
717 }
718 else
719 ha_alert("parsing [%s:%d] : '%s' : error encountered while parsing listening address '%s'.\n",
720 file, linenum, args[0], args[1]);
721 err_code |= ERR_ALERT | ERR_FATAL;
722 goto out;
723 }
724
725 list_for_each_entry(l, &bind_conf->listeners, by_bind) {
726 /* Set default global rights and owner for unix bind */
727 global.maxsock++;
728 }
729
730 cur_arg = 2;
731 while (*(args[cur_arg])) {
732 static int bind_dumped;
733 struct bind_kw *kw;
734 char *err;
735
736 kw = bind_find_kw(args[cur_arg]);
737 if (kw) {
738 char *err = NULL;
739 int code;
740
741 if (!kw->parse) {
742 ha_alert("parsing [%s:%d] : '%s %s' : '%s' option is not implemented in this version (check build options).\n",
743 file, linenum, args[0], args[1], args[cur_arg]);
744 cur_arg += 1 + kw->skip ;
745 err_code |= ERR_ALERT | ERR_FATAL;
746 goto out;
747 }
748
749 code = kw->parse(args, cur_arg, curproxy, bind_conf, &err);
750 err_code |= code;
751
752 if (code) {
753 if (err && *err) {
754 indent_msg(&err, 2);
755 ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], err);
756 }
757 else
758 ha_alert("parsing [%s:%d] : '%s %s' : error encountered while processing '%s'.\n",
759 file, linenum, args[0], args[1], args[cur_arg]);
760 if (code & ERR_FATAL) {
761 free(err);
762 cur_arg += 1 + kw->skip;
763 goto out;
764 }
765 }
766 free(err);
767 cur_arg += 1 + kw->skip;
768 continue;
769 }
770
771 err = NULL;
772 if (!bind_dumped) {
773 bind_dump_kws(&err);
774 indent_msg(&err, 4);
775 bind_dumped = 1;
776 }
777
778 ha_alert("parsing [%s:%d] : '%s %s' unknown keyword '%s'.%s%s\n",
779 file, linenum, args[0], args[1], args[cur_arg],
780 err ? " Registered keywords :" : "", err ? err : "");
781 free(err);
782
783 err_code |= ERR_ALERT | ERR_FATAL;
784 goto out;
785 }
786 goto out;
787 }
788 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
789 if (!*args[1] || !str2net(args[1], 1, &curproxy->mon_net, &curproxy->mon_mask)) {
790 ha_alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
791 file, linenum, args[0]);
792 err_code |= ERR_ALERT | ERR_FATAL;
793 goto out;
794 }
795 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
796 err_code |= ERR_WARN;
797
798 /* flush useless bits */
799 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
800 goto out;
801 }
802 else if (!strcmp(args[0], "monitor-uri")) { /* set the URI to intercept */
803 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
804 err_code |= ERR_WARN;
805
806 if (alertif_too_many_args(1, file, linenum, args, &err_code))
807 goto out;
808
809 if (!*args[1]) {
810 ha_alert("parsing [%s:%d] : '%s' expects an URI.\n",
811 file, linenum, args[0]);
812 err_code |= ERR_ALERT | ERR_FATAL;
813 goto out;
814 }
815
816 free(curproxy->monitor_uri);
817 curproxy->monitor_uri_len = strlen(args[1]);
818 curproxy->monitor_uri = calloc(1, curproxy->monitor_uri_len + 1);
819 memcpy(curproxy->monitor_uri, args[1], curproxy->monitor_uri_len);
820 curproxy->monitor_uri[curproxy->monitor_uri_len] = '\0';
821
822 goto out;
823 }
824 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
825 if (alertif_too_many_args(1, file, linenum, args, &err_code))
826 goto out;
827
828 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
829 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
830 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
831 else {
832 ha_alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
833 err_code |= ERR_ALERT | ERR_FATAL;
834 goto out;
835 }
836 }
837 else if (!strcmp(args[0], "id")) {
838 struct eb32_node *node;
839
840 if (curproxy == &defproxy) {
841 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n",
842 file, linenum, args[0]);
843 err_code |= ERR_ALERT | ERR_FATAL;
844 goto out;
845 }
846
847 if (alertif_too_many_args(1, file, linenum, args, &err_code))
848 goto out;
849
850 if (!*args[1]) {
851 ha_alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
852 file, linenum, args[0]);
853 err_code |= ERR_ALERT | ERR_FATAL;
854 goto out;
855 }
856
857 curproxy->uuid = atol(args[1]);
858 curproxy->conf.id.key = curproxy->uuid;
859 curproxy->options |= PR_O_FORCED_ID;
860
861 if (curproxy->uuid <= 0) {
862 ha_alert("parsing [%s:%d]: custom id has to be > 0.\n",
863 file, linenum);
864 err_code |= ERR_ALERT | ERR_FATAL;
865 goto out;
866 }
867
868 node = eb32_lookup(&used_proxy_id, curproxy->uuid);
869 if (node) {
870 struct proxy *target = container_of(node, struct proxy, conf.id);
871 ha_alert("parsing [%s:%d]: %s %s reuses same custom id as %s %s (declared at %s:%d).\n",
872 file, linenum, proxy_type_str(curproxy), curproxy->id,
873 proxy_type_str(target), target->id, target->conf.file, target->conf.line);
874 err_code |= ERR_ALERT | ERR_FATAL;
875 goto out;
876 }
877 eb32_insert(&used_proxy_id, &curproxy->conf.id);
878 }
879 else if (!strcmp(args[0], "description")) {
880 int i, len=0;
881 char *d;
882
883 if (curproxy == &defproxy) {
884 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n",
885 file, linenum, args[0]);
886 err_code |= ERR_ALERT | ERR_FATAL;
887 goto out;
888 }
889
890 if (!*args[1]) {
891 ha_alert("parsing [%s:%d]: '%s' expects a string argument.\n",
892 file, linenum, args[0]);
893 return -1;
894 }
895
896 for (i = 1; *args[i]; i++)
897 len += strlen(args[i]) + 1;
898
899 d = calloc(1, len);
900 curproxy->desc = d;
901
902 d += snprintf(d, curproxy->desc + len - d, "%s", args[1]);
903 for (i = 2; *args[i]; i++)
904 d += snprintf(d, curproxy->desc + len - d, " %s", args[i]);
905
906 }
907 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
908 if (alertif_too_many_args(0, file, linenum, args, &err_code))
909 goto out;
910 curproxy->state = PR_STSTOPPED;
911 }
912 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
913 if (alertif_too_many_args(0, file, linenum, args, &err_code))
914 goto out;
915 curproxy->state = PR_STNEW;
916 }
917 else if (!strcmp(args[0], "bind-process")) { /* enable this proxy only on some processes */
918 int cur_arg = 1;
919 unsigned long set = 0;
920
921 while (*args[cur_arg]) {
922 if (strcmp(args[cur_arg], "all") == 0) {
923 set = 0;
924 break;
925 }
926 if (parse_process_number(args[cur_arg], &set, NULL, &errmsg)) {
927 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
928 err_code |= ERR_ALERT | ERR_FATAL;
929 goto out;
930 }
931 cur_arg++;
932 }
933 curproxy->bind_proc = set;
934 }
935 else if (!strcmp(args[0], "acl")) { /* add an ACL */
936 if (curproxy == &defproxy) {
937 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
938 err_code |= ERR_ALERT | ERR_FATAL;
939 goto out;
940 }
941
942 err = invalid_char(args[1]);
943 if (err) {
944 ha_alert("parsing [%s:%d] : character '%c' is not permitted in acl name '%s'.\n",
945 file, linenum, *err, args[1]);
946 err_code |= ERR_ALERT | ERR_FATAL;
947 goto out;
948 }
949
950 if (parse_acl((const char **)args + 1, &curproxy->acl, &errmsg, &curproxy->conf.args, file, linenum) == NULL) {
951 ha_alert("parsing [%s:%d] : error detected while parsing ACL '%s' : %s.\n",
952 file, linenum, args[1], errmsg);
953 err_code |= ERR_ALERT | ERR_FATAL;
954 goto out;
955 }
956 }
957 else if (!strcmp(args[0], "dynamic-cookie-key")) { /* Dynamic cookies secret key */
958
959 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
960 err_code |= ERR_WARN;
961
962 if (*(args[1]) == 0) {
963 ha_alert("parsing [%s:%d] : '%s' expects <secret_key> as argument.\n",
964 file, linenum, args[0]);
965 err_code |= ERR_ALERT | ERR_FATAL;
966 goto out;
967 }
968 free(curproxy->dyncookie_key);
969 curproxy->dyncookie_key = strdup(args[1]);
970 }
971 else if (!strcmp(args[0], "cookie")) { /* cookie name */
972 int cur_arg;
973
974 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
975 err_code |= ERR_WARN;
976
977 if (*(args[1]) == 0) {
978 ha_alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
979 file, linenum, args[0]);
980 err_code |= ERR_ALERT | ERR_FATAL;
981 goto out;
982 }
983
984 curproxy->ck_opts = 0;
985 curproxy->cookie_maxidle = curproxy->cookie_maxlife = 0;
986 free(curproxy->cookie_domain); curproxy->cookie_domain = NULL;
987 free(curproxy->cookie_name);
988 curproxy->cookie_name = strdup(args[1]);
989 curproxy->cookie_len = strlen(curproxy->cookie_name);
990
991 cur_arg = 2;
992 while (*(args[cur_arg])) {
993 if (!strcmp(args[cur_arg], "rewrite")) {
994 curproxy->ck_opts |= PR_CK_RW;
995 }
996 else if (!strcmp(args[cur_arg], "indirect")) {
997 curproxy->ck_opts |= PR_CK_IND;
998 }
999 else if (!strcmp(args[cur_arg], "insert")) {
1000 curproxy->ck_opts |= PR_CK_INS;
1001 }
1002 else if (!strcmp(args[cur_arg], "nocache")) {
1003 curproxy->ck_opts |= PR_CK_NOC;
1004 }
1005 else if (!strcmp(args[cur_arg], "postonly")) {
1006 curproxy->ck_opts |= PR_CK_POST;
1007 }
1008 else if (!strcmp(args[cur_arg], "preserve")) {
1009 curproxy->ck_opts |= PR_CK_PSV;
1010 }
1011 else if (!strcmp(args[cur_arg], "prefix")) {
1012 curproxy->ck_opts |= PR_CK_PFX;
1013 }
1014 else if (!strcmp(args[cur_arg], "httponly")) {
1015 curproxy->ck_opts |= PR_CK_HTTPONLY;
1016 }
1017 else if (!strcmp(args[cur_arg], "secure")) {
1018 curproxy->ck_opts |= PR_CK_SECURE;
1019 }
1020 else if (!strcmp(args[cur_arg], "domain")) {
1021 if (!*args[cur_arg + 1]) {
1022 ha_alert("parsing [%s:%d]: '%s' expects <domain> as argument.\n",
1023 file, linenum, args[cur_arg]);
1024 err_code |= ERR_ALERT | ERR_FATAL;
1025 goto out;
1026 }
1027
1028 if (*args[cur_arg + 1] != '.' || !strchr(args[cur_arg + 1] + 1, '.')) {
1029 /* rfc2109, 4.3.2 Rejecting Cookies */
1030 ha_warning("parsing [%s:%d]: domain '%s' contains no embedded"
1031 " dots nor does not start with a dot."
1032 " RFC forbids it, this configuration may not work properly.\n",
1033 file, linenum, args[cur_arg + 1]);
1034 err_code |= ERR_WARN;
1035 }
1036
1037 err = invalid_domainchar(args[cur_arg + 1]);
1038 if (err) {
1039 ha_alert("parsing [%s:%d]: character '%c' is not permitted in domain name '%s'.\n",
1040 file, linenum, *err, args[cur_arg + 1]);
1041 err_code |= ERR_ALERT | ERR_FATAL;
1042 goto out;
1043 }
1044
1045 if (!curproxy->cookie_domain) {
1046 curproxy->cookie_domain = strdup(args[cur_arg + 1]);
1047 } else {
1048 /* one domain was already specified, add another one by
1049 * building the string which will be returned along with
1050 * the cookie.
1051 */
1052 char *new_ptr;
1053 int new_len = strlen(curproxy->cookie_domain) +
1054 strlen("; domain=") + strlen(args[cur_arg + 1]) + 1;
1055 new_ptr = malloc(new_len);
1056 snprintf(new_ptr, new_len, "%s; domain=%s", curproxy->cookie_domain, args[cur_arg+1]);
1057 free(curproxy->cookie_domain);
1058 curproxy->cookie_domain = new_ptr;
1059 }
1060 cur_arg++;
1061 }
1062 else if (!strcmp(args[cur_arg], "maxidle")) {
1063 unsigned int maxidle;
1064 const char *res;
1065
1066 if (!*args[cur_arg + 1]) {
1067 ha_alert("parsing [%s:%d]: '%s' expects <idletime> in seconds as argument.\n",
1068 file, linenum, args[cur_arg]);
1069 err_code |= ERR_ALERT | ERR_FATAL;
1070 goto out;
1071 }
1072
1073 res = parse_time_err(args[cur_arg + 1], &maxidle, TIME_UNIT_S);
1074 if (res) {
1075 ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
1076 file, linenum, *res, args[cur_arg]);
1077 err_code |= ERR_ALERT | ERR_FATAL;
1078 goto out;
1079 }
1080 curproxy->cookie_maxidle = maxidle;
1081 cur_arg++;
1082 }
1083 else if (!strcmp(args[cur_arg], "maxlife")) {
1084 unsigned int maxlife;
1085 const char *res;
1086
1087 if (!*args[cur_arg + 1]) {
1088 ha_alert("parsing [%s:%d]: '%s' expects <lifetime> in seconds as argument.\n",
1089 file, linenum, args[cur_arg]);
1090 err_code |= ERR_ALERT | ERR_FATAL;
1091 goto out;
1092 }
1093
1094 res = parse_time_err(args[cur_arg + 1], &maxlife, TIME_UNIT_S);
1095 if (res) {
1096 ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
1097 file, linenum, *res, args[cur_arg]);
1098 err_code |= ERR_ALERT | ERR_FATAL;
1099 goto out;
1100 }
1101 curproxy->cookie_maxlife = maxlife;
1102 cur_arg++;
1103 }
1104 else if (!strcmp(args[cur_arg], "dynamic")) { /* Dynamic persistent cookies secret key */
1105
1106 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[cur_arg], NULL))
1107 err_code |= ERR_WARN;
1108 curproxy->ck_opts |= PR_CK_DYNAMIC;
1109 }
1110
1111 else {
1112 ha_alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache', 'postonly', 'domain', 'maxidle', 'dynamic' and 'maxlife' options.\n",
1113 file, linenum, args[0]);
1114 err_code |= ERR_ALERT | ERR_FATAL;
1115 goto out;
1116 }
1117 cur_arg++;
1118 }
1119 if (!POWEROF2(curproxy->ck_opts & (PR_CK_RW|PR_CK_IND))) {
1120 ha_alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
1121 file, linenum);
1122 err_code |= ERR_ALERT | ERR_FATAL;
1123 }
1124
1125 if (!POWEROF2(curproxy->ck_opts & (PR_CK_RW|PR_CK_INS|PR_CK_PFX))) {
1126 ha_alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
1127 file, linenum);
1128 err_code |= ERR_ALERT | ERR_FATAL;
1129 }
1130
1131 if ((curproxy->ck_opts & (PR_CK_PSV | PR_CK_INS | PR_CK_IND)) == PR_CK_PSV) {
1132 ha_alert("parsing [%s:%d] : cookie 'preserve' requires at least 'insert' or 'indirect'.\n",
1133 file, linenum);
1134 err_code |= ERR_ALERT | ERR_FATAL;
1135 }
1136 }/* end else if (!strcmp(args[0], "cookie")) */
1137 else if (!strcmp(args[0], "email-alert")) {
1138 if (*(args[1]) == 0) {
1139 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1140 file, linenum, args[0]);
1141 err_code |= ERR_ALERT | ERR_FATAL;
1142 goto out;
1143 }
1144
1145 if (!strcmp(args[1], "from")) {
1146 if (*(args[1]) == 0) {
1147 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1148 file, linenum, args[1]);
1149 err_code |= ERR_ALERT | ERR_FATAL;
1150 goto out;
1151 }
1152 free(curproxy->email_alert.from);
1153 curproxy->email_alert.from = strdup(args[2]);
1154 }
1155 else if (!strcmp(args[1], "mailers")) {
1156 if (*(args[1]) == 0) {
1157 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1158 file, linenum, args[1]);
1159 err_code |= ERR_ALERT | ERR_FATAL;
1160 goto out;
1161 }
1162 free(curproxy->email_alert.mailers.name);
1163 curproxy->email_alert.mailers.name = strdup(args[2]);
1164 }
1165 else if (!strcmp(args[1], "myhostname")) {
1166 if (*(args[1]) == 0) {
1167 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1168 file, linenum, args[1]);
1169 err_code |= ERR_ALERT | ERR_FATAL;
1170 goto out;
1171 }
1172 free(curproxy->email_alert.myhostname);
1173 curproxy->email_alert.myhostname = strdup(args[2]);
1174 }
1175 else if (!strcmp(args[1], "level")) {
1176 curproxy->email_alert.level = get_log_level(args[2]);
1177 if (curproxy->email_alert.level < 0) {
1178 ha_alert("parsing [%s:%d] : unknown log level '%s' after '%s'\n",
1179 file, linenum, args[1], args[2]);
1180 err_code |= ERR_ALERT | ERR_FATAL;
1181 goto out;
1182 }
1183 }
1184 else if (!strcmp(args[1], "to")) {
1185 if (*(args[1]) == 0) {
1186 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1187 file, linenum, args[1]);
1188 err_code |= ERR_ALERT | ERR_FATAL;
1189 goto out;
1190 }
1191 free(curproxy->email_alert.to);
1192 curproxy->email_alert.to = strdup(args[2]);
1193 }
1194 else {
1195 ha_alert("parsing [%s:%d] : email-alert: unknown argument '%s'.\n",
1196 file, linenum, args[1]);
1197 err_code |= ERR_ALERT | ERR_FATAL;
1198 goto out;
1199 }
1200 /* Indicate that the email_alert is at least partially configured */
1201 curproxy->email_alert.set = 1;
1202 }/* end else if (!strcmp(args[0], "email-alert")) */
1203 else if (!strcmp(args[0], "external-check")) {
1204 if (*(args[1]) == 0) {
1205 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1206 file, linenum, args[0]);
1207 err_code |= ERR_ALERT | ERR_FATAL;
1208 goto out;
1209 }
1210
1211 if (!strcmp(args[1], "command")) {
1212 if (alertif_too_many_args(2, file, linenum, args, &err_code))
1213 goto out;
1214 if (*(args[2]) == 0) {
1215 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1216 file, linenum, args[1]);
1217 err_code |= ERR_ALERT | ERR_FATAL;
1218 goto out;
1219 }
1220 free(curproxy->check_command);
1221 curproxy->check_command = strdup(args[2]);
1222 }
1223 else if (!strcmp(args[1], "path")) {
1224 if (alertif_too_many_args(2, file, linenum, args, &err_code))
1225 goto out;
1226 if (*(args[2]) == 0) {
1227 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1228 file, linenum, args[1]);
1229 err_code |= ERR_ALERT | ERR_FATAL;
1230 goto out;
1231 }
1232 free(curproxy->check_path);
1233 curproxy->check_path = strdup(args[2]);
1234 }
1235 else {
1236 ha_alert("parsing [%s:%d] : external-check: unknown argument '%s'.\n",
1237 file, linenum, args[1]);
1238 err_code |= ERR_ALERT | ERR_FATAL;
1239 goto out;
1240 }
1241 }/* end else if (!strcmp(args[0], "external-check")) */
1242 else if (!strcmp(args[0], "persist")) { /* persist */
1243 if (*(args[1]) == 0) {
1244 ha_alert("parsing [%s:%d] : missing persist method.\n",
1245 file, linenum);
1246 err_code |= ERR_ALERT | ERR_FATAL;
1247 goto out;
1248 }
1249
1250 if (!strncmp(args[1], "rdp-cookie", 10)) {
1251 curproxy->options2 |= PR_O2_RDPC_PRST;
1252
1253 if (*(args[1] + 10) == '(') { /* cookie name */
1254 const char *beg, *end;
1255
1256 beg = args[1] + 11;
1257 end = strchr(beg, ')');
1258
1259 if (alertif_too_many_args(1, file, linenum, args, &err_code))
1260 goto out;
1261
1262 if (!end || end == beg) {
1263 ha_alert("parsing [%s:%d] : persist rdp-cookie(name)' requires an rdp cookie name.\n",
1264 file, linenum);
1265 err_code |= ERR_ALERT | ERR_FATAL;
1266 goto out;
1267 }
1268
1269 free(curproxy->rdp_cookie_name);
1270 curproxy->rdp_cookie_name = my_strndup(beg, end - beg);
1271 curproxy->rdp_cookie_len = end-beg;
1272 }
1273 else if (*(args[1] + 10) == '\0') { /* default cookie name 'msts' */
1274 free(curproxy->rdp_cookie_name);
1275 curproxy->rdp_cookie_name = strdup("msts");
1276 curproxy->rdp_cookie_len = strlen(curproxy->rdp_cookie_name);
1277 }
1278 else { /* syntax */
1279 ha_alert("parsing [%s:%d] : persist rdp-cookie(name)' requires an rdp cookie name.\n",
1280 file, linenum);
1281 err_code |= ERR_ALERT | ERR_FATAL;
1282 goto out;
1283 }
1284 }
1285 else {
1286 ha_alert("parsing [%s:%d] : unknown persist method.\n",
1287 file, linenum);
1288 err_code |= ERR_ALERT | ERR_FATAL;
1289 goto out;
1290 }
1291 }
1292 else if (!strcmp(args[0], "appsession")) { /* cookie name */
1293 ha_alert("parsing [%s:%d] : '%s' is not supported anymore, please check the documentation.\n", file, linenum, args[0]);
1294 err_code |= ERR_ALERT | ERR_FATAL;
1295 goto out;
1296 }
1297 else if (!strcmp(args[0], "load-server-state-from-file")) {
1298 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1299 err_code |= ERR_WARN;
1300 if (!strcmp(args[1], "global")) { /* use the file pointed to by global server-state-file directive */
1301 curproxy->load_server_state_from_file = PR_SRV_STATE_FILE_GLOBAL;
1302 }
1303 else if (!strcmp(args[1], "local")) { /* use the server-state-file-name variable to locate the server-state file */
1304 curproxy->load_server_state_from_file = PR_SRV_STATE_FILE_LOCAL;
1305 }
1306 else if (!strcmp(args[1], "none")) { /* don't use server-state-file directive for this backend */
1307 curproxy->load_server_state_from_file = PR_SRV_STATE_FILE_NONE;
1308 }
1309 else {
1310 ha_alert("parsing [%s:%d] : '%s' expects 'global', 'local' or 'none'. Got '%s'\n",
1311 file, linenum, args[0], args[1]);
1312 err_code |= ERR_ALERT | ERR_FATAL;
1313 goto out;
1314 }
1315 }
1316 else if (!strcmp(args[0], "server-state-file-name")) {
1317 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1318 err_code |= ERR_WARN;
1319 if (*(args[1]) == 0) {
1320 ha_alert("parsing [%s:%d] : '%s' expects 'use-backend-name' or a string. Got no argument\n",
1321 file, linenum, args[0]);
1322 err_code |= ERR_ALERT | ERR_FATAL;
1323 goto out;
1324 }
1325 else if (!strcmp(args[1], "use-backend-name"))
1326 curproxy->server_state_file_name = strdup(curproxy->id);
1327 else
1328 curproxy->server_state_file_name = strdup(args[1]);
1329 }
1330 else if (!strcmp(args[0], "capture")) {
1331 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1332 err_code |= ERR_WARN;
1333
1334 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
1335 if (curproxy == &defproxy) {
1336 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1337 err_code |= ERR_ALERT | ERR_FATAL;
1338 goto out;
1339 }
1340
1341 if (alertif_too_many_args_idx(4, 1, file, linenum, args, &err_code))
1342 goto out;
1343
1344 if (*(args[4]) == 0) {
1345 ha_alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
1346 file, linenum, args[0]);
1347 err_code |= ERR_ALERT | ERR_FATAL;
1348 goto out;
1349 }
1350 free(curproxy->capture_name);
1351 curproxy->capture_name = strdup(args[2]);
1352 curproxy->capture_namelen = strlen(curproxy->capture_name);
1353 curproxy->capture_len = atol(args[4]);
1354 curproxy->to_log |= LW_COOKIE;
1355 }
1356 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
1357 struct cap_hdr *hdr;
1358
1359 if (curproxy == &defproxy) {
1360 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1361 err_code |= ERR_ALERT | ERR_FATAL;
1362 goto out;
1363 }
1364
1365 if (alertif_too_many_args_idx(4, 1, file, linenum, args, &err_code))
1366 goto out;
1367
1368 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
1369 ha_alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
1370 file, linenum, args[0], args[1]);
1371 err_code |= ERR_ALERT | ERR_FATAL;
1372 goto out;
1373 }
1374
1375 hdr = calloc(1, sizeof(*hdr));
1376 hdr->next = curproxy->req_cap;
1377 hdr->name = strdup(args[3]);
1378 hdr->namelen = strlen(args[3]);
1379 hdr->len = atol(args[5]);
1380 hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
1381 hdr->index = curproxy->nb_req_cap++;
1382 curproxy->req_cap = hdr;
1383 curproxy->to_log |= LW_REQHDR;
1384 }
1385 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
1386 struct cap_hdr *hdr;
1387
1388 if (curproxy == &defproxy) {
1389 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1390 err_code |= ERR_ALERT | ERR_FATAL;
1391 goto out;
1392 }
1393
1394 if (alertif_too_many_args_idx(4, 1, file, linenum, args, &err_code))
1395 goto out;
1396
1397 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
1398 ha_alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
1399 file, linenum, args[0], args[1]);
1400 err_code |= ERR_ALERT | ERR_FATAL;
1401 goto out;
1402 }
1403 hdr = calloc(1, sizeof(*hdr));
1404 hdr->next = curproxy->rsp_cap;
1405 hdr->name = strdup(args[3]);
1406 hdr->namelen = strlen(args[3]);
1407 hdr->len = atol(args[5]);
1408 hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
1409 hdr->index = curproxy->nb_rsp_cap++;
1410 curproxy->rsp_cap = hdr;
1411 curproxy->to_log |= LW_RSPHDR;
1412 }
1413 else {
1414 ha_alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
1415 file, linenum, args[0]);
1416 err_code |= ERR_ALERT | ERR_FATAL;
1417 goto out;
1418 }
1419 }
1420 else if (!strcmp(args[0], "retries")) { /* connection retries */
1421 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1422 err_code |= ERR_WARN;
1423
1424 if (alertif_too_many_args(1, file, linenum, args, &err_code))
1425 goto out;
1426
1427 if (*(args[1]) == 0) {
1428 ha_alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
1429 file, linenum, args[0]);
1430 err_code |= ERR_ALERT | ERR_FATAL;
1431 goto out;
1432 }
1433 curproxy->conn_retries = atol(args[1]);
1434 }
1435 else if (!strcmp(args[0], "http-request")) { /* request access control: allow/deny/auth */
1436 struct act_rule *rule;
1437
1438 if (curproxy == &defproxy) {
1439 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1440 err_code |= ERR_ALERT | ERR_FATAL;
1441 goto out;
1442 }
1443
1444 if (!LIST_ISEMPTY(&curproxy->http_req_rules) &&
1445 !LIST_PREV(&curproxy->http_req_rules, struct act_rule *, list)->cond &&
1446 (LIST_PREV(&curproxy->http_req_rules, struct act_rule *, list)->action == ACT_ACTION_ALLOW ||
1447 LIST_PREV(&curproxy->http_req_rules, struct act_rule *, list)->action == ACT_ACTION_DENY ||
1448 LIST_PREV(&curproxy->http_req_rules, struct act_rule *, list)->action == ACT_HTTP_REDIR ||
1449 LIST_PREV(&curproxy->http_req_rules, struct act_rule *, list)->action == ACT_HTTP_REQ_AUTH)) {
1450 ha_warning("parsing [%s:%d]: previous '%s' action is final and has no condition attached, further entries are NOOP.\n",
1451 file, linenum, args[0]);
1452 err_code |= ERR_WARN;
1453 }
1454
1455 rule = parse_http_req_cond((const char **)args + 1, file, linenum, curproxy);
1456
1457 if (!rule) {
1458 err_code |= ERR_ALERT | ERR_ABORT;
1459 goto out;
1460 }
1461
1462 err_code |= warnif_misplaced_http_req(curproxy, file, linenum, args[0]);
1463 err_code |= warnif_cond_conflicts(rule->cond,
1464 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1465 file, linenum);
1466
1467 LIST_ADDQ(&curproxy->http_req_rules, &rule->list);
1468 }
1469 else if (!strcmp(args[0], "http-response")) { /* response access control */
1470 struct act_rule *rule;
1471
1472 if (curproxy == &defproxy) {
1473 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1474 err_code |= ERR_ALERT | ERR_FATAL;
1475 goto out;
1476 }
1477
1478 if (!LIST_ISEMPTY(&curproxy->http_res_rules) &&
1479 !LIST_PREV(&curproxy->http_res_rules, struct act_rule *, list)->cond &&
1480 (LIST_PREV(&curproxy->http_res_rules, struct act_rule *, list)->action == ACT_ACTION_ALLOW ||
1481 LIST_PREV(&curproxy->http_res_rules, struct act_rule *, list)->action == ACT_ACTION_DENY)) {
1482 ha_warning("parsing [%s:%d]: previous '%s' action is final and has no condition attached, further entries are NOOP.\n",
1483 file, linenum, args[0]);
1484 err_code |= ERR_WARN;
1485 }
1486
1487 rule = parse_http_res_cond((const char **)args + 1, file, linenum, curproxy);
1488
1489 if (!rule) {
1490 err_code |= ERR_ALERT | ERR_ABORT;
1491 goto out;
1492 }
1493
1494 err_code |= warnif_cond_conflicts(rule->cond,
1495 (curproxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
1496 file, linenum);
1497
1498 LIST_ADDQ(&curproxy->http_res_rules, &rule->list);
1499 }
1500 else if (!strcmp(args[0], "http-send-name-header")) { /* send server name in request header */
1501 /* set the header name and length into the proxy structure */
1502 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1503 err_code |= ERR_WARN;
1504
1505 if (!*args[1]) {
1506 ha_alert("parsing [%s:%d] : '%s' requires a header string.\n",
1507 file, linenum, args[0]);
1508 err_code |= ERR_ALERT | ERR_FATAL;
1509 goto out;
1510 }
1511
1512 /* set the desired header name */
1513 free(curproxy->server_id_hdr_name);
1514 curproxy->server_id_hdr_name = strdup(args[1]);
1515 curproxy->server_id_hdr_len = strlen(curproxy->server_id_hdr_name);
1516 }
1517 else if (!strcmp(args[0], "block")) { /* early blocking based on ACLs */
1518 struct act_rule *rule;
1519
1520 if (curproxy == &defproxy) {
1521 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1522 err_code |= ERR_ALERT | ERR_FATAL;
1523 goto out;
1524 }
1525
1526 /* emulate "block" using "http-request block". Since these rules are supposed to
1527 * be processed before all http-request rules, we put them into their own list
1528 * and will insert them at the end.
1529 */
1530 rule = parse_http_req_cond((const char **)args, file, linenum, curproxy);
1531 if (!rule) {
1532 err_code |= ERR_ALERT | ERR_ABORT;
1533 goto out;
1534 }
1535 err_code |= warnif_misplaced_block(curproxy, file, linenum, args[0]);
1536 err_code |= warnif_cond_conflicts(rule->cond,
1537 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1538 file, linenum);
1539 LIST_ADDQ(&curproxy->block_rules, &rule->list);
1540
1541 if (!already_warned(WARN_BLOCK_DEPRECATED))
1542 ha_warning("parsing [%s:%d] : The '%s' directive is now deprecated in favor of 'http-request deny' which uses the exact same syntax. The rules are translated but support might disappear in a future version.\n", file, linenum, args[0]);
1543
1544 }
1545 else if (!strcmp(args[0], "redirect")) {
1546 struct redirect_rule *rule;
1547
1548 if (curproxy == &defproxy) {
1549 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1550 err_code |= ERR_ALERT | ERR_FATAL;
1551 goto out;
1552 }
1553
1554 if ((rule = http_parse_redirect_rule(file, linenum, curproxy, (const char **)args + 1, &errmsg, 0, 0)) == NULL) {
1555 ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing redirect rule : %s.\n",
1556 file, linenum, proxy_type_str(curproxy), curproxy->id, errmsg);
1557 err_code |= ERR_ALERT | ERR_FATAL;
1558 goto out;
1559 }
1560
1561 LIST_ADDQ(&curproxy->redirect_rules, &rule->list);
1562 err_code |= warnif_misplaced_redirect(curproxy, file, linenum, args[0]);
1563 err_code |= warnif_cond_conflicts(rule->cond,
1564 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1565 file, linenum);
1566 }
1567 else if (!strcmp(args[0], "use_backend")) {
1568 struct switching_rule *rule;
1569
1570 if (curproxy == &defproxy) {
1571 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1572 err_code |= ERR_ALERT | ERR_FATAL;
1573 goto out;
1574 }
1575
1576 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1577 err_code |= ERR_WARN;
1578
1579 if (*(args[1]) == 0) {
1580 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
1581 err_code |= ERR_ALERT | ERR_FATAL;
1582 goto out;
1583 }
1584
1585 if (strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0) {
1586 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1587 ha_alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
1588 file, linenum, errmsg);
1589 err_code |= ERR_ALERT | ERR_FATAL;
1590 goto out;
1591 }
1592
1593 err_code |= warnif_cond_conflicts(cond, SMP_VAL_FE_SET_BCK, file, linenum);
1594 }
1595 else if (*args[2]) {
1596 ha_alert("parsing [%s:%d] : unexpected keyword '%s' after switching rule, only 'if' and 'unless' are allowed.\n",
1597 file, linenum, args[2]);
1598 err_code |= ERR_ALERT | ERR_FATAL;
1599 goto out;
1600 }
1601
1602 rule = calloc(1, sizeof(*rule));
1603 if (!rule) {
1604 ha_alert("Out of memory error.\n");
1605 goto out;
1606 }
1607 rule->cond = cond;
1608 rule->be.name = strdup(args[1]);
1609 rule->line = linenum;
1610 rule->file = strdup(file);
1611 if (!rule->file) {
1612 ha_alert("Out of memory error.\n");
1613 goto out;
1614 }
1615 LIST_INIT(&rule->list);
1616 LIST_ADDQ(&curproxy->switching_rules, &rule->list);
1617 }
1618 else if (strcmp(args[0], "use-server") == 0) {
1619 struct server_rule *rule;
1620
1621 if (curproxy == &defproxy) {
1622 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1623 err_code |= ERR_ALERT | ERR_FATAL;
1624 goto out;
1625 }
1626
1627 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1628 err_code |= ERR_WARN;
1629
1630 if (*(args[1]) == 0) {
1631 ha_alert("parsing [%s:%d] : '%s' expects a server name.\n", file, linenum, args[0]);
1632 err_code |= ERR_ALERT | ERR_FATAL;
1633 goto out;
1634 }
1635
1636 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
1637 ha_alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1638 file, linenum, args[0]);
1639 err_code |= ERR_ALERT | ERR_FATAL;
1640 goto out;
1641 }
1642
1643 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1644 ha_alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
1645 file, linenum, errmsg);
1646 err_code |= ERR_ALERT | ERR_FATAL;
1647 goto out;
1648 }
1649
1650 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, file, linenum);
1651
1652 rule = calloc(1, sizeof(*rule));
1653 rule->cond = cond;
1654 rule->srv.name = strdup(args[1]);
1655 LIST_INIT(&rule->list);
1656 LIST_ADDQ(&curproxy->server_rules, &rule->list);
1657 curproxy->be_req_ana |= AN_REQ_SRV_RULES;
1658 }
1659 else if ((!strcmp(args[0], "force-persist")) ||
1660 (!strcmp(args[0], "ignore-persist"))) {
1661 struct persist_rule *rule;
1662
1663 if (curproxy == &defproxy) {
1664 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1665 err_code |= ERR_ALERT | ERR_FATAL;
1666 goto out;
1667 }
1668
1669 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1670 err_code |= ERR_WARN;
1671
1672 if (strcmp(args[1], "if") != 0 && strcmp(args[1], "unless") != 0) {
1673 ha_alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1674 file, linenum, args[0]);
1675 err_code |= ERR_ALERT | ERR_FATAL;
1676 goto out;
1677 }
1678
1679 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 1, &errmsg)) == NULL) {
1680 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' rule : %s.\n",
1681 file, linenum, args[0], errmsg);
1682 err_code |= ERR_ALERT | ERR_FATAL;
1683 goto out;
1684 }
1685
1686 /* note: BE_REQ_CNT is the first one after FE_SET_BCK, which is
1687 * where force-persist is applied.
1688 */
1689 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_REQ_CNT, file, linenum);
1690
1691 rule = calloc(1, sizeof(*rule));
1692 rule->cond = cond;
1693 if (!strcmp(args[0], "force-persist")) {
1694 rule->type = PERSIST_TYPE_FORCE;
1695 } else {
1696 rule->type = PERSIST_TYPE_IGNORE;
1697 }
1698 LIST_INIT(&rule->list);
1699 LIST_ADDQ(&curproxy->persist_rules, &rule->list);
1700 }
1701 else if (!strcmp(args[0], "stick-table")) {
1702 int myidx = 1;
1703 struct proxy *other;
1704
1705 if (curproxy == &defproxy) {
1706 ha_alert("parsing [%s:%d] : 'stick-table' is not supported in 'defaults' section.\n",
1707 file, linenum);
1708 err_code |= ERR_ALERT | ERR_FATAL;
1709 goto out;
1710 }
1711
1712 other = proxy_tbl_by_name(curproxy->id);
1713 if (other) {
1714 ha_alert("parsing [%s:%d] : stick-table name '%s' conflicts with table declared in %s '%s' at %s:%d.\n",
1715 file, linenum, curproxy->id, proxy_type_str(other), other->id, other->conf.file, other->conf.line);
1716 err_code |= ERR_ALERT | ERR_FATAL;
1717 goto out;
1718 }
1719
1720 curproxy->table.id = curproxy->id;
1721 curproxy->table.type = (unsigned int)-1;
1722 while (*args[myidx]) {
1723 const char *err;
1724
1725 if (strcmp(args[myidx], "size") == 0) {
1726 myidx++;
1727 if (!*(args[myidx])) {
1728 ha_alert("parsing [%s:%d] : stick-table: missing argument after '%s'.\n",
1729 file, linenum, args[myidx-1]);
1730 err_code |= ERR_ALERT | ERR_FATAL;
1731 goto out;
1732 }
1733 if ((err = parse_size_err(args[myidx], &curproxy->table.size))) {
1734 ha_alert("parsing [%s:%d] : stick-table: unexpected character '%c' in argument of '%s'.\n",
1735 file, linenum, *err, args[myidx-1]);
1736 err_code |= ERR_ALERT | ERR_FATAL;
1737 goto out;
1738 }
1739 myidx++;
1740 }
1741 else if (strcmp(args[myidx], "peers") == 0) {
1742 myidx++;
1743 if (!*(args[myidx])) {
1744 ha_alert("parsing [%s:%d] : stick-table: missing argument after '%s'.\n",
1745 file, linenum, args[myidx-1]);
1746 err_code |= ERR_ALERT | ERR_FATAL;
1747 goto out;
1748 }
1749 curproxy->table.peers.name = strdup(args[myidx++]);
1750 }
1751 else if (strcmp(args[myidx], "expire") == 0) {
1752 myidx++;
1753 if (!*(args[myidx])) {
1754 ha_alert("parsing [%s:%d] : stick-table: missing argument after '%s'.\n",
1755 file, linenum, args[myidx-1]);
1756 err_code |= ERR_ALERT | ERR_FATAL;
1757 goto out;
1758 }
1759 err = parse_time_err(args[myidx], &val, TIME_UNIT_MS);
1760 if (err) {
1761 ha_alert("parsing [%s:%d] : stick-table: unexpected character '%c' in argument of '%s'.\n",
1762 file, linenum, *err, args[myidx-1]);
1763 err_code |= ERR_ALERT | ERR_FATAL;
1764 goto out;
1765 }
1766 if (val > INT_MAX) {
1767 ha_alert("parsing [%s:%d] : Expire value [%u]ms exceeds maxmimum value of 24.85 days.\n",
1768 file, linenum, val);
1769 err_code |= ERR_ALERT | ERR_FATAL;
1770 goto out;
1771 }
1772 curproxy->table.expire = val;
1773 myidx++;
1774 }
1775 else if (strcmp(args[myidx], "nopurge") == 0) {
1776 curproxy->table.nopurge = 1;
1777 myidx++;
1778 }
1779 else if (strcmp(args[myidx], "type") == 0) {
1780 myidx++;
1781 if (stktable_parse_type(args, &myidx, &curproxy->table.type, &curproxy->table.key_size) != 0) {
1782 ha_alert("parsing [%s:%d] : stick-table: unknown type '%s'.\n",
1783 file, linenum, args[myidx]);
1784 err_code |= ERR_ALERT | ERR_FATAL;
1785 goto out;
1786 }
1787 /* myidx already points to next arg */
1788 }
1789 else if (strcmp(args[myidx], "store") == 0) {
1790 int type, err;
1791 char *cw, *nw, *sa;
1792
1793 myidx++;
1794 nw = args[myidx];
1795 while (*nw) {
1796 /* the "store" keyword supports a comma-separated list */
1797 cw = nw;
1798 sa = NULL; /* store arg */
1799 while (*nw && *nw != ',') {
1800 if (*nw == '(') {
1801 *nw = 0;
1802 sa = ++nw;
1803 while (*nw != ')') {
1804 if (!*nw) {
1805 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
1806 file, linenum, args[0], cw);
1807 err_code |= ERR_ALERT | ERR_FATAL;
1808 goto out;
1809 }
1810 nw++;
1811 }
1812 *nw = '\0';
1813 }
1814 nw++;
1815 }
1816 if (*nw)
1817 *nw++ = '\0';
1818 type = stktable_get_data_type(cw);
1819 if (type < 0) {
1820 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
1821 file, linenum, args[0], cw);
1822 err_code |= ERR_ALERT | ERR_FATAL;
1823 goto out;
1824 }
1825
1826 err = stktable_alloc_data_type(&curproxy->table, type, sa);
1827 switch (err) {
1828 case PE_NONE: break;
1829 case PE_EXIST:
1830 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
1831 file, linenum, args[0], cw);
1832 err_code |= ERR_WARN;
1833 break;
1834
1835 case PE_ARG_MISSING:
1836 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
1837 file, linenum, args[0], cw);
1838 err_code |= ERR_ALERT | ERR_FATAL;
1839 goto out;
1840
1841 case PE_ARG_NOT_USED:
1842 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
1843 file, linenum, args[0], cw);
1844 err_code |= ERR_ALERT | ERR_FATAL;
1845 goto out;
1846
1847 default:
1848 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
1849 file, linenum, args[0], cw);
1850 err_code |= ERR_ALERT | ERR_FATAL;
1851 goto out;
1852 }
1853 }
1854 myidx++;
1855 }
1856 else {
1857 ha_alert("parsing [%s:%d] : stick-table: unknown argument '%s'.\n",
1858 file, linenum, args[myidx]);
1859 err_code |= ERR_ALERT | ERR_FATAL;
1860 goto out;
1861 }
1862 }
1863
1864 if (!curproxy->table.size) {
1865 ha_alert("parsing [%s:%d] : stick-table: missing size.\n",
1866 file, linenum);
1867 err_code |= ERR_ALERT | ERR_FATAL;
1868 goto out;
1869 }
1870
1871 if (curproxy->table.type == (unsigned int)-1) {
1872 ha_alert("parsing [%s:%d] : stick-table: missing type.\n",
1873 file, linenum);
1874 err_code |= ERR_ALERT | ERR_FATAL;
1875 goto out;
1876 }
1877 }
1878 else if (!strcmp(args[0], "stick")) {
1879 struct sticking_rule *rule;
1880 struct sample_expr *expr;
1881 int myidx = 0;
1882 const char *name = NULL;
1883 int flags;
1884
1885 if (curproxy == &defproxy) {
1886 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1887 err_code |= ERR_ALERT | ERR_FATAL;
1888 goto out;
1889 }
1890
1891 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) {
1892 err_code |= ERR_WARN;
1893 goto out;
1894 }
1895
1896 myidx++;
1897 if ((strcmp(args[myidx], "store") == 0) ||
1898 (strcmp(args[myidx], "store-request") == 0)) {
1899 myidx++;
1900 flags = STK_IS_STORE;
1901 }
1902 else if (strcmp(args[myidx], "store-response") == 0) {
1903 myidx++;
1904 flags = STK_IS_STORE | STK_ON_RSP;
1905 }
1906 else if (strcmp(args[myidx], "match") == 0) {
1907 myidx++;
1908 flags = STK_IS_MATCH;
1909 }
1910 else if (strcmp(args[myidx], "on") == 0) {
1911 myidx++;
1912 flags = STK_IS_MATCH | STK_IS_STORE;
1913 }
1914 else {
1915 ha_alert("parsing [%s:%d] : '%s' expects 'on', 'match', or 'store'.\n", file, linenum, args[0]);
1916 err_code |= ERR_ALERT | ERR_FATAL;
1917 goto out;
1918 }
1919
1920 if (*(args[myidx]) == 0) {
1921 ha_alert("parsing [%s:%d] : '%s' expects a fetch method.\n", file, linenum, args[0]);
1922 err_code |= ERR_ALERT | ERR_FATAL;
1923 goto out;
1924 }
1925
1926 curproxy->conf.args.ctx = ARGC_STK;
1927 expr = sample_parse_expr(args, &myidx, file, linenum, &errmsg, &curproxy->conf.args);
1928 if (!expr) {
1929 ha_alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], errmsg);
1930 err_code |= ERR_ALERT | ERR_FATAL;
1931 goto out;
1932 }
1933
1934 if (flags & STK_ON_RSP) {
1935 if (!(expr->fetch->val & SMP_VAL_BE_STO_RUL)) {
1936 ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available for 'store-response'.\n",
1937 file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
1938 err_code |= ERR_ALERT | ERR_FATAL;
1939 free(expr);
1940 goto out;
1941 }
1942 } else {
1943 if (!(expr->fetch->val & SMP_VAL_BE_SET_SRV)) {
1944 ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available during request.\n",
1945 file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
1946 err_code |= ERR_ALERT | ERR_FATAL;
1947 free(expr);
1948 goto out;
1949 }
1950 }
1951
1952 /* check if we need to allocate an hdr_idx struct for HTTP parsing */
1953 curproxy->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
1954
1955 if (strcmp(args[myidx], "table") == 0) {
1956 myidx++;
1957 name = args[myidx++];
1958 }
1959
1960 if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) {
1961 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + myidx, &errmsg)) == NULL) {
1962 ha_alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition : %s.\n",
1963 file, linenum, args[0], errmsg);
1964 err_code |= ERR_ALERT | ERR_FATAL;
1965 free(expr);
1966 goto out;
1967 }
1968 }
1969 else if (*(args[myidx])) {
1970 ha_alert("parsing [%s:%d] : '%s': unknown keyword '%s'.\n",
1971 file, linenum, args[0], args[myidx]);
1972 err_code |= ERR_ALERT | ERR_FATAL;
1973 free(expr);
1974 goto out;
1975 }
1976 if (flags & STK_ON_RSP)
1977 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_STO_RUL, file, linenum);
1978 else
1979 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, file, linenum);
1980
1981 rule = calloc(1, sizeof(*rule));
1982 rule->cond = cond;
1983 rule->expr = expr;
1984 rule->flags = flags;
1985 rule->table.name = name ? strdup(name) : NULL;
1986 LIST_INIT(&rule->list);
1987 if (flags & STK_ON_RSP)
1988 LIST_ADDQ(&curproxy->storersp_rules, &rule->list);
1989 else
1990 LIST_ADDQ(&curproxy->sticking_rules, &rule->list);
1991 }
1992 else if (!strcmp(args[0], "stats")) {
1993 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
1994 curproxy->uri_auth = NULL; /* we must detach from the default config */
1995
1996 if (!*args[1]) {
1997 goto stats_error_parsing;
1998 } else if (!strcmp(args[1], "admin")) {
1999 struct stats_admin_rule *rule;
2000
2001 if (curproxy == &defproxy) {
2002 ha_alert("parsing [%s:%d]: '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
2003 err_code |= ERR_ALERT | ERR_FATAL;
2004 goto out;
2005 }
2006
2007 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
2008 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2009 err_code |= ERR_ALERT | ERR_ABORT;
2010 goto out;
2011 }
2012
2013 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
2014 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
2015 file, linenum, args[0], args[1]);
2016 err_code |= ERR_ALERT | ERR_FATAL;
2017 goto out;
2018 }
2019 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
2020 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' rule : %s.\n",
2021 file, linenum, args[0], args[1], errmsg);
2022 err_code |= ERR_ALERT | ERR_FATAL;
2023 goto out;
2024 }
2025
2026 err_code |= warnif_cond_conflicts(cond,
2027 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
2028 file, linenum);
2029
2030 rule = calloc(1, sizeof(*rule));
2031 rule->cond = cond;
2032 LIST_INIT(&rule->list);
2033 LIST_ADDQ(&curproxy->uri_auth->admin_rules, &rule->list);
2034 } else if (!strcmp(args[1], "uri")) {
2035 if (*(args[2]) == 0) {
2036 ha_alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
2037 err_code |= ERR_ALERT | ERR_FATAL;
2038 goto out;
2039 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
2040 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2041 err_code |= ERR_ALERT | ERR_ABORT;
2042 goto out;
2043 }
2044 } else if (!strcmp(args[1], "realm")) {
2045 if (*(args[2]) == 0) {
2046 ha_alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
2047 err_code |= ERR_ALERT | ERR_FATAL;
2048 goto out;
2049 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
2050 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2051 err_code |= ERR_ALERT | ERR_ABORT;
2052 goto out;
2053 }
2054 } else if (!strcmp(args[1], "refresh")) {
2055 unsigned interval;
2056
2057 err = parse_time_err(args[2], &interval, TIME_UNIT_S);
2058 if (err) {
2059 ha_alert("parsing [%s:%d] : unexpected character '%c' in stats refresh interval.\n",
2060 file, linenum, *err);
2061 err_code |= ERR_ALERT | ERR_FATAL;
2062 goto out;
2063 } else if (!stats_set_refresh(&curproxy->uri_auth, interval)) {
2064 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2065 err_code |= ERR_ALERT | ERR_ABORT;
2066 goto out;
2067 }
2068 } else if (!strcmp(args[1], "http-request")) { /* request access control: allow/deny/auth */
2069 struct act_rule *rule;
2070
2071 if (curproxy == &defproxy) {
2072 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2073 err_code |= ERR_ALERT | ERR_FATAL;
2074 goto out;
2075 }
2076
2077 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
2078 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2079 err_code |= ERR_ALERT | ERR_ABORT;
2080 goto out;
2081 }
2082
2083 if (!LIST_ISEMPTY(&curproxy->uri_auth->http_req_rules) &&
2084 !LIST_PREV(&curproxy->uri_auth->http_req_rules, struct act_rule *, list)->cond) {
2085 ha_warning("parsing [%s:%d]: previous '%s' action has no condition attached, further entries are NOOP.\n",
2086 file, linenum, args[0]);
2087 err_code |= ERR_WARN;
2088 }
2089
2090 rule = parse_http_req_cond((const char **)args + 2, file, linenum, curproxy);
2091
2092 if (!rule) {
2093 err_code |= ERR_ALERT | ERR_ABORT;
2094 goto out;
2095 }
2096
2097 err_code |= warnif_cond_conflicts(rule->cond,
2098 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
2099 file, linenum);
2100 LIST_ADDQ(&curproxy->uri_auth->http_req_rules, &rule->list);
2101
2102 } else if (!strcmp(args[1], "auth")) {
2103 if (*(args[2]) == 0) {
2104 ha_alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
2105 err_code |= ERR_ALERT | ERR_FATAL;
2106 goto out;
2107 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
2108 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2109 err_code |= ERR_ALERT | ERR_ABORT;
2110 goto out;
2111 }
2112 } else if (!strcmp(args[1], "scope")) {
2113 if (*(args[2]) == 0) {
2114 ha_alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
2115 err_code |= ERR_ALERT | ERR_FATAL;
2116 goto out;
2117 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
2118 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2119 err_code |= ERR_ALERT | ERR_ABORT;
2120 goto out;
2121 }
2122 } else if (!strcmp(args[1], "enable")) {
2123 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
2124 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2125 err_code |= ERR_ALERT | ERR_ABORT;
2126 goto out;
2127 }
2128 } else if (!strcmp(args[1], "hide-version")) {
2129 if (!stats_set_flag(&curproxy->uri_auth, ST_HIDEVER)) {
2130 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2131 err_code |= ERR_ALERT | ERR_ABORT;
2132 goto out;
2133 }
2134 } else if (!strcmp(args[1], "show-legends")) {
2135 if (!stats_set_flag(&curproxy->uri_auth, ST_SHLGNDS)) {
2136 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2137 err_code |= ERR_ALERT | ERR_ABORT;
2138 goto out;
2139 }
2140 } else if (!strcmp(args[1], "show-node")) {
2141
2142 if (*args[2]) {
2143 int i;
2144 char c;
2145
2146 for (i=0; args[2][i]; i++) {
2147 c = args[2][i];
2148 if (!isupper((unsigned char)c) && !islower((unsigned char)c) &&
2149 !isdigit((unsigned char)c) && c != '_' && c != '-' && c != '.')
2150 break;
2151 }
2152
2153 if (!i || args[2][i]) {
2154 ha_alert("parsing [%s:%d]: '%s %s' invalid node name - should be a string"
2155 "with digits(0-9), letters(A-Z, a-z), hyphen(-) or underscode(_).\n",
2156 file, linenum, args[0], args[1]);
2157 err_code |= ERR_ALERT | ERR_FATAL;
2158 goto out;
2159 }
2160 }
2161
2162 if (!stats_set_node(&curproxy->uri_auth, args[2])) {
2163 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2164 err_code |= ERR_ALERT | ERR_ABORT;
2165 goto out;
2166 }
2167 } else if (!strcmp(args[1], "show-desc")) {
2168 char *desc = NULL;
2169
2170 if (*args[2]) {
2171 int i, len=0;
2172 char *d;
2173
2174 for (i = 2; *args[i]; i++)
2175 len += strlen(args[i]) + 1;
2176
2177 desc = d = calloc(1, len);
2178
2179 d += snprintf(d, desc + len - d, "%s", args[2]);
2180 for (i = 3; *args[i]; i++)
2181 d += snprintf(d, desc + len - d, " %s", args[i]);
2182 }
2183
2184 if (!*args[2] && !global.desc)
2185 ha_warning("parsing [%s:%d]: '%s' requires a parameter or 'desc' to be set in the global section.\n",
2186 file, linenum, args[1]);
2187 else {
2188 if (!stats_set_desc(&curproxy->uri_auth, desc)) {
2189 free(desc);
2190 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2191 err_code |= ERR_ALERT | ERR_ABORT;
2192 goto out;
2193 }
2194 free(desc);
2195 }
2196 } else {
2197stats_error_parsing:
2198 ha_alert("parsing [%s:%d]: %s '%s', expects 'admin', 'uri', 'realm', 'auth', 'scope', 'enable', 'hide-version', 'show-node', 'show-desc' or 'show-legends'.\n",
2199 file, linenum, *args[1]?"unknown stats parameter":"missing keyword in", args[*args[1]?1:0]);
2200 err_code |= ERR_ALERT | ERR_FATAL;
2201 goto out;
2202 }
2203 }
2204 else if (!strcmp(args[0], "option")) {
2205 int optnum;
2206
2207 if (*(args[1]) == '\0') {
2208 ha_alert("parsing [%s:%d]: '%s' expects an option name.\n",
2209 file, linenum, args[0]);
2210 err_code |= ERR_ALERT | ERR_FATAL;
2211 goto out;
2212 }
2213
2214 for (optnum = 0; cfg_opts[optnum].name; optnum++) {
2215 if (!strcmp(args[1], cfg_opts[optnum].name)) {
2216 if (cfg_opts[optnum].cap == PR_CAP_NONE) {
2217 ha_alert("parsing [%s:%d]: option '%s' is not supported due to build options.\n",
2218 file, linenum, cfg_opts[optnum].name);
2219 err_code |= ERR_ALERT | ERR_FATAL;
2220 goto out;
2221 }
2222 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2223 goto out;
2224
2225 if (warnifnotcap(curproxy, cfg_opts[optnum].cap, file, linenum, args[1], NULL)) {
2226 err_code |= ERR_WARN;
2227 goto out;
2228 }
2229
2230 curproxy->no_options &= ~cfg_opts[optnum].val;
2231 curproxy->options &= ~cfg_opts[optnum].val;
2232
2233 switch (kwm) {
2234 case KWM_STD:
2235 curproxy->options |= cfg_opts[optnum].val;
2236 break;
2237 case KWM_NO:
2238 curproxy->no_options |= cfg_opts[optnum].val;
2239 break;
2240 case KWM_DEF: /* already cleared */
2241 break;
2242 }
2243
2244 goto out;
2245 }
2246 }
2247
2248 for (optnum = 0; cfg_opts2[optnum].name; optnum++) {
2249 if (!strcmp(args[1], cfg_opts2[optnum].name)) {
2250 if (cfg_opts2[optnum].cap == PR_CAP_NONE) {
2251 ha_alert("parsing [%s:%d]: option '%s' is not supported due to build options.\n",
2252 file, linenum, cfg_opts2[optnum].name);
2253 err_code |= ERR_ALERT | ERR_FATAL;
2254 goto out;
2255 }
2256 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2257 goto out;
2258 if (warnifnotcap(curproxy, cfg_opts2[optnum].cap, file, linenum, args[1], NULL)) {
2259 err_code |= ERR_WARN;
2260 goto out;
2261 }
2262
2263 curproxy->no_options2 &= ~cfg_opts2[optnum].val;
2264 curproxy->options2 &= ~cfg_opts2[optnum].val;
2265
2266 switch (kwm) {
2267 case KWM_STD:
2268 curproxy->options2 |= cfg_opts2[optnum].val;
2269 break;
2270 case KWM_NO:
2271 curproxy->no_options2 |= cfg_opts2[optnum].val;
2272 break;
2273 case KWM_DEF: /* already cleared */
2274 break;
2275 }
2276 goto out;
2277 }
2278 }
2279
2280 /* HTTP options override each other. They can be cancelled using
2281 * "no option xxx" which only switches to default mode if the mode
2282 * was this one (useful for cancelling options set in defaults
2283 * sections).
2284 */
2285 if (strcmp(args[1], "httpclose") == 0 || strcmp(args[1], "forceclose") == 0) {
2286 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2287 goto out;
2288 if (kwm == KWM_STD) {
2289 curproxy->options &= ~PR_O_HTTP_MODE;
2290 curproxy->options |= PR_O_HTTP_CLO;
2291 goto out;
2292 }
2293 else if (kwm == KWM_NO) {
2294 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_CLO)
2295 curproxy->options &= ~PR_O_HTTP_MODE;
2296 goto out;
2297 }
2298 }
2299 else if (strcmp(args[1], "http-server-close") == 0) {
2300 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2301 goto out;
2302 if (kwm == KWM_STD) {
2303 curproxy->options &= ~PR_O_HTTP_MODE;
2304 curproxy->options |= PR_O_HTTP_SCL;
2305 goto out;
2306 }
2307 else if (kwm == KWM_NO) {
2308 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL)
2309 curproxy->options &= ~PR_O_HTTP_MODE;
2310 goto out;
2311 }
2312 }
2313 else if (strcmp(args[1], "http-keep-alive") == 0) {
2314 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2315 goto out;
2316 if (kwm == KWM_STD) {
2317 curproxy->options &= ~PR_O_HTTP_MODE;
2318 curproxy->options |= PR_O_HTTP_KAL;
2319 goto out;
2320 }
2321 else if (kwm == KWM_NO) {
2322 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_KAL)
2323 curproxy->options &= ~PR_O_HTTP_MODE;
2324 goto out;
2325 }
2326 }
2327 else if (strcmp(args[1], "http-tunnel") == 0) {
2328 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[1], NULL)) {
2329 err_code |= ERR_WARN;
2330 goto out;
2331 }
2332 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2333 goto out;
2334 if (kwm == KWM_STD) {
2335 curproxy->options &= ~PR_O_HTTP_MODE;
2336 curproxy->options |= PR_O_HTTP_TUN;
2337 goto out;
2338 }
2339 else if (kwm == KWM_NO) {
2340 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN)
2341 curproxy->options &= ~PR_O_HTTP_MODE;
2342 goto out;
2343 }
2344 }
2345
2346 /* Redispatch can take an integer argument that control when the
2347 * resispatch occurs. All values are relative to the retries option.
2348 * This can be cancelled using "no option xxx".
2349 */
2350 if (strcmp(args[1], "redispatch") == 0) {
2351 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL)) {
2352 err_code |= ERR_WARN;
2353 goto out;
2354 }
2355
2356 curproxy->no_options &= ~PR_O_REDISP;
2357 curproxy->options &= ~PR_O_REDISP;
2358
2359 switch (kwm) {
2360 case KWM_STD:
2361 curproxy->options |= PR_O_REDISP;
2362 curproxy->redispatch_after = -1;
2363 if(*args[2]) {
2364 curproxy->redispatch_after = atol(args[2]);
2365 }
2366 break;
2367 case KWM_NO:
2368 curproxy->no_options |= PR_O_REDISP;
2369 curproxy->redispatch_after = 0;
2370 break;
2371 case KWM_DEF: /* already cleared */
2372 break;
2373 }
2374 goto out;
2375 }
2376
2377 if (kwm != KWM_STD) {
2378 ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
2379 file, linenum, args[1]);
2380 err_code |= ERR_ALERT | ERR_FATAL;
2381 goto out;
2382 }
2383
2384 if (!strcmp(args[1], "httplog")) {
2385 char *logformat;
2386 /* generate a complete HTTP log */
2387 logformat = default_http_log_format;
2388 if (*(args[2]) != '\0') {
2389 if (!strcmp(args[2], "clf")) {
2390 curproxy->options2 |= PR_O2_CLFLOG;
2391 logformat = clf_http_log_format;
2392 } else {
2393 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'clf'.\n", file, linenum, args[1]);
2394 err_code |= ERR_ALERT | ERR_FATAL;
2395 goto out;
2396 }
2397 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
2398 goto out;
2399 }
2400 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2401 char *oldlogformat = "log-format";
2402 char *clflogformat = "";
2403
2404 if (curproxy->conf.logformat_string == default_http_log_format)
2405 oldlogformat = "option httplog";
2406 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2407 oldlogformat = "option tcplog";
2408 else if (curproxy->conf.logformat_string == clf_http_log_format)
2409 oldlogformat = "option httplog clf";
2410 if (logformat == clf_http_log_format)
2411 clflogformat = " clf";
2412 ha_warning("parsing [%s:%d]: 'option httplog%s' overrides previous '%s' in 'defaults' section.\n",
2413 file, linenum, clflogformat, oldlogformat);
2414 }
2415 if (curproxy->conf.logformat_string != default_http_log_format &&
2416 curproxy->conf.logformat_string != default_tcp_log_format &&
2417 curproxy->conf.logformat_string != clf_http_log_format)
2418 free(curproxy->conf.logformat_string);
2419 curproxy->conf.logformat_string = logformat;
2420
2421 free(curproxy->conf.lfs_file);
2422 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2423 curproxy->conf.lfs_line = curproxy->conf.args.line;
2424
2425 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2426 ha_warning("parsing [%s:%d] : backend '%s' : 'option httplog' directive is ignored in backends.\n",
2427 file, linenum, curproxy->id);
2428 err_code |= ERR_WARN;
2429 }
2430 }
2431 else if (!strcmp(args[1], "tcplog")) {
2432 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2433 char *oldlogformat = "log-format";
2434
2435 if (curproxy->conf.logformat_string == default_http_log_format)
2436 oldlogformat = "option httplog";
2437 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2438 oldlogformat = "option tcplog";
2439 else if (curproxy->conf.logformat_string == clf_http_log_format)
2440 oldlogformat = "option httplog clf";
2441 ha_warning("parsing [%s:%d]: 'option tcplog' overrides previous '%s' in 'defaults' section.\n",
2442 file, linenum, oldlogformat);
2443 }
2444 /* generate a detailed TCP log */
2445 if (curproxy->conf.logformat_string != default_http_log_format &&
2446 curproxy->conf.logformat_string != default_tcp_log_format &&
2447 curproxy->conf.logformat_string != clf_http_log_format)
2448 free(curproxy->conf.logformat_string);
2449 curproxy->conf.logformat_string = default_tcp_log_format;
2450
2451 free(curproxy->conf.lfs_file);
2452 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2453 curproxy->conf.lfs_line = curproxy->conf.args.line;
2454
2455 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2456 goto out;
2457
2458 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2459 ha_warning("parsing [%s:%d] : backend '%s' : 'option tcplog' directive is ignored in backends.\n",
2460 file, linenum, curproxy->id);
2461 err_code |= ERR_WARN;
2462 }
2463 }
2464 else if (!strcmp(args[1], "tcpka")) {
2465 /* enable TCP keep-alives on client and server streams */
2466 if (warnifnotcap(curproxy, PR_CAP_BE | PR_CAP_FE, file, linenum, args[1], NULL))
2467 err_code |= ERR_WARN;
2468
2469 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2470 goto out;
2471
2472 if (curproxy->cap & PR_CAP_FE)
2473 curproxy->options |= PR_O_TCP_CLI_KA;
2474 if (curproxy->cap & PR_CAP_BE)
2475 curproxy->options |= PR_O_TCP_SRV_KA;
2476 }
2477 else if (!strcmp(args[1], "httpchk")) {
2478 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2479 err_code |= ERR_WARN;
2480
2481 /* use HTTP request to check servers' health */
2482 free(curproxy->check_req);
2483 curproxy->check_req = NULL;
2484 curproxy->options2 &= ~PR_O2_CHK_ANY;
2485 curproxy->options2 |= PR_O2_HTTP_CHK;
2486 if (!*args[2]) { /* no argument */
2487 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
2488 curproxy->check_len = strlen(DEF_CHECK_REQ);
2489 } else if (!*args[3]) { /* one argument : URI */
2490 int reqlen = strlen(args[2]) + strlen("OPTIONS HTTP/1.0\r\n") + 1;
2491 curproxy->check_req = malloc(reqlen);
2492 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2493 "OPTIONS %s HTTP/1.0\r\n", args[2]); /* URI to use */
2494 } else { /* more arguments : METHOD URI [HTTP_VER] */
2495 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n");
2496 if (*args[4])
2497 reqlen += strlen(args[4]);
2498 else
2499 reqlen += strlen("HTTP/1.0");
2500
2501 curproxy->check_req = malloc(reqlen);
2502 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2503 "%s %s %s\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
2504 }
2505 if (alertif_too_many_args_idx(3, 1, file, linenum, args, &err_code))
2506 goto out;
2507 }
2508 else if (!strcmp(args[1], "ssl-hello-chk")) {
2509 /* use SSLv3 CLIENT HELLO to check servers' health */
2510 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2511 err_code |= ERR_WARN;
2512
2513 free(curproxy->check_req);
2514 curproxy->check_req = NULL;
2515 curproxy->options2 &= ~PR_O2_CHK_ANY;
2516 curproxy->options2 |= PR_O2_SSL3_CHK;
2517
2518 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2519 goto out;
2520 }
2521 else if (!strcmp(args[1], "smtpchk")) {
2522 /* use SMTP request to check servers' health */
2523 free(curproxy->check_req);
2524 curproxy->check_req = NULL;
2525 curproxy->options2 &= ~PR_O2_CHK_ANY;
2526 curproxy->options2 |= PR_O2_SMTP_CHK;
2527
2528 if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */
2529 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2530 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2531 } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */
2532 if (!strcmp(args[2], "EHLO") || !strcmp(args[2], "HELO")) {
2533 int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" \r\n") + 1;
2534 curproxy->check_req = malloc(reqlen);
2535 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2536 "%s %s\r\n", args[2], args[3]); /* HELO hostname */
2537 } else {
2538 /* this just hits the default for now, but you could potentially expand it to allow for other stuff
2539 though, it's unlikely you'd want to send anything other than an EHLO or HELO */
2540 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2541 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2542 }
2543 }
2544 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2545 goto out;
2546 }
2547 else if (!strcmp(args[1], "pgsql-check")) {
2548 /* use PostgreSQL request to check servers' health */
2549 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2550 err_code |= ERR_WARN;
2551
2552 free(curproxy->check_req);
2553 curproxy->check_req = NULL;
2554 curproxy->options2 &= ~PR_O2_CHK_ANY;
2555 curproxy->options2 |= PR_O2_PGSQL_CHK;
2556
2557 if (*(args[2])) {
2558 int cur_arg = 2;
2559
2560 while (*(args[cur_arg])) {
2561 if (strcmp(args[cur_arg], "user") == 0) {
2562 char * packet;
2563 uint32_t packet_len;
2564 uint32_t pv;
2565
2566 /* suboption header - needs additional argument for it */
2567 if (*(args[cur_arg+1]) == 0) {
2568 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2569 file, linenum, args[0], args[1], args[cur_arg]);
2570 err_code |= ERR_ALERT | ERR_FATAL;
2571 goto out;
2572 }
2573
2574 /* uint32_t + uint32_t + strlen("user")+1 + strlen(username)+1 + 1 */
2575 packet_len = 4 + 4 + 5 + strlen(args[cur_arg + 1])+1 +1;
2576 pv = htonl(0x30000); /* protocol version 3.0 */
2577
2578 packet = calloc(1, packet_len);
2579
2580 memcpy(packet + 4, &pv, 4);
2581
2582 /* copy "user" */
2583 memcpy(packet + 8, "user", 4);
2584
2585 /* copy username */
2586 memcpy(packet + 13, args[cur_arg+1], strlen(args[cur_arg+1]));
2587
2588 free(curproxy->check_req);
2589 curproxy->check_req = packet;
2590 curproxy->check_len = packet_len;
2591
2592 packet_len = htonl(packet_len);
2593 memcpy(packet, &packet_len, 4);
2594 cur_arg += 2;
2595 } else {
2596 /* unknown suboption - catchall */
2597 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2598 file, linenum, args[0], args[1]);
2599 err_code |= ERR_ALERT | ERR_FATAL;
2600 goto out;
2601 }
2602 } /* end while loop */
2603 }
2604 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2605 goto out;
2606 }
2607
2608 else if (!strcmp(args[1], "redis-check")) {
2609 /* use REDIS PING request to check servers' health */
2610 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2611 err_code |= ERR_WARN;
2612
2613 free(curproxy->check_req);
2614 curproxy->check_req = NULL;
2615 curproxy->options2 &= ~PR_O2_CHK_ANY;
2616 curproxy->options2 |= PR_O2_REDIS_CHK;
2617
2618 curproxy->check_req = malloc(sizeof(DEF_REDIS_CHECK_REQ) - 1);
2619 memcpy(curproxy->check_req, DEF_REDIS_CHECK_REQ, sizeof(DEF_REDIS_CHECK_REQ) - 1);
2620 curproxy->check_len = sizeof(DEF_REDIS_CHECK_REQ) - 1;
2621
2622 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2623 goto out;
2624 }
2625
2626 else if (!strcmp(args[1], "mysql-check")) {
2627 /* use MYSQL request to check servers' health */
2628 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2629 err_code |= ERR_WARN;
2630
2631 free(curproxy->check_req);
2632 curproxy->check_req = NULL;
2633 curproxy->options2 &= ~PR_O2_CHK_ANY;
2634 curproxy->options2 |= PR_O2_MYSQL_CHK;
2635
2636 /* This is an example of a MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte.
2637 * const char mysql40_client_auth_pkt[] = {
2638 * "\x0e\x00\x00" // packet length
2639 * "\x01" // packet number
2640 * "\x00\x00" // client capabilities
2641 * "\x00\x00\x01" // max packet
2642 * "haproxy\x00" // username (null terminated string)
2643 * "\x00" // filler (always 0x00)
2644 * "\x01\x00\x00" // packet length
2645 * "\x00" // packet number
2646 * "\x01" // COM_QUIT command
2647 * };
2648 */
2649
2650 /* This is an example of a MySQL >=4.1 client Authentication packet provided by Nenad Merdanovic.
2651 * const char mysql41_client_auth_pkt[] = {
2652 * "\x0e\x00\x00\" // packet length
2653 * "\x01" // packet number
2654 * "\x00\x00\x00\x00" // client capabilities
2655 * "\x00\x00\x00\x01" // max packet
2656 * "\x21" // character set (UTF-8)
2657 * char[23] // All zeroes
2658 * "haproxy\x00" // username (null terminated string)
2659 * "\x00" // filler (always 0x00)
2660 * "\x01\x00\x00" // packet length
2661 * "\x00" // packet number
2662 * "\x01" // COM_QUIT command
2663 * };
2664 */
2665
2666
2667 if (*(args[2])) {
2668 int cur_arg = 2;
2669
2670 while (*(args[cur_arg])) {
2671 if (strcmp(args[cur_arg], "user") == 0) {
2672 char *mysqluser;
2673 int packetlen, reqlen, userlen;
2674
2675 /* suboption header - needs additional argument for it */
2676 if (*(args[cur_arg+1]) == 0) {
2677 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2678 file, linenum, args[0], args[1], args[cur_arg]);
2679 err_code |= ERR_ALERT | ERR_FATAL;
2680 goto out;
2681 }
2682 mysqluser = args[cur_arg + 1];
2683 userlen = strlen(mysqluser);
2684
2685 if (*(args[cur_arg+2])) {
2686 if (!strcmp(args[cur_arg+2], "post-41")) {
2687 packetlen = userlen + 7 + 27;
2688 reqlen = packetlen + 9;
2689
2690 free(curproxy->check_req);
2691 curproxy->check_req = calloc(1, reqlen);
2692 curproxy->check_len = reqlen;
2693
2694 snprintf(curproxy->check_req, 4, "%c%c%c",
2695 ((unsigned char) packetlen & 0xff),
2696 ((unsigned char) (packetlen >> 8) & 0xff),
2697 ((unsigned char) (packetlen >> 16) & 0xff));
2698
2699 curproxy->check_req[3] = 1;
2700 curproxy->check_req[5] = 0x82; // 130
2701 curproxy->check_req[11] = 1;
2702 curproxy->check_req[12] = 33;
2703 memcpy(&curproxy->check_req[36], mysqluser, userlen);
2704 curproxy->check_req[36 + userlen + 1 + 1] = 1;
2705 curproxy->check_req[36 + userlen + 1 + 1 + 4] = 1;
2706 cur_arg += 3;
2707 } else {
2708 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'post-41'.\n", file, linenum, args[cur_arg+2]);
2709 err_code |= ERR_ALERT | ERR_FATAL;
2710 goto out;
2711 }
2712 } else {
2713 packetlen = userlen + 7;
2714 reqlen = packetlen + 9;
2715
2716 free(curproxy->check_req);
2717 curproxy->check_req = calloc(1, reqlen);
2718 curproxy->check_len = reqlen;
2719
2720 snprintf(curproxy->check_req, 4, "%c%c%c",
2721 ((unsigned char) packetlen & 0xff),
2722 ((unsigned char) (packetlen >> 8) & 0xff),
2723 ((unsigned char) (packetlen >> 16) & 0xff));
2724
2725 curproxy->check_req[3] = 1;
2726 curproxy->check_req[5] = 0x80;
2727 curproxy->check_req[8] = 1;
2728 memcpy(&curproxy->check_req[9], mysqluser, userlen);
2729 curproxy->check_req[9 + userlen + 1 + 1] = 1;
2730 curproxy->check_req[9 + userlen + 1 + 1 + 4] = 1;
2731 cur_arg += 2;
2732 }
2733 } else {
2734 /* unknown suboption - catchall */
2735 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2736 file, linenum, args[0], args[1]);
2737 err_code |= ERR_ALERT | ERR_FATAL;
2738 goto out;
2739 }
2740 } /* end while loop */
2741 }
2742 }
2743 else if (!strcmp(args[1], "ldap-check")) {
2744 /* use LDAP request to check servers' health */
2745 free(curproxy->check_req);
2746 curproxy->check_req = NULL;
2747 curproxy->options2 &= ~PR_O2_CHK_ANY;
2748 curproxy->options2 |= PR_O2_LDAP_CHK;
2749
2750 curproxy->check_req = malloc(sizeof(DEF_LDAP_CHECK_REQ) - 1);
2751 memcpy(curproxy->check_req, DEF_LDAP_CHECK_REQ, sizeof(DEF_LDAP_CHECK_REQ) - 1);
2752 curproxy->check_len = sizeof(DEF_LDAP_CHECK_REQ) - 1;
2753 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2754 goto out;
2755 }
2756 else if (!strcmp(args[1], "spop-check")) {
2757 if (curproxy == &defproxy) {
2758 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n",
2759 file, linenum, args[0], args[1]);
2760 err_code |= ERR_ALERT | ERR_FATAL;
2761 goto out;
2762 }
2763 if (curproxy->cap & PR_CAP_FE) {
2764 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'frontend' and 'listen' sections.\n",
2765 file, linenum, args[0], args[1]);
2766 err_code |= ERR_ALERT | ERR_FATAL;
2767 goto out;
2768 }
2769
2770 /* use SPOE request to check servers' health */
2771 free(curproxy->check_req);
2772 curproxy->check_req = NULL;
2773 curproxy->options2 &= ~PR_O2_CHK_ANY;
2774 curproxy->options2 |= PR_O2_SPOP_CHK;
2775
2776 if (spoe_prepare_healthcheck_request(&curproxy->check_req, &curproxy->check_len)) {
2777 ha_alert("parsing [%s:%d] : failed to prepare SPOP healthcheck request.\n", file, linenum);
2778 err_code |= ERR_ALERT | ERR_FATAL;
2779 goto out;
2780 }
2781 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2782 goto out;
2783 }
2784 else if (!strcmp(args[1], "tcp-check")) {
2785 /* use raw TCPCHK send/expect to check servers' health */
2786 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2787 err_code |= ERR_WARN;
2788
2789 free(curproxy->check_req);
2790 curproxy->check_req = NULL;
2791 curproxy->options2 &= ~PR_O2_CHK_ANY;
2792 curproxy->options2 |= PR_O2_TCPCHK_CHK;
2793 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2794 goto out;
2795 }
2796 else if (!strcmp(args[1], "external-check")) {
2797 /* excute an external command to check servers' health */
2798 free(curproxy->check_req);
2799 curproxy->check_req = NULL;
2800 curproxy->options2 &= ~PR_O2_CHK_ANY;
2801 curproxy->options2 |= PR_O2_EXT_CHK;
2802 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2803 goto out;
2804 }
2805 else if (!strcmp(args[1], "forwardfor")) {
2806 int cur_arg;
2807
2808 /* insert x-forwarded-for field, but not for the IP address listed as an except.
2809 * set default options (ie: bitfield, header name, etc)
2810 */
2811
2812 curproxy->options |= PR_O_FWDFOR | PR_O_FF_ALWAYS;
2813
2814 free(curproxy->fwdfor_hdr_name);
2815 curproxy->fwdfor_hdr_name = strdup(DEF_XFORWARDFOR_HDR);
2816 curproxy->fwdfor_hdr_len = strlen(DEF_XFORWARDFOR_HDR);
2817
2818 /* loop to go through arguments - start at 2, since 0+1 = "option" "forwardfor" */
2819 cur_arg = 2;
2820 while (*(args[cur_arg])) {
2821 if (!strcmp(args[cur_arg], "except")) {
2822 /* suboption except - needs additional argument for it */
2823 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_net, &curproxy->except_mask)) {
2824 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2825 file, linenum, args[0], args[1], args[cur_arg]);
2826 err_code |= ERR_ALERT | ERR_FATAL;
2827 goto out;
2828 }
2829 /* flush useless bits */
2830 curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
2831 cur_arg += 2;
2832 } else if (!strcmp(args[cur_arg], "header")) {
2833 /* suboption header - needs additional argument for it */
2834 if (*(args[cur_arg+1]) == 0) {
2835 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2836 file, linenum, args[0], args[1], args[cur_arg]);
2837 err_code |= ERR_ALERT | ERR_FATAL;
2838 goto out;
2839 }
2840 free(curproxy->fwdfor_hdr_name);
2841 curproxy->fwdfor_hdr_name = strdup(args[cur_arg+1]);
2842 curproxy->fwdfor_hdr_len = strlen(curproxy->fwdfor_hdr_name);
2843 cur_arg += 2;
2844 } else if (!strcmp(args[cur_arg], "if-none")) {
2845 curproxy->options &= ~PR_O_FF_ALWAYS;
2846 cur_arg += 1;
2847 } else {
2848 /* unknown suboption - catchall */
2849 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except', 'header' and 'if-none'.\n",
2850 file, linenum, args[0], args[1]);
2851 err_code |= ERR_ALERT | ERR_FATAL;
2852 goto out;
2853 }
2854 } /* end while loop */
2855 }
2856 else if (!strcmp(args[1], "originalto")) {
2857 int cur_arg;
2858
2859 /* insert x-original-to field, but not for the IP address listed as an except.
2860 * set default options (ie: bitfield, header name, etc)
2861 */
2862
2863 curproxy->options |= PR_O_ORGTO;
2864
2865 free(curproxy->orgto_hdr_name);
2866 curproxy->orgto_hdr_name = strdup(DEF_XORIGINALTO_HDR);
2867 curproxy->orgto_hdr_len = strlen(DEF_XORIGINALTO_HDR);
2868
2869 /* loop to go through arguments - start at 2, since 0+1 = "option" "originalto" */
2870 cur_arg = 2;
2871 while (*(args[cur_arg])) {
2872 if (!strcmp(args[cur_arg], "except")) {
2873 /* suboption except - needs additional argument for it */
2874 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_to, &curproxy->except_mask_to)) {
2875 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2876 file, linenum, args[0], args[1], args[cur_arg]);
2877 err_code |= ERR_ALERT | ERR_FATAL;
2878 goto out;
2879 }
2880 /* flush useless bits */
2881 curproxy->except_to.s_addr &= curproxy->except_mask_to.s_addr;
2882 cur_arg += 2;
2883 } else if (!strcmp(args[cur_arg], "header")) {
2884 /* suboption header - needs additional argument for it */
2885 if (*(args[cur_arg+1]) == 0) {
2886 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2887 file, linenum, args[0], args[1], args[cur_arg]);
2888 err_code |= ERR_ALERT | ERR_FATAL;
2889 goto out;
2890 }
2891 free(curproxy->orgto_hdr_name);
2892 curproxy->orgto_hdr_name = strdup(args[cur_arg+1]);
2893 curproxy->orgto_hdr_len = strlen(curproxy->orgto_hdr_name);
2894 cur_arg += 2;
2895 } else {
2896 /* unknown suboption - catchall */
2897 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
2898 file, linenum, args[0], args[1]);
2899 err_code |= ERR_ALERT | ERR_FATAL;
2900 goto out;
2901 }
2902 } /* end while loop */
2903 }
2904 else {
2905 ha_alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
2906 err_code |= ERR_ALERT | ERR_FATAL;
2907 goto out;
2908 }
2909 goto out;
2910 }
2911 else if (!strcmp(args[0], "default_backend")) {
2912 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
2913 err_code |= ERR_WARN;
2914
2915 if (*(args[1]) == 0) {
2916 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
2917 err_code |= ERR_ALERT | ERR_FATAL;
2918 goto out;
2919 }
2920 free(curproxy->defbe.name);
2921 curproxy->defbe.name = strdup(args[1]);
2922
2923 if (alertif_too_many_args_idx(1, 0, file, linenum, args, &err_code))
2924 goto out;
2925 }
2926 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
2927 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2928 err_code |= ERR_WARN;
2929
2930 if (!already_warned(WARN_REDISPATCH_DEPRECATED))
2931 ha_warning("parsing [%s:%d]: keyword '%s' is deprecated in favor of 'option redispatch', and will not be supported by future versions.\n",
2932 file, linenum, args[0]);
2933 err_code |= ERR_WARN;
2934 /* enable reconnections to dispatch */
2935 curproxy->options |= PR_O_REDISP;
2936
2937 if (alertif_too_many_args_idx(1, 0, file, linenum, args, &err_code))
2938 goto out;
2939 }
2940 else if (!strcmp(args[0], "http-reuse")) {
2941 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2942 err_code |= ERR_WARN;
2943
2944 if (strcmp(args[1], "never") == 0) {
2945 /* enable a graceful server shutdown on an HTTP 404 response */
2946 curproxy->options &= ~PR_O_REUSE_MASK;
2947 curproxy->options |= PR_O_REUSE_NEVR;
2948 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2949 goto out;
2950 }
2951 else if (strcmp(args[1], "safe") == 0) {
2952 /* enable a graceful server shutdown on an HTTP 404 response */
2953 curproxy->options &= ~PR_O_REUSE_MASK;
2954 curproxy->options |= PR_O_REUSE_SAFE;
2955 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2956 goto out;
2957 }
2958 else if (strcmp(args[1], "aggressive") == 0) {
2959 curproxy->options &= ~PR_O_REUSE_MASK;
2960 curproxy->options |= PR_O_REUSE_AGGR;
2961 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2962 goto out;
2963 }
2964 else if (strcmp(args[1], "always") == 0) {
2965 /* enable a graceful server shutdown on an HTTP 404 response */
2966 curproxy->options &= ~PR_O_REUSE_MASK;
2967 curproxy->options |= PR_O_REUSE_ALWS;
2968 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2969 goto out;
2970 }
2971 else {
2972 ha_alert("parsing [%s:%d] : '%s' only supports 'never', 'safe', 'aggressive', 'always'.\n", file, linenum, args[0]);
2973 err_code |= ERR_ALERT | ERR_FATAL;
2974 goto out;
2975 }
2976 }
2977 else if (!strcmp(args[0], "http-check")) {
2978 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2979 err_code |= ERR_WARN;
2980
2981 if (strcmp(args[1], "disable-on-404") == 0) {
2982 /* enable a graceful server shutdown on an HTTP 404 response */
2983 curproxy->options |= PR_O_DISABLE404;
2984 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2985 goto out;
2986 }
2987 else if (strcmp(args[1], "send-state") == 0) {
2988 /* enable emission of the apparent state of a server in HTTP checks */
2989 curproxy->options2 |= PR_O2_CHK_SNDST;
2990 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2991 goto out;
2992 }
2993 else if (strcmp(args[1], "expect") == 0) {
2994 const char *ptr_arg;
2995 int cur_arg;
2996
2997 if (curproxy->options2 & PR_O2_EXP_TYPE) {
2998 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
2999 err_code |= ERR_ALERT | ERR_FATAL;
3000 goto out;
3001 }
3002
3003 cur_arg = 2;
3004 /* consider exclamation marks, sole or at the beginning of a word */
3005 while (*(ptr_arg = args[cur_arg])) {
3006 while (*ptr_arg == '!') {
3007 curproxy->options2 ^= PR_O2_EXP_INV;
3008 ptr_arg++;
3009 }
3010 if (*ptr_arg)
3011 break;
3012 cur_arg++;
3013 }
3014 /* now ptr_arg points to the beginning of a word past any possible
3015 * exclamation mark, and cur_arg is the argument which holds this word.
3016 */
3017 if (strcmp(ptr_arg, "status") == 0) {
3018 if (!*(args[cur_arg + 1])) {
3019 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3020 file, linenum, args[0], args[1], ptr_arg);
3021 err_code |= ERR_ALERT | ERR_FATAL;
3022 goto out;
3023 }
3024 curproxy->options2 |= PR_O2_EXP_STS;
3025 free(curproxy->expect_str);
3026 curproxy->expect_str = strdup(args[cur_arg + 1]);
3027 }
3028 else if (strcmp(ptr_arg, "string") == 0) {
3029 if (!*(args[cur_arg + 1])) {
3030 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3031 file, linenum, args[0], args[1], ptr_arg);
3032 err_code |= ERR_ALERT | ERR_FATAL;
3033 goto out;
3034 }
3035 curproxy->options2 |= PR_O2_EXP_STR;
3036 free(curproxy->expect_str);
3037 curproxy->expect_str = strdup(args[cur_arg + 1]);
3038 }
3039 else if (strcmp(ptr_arg, "rstatus") == 0) {
3040 if (!*(args[cur_arg + 1])) {
3041 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3042 file, linenum, args[0], args[1], ptr_arg);
3043 err_code |= ERR_ALERT | ERR_FATAL;
3044 goto out;
3045 }
3046 curproxy->options2 |= PR_O2_EXP_RSTS;
3047 free(curproxy->expect_str);
3048 if (curproxy->expect_regex) {
3049 regex_free(curproxy->expect_regex);
3050 free(curproxy->expect_regex);
3051 curproxy->expect_regex = NULL;
3052 }
3053 curproxy->expect_str = strdup(args[cur_arg + 1]);
3054 curproxy->expect_regex = calloc(1, sizeof(*curproxy->expect_regex));
3055 error = NULL;
3056 if (!regex_comp(args[cur_arg + 1], curproxy->expect_regex, 1, 1, &error)) {
3057 ha_alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s': %s.\n",
3058 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3059 free(error);
3060 err_code |= ERR_ALERT | ERR_FATAL;
3061 goto out;
3062 }
3063 }
3064 else if (strcmp(ptr_arg, "rstring") == 0) {
3065 if (!*(args[cur_arg + 1])) {
3066 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3067 file, linenum, args[0], args[1], ptr_arg);
3068 err_code |= ERR_ALERT | ERR_FATAL;
3069 goto out;
3070 }
3071 curproxy->options2 |= PR_O2_EXP_RSTR;
3072 free(curproxy->expect_str);
3073 if (curproxy->expect_regex) {
3074 regex_free(curproxy->expect_regex);
3075 free(curproxy->expect_regex);
3076 curproxy->expect_regex = NULL;
3077 }
3078 curproxy->expect_str = strdup(args[cur_arg + 1]);
3079 curproxy->expect_regex = calloc(1, sizeof(*curproxy->expect_regex));
3080 error = NULL;
3081 if (!regex_comp(args[cur_arg + 1], curproxy->expect_regex, 1, 1, &error)) {
3082 ha_alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s': %s.\n",
3083 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3084 free(error);
3085 err_code |= ERR_ALERT | ERR_FATAL;
3086 goto out;
3087 }
3088 }
3089 else {
3090 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'status', 'string', 'rstatus', 'rstring', found '%s'.\n",
3091 file, linenum, args[0], args[1], ptr_arg);
3092 err_code |= ERR_ALERT | ERR_FATAL;
3093 goto out;
3094 }
3095 }
3096 else {
3097 ha_alert("parsing [%s:%d] : '%s' only supports 'disable-on-404', 'send-state', 'expect'.\n", file, linenum, args[0]);
3098 err_code |= ERR_ALERT | ERR_FATAL;
3099 goto out;
3100 }
3101 }
3102 else if (!strcmp(args[0], "tcp-check")) {
3103 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3104 err_code |= ERR_WARN;
3105
3106 if (strcmp(args[1], "comment") == 0) {
3107 int cur_arg;
3108 struct tcpcheck_rule *tcpcheck;
3109
3110 cur_arg = 1;
3111 tcpcheck = calloc(1, sizeof(*tcpcheck));
3112 tcpcheck->action = TCPCHK_ACT_COMMENT;
3113
3114 if (!*args[cur_arg + 1]) {
3115 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3116 file, linenum, args[cur_arg]);
3117 err_code |= ERR_ALERT | ERR_FATAL;
3118 goto out;
3119 }
3120
3121 tcpcheck->comment = strdup(args[cur_arg + 1]);
3122
3123 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3124 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
3125 goto out;
3126 }
3127 else if (strcmp(args[1], "connect") == 0) {
3128 const char *ptr_arg;
3129 int cur_arg;
3130 struct tcpcheck_rule *tcpcheck;
3131
3132 /* check if first rule is also a 'connect' action */
3133 tcpcheck = LIST_NEXT(&curproxy->tcpcheck_rules, struct tcpcheck_rule *, list);
3134 while (&tcpcheck->list != &curproxy->tcpcheck_rules &&
3135 tcpcheck->action == TCPCHK_ACT_COMMENT) {
3136 tcpcheck = LIST_NEXT(&tcpcheck->list, struct tcpcheck_rule *, list);
3137 }
3138
3139 if (&tcpcheck->list != &curproxy->tcpcheck_rules
3140 && tcpcheck->action != TCPCHK_ACT_CONNECT) {
3141 ha_alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
3142 file, linenum);
3143 err_code |= ERR_ALERT | ERR_FATAL;
3144 goto out;
3145 }
3146
3147 cur_arg = 2;
3148 tcpcheck = calloc(1, sizeof(*tcpcheck));
3149 tcpcheck->action = TCPCHK_ACT_CONNECT;
3150
3151 /* parsing each parameters to fill up the rule */
3152 while (*(ptr_arg = args[cur_arg])) {
3153 /* tcp port */
3154 if (strcmp(args[cur_arg], "port") == 0) {
3155 if ( (atol(args[cur_arg + 1]) > 65535) ||
3156 (atol(args[cur_arg + 1]) < 1) ){
3157 ha_alert("parsing [%s:%d] : '%s %s %s' expects a valid TCP port (from range 1 to 65535), got %s.\n",
3158 file, linenum, args[0], args[1], "port", args[cur_arg + 1]);
3159 err_code |= ERR_ALERT | ERR_FATAL;
3160 goto out;
3161 }
3162 tcpcheck->port = atol(args[cur_arg + 1]);
3163 cur_arg += 2;
3164 }
3165 /* send proxy protocol */
3166 else if (strcmp(args[cur_arg], "send-proxy") == 0) {
3167 tcpcheck->conn_opts |= TCPCHK_OPT_SEND_PROXY;
3168 cur_arg++;
3169 }
3170#ifdef USE_OPENSSL
3171 else if (strcmp(args[cur_arg], "ssl") == 0) {
3172 curproxy->options |= PR_O_TCPCHK_SSL;
3173 tcpcheck->conn_opts |= TCPCHK_OPT_SSL;
3174 cur_arg++;
3175 }
3176#endif /* USE_OPENSSL */
3177 /* comment for this tcpcheck line */
3178 else if (strcmp(args[cur_arg], "comment") == 0) {
3179 if (!*args[cur_arg + 1]) {
3180 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3181 file, linenum, args[cur_arg]);
3182 err_code |= ERR_ALERT | ERR_FATAL;
3183 goto out;
3184 }
3185 tcpcheck->comment = strdup(args[cur_arg + 1]);
3186 cur_arg += 2;
3187 }
3188 else {
3189#ifdef USE_OPENSSL
3190 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n",
3191#else /* USE_OPENSSL */
3192 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or but got '%s' as argument.\n",
3193#endif /* USE_OPENSSL */
3194 file, linenum, args[0], args[1], args[cur_arg]);
3195 err_code |= ERR_ALERT | ERR_FATAL;
3196 goto out;
3197 }
3198
3199 }
3200
3201 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3202 }
3203 else if (strcmp(args[1], "send") == 0) {
3204 if (! *(args[2]) ) {
3205 /* SEND string expected */
3206 ha_alert("parsing [%s:%d] : '%s %s %s' expects <STRING> as argument.\n",
3207 file, linenum, args[0], args[1], args[2]);
3208 err_code |= ERR_ALERT | ERR_FATAL;
3209 goto out;
3210 } else {
3211 struct tcpcheck_rule *tcpcheck;
3212
3213 tcpcheck = calloc(1, sizeof(*tcpcheck));
3214
3215 tcpcheck->action = TCPCHK_ACT_SEND;
3216 tcpcheck->string_len = strlen(args[2]);
3217 tcpcheck->string = strdup(args[2]);
3218 tcpcheck->expect_regex = NULL;
3219
3220 /* comment for this tcpcheck line */
3221 if (strcmp(args[3], "comment") == 0) {
3222 if (!*args[4]) {
3223 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3224 file, linenum, args[3]);
3225 err_code |= ERR_ALERT | ERR_FATAL;
3226 goto out;
3227 }
3228 tcpcheck->comment = strdup(args[4]);
3229 }
3230
3231 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3232 }
3233 }
3234 else if (strcmp(args[1], "send-binary") == 0) {
3235 if (! *(args[2]) ) {
3236 /* SEND binary string expected */
3237 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument.\n",
3238 file, linenum, args[0], args[1], args[2]);
3239 err_code |= ERR_ALERT | ERR_FATAL;
3240 goto out;
3241 } else {
3242 struct tcpcheck_rule *tcpcheck;
3243 char *err = NULL;
3244
3245 tcpcheck = calloc(1, sizeof(*tcpcheck));
3246
3247 tcpcheck->action = TCPCHK_ACT_SEND;
3248 if (parse_binary(args[2], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3249 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3250 file, linenum, args[0], args[1], args[2], err);
3251 err_code |= ERR_ALERT | ERR_FATAL;
3252 goto out;
3253 }
3254 tcpcheck->expect_regex = NULL;
3255
3256 /* comment for this tcpcheck line */
3257 if (strcmp(args[3], "comment") == 0) {
3258 if (!*args[4]) {
3259 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3260 file, linenum, args[3]);
3261 err_code |= ERR_ALERT | ERR_FATAL;
3262 goto out;
3263 }
3264 tcpcheck->comment = strdup(args[4]);
3265 }
3266
3267 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3268 }
3269 }
3270 else if (strcmp(args[1], "expect") == 0) {
3271 const char *ptr_arg;
3272 int cur_arg;
3273 int inverse = 0;
3274
3275 if (curproxy->options2 & PR_O2_EXP_TYPE) {
3276 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
3277 err_code |= ERR_ALERT | ERR_FATAL;
3278 goto out;
3279 }
3280
3281 cur_arg = 2;
3282 /* consider exclamation marks, sole or at the beginning of a word */
3283 while (*(ptr_arg = args[cur_arg])) {
3284 while (*ptr_arg == '!') {
3285 inverse = !inverse;
3286 ptr_arg++;
3287 }
3288 if (*ptr_arg)
3289 break;
3290 cur_arg++;
3291 }
3292 /* now ptr_arg points to the beginning of a word past any possible
3293 * exclamation mark, and cur_arg is the argument which holds this word.
3294 */
3295 if (strcmp(ptr_arg, "binary") == 0) {
3296 struct tcpcheck_rule *tcpcheck;
3297 char *err = NULL;
3298
3299 if (!*(args[cur_arg + 1])) {
3300 ha_alert("parsing [%s:%d] : '%s %s %s' expects <binary string> as an argument.\n",
3301 file, linenum, args[0], args[1], ptr_arg);
3302 err_code |= ERR_ALERT | ERR_FATAL;
3303 goto out;
3304 }
3305
3306 tcpcheck = calloc(1, sizeof(*tcpcheck));
3307
3308 tcpcheck->action = TCPCHK_ACT_EXPECT;
3309 if (parse_binary(args[cur_arg + 1], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3310 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3311 file, linenum, args[0], args[1], args[2], err);
3312 err_code |= ERR_ALERT | ERR_FATAL;
3313 goto out;
3314 }
3315 tcpcheck->expect_regex = NULL;
3316 tcpcheck->inverse = inverse;
3317
3318 /* tcpcheck comment */
3319 cur_arg += 2;
3320 if (strcmp(args[cur_arg], "comment") == 0) {
3321 if (!*args[cur_arg + 1]) {
3322 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3323 file, linenum, args[cur_arg + 1]);
3324 err_code |= ERR_ALERT | ERR_FATAL;
3325 goto out;
3326 }
3327 tcpcheck->comment = strdup(args[cur_arg + 1]);
3328 }
3329
3330 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3331 }
3332 else if (strcmp(ptr_arg, "string") == 0) {
3333 struct tcpcheck_rule *tcpcheck;
3334
3335 if (!*(args[cur_arg + 1])) {
3336 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3337 file, linenum, args[0], args[1], ptr_arg);
3338 err_code |= ERR_ALERT | ERR_FATAL;
3339 goto out;
3340 }
3341
3342 tcpcheck = calloc(1, sizeof(*tcpcheck));
3343
3344 tcpcheck->action = TCPCHK_ACT_EXPECT;
3345 tcpcheck->string_len = strlen(args[cur_arg + 1]);
3346 tcpcheck->string = strdup(args[cur_arg + 1]);
3347 tcpcheck->expect_regex = NULL;
3348 tcpcheck->inverse = inverse;
3349
3350 /* tcpcheck comment */
3351 cur_arg += 2;
3352 if (strcmp(args[cur_arg], "comment") == 0) {
3353 if (!*args[cur_arg + 1]) {
3354 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3355 file, linenum, args[cur_arg + 1]);
3356 err_code |= ERR_ALERT | ERR_FATAL;
3357 goto out;
3358 }
3359 tcpcheck->comment = strdup(args[cur_arg + 1]);
3360 }
3361
3362 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3363 }
3364 else if (strcmp(ptr_arg, "rstring") == 0) {
3365 struct tcpcheck_rule *tcpcheck;
3366
3367 if (!*(args[cur_arg + 1])) {
3368 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3369 file, linenum, args[0], args[1], ptr_arg);
3370 err_code |= ERR_ALERT | ERR_FATAL;
3371 goto out;
3372 }
3373
3374 tcpcheck = calloc(1, sizeof(*tcpcheck));
3375
3376 tcpcheck->action = TCPCHK_ACT_EXPECT;
3377 tcpcheck->string_len = 0;
3378 tcpcheck->string = NULL;
3379 tcpcheck->expect_regex = calloc(1, sizeof(*tcpcheck->expect_regex));
3380 error = NULL;
3381 if (!regex_comp(args[cur_arg + 1], tcpcheck->expect_regex, 1, 1, &error)) {
3382 ha_alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s': %s.\n",
3383 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3384 free(error);
3385 err_code |= ERR_ALERT | ERR_FATAL;
3386 goto out;
3387 }
3388 tcpcheck->inverse = inverse;
3389
3390 /* tcpcheck comment */
3391 cur_arg += 2;
3392 if (strcmp(args[cur_arg], "comment") == 0) {
3393 if (!*args[cur_arg + 1]) {
3394 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3395 file, linenum, args[cur_arg + 1]);
3396 err_code |= ERR_ALERT | ERR_FATAL;
3397 goto out;
3398 }
3399 tcpcheck->comment = strdup(args[cur_arg + 1]);
3400 }
3401
3402 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3403 }
3404 else {
3405 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'binary', 'string', 'rstring', found '%s'.\n",
3406 file, linenum, args[0], args[1], ptr_arg);
3407 err_code |= ERR_ALERT | ERR_FATAL;
3408 goto out;
3409 }
3410 }
3411 else {
3412 ha_alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
3413 err_code |= ERR_ALERT | ERR_FATAL;
3414 goto out;
3415 }
3416 }
3417 else if (!strcmp(args[0], "monitor")) {
3418 if (curproxy == &defproxy) {
3419 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3420 err_code |= ERR_ALERT | ERR_FATAL;
3421 goto out;
3422 }
3423
3424 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3425 err_code |= ERR_WARN;
3426
3427 if (strcmp(args[1], "fail") == 0) {
3428 /* add a condition to fail monitor requests */
3429 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
3430 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
3431 file, linenum, args[0], args[1]);
3432 err_code |= ERR_ALERT | ERR_FATAL;
3433 goto out;
3434 }
3435
3436 err_code |= warnif_misplaced_monitor(curproxy, file, linenum, "monitor fail");
3437 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
3438 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
3439 file, linenum, args[0], args[1], errmsg);
3440 err_code |= ERR_ALERT | ERR_FATAL;
3441 goto out;
3442 }
3443 LIST_ADDQ(&curproxy->mon_fail_cond, &cond->list);
3444 }
3445 else {
3446 ha_alert("parsing [%s:%d] : '%s' only supports 'fail'.\n", file, linenum, args[0]);
3447 err_code |= ERR_ALERT | ERR_FATAL;
3448 goto out;
3449 }
3450 }
3451#ifdef TPROXY
3452 else if (!strcmp(args[0], "transparent")) {
3453 /* enable transparent proxy connections */
3454 curproxy->options |= PR_O_TRANSP;
3455 if (alertif_too_many_args(0, file, linenum, args, &err_code))
3456 goto out;
3457 }
3458#endif
3459 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3460 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
3461 err_code |= ERR_WARN;
3462
3463 if (*(args[1]) == 0) {
3464 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3465 err_code |= ERR_ALERT | ERR_FATAL;
3466 goto out;
3467 }
3468 curproxy->maxconn = atol(args[1]);
3469 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3470 goto out;
3471 }
3472 else if (!strcmp(args[0], "backlog")) { /* backlog */
3473 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3474 err_code |= ERR_WARN;
3475
3476 if (*(args[1]) == 0) {
3477 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3478 err_code |= ERR_ALERT | ERR_FATAL;
3479 goto out;
3480 }
3481 curproxy->backlog = atol(args[1]);
3482 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3483 goto out;
3484 }
3485 else if (!strcmp(args[0], "fullconn")) { /* fullconn */
3486 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
3487 err_code |= ERR_WARN;
3488
3489 if (*(args[1]) == 0) {
3490 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3491 err_code |= ERR_ALERT | ERR_FATAL;
3492 goto out;
3493 }
3494 curproxy->fullconn = atol(args[1]);
3495 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3496 goto out;
3497 }
3498 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3499 if (*(args[1]) == 0) {
3500 ha_alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
3501 err_code |= ERR_ALERT | ERR_FATAL;
3502 goto out;
3503 }
3504 err = parse_time_err(args[1], &val, TIME_UNIT_MS);
3505 if (err) {
3506 ha_alert("parsing [%s:%d] : unexpected character '%c' in grace time.\n",
3507 file, linenum, *err);
3508 err_code |= ERR_ALERT | ERR_FATAL;
3509 goto out;
3510 }
3511 curproxy->grace = val;
3512 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3513 goto out;
3514 }
3515 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3516 struct sockaddr_storage *sk;
3517 int port1, port2;
3518 struct protocol *proto;
3519
3520 if (curproxy == &defproxy) {
3521 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3522 err_code |= ERR_ALERT | ERR_FATAL;
3523 goto out;
3524 }
3525 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3526 err_code |= ERR_WARN;
3527
3528 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3529 if (!sk) {
3530 ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
3531 err_code |= ERR_ALERT | ERR_FATAL;
3532 goto out;
3533 }
3534
3535 proto = protocol_by_family(sk->ss_family);
3536 if (!proto || !proto->connect) {
3537 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3538 file, linenum, args[0], args[1]);
3539 err_code |= ERR_ALERT | ERR_FATAL;
3540 goto out;
3541 }
3542
3543 if (port1 != port2) {
3544 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'.\n",
3545 file, linenum, args[0], args[1]);
3546 err_code |= ERR_ALERT | ERR_FATAL;
3547 goto out;
3548 }
3549
3550 if (!port1) {
3551 ha_alert("parsing [%s:%d] : '%s' : missing port number in '%s', <addr:port> expected.\n",
3552 file, linenum, args[0], args[1]);
3553 err_code |= ERR_ALERT | ERR_FATAL;
3554 goto out;
3555 }
3556
3557 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3558 goto out;
3559
3560 curproxy->dispatch_addr = *sk;
3561 curproxy->options |= PR_O_DISPATCH;
3562 }
3563 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
3564 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3565 err_code |= ERR_WARN;
3566
3567 if (backend_parse_balance((const char **)args + 1, &errmsg, curproxy) < 0) {
3568 ha_alert("parsing [%s:%d] : %s %s\n", file, linenum, args[0], errmsg);
3569 err_code |= ERR_ALERT | ERR_FATAL;
3570 goto out;
3571 }
3572 }
3573 else if (!strcmp(args[0], "hash-type")) { /* set hashing method */
3574 /**
3575 * The syntax for hash-type config element is
3576 * hash-type {map-based|consistent} [[<algo>] avalanche]
3577 *
3578 * The default hash function is sdbm for map-based and sdbm+avalanche for consistent.
3579 */
3580 curproxy->lbprm.algo &= ~(BE_LB_HASH_TYPE | BE_LB_HASH_FUNC | BE_LB_HASH_MOD);
3581
3582 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3583 err_code |= ERR_WARN;
3584
3585 if (strcmp(args[1], "consistent") == 0) { /* use consistent hashing */
3586 curproxy->lbprm.algo |= BE_LB_HASH_CONS;
3587 }
3588 else if (strcmp(args[1], "map-based") == 0) { /* use map-based hashing */
3589 curproxy->lbprm.algo |= BE_LB_HASH_MAP;
3590 }
3591 else if (strcmp(args[1], "avalanche") == 0) {
3592 ha_alert("parsing [%s:%d] : experimental feature '%s %s' is not supported anymore, please use '%s map-based sdbm avalanche' instead.\n", file, linenum, args[0], args[1], args[0]);
3593 err_code |= ERR_ALERT | ERR_FATAL;
3594 goto out;
3595 }
3596 else {
3597 ha_alert("parsing [%s:%d] : '%s' only supports 'consistent' and 'map-based'.\n", file, linenum, args[0]);
3598 err_code |= ERR_ALERT | ERR_FATAL;
3599 goto out;
3600 }
3601
3602 /* set the hash function to use */
3603 if (!*args[2]) {
3604 /* the default algo is sdbm */
3605 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3606
3607 /* if consistent with no argument, then avalanche modifier is also applied */
3608 if ((curproxy->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS)
3609 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3610 } else {
3611 /* set the hash function */
3612 if (!strcmp(args[2], "sdbm")) {
3613 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3614 }
3615 else if (!strcmp(args[2], "djb2")) {
3616 curproxy->lbprm.algo |= BE_LB_HFCN_DJB2;
3617 }
3618 else if (!strcmp(args[2], "wt6")) {
3619 curproxy->lbprm.algo |= BE_LB_HFCN_WT6;
3620 }
3621 else if (!strcmp(args[2], "crc32")) {
3622 curproxy->lbprm.algo |= BE_LB_HFCN_CRC32;
3623 }
3624 else {
3625 ha_alert("parsing [%s:%d] : '%s' only supports 'sdbm', 'djb2', 'crc32', or 'wt6' hash functions.\n", file, linenum, args[0]);
3626 err_code |= ERR_ALERT | ERR_FATAL;
3627 goto out;
3628 }
3629
3630 /* set the hash modifier */
3631 if (!strcmp(args[3], "avalanche")) {
3632 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3633 }
3634 else if (*args[3]) {
3635 ha_alert("parsing [%s:%d] : '%s' only supports 'avalanche' as a modifier for hash functions.\n", file, linenum, args[0]);
3636 err_code |= ERR_ALERT | ERR_FATAL;
3637 goto out;
3638 }
3639 }
3640 }
3641 else if (strcmp(args[0], "hash-balance-factor") == 0) {
3642 if (*(args[1]) == 0) {
3643 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3644 err_code |= ERR_ALERT | ERR_FATAL;
3645 goto out;
3646 }
3647 curproxy->lbprm.chash.balance_factor = atol(args[1]);
3648 if (curproxy->lbprm.chash.balance_factor != 0 && curproxy->lbprm.chash.balance_factor <= 100) {
3649 ha_alert("parsing [%s:%d] : '%s' must be 0 or greater than 100.\n", file, linenum, args[0]);
3650 err_code |= ERR_ALERT | ERR_FATAL;
3651 goto out;
3652 }
3653 }
3654 else if (strcmp(args[0], "unique-id-format") == 0) {
3655 if (!*(args[1])) {
3656 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3657 err_code |= ERR_ALERT | ERR_FATAL;
3658 goto out;
3659 }
3660 if (*(args[2])) {
3661 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3662 err_code |= ERR_ALERT | ERR_FATAL;
3663 goto out;
3664 }
3665 free(curproxy->conf.uniqueid_format_string);
3666 curproxy->conf.uniqueid_format_string = strdup(args[1]);
3667
3668 free(curproxy->conf.uif_file);
3669 curproxy->conf.uif_file = strdup(curproxy->conf.args.file);
3670 curproxy->conf.uif_line = curproxy->conf.args.line;
3671 }
3672
3673 else if (strcmp(args[0], "unique-id-header") == 0) {
3674 if (!*(args[1])) {
3675 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3676 err_code |= ERR_ALERT | ERR_FATAL;
3677 goto out;
3678 }
3679 free(curproxy->header_unique_id);
3680 curproxy->header_unique_id = strdup(args[1]);
3681 }
3682
3683 else if (strcmp(args[0], "log-format") == 0) {
3684 if (!*(args[1])) {
3685 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3686 err_code |= ERR_ALERT | ERR_FATAL;
3687 goto out;
3688 }
3689 if (*(args[2])) {
3690 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3691 err_code |= ERR_ALERT | ERR_FATAL;
3692 goto out;
3693 }
3694 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
3695 char *oldlogformat = "log-format";
3696
3697 if (curproxy->conf.logformat_string == default_http_log_format)
3698 oldlogformat = "option httplog";
3699 else if (curproxy->conf.logformat_string == default_tcp_log_format)
3700 oldlogformat = "option tcplog";
3701 else if (curproxy->conf.logformat_string == clf_http_log_format)
3702 oldlogformat = "option httplog clf";
3703 ha_warning("parsing [%s:%d]: 'log-format' overrides previous '%s' in 'defaults' section.\n",
3704 file, linenum, oldlogformat);
3705 }
3706 if (curproxy->conf.logformat_string != default_http_log_format &&
3707 curproxy->conf.logformat_string != default_tcp_log_format &&
3708 curproxy->conf.logformat_string != clf_http_log_format)
3709 free(curproxy->conf.logformat_string);
3710 curproxy->conf.logformat_string = strdup(args[1]);
3711
3712 free(curproxy->conf.lfs_file);
3713 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
3714 curproxy->conf.lfs_line = curproxy->conf.args.line;
3715
3716 /* get a chance to improve log-format error reporting by
3717 * reporting the correct line-number when possible.
3718 */
3719 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3720 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format' directive is ignored in backends.\n",
3721 file, linenum, curproxy->id);
3722 err_code |= ERR_WARN;
3723 }
3724 }
3725 else if (!strcmp(args[0], "log-format-sd")) {
3726 if (!*(args[1])) {
3727 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3728 err_code |= ERR_ALERT | ERR_FATAL;
3729 goto out;
3730 }
3731 if (*(args[2])) {
3732 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3733 err_code |= ERR_ALERT | ERR_FATAL;
3734 goto out;
3735 }
3736
3737 if (curproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
3738 free(curproxy->conf.logformat_sd_string);
3739 curproxy->conf.logformat_sd_string = strdup(args[1]);
3740
3741 free(curproxy->conf.lfsd_file);
3742 curproxy->conf.lfsd_file = strdup(curproxy->conf.args.file);
3743 curproxy->conf.lfsd_line = curproxy->conf.args.line;
3744
3745 /* get a chance to improve log-format-sd error reporting by
3746 * reporting the correct line-number when possible.
3747 */
3748 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3749 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format-sd' directive is ignored in backends.\n",
3750 file, linenum, curproxy->id);
3751 err_code |= ERR_WARN;
3752 }
3753 }
3754 else if (!strcmp(args[0], "log-tag")) { /* tag to report to syslog */
3755 if (*(args[1]) == 0) {
3756 ha_alert("parsing [%s:%d] : '%s' expects a tag for use in syslog.\n", file, linenum, args[0]);
3757 err_code |= ERR_ALERT | ERR_FATAL;
3758 goto out;
3759 }
3760 chunk_destroy(&curproxy->log_tag);
3761 chunk_initstr(&curproxy->log_tag, strdup(args[1]));
3762 }
3763 else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
3764 if (!parse_logsrv(args, &curproxy->logsrvs, (kwm == KWM_NO), &errmsg)) {
3765 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
3766 err_code |= ERR_ALERT | ERR_FATAL;
3767 goto out;
3768 }
3769 }
3770 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
3771 int cur_arg;
3772 int port1, port2;
3773 struct sockaddr_storage *sk;
3774 struct protocol *proto;
3775
3776 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3777 err_code |= ERR_WARN;
3778
3779 if (!*args[1]) {
3780 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optionally '%s' <addr>, and '%s' <name>.\n",
3781 file, linenum, "source", "usesrc", "interface");
3782 err_code |= ERR_ALERT | ERR_FATAL;
3783 goto out;
3784 }
3785
3786 /* we must first clear any optional default setting */
3787 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3788 free(curproxy->conn_src.iface_name);
3789 curproxy->conn_src.iface_name = NULL;
3790 curproxy->conn_src.iface_len = 0;
3791
3792 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3793 if (!sk) {
3794 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3795 file, linenum, args[0], args[1], errmsg);
3796 err_code |= ERR_ALERT | ERR_FATAL;
3797 goto out;
3798 }
3799
3800 proto = protocol_by_family(sk->ss_family);
3801 if (!proto || !proto->connect) {
3802 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3803 file, linenum, args[0], args[1]);
3804 err_code |= ERR_ALERT | ERR_FATAL;
3805 goto out;
3806 }
3807
3808 if (port1 != port2) {
3809 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3810 file, linenum, args[0], args[1]);
3811 err_code |= ERR_ALERT | ERR_FATAL;
3812 goto out;
3813 }
3814
3815 curproxy->conn_src.source_addr = *sk;
3816 curproxy->conn_src.opts |= CO_SRC_BIND;
3817
3818 cur_arg = 2;
3819 while (*(args[cur_arg])) {
3820 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
3821#if defined(CONFIG_HAP_TRANSPARENT)
3822 if (!*args[cur_arg + 1]) {
3823 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
3824 file, linenum, "usesrc");
3825 err_code |= ERR_ALERT | ERR_FATAL;
3826 goto out;
3827 }
3828
3829 if (!strcmp(args[cur_arg + 1], "client")) {
3830 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3831 curproxy->conn_src.opts |= CO_SRC_TPROXY_CLI;
3832 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
3833 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3834 curproxy->conn_src.opts |= CO_SRC_TPROXY_CIP;
3835 } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
3836 char *name, *end;
3837
3838 name = args[cur_arg+1] + 7;
3839 while (isspace(*name))
3840 name++;
3841
3842 end = name;
3843 while (*end && !isspace(*end) && *end != ',' && *end != ')')
3844 end++;
3845
3846 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3847 curproxy->conn_src.opts |= CO_SRC_TPROXY_DYN;
3848 curproxy->conn_src.bind_hdr_name = calloc(1, end - name + 1);
3849 curproxy->conn_src.bind_hdr_len = end - name;
3850 memcpy(curproxy->conn_src.bind_hdr_name, name, end - name);
3851 curproxy->conn_src.bind_hdr_name[end-name] = '\0';
3852 curproxy->conn_src.bind_hdr_occ = -1;
3853
3854 /* now look for an occurrence number */
3855 while (isspace(*end))
3856 end++;
3857 if (*end == ',') {
3858 end++;
3859 name = end;
3860 if (*end == '-')
3861 end++;
3862 while (isdigit((int)*end))
3863 end++;
3864 curproxy->conn_src.bind_hdr_occ = strl2ic(name, end-name);
3865 }
3866
3867 if (curproxy->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
3868 ha_alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
3869 " occurrences values smaller than %d.\n",
3870 file, linenum, MAX_HDR_HISTORY);
3871 err_code |= ERR_ALERT | ERR_FATAL;
3872 goto out;
3873 }
3874 } else {
3875 struct sockaddr_storage *sk;
3876
3877 sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3878 if (!sk) {
3879 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3880 file, linenum, args[cur_arg], args[cur_arg+1], errmsg);
3881 err_code |= ERR_ALERT | ERR_FATAL;
3882 goto out;
3883 }
3884
3885 proto = protocol_by_family(sk->ss_family);
3886 if (!proto || !proto->connect) {
3887 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3888 file, linenum, args[cur_arg], args[cur_arg+1]);
3889 err_code |= ERR_ALERT | ERR_FATAL;
3890 goto out;
3891 }
3892
3893 if (port1 != port2) {
3894 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3895 file, linenum, args[cur_arg], args[cur_arg + 1]);
3896 err_code |= ERR_ALERT | ERR_FATAL;
3897 goto out;
3898 }
3899 curproxy->conn_src.tproxy_addr = *sk;
3900 curproxy->conn_src.opts |= CO_SRC_TPROXY_ADDR;
3901 }
3902 global.last_checks |= LSTCHK_NETADM;
3903#else /* no TPROXY support */
3904 ha_alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
3905 file, linenum, "usesrc");
3906 err_code |= ERR_ALERT | ERR_FATAL;
3907 goto out;
3908#endif
3909 cur_arg += 2;
3910 continue;
3911 }
3912
3913 if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
3914#ifdef SO_BINDTODEVICE
3915 if (!*args[cur_arg + 1]) {
3916 ha_alert("parsing [%s:%d] : '%s' : missing interface name.\n",
3917 file, linenum, args[0]);
3918 err_code |= ERR_ALERT | ERR_FATAL;
3919 goto out;
3920 }
3921 free(curproxy->conn_src.iface_name);
3922 curproxy->conn_src.iface_name = strdup(args[cur_arg + 1]);
3923 curproxy->conn_src.iface_len = strlen(curproxy->conn_src.iface_name);
3924 global.last_checks |= LSTCHK_NETADM;
3925#else
3926 ha_alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
3927 file, linenum, args[0], args[cur_arg]);
3928 err_code |= ERR_ALERT | ERR_FATAL;
3929 goto out;
3930#endif
3931 cur_arg += 2;
3932 continue;
3933 }
3934 ha_alert("parsing [%s:%d] : '%s' only supports optional keywords '%s' and '%s'.\n",
3935 file, linenum, args[0], "interface", "usesrc");
3936 err_code |= ERR_ALERT | ERR_FATAL;
3937 goto out;
3938 }
3939 }
3940 else if (!strcmp(args[0], "usesrc")) { /* address to use outside: needs "source" first */
3941 ha_alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
3942 file, linenum, "usesrc", "source");
3943 err_code |= ERR_ALERT | ERR_FATAL;
3944 goto out;
3945 }
3946 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
3947 if (*(args[2]) == 0) {
3948 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3949 file, linenum, args[0]);
3950 err_code |= ERR_ALERT | ERR_FATAL;
3951 goto out;
3952 }
3953
3954 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3955 SMP_OPT_DIR_REQ, ACT_REPLACE, 0,
3956 args[0], args[1], args[2], (const char **)args+3);
3957 if (err_code & ERR_FATAL)
3958 goto out;
3959 }
3960 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
3961 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3962 SMP_OPT_DIR_REQ, ACT_REMOVE, 0,
3963 args[0], args[1], NULL, (const char **)args+2);
3964 if (err_code & ERR_FATAL)
3965 goto out;
3966 }
3967 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
3968 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3969 SMP_OPT_DIR_REQ, ACT_DENY, 0,
3970 args[0], args[1], NULL, (const char **)args+2);
3971 if (err_code & ERR_FATAL)
3972 goto out;
3973 }
3974 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
3975 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3976 SMP_OPT_DIR_REQ, ACT_PASS, 0,
3977 args[0], args[1], NULL, (const char **)args+2);
3978 if (err_code & ERR_FATAL)
3979 goto out;
3980 }
3981 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
3982 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3983 SMP_OPT_DIR_REQ, ACT_ALLOW, 0,
3984 args[0], args[1], NULL, (const char **)args+2);
3985 if (err_code & ERR_FATAL)
3986 goto out;
3987 }
3988 else if (!strcmp(args[0], "reqtarpit")) { /* tarpit a request if a header matches this regex */
3989 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3990 SMP_OPT_DIR_REQ, ACT_TARPIT, 0,
3991 args[0], args[1], NULL, (const char **)args+2);
3992 if (err_code & ERR_FATAL)
3993 goto out;
3994 }
3995 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
3996 if (*(args[2]) == 0) {
3997 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3998 file, linenum, args[0]);
3999 err_code |= ERR_ALERT | ERR_FATAL;
4000 goto out;
4001 }
4002
4003 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4004 SMP_OPT_DIR_REQ, ACT_REPLACE, REG_ICASE,
4005 args[0], args[1], args[2], (const char **)args+3);
4006 if (err_code & ERR_FATAL)
4007 goto out;
4008 }
4009 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
4010 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4011 SMP_OPT_DIR_REQ, ACT_REMOVE, REG_ICASE,
4012 args[0], args[1], NULL, (const char **)args+2);
4013 if (err_code & ERR_FATAL)
4014 goto out;
4015 }
4016 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
4017 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4018 SMP_OPT_DIR_REQ, ACT_DENY, REG_ICASE,
4019 args[0], args[1], NULL, (const char **)args+2);
4020 if (err_code & ERR_FATAL)
4021 goto out;
4022 }
4023 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
4024 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4025 SMP_OPT_DIR_REQ, ACT_PASS, REG_ICASE,
4026 args[0], args[1], NULL, (const char **)args+2);
4027 if (err_code & ERR_FATAL)
4028 goto out;
4029 }
4030 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
4031 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4032 SMP_OPT_DIR_REQ, ACT_ALLOW, REG_ICASE,
4033 args[0], args[1], NULL, (const char **)args+2);
4034 if (err_code & ERR_FATAL)
4035 goto out;
4036 }
4037 else if (!strcmp(args[0], "reqitarpit")) { /* tarpit a request if a header matches this regex ignoring case */
4038 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4039 SMP_OPT_DIR_REQ, ACT_TARPIT, REG_ICASE,
4040 args[0], args[1], NULL, (const char **)args+2);
4041 if (err_code & ERR_FATAL)
4042 goto out;
4043 }
4044 else if (!strcmp(args[0], "reqadd")) { /* add request header */
4045 struct cond_wordlist *wl;
4046
4047 if (curproxy == &defproxy) {
4048 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4049 err_code |= ERR_ALERT | ERR_FATAL;
4050 goto out;
4051 }
4052 else if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4053 err_code |= ERR_WARN;
4054
4055 if (*(args[1]) == 0) {
4056 ha_alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
4057 err_code |= ERR_ALERT | ERR_FATAL;
4058 goto out;
4059 }
4060
4061 if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
4062 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args+2, &errmsg)) == NULL) {
4063 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
4064 file, linenum, args[0], errmsg);
4065 err_code |= ERR_ALERT | ERR_FATAL;
4066 goto out;
4067 }
4068 err_code |= warnif_cond_conflicts(cond,
4069 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
4070 file, linenum);
4071 }
4072 else if (*args[2]) {
4073 ha_alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
4074 file, linenum, args[0], args[2]);
4075 err_code |= ERR_ALERT | ERR_FATAL;
4076 goto out;
4077 }
4078
4079 wl = calloc(1, sizeof(*wl));
4080 wl->cond = cond;
4081 wl->s = strdup(args[1]);
4082 LIST_ADDQ(&curproxy->req_add, &wl->list);
4083 warnif_misplaced_reqadd(curproxy, file, linenum, args[0]);
4084 }
4085 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
4086 if (*(args[2]) == 0) {
4087 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4088 file, linenum, args[0]);
4089 err_code |= ERR_ALERT | ERR_FATAL;
4090 goto out;
4091 }
4092
4093 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4094 SMP_OPT_DIR_RES, ACT_REPLACE, 0,
4095 args[0], args[1], args[2], (const char **)args+3);
4096 if (err_code & ERR_FATAL)
4097 goto out;
4098 }
4099 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
4100 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4101 SMP_OPT_DIR_RES, ACT_REMOVE, 0,
4102 args[0], args[1], NULL, (const char **)args+2);
4103 if (err_code & ERR_FATAL)
4104 goto out;
4105 }
4106 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
4107 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4108 SMP_OPT_DIR_RES, ACT_DENY, 0,
4109 args[0], args[1], NULL, (const char **)args+2);
4110 if (err_code & ERR_FATAL)
4111 goto out;
4112 }
4113 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
4114 if (*(args[2]) == 0) {
4115 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4116 file, linenum, args[0]);
4117 err_code |= ERR_ALERT | ERR_FATAL;
4118 goto out;
4119 }
4120
4121 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4122 SMP_OPT_DIR_RES, ACT_REPLACE, REG_ICASE,
4123 args[0], args[1], args[2], (const char **)args+3);
4124 if (err_code & ERR_FATAL)
4125 goto out;
4126 }
4127 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
4128 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4129 SMP_OPT_DIR_RES, ACT_REMOVE, REG_ICASE,
4130 args[0], args[1], NULL, (const char **)args+2);
4131 if (err_code & ERR_FATAL)
4132 goto out;
4133 }
4134 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
4135 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4136 SMP_OPT_DIR_RES, ACT_DENY, REG_ICASE,
4137 args[0], args[1], NULL, (const char **)args+2);
4138 if (err_code & ERR_FATAL)
4139 goto out;
4140 }
4141 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4142 struct cond_wordlist *wl;
4143
4144 if (curproxy == &defproxy) {
4145 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4146 err_code |= ERR_ALERT | ERR_FATAL;
4147 goto out;
4148 }
4149 else if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4150 err_code |= ERR_WARN;
4151
4152 if (*(args[1]) == 0) {
4153 ha_alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
4154 err_code |= ERR_ALERT | ERR_FATAL;
4155 goto out;
4156 }
4157
4158 if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
4159 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args+2, &errmsg)) == NULL) {
4160 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
4161 file, linenum, args[0], errmsg);
4162 err_code |= ERR_ALERT | ERR_FATAL;
4163 goto out;
4164 }
4165 err_code |= warnif_cond_conflicts(cond,
4166 (curproxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
4167 file, linenum);
4168 }
4169 else if (*args[2]) {
4170 ha_alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
4171 file, linenum, args[0], args[2]);
4172 err_code |= ERR_ALERT | ERR_FATAL;
4173 goto out;
4174 }
4175
4176 wl = calloc(1, sizeof(*wl));
4177 wl->cond = cond;
4178 wl->s = strdup(args[1]);
4179 LIST_ADDQ(&curproxy->rsp_add, &wl->list);
4180 }
4181 else if (!strcmp(args[0], "errorloc") ||
4182 !strcmp(args[0], "errorloc302") ||
4183 !strcmp(args[0], "errorloc303")) { /* error location */
4184 int errnum, errlen;
4185 char *err;
4186
4187 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4188 err_code |= ERR_WARN;
4189
4190 if (*(args[2]) == 0) {
4191 ha_alert("parsing [%s:%d] : <%s> expects <status_code> and <url> as arguments.\n", file, linenum, args[0]);
4192 err_code |= ERR_ALERT | ERR_FATAL;
4193 goto out;
4194 }
4195
4196 errnum = atol(args[1]);
4197 if (!strcmp(args[0], "errorloc303")) {
4198 errlen = strlen(HTTP_303) + strlen(args[2]) + 5;
4199 err = malloc(errlen);
4200 errlen = snprintf(err, errlen, "%s%s\r\n\r\n", HTTP_303, args[2]);
4201 } else {
4202 errlen = strlen(HTTP_302) + strlen(args[2]) + 5;
4203 err = malloc(errlen);
4204 errlen = snprintf(err, errlen, "%s%s\r\n\r\n", HTTP_302, args[2]);
4205 }
4206
4207 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
4208 if (http_err_codes[rc] == errnum) {
4209 chunk_destroy(&curproxy->errmsg[rc]);
4210 chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen);
4211 break;
4212 }
4213 }
4214
4215 if (rc >= HTTP_ERR_SIZE) {
4216 ha_warning("parsing [%s:%d] : status code %d not handled by '%s', error relocation will be ignored.\n",
4217 file, linenum, errnum, args[0]);
4218 free(err);
4219 }
4220 }
4221 else if (!strcmp(args[0], "errorfile")) { /* error message from a file */
4222 int errnum, errlen, fd;
4223 char *err;
4224 struct stat stat;
4225
4226 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4227 err_code |= ERR_WARN;
4228
4229 if (*(args[2]) == 0) {
4230 ha_alert("parsing [%s:%d] : <%s> expects <status_code> and <file> as arguments.\n", file, linenum, args[0]);
4231 err_code |= ERR_ALERT | ERR_FATAL;
4232 goto out;
4233 }
4234
4235 fd = open(args[2], O_RDONLY);
4236 if ((fd < 0) || (fstat(fd, &stat) < 0)) {
4237 ha_alert("parsing [%s:%d] : error opening file <%s> for custom error message <%s>.\n",
4238 file, linenum, args[2], args[1]);
4239 if (fd >= 0)
4240 close(fd);
4241 err_code |= ERR_ALERT | ERR_FATAL;
4242 goto out;
4243 }
4244
4245 if (stat.st_size <= global.tune.bufsize) {
4246 errlen = stat.st_size;
4247 } else {
4248 ha_warning("parsing [%s:%d] : custom error message file <%s> larger than %d bytes. Truncating.\n",
4249 file, linenum, args[2], global.tune.bufsize);
4250 err_code |= ERR_WARN;
4251 errlen = global.tune.bufsize;
4252 }
4253
4254 err = malloc(errlen); /* malloc() must succeed during parsing */
4255 errnum = read(fd, err, errlen);
4256 if (errnum != errlen) {
4257 ha_alert("parsing [%s:%d] : error reading file <%s> for custom error message <%s>.\n",
4258 file, linenum, args[2], args[1]);
4259 close(fd);
4260 free(err);
4261 err_code |= ERR_ALERT | ERR_FATAL;
4262 goto out;
4263 }
4264 close(fd);
4265
4266 errnum = atol(args[1]);
4267 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
4268 if (http_err_codes[rc] == errnum) {
4269 chunk_destroy(&curproxy->errmsg[rc]);
4270 chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen);
4271 break;
4272 }
4273 }
4274
4275 if (rc >= HTTP_ERR_SIZE) {
4276 ha_warning("parsing [%s:%d] : status code %d not handled by '%s', error customization will be ignored.\n",
4277 file, linenum, errnum, args[0]);
4278 err_code |= ERR_WARN;
4279 free(err);
4280 }
4281 }
4282 else {
4283 struct cfg_kw_list *kwl;
4284 int index;
4285
4286 list_for_each_entry(kwl, &cfg_keywords.list, list) {
4287 for (index = 0; kwl->kw[index].kw != NULL; index++) {
4288 if (kwl->kw[index].section != CFG_LISTEN)
4289 continue;
4290 if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
4291 /* prepare error message just in case */
4292 rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, file, linenum, &errmsg);
4293 if (rc < 0) {
4294 ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4295 err_code |= ERR_ALERT | ERR_FATAL;
4296 goto out;
4297 }
4298 else if (rc > 0) {
4299 ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4300 err_code |= ERR_WARN;
4301 goto out;
4302 }
4303 goto out;
4304 }
4305 }
4306 }
4307
4308 ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
4309 err_code |= ERR_ALERT | ERR_FATAL;
4310 goto out;
4311 }
4312 out:
4313 free(errmsg);
4314 return err_code;
4315}