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