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