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