blob: 31c61c2d8ebaf165fbfebd26793029ab4121cb6f [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")) {
Emeric Brun33f0a732020-07-21 16:54:36 +0200696 err_code |= parse_server(file, linenum, args, curproxy, &defproxy, 1, 0, 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 */
Christopher Faulet816a84e2020-05-20 16:15:02 +02002473 int reqlen = strlen(args[2]) + strlen(args[3]) + strlen("HTTP/1.0\r\n") + 3;
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
Christopher Fauletf304ad32020-04-09 08:44:06 +02002483 if (hdrs == body)
2484 hdrs = NULL;
2485 if (hdrs) {
2486 *hdrs = '\0';
2487 hdrs += 2;
2488 }
2489 if (body) {
2490 *body = '\0';
2491 body += 4;
2492 }
2493
2494 curproxy->check_len = strlen(args[2]) + strlen(args[3]) + strlen(vsn) + 4;
2495 curproxy->check_req = malloc(curproxy->check_len+1);
2496 snprintf(curproxy->check_req, curproxy->check_len+1, "%s %s %s\r\n", args[2], args[3], vsn);
2497
2498 if (hdrs) {
2499 curproxy->check_hdrs_len = strlen(hdrs) + 2;
2500 curproxy->check_hdrs = malloc(curproxy->check_hdrs_len+1);
2501 snprintf(curproxy->check_hdrs, curproxy->check_hdrs_len+1, "%s\r\n", hdrs);
2502 }
2503
2504 if (body) {
2505 curproxy->check_body_len = strlen(body);
2506 curproxy->check_body = strdup(body);
2507 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002508 }
2509 if (alertif_too_many_args_idx(3, 1, file, linenum, args, &err_code))
2510 goto out;
2511 }
2512 else if (!strcmp(args[1], "ssl-hello-chk")) {
2513 /* use SSLv3 CLIENT HELLO to check servers' health */
2514 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2515 err_code |= ERR_WARN;
2516
2517 free(curproxy->check_req);
2518 curproxy->check_req = NULL;
2519 curproxy->options2 &= ~PR_O2_CHK_ANY;
2520 curproxy->options2 |= PR_O2_SSL3_CHK;
2521
2522 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2523 goto out;
2524 }
2525 else if (!strcmp(args[1], "smtpchk")) {
2526 /* use SMTP request to check servers' health */
2527 free(curproxy->check_req);
2528 curproxy->check_req = NULL;
2529 curproxy->options2 &= ~PR_O2_CHK_ANY;
2530 curproxy->options2 |= PR_O2_SMTP_CHK;
2531
2532 if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */
2533 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2534 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2535 } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */
2536 if (!strcmp(args[2], "EHLO") || !strcmp(args[2], "HELO")) {
2537 int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" \r\n") + 1;
2538 curproxy->check_req = malloc(reqlen);
2539 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2540 "%s %s\r\n", args[2], args[3]); /* HELO hostname */
2541 } else {
2542 /* this just hits the default for now, but you could potentially expand it to allow for other stuff
2543 though, it's unlikely you'd want to send anything other than an EHLO or HELO */
2544 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2545 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2546 }
2547 }
2548 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2549 goto out;
2550 }
2551 else if (!strcmp(args[1], "pgsql-check")) {
2552 /* use PostgreSQL request to check servers' health */
2553 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2554 err_code |= ERR_WARN;
2555
2556 free(curproxy->check_req);
2557 curproxy->check_req = NULL;
2558 curproxy->options2 &= ~PR_O2_CHK_ANY;
2559 curproxy->options2 |= PR_O2_PGSQL_CHK;
2560
2561 if (*(args[2])) {
2562 int cur_arg = 2;
2563
2564 while (*(args[cur_arg])) {
2565 if (strcmp(args[cur_arg], "user") == 0) {
2566 char * packet;
2567 uint32_t packet_len;
2568 uint32_t pv;
2569
2570 /* suboption header - needs additional argument for it */
2571 if (*(args[cur_arg+1]) == 0) {
2572 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2573 file, linenum, args[0], args[1], args[cur_arg]);
2574 err_code |= ERR_ALERT | ERR_FATAL;
2575 goto out;
2576 }
2577
2578 /* uint32_t + uint32_t + strlen("user")+1 + strlen(username)+1 + 1 */
2579 packet_len = 4 + 4 + 5 + strlen(args[cur_arg + 1])+1 +1;
2580 pv = htonl(0x30000); /* protocol version 3.0 */
2581
2582 packet = calloc(1, packet_len);
2583
2584 memcpy(packet + 4, &pv, 4);
2585
2586 /* copy "user" */
2587 memcpy(packet + 8, "user", 4);
2588
2589 /* copy username */
2590 memcpy(packet + 13, args[cur_arg+1], strlen(args[cur_arg+1]));
2591
2592 free(curproxy->check_req);
2593 curproxy->check_req = packet;
2594 curproxy->check_len = packet_len;
2595
2596 packet_len = htonl(packet_len);
2597 memcpy(packet, &packet_len, 4);
2598 cur_arg += 2;
2599 } else {
2600 /* unknown suboption - catchall */
2601 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2602 file, linenum, args[0], args[1]);
2603 err_code |= ERR_ALERT | ERR_FATAL;
2604 goto out;
2605 }
2606 } /* end while loop */
2607 }
2608 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2609 goto out;
2610 }
2611
2612 else if (!strcmp(args[1], "redis-check")) {
2613 /* use REDIS PING request to check servers' health */
2614 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2615 err_code |= ERR_WARN;
2616
2617 free(curproxy->check_req);
2618 curproxy->check_req = NULL;
2619 curproxy->options2 &= ~PR_O2_CHK_ANY;
2620 curproxy->options2 |= PR_O2_REDIS_CHK;
2621
2622 curproxy->check_req = malloc(sizeof(DEF_REDIS_CHECK_REQ) - 1);
2623 memcpy(curproxy->check_req, DEF_REDIS_CHECK_REQ, sizeof(DEF_REDIS_CHECK_REQ) - 1);
2624 curproxy->check_len = sizeof(DEF_REDIS_CHECK_REQ) - 1;
2625
2626 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2627 goto out;
2628 }
2629
2630 else if (!strcmp(args[1], "mysql-check")) {
2631 /* use MYSQL request to check servers' health */
2632 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2633 err_code |= ERR_WARN;
2634
2635 free(curproxy->check_req);
2636 curproxy->check_req = NULL;
2637 curproxy->options2 &= ~PR_O2_CHK_ANY;
2638 curproxy->options2 |= PR_O2_MYSQL_CHK;
2639
2640 /* This is an example of a MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte.
2641 * const char mysql40_client_auth_pkt[] = {
2642 * "\x0e\x00\x00" // packet length
2643 * "\x01" // packet number
2644 * "\x00\x00" // client capabilities
2645 * "\x00\x00\x01" // max packet
2646 * "haproxy\x00" // username (null terminated string)
2647 * "\x00" // filler (always 0x00)
2648 * "\x01\x00\x00" // packet length
2649 * "\x00" // packet number
2650 * "\x01" // COM_QUIT command
2651 * };
2652 */
2653
2654 /* This is an example of a MySQL >=4.1 client Authentication packet provided by Nenad Merdanovic.
2655 * const char mysql41_client_auth_pkt[] = {
2656 * "\x0e\x00\x00\" // packet length
2657 * "\x01" // packet number
2658 * "\x00\x00\x00\x00" // client capabilities
2659 * "\x00\x00\x00\x01" // max packet
2660 * "\x21" // character set (UTF-8)
2661 * char[23] // All zeroes
2662 * "haproxy\x00" // username (null terminated string)
2663 * "\x00" // filler (always 0x00)
2664 * "\x01\x00\x00" // packet length
2665 * "\x00" // packet number
2666 * "\x01" // COM_QUIT command
2667 * };
2668 */
2669
2670
2671 if (*(args[2])) {
2672 int cur_arg = 2;
2673
2674 while (*(args[cur_arg])) {
2675 if (strcmp(args[cur_arg], "user") == 0) {
2676 char *mysqluser;
2677 int packetlen, reqlen, userlen;
2678
2679 /* suboption header - needs additional argument for it */
2680 if (*(args[cur_arg+1]) == 0) {
2681 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2682 file, linenum, args[0], args[1], args[cur_arg]);
2683 err_code |= ERR_ALERT | ERR_FATAL;
2684 goto out;
2685 }
2686 mysqluser = args[cur_arg + 1];
2687 userlen = strlen(mysqluser);
2688
2689 if (*(args[cur_arg+2])) {
2690 if (!strcmp(args[cur_arg+2], "post-41")) {
2691 packetlen = userlen + 7 + 27;
2692 reqlen = packetlen + 9;
2693
2694 free(curproxy->check_req);
2695 curproxy->check_req = calloc(1, reqlen);
2696 curproxy->check_len = reqlen;
2697
2698 snprintf(curproxy->check_req, 4, "%c%c%c",
2699 ((unsigned char) packetlen & 0xff),
2700 ((unsigned char) (packetlen >> 8) & 0xff),
2701 ((unsigned char) (packetlen >> 16) & 0xff));
2702
2703 curproxy->check_req[3] = 1;
2704 curproxy->check_req[5] = 0x82; // 130
2705 curproxy->check_req[11] = 1;
2706 curproxy->check_req[12] = 33;
2707 memcpy(&curproxy->check_req[36], mysqluser, userlen);
2708 curproxy->check_req[36 + userlen + 1 + 1] = 1;
2709 curproxy->check_req[36 + userlen + 1 + 1 + 4] = 1;
2710 cur_arg += 3;
2711 } else {
2712 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'post-41'.\n", file, linenum, args[cur_arg+2]);
2713 err_code |= ERR_ALERT | ERR_FATAL;
2714 goto out;
2715 }
2716 } else {
2717 packetlen = userlen + 7;
2718 reqlen = packetlen + 9;
2719
2720 free(curproxy->check_req);
2721 curproxy->check_req = calloc(1, reqlen);
2722 curproxy->check_len = reqlen;
2723
2724 snprintf(curproxy->check_req, 4, "%c%c%c",
2725 ((unsigned char) packetlen & 0xff),
2726 ((unsigned char) (packetlen >> 8) & 0xff),
2727 ((unsigned char) (packetlen >> 16) & 0xff));
2728
2729 curproxy->check_req[3] = 1;
2730 curproxy->check_req[5] = 0x80;
2731 curproxy->check_req[8] = 1;
2732 memcpy(&curproxy->check_req[9], mysqluser, userlen);
2733 curproxy->check_req[9 + userlen + 1 + 1] = 1;
2734 curproxy->check_req[9 + userlen + 1 + 1 + 4] = 1;
2735 cur_arg += 2;
2736 }
2737 } else {
2738 /* unknown suboption - catchall */
2739 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2740 file, linenum, args[0], args[1]);
2741 err_code |= ERR_ALERT | ERR_FATAL;
2742 goto out;
2743 }
2744 } /* end while loop */
2745 }
2746 }
2747 else if (!strcmp(args[1], "ldap-check")) {
2748 /* use LDAP request to check servers' health */
2749 free(curproxy->check_req);
2750 curproxy->check_req = NULL;
2751 curproxy->options2 &= ~PR_O2_CHK_ANY;
2752 curproxy->options2 |= PR_O2_LDAP_CHK;
2753
2754 curproxy->check_req = malloc(sizeof(DEF_LDAP_CHECK_REQ) - 1);
2755 memcpy(curproxy->check_req, DEF_LDAP_CHECK_REQ, sizeof(DEF_LDAP_CHECK_REQ) - 1);
2756 curproxy->check_len = sizeof(DEF_LDAP_CHECK_REQ) - 1;
2757 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2758 goto out;
2759 }
2760 else if (!strcmp(args[1], "spop-check")) {
2761 if (curproxy == &defproxy) {
2762 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n",
2763 file, linenum, args[0], args[1]);
2764 err_code |= ERR_ALERT | ERR_FATAL;
2765 goto out;
2766 }
2767 if (curproxy->cap & PR_CAP_FE) {
2768 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'frontend' and 'listen' sections.\n",
2769 file, linenum, args[0], args[1]);
2770 err_code |= ERR_ALERT | ERR_FATAL;
2771 goto out;
2772 }
2773
2774 /* use SPOE request to check servers' health */
2775 free(curproxy->check_req);
2776 curproxy->check_req = NULL;
2777 curproxy->options2 &= ~PR_O2_CHK_ANY;
2778 curproxy->options2 |= PR_O2_SPOP_CHK;
2779
2780 if (spoe_prepare_healthcheck_request(&curproxy->check_req, &curproxy->check_len)) {
2781 ha_alert("parsing [%s:%d] : failed to prepare SPOP healthcheck request.\n", file, linenum);
2782 err_code |= ERR_ALERT | ERR_FATAL;
2783 goto out;
2784 }
2785 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2786 goto out;
2787 }
2788 else if (!strcmp(args[1], "tcp-check")) {
2789 /* use raw TCPCHK send/expect to check servers' health */
2790 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2791 err_code |= ERR_WARN;
2792
2793 free(curproxy->check_req);
2794 curproxy->check_req = NULL;
2795 curproxy->options2 &= ~PR_O2_CHK_ANY;
2796 curproxy->options2 |= PR_O2_TCPCHK_CHK;
2797 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2798 goto out;
2799 }
2800 else if (!strcmp(args[1], "external-check")) {
2801 /* excute an external command to check servers' health */
2802 free(curproxy->check_req);
2803 curproxy->check_req = NULL;
2804 curproxy->options2 &= ~PR_O2_CHK_ANY;
2805 curproxy->options2 |= PR_O2_EXT_CHK;
2806 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2807 goto out;
2808 }
2809 else if (!strcmp(args[1], "forwardfor")) {
2810 int cur_arg;
2811
2812 /* insert x-forwarded-for field, but not for the IP address listed as an except.
2813 * set default options (ie: bitfield, header name, etc)
2814 */
2815
2816 curproxy->options |= PR_O_FWDFOR | PR_O_FF_ALWAYS;
2817
2818 free(curproxy->fwdfor_hdr_name);
2819 curproxy->fwdfor_hdr_name = strdup(DEF_XFORWARDFOR_HDR);
2820 curproxy->fwdfor_hdr_len = strlen(DEF_XFORWARDFOR_HDR);
2821
2822 /* loop to go through arguments - start at 2, since 0+1 = "option" "forwardfor" */
2823 cur_arg = 2;
2824 while (*(args[cur_arg])) {
2825 if (!strcmp(args[cur_arg], "except")) {
2826 /* suboption except - needs additional argument for it */
2827 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_net, &curproxy->except_mask)) {
2828 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2829 file, linenum, args[0], args[1], args[cur_arg]);
2830 err_code |= ERR_ALERT | ERR_FATAL;
2831 goto out;
2832 }
2833 /* flush useless bits */
2834 curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
2835 cur_arg += 2;
2836 } else if (!strcmp(args[cur_arg], "header")) {
2837 /* suboption header - needs additional argument for it */
2838 if (*(args[cur_arg+1]) == 0) {
2839 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2840 file, linenum, args[0], args[1], args[cur_arg]);
2841 err_code |= ERR_ALERT | ERR_FATAL;
2842 goto out;
2843 }
2844 free(curproxy->fwdfor_hdr_name);
2845 curproxy->fwdfor_hdr_name = strdup(args[cur_arg+1]);
2846 curproxy->fwdfor_hdr_len = strlen(curproxy->fwdfor_hdr_name);
2847 cur_arg += 2;
2848 } else if (!strcmp(args[cur_arg], "if-none")) {
2849 curproxy->options &= ~PR_O_FF_ALWAYS;
2850 cur_arg += 1;
2851 } else {
2852 /* unknown suboption - catchall */
2853 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except', 'header' and 'if-none'.\n",
2854 file, linenum, args[0], args[1]);
2855 err_code |= ERR_ALERT | ERR_FATAL;
2856 goto out;
2857 }
2858 } /* end while loop */
2859 }
2860 else if (!strcmp(args[1], "originalto")) {
2861 int cur_arg;
2862
2863 /* insert x-original-to field, but not for the IP address listed as an except.
2864 * set default options (ie: bitfield, header name, etc)
2865 */
2866
2867 curproxy->options |= PR_O_ORGTO;
2868
2869 free(curproxy->orgto_hdr_name);
2870 curproxy->orgto_hdr_name = strdup(DEF_XORIGINALTO_HDR);
2871 curproxy->orgto_hdr_len = strlen(DEF_XORIGINALTO_HDR);
2872
2873 /* loop to go through arguments - start at 2, since 0+1 = "option" "originalto" */
2874 cur_arg = 2;
2875 while (*(args[cur_arg])) {
2876 if (!strcmp(args[cur_arg], "except")) {
2877 /* suboption except - needs additional argument for it */
2878 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_to, &curproxy->except_mask_to)) {
2879 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2880 file, linenum, args[0], args[1], args[cur_arg]);
2881 err_code |= ERR_ALERT | ERR_FATAL;
2882 goto out;
2883 }
2884 /* flush useless bits */
2885 curproxy->except_to.s_addr &= curproxy->except_mask_to.s_addr;
2886 cur_arg += 2;
2887 } else if (!strcmp(args[cur_arg], "header")) {
2888 /* suboption header - needs additional argument for it */
2889 if (*(args[cur_arg+1]) == 0) {
2890 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2891 file, linenum, args[0], args[1], args[cur_arg]);
2892 err_code |= ERR_ALERT | ERR_FATAL;
2893 goto out;
2894 }
2895 free(curproxy->orgto_hdr_name);
2896 curproxy->orgto_hdr_name = strdup(args[cur_arg+1]);
2897 curproxy->orgto_hdr_len = strlen(curproxy->orgto_hdr_name);
2898 cur_arg += 2;
2899 } else {
2900 /* unknown suboption - catchall */
2901 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
2902 file, linenum, args[0], args[1]);
2903 err_code |= ERR_ALERT | ERR_FATAL;
2904 goto out;
2905 }
2906 } /* end while loop */
2907 }
2908 else {
2909 ha_alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
2910 err_code |= ERR_ALERT | ERR_FATAL;
2911 goto out;
2912 }
2913 goto out;
2914 }
2915 else if (!strcmp(args[0], "default_backend")) {
2916 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
2917 err_code |= ERR_WARN;
2918
2919 if (*(args[1]) == 0) {
2920 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
2921 err_code |= ERR_ALERT | ERR_FATAL;
2922 goto out;
2923 }
2924 free(curproxy->defbe.name);
2925 curproxy->defbe.name = strdup(args[1]);
2926
2927 if (alertif_too_many_args_idx(1, 0, file, linenum, args, &err_code))
2928 goto out;
2929 }
2930 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
2931 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2932 err_code |= ERR_WARN;
2933
2934 if (!already_warned(WARN_REDISPATCH_DEPRECATED))
2935 ha_warning("parsing [%s:%d]: keyword '%s' is deprecated in favor of 'option redispatch', and will not be supported by future versions.\n",
2936 file, linenum, args[0]);
2937 err_code |= ERR_WARN;
2938 /* enable reconnections to dispatch */
2939 curproxy->options |= PR_O_REDISP;
2940
2941 if (alertif_too_many_args_idx(1, 0, file, linenum, args, &err_code))
2942 goto out;
2943 }
2944 else if (!strcmp(args[0], "http-reuse")) {
2945 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2946 err_code |= ERR_WARN;
2947
2948 if (strcmp(args[1], "never") == 0) {
2949 /* enable a graceful server shutdown on an HTTP 404 response */
2950 curproxy->options &= ~PR_O_REUSE_MASK;
2951 curproxy->options |= PR_O_REUSE_NEVR;
2952 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2953 goto out;
2954 }
2955 else if (strcmp(args[1], "safe") == 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_SAFE;
2959 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2960 goto out;
2961 }
2962 else if (strcmp(args[1], "aggressive") == 0) {
2963 curproxy->options &= ~PR_O_REUSE_MASK;
2964 curproxy->options |= PR_O_REUSE_AGGR;
2965 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2966 goto out;
2967 }
2968 else if (strcmp(args[1], "always") == 0) {
2969 /* enable a graceful server shutdown on an HTTP 404 response */
2970 curproxy->options &= ~PR_O_REUSE_MASK;
2971 curproxy->options |= PR_O_REUSE_ALWS;
2972 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2973 goto out;
2974 }
2975 else {
2976 ha_alert("parsing [%s:%d] : '%s' only supports 'never', 'safe', 'aggressive', 'always'.\n", file, linenum, args[0]);
2977 err_code |= ERR_ALERT | ERR_FATAL;
2978 goto out;
2979 }
2980 }
2981 else if (!strcmp(args[0], "http-check")) {
2982 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2983 err_code |= ERR_WARN;
2984
2985 if (strcmp(args[1], "disable-on-404") == 0) {
2986 /* enable a graceful server shutdown on an HTTP 404 response */
2987 curproxy->options |= PR_O_DISABLE404;
2988 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2989 goto out;
2990 }
2991 else if (strcmp(args[1], "send-state") == 0) {
2992 /* enable emission of the apparent state of a server in HTTP checks */
2993 curproxy->options2 |= PR_O2_CHK_SNDST;
2994 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2995 goto out;
2996 }
Christopher Fauletf304ad32020-04-09 08:44:06 +02002997 else if (strcmp(args[1], "send") == 0) {
2998 int cur_arg = 2;
2999
3000 free(curproxy->check_hdrs);
3001 free(curproxy->check_body);
3002 curproxy->check_hdrs = curproxy->check_body = NULL;
3003 curproxy->check_hdrs_len = curproxy->check_body_len = 0;
3004 while (*(args[cur_arg])) {
3005 if (strcmp(args[cur_arg], "hdr") == 0) {
3006 int hdr_len;
3007 if (!*(args[cur_arg+1]) || !*(args[cur_arg+2])) {
3008 ha_alert("parsing [%s:%d] : '%s %s' : %s expects a name and a value as parameter.\n",
3009 file, linenum, args[0], args[1], args[cur_arg]);
3010 err_code |= ERR_ALERT | ERR_FATAL;
3011 goto out;
3012 }
3013
3014 cur_arg++;
3015 hdr_len = strlen(args[cur_arg]) + strlen(args[cur_arg+1]) + 4;
3016 curproxy->check_hdrs = my_realloc2(curproxy->check_hdrs, curproxy->check_hdrs_len+hdr_len+1);
3017 if (curproxy->check_hdrs == NULL) {
3018 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
3019 err_code |= ERR_ALERT | ERR_FATAL;
3020 goto out;
3021 }
3022 snprintf(curproxy->check_hdrs + curproxy->check_hdrs_len, hdr_len+1, "%s: %s\r\n", args[cur_arg], args[cur_arg+1]);
3023 curproxy->check_hdrs_len += hdr_len;
3024
3025 cur_arg++;
3026 }
3027 else if (strcmp(args[cur_arg], "body") == 0) {
3028 if (!*(args[cur_arg+1])) {
3029 ha_alert("parsing [%s:%d] : '%s %s' : %s expects a string as parameter.\n",
3030 file, linenum, args[0], args[1], args[cur_arg]);
3031 err_code |= ERR_ALERT | ERR_FATAL;
3032 goto out;
3033 }
3034 cur_arg++;
3035 free(curproxy->check_body);
3036 curproxy->check_body = strdup(args[cur_arg]);
3037 curproxy->check_body_len = strlen(args[cur_arg]);
3038 if (curproxy->check_body == NULL) {
3039 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
3040 err_code |= ERR_ALERT | ERR_FATAL;
3041 goto out;
3042 }
3043 }
3044 else {
3045 ha_alert("parsing [%s:%d] : '%s %s' only supports 'hdr' and 'body', found '%s'.\n",
3046 file, linenum, args[0], args[1], args[cur_arg]);
3047 err_code |= ERR_ALERT | ERR_FATAL;
3048 goto out;
3049 }
3050 cur_arg++;
3051 }
3052
3053 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003054 else if (strcmp(args[1], "expect") == 0) {
3055 const char *ptr_arg;
3056 int cur_arg;
3057
3058 if (curproxy->options2 & PR_O2_EXP_TYPE) {
3059 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
3060 err_code |= ERR_ALERT | ERR_FATAL;
3061 goto out;
3062 }
3063
3064 cur_arg = 2;
3065 /* consider exclamation marks, sole or at the beginning of a word */
3066 while (*(ptr_arg = args[cur_arg])) {
3067 while (*ptr_arg == '!') {
3068 curproxy->options2 ^= PR_O2_EXP_INV;
3069 ptr_arg++;
3070 }
3071 if (*ptr_arg)
3072 break;
3073 cur_arg++;
3074 }
3075 /* now ptr_arg points to the beginning of a word past any possible
3076 * exclamation mark, and cur_arg is the argument which holds this word.
3077 */
3078 if (strcmp(ptr_arg, "status") == 0) {
3079 if (!*(args[cur_arg + 1])) {
3080 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3081 file, linenum, args[0], args[1], ptr_arg);
3082 err_code |= ERR_ALERT | ERR_FATAL;
3083 goto out;
3084 }
3085 curproxy->options2 |= PR_O2_EXP_STS;
3086 free(curproxy->expect_str);
3087 curproxy->expect_str = strdup(args[cur_arg + 1]);
3088 }
3089 else if (strcmp(ptr_arg, "string") == 0) {
3090 if (!*(args[cur_arg + 1])) {
3091 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3092 file, linenum, args[0], args[1], ptr_arg);
3093 err_code |= ERR_ALERT | ERR_FATAL;
3094 goto out;
3095 }
3096 curproxy->options2 |= PR_O2_EXP_STR;
3097 free(curproxy->expect_str);
3098 curproxy->expect_str = strdup(args[cur_arg + 1]);
3099 }
3100 else if (strcmp(ptr_arg, "rstatus") == 0) {
3101 if (!*(args[cur_arg + 1])) {
3102 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3103 file, linenum, args[0], args[1], ptr_arg);
3104 err_code |= ERR_ALERT | ERR_FATAL;
3105 goto out;
3106 }
3107 curproxy->options2 |= PR_O2_EXP_RSTS;
3108 free(curproxy->expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +02003109 regex_free(curproxy->expect_regex);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003110 curproxy->expect_str = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003111 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02003112 if (!(curproxy->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
3113 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003114 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3115 free(error);
3116 err_code |= ERR_ALERT | ERR_FATAL;
3117 goto out;
3118 }
3119 }
3120 else if (strcmp(ptr_arg, "rstring") == 0) {
3121 if (!*(args[cur_arg + 1])) {
3122 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3123 file, linenum, args[0], args[1], ptr_arg);
3124 err_code |= ERR_ALERT | ERR_FATAL;
3125 goto out;
3126 }
3127 curproxy->options2 |= PR_O2_EXP_RSTR;
3128 free(curproxy->expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +02003129 regex_free(curproxy->expect_regex);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003130 curproxy->expect_str = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003131 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02003132 if (!(curproxy->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
3133 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003134 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3135 free(error);
3136 err_code |= ERR_ALERT | ERR_FATAL;
3137 goto out;
3138 }
3139 }
3140 else {
3141 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'status', 'string', 'rstatus', 'rstring', found '%s'.\n",
3142 file, linenum, args[0], args[1], ptr_arg);
3143 err_code |= ERR_ALERT | ERR_FATAL;
3144 goto out;
3145 }
3146 }
3147 else {
3148 ha_alert("parsing [%s:%d] : '%s' only supports 'disable-on-404', 'send-state', 'expect'.\n", file, linenum, args[0]);
3149 err_code |= ERR_ALERT | ERR_FATAL;
3150 goto out;
3151 }
3152 }
3153 else if (!strcmp(args[0], "tcp-check")) {
3154 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3155 err_code |= ERR_WARN;
3156
3157 if (strcmp(args[1], "comment") == 0) {
3158 int cur_arg;
3159 struct tcpcheck_rule *tcpcheck;
3160
3161 cur_arg = 1;
3162 tcpcheck = calloc(1, sizeof(*tcpcheck));
3163 tcpcheck->action = TCPCHK_ACT_COMMENT;
3164
3165 if (!*args[cur_arg + 1]) {
3166 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3167 file, linenum, args[cur_arg]);
3168 err_code |= ERR_ALERT | ERR_FATAL;
3169 goto out;
3170 }
3171
3172 tcpcheck->comment = strdup(args[cur_arg + 1]);
3173
3174 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3175 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
3176 goto out;
3177 }
3178 else if (strcmp(args[1], "connect") == 0) {
3179 const char *ptr_arg;
3180 int cur_arg;
3181 struct tcpcheck_rule *tcpcheck;
3182
3183 /* check if first rule is also a 'connect' action */
3184 tcpcheck = LIST_NEXT(&curproxy->tcpcheck_rules, struct tcpcheck_rule *, list);
3185 while (&tcpcheck->list != &curproxy->tcpcheck_rules &&
3186 tcpcheck->action == TCPCHK_ACT_COMMENT) {
3187 tcpcheck = LIST_NEXT(&tcpcheck->list, struct tcpcheck_rule *, list);
3188 }
3189
3190 if (&tcpcheck->list != &curproxy->tcpcheck_rules
3191 && tcpcheck->action != TCPCHK_ACT_CONNECT) {
3192 ha_alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
3193 file, linenum);
3194 err_code |= ERR_ALERT | ERR_FATAL;
3195 goto out;
3196 }
3197
3198 cur_arg = 2;
3199 tcpcheck = calloc(1, sizeof(*tcpcheck));
3200 tcpcheck->action = TCPCHK_ACT_CONNECT;
3201
3202 /* parsing each parameters to fill up the rule */
3203 while (*(ptr_arg = args[cur_arg])) {
3204 /* tcp port */
3205 if (strcmp(args[cur_arg], "port") == 0) {
3206 if ( (atol(args[cur_arg + 1]) > 65535) ||
3207 (atol(args[cur_arg + 1]) < 1) ){
3208 ha_alert("parsing [%s:%d] : '%s %s %s' expects a valid TCP port (from range 1 to 65535), got %s.\n",
3209 file, linenum, args[0], args[1], "port", args[cur_arg + 1]);
3210 err_code |= ERR_ALERT | ERR_FATAL;
3211 goto out;
3212 }
3213 tcpcheck->port = atol(args[cur_arg + 1]);
3214 cur_arg += 2;
3215 }
3216 /* send proxy protocol */
3217 else if (strcmp(args[cur_arg], "send-proxy") == 0) {
3218 tcpcheck->conn_opts |= TCPCHK_OPT_SEND_PROXY;
3219 cur_arg++;
3220 }
3221#ifdef USE_OPENSSL
3222 else if (strcmp(args[cur_arg], "ssl") == 0) {
3223 curproxy->options |= PR_O_TCPCHK_SSL;
3224 tcpcheck->conn_opts |= TCPCHK_OPT_SSL;
3225 cur_arg++;
3226 }
3227#endif /* USE_OPENSSL */
3228 /* comment for this tcpcheck line */
3229 else if (strcmp(args[cur_arg], "comment") == 0) {
3230 if (!*args[cur_arg + 1]) {
3231 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3232 file, linenum, args[cur_arg]);
3233 err_code |= ERR_ALERT | ERR_FATAL;
3234 goto out;
3235 }
3236 tcpcheck->comment = strdup(args[cur_arg + 1]);
3237 cur_arg += 2;
3238 }
3239 else {
3240#ifdef USE_OPENSSL
3241 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n",
3242#else /* USE_OPENSSL */
3243 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or but got '%s' as argument.\n",
3244#endif /* USE_OPENSSL */
3245 file, linenum, args[0], args[1], args[cur_arg]);
3246 err_code |= ERR_ALERT | ERR_FATAL;
3247 goto out;
3248 }
3249
3250 }
3251
3252 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3253 }
3254 else if (strcmp(args[1], "send") == 0) {
3255 if (! *(args[2]) ) {
3256 /* SEND string expected */
3257 ha_alert("parsing [%s:%d] : '%s %s %s' expects <STRING> as argument.\n",
3258 file, linenum, args[0], args[1], args[2]);
3259 err_code |= ERR_ALERT | ERR_FATAL;
3260 goto out;
3261 } else {
3262 struct tcpcheck_rule *tcpcheck;
3263
3264 tcpcheck = calloc(1, sizeof(*tcpcheck));
3265
3266 tcpcheck->action = TCPCHK_ACT_SEND;
3267 tcpcheck->string_len = strlen(args[2]);
3268 tcpcheck->string = strdup(args[2]);
3269 tcpcheck->expect_regex = NULL;
3270
3271 /* comment for this tcpcheck line */
3272 if (strcmp(args[3], "comment") == 0) {
3273 if (!*args[4]) {
3274 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3275 file, linenum, args[3]);
3276 err_code |= ERR_ALERT | ERR_FATAL;
3277 goto out;
3278 }
3279 tcpcheck->comment = strdup(args[4]);
3280 }
3281
3282 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3283 }
3284 }
3285 else if (strcmp(args[1], "send-binary") == 0) {
3286 if (! *(args[2]) ) {
3287 /* SEND binary string expected */
3288 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument.\n",
3289 file, linenum, args[0], args[1], args[2]);
3290 err_code |= ERR_ALERT | ERR_FATAL;
3291 goto out;
3292 } else {
3293 struct tcpcheck_rule *tcpcheck;
3294 char *err = NULL;
3295
3296 tcpcheck = calloc(1, sizeof(*tcpcheck));
3297
3298 tcpcheck->action = TCPCHK_ACT_SEND;
3299 if (parse_binary(args[2], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3300 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3301 file, linenum, args[0], args[1], args[2], err);
3302 err_code |= ERR_ALERT | ERR_FATAL;
3303 goto out;
3304 }
3305 tcpcheck->expect_regex = NULL;
3306
3307 /* comment for this tcpcheck line */
3308 if (strcmp(args[3], "comment") == 0) {
3309 if (!*args[4]) {
3310 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3311 file, linenum, args[3]);
3312 err_code |= ERR_ALERT | ERR_FATAL;
3313 goto out;
3314 }
3315 tcpcheck->comment = strdup(args[4]);
3316 }
3317
3318 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3319 }
3320 }
3321 else if (strcmp(args[1], "expect") == 0) {
3322 const char *ptr_arg;
3323 int cur_arg;
3324 int inverse = 0;
3325
3326 if (curproxy->options2 & PR_O2_EXP_TYPE) {
3327 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
3328 err_code |= ERR_ALERT | ERR_FATAL;
3329 goto out;
3330 }
3331
3332 cur_arg = 2;
3333 /* consider exclamation marks, sole or at the beginning of a word */
3334 while (*(ptr_arg = args[cur_arg])) {
3335 while (*ptr_arg == '!') {
3336 inverse = !inverse;
3337 ptr_arg++;
3338 }
3339 if (*ptr_arg)
3340 break;
3341 cur_arg++;
3342 }
3343 /* now ptr_arg points to the beginning of a word past any possible
3344 * exclamation mark, and cur_arg is the argument which holds this word.
3345 */
3346 if (strcmp(ptr_arg, "binary") == 0) {
3347 struct tcpcheck_rule *tcpcheck;
3348 char *err = NULL;
3349
3350 if (!*(args[cur_arg + 1])) {
3351 ha_alert("parsing [%s:%d] : '%s %s %s' expects <binary string> as an argument.\n",
3352 file, linenum, args[0], args[1], ptr_arg);
3353 err_code |= ERR_ALERT | ERR_FATAL;
3354 goto out;
3355 }
3356
3357 tcpcheck = calloc(1, sizeof(*tcpcheck));
3358
3359 tcpcheck->action = TCPCHK_ACT_EXPECT;
3360 if (parse_binary(args[cur_arg + 1], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3361 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3362 file, linenum, args[0], args[1], args[2], err);
3363 err_code |= ERR_ALERT | ERR_FATAL;
3364 goto out;
3365 }
3366 tcpcheck->expect_regex = NULL;
3367 tcpcheck->inverse = inverse;
3368
3369 /* tcpcheck comment */
3370 cur_arg += 2;
3371 if (strcmp(args[cur_arg], "comment") == 0) {
3372 if (!*args[cur_arg + 1]) {
3373 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3374 file, linenum, args[cur_arg + 1]);
3375 err_code |= ERR_ALERT | ERR_FATAL;
3376 goto out;
3377 }
3378 tcpcheck->comment = strdup(args[cur_arg + 1]);
3379 }
3380
3381 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3382 }
3383 else if (strcmp(ptr_arg, "string") == 0) {
3384 struct tcpcheck_rule *tcpcheck;
3385
3386 if (!*(args[cur_arg + 1])) {
3387 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3388 file, linenum, args[0], args[1], ptr_arg);
3389 err_code |= ERR_ALERT | ERR_FATAL;
3390 goto out;
3391 }
3392
3393 tcpcheck = calloc(1, sizeof(*tcpcheck));
3394
3395 tcpcheck->action = TCPCHK_ACT_EXPECT;
3396 tcpcheck->string_len = strlen(args[cur_arg + 1]);
3397 tcpcheck->string = strdup(args[cur_arg + 1]);
3398 tcpcheck->expect_regex = NULL;
3399 tcpcheck->inverse = inverse;
3400
3401 /* tcpcheck comment */
3402 cur_arg += 2;
3403 if (strcmp(args[cur_arg], "comment") == 0) {
3404 if (!*args[cur_arg + 1]) {
3405 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3406 file, linenum, args[cur_arg + 1]);
3407 err_code |= ERR_ALERT | ERR_FATAL;
3408 goto out;
3409 }
3410 tcpcheck->comment = strdup(args[cur_arg + 1]);
3411 }
3412
3413 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3414 }
3415 else if (strcmp(ptr_arg, "rstring") == 0) {
3416 struct tcpcheck_rule *tcpcheck;
3417
3418 if (!*(args[cur_arg + 1])) {
3419 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3420 file, linenum, args[0], args[1], ptr_arg);
3421 err_code |= ERR_ALERT | ERR_FATAL;
3422 goto out;
3423 }
3424
3425 tcpcheck = calloc(1, sizeof(*tcpcheck));
3426
3427 tcpcheck->action = TCPCHK_ACT_EXPECT;
3428 tcpcheck->string_len = 0;
3429 tcpcheck->string = NULL;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003430 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02003431 if (!(tcpcheck->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
3432 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003433 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3434 free(error);
3435 err_code |= ERR_ALERT | ERR_FATAL;
3436 goto out;
3437 }
3438 tcpcheck->inverse = inverse;
3439
3440 /* tcpcheck comment */
3441 cur_arg += 2;
3442 if (strcmp(args[cur_arg], "comment") == 0) {
3443 if (!*args[cur_arg + 1]) {
3444 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3445 file, linenum, args[cur_arg + 1]);
3446 err_code |= ERR_ALERT | ERR_FATAL;
3447 goto out;
3448 }
3449 tcpcheck->comment = strdup(args[cur_arg + 1]);
3450 }
3451
3452 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3453 }
3454 else {
3455 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'binary', 'string', 'rstring', found '%s'.\n",
3456 file, linenum, args[0], args[1], ptr_arg);
3457 err_code |= ERR_ALERT | ERR_FATAL;
3458 goto out;
3459 }
3460 }
3461 else {
3462 ha_alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
3463 err_code |= ERR_ALERT | ERR_FATAL;
3464 goto out;
3465 }
3466 }
3467 else if (!strcmp(args[0], "monitor")) {
3468 if (curproxy == &defproxy) {
3469 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3470 err_code |= ERR_ALERT | ERR_FATAL;
3471 goto out;
3472 }
3473
3474 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3475 err_code |= ERR_WARN;
3476
3477 if (strcmp(args[1], "fail") == 0) {
3478 /* add a condition to fail monitor requests */
3479 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
3480 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
3481 file, linenum, args[0], args[1]);
3482 err_code |= ERR_ALERT | ERR_FATAL;
3483 goto out;
3484 }
3485
3486 err_code |= warnif_misplaced_monitor(curproxy, file, linenum, "monitor fail");
3487 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
3488 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
3489 file, linenum, args[0], args[1], errmsg);
3490 err_code |= ERR_ALERT | ERR_FATAL;
3491 goto out;
3492 }
3493 LIST_ADDQ(&curproxy->mon_fail_cond, &cond->list);
3494 }
3495 else {
3496 ha_alert("parsing [%s:%d] : '%s' only supports 'fail'.\n", file, linenum, args[0]);
3497 err_code |= ERR_ALERT | ERR_FATAL;
3498 goto out;
3499 }
3500 }
Willy Tarreaue5733232019-05-22 19:24:06 +02003501#ifdef USE_TPROXY
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003502 else if (!strcmp(args[0], "transparent")) {
3503 /* enable transparent proxy connections */
3504 curproxy->options |= PR_O_TRANSP;
3505 if (alertif_too_many_args(0, file, linenum, args, &err_code))
3506 goto out;
3507 }
3508#endif
3509 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3510 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
3511 err_code |= ERR_WARN;
3512
3513 if (*(args[1]) == 0) {
3514 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3515 err_code |= ERR_ALERT | ERR_FATAL;
3516 goto out;
3517 }
3518 curproxy->maxconn = atol(args[1]);
3519 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3520 goto out;
3521 }
3522 else if (!strcmp(args[0], "backlog")) { /* backlog */
3523 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3524 err_code |= ERR_WARN;
3525
3526 if (*(args[1]) == 0) {
3527 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3528 err_code |= ERR_ALERT | ERR_FATAL;
3529 goto out;
3530 }
3531 curproxy->backlog = atol(args[1]);
3532 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3533 goto out;
3534 }
3535 else if (!strcmp(args[0], "fullconn")) { /* fullconn */
3536 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
3537 err_code |= ERR_WARN;
3538
3539 if (*(args[1]) == 0) {
3540 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3541 err_code |= ERR_ALERT | ERR_FATAL;
3542 goto out;
3543 }
3544 curproxy->fullconn = atol(args[1]);
3545 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3546 goto out;
3547 }
3548 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3549 if (*(args[1]) == 0) {
3550 ha_alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
3551 err_code |= ERR_ALERT | ERR_FATAL;
3552 goto out;
3553 }
3554 err = parse_time_err(args[1], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +02003555 if (err == PARSE_TIME_OVER) {
3556 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to grace time, maximum value is 2147483647 ms (~24.8 days).\n",
3557 file, linenum, args[1]);
3558 err_code |= ERR_ALERT | ERR_FATAL;
3559 goto out;
3560 }
3561 else if (err == PARSE_TIME_UNDER) {
3562 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to grace time, minimum non-null value is 1 ms.\n",
3563 file, linenum, args[1]);
3564 err_code |= ERR_ALERT | ERR_FATAL;
3565 goto out;
3566 }
3567 else if (err) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003568 ha_alert("parsing [%s:%d] : unexpected character '%c' in grace time.\n",
3569 file, linenum, *err);
3570 err_code |= ERR_ALERT | ERR_FATAL;
3571 goto out;
3572 }
3573 curproxy->grace = val;
3574 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3575 goto out;
3576 }
3577 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3578 struct sockaddr_storage *sk;
3579 int port1, port2;
3580 struct protocol *proto;
3581
3582 if (curproxy == &defproxy) {
3583 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3584 err_code |= ERR_ALERT | ERR_FATAL;
3585 goto out;
3586 }
3587 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3588 err_code |= ERR_WARN;
3589
3590 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3591 if (!sk) {
3592 ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
3593 err_code |= ERR_ALERT | ERR_FATAL;
3594 goto out;
3595 }
3596
3597 proto = protocol_by_family(sk->ss_family);
3598 if (!proto || !proto->connect) {
3599 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3600 file, linenum, args[0], args[1]);
3601 err_code |= ERR_ALERT | ERR_FATAL;
3602 goto out;
3603 }
3604
3605 if (port1 != port2) {
3606 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'.\n",
3607 file, linenum, args[0], args[1]);
3608 err_code |= ERR_ALERT | ERR_FATAL;
3609 goto out;
3610 }
3611
3612 if (!port1) {
3613 ha_alert("parsing [%s:%d] : '%s' : missing port number in '%s', <addr:port> expected.\n",
3614 file, linenum, args[0], args[1]);
3615 err_code |= ERR_ALERT | ERR_FATAL;
3616 goto out;
3617 }
3618
3619 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3620 goto out;
3621
3622 curproxy->dispatch_addr = *sk;
3623 curproxy->options |= PR_O_DISPATCH;
3624 }
3625 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
3626 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3627 err_code |= ERR_WARN;
3628
3629 if (backend_parse_balance((const char **)args + 1, &errmsg, curproxy) < 0) {
3630 ha_alert("parsing [%s:%d] : %s %s\n", file, linenum, args[0], errmsg);
3631 err_code |= ERR_ALERT | ERR_FATAL;
3632 goto out;
3633 }
3634 }
3635 else if (!strcmp(args[0], "hash-type")) { /* set hashing method */
3636 /**
3637 * The syntax for hash-type config element is
3638 * hash-type {map-based|consistent} [[<algo>] avalanche]
3639 *
3640 * The default hash function is sdbm for map-based and sdbm+avalanche for consistent.
3641 */
3642 curproxy->lbprm.algo &= ~(BE_LB_HASH_TYPE | BE_LB_HASH_FUNC | BE_LB_HASH_MOD);
3643
3644 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3645 err_code |= ERR_WARN;
3646
3647 if (strcmp(args[1], "consistent") == 0) { /* use consistent hashing */
3648 curproxy->lbprm.algo |= BE_LB_HASH_CONS;
3649 }
3650 else if (strcmp(args[1], "map-based") == 0) { /* use map-based hashing */
3651 curproxy->lbprm.algo |= BE_LB_HASH_MAP;
3652 }
3653 else if (strcmp(args[1], "avalanche") == 0) {
3654 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]);
3655 err_code |= ERR_ALERT | ERR_FATAL;
3656 goto out;
3657 }
3658 else {
3659 ha_alert("parsing [%s:%d] : '%s' only supports 'consistent' and 'map-based'.\n", file, linenum, args[0]);
3660 err_code |= ERR_ALERT | ERR_FATAL;
3661 goto out;
3662 }
3663
3664 /* set the hash function to use */
3665 if (!*args[2]) {
3666 /* the default algo is sdbm */
3667 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3668
3669 /* if consistent with no argument, then avalanche modifier is also applied */
3670 if ((curproxy->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS)
3671 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3672 } else {
3673 /* set the hash function */
3674 if (!strcmp(args[2], "sdbm")) {
3675 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3676 }
3677 else if (!strcmp(args[2], "djb2")) {
3678 curproxy->lbprm.algo |= BE_LB_HFCN_DJB2;
3679 }
3680 else if (!strcmp(args[2], "wt6")) {
3681 curproxy->lbprm.algo |= BE_LB_HFCN_WT6;
3682 }
3683 else if (!strcmp(args[2], "crc32")) {
3684 curproxy->lbprm.algo |= BE_LB_HFCN_CRC32;
3685 }
3686 else {
3687 ha_alert("parsing [%s:%d] : '%s' only supports 'sdbm', 'djb2', 'crc32', or 'wt6' hash functions.\n", file, linenum, args[0]);
3688 err_code |= ERR_ALERT | ERR_FATAL;
3689 goto out;
3690 }
3691
3692 /* set the hash modifier */
3693 if (!strcmp(args[3], "avalanche")) {
3694 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3695 }
3696 else if (*args[3]) {
3697 ha_alert("parsing [%s:%d] : '%s' only supports 'avalanche' as a modifier for hash functions.\n", file, linenum, args[0]);
3698 err_code |= ERR_ALERT | ERR_FATAL;
3699 goto out;
3700 }
3701 }
3702 }
3703 else if (strcmp(args[0], "hash-balance-factor") == 0) {
3704 if (*(args[1]) == 0) {
3705 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3706 err_code |= ERR_ALERT | ERR_FATAL;
3707 goto out;
3708 }
Willy Tarreau76e84f52019-01-14 16:50:58 +01003709 curproxy->lbprm.hash_balance_factor = atol(args[1]);
3710 if (curproxy->lbprm.hash_balance_factor != 0 && curproxy->lbprm.hash_balance_factor <= 100) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003711 ha_alert("parsing [%s:%d] : '%s' must be 0 or greater than 100.\n", file, linenum, args[0]);
3712 err_code |= ERR_ALERT | ERR_FATAL;
3713 goto out;
3714 }
3715 }
3716 else if (strcmp(args[0], "unique-id-format") == 0) {
3717 if (!*(args[1])) {
3718 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3719 err_code |= ERR_ALERT | ERR_FATAL;
3720 goto out;
3721 }
3722 if (*(args[2])) {
3723 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3724 err_code |= ERR_ALERT | ERR_FATAL;
3725 goto out;
3726 }
3727 free(curproxy->conf.uniqueid_format_string);
3728 curproxy->conf.uniqueid_format_string = strdup(args[1]);
3729
3730 free(curproxy->conf.uif_file);
3731 curproxy->conf.uif_file = strdup(curproxy->conf.args.file);
3732 curproxy->conf.uif_line = curproxy->conf.args.line;
3733 }
3734
3735 else if (strcmp(args[0], "unique-id-header") == 0) {
3736 if (!*(args[1])) {
3737 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3738 err_code |= ERR_ALERT | ERR_FATAL;
3739 goto out;
3740 }
3741 free(curproxy->header_unique_id);
3742 curproxy->header_unique_id = strdup(args[1]);
3743 }
3744
3745 else if (strcmp(args[0], "log-format") == 0) {
3746 if (!*(args[1])) {
3747 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3748 err_code |= ERR_ALERT | ERR_FATAL;
3749 goto out;
3750 }
3751 if (*(args[2])) {
3752 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3753 err_code |= ERR_ALERT | ERR_FATAL;
3754 goto out;
3755 }
3756 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
3757 char *oldlogformat = "log-format";
3758
3759 if (curproxy->conf.logformat_string == default_http_log_format)
3760 oldlogformat = "option httplog";
3761 else if (curproxy->conf.logformat_string == default_tcp_log_format)
3762 oldlogformat = "option tcplog";
3763 else if (curproxy->conf.logformat_string == clf_http_log_format)
3764 oldlogformat = "option httplog clf";
3765 ha_warning("parsing [%s:%d]: 'log-format' overrides previous '%s' in 'defaults' section.\n",
3766 file, linenum, oldlogformat);
3767 }
3768 if (curproxy->conf.logformat_string != default_http_log_format &&
3769 curproxy->conf.logformat_string != default_tcp_log_format &&
3770 curproxy->conf.logformat_string != clf_http_log_format)
3771 free(curproxy->conf.logformat_string);
3772 curproxy->conf.logformat_string = strdup(args[1]);
3773
3774 free(curproxy->conf.lfs_file);
3775 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
3776 curproxy->conf.lfs_line = curproxy->conf.args.line;
3777
3778 /* get a chance to improve log-format error reporting by
3779 * reporting the correct line-number when possible.
3780 */
3781 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3782 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format' directive is ignored in backends.\n",
3783 file, linenum, curproxy->id);
3784 err_code |= ERR_WARN;
3785 }
3786 }
3787 else if (!strcmp(args[0], "log-format-sd")) {
3788 if (!*(args[1])) {
3789 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3790 err_code |= ERR_ALERT | ERR_FATAL;
3791 goto out;
3792 }
3793 if (*(args[2])) {
3794 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3795 err_code |= ERR_ALERT | ERR_FATAL;
3796 goto out;
3797 }
3798
3799 if (curproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
3800 free(curproxy->conf.logformat_sd_string);
3801 curproxy->conf.logformat_sd_string = strdup(args[1]);
3802
3803 free(curproxy->conf.lfsd_file);
3804 curproxy->conf.lfsd_file = strdup(curproxy->conf.args.file);
3805 curproxy->conf.lfsd_line = curproxy->conf.args.line;
3806
3807 /* get a chance to improve log-format-sd error reporting by
3808 * reporting the correct line-number when possible.
3809 */
3810 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3811 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format-sd' directive is ignored in backends.\n",
3812 file, linenum, curproxy->id);
3813 err_code |= ERR_WARN;
3814 }
3815 }
3816 else if (!strcmp(args[0], "log-tag")) { /* tag to report to syslog */
3817 if (*(args[1]) == 0) {
3818 ha_alert("parsing [%s:%d] : '%s' expects a tag for use in syslog.\n", file, linenum, args[0]);
3819 err_code |= ERR_ALERT | ERR_FATAL;
3820 goto out;
3821 }
3822 chunk_destroy(&curproxy->log_tag);
3823 chunk_initstr(&curproxy->log_tag, strdup(args[1]));
3824 }
3825 else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
3826 if (!parse_logsrv(args, &curproxy->logsrvs, (kwm == KWM_NO), &errmsg)) {
3827 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
3828 err_code |= ERR_ALERT | ERR_FATAL;
3829 goto out;
3830 }
3831 }
3832 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
3833 int cur_arg;
3834 int port1, port2;
3835 struct sockaddr_storage *sk;
3836 struct protocol *proto;
3837
3838 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3839 err_code |= ERR_WARN;
3840
3841 if (!*args[1]) {
3842 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optionally '%s' <addr>, and '%s' <name>.\n",
3843 file, linenum, "source", "usesrc", "interface");
3844 err_code |= ERR_ALERT | ERR_FATAL;
3845 goto out;
3846 }
3847
3848 /* we must first clear any optional default setting */
3849 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3850 free(curproxy->conn_src.iface_name);
3851 curproxy->conn_src.iface_name = NULL;
3852 curproxy->conn_src.iface_len = 0;
3853
3854 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3855 if (!sk) {
3856 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3857 file, linenum, args[0], args[1], errmsg);
3858 err_code |= ERR_ALERT | ERR_FATAL;
3859 goto out;
3860 }
3861
3862 proto = protocol_by_family(sk->ss_family);
3863 if (!proto || !proto->connect) {
3864 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3865 file, linenum, args[0], args[1]);
3866 err_code |= ERR_ALERT | ERR_FATAL;
3867 goto out;
3868 }
3869
3870 if (port1 != port2) {
3871 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3872 file, linenum, args[0], args[1]);
3873 err_code |= ERR_ALERT | ERR_FATAL;
3874 goto out;
3875 }
3876
3877 curproxy->conn_src.source_addr = *sk;
3878 curproxy->conn_src.opts |= CO_SRC_BIND;
3879
3880 cur_arg = 2;
3881 while (*(args[cur_arg])) {
3882 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
3883#if defined(CONFIG_HAP_TRANSPARENT)
3884 if (!*args[cur_arg + 1]) {
3885 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
3886 file, linenum, "usesrc");
3887 err_code |= ERR_ALERT | ERR_FATAL;
3888 goto out;
3889 }
3890
3891 if (!strcmp(args[cur_arg + 1], "client")) {
3892 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3893 curproxy->conn_src.opts |= CO_SRC_TPROXY_CLI;
3894 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
3895 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3896 curproxy->conn_src.opts |= CO_SRC_TPROXY_CIP;
3897 } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
3898 char *name, *end;
3899
3900 name = args[cur_arg+1] + 7;
3901 while (isspace(*name))
3902 name++;
3903
3904 end = name;
3905 while (*end && !isspace(*end) && *end != ',' && *end != ')')
3906 end++;
3907
3908 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3909 curproxy->conn_src.opts |= CO_SRC_TPROXY_DYN;
3910 curproxy->conn_src.bind_hdr_name = calloc(1, end - name + 1);
3911 curproxy->conn_src.bind_hdr_len = end - name;
3912 memcpy(curproxy->conn_src.bind_hdr_name, name, end - name);
3913 curproxy->conn_src.bind_hdr_name[end-name] = '\0';
3914 curproxy->conn_src.bind_hdr_occ = -1;
3915
3916 /* now look for an occurrence number */
3917 while (isspace(*end))
3918 end++;
3919 if (*end == ',') {
3920 end++;
3921 name = end;
3922 if (*end == '-')
3923 end++;
3924 while (isdigit((int)*end))
3925 end++;
3926 curproxy->conn_src.bind_hdr_occ = strl2ic(name, end-name);
3927 }
3928
3929 if (curproxy->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
3930 ha_alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
3931 " occurrences values smaller than %d.\n",
3932 file, linenum, MAX_HDR_HISTORY);
3933 err_code |= ERR_ALERT | ERR_FATAL;
3934 goto out;
3935 }
3936 } else {
3937 struct sockaddr_storage *sk;
3938
3939 sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3940 if (!sk) {
3941 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3942 file, linenum, args[cur_arg], args[cur_arg+1], errmsg);
3943 err_code |= ERR_ALERT | ERR_FATAL;
3944 goto out;
3945 }
3946
3947 proto = protocol_by_family(sk->ss_family);
3948 if (!proto || !proto->connect) {
3949 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3950 file, linenum, args[cur_arg], args[cur_arg+1]);
3951 err_code |= ERR_ALERT | ERR_FATAL;
3952 goto out;
3953 }
3954
3955 if (port1 != port2) {
3956 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3957 file, linenum, args[cur_arg], args[cur_arg + 1]);
3958 err_code |= ERR_ALERT | ERR_FATAL;
3959 goto out;
3960 }
3961 curproxy->conn_src.tproxy_addr = *sk;
3962 curproxy->conn_src.opts |= CO_SRC_TPROXY_ADDR;
3963 }
3964 global.last_checks |= LSTCHK_NETADM;
3965#else /* no TPROXY support */
3966 ha_alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
3967 file, linenum, "usesrc");
3968 err_code |= ERR_ALERT | ERR_FATAL;
3969 goto out;
3970#endif
3971 cur_arg += 2;
3972 continue;
3973 }
3974
3975 if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
3976#ifdef SO_BINDTODEVICE
3977 if (!*args[cur_arg + 1]) {
3978 ha_alert("parsing [%s:%d] : '%s' : missing interface name.\n",
3979 file, linenum, args[0]);
3980 err_code |= ERR_ALERT | ERR_FATAL;
3981 goto out;
3982 }
3983 free(curproxy->conn_src.iface_name);
3984 curproxy->conn_src.iface_name = strdup(args[cur_arg + 1]);
3985 curproxy->conn_src.iface_len = strlen(curproxy->conn_src.iface_name);
3986 global.last_checks |= LSTCHK_NETADM;
3987#else
3988 ha_alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
3989 file, linenum, args[0], args[cur_arg]);
3990 err_code |= ERR_ALERT | ERR_FATAL;
3991 goto out;
3992#endif
3993 cur_arg += 2;
3994 continue;
3995 }
3996 ha_alert("parsing [%s:%d] : '%s' only supports optional keywords '%s' and '%s'.\n",
3997 file, linenum, args[0], "interface", "usesrc");
3998 err_code |= ERR_ALERT | ERR_FATAL;
3999 goto out;
4000 }
4001 }
4002 else if (!strcmp(args[0], "usesrc")) { /* address to use outside: needs "source" first */
4003 ha_alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
4004 file, linenum, "usesrc", "source");
4005 err_code |= ERR_ALERT | ERR_FATAL;
4006 goto out;
4007 }
4008 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004009 if (!already_warned(WARN_REQREP_DEPRECATED))
Willy Tarreaudfc85772019-12-17 06:52:51 +01004010 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 +02004011
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004012 if (*(args[2]) == 0) {
4013 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4014 file, linenum, args[0]);
4015 err_code |= ERR_ALERT | ERR_FATAL;
4016 goto out;
4017 }
4018
4019 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4020 SMP_OPT_DIR_REQ, ACT_REPLACE, 0,
4021 args[0], args[1], args[2], (const char **)args+3);
4022 if (err_code & ERR_FATAL)
4023 goto out;
4024 }
4025 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004026 if (!already_warned(WARN_REQDEL_DEPRECATED))
4027 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]);
4028
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004029 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4030 SMP_OPT_DIR_REQ, ACT_REMOVE, 0,
4031 args[0], args[1], NULL, (const char **)args+2);
4032 if (err_code & ERR_FATAL)
4033 goto out;
4034 }
4035 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004036 if (!already_warned(WARN_REQDENY_DEPRECATED))
4037 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]);
4038
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004039 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4040 SMP_OPT_DIR_REQ, ACT_DENY, 0,
4041 args[0], args[1], NULL, (const char **)args+2);
4042 if (err_code & ERR_FATAL)
4043 goto out;
4044 }
4045 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
Willy Tarreau96d51952019-05-22 20:34:35 +02004046 if (!already_warned(WARN_REQPASS_DEPRECATED))
4047 ha_warning("parsing [%s:%d] : The '%s' directive is deprecated and will be removed in next version.\n", file, linenum, args[0]);
4048
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004049 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4050 SMP_OPT_DIR_REQ, ACT_PASS, 0,
4051 args[0], args[1], NULL, (const char **)args+2);
4052 if (err_code & ERR_FATAL)
4053 goto out;
4054 }
4055 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004056 if (!already_warned(WARN_REQALLOW_DEPRECATED))
4057 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]);
4058
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004059 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4060 SMP_OPT_DIR_REQ, ACT_ALLOW, 0,
4061 args[0], args[1], NULL, (const char **)args+2);
4062 if (err_code & ERR_FATAL)
4063 goto out;
4064 }
4065 else if (!strcmp(args[0], "reqtarpit")) { /* tarpit a request if a header matches this regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004066 if (!already_warned(WARN_REQTARPIT_DEPRECATED))
4067 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]);
4068
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004069 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4070 SMP_OPT_DIR_REQ, ACT_TARPIT, 0,
4071 args[0], args[1], NULL, (const char **)args+2);
4072 if (err_code & ERR_FATAL)
4073 goto out;
4074 }
4075 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004076 if (!already_warned(WARN_REQREP_DEPRECATED))
4077 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]);
4078
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004079 if (*(args[2]) == 0) {
4080 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4081 file, linenum, args[0]);
4082 err_code |= ERR_ALERT | ERR_FATAL;
4083 goto out;
4084 }
4085
4086 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4087 SMP_OPT_DIR_REQ, ACT_REPLACE, REG_ICASE,
4088 args[0], args[1], args[2], (const char **)args+3);
4089 if (err_code & ERR_FATAL)
4090 goto out;
4091 }
4092 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004093 if (!already_warned(WARN_REQDEL_DEPRECATED))
4094 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]);
4095
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004096 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4097 SMP_OPT_DIR_REQ, ACT_REMOVE, REG_ICASE,
4098 args[0], args[1], NULL, (const char **)args+2);
4099 if (err_code & ERR_FATAL)
4100 goto out;
4101 }
4102 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004103 if (!already_warned(WARN_REQDENY_DEPRECATED))
4104 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]);
4105
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004106 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4107 SMP_OPT_DIR_REQ, ACT_DENY, REG_ICASE,
4108 args[0], args[1], NULL, (const char **)args+2);
4109 if (err_code & ERR_FATAL)
4110 goto out;
4111 }
4112 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
Willy Tarreau96d51952019-05-22 20:34:35 +02004113 if (!already_warned(WARN_REQPASS_DEPRECATED))
4114 ha_warning("parsing [%s:%d] : The '%s' directive is deprecated and will be removed in next version.\n", file, linenum, args[0]);
4115
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004116 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4117 SMP_OPT_DIR_REQ, ACT_PASS, REG_ICASE,
4118 args[0], args[1], NULL, (const char **)args+2);
4119 if (err_code & ERR_FATAL)
4120 goto out;
4121 }
4122 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004123 if (!already_warned(WARN_REQALLOW_DEPRECATED))
4124 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]);
4125
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004126 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4127 SMP_OPT_DIR_REQ, ACT_ALLOW, REG_ICASE,
4128 args[0], args[1], NULL, (const char **)args+2);
4129 if (err_code & ERR_FATAL)
4130 goto out;
4131 }
4132 else if (!strcmp(args[0], "reqitarpit")) { /* tarpit a request if a header matches this regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004133 if (!already_warned(WARN_REQTARPIT_DEPRECATED))
4134 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]);
4135
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004136 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4137 SMP_OPT_DIR_REQ, ACT_TARPIT, REG_ICASE,
4138 args[0], args[1], NULL, (const char **)args+2);
4139 if (err_code & ERR_FATAL)
4140 goto out;
4141 }
4142 else if (!strcmp(args[0], "reqadd")) { /* add request header */
4143 struct cond_wordlist *wl;
4144
Willy Tarreau96d51952019-05-22 20:34:35 +02004145 if (!already_warned(WARN_REQADD_DEPRECATED))
4146 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]);
4147
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004148 if (curproxy == &defproxy) {
4149 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4150 err_code |= ERR_ALERT | ERR_FATAL;
4151 goto out;
4152 }
4153 else if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4154 err_code |= ERR_WARN;
4155
4156 if (*(args[1]) == 0) {
4157 ha_alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
4158 err_code |= ERR_ALERT | ERR_FATAL;
4159 goto out;
4160 }
4161
4162 if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
4163 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args+2, &errmsg)) == NULL) {
4164 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
4165 file, linenum, args[0], errmsg);
4166 err_code |= ERR_ALERT | ERR_FATAL;
4167 goto out;
4168 }
4169 err_code |= warnif_cond_conflicts(cond,
4170 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
4171 file, linenum);
4172 }
4173 else if (*args[2]) {
4174 ha_alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
4175 file, linenum, args[0], args[2]);
4176 err_code |= ERR_ALERT | ERR_FATAL;
4177 goto out;
4178 }
4179
Willy Tarreau41898a22019-10-25 14:16:14 +02004180 if (strchr(args[1], '\n')) {
4181 ha_warning("parsing [%s:%d] : '%s' : hack involving '\\n' character in new header value will fail with HTTP/2.\n",
4182 file, linenum, args[0]);
4183 err_code |= ERR_WARN;
4184 }
4185
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004186 wl = calloc(1, sizeof(*wl));
4187 wl->cond = cond;
4188 wl->s = strdup(args[1]);
4189 LIST_ADDQ(&curproxy->req_add, &wl->list);
4190 warnif_misplaced_reqadd(curproxy, file, linenum, args[0]);
4191 }
4192 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004193 if (!already_warned(WARN_RSPREP_DEPRECATED))
4194 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]);
4195
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004196 if (*(args[2]) == 0) {
4197 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4198 file, linenum, args[0]);
4199 err_code |= ERR_ALERT | ERR_FATAL;
4200 goto out;
4201 }
4202
4203 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4204 SMP_OPT_DIR_RES, ACT_REPLACE, 0,
4205 args[0], args[1], args[2], (const char **)args+3);
4206 if (err_code & ERR_FATAL)
4207 goto out;
4208 }
4209 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004210 if (!already_warned(WARN_RSPDEL_DEPRECATED))
4211 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]);
4212
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004213 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4214 SMP_OPT_DIR_RES, ACT_REMOVE, 0,
4215 args[0], args[1], NULL, (const char **)args+2);
4216 if (err_code & ERR_FATAL)
4217 goto out;
4218 }
4219 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004220 if (!already_warned(WARN_RSPDENY_DEPRECATED))
4221 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]);
4222
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004223 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4224 SMP_OPT_DIR_RES, ACT_DENY, 0,
4225 args[0], args[1], NULL, (const char **)args+2);
4226 if (err_code & ERR_FATAL)
4227 goto out;
4228 }
4229 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004230 if (!already_warned(WARN_RSPREP_DEPRECATED))
4231 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]);
4232
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004233 if (*(args[2]) == 0) {
4234 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4235 file, linenum, args[0]);
4236 err_code |= ERR_ALERT | ERR_FATAL;
4237 goto out;
4238 }
4239
4240 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4241 SMP_OPT_DIR_RES, ACT_REPLACE, REG_ICASE,
4242 args[0], args[1], args[2], (const char **)args+3);
4243 if (err_code & ERR_FATAL)
4244 goto out;
4245 }
4246 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004247 if (!already_warned(WARN_RSPDEL_DEPRECATED))
4248 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]);
4249
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004250 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4251 SMP_OPT_DIR_RES, ACT_REMOVE, REG_ICASE,
4252 args[0], args[1], NULL, (const char **)args+2);
4253 if (err_code & ERR_FATAL)
4254 goto out;
4255 }
4256 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004257 if (!already_warned(WARN_RSPDENY_DEPRECATED))
4258 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]);
4259
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004260 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4261 SMP_OPT_DIR_RES, ACT_DENY, REG_ICASE,
4262 args[0], args[1], NULL, (const char **)args+2);
4263 if (err_code & ERR_FATAL)
4264 goto out;
4265 }
4266 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4267 struct cond_wordlist *wl;
4268
Willy Tarreau96d51952019-05-22 20:34:35 +02004269 if (!already_warned(WARN_RSPADD_DEPRECATED))
4270 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]);
4271
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004272 if (curproxy == &defproxy) {
4273 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4274 err_code |= ERR_ALERT | ERR_FATAL;
4275 goto out;
4276 }
4277 else if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4278 err_code |= ERR_WARN;
4279
4280 if (*(args[1]) == 0) {
4281 ha_alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
4282 err_code |= ERR_ALERT | ERR_FATAL;
4283 goto out;
4284 }
4285
4286 if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
4287 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args+2, &errmsg)) == NULL) {
4288 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
4289 file, linenum, args[0], errmsg);
4290 err_code |= ERR_ALERT | ERR_FATAL;
4291 goto out;
4292 }
4293 err_code |= warnif_cond_conflicts(cond,
4294 (curproxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
4295 file, linenum);
4296 }
4297 else if (*args[2]) {
4298 ha_alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
4299 file, linenum, args[0], args[2]);
4300 err_code |= ERR_ALERT | ERR_FATAL;
4301 goto out;
4302 }
4303
Willy Tarreau41898a22019-10-25 14:16:14 +02004304 if (strchr(args[1], '\n')) {
4305 ha_warning("parsing [%s:%d] : '%s' : hack involving '\\n' character in new header value will fail with HTTP/2.\n",
4306 file, linenum, args[0]);
4307 err_code |= ERR_WARN;
4308 }
4309
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004310 wl = calloc(1, sizeof(*wl));
4311 wl->cond = cond;
4312 wl->s = strdup(args[1]);
4313 LIST_ADDQ(&curproxy->rsp_add, &wl->list);
4314 }
4315 else if (!strcmp(args[0], "errorloc") ||
4316 !strcmp(args[0], "errorloc302") ||
4317 !strcmp(args[0], "errorloc303")) { /* error location */
4318 int errnum, errlen;
4319 char *err;
4320
4321 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4322 err_code |= ERR_WARN;
4323
4324 if (*(args[2]) == 0) {
4325 ha_alert("parsing [%s:%d] : <%s> expects <status_code> and <url> as arguments.\n", file, linenum, args[0]);
4326 err_code |= ERR_ALERT | ERR_FATAL;
4327 goto out;
4328 }
4329
4330 errnum = atol(args[1]);
4331 if (!strcmp(args[0], "errorloc303")) {
4332 errlen = strlen(HTTP_303) + strlen(args[2]) + 5;
4333 err = malloc(errlen);
4334 errlen = snprintf(err, errlen, "%s%s\r\n\r\n", HTTP_303, args[2]);
4335 } else {
4336 errlen = strlen(HTTP_302) + strlen(args[2]) + 5;
4337 err = malloc(errlen);
4338 errlen = snprintf(err, errlen, "%s%s\r\n\r\n", HTTP_302, args[2]);
4339 }
4340
4341 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
4342 if (http_err_codes[rc] == errnum) {
4343 chunk_destroy(&curproxy->errmsg[rc]);
4344 chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen);
4345 break;
4346 }
4347 }
4348
4349 if (rc >= HTTP_ERR_SIZE) {
4350 ha_warning("parsing [%s:%d] : status code %d not handled by '%s', error relocation will be ignored.\n",
4351 file, linenum, errnum, args[0]);
4352 free(err);
4353 }
4354 }
4355 else if (!strcmp(args[0], "errorfile")) { /* error message from a file */
4356 int errnum, errlen, fd;
4357 char *err;
4358 struct stat stat;
4359
4360 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4361 err_code |= ERR_WARN;
4362
4363 if (*(args[2]) == 0) {
4364 ha_alert("parsing [%s:%d] : <%s> expects <status_code> and <file> as arguments.\n", file, linenum, args[0]);
4365 err_code |= ERR_ALERT | ERR_FATAL;
4366 goto out;
4367 }
4368
4369 fd = open(args[2], O_RDONLY);
4370 if ((fd < 0) || (fstat(fd, &stat) < 0)) {
4371 ha_alert("parsing [%s:%d] : error opening file <%s> for custom error message <%s>.\n",
4372 file, linenum, args[2], args[1]);
4373 if (fd >= 0)
4374 close(fd);
4375 err_code |= ERR_ALERT | ERR_FATAL;
4376 goto out;
4377 }
4378
4379 if (stat.st_size <= global.tune.bufsize) {
4380 errlen = stat.st_size;
4381 } else {
4382 ha_warning("parsing [%s:%d] : custom error message file <%s> larger than %d bytes. Truncating.\n",
4383 file, linenum, args[2], global.tune.bufsize);
4384 err_code |= ERR_WARN;
4385 errlen = global.tune.bufsize;
4386 }
4387
4388 err = malloc(errlen); /* malloc() must succeed during parsing */
4389 errnum = read(fd, err, errlen);
4390 if (errnum != errlen) {
4391 ha_alert("parsing [%s:%d] : error reading file <%s> for custom error message <%s>.\n",
4392 file, linenum, args[2], args[1]);
4393 close(fd);
4394 free(err);
4395 err_code |= ERR_ALERT | ERR_FATAL;
4396 goto out;
4397 }
4398 close(fd);
4399
4400 errnum = atol(args[1]);
4401 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
4402 if (http_err_codes[rc] == errnum) {
4403 chunk_destroy(&curproxy->errmsg[rc]);
4404 chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen);
4405 break;
4406 }
4407 }
4408
4409 if (rc >= HTTP_ERR_SIZE) {
4410 ha_warning("parsing [%s:%d] : status code %d not handled by '%s', error customization will be ignored.\n",
4411 file, linenum, errnum, args[0]);
4412 err_code |= ERR_WARN;
4413 free(err);
4414 }
4415 }
4416 else {
4417 struct cfg_kw_list *kwl;
4418 int index;
4419
4420 list_for_each_entry(kwl, &cfg_keywords.list, list) {
4421 for (index = 0; kwl->kw[index].kw != NULL; index++) {
4422 if (kwl->kw[index].section != CFG_LISTEN)
4423 continue;
4424 if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
4425 /* prepare error message just in case */
4426 rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, file, linenum, &errmsg);
4427 if (rc < 0) {
4428 ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4429 err_code |= ERR_ALERT | ERR_FATAL;
4430 goto out;
4431 }
4432 else if (rc > 0) {
4433 ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4434 err_code |= ERR_WARN;
4435 goto out;
4436 }
4437 goto out;
4438 }
4439 }
4440 }
4441
4442 ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
4443 err_code |= ERR_ALERT | ERR_FATAL;
4444 goto out;
4445 }
4446 out:
4447 free(errmsg);
4448 return err_code;
4449}