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