blob: 2b2785a553d6b04daf376a9dc11efd80594eab79 [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
1742 err_code |= parse_stick_table(file, linenum, args, curproxy->table, curproxy->id, NULL);
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001743 if (err_code & ERR_FATAL)
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001744 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001745
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001746 /* Store the proxy in the stick-table. */
1747 curproxy->table->proxy = curproxy;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001748
1749 stktable_store_name(curproxy->table);
1750 curproxy->table->next = stktables_list;
1751 stktables_list = curproxy->table;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001752 }
1753 else if (!strcmp(args[0], "stick")) {
1754 struct sticking_rule *rule;
1755 struct sample_expr *expr;
1756 int myidx = 0;
1757 const char *name = NULL;
1758 int flags;
1759
1760 if (curproxy == &defproxy) {
1761 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1762 err_code |= ERR_ALERT | ERR_FATAL;
1763 goto out;
1764 }
1765
1766 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) {
1767 err_code |= ERR_WARN;
1768 goto out;
1769 }
1770
1771 myidx++;
1772 if ((strcmp(args[myidx], "store") == 0) ||
1773 (strcmp(args[myidx], "store-request") == 0)) {
1774 myidx++;
1775 flags = STK_IS_STORE;
1776 }
1777 else if (strcmp(args[myidx], "store-response") == 0) {
1778 myidx++;
1779 flags = STK_IS_STORE | STK_ON_RSP;
1780 }
1781 else if (strcmp(args[myidx], "match") == 0) {
1782 myidx++;
1783 flags = STK_IS_MATCH;
1784 }
1785 else if (strcmp(args[myidx], "on") == 0) {
1786 myidx++;
1787 flags = STK_IS_MATCH | STK_IS_STORE;
1788 }
1789 else {
1790 ha_alert("parsing [%s:%d] : '%s' expects 'on', 'match', or 'store'.\n", file, linenum, args[0]);
1791 err_code |= ERR_ALERT | ERR_FATAL;
1792 goto out;
1793 }
1794
1795 if (*(args[myidx]) == 0) {
1796 ha_alert("parsing [%s:%d] : '%s' expects a fetch method.\n", file, linenum, args[0]);
1797 err_code |= ERR_ALERT | ERR_FATAL;
1798 goto out;
1799 }
1800
1801 curproxy->conf.args.ctx = ARGC_STK;
1802 expr = sample_parse_expr(args, &myidx, file, linenum, &errmsg, &curproxy->conf.args);
1803 if (!expr) {
1804 ha_alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], errmsg);
1805 err_code |= ERR_ALERT | ERR_FATAL;
1806 goto out;
1807 }
1808
1809 if (flags & STK_ON_RSP) {
1810 if (!(expr->fetch->val & SMP_VAL_BE_STO_RUL)) {
1811 ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available for 'store-response'.\n",
1812 file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
1813 err_code |= ERR_ALERT | ERR_FATAL;
1814 free(expr);
1815 goto out;
1816 }
1817 } else {
1818 if (!(expr->fetch->val & SMP_VAL_BE_SET_SRV)) {
1819 ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available during request.\n",
1820 file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
1821 err_code |= ERR_ALERT | ERR_FATAL;
1822 free(expr);
1823 goto out;
1824 }
1825 }
1826
1827 /* check if we need to allocate an hdr_idx struct for HTTP parsing */
1828 curproxy->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
1829
1830 if (strcmp(args[myidx], "table") == 0) {
1831 myidx++;
1832 name = args[myidx++];
1833 }
1834
1835 if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) {
1836 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + myidx, &errmsg)) == NULL) {
1837 ha_alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition : %s.\n",
1838 file, linenum, args[0], errmsg);
1839 err_code |= ERR_ALERT | ERR_FATAL;
1840 free(expr);
1841 goto out;
1842 }
1843 }
1844 else if (*(args[myidx])) {
1845 ha_alert("parsing [%s:%d] : '%s': unknown keyword '%s'.\n",
1846 file, linenum, args[0], args[myidx]);
1847 err_code |= ERR_ALERT | ERR_FATAL;
1848 free(expr);
1849 goto out;
1850 }
1851 if (flags & STK_ON_RSP)
1852 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_STO_RUL, file, linenum);
1853 else
1854 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, file, linenum);
1855
1856 rule = calloc(1, sizeof(*rule));
1857 rule->cond = cond;
1858 rule->expr = expr;
1859 rule->flags = flags;
1860 rule->table.name = name ? strdup(name) : NULL;
1861 LIST_INIT(&rule->list);
1862 if (flags & STK_ON_RSP)
1863 LIST_ADDQ(&curproxy->storersp_rules, &rule->list);
1864 else
1865 LIST_ADDQ(&curproxy->sticking_rules, &rule->list);
1866 }
1867 else if (!strcmp(args[0], "stats")) {
1868 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
1869 curproxy->uri_auth = NULL; /* we must detach from the default config */
1870
1871 if (!*args[1]) {
1872 goto stats_error_parsing;
1873 } else if (!strcmp(args[1], "admin")) {
1874 struct stats_admin_rule *rule;
1875
1876 if (curproxy == &defproxy) {
1877 ha_alert("parsing [%s:%d]: '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1878 err_code |= ERR_ALERT | ERR_FATAL;
1879 goto out;
1880 }
1881
1882 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1883 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1884 err_code |= ERR_ALERT | ERR_ABORT;
1885 goto out;
1886 }
1887
1888 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
1889 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
1890 file, linenum, args[0], args[1]);
1891 err_code |= ERR_ALERT | ERR_FATAL;
1892 goto out;
1893 }
1894 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1895 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' rule : %s.\n",
1896 file, linenum, args[0], args[1], errmsg);
1897 err_code |= ERR_ALERT | ERR_FATAL;
1898 goto out;
1899 }
1900
1901 err_code |= warnif_cond_conflicts(cond,
1902 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1903 file, linenum);
1904
1905 rule = calloc(1, sizeof(*rule));
1906 rule->cond = cond;
1907 LIST_INIT(&rule->list);
1908 LIST_ADDQ(&curproxy->uri_auth->admin_rules, &rule->list);
1909 } else if (!strcmp(args[1], "uri")) {
1910 if (*(args[2]) == 0) {
1911 ha_alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
1912 err_code |= ERR_ALERT | ERR_FATAL;
1913 goto out;
1914 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
1915 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1916 err_code |= ERR_ALERT | ERR_ABORT;
1917 goto out;
1918 }
1919 } else if (!strcmp(args[1], "realm")) {
1920 if (*(args[2]) == 0) {
1921 ha_alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
1922 err_code |= ERR_ALERT | ERR_FATAL;
1923 goto out;
1924 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
1925 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1926 err_code |= ERR_ALERT | ERR_ABORT;
1927 goto out;
1928 }
1929 } else if (!strcmp(args[1], "refresh")) {
1930 unsigned interval;
1931
1932 err = parse_time_err(args[2], &interval, TIME_UNIT_S);
1933 if (err) {
1934 ha_alert("parsing [%s:%d] : unexpected character '%c' in stats refresh interval.\n",
1935 file, linenum, *err);
1936 err_code |= ERR_ALERT | ERR_FATAL;
1937 goto out;
1938 } else if (!stats_set_refresh(&curproxy->uri_auth, interval)) {
1939 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1940 err_code |= ERR_ALERT | ERR_ABORT;
1941 goto out;
1942 }
1943 } else if (!strcmp(args[1], "http-request")) { /* request access control: allow/deny/auth */
1944 struct act_rule *rule;
1945
1946 if (curproxy == &defproxy) {
1947 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1948 err_code |= ERR_ALERT | ERR_FATAL;
1949 goto out;
1950 }
1951
1952 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1953 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1954 err_code |= ERR_ALERT | ERR_ABORT;
1955 goto out;
1956 }
1957
1958 if (!LIST_ISEMPTY(&curproxy->uri_auth->http_req_rules) &&
1959 !LIST_PREV(&curproxy->uri_auth->http_req_rules, struct act_rule *, list)->cond) {
1960 ha_warning("parsing [%s:%d]: previous '%s' action has no condition attached, further entries are NOOP.\n",
1961 file, linenum, args[0]);
1962 err_code |= ERR_WARN;
1963 }
1964
1965 rule = parse_http_req_cond((const char **)args + 2, file, linenum, curproxy);
1966
1967 if (!rule) {
1968 err_code |= ERR_ALERT | ERR_ABORT;
1969 goto out;
1970 }
1971
1972 err_code |= warnif_cond_conflicts(rule->cond,
1973 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1974 file, linenum);
1975 LIST_ADDQ(&curproxy->uri_auth->http_req_rules, &rule->list);
1976
1977 } else if (!strcmp(args[1], "auth")) {
1978 if (*(args[2]) == 0) {
1979 ha_alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
1980 err_code |= ERR_ALERT | ERR_FATAL;
1981 goto out;
1982 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
1983 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1984 err_code |= ERR_ALERT | ERR_ABORT;
1985 goto out;
1986 }
1987 } else if (!strcmp(args[1], "scope")) {
1988 if (*(args[2]) == 0) {
1989 ha_alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
1990 err_code |= ERR_ALERT | ERR_FATAL;
1991 goto out;
1992 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
1993 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1994 err_code |= ERR_ALERT | ERR_ABORT;
1995 goto out;
1996 }
1997 } else if (!strcmp(args[1], "enable")) {
1998 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1999 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2000 err_code |= ERR_ALERT | ERR_ABORT;
2001 goto out;
2002 }
2003 } else if (!strcmp(args[1], "hide-version")) {
2004 if (!stats_set_flag(&curproxy->uri_auth, ST_HIDEVER)) {
2005 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2006 err_code |= ERR_ALERT | ERR_ABORT;
2007 goto out;
2008 }
2009 } else if (!strcmp(args[1], "show-legends")) {
2010 if (!stats_set_flag(&curproxy->uri_auth, ST_SHLGNDS)) {
2011 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2012 err_code |= ERR_ALERT | ERR_ABORT;
2013 goto out;
2014 }
2015 } else if (!strcmp(args[1], "show-node")) {
2016
2017 if (*args[2]) {
2018 int i;
2019 char c;
2020
2021 for (i=0; args[2][i]; i++) {
2022 c = args[2][i];
2023 if (!isupper((unsigned char)c) && !islower((unsigned char)c) &&
2024 !isdigit((unsigned char)c) && c != '_' && c != '-' && c != '.')
2025 break;
2026 }
2027
2028 if (!i || args[2][i]) {
2029 ha_alert("parsing [%s:%d]: '%s %s' invalid node name - should be a string"
2030 "with digits(0-9), letters(A-Z, a-z), hyphen(-) or underscode(_).\n",
2031 file, linenum, args[0], args[1]);
2032 err_code |= ERR_ALERT | ERR_FATAL;
2033 goto out;
2034 }
2035 }
2036
2037 if (!stats_set_node(&curproxy->uri_auth, args[2])) {
2038 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2039 err_code |= ERR_ALERT | ERR_ABORT;
2040 goto out;
2041 }
2042 } else if (!strcmp(args[1], "show-desc")) {
2043 char *desc = NULL;
2044
2045 if (*args[2]) {
2046 int i, len=0;
2047 char *d;
2048
2049 for (i = 2; *args[i]; i++)
2050 len += strlen(args[i]) + 1;
2051
2052 desc = d = calloc(1, len);
2053
2054 d += snprintf(d, desc + len - d, "%s", args[2]);
2055 for (i = 3; *args[i]; i++)
2056 d += snprintf(d, desc + len - d, " %s", args[i]);
2057 }
2058
2059 if (!*args[2] && !global.desc)
2060 ha_warning("parsing [%s:%d]: '%s' requires a parameter or 'desc' to be set in the global section.\n",
2061 file, linenum, args[1]);
2062 else {
2063 if (!stats_set_desc(&curproxy->uri_auth, desc)) {
2064 free(desc);
2065 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2066 err_code |= ERR_ALERT | ERR_ABORT;
2067 goto out;
2068 }
2069 free(desc);
2070 }
2071 } else {
2072stats_error_parsing:
2073 ha_alert("parsing [%s:%d]: %s '%s', expects 'admin', 'uri', 'realm', 'auth', 'scope', 'enable', 'hide-version', 'show-node', 'show-desc' or 'show-legends'.\n",
2074 file, linenum, *args[1]?"unknown stats parameter":"missing keyword in", args[*args[1]?1:0]);
2075 err_code |= ERR_ALERT | ERR_FATAL;
2076 goto out;
2077 }
2078 }
2079 else if (!strcmp(args[0], "option")) {
2080 int optnum;
2081
2082 if (*(args[1]) == '\0') {
2083 ha_alert("parsing [%s:%d]: '%s' expects an option name.\n",
2084 file, linenum, args[0]);
2085 err_code |= ERR_ALERT | ERR_FATAL;
2086 goto out;
2087 }
2088
2089 for (optnum = 0; cfg_opts[optnum].name; optnum++) {
2090 if (!strcmp(args[1], cfg_opts[optnum].name)) {
2091 if (cfg_opts[optnum].cap == PR_CAP_NONE) {
2092 ha_alert("parsing [%s:%d]: option '%s' is not supported due to build options.\n",
2093 file, linenum, cfg_opts[optnum].name);
2094 err_code |= ERR_ALERT | ERR_FATAL;
2095 goto out;
2096 }
2097 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2098 goto out;
2099
2100 if (warnifnotcap(curproxy, cfg_opts[optnum].cap, file, linenum, args[1], NULL)) {
2101 err_code |= ERR_WARN;
2102 goto out;
2103 }
2104
2105 curproxy->no_options &= ~cfg_opts[optnum].val;
2106 curproxy->options &= ~cfg_opts[optnum].val;
2107
2108 switch (kwm) {
2109 case KWM_STD:
2110 curproxy->options |= cfg_opts[optnum].val;
2111 break;
2112 case KWM_NO:
2113 curproxy->no_options |= cfg_opts[optnum].val;
2114 break;
2115 case KWM_DEF: /* already cleared */
2116 break;
2117 }
2118
2119 goto out;
2120 }
2121 }
2122
2123 for (optnum = 0; cfg_opts2[optnum].name; optnum++) {
2124 if (!strcmp(args[1], cfg_opts2[optnum].name)) {
2125 if (cfg_opts2[optnum].cap == PR_CAP_NONE) {
2126 ha_alert("parsing [%s:%d]: option '%s' is not supported due to build options.\n",
2127 file, linenum, cfg_opts2[optnum].name);
2128 err_code |= ERR_ALERT | ERR_FATAL;
2129 goto out;
2130 }
2131 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2132 goto out;
2133 if (warnifnotcap(curproxy, cfg_opts2[optnum].cap, file, linenum, args[1], NULL)) {
2134 err_code |= ERR_WARN;
2135 goto out;
2136 }
2137
2138 curproxy->no_options2 &= ~cfg_opts2[optnum].val;
2139 curproxy->options2 &= ~cfg_opts2[optnum].val;
2140
2141 switch (kwm) {
2142 case KWM_STD:
2143 curproxy->options2 |= cfg_opts2[optnum].val;
2144 break;
2145 case KWM_NO:
2146 curproxy->no_options2 |= cfg_opts2[optnum].val;
2147 break;
2148 case KWM_DEF: /* already cleared */
2149 break;
2150 }
2151 goto out;
2152 }
2153 }
2154
2155 /* HTTP options override each other. They can be cancelled using
2156 * "no option xxx" which only switches to default mode if the mode
2157 * was this one (useful for cancelling options set in defaults
2158 * sections).
2159 */
2160 if (strcmp(args[1], "httpclose") == 0 || strcmp(args[1], "forceclose") == 0) {
2161 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2162 goto out;
2163 if (kwm == KWM_STD) {
2164 curproxy->options &= ~PR_O_HTTP_MODE;
2165 curproxy->options |= PR_O_HTTP_CLO;
2166 goto out;
2167 }
2168 else if (kwm == KWM_NO) {
2169 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_CLO)
2170 curproxy->options &= ~PR_O_HTTP_MODE;
2171 goto out;
2172 }
2173 }
2174 else if (strcmp(args[1], "http-server-close") == 0) {
2175 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2176 goto out;
2177 if (kwm == KWM_STD) {
2178 curproxy->options &= ~PR_O_HTTP_MODE;
2179 curproxy->options |= PR_O_HTTP_SCL;
2180 goto out;
2181 }
2182 else if (kwm == KWM_NO) {
2183 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL)
2184 curproxy->options &= ~PR_O_HTTP_MODE;
2185 goto out;
2186 }
2187 }
2188 else if (strcmp(args[1], "http-keep-alive") == 0) {
2189 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2190 goto out;
2191 if (kwm == KWM_STD) {
2192 curproxy->options &= ~PR_O_HTTP_MODE;
2193 curproxy->options |= PR_O_HTTP_KAL;
2194 goto out;
2195 }
2196 else if (kwm == KWM_NO) {
2197 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_KAL)
2198 curproxy->options &= ~PR_O_HTTP_MODE;
2199 goto out;
2200 }
2201 }
2202 else if (strcmp(args[1], "http-tunnel") == 0) {
2203 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[1], NULL)) {
2204 err_code |= ERR_WARN;
2205 goto out;
2206 }
2207 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2208 goto out;
2209 if (kwm == KWM_STD) {
2210 curproxy->options &= ~PR_O_HTTP_MODE;
2211 curproxy->options |= PR_O_HTTP_TUN;
2212 goto out;
2213 }
2214 else if (kwm == KWM_NO) {
2215 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN)
2216 curproxy->options &= ~PR_O_HTTP_MODE;
2217 goto out;
2218 }
2219 }
2220
2221 /* Redispatch can take an integer argument that control when the
2222 * resispatch occurs. All values are relative to the retries option.
2223 * This can be cancelled using "no option xxx".
2224 */
2225 if (strcmp(args[1], "redispatch") == 0) {
2226 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL)) {
2227 err_code |= ERR_WARN;
2228 goto out;
2229 }
2230
2231 curproxy->no_options &= ~PR_O_REDISP;
2232 curproxy->options &= ~PR_O_REDISP;
2233
2234 switch (kwm) {
2235 case KWM_STD:
2236 curproxy->options |= PR_O_REDISP;
2237 curproxy->redispatch_after = -1;
2238 if(*args[2]) {
2239 curproxy->redispatch_after = atol(args[2]);
2240 }
2241 break;
2242 case KWM_NO:
2243 curproxy->no_options |= PR_O_REDISP;
2244 curproxy->redispatch_after = 0;
2245 break;
2246 case KWM_DEF: /* already cleared */
2247 break;
2248 }
2249 goto out;
2250 }
2251
2252 if (kwm != KWM_STD) {
2253 ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
2254 file, linenum, args[1]);
2255 err_code |= ERR_ALERT | ERR_FATAL;
2256 goto out;
2257 }
2258
2259 if (!strcmp(args[1], "httplog")) {
2260 char *logformat;
2261 /* generate a complete HTTP log */
2262 logformat = default_http_log_format;
2263 if (*(args[2]) != '\0') {
2264 if (!strcmp(args[2], "clf")) {
2265 curproxy->options2 |= PR_O2_CLFLOG;
2266 logformat = clf_http_log_format;
2267 } else {
2268 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'clf'.\n", file, linenum, args[1]);
2269 err_code |= ERR_ALERT | ERR_FATAL;
2270 goto out;
2271 }
2272 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
2273 goto out;
2274 }
2275 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2276 char *oldlogformat = "log-format";
2277 char *clflogformat = "";
2278
2279 if (curproxy->conf.logformat_string == default_http_log_format)
2280 oldlogformat = "option httplog";
2281 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2282 oldlogformat = "option tcplog";
2283 else if (curproxy->conf.logformat_string == clf_http_log_format)
2284 oldlogformat = "option httplog clf";
2285 if (logformat == clf_http_log_format)
2286 clflogformat = " clf";
2287 ha_warning("parsing [%s:%d]: 'option httplog%s' overrides previous '%s' in 'defaults' section.\n",
2288 file, linenum, clflogformat, oldlogformat);
2289 }
2290 if (curproxy->conf.logformat_string != default_http_log_format &&
2291 curproxy->conf.logformat_string != default_tcp_log_format &&
2292 curproxy->conf.logformat_string != clf_http_log_format)
2293 free(curproxy->conf.logformat_string);
2294 curproxy->conf.logformat_string = logformat;
2295
2296 free(curproxy->conf.lfs_file);
2297 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2298 curproxy->conf.lfs_line = curproxy->conf.args.line;
2299
2300 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2301 ha_warning("parsing [%s:%d] : backend '%s' : 'option httplog' directive is ignored in backends.\n",
2302 file, linenum, curproxy->id);
2303 err_code |= ERR_WARN;
2304 }
2305 }
2306 else if (!strcmp(args[1], "tcplog")) {
2307 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2308 char *oldlogformat = "log-format";
2309
2310 if (curproxy->conf.logformat_string == default_http_log_format)
2311 oldlogformat = "option httplog";
2312 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2313 oldlogformat = "option tcplog";
2314 else if (curproxy->conf.logformat_string == clf_http_log_format)
2315 oldlogformat = "option httplog clf";
2316 ha_warning("parsing [%s:%d]: 'option tcplog' overrides previous '%s' in 'defaults' section.\n",
2317 file, linenum, oldlogformat);
2318 }
2319 /* generate a detailed TCP log */
2320 if (curproxy->conf.logformat_string != default_http_log_format &&
2321 curproxy->conf.logformat_string != default_tcp_log_format &&
2322 curproxy->conf.logformat_string != clf_http_log_format)
2323 free(curproxy->conf.logformat_string);
2324 curproxy->conf.logformat_string = default_tcp_log_format;
2325
2326 free(curproxy->conf.lfs_file);
2327 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2328 curproxy->conf.lfs_line = curproxy->conf.args.line;
2329
2330 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2331 goto out;
2332
2333 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2334 ha_warning("parsing [%s:%d] : backend '%s' : 'option tcplog' directive is ignored in backends.\n",
2335 file, linenum, curproxy->id);
2336 err_code |= ERR_WARN;
2337 }
2338 }
2339 else if (!strcmp(args[1], "tcpka")) {
2340 /* enable TCP keep-alives on client and server streams */
2341 if (warnifnotcap(curproxy, PR_CAP_BE | PR_CAP_FE, file, linenum, args[1], NULL))
2342 err_code |= ERR_WARN;
2343
2344 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2345 goto out;
2346
2347 if (curproxy->cap & PR_CAP_FE)
2348 curproxy->options |= PR_O_TCP_CLI_KA;
2349 if (curproxy->cap & PR_CAP_BE)
2350 curproxy->options |= PR_O_TCP_SRV_KA;
2351 }
2352 else if (!strcmp(args[1], "httpchk")) {
2353 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2354 err_code |= ERR_WARN;
2355
2356 /* use HTTP request to check servers' health */
2357 free(curproxy->check_req);
2358 curproxy->check_req = NULL;
2359 curproxy->options2 &= ~PR_O2_CHK_ANY;
2360 curproxy->options2 |= PR_O2_HTTP_CHK;
2361 if (!*args[2]) { /* no argument */
2362 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
2363 curproxy->check_len = strlen(DEF_CHECK_REQ);
2364 } else if (!*args[3]) { /* one argument : URI */
2365 int reqlen = strlen(args[2]) + strlen("OPTIONS HTTP/1.0\r\n") + 1;
2366 curproxy->check_req = malloc(reqlen);
2367 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2368 "OPTIONS %s HTTP/1.0\r\n", args[2]); /* URI to use */
2369 } else { /* more arguments : METHOD URI [HTTP_VER] */
2370 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n");
2371 if (*args[4])
2372 reqlen += strlen(args[4]);
2373 else
2374 reqlen += strlen("HTTP/1.0");
2375
2376 curproxy->check_req = malloc(reqlen);
2377 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2378 "%s %s %s\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
2379 }
2380 if (alertif_too_many_args_idx(3, 1, file, linenum, args, &err_code))
2381 goto out;
2382 }
2383 else if (!strcmp(args[1], "ssl-hello-chk")) {
2384 /* use SSLv3 CLIENT HELLO to check servers' health */
2385 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2386 err_code |= ERR_WARN;
2387
2388 free(curproxy->check_req);
2389 curproxy->check_req = NULL;
2390 curproxy->options2 &= ~PR_O2_CHK_ANY;
2391 curproxy->options2 |= PR_O2_SSL3_CHK;
2392
2393 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2394 goto out;
2395 }
2396 else if (!strcmp(args[1], "smtpchk")) {
2397 /* use SMTP request to check servers' health */
2398 free(curproxy->check_req);
2399 curproxy->check_req = NULL;
2400 curproxy->options2 &= ~PR_O2_CHK_ANY;
2401 curproxy->options2 |= PR_O2_SMTP_CHK;
2402
2403 if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */
2404 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2405 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2406 } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */
2407 if (!strcmp(args[2], "EHLO") || !strcmp(args[2], "HELO")) {
2408 int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" \r\n") + 1;
2409 curproxy->check_req = malloc(reqlen);
2410 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2411 "%s %s\r\n", args[2], args[3]); /* HELO hostname */
2412 } else {
2413 /* this just hits the default for now, but you could potentially expand it to allow for other stuff
2414 though, it's unlikely you'd want to send anything other than an EHLO or HELO */
2415 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2416 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2417 }
2418 }
2419 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2420 goto out;
2421 }
2422 else if (!strcmp(args[1], "pgsql-check")) {
2423 /* use PostgreSQL request to check servers' health */
2424 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2425 err_code |= ERR_WARN;
2426
2427 free(curproxy->check_req);
2428 curproxy->check_req = NULL;
2429 curproxy->options2 &= ~PR_O2_CHK_ANY;
2430 curproxy->options2 |= PR_O2_PGSQL_CHK;
2431
2432 if (*(args[2])) {
2433 int cur_arg = 2;
2434
2435 while (*(args[cur_arg])) {
2436 if (strcmp(args[cur_arg], "user") == 0) {
2437 char * packet;
2438 uint32_t packet_len;
2439 uint32_t pv;
2440
2441 /* suboption header - needs additional argument for it */
2442 if (*(args[cur_arg+1]) == 0) {
2443 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2444 file, linenum, args[0], args[1], args[cur_arg]);
2445 err_code |= ERR_ALERT | ERR_FATAL;
2446 goto out;
2447 }
2448
2449 /* uint32_t + uint32_t + strlen("user")+1 + strlen(username)+1 + 1 */
2450 packet_len = 4 + 4 + 5 + strlen(args[cur_arg + 1])+1 +1;
2451 pv = htonl(0x30000); /* protocol version 3.0 */
2452
2453 packet = calloc(1, packet_len);
2454
2455 memcpy(packet + 4, &pv, 4);
2456
2457 /* copy "user" */
2458 memcpy(packet + 8, "user", 4);
2459
2460 /* copy username */
2461 memcpy(packet + 13, args[cur_arg+1], strlen(args[cur_arg+1]));
2462
2463 free(curproxy->check_req);
2464 curproxy->check_req = packet;
2465 curproxy->check_len = packet_len;
2466
2467 packet_len = htonl(packet_len);
2468 memcpy(packet, &packet_len, 4);
2469 cur_arg += 2;
2470 } else {
2471 /* unknown suboption - catchall */
2472 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2473 file, linenum, args[0], args[1]);
2474 err_code |= ERR_ALERT | ERR_FATAL;
2475 goto out;
2476 }
2477 } /* end while loop */
2478 }
2479 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2480 goto out;
2481 }
2482
2483 else if (!strcmp(args[1], "redis-check")) {
2484 /* use REDIS PING request to check servers' health */
2485 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2486 err_code |= ERR_WARN;
2487
2488 free(curproxy->check_req);
2489 curproxy->check_req = NULL;
2490 curproxy->options2 &= ~PR_O2_CHK_ANY;
2491 curproxy->options2 |= PR_O2_REDIS_CHK;
2492
2493 curproxy->check_req = malloc(sizeof(DEF_REDIS_CHECK_REQ) - 1);
2494 memcpy(curproxy->check_req, DEF_REDIS_CHECK_REQ, sizeof(DEF_REDIS_CHECK_REQ) - 1);
2495 curproxy->check_len = sizeof(DEF_REDIS_CHECK_REQ) - 1;
2496
2497 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2498 goto out;
2499 }
2500
2501 else if (!strcmp(args[1], "mysql-check")) {
2502 /* use MYSQL request to check servers' health */
2503 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2504 err_code |= ERR_WARN;
2505
2506 free(curproxy->check_req);
2507 curproxy->check_req = NULL;
2508 curproxy->options2 &= ~PR_O2_CHK_ANY;
2509 curproxy->options2 |= PR_O2_MYSQL_CHK;
2510
2511 /* This is an example of a MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte.
2512 * const char mysql40_client_auth_pkt[] = {
2513 * "\x0e\x00\x00" // packet length
2514 * "\x01" // packet number
2515 * "\x00\x00" // client capabilities
2516 * "\x00\x00\x01" // max packet
2517 * "haproxy\x00" // username (null terminated string)
2518 * "\x00" // filler (always 0x00)
2519 * "\x01\x00\x00" // packet length
2520 * "\x00" // packet number
2521 * "\x01" // COM_QUIT command
2522 * };
2523 */
2524
2525 /* This is an example of a MySQL >=4.1 client Authentication packet provided by Nenad Merdanovic.
2526 * const char mysql41_client_auth_pkt[] = {
2527 * "\x0e\x00\x00\" // packet length
2528 * "\x01" // packet number
2529 * "\x00\x00\x00\x00" // client capabilities
2530 * "\x00\x00\x00\x01" // max packet
2531 * "\x21" // character set (UTF-8)
2532 * char[23] // All zeroes
2533 * "haproxy\x00" // username (null terminated string)
2534 * "\x00" // filler (always 0x00)
2535 * "\x01\x00\x00" // packet length
2536 * "\x00" // packet number
2537 * "\x01" // COM_QUIT command
2538 * };
2539 */
2540
2541
2542 if (*(args[2])) {
2543 int cur_arg = 2;
2544
2545 while (*(args[cur_arg])) {
2546 if (strcmp(args[cur_arg], "user") == 0) {
2547 char *mysqluser;
2548 int packetlen, reqlen, userlen;
2549
2550 /* suboption header - needs additional argument for it */
2551 if (*(args[cur_arg+1]) == 0) {
2552 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2553 file, linenum, args[0], args[1], args[cur_arg]);
2554 err_code |= ERR_ALERT | ERR_FATAL;
2555 goto out;
2556 }
2557 mysqluser = args[cur_arg + 1];
2558 userlen = strlen(mysqluser);
2559
2560 if (*(args[cur_arg+2])) {
2561 if (!strcmp(args[cur_arg+2], "post-41")) {
2562 packetlen = userlen + 7 + 27;
2563 reqlen = packetlen + 9;
2564
2565 free(curproxy->check_req);
2566 curproxy->check_req = calloc(1, reqlen);
2567 curproxy->check_len = reqlen;
2568
2569 snprintf(curproxy->check_req, 4, "%c%c%c",
2570 ((unsigned char) packetlen & 0xff),
2571 ((unsigned char) (packetlen >> 8) & 0xff),
2572 ((unsigned char) (packetlen >> 16) & 0xff));
2573
2574 curproxy->check_req[3] = 1;
2575 curproxy->check_req[5] = 0x82; // 130
2576 curproxy->check_req[11] = 1;
2577 curproxy->check_req[12] = 33;
2578 memcpy(&curproxy->check_req[36], mysqluser, userlen);
2579 curproxy->check_req[36 + userlen + 1 + 1] = 1;
2580 curproxy->check_req[36 + userlen + 1 + 1 + 4] = 1;
2581 cur_arg += 3;
2582 } else {
2583 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'post-41'.\n", file, linenum, args[cur_arg+2]);
2584 err_code |= ERR_ALERT | ERR_FATAL;
2585 goto out;
2586 }
2587 } else {
2588 packetlen = userlen + 7;
2589 reqlen = packetlen + 9;
2590
2591 free(curproxy->check_req);
2592 curproxy->check_req = calloc(1, reqlen);
2593 curproxy->check_len = reqlen;
2594
2595 snprintf(curproxy->check_req, 4, "%c%c%c",
2596 ((unsigned char) packetlen & 0xff),
2597 ((unsigned char) (packetlen >> 8) & 0xff),
2598 ((unsigned char) (packetlen >> 16) & 0xff));
2599
2600 curproxy->check_req[3] = 1;
2601 curproxy->check_req[5] = 0x80;
2602 curproxy->check_req[8] = 1;
2603 memcpy(&curproxy->check_req[9], mysqluser, userlen);
2604 curproxy->check_req[9 + userlen + 1 + 1] = 1;
2605 curproxy->check_req[9 + userlen + 1 + 1 + 4] = 1;
2606 cur_arg += 2;
2607 }
2608 } else {
2609 /* unknown suboption - catchall */
2610 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2611 file, linenum, args[0], args[1]);
2612 err_code |= ERR_ALERT | ERR_FATAL;
2613 goto out;
2614 }
2615 } /* end while loop */
2616 }
2617 }
2618 else if (!strcmp(args[1], "ldap-check")) {
2619 /* use LDAP request to check servers' health */
2620 free(curproxy->check_req);
2621 curproxy->check_req = NULL;
2622 curproxy->options2 &= ~PR_O2_CHK_ANY;
2623 curproxy->options2 |= PR_O2_LDAP_CHK;
2624
2625 curproxy->check_req = malloc(sizeof(DEF_LDAP_CHECK_REQ) - 1);
2626 memcpy(curproxy->check_req, DEF_LDAP_CHECK_REQ, sizeof(DEF_LDAP_CHECK_REQ) - 1);
2627 curproxy->check_len = sizeof(DEF_LDAP_CHECK_REQ) - 1;
2628 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2629 goto out;
2630 }
2631 else if (!strcmp(args[1], "spop-check")) {
2632 if (curproxy == &defproxy) {
2633 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n",
2634 file, linenum, args[0], args[1]);
2635 err_code |= ERR_ALERT | ERR_FATAL;
2636 goto out;
2637 }
2638 if (curproxy->cap & PR_CAP_FE) {
2639 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'frontend' and 'listen' sections.\n",
2640 file, linenum, args[0], args[1]);
2641 err_code |= ERR_ALERT | ERR_FATAL;
2642 goto out;
2643 }
2644
2645 /* use SPOE request to check servers' health */
2646 free(curproxy->check_req);
2647 curproxy->check_req = NULL;
2648 curproxy->options2 &= ~PR_O2_CHK_ANY;
2649 curproxy->options2 |= PR_O2_SPOP_CHK;
2650
2651 if (spoe_prepare_healthcheck_request(&curproxy->check_req, &curproxy->check_len)) {
2652 ha_alert("parsing [%s:%d] : failed to prepare SPOP healthcheck request.\n", file, linenum);
2653 err_code |= ERR_ALERT | ERR_FATAL;
2654 goto out;
2655 }
2656 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2657 goto out;
2658 }
2659 else if (!strcmp(args[1], "tcp-check")) {
2660 /* use raw TCPCHK send/expect to check servers' health */
2661 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2662 err_code |= ERR_WARN;
2663
2664 free(curproxy->check_req);
2665 curproxy->check_req = NULL;
2666 curproxy->options2 &= ~PR_O2_CHK_ANY;
2667 curproxy->options2 |= PR_O2_TCPCHK_CHK;
2668 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2669 goto out;
2670 }
2671 else if (!strcmp(args[1], "external-check")) {
2672 /* excute an external command to check servers' health */
2673 free(curproxy->check_req);
2674 curproxy->check_req = NULL;
2675 curproxy->options2 &= ~PR_O2_CHK_ANY;
2676 curproxy->options2 |= PR_O2_EXT_CHK;
2677 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2678 goto out;
2679 }
2680 else if (!strcmp(args[1], "forwardfor")) {
2681 int cur_arg;
2682
2683 /* insert x-forwarded-for field, but not for the IP address listed as an except.
2684 * set default options (ie: bitfield, header name, etc)
2685 */
2686
2687 curproxy->options |= PR_O_FWDFOR | PR_O_FF_ALWAYS;
2688
2689 free(curproxy->fwdfor_hdr_name);
2690 curproxy->fwdfor_hdr_name = strdup(DEF_XFORWARDFOR_HDR);
2691 curproxy->fwdfor_hdr_len = strlen(DEF_XFORWARDFOR_HDR);
2692
2693 /* loop to go through arguments - start at 2, since 0+1 = "option" "forwardfor" */
2694 cur_arg = 2;
2695 while (*(args[cur_arg])) {
2696 if (!strcmp(args[cur_arg], "except")) {
2697 /* suboption except - needs additional argument for it */
2698 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_net, &curproxy->except_mask)) {
2699 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2700 file, linenum, args[0], args[1], args[cur_arg]);
2701 err_code |= ERR_ALERT | ERR_FATAL;
2702 goto out;
2703 }
2704 /* flush useless bits */
2705 curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
2706 cur_arg += 2;
2707 } else if (!strcmp(args[cur_arg], "header")) {
2708 /* suboption header - needs additional argument for it */
2709 if (*(args[cur_arg+1]) == 0) {
2710 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2711 file, linenum, args[0], args[1], args[cur_arg]);
2712 err_code |= ERR_ALERT | ERR_FATAL;
2713 goto out;
2714 }
2715 free(curproxy->fwdfor_hdr_name);
2716 curproxy->fwdfor_hdr_name = strdup(args[cur_arg+1]);
2717 curproxy->fwdfor_hdr_len = strlen(curproxy->fwdfor_hdr_name);
2718 cur_arg += 2;
2719 } else if (!strcmp(args[cur_arg], "if-none")) {
2720 curproxy->options &= ~PR_O_FF_ALWAYS;
2721 cur_arg += 1;
2722 } else {
2723 /* unknown suboption - catchall */
2724 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except', 'header' and 'if-none'.\n",
2725 file, linenum, args[0], args[1]);
2726 err_code |= ERR_ALERT | ERR_FATAL;
2727 goto out;
2728 }
2729 } /* end while loop */
2730 }
2731 else if (!strcmp(args[1], "originalto")) {
2732 int cur_arg;
2733
2734 /* insert x-original-to field, but not for the IP address listed as an except.
2735 * set default options (ie: bitfield, header name, etc)
2736 */
2737
2738 curproxy->options |= PR_O_ORGTO;
2739
2740 free(curproxy->orgto_hdr_name);
2741 curproxy->orgto_hdr_name = strdup(DEF_XORIGINALTO_HDR);
2742 curproxy->orgto_hdr_len = strlen(DEF_XORIGINALTO_HDR);
2743
2744 /* loop to go through arguments - start at 2, since 0+1 = "option" "originalto" */
2745 cur_arg = 2;
2746 while (*(args[cur_arg])) {
2747 if (!strcmp(args[cur_arg], "except")) {
2748 /* suboption except - needs additional argument for it */
2749 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_to, &curproxy->except_mask_to)) {
2750 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2751 file, linenum, args[0], args[1], args[cur_arg]);
2752 err_code |= ERR_ALERT | ERR_FATAL;
2753 goto out;
2754 }
2755 /* flush useless bits */
2756 curproxy->except_to.s_addr &= curproxy->except_mask_to.s_addr;
2757 cur_arg += 2;
2758 } else if (!strcmp(args[cur_arg], "header")) {
2759 /* suboption header - needs additional argument for it */
2760 if (*(args[cur_arg+1]) == 0) {
2761 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2762 file, linenum, args[0], args[1], args[cur_arg]);
2763 err_code |= ERR_ALERT | ERR_FATAL;
2764 goto out;
2765 }
2766 free(curproxy->orgto_hdr_name);
2767 curproxy->orgto_hdr_name = strdup(args[cur_arg+1]);
2768 curproxy->orgto_hdr_len = strlen(curproxy->orgto_hdr_name);
2769 cur_arg += 2;
2770 } else {
2771 /* unknown suboption - catchall */
2772 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
2773 file, linenum, args[0], args[1]);
2774 err_code |= ERR_ALERT | ERR_FATAL;
2775 goto out;
2776 }
2777 } /* end while loop */
2778 }
2779 else {
2780 ha_alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
2781 err_code |= ERR_ALERT | ERR_FATAL;
2782 goto out;
2783 }
2784 goto out;
2785 }
2786 else if (!strcmp(args[0], "default_backend")) {
2787 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
2788 err_code |= ERR_WARN;
2789
2790 if (*(args[1]) == 0) {
2791 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
2792 err_code |= ERR_ALERT | ERR_FATAL;
2793 goto out;
2794 }
2795 free(curproxy->defbe.name);
2796 curproxy->defbe.name = strdup(args[1]);
2797
2798 if (alertif_too_many_args_idx(1, 0, file, linenum, args, &err_code))
2799 goto out;
2800 }
2801 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
2802 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2803 err_code |= ERR_WARN;
2804
2805 if (!already_warned(WARN_REDISPATCH_DEPRECATED))
2806 ha_warning("parsing [%s:%d]: keyword '%s' is deprecated in favor of 'option redispatch', and will not be supported by future versions.\n",
2807 file, linenum, args[0]);
2808 err_code |= ERR_WARN;
2809 /* enable reconnections to dispatch */
2810 curproxy->options |= PR_O_REDISP;
2811
2812 if (alertif_too_many_args_idx(1, 0, file, linenum, args, &err_code))
2813 goto out;
2814 }
2815 else if (!strcmp(args[0], "http-reuse")) {
2816 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2817 err_code |= ERR_WARN;
2818
2819 if (strcmp(args[1], "never") == 0) {
2820 /* enable a graceful server shutdown on an HTTP 404 response */
2821 curproxy->options &= ~PR_O_REUSE_MASK;
2822 curproxy->options |= PR_O_REUSE_NEVR;
2823 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2824 goto out;
2825 }
2826 else if (strcmp(args[1], "safe") == 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_SAFE;
2830 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2831 goto out;
2832 }
2833 else if (strcmp(args[1], "aggressive") == 0) {
2834 curproxy->options &= ~PR_O_REUSE_MASK;
2835 curproxy->options |= PR_O_REUSE_AGGR;
2836 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2837 goto out;
2838 }
2839 else if (strcmp(args[1], "always") == 0) {
2840 /* enable a graceful server shutdown on an HTTP 404 response */
2841 curproxy->options &= ~PR_O_REUSE_MASK;
2842 curproxy->options |= PR_O_REUSE_ALWS;
2843 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2844 goto out;
2845 }
2846 else {
2847 ha_alert("parsing [%s:%d] : '%s' only supports 'never', 'safe', 'aggressive', 'always'.\n", file, linenum, args[0]);
2848 err_code |= ERR_ALERT | ERR_FATAL;
2849 goto out;
2850 }
2851 }
2852 else if (!strcmp(args[0], "http-check")) {
2853 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2854 err_code |= ERR_WARN;
2855
2856 if (strcmp(args[1], "disable-on-404") == 0) {
2857 /* enable a graceful server shutdown on an HTTP 404 response */
2858 curproxy->options |= PR_O_DISABLE404;
2859 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2860 goto out;
2861 }
2862 else if (strcmp(args[1], "send-state") == 0) {
2863 /* enable emission of the apparent state of a server in HTTP checks */
2864 curproxy->options2 |= PR_O2_CHK_SNDST;
2865 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2866 goto out;
2867 }
2868 else if (strcmp(args[1], "expect") == 0) {
2869 const char *ptr_arg;
2870 int cur_arg;
2871
2872 if (curproxy->options2 & PR_O2_EXP_TYPE) {
2873 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
2874 err_code |= ERR_ALERT | ERR_FATAL;
2875 goto out;
2876 }
2877
2878 cur_arg = 2;
2879 /* consider exclamation marks, sole or at the beginning of a word */
2880 while (*(ptr_arg = args[cur_arg])) {
2881 while (*ptr_arg == '!') {
2882 curproxy->options2 ^= PR_O2_EXP_INV;
2883 ptr_arg++;
2884 }
2885 if (*ptr_arg)
2886 break;
2887 cur_arg++;
2888 }
2889 /* now ptr_arg points to the beginning of a word past any possible
2890 * exclamation mark, and cur_arg is the argument which holds this word.
2891 */
2892 if (strcmp(ptr_arg, "status") == 0) {
2893 if (!*(args[cur_arg + 1])) {
2894 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
2895 file, linenum, args[0], args[1], ptr_arg);
2896 err_code |= ERR_ALERT | ERR_FATAL;
2897 goto out;
2898 }
2899 curproxy->options2 |= PR_O2_EXP_STS;
2900 free(curproxy->expect_str);
2901 curproxy->expect_str = strdup(args[cur_arg + 1]);
2902 }
2903 else if (strcmp(ptr_arg, "string") == 0) {
2904 if (!*(args[cur_arg + 1])) {
2905 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
2906 file, linenum, args[0], args[1], ptr_arg);
2907 err_code |= ERR_ALERT | ERR_FATAL;
2908 goto out;
2909 }
2910 curproxy->options2 |= PR_O2_EXP_STR;
2911 free(curproxy->expect_str);
2912 curproxy->expect_str = strdup(args[cur_arg + 1]);
2913 }
2914 else if (strcmp(ptr_arg, "rstatus") == 0) {
2915 if (!*(args[cur_arg + 1])) {
2916 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
2917 file, linenum, args[0], args[1], ptr_arg);
2918 err_code |= ERR_ALERT | ERR_FATAL;
2919 goto out;
2920 }
2921 curproxy->options2 |= PR_O2_EXP_RSTS;
2922 free(curproxy->expect_str);
2923 if (curproxy->expect_regex) {
2924 regex_free(curproxy->expect_regex);
2925 free(curproxy->expect_regex);
2926 curproxy->expect_regex = NULL;
2927 }
2928 curproxy->expect_str = strdup(args[cur_arg + 1]);
2929 curproxy->expect_regex = calloc(1, sizeof(*curproxy->expect_regex));
2930 error = NULL;
2931 if (!regex_comp(args[cur_arg + 1], curproxy->expect_regex, 1, 1, &error)) {
2932 ha_alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s': %s.\n",
2933 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
2934 free(error);
2935 err_code |= ERR_ALERT | ERR_FATAL;
2936 goto out;
2937 }
2938 }
2939 else if (strcmp(ptr_arg, "rstring") == 0) {
2940 if (!*(args[cur_arg + 1])) {
2941 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
2942 file, linenum, args[0], args[1], ptr_arg);
2943 err_code |= ERR_ALERT | ERR_FATAL;
2944 goto out;
2945 }
2946 curproxy->options2 |= PR_O2_EXP_RSTR;
2947 free(curproxy->expect_str);
2948 if (curproxy->expect_regex) {
2949 regex_free(curproxy->expect_regex);
2950 free(curproxy->expect_regex);
2951 curproxy->expect_regex = NULL;
2952 }
2953 curproxy->expect_str = strdup(args[cur_arg + 1]);
2954 curproxy->expect_regex = calloc(1, sizeof(*curproxy->expect_regex));
2955 error = NULL;
2956 if (!regex_comp(args[cur_arg + 1], curproxy->expect_regex, 1, 1, &error)) {
2957 ha_alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s': %s.\n",
2958 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
2959 free(error);
2960 err_code |= ERR_ALERT | ERR_FATAL;
2961 goto out;
2962 }
2963 }
2964 else {
2965 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'status', 'string', 'rstatus', 'rstring', found '%s'.\n",
2966 file, linenum, args[0], args[1], ptr_arg);
2967 err_code |= ERR_ALERT | ERR_FATAL;
2968 goto out;
2969 }
2970 }
2971 else {
2972 ha_alert("parsing [%s:%d] : '%s' only supports 'disable-on-404', 'send-state', 'expect'.\n", file, linenum, args[0]);
2973 err_code |= ERR_ALERT | ERR_FATAL;
2974 goto out;
2975 }
2976 }
2977 else if (!strcmp(args[0], "tcp-check")) {
2978 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2979 err_code |= ERR_WARN;
2980
2981 if (strcmp(args[1], "comment") == 0) {
2982 int cur_arg;
2983 struct tcpcheck_rule *tcpcheck;
2984
2985 cur_arg = 1;
2986 tcpcheck = calloc(1, sizeof(*tcpcheck));
2987 tcpcheck->action = TCPCHK_ACT_COMMENT;
2988
2989 if (!*args[cur_arg + 1]) {
2990 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
2991 file, linenum, args[cur_arg]);
2992 err_code |= ERR_ALERT | ERR_FATAL;
2993 goto out;
2994 }
2995
2996 tcpcheck->comment = strdup(args[cur_arg + 1]);
2997
2998 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
2999 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
3000 goto out;
3001 }
3002 else if (strcmp(args[1], "connect") == 0) {
3003 const char *ptr_arg;
3004 int cur_arg;
3005 struct tcpcheck_rule *tcpcheck;
3006
3007 /* check if first rule is also a 'connect' action */
3008 tcpcheck = LIST_NEXT(&curproxy->tcpcheck_rules, struct tcpcheck_rule *, list);
3009 while (&tcpcheck->list != &curproxy->tcpcheck_rules &&
3010 tcpcheck->action == TCPCHK_ACT_COMMENT) {
3011 tcpcheck = LIST_NEXT(&tcpcheck->list, struct tcpcheck_rule *, list);
3012 }
3013
3014 if (&tcpcheck->list != &curproxy->tcpcheck_rules
3015 && tcpcheck->action != TCPCHK_ACT_CONNECT) {
3016 ha_alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
3017 file, linenum);
3018 err_code |= ERR_ALERT | ERR_FATAL;
3019 goto out;
3020 }
3021
3022 cur_arg = 2;
3023 tcpcheck = calloc(1, sizeof(*tcpcheck));
3024 tcpcheck->action = TCPCHK_ACT_CONNECT;
3025
3026 /* parsing each parameters to fill up the rule */
3027 while (*(ptr_arg = args[cur_arg])) {
3028 /* tcp port */
3029 if (strcmp(args[cur_arg], "port") == 0) {
3030 if ( (atol(args[cur_arg + 1]) > 65535) ||
3031 (atol(args[cur_arg + 1]) < 1) ){
3032 ha_alert("parsing [%s:%d] : '%s %s %s' expects a valid TCP port (from range 1 to 65535), got %s.\n",
3033 file, linenum, args[0], args[1], "port", args[cur_arg + 1]);
3034 err_code |= ERR_ALERT | ERR_FATAL;
3035 goto out;
3036 }
3037 tcpcheck->port = atol(args[cur_arg + 1]);
3038 cur_arg += 2;
3039 }
3040 /* send proxy protocol */
3041 else if (strcmp(args[cur_arg], "send-proxy") == 0) {
3042 tcpcheck->conn_opts |= TCPCHK_OPT_SEND_PROXY;
3043 cur_arg++;
3044 }
3045#ifdef USE_OPENSSL
3046 else if (strcmp(args[cur_arg], "ssl") == 0) {
3047 curproxy->options |= PR_O_TCPCHK_SSL;
3048 tcpcheck->conn_opts |= TCPCHK_OPT_SSL;
3049 cur_arg++;
3050 }
3051#endif /* USE_OPENSSL */
3052 /* comment for this tcpcheck line */
3053 else if (strcmp(args[cur_arg], "comment") == 0) {
3054 if (!*args[cur_arg + 1]) {
3055 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3056 file, linenum, args[cur_arg]);
3057 err_code |= ERR_ALERT | ERR_FATAL;
3058 goto out;
3059 }
3060 tcpcheck->comment = strdup(args[cur_arg + 1]);
3061 cur_arg += 2;
3062 }
3063 else {
3064#ifdef USE_OPENSSL
3065 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n",
3066#else /* USE_OPENSSL */
3067 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or but got '%s' as argument.\n",
3068#endif /* USE_OPENSSL */
3069 file, linenum, args[0], args[1], args[cur_arg]);
3070 err_code |= ERR_ALERT | ERR_FATAL;
3071 goto out;
3072 }
3073
3074 }
3075
3076 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3077 }
3078 else if (strcmp(args[1], "send") == 0) {
3079 if (! *(args[2]) ) {
3080 /* SEND string expected */
3081 ha_alert("parsing [%s:%d] : '%s %s %s' expects <STRING> as argument.\n",
3082 file, linenum, args[0], args[1], args[2]);
3083 err_code |= ERR_ALERT | ERR_FATAL;
3084 goto out;
3085 } else {
3086 struct tcpcheck_rule *tcpcheck;
3087
3088 tcpcheck = calloc(1, sizeof(*tcpcheck));
3089
3090 tcpcheck->action = TCPCHK_ACT_SEND;
3091 tcpcheck->string_len = strlen(args[2]);
3092 tcpcheck->string = strdup(args[2]);
3093 tcpcheck->expect_regex = NULL;
3094
3095 /* comment for this tcpcheck line */
3096 if (strcmp(args[3], "comment") == 0) {
3097 if (!*args[4]) {
3098 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3099 file, linenum, args[3]);
3100 err_code |= ERR_ALERT | ERR_FATAL;
3101 goto out;
3102 }
3103 tcpcheck->comment = strdup(args[4]);
3104 }
3105
3106 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3107 }
3108 }
3109 else if (strcmp(args[1], "send-binary") == 0) {
3110 if (! *(args[2]) ) {
3111 /* SEND binary string expected */
3112 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument.\n",
3113 file, linenum, args[0], args[1], args[2]);
3114 err_code |= ERR_ALERT | ERR_FATAL;
3115 goto out;
3116 } else {
3117 struct tcpcheck_rule *tcpcheck;
3118 char *err = NULL;
3119
3120 tcpcheck = calloc(1, sizeof(*tcpcheck));
3121
3122 tcpcheck->action = TCPCHK_ACT_SEND;
3123 if (parse_binary(args[2], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3124 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3125 file, linenum, args[0], args[1], args[2], err);
3126 err_code |= ERR_ALERT | ERR_FATAL;
3127 goto out;
3128 }
3129 tcpcheck->expect_regex = NULL;
3130
3131 /* comment for this tcpcheck line */
3132 if (strcmp(args[3], "comment") == 0) {
3133 if (!*args[4]) {
3134 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3135 file, linenum, args[3]);
3136 err_code |= ERR_ALERT | ERR_FATAL;
3137 goto out;
3138 }
3139 tcpcheck->comment = strdup(args[4]);
3140 }
3141
3142 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3143 }
3144 }
3145 else if (strcmp(args[1], "expect") == 0) {
3146 const char *ptr_arg;
3147 int cur_arg;
3148 int inverse = 0;
3149
3150 if (curproxy->options2 & PR_O2_EXP_TYPE) {
3151 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
3152 err_code |= ERR_ALERT | ERR_FATAL;
3153 goto out;
3154 }
3155
3156 cur_arg = 2;
3157 /* consider exclamation marks, sole or at the beginning of a word */
3158 while (*(ptr_arg = args[cur_arg])) {
3159 while (*ptr_arg == '!') {
3160 inverse = !inverse;
3161 ptr_arg++;
3162 }
3163 if (*ptr_arg)
3164 break;
3165 cur_arg++;
3166 }
3167 /* now ptr_arg points to the beginning of a word past any possible
3168 * exclamation mark, and cur_arg is the argument which holds this word.
3169 */
3170 if (strcmp(ptr_arg, "binary") == 0) {
3171 struct tcpcheck_rule *tcpcheck;
3172 char *err = NULL;
3173
3174 if (!*(args[cur_arg + 1])) {
3175 ha_alert("parsing [%s:%d] : '%s %s %s' expects <binary string> as an argument.\n",
3176 file, linenum, args[0], args[1], ptr_arg);
3177 err_code |= ERR_ALERT | ERR_FATAL;
3178 goto out;
3179 }
3180
3181 tcpcheck = calloc(1, sizeof(*tcpcheck));
3182
3183 tcpcheck->action = TCPCHK_ACT_EXPECT;
3184 if (parse_binary(args[cur_arg + 1], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3185 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3186 file, linenum, args[0], args[1], args[2], err);
3187 err_code |= ERR_ALERT | ERR_FATAL;
3188 goto out;
3189 }
3190 tcpcheck->expect_regex = NULL;
3191 tcpcheck->inverse = inverse;
3192
3193 /* tcpcheck comment */
3194 cur_arg += 2;
3195 if (strcmp(args[cur_arg], "comment") == 0) {
3196 if (!*args[cur_arg + 1]) {
3197 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3198 file, linenum, args[cur_arg + 1]);
3199 err_code |= ERR_ALERT | ERR_FATAL;
3200 goto out;
3201 }
3202 tcpcheck->comment = strdup(args[cur_arg + 1]);
3203 }
3204
3205 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3206 }
3207 else if (strcmp(ptr_arg, "string") == 0) {
3208 struct tcpcheck_rule *tcpcheck;
3209
3210 if (!*(args[cur_arg + 1])) {
3211 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3212 file, linenum, args[0], args[1], ptr_arg);
3213 err_code |= ERR_ALERT | ERR_FATAL;
3214 goto out;
3215 }
3216
3217 tcpcheck = calloc(1, sizeof(*tcpcheck));
3218
3219 tcpcheck->action = TCPCHK_ACT_EXPECT;
3220 tcpcheck->string_len = strlen(args[cur_arg + 1]);
3221 tcpcheck->string = strdup(args[cur_arg + 1]);
3222 tcpcheck->expect_regex = NULL;
3223 tcpcheck->inverse = inverse;
3224
3225 /* tcpcheck comment */
3226 cur_arg += 2;
3227 if (strcmp(args[cur_arg], "comment") == 0) {
3228 if (!*args[cur_arg + 1]) {
3229 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3230 file, linenum, args[cur_arg + 1]);
3231 err_code |= ERR_ALERT | ERR_FATAL;
3232 goto out;
3233 }
3234 tcpcheck->comment = strdup(args[cur_arg + 1]);
3235 }
3236
3237 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3238 }
3239 else if (strcmp(ptr_arg, "rstring") == 0) {
3240 struct tcpcheck_rule *tcpcheck;
3241
3242 if (!*(args[cur_arg + 1])) {
3243 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3244 file, linenum, args[0], args[1], ptr_arg);
3245 err_code |= ERR_ALERT | ERR_FATAL;
3246 goto out;
3247 }
3248
3249 tcpcheck = calloc(1, sizeof(*tcpcheck));
3250
3251 tcpcheck->action = TCPCHK_ACT_EXPECT;
3252 tcpcheck->string_len = 0;
3253 tcpcheck->string = NULL;
3254 tcpcheck->expect_regex = calloc(1, sizeof(*tcpcheck->expect_regex));
3255 error = NULL;
3256 if (!regex_comp(args[cur_arg + 1], tcpcheck->expect_regex, 1, 1, &error)) {
3257 ha_alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s': %s.\n",
3258 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3259 free(error);
3260 err_code |= ERR_ALERT | ERR_FATAL;
3261 goto out;
3262 }
3263 tcpcheck->inverse = inverse;
3264
3265 /* tcpcheck comment */
3266 cur_arg += 2;
3267 if (strcmp(args[cur_arg], "comment") == 0) {
3268 if (!*args[cur_arg + 1]) {
3269 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3270 file, linenum, args[cur_arg + 1]);
3271 err_code |= ERR_ALERT | ERR_FATAL;
3272 goto out;
3273 }
3274 tcpcheck->comment = strdup(args[cur_arg + 1]);
3275 }
3276
3277 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3278 }
3279 else {
3280 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'binary', 'string', 'rstring', found '%s'.\n",
3281 file, linenum, args[0], args[1], ptr_arg);
3282 err_code |= ERR_ALERT | ERR_FATAL;
3283 goto out;
3284 }
3285 }
3286 else {
3287 ha_alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
3288 err_code |= ERR_ALERT | ERR_FATAL;
3289 goto out;
3290 }
3291 }
3292 else if (!strcmp(args[0], "monitor")) {
3293 if (curproxy == &defproxy) {
3294 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3295 err_code |= ERR_ALERT | ERR_FATAL;
3296 goto out;
3297 }
3298
3299 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3300 err_code |= ERR_WARN;
3301
3302 if (strcmp(args[1], "fail") == 0) {
3303 /* add a condition to fail monitor requests */
3304 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
3305 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
3306 file, linenum, args[0], args[1]);
3307 err_code |= ERR_ALERT | ERR_FATAL;
3308 goto out;
3309 }
3310
3311 err_code |= warnif_misplaced_monitor(curproxy, file, linenum, "monitor fail");
3312 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
3313 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
3314 file, linenum, args[0], args[1], errmsg);
3315 err_code |= ERR_ALERT | ERR_FATAL;
3316 goto out;
3317 }
3318 LIST_ADDQ(&curproxy->mon_fail_cond, &cond->list);
3319 }
3320 else {
3321 ha_alert("parsing [%s:%d] : '%s' only supports 'fail'.\n", file, linenum, args[0]);
3322 err_code |= ERR_ALERT | ERR_FATAL;
3323 goto out;
3324 }
3325 }
3326#ifdef TPROXY
3327 else if (!strcmp(args[0], "transparent")) {
3328 /* enable transparent proxy connections */
3329 curproxy->options |= PR_O_TRANSP;
3330 if (alertif_too_many_args(0, file, linenum, args, &err_code))
3331 goto out;
3332 }
3333#endif
3334 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3335 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
3336 err_code |= ERR_WARN;
3337
3338 if (*(args[1]) == 0) {
3339 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3340 err_code |= ERR_ALERT | ERR_FATAL;
3341 goto out;
3342 }
3343 curproxy->maxconn = atol(args[1]);
3344 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3345 goto out;
3346 }
3347 else if (!strcmp(args[0], "backlog")) { /* backlog */
3348 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3349 err_code |= ERR_WARN;
3350
3351 if (*(args[1]) == 0) {
3352 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3353 err_code |= ERR_ALERT | ERR_FATAL;
3354 goto out;
3355 }
3356 curproxy->backlog = atol(args[1]);
3357 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3358 goto out;
3359 }
3360 else if (!strcmp(args[0], "fullconn")) { /* fullconn */
3361 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
3362 err_code |= ERR_WARN;
3363
3364 if (*(args[1]) == 0) {
3365 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3366 err_code |= ERR_ALERT | ERR_FATAL;
3367 goto out;
3368 }
3369 curproxy->fullconn = atol(args[1]);
3370 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3371 goto out;
3372 }
3373 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3374 if (*(args[1]) == 0) {
3375 ha_alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
3376 err_code |= ERR_ALERT | ERR_FATAL;
3377 goto out;
3378 }
3379 err = parse_time_err(args[1], &val, TIME_UNIT_MS);
3380 if (err) {
3381 ha_alert("parsing [%s:%d] : unexpected character '%c' in grace time.\n",
3382 file, linenum, *err);
3383 err_code |= ERR_ALERT | ERR_FATAL;
3384 goto out;
3385 }
3386 curproxy->grace = val;
3387 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3388 goto out;
3389 }
3390 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3391 struct sockaddr_storage *sk;
3392 int port1, port2;
3393 struct protocol *proto;
3394
3395 if (curproxy == &defproxy) {
3396 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3397 err_code |= ERR_ALERT | ERR_FATAL;
3398 goto out;
3399 }
3400 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3401 err_code |= ERR_WARN;
3402
3403 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3404 if (!sk) {
3405 ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
3406 err_code |= ERR_ALERT | ERR_FATAL;
3407 goto out;
3408 }
3409
3410 proto = protocol_by_family(sk->ss_family);
3411 if (!proto || !proto->connect) {
3412 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3413 file, linenum, args[0], args[1]);
3414 err_code |= ERR_ALERT | ERR_FATAL;
3415 goto out;
3416 }
3417
3418 if (port1 != port2) {
3419 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'.\n",
3420 file, linenum, args[0], args[1]);
3421 err_code |= ERR_ALERT | ERR_FATAL;
3422 goto out;
3423 }
3424
3425 if (!port1) {
3426 ha_alert("parsing [%s:%d] : '%s' : missing port number in '%s', <addr:port> expected.\n",
3427 file, linenum, args[0], args[1]);
3428 err_code |= ERR_ALERT | ERR_FATAL;
3429 goto out;
3430 }
3431
3432 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3433 goto out;
3434
3435 curproxy->dispatch_addr = *sk;
3436 curproxy->options |= PR_O_DISPATCH;
3437 }
3438 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
3439 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3440 err_code |= ERR_WARN;
3441
3442 if (backend_parse_balance((const char **)args + 1, &errmsg, curproxy) < 0) {
3443 ha_alert("parsing [%s:%d] : %s %s\n", file, linenum, args[0], errmsg);
3444 err_code |= ERR_ALERT | ERR_FATAL;
3445 goto out;
3446 }
3447 }
3448 else if (!strcmp(args[0], "hash-type")) { /* set hashing method */
3449 /**
3450 * The syntax for hash-type config element is
3451 * hash-type {map-based|consistent} [[<algo>] avalanche]
3452 *
3453 * The default hash function is sdbm for map-based and sdbm+avalanche for consistent.
3454 */
3455 curproxy->lbprm.algo &= ~(BE_LB_HASH_TYPE | BE_LB_HASH_FUNC | BE_LB_HASH_MOD);
3456
3457 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3458 err_code |= ERR_WARN;
3459
3460 if (strcmp(args[1], "consistent") == 0) { /* use consistent hashing */
3461 curproxy->lbprm.algo |= BE_LB_HASH_CONS;
3462 }
3463 else if (strcmp(args[1], "map-based") == 0) { /* use map-based hashing */
3464 curproxy->lbprm.algo |= BE_LB_HASH_MAP;
3465 }
3466 else if (strcmp(args[1], "avalanche") == 0) {
3467 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]);
3468 err_code |= ERR_ALERT | ERR_FATAL;
3469 goto out;
3470 }
3471 else {
3472 ha_alert("parsing [%s:%d] : '%s' only supports 'consistent' and 'map-based'.\n", file, linenum, args[0]);
3473 err_code |= ERR_ALERT | ERR_FATAL;
3474 goto out;
3475 }
3476
3477 /* set the hash function to use */
3478 if (!*args[2]) {
3479 /* the default algo is sdbm */
3480 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3481
3482 /* if consistent with no argument, then avalanche modifier is also applied */
3483 if ((curproxy->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS)
3484 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3485 } else {
3486 /* set the hash function */
3487 if (!strcmp(args[2], "sdbm")) {
3488 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3489 }
3490 else if (!strcmp(args[2], "djb2")) {
3491 curproxy->lbprm.algo |= BE_LB_HFCN_DJB2;
3492 }
3493 else if (!strcmp(args[2], "wt6")) {
3494 curproxy->lbprm.algo |= BE_LB_HFCN_WT6;
3495 }
3496 else if (!strcmp(args[2], "crc32")) {
3497 curproxy->lbprm.algo |= BE_LB_HFCN_CRC32;
3498 }
3499 else {
3500 ha_alert("parsing [%s:%d] : '%s' only supports 'sdbm', 'djb2', 'crc32', or 'wt6' hash functions.\n", file, linenum, args[0]);
3501 err_code |= ERR_ALERT | ERR_FATAL;
3502 goto out;
3503 }
3504
3505 /* set the hash modifier */
3506 if (!strcmp(args[3], "avalanche")) {
3507 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3508 }
3509 else if (*args[3]) {
3510 ha_alert("parsing [%s:%d] : '%s' only supports 'avalanche' as a modifier for hash functions.\n", file, linenum, args[0]);
3511 err_code |= ERR_ALERT | ERR_FATAL;
3512 goto out;
3513 }
3514 }
3515 }
3516 else if (strcmp(args[0], "hash-balance-factor") == 0) {
3517 if (*(args[1]) == 0) {
3518 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3519 err_code |= ERR_ALERT | ERR_FATAL;
3520 goto out;
3521 }
Willy Tarreau76e84f52019-01-14 16:50:58 +01003522 curproxy->lbprm.hash_balance_factor = atol(args[1]);
3523 if (curproxy->lbprm.hash_balance_factor != 0 && curproxy->lbprm.hash_balance_factor <= 100) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003524 ha_alert("parsing [%s:%d] : '%s' must be 0 or greater than 100.\n", file, linenum, args[0]);
3525 err_code |= ERR_ALERT | ERR_FATAL;
3526 goto out;
3527 }
3528 }
3529 else if (strcmp(args[0], "unique-id-format") == 0) {
3530 if (!*(args[1])) {
3531 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3532 err_code |= ERR_ALERT | ERR_FATAL;
3533 goto out;
3534 }
3535 if (*(args[2])) {
3536 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3537 err_code |= ERR_ALERT | ERR_FATAL;
3538 goto out;
3539 }
3540 free(curproxy->conf.uniqueid_format_string);
3541 curproxy->conf.uniqueid_format_string = strdup(args[1]);
3542
3543 free(curproxy->conf.uif_file);
3544 curproxy->conf.uif_file = strdup(curproxy->conf.args.file);
3545 curproxy->conf.uif_line = curproxy->conf.args.line;
3546 }
3547
3548 else if (strcmp(args[0], "unique-id-header") == 0) {
3549 if (!*(args[1])) {
3550 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3551 err_code |= ERR_ALERT | ERR_FATAL;
3552 goto out;
3553 }
3554 free(curproxy->header_unique_id);
3555 curproxy->header_unique_id = strdup(args[1]);
3556 }
3557
3558 else if (strcmp(args[0], "log-format") == 0) {
3559 if (!*(args[1])) {
3560 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3561 err_code |= ERR_ALERT | ERR_FATAL;
3562 goto out;
3563 }
3564 if (*(args[2])) {
3565 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3566 err_code |= ERR_ALERT | ERR_FATAL;
3567 goto out;
3568 }
3569 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
3570 char *oldlogformat = "log-format";
3571
3572 if (curproxy->conf.logformat_string == default_http_log_format)
3573 oldlogformat = "option httplog";
3574 else if (curproxy->conf.logformat_string == default_tcp_log_format)
3575 oldlogformat = "option tcplog";
3576 else if (curproxy->conf.logformat_string == clf_http_log_format)
3577 oldlogformat = "option httplog clf";
3578 ha_warning("parsing [%s:%d]: 'log-format' overrides previous '%s' in 'defaults' section.\n",
3579 file, linenum, oldlogformat);
3580 }
3581 if (curproxy->conf.logformat_string != default_http_log_format &&
3582 curproxy->conf.logformat_string != default_tcp_log_format &&
3583 curproxy->conf.logformat_string != clf_http_log_format)
3584 free(curproxy->conf.logformat_string);
3585 curproxy->conf.logformat_string = strdup(args[1]);
3586
3587 free(curproxy->conf.lfs_file);
3588 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
3589 curproxy->conf.lfs_line = curproxy->conf.args.line;
3590
3591 /* get a chance to improve log-format error reporting by
3592 * reporting the correct line-number when possible.
3593 */
3594 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3595 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format' directive is ignored in backends.\n",
3596 file, linenum, curproxy->id);
3597 err_code |= ERR_WARN;
3598 }
3599 }
3600 else if (!strcmp(args[0], "log-format-sd")) {
3601 if (!*(args[1])) {
3602 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3603 err_code |= ERR_ALERT | ERR_FATAL;
3604 goto out;
3605 }
3606 if (*(args[2])) {
3607 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3608 err_code |= ERR_ALERT | ERR_FATAL;
3609 goto out;
3610 }
3611
3612 if (curproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
3613 free(curproxy->conf.logformat_sd_string);
3614 curproxy->conf.logformat_sd_string = strdup(args[1]);
3615
3616 free(curproxy->conf.lfsd_file);
3617 curproxy->conf.lfsd_file = strdup(curproxy->conf.args.file);
3618 curproxy->conf.lfsd_line = curproxy->conf.args.line;
3619
3620 /* get a chance to improve log-format-sd error reporting by
3621 * reporting the correct line-number when possible.
3622 */
3623 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3624 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format-sd' directive is ignored in backends.\n",
3625 file, linenum, curproxy->id);
3626 err_code |= ERR_WARN;
3627 }
3628 }
3629 else if (!strcmp(args[0], "log-tag")) { /* tag to report to syslog */
3630 if (*(args[1]) == 0) {
3631 ha_alert("parsing [%s:%d] : '%s' expects a tag for use in syslog.\n", file, linenum, args[0]);
3632 err_code |= ERR_ALERT | ERR_FATAL;
3633 goto out;
3634 }
3635 chunk_destroy(&curproxy->log_tag);
3636 chunk_initstr(&curproxy->log_tag, strdup(args[1]));
3637 }
3638 else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
3639 if (!parse_logsrv(args, &curproxy->logsrvs, (kwm == KWM_NO), &errmsg)) {
3640 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
3641 err_code |= ERR_ALERT | ERR_FATAL;
3642 goto out;
3643 }
3644 }
3645 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
3646 int cur_arg;
3647 int port1, port2;
3648 struct sockaddr_storage *sk;
3649 struct protocol *proto;
3650
3651 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3652 err_code |= ERR_WARN;
3653
3654 if (!*args[1]) {
3655 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optionally '%s' <addr>, and '%s' <name>.\n",
3656 file, linenum, "source", "usesrc", "interface");
3657 err_code |= ERR_ALERT | ERR_FATAL;
3658 goto out;
3659 }
3660
3661 /* we must first clear any optional default setting */
3662 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3663 free(curproxy->conn_src.iface_name);
3664 curproxy->conn_src.iface_name = NULL;
3665 curproxy->conn_src.iface_len = 0;
3666
3667 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3668 if (!sk) {
3669 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3670 file, linenum, args[0], args[1], errmsg);
3671 err_code |= ERR_ALERT | ERR_FATAL;
3672 goto out;
3673 }
3674
3675 proto = protocol_by_family(sk->ss_family);
3676 if (!proto || !proto->connect) {
3677 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3678 file, linenum, args[0], args[1]);
3679 err_code |= ERR_ALERT | ERR_FATAL;
3680 goto out;
3681 }
3682
3683 if (port1 != port2) {
3684 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3685 file, linenum, args[0], args[1]);
3686 err_code |= ERR_ALERT | ERR_FATAL;
3687 goto out;
3688 }
3689
3690 curproxy->conn_src.source_addr = *sk;
3691 curproxy->conn_src.opts |= CO_SRC_BIND;
3692
3693 cur_arg = 2;
3694 while (*(args[cur_arg])) {
3695 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
3696#if defined(CONFIG_HAP_TRANSPARENT)
3697 if (!*args[cur_arg + 1]) {
3698 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
3699 file, linenum, "usesrc");
3700 err_code |= ERR_ALERT | ERR_FATAL;
3701 goto out;
3702 }
3703
3704 if (!strcmp(args[cur_arg + 1], "client")) {
3705 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3706 curproxy->conn_src.opts |= CO_SRC_TPROXY_CLI;
3707 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
3708 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3709 curproxy->conn_src.opts |= CO_SRC_TPROXY_CIP;
3710 } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
3711 char *name, *end;
3712
3713 name = args[cur_arg+1] + 7;
3714 while (isspace(*name))
3715 name++;
3716
3717 end = name;
3718 while (*end && !isspace(*end) && *end != ',' && *end != ')')
3719 end++;
3720
3721 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3722 curproxy->conn_src.opts |= CO_SRC_TPROXY_DYN;
3723 curproxy->conn_src.bind_hdr_name = calloc(1, end - name + 1);
3724 curproxy->conn_src.bind_hdr_len = end - name;
3725 memcpy(curproxy->conn_src.bind_hdr_name, name, end - name);
3726 curproxy->conn_src.bind_hdr_name[end-name] = '\0';
3727 curproxy->conn_src.bind_hdr_occ = -1;
3728
3729 /* now look for an occurrence number */
3730 while (isspace(*end))
3731 end++;
3732 if (*end == ',') {
3733 end++;
3734 name = end;
3735 if (*end == '-')
3736 end++;
3737 while (isdigit((int)*end))
3738 end++;
3739 curproxy->conn_src.bind_hdr_occ = strl2ic(name, end-name);
3740 }
3741
3742 if (curproxy->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
3743 ha_alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
3744 " occurrences values smaller than %d.\n",
3745 file, linenum, MAX_HDR_HISTORY);
3746 err_code |= ERR_ALERT | ERR_FATAL;
3747 goto out;
3748 }
3749 } else {
3750 struct sockaddr_storage *sk;
3751
3752 sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3753 if (!sk) {
3754 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3755 file, linenum, args[cur_arg], args[cur_arg+1], errmsg);
3756 err_code |= ERR_ALERT | ERR_FATAL;
3757 goto out;
3758 }
3759
3760 proto = protocol_by_family(sk->ss_family);
3761 if (!proto || !proto->connect) {
3762 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3763 file, linenum, args[cur_arg], args[cur_arg+1]);
3764 err_code |= ERR_ALERT | ERR_FATAL;
3765 goto out;
3766 }
3767
3768 if (port1 != port2) {
3769 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3770 file, linenum, args[cur_arg], args[cur_arg + 1]);
3771 err_code |= ERR_ALERT | ERR_FATAL;
3772 goto out;
3773 }
3774 curproxy->conn_src.tproxy_addr = *sk;
3775 curproxy->conn_src.opts |= CO_SRC_TPROXY_ADDR;
3776 }
3777 global.last_checks |= LSTCHK_NETADM;
3778#else /* no TPROXY support */
3779 ha_alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
3780 file, linenum, "usesrc");
3781 err_code |= ERR_ALERT | ERR_FATAL;
3782 goto out;
3783#endif
3784 cur_arg += 2;
3785 continue;
3786 }
3787
3788 if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
3789#ifdef SO_BINDTODEVICE
3790 if (!*args[cur_arg + 1]) {
3791 ha_alert("parsing [%s:%d] : '%s' : missing interface name.\n",
3792 file, linenum, args[0]);
3793 err_code |= ERR_ALERT | ERR_FATAL;
3794 goto out;
3795 }
3796 free(curproxy->conn_src.iface_name);
3797 curproxy->conn_src.iface_name = strdup(args[cur_arg + 1]);
3798 curproxy->conn_src.iface_len = strlen(curproxy->conn_src.iface_name);
3799 global.last_checks |= LSTCHK_NETADM;
3800#else
3801 ha_alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
3802 file, linenum, args[0], args[cur_arg]);
3803 err_code |= ERR_ALERT | ERR_FATAL;
3804 goto out;
3805#endif
3806 cur_arg += 2;
3807 continue;
3808 }
3809 ha_alert("parsing [%s:%d] : '%s' only supports optional keywords '%s' and '%s'.\n",
3810 file, linenum, args[0], "interface", "usesrc");
3811 err_code |= ERR_ALERT | ERR_FATAL;
3812 goto out;
3813 }
3814 }
3815 else if (!strcmp(args[0], "usesrc")) { /* address to use outside: needs "source" first */
3816 ha_alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
3817 file, linenum, "usesrc", "source");
3818 err_code |= ERR_ALERT | ERR_FATAL;
3819 goto out;
3820 }
3821 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
3822 if (*(args[2]) == 0) {
3823 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3824 file, linenum, args[0]);
3825 err_code |= ERR_ALERT | ERR_FATAL;
3826 goto out;
3827 }
3828
3829 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3830 SMP_OPT_DIR_REQ, ACT_REPLACE, 0,
3831 args[0], args[1], args[2], (const char **)args+3);
3832 if (err_code & ERR_FATAL)
3833 goto out;
3834 }
3835 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
3836 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3837 SMP_OPT_DIR_REQ, ACT_REMOVE, 0,
3838 args[0], args[1], NULL, (const char **)args+2);
3839 if (err_code & ERR_FATAL)
3840 goto out;
3841 }
3842 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
3843 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3844 SMP_OPT_DIR_REQ, ACT_DENY, 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], "reqpass")) { /* pass this header without allowing or denying the request */
3850 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3851 SMP_OPT_DIR_REQ, ACT_PASS, 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], "reqallow")) { /* allow a request if a header matches this regex */
3857 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3858 SMP_OPT_DIR_REQ, ACT_ALLOW, 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], "reqtarpit")) { /* tarpit a request if a header matches this regex */
3864 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3865 SMP_OPT_DIR_REQ, ACT_TARPIT, 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], "reqirep")) { /* replace request header from a regex, ignoring case */
3871 if (*(args[2]) == 0) {
3872 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3873 file, linenum, args[0]);
3874 err_code |= ERR_ALERT | ERR_FATAL;
3875 goto out;
3876 }
3877
3878 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3879 SMP_OPT_DIR_REQ, ACT_REPLACE, REG_ICASE,
3880 args[0], args[1], args[2], (const char **)args+3);
3881 if (err_code & ERR_FATAL)
3882 goto out;
3883 }
3884 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
3885 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3886 SMP_OPT_DIR_REQ, ACT_REMOVE, REG_ICASE,
3887 args[0], args[1], NULL, (const char **)args+2);
3888 if (err_code & ERR_FATAL)
3889 goto out;
3890 }
3891 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
3892 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3893 SMP_OPT_DIR_REQ, ACT_DENY, 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], "reqipass")) { /* pass this header without allowing or denying the request */
3899 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3900 SMP_OPT_DIR_REQ, ACT_PASS, 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], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
3906 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3907 SMP_OPT_DIR_REQ, ACT_ALLOW, 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], "reqitarpit")) { /* tarpit 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_TARPIT, 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], "reqadd")) { /* add request header */
3920 struct cond_wordlist *wl;
3921
3922 if (curproxy == &defproxy) {
3923 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3924 err_code |= ERR_ALERT | ERR_FATAL;
3925 goto out;
3926 }
3927 else if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
3928 err_code |= ERR_WARN;
3929
3930 if (*(args[1]) == 0) {
3931 ha_alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
3932 err_code |= ERR_ALERT | ERR_FATAL;
3933 goto out;
3934 }
3935
3936 if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
3937 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args+2, &errmsg)) == NULL) {
3938 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
3939 file, linenum, args[0], errmsg);
3940 err_code |= ERR_ALERT | ERR_FATAL;
3941 goto out;
3942 }
3943 err_code |= warnif_cond_conflicts(cond,
3944 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
3945 file, linenum);
3946 }
3947 else if (*args[2]) {
3948 ha_alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
3949 file, linenum, args[0], args[2]);
3950 err_code |= ERR_ALERT | ERR_FATAL;
3951 goto out;
3952 }
3953
3954 wl = calloc(1, sizeof(*wl));
3955 wl->cond = cond;
3956 wl->s = strdup(args[1]);
3957 LIST_ADDQ(&curproxy->req_add, &wl->list);
3958 warnif_misplaced_reqadd(curproxy, file, linenum, args[0]);
3959 }
3960 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
3961 if (*(args[2]) == 0) {
3962 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3963 file, linenum, args[0]);
3964 err_code |= ERR_ALERT | ERR_FATAL;
3965 goto out;
3966 }
3967
3968 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3969 SMP_OPT_DIR_RES, ACT_REPLACE, 0,
3970 args[0], args[1], args[2], (const char **)args+3);
3971 if (err_code & ERR_FATAL)
3972 goto out;
3973 }
3974 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
3975 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3976 SMP_OPT_DIR_RES, ACT_REMOVE, 0,
3977 args[0], args[1], NULL, (const char **)args+2);
3978 if (err_code & ERR_FATAL)
3979 goto out;
3980 }
3981 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
3982 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3983 SMP_OPT_DIR_RES, ACT_DENY, 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], "rspirep")) { /* replace response header from a regex ignoring case */
3989 if (*(args[2]) == 0) {
3990 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3991 file, linenum, args[0]);
3992 err_code |= ERR_ALERT | ERR_FATAL;
3993 goto out;
3994 }
3995
3996 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3997 SMP_OPT_DIR_RES, ACT_REPLACE, REG_ICASE,
3998 args[0], args[1], args[2], (const char **)args+3);
3999 if (err_code & ERR_FATAL)
4000 goto out;
4001 }
4002 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
4003 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4004 SMP_OPT_DIR_RES, ACT_REMOVE, REG_ICASE,
4005 args[0], args[1], NULL, (const char **)args+2);
4006 if (err_code & ERR_FATAL)
4007 goto out;
4008 }
4009 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
4010 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4011 SMP_OPT_DIR_RES, ACT_DENY, 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], "rspadd")) { /* add response header */
4017 struct cond_wordlist *wl;
4018
4019 if (curproxy == &defproxy) {
4020 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4021 err_code |= ERR_ALERT | ERR_FATAL;
4022 goto out;
4023 }
4024 else if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4025 err_code |= ERR_WARN;
4026
4027 if (*(args[1]) == 0) {
4028 ha_alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
4029 err_code |= ERR_ALERT | ERR_FATAL;
4030 goto out;
4031 }
4032
4033 if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
4034 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args+2, &errmsg)) == NULL) {
4035 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
4036 file, linenum, args[0], errmsg);
4037 err_code |= ERR_ALERT | ERR_FATAL;
4038 goto out;
4039 }
4040 err_code |= warnif_cond_conflicts(cond,
4041 (curproxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
4042 file, linenum);
4043 }
4044 else if (*args[2]) {
4045 ha_alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
4046 file, linenum, args[0], args[2]);
4047 err_code |= ERR_ALERT | ERR_FATAL;
4048 goto out;
4049 }
4050
4051 wl = calloc(1, sizeof(*wl));
4052 wl->cond = cond;
4053 wl->s = strdup(args[1]);
4054 LIST_ADDQ(&curproxy->rsp_add, &wl->list);
4055 }
4056 else if (!strcmp(args[0], "errorloc") ||
4057 !strcmp(args[0], "errorloc302") ||
4058 !strcmp(args[0], "errorloc303")) { /* error location */
4059 int errnum, errlen;
4060 char *err;
4061
4062 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4063 err_code |= ERR_WARN;
4064
4065 if (*(args[2]) == 0) {
4066 ha_alert("parsing [%s:%d] : <%s> expects <status_code> and <url> as arguments.\n", file, linenum, args[0]);
4067 err_code |= ERR_ALERT | ERR_FATAL;
4068 goto out;
4069 }
4070
4071 errnum = atol(args[1]);
4072 if (!strcmp(args[0], "errorloc303")) {
4073 errlen = strlen(HTTP_303) + strlen(args[2]) + 5;
4074 err = malloc(errlen);
4075 errlen = snprintf(err, errlen, "%s%s\r\n\r\n", HTTP_303, args[2]);
4076 } else {
4077 errlen = strlen(HTTP_302) + strlen(args[2]) + 5;
4078 err = malloc(errlen);
4079 errlen = snprintf(err, errlen, "%s%s\r\n\r\n", HTTP_302, args[2]);
4080 }
4081
4082 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
4083 if (http_err_codes[rc] == errnum) {
4084 chunk_destroy(&curproxy->errmsg[rc]);
4085 chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen);
4086 break;
4087 }
4088 }
4089
4090 if (rc >= HTTP_ERR_SIZE) {
4091 ha_warning("parsing [%s:%d] : status code %d not handled by '%s', error relocation will be ignored.\n",
4092 file, linenum, errnum, args[0]);
4093 free(err);
4094 }
4095 }
4096 else if (!strcmp(args[0], "errorfile")) { /* error message from a file */
4097 int errnum, errlen, fd;
4098 char *err;
4099 struct stat stat;
4100
4101 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4102 err_code |= ERR_WARN;
4103
4104 if (*(args[2]) == 0) {
4105 ha_alert("parsing [%s:%d] : <%s> expects <status_code> and <file> as arguments.\n", file, linenum, args[0]);
4106 err_code |= ERR_ALERT | ERR_FATAL;
4107 goto out;
4108 }
4109
4110 fd = open(args[2], O_RDONLY);
4111 if ((fd < 0) || (fstat(fd, &stat) < 0)) {
4112 ha_alert("parsing [%s:%d] : error opening file <%s> for custom error message <%s>.\n",
4113 file, linenum, args[2], args[1]);
4114 if (fd >= 0)
4115 close(fd);
4116 err_code |= ERR_ALERT | ERR_FATAL;
4117 goto out;
4118 }
4119
4120 if (stat.st_size <= global.tune.bufsize) {
4121 errlen = stat.st_size;
4122 } else {
4123 ha_warning("parsing [%s:%d] : custom error message file <%s> larger than %d bytes. Truncating.\n",
4124 file, linenum, args[2], global.tune.bufsize);
4125 err_code |= ERR_WARN;
4126 errlen = global.tune.bufsize;
4127 }
4128
4129 err = malloc(errlen); /* malloc() must succeed during parsing */
4130 errnum = read(fd, err, errlen);
4131 if (errnum != errlen) {
4132 ha_alert("parsing [%s:%d] : error reading file <%s> for custom error message <%s>.\n",
4133 file, linenum, args[2], args[1]);
4134 close(fd);
4135 free(err);
4136 err_code |= ERR_ALERT | ERR_FATAL;
4137 goto out;
4138 }
4139 close(fd);
4140
4141 errnum = atol(args[1]);
4142 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
4143 if (http_err_codes[rc] == errnum) {
4144 chunk_destroy(&curproxy->errmsg[rc]);
4145 chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen);
4146 break;
4147 }
4148 }
4149
4150 if (rc >= HTTP_ERR_SIZE) {
4151 ha_warning("parsing [%s:%d] : status code %d not handled by '%s', error customization will be ignored.\n",
4152 file, linenum, errnum, args[0]);
4153 err_code |= ERR_WARN;
4154 free(err);
4155 }
4156 }
4157 else {
4158 struct cfg_kw_list *kwl;
4159 int index;
4160
4161 list_for_each_entry(kwl, &cfg_keywords.list, list) {
4162 for (index = 0; kwl->kw[index].kw != NULL; index++) {
4163 if (kwl->kw[index].section != CFG_LISTEN)
4164 continue;
4165 if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
4166 /* prepare error message just in case */
4167 rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, file, linenum, &errmsg);
4168 if (rc < 0) {
4169 ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4170 err_code |= ERR_ALERT | ERR_FATAL;
4171 goto out;
4172 }
4173 else if (rc > 0) {
4174 ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4175 err_code |= ERR_WARN;
4176 goto out;
4177 }
4178 goto out;
4179 }
4180 }
4181 }
4182
4183 ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
4184 err_code |= ERR_ALERT | ERR_FATAL;
4185 goto out;
4186 }
4187 out:
4188 free(errmsg);
4189 return err_code;
4190}