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