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