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