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