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