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