blob: 5fd8ecf5a7b759366f113b1ce88dfb5750395195 [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 }
Tim Duesterhus7b7c47f2019-05-14 20:57:57 +02001549 else if (!strcmp(args[0], "block")) {
1550 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. Use 'http-request deny' which uses the exact same syntax.\n", file, linenum, args[0]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001551
Tim Duesterhus7b7c47f2019-05-14 20:57:57 +02001552 err_code |= ERR_ALERT | ERR_FATAL;
1553 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001554 }
1555 else if (!strcmp(args[0], "redirect")) {
1556 struct redirect_rule *rule;
1557
1558 if (curproxy == &defproxy) {
1559 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1560 err_code |= ERR_ALERT | ERR_FATAL;
1561 goto out;
1562 }
1563
1564 if ((rule = http_parse_redirect_rule(file, linenum, curproxy, (const char **)args + 1, &errmsg, 0, 0)) == NULL) {
1565 ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing redirect rule : %s.\n",
1566 file, linenum, proxy_type_str(curproxy), curproxy->id, errmsg);
1567 err_code |= ERR_ALERT | ERR_FATAL;
1568 goto out;
1569 }
1570
1571 LIST_ADDQ(&curproxy->redirect_rules, &rule->list);
1572 err_code |= warnif_misplaced_redirect(curproxy, file, linenum, args[0]);
1573 err_code |= warnif_cond_conflicts(rule->cond,
1574 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1575 file, linenum);
1576 }
1577 else if (!strcmp(args[0], "use_backend")) {
1578 struct switching_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 (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1587 err_code |= ERR_WARN;
1588
1589 if (*(args[1]) == 0) {
1590 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
1591 err_code |= ERR_ALERT | ERR_FATAL;
1592 goto out;
1593 }
1594
1595 if (strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0) {
1596 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1597 ha_alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
1598 file, linenum, errmsg);
1599 err_code |= ERR_ALERT | ERR_FATAL;
1600 goto out;
1601 }
1602
1603 err_code |= warnif_cond_conflicts(cond, SMP_VAL_FE_SET_BCK, file, linenum);
1604 }
1605 else if (*args[2]) {
1606 ha_alert("parsing [%s:%d] : unexpected keyword '%s' after switching rule, only 'if' and 'unless' are allowed.\n",
1607 file, linenum, args[2]);
1608 err_code |= ERR_ALERT | ERR_FATAL;
1609 goto out;
1610 }
1611
1612 rule = calloc(1, sizeof(*rule));
1613 if (!rule) {
1614 ha_alert("Out of memory error.\n");
1615 goto out;
1616 }
1617 rule->cond = cond;
1618 rule->be.name = strdup(args[1]);
1619 rule->line = linenum;
1620 rule->file = strdup(file);
1621 if (!rule->file) {
1622 ha_alert("Out of memory error.\n");
1623 goto out;
1624 }
1625 LIST_INIT(&rule->list);
1626 LIST_ADDQ(&curproxy->switching_rules, &rule->list);
1627 }
1628 else if (strcmp(args[0], "use-server") == 0) {
1629 struct server_rule *rule;
1630
1631 if (curproxy == &defproxy) {
1632 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1633 err_code |= ERR_ALERT | ERR_FATAL;
1634 goto out;
1635 }
1636
1637 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1638 err_code |= ERR_WARN;
1639
1640 if (*(args[1]) == 0) {
1641 ha_alert("parsing [%s:%d] : '%s' expects a server name.\n", file, linenum, args[0]);
1642 err_code |= ERR_ALERT | ERR_FATAL;
1643 goto out;
1644 }
1645
1646 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
1647 ha_alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1648 file, linenum, args[0]);
1649 err_code |= ERR_ALERT | ERR_FATAL;
1650 goto out;
1651 }
1652
1653 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1654 ha_alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
1655 file, linenum, errmsg);
1656 err_code |= ERR_ALERT | ERR_FATAL;
1657 goto out;
1658 }
1659
1660 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, file, linenum);
1661
1662 rule = calloc(1, sizeof(*rule));
1663 rule->cond = cond;
1664 rule->srv.name = strdup(args[1]);
1665 LIST_INIT(&rule->list);
1666 LIST_ADDQ(&curproxy->server_rules, &rule->list);
1667 curproxy->be_req_ana |= AN_REQ_SRV_RULES;
1668 }
1669 else if ((!strcmp(args[0], "force-persist")) ||
1670 (!strcmp(args[0], "ignore-persist"))) {
1671 struct persist_rule *rule;
1672
1673 if (curproxy == &defproxy) {
1674 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1675 err_code |= ERR_ALERT | ERR_FATAL;
1676 goto out;
1677 }
1678
1679 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1680 err_code |= ERR_WARN;
1681
1682 if (strcmp(args[1], "if") != 0 && strcmp(args[1], "unless") != 0) {
1683 ha_alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1684 file, linenum, args[0]);
1685 err_code |= ERR_ALERT | ERR_FATAL;
1686 goto out;
1687 }
1688
1689 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 1, &errmsg)) == NULL) {
1690 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' rule : %s.\n",
1691 file, linenum, args[0], errmsg);
1692 err_code |= ERR_ALERT | ERR_FATAL;
1693 goto out;
1694 }
1695
1696 /* note: BE_REQ_CNT is the first one after FE_SET_BCK, which is
1697 * where force-persist is applied.
1698 */
1699 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_REQ_CNT, file, linenum);
1700
1701 rule = calloc(1, sizeof(*rule));
1702 rule->cond = cond;
1703 if (!strcmp(args[0], "force-persist")) {
1704 rule->type = PERSIST_TYPE_FORCE;
1705 } else {
1706 rule->type = PERSIST_TYPE_IGNORE;
1707 }
1708 LIST_INIT(&rule->list);
1709 LIST_ADDQ(&curproxy->persist_rules, &rule->list);
1710 }
1711 else if (!strcmp(args[0], "stick-table")) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001712 struct stktable *other;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001713
1714 if (curproxy == &defproxy) {
1715 ha_alert("parsing [%s:%d] : 'stick-table' is not supported in 'defaults' section.\n",
1716 file, linenum);
1717 err_code |= ERR_ALERT | ERR_FATAL;
1718 goto out;
1719 }
1720
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001721 other = stktable_find_by_name(curproxy->id);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001722 if (other) {
1723 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 +01001724 file, linenum, curproxy->id,
1725 other->proxy ? proxy_cap_str(other->proxy->cap) : "peers",
1726 other->proxy ? other->id : other->peers.p->id,
1727 other->conf.file, other->conf.line);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001728 err_code |= ERR_ALERT | ERR_FATAL;
1729 goto out;
1730 }
1731
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001732 curproxy->table = calloc(1, sizeof *curproxy->table);
1733 if (!curproxy->table) {
1734 ha_alert("parsing [%s:%d]: '%s %s' : memory allocation failed\n",
1735 file, linenum, args[0], args[1]);
1736 err_code |= ERR_ALERT | ERR_FATAL;
1737 goto out;
1738 }
1739
Frédéric Lécaillec02766a2019-03-20 15:06:55 +01001740 err_code |= parse_stick_table(file, linenum, args, curproxy->table,
1741 curproxy->id, curproxy->id, NULL);
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001742 if (err_code & ERR_FATAL)
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001743 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001744
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001745 /* Store the proxy in the stick-table. */
1746 curproxy->table->proxy = curproxy;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001747
1748 stktable_store_name(curproxy->table);
1749 curproxy->table->next = stktables_list;
1750 stktables_list = curproxy->table;
Frédéric Lécaille015e4d72019-03-19 14:55:01 +01001751
1752 /* Add this proxy to the list of proxies which refer to its stick-table. */
1753 if (curproxy->table->proxies_list != curproxy) {
1754 curproxy->next_stkt_ref = curproxy->table->proxies_list;
1755 curproxy->table->proxies_list = curproxy;
1756 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001757 }
1758 else if (!strcmp(args[0], "stick")) {
1759 struct sticking_rule *rule;
1760 struct sample_expr *expr;
1761 int myidx = 0;
1762 const char *name = NULL;
1763 int flags;
1764
1765 if (curproxy == &defproxy) {
1766 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1767 err_code |= ERR_ALERT | ERR_FATAL;
1768 goto out;
1769 }
1770
1771 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) {
1772 err_code |= ERR_WARN;
1773 goto out;
1774 }
1775
1776 myidx++;
1777 if ((strcmp(args[myidx], "store") == 0) ||
1778 (strcmp(args[myidx], "store-request") == 0)) {
1779 myidx++;
1780 flags = STK_IS_STORE;
1781 }
1782 else if (strcmp(args[myidx], "store-response") == 0) {
1783 myidx++;
1784 flags = STK_IS_STORE | STK_ON_RSP;
1785 }
1786 else if (strcmp(args[myidx], "match") == 0) {
1787 myidx++;
1788 flags = STK_IS_MATCH;
1789 }
1790 else if (strcmp(args[myidx], "on") == 0) {
1791 myidx++;
1792 flags = STK_IS_MATCH | STK_IS_STORE;
1793 }
1794 else {
1795 ha_alert("parsing [%s:%d] : '%s' expects 'on', 'match', or 'store'.\n", file, linenum, args[0]);
1796 err_code |= ERR_ALERT | ERR_FATAL;
1797 goto out;
1798 }
1799
1800 if (*(args[myidx]) == 0) {
1801 ha_alert("parsing [%s:%d] : '%s' expects a fetch method.\n", file, linenum, args[0]);
1802 err_code |= ERR_ALERT | ERR_FATAL;
1803 goto out;
1804 }
1805
1806 curproxy->conf.args.ctx = ARGC_STK;
1807 expr = sample_parse_expr(args, &myidx, file, linenum, &errmsg, &curproxy->conf.args);
1808 if (!expr) {
1809 ha_alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], errmsg);
1810 err_code |= ERR_ALERT | ERR_FATAL;
1811 goto out;
1812 }
1813
1814 if (flags & STK_ON_RSP) {
1815 if (!(expr->fetch->val & SMP_VAL_BE_STO_RUL)) {
1816 ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available for 'store-response'.\n",
1817 file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
1818 err_code |= ERR_ALERT | ERR_FATAL;
1819 free(expr);
1820 goto out;
1821 }
1822 } else {
1823 if (!(expr->fetch->val & SMP_VAL_BE_SET_SRV)) {
1824 ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available during request.\n",
1825 file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
1826 err_code |= ERR_ALERT | ERR_FATAL;
1827 free(expr);
1828 goto out;
1829 }
1830 }
1831
1832 /* check if we need to allocate an hdr_idx struct for HTTP parsing */
1833 curproxy->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
1834
1835 if (strcmp(args[myidx], "table") == 0) {
1836 myidx++;
1837 name = args[myidx++];
1838 }
1839
1840 if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) {
1841 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + myidx, &errmsg)) == NULL) {
1842 ha_alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition : %s.\n",
1843 file, linenum, args[0], errmsg);
1844 err_code |= ERR_ALERT | ERR_FATAL;
1845 free(expr);
1846 goto out;
1847 }
1848 }
1849 else if (*(args[myidx])) {
1850 ha_alert("parsing [%s:%d] : '%s': unknown keyword '%s'.\n",
1851 file, linenum, args[0], args[myidx]);
1852 err_code |= ERR_ALERT | ERR_FATAL;
1853 free(expr);
1854 goto out;
1855 }
1856 if (flags & STK_ON_RSP)
1857 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_STO_RUL, file, linenum);
1858 else
1859 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, file, linenum);
1860
1861 rule = calloc(1, sizeof(*rule));
1862 rule->cond = cond;
1863 rule->expr = expr;
1864 rule->flags = flags;
1865 rule->table.name = name ? strdup(name) : NULL;
1866 LIST_INIT(&rule->list);
1867 if (flags & STK_ON_RSP)
1868 LIST_ADDQ(&curproxy->storersp_rules, &rule->list);
1869 else
1870 LIST_ADDQ(&curproxy->sticking_rules, &rule->list);
1871 }
1872 else if (!strcmp(args[0], "stats")) {
1873 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
1874 curproxy->uri_auth = NULL; /* we must detach from the default config */
1875
1876 if (!*args[1]) {
1877 goto stats_error_parsing;
1878 } else if (!strcmp(args[1], "admin")) {
1879 struct stats_admin_rule *rule;
1880
1881 if (curproxy == &defproxy) {
1882 ha_alert("parsing [%s:%d]: '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1883 err_code |= ERR_ALERT | ERR_FATAL;
1884 goto out;
1885 }
1886
1887 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1888 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1889 err_code |= ERR_ALERT | ERR_ABORT;
1890 goto out;
1891 }
1892
1893 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
1894 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
1895 file, linenum, args[0], args[1]);
1896 err_code |= ERR_ALERT | ERR_FATAL;
1897 goto out;
1898 }
1899 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1900 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' rule : %s.\n",
1901 file, linenum, args[0], args[1], errmsg);
1902 err_code |= ERR_ALERT | ERR_FATAL;
1903 goto out;
1904 }
1905
1906 err_code |= warnif_cond_conflicts(cond,
1907 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1908 file, linenum);
1909
1910 rule = calloc(1, sizeof(*rule));
1911 rule->cond = cond;
1912 LIST_INIT(&rule->list);
1913 LIST_ADDQ(&curproxy->uri_auth->admin_rules, &rule->list);
1914 } else if (!strcmp(args[1], "uri")) {
1915 if (*(args[2]) == 0) {
1916 ha_alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
1917 err_code |= ERR_ALERT | ERR_FATAL;
1918 goto out;
1919 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
1920 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1921 err_code |= ERR_ALERT | ERR_ABORT;
1922 goto out;
1923 }
1924 } else if (!strcmp(args[1], "realm")) {
1925 if (*(args[2]) == 0) {
1926 ha_alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
1927 err_code |= ERR_ALERT | ERR_FATAL;
1928 goto out;
1929 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
1930 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1931 err_code |= ERR_ALERT | ERR_ABORT;
1932 goto out;
1933 }
1934 } else if (!strcmp(args[1], "refresh")) {
1935 unsigned interval;
1936
1937 err = parse_time_err(args[2], &interval, TIME_UNIT_S);
Willy Tarreau9faebe32019-06-07 19:00:37 +02001938 if (err == PARSE_TIME_OVER) {
1939 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to stats refresh interval, maximum value is 2147483647 s (~68 years).\n",
1940 file, linenum, args[2]);
1941 err_code |= ERR_ALERT | ERR_FATAL;
1942 goto out;
1943 }
1944 else if (err == PARSE_TIME_UNDER) {
1945 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to stats refresh interval, minimum non-null value is 1 s.\n",
1946 file, linenum, args[2]);
1947 err_code |= ERR_ALERT | ERR_FATAL;
1948 goto out;
1949 }
1950 else if (err) {
1951 ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to stats refresh interval.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001952 file, linenum, *err);
1953 err_code |= ERR_ALERT | ERR_FATAL;
1954 goto out;
1955 } else if (!stats_set_refresh(&curproxy->uri_auth, interval)) {
1956 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1957 err_code |= ERR_ALERT | ERR_ABORT;
1958 goto out;
1959 }
1960 } else if (!strcmp(args[1], "http-request")) { /* request access control: allow/deny/auth */
1961 struct act_rule *rule;
1962
1963 if (curproxy == &defproxy) {
1964 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1965 err_code |= ERR_ALERT | ERR_FATAL;
1966 goto out;
1967 }
1968
1969 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1970 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1971 err_code |= ERR_ALERT | ERR_ABORT;
1972 goto out;
1973 }
1974
1975 if (!LIST_ISEMPTY(&curproxy->uri_auth->http_req_rules) &&
1976 !LIST_PREV(&curproxy->uri_auth->http_req_rules, struct act_rule *, list)->cond) {
1977 ha_warning("parsing [%s:%d]: previous '%s' action has no condition attached, further entries are NOOP.\n",
1978 file, linenum, args[0]);
1979 err_code |= ERR_WARN;
1980 }
1981
1982 rule = parse_http_req_cond((const char **)args + 2, file, linenum, curproxy);
1983
1984 if (!rule) {
1985 err_code |= ERR_ALERT | ERR_ABORT;
1986 goto out;
1987 }
1988
1989 err_code |= warnif_cond_conflicts(rule->cond,
1990 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1991 file, linenum);
1992 LIST_ADDQ(&curproxy->uri_auth->http_req_rules, &rule->list);
1993
1994 } else if (!strcmp(args[1], "auth")) {
1995 if (*(args[2]) == 0) {
1996 ha_alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
1997 err_code |= ERR_ALERT | ERR_FATAL;
1998 goto out;
1999 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
2000 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2001 err_code |= ERR_ALERT | ERR_ABORT;
2002 goto out;
2003 }
2004 } else if (!strcmp(args[1], "scope")) {
2005 if (*(args[2]) == 0) {
2006 ha_alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
2007 err_code |= ERR_ALERT | ERR_FATAL;
2008 goto out;
2009 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
2010 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2011 err_code |= ERR_ALERT | ERR_ABORT;
2012 goto out;
2013 }
2014 } else if (!strcmp(args[1], "enable")) {
2015 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
2016 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2017 err_code |= ERR_ALERT | ERR_ABORT;
2018 goto out;
2019 }
2020 } else if (!strcmp(args[1], "hide-version")) {
2021 if (!stats_set_flag(&curproxy->uri_auth, ST_HIDEVER)) {
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], "show-legends")) {
2027 if (!stats_set_flag(&curproxy->uri_auth, ST_SHLGNDS)) {
2028 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2029 err_code |= ERR_ALERT | ERR_ABORT;
2030 goto out;
2031 }
2032 } else if (!strcmp(args[1], "show-node")) {
2033
2034 if (*args[2]) {
2035 int i;
2036 char c;
2037
2038 for (i=0; args[2][i]; i++) {
2039 c = args[2][i];
2040 if (!isupper((unsigned char)c) && !islower((unsigned char)c) &&
2041 !isdigit((unsigned char)c) && c != '_' && c != '-' && c != '.')
2042 break;
2043 }
2044
2045 if (!i || args[2][i]) {
2046 ha_alert("parsing [%s:%d]: '%s %s' invalid node name - should be a string"
2047 "with digits(0-9), letters(A-Z, a-z), hyphen(-) or underscode(_).\n",
2048 file, linenum, args[0], args[1]);
2049 err_code |= ERR_ALERT | ERR_FATAL;
2050 goto out;
2051 }
2052 }
2053
2054 if (!stats_set_node(&curproxy->uri_auth, args[2])) {
2055 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2056 err_code |= ERR_ALERT | ERR_ABORT;
2057 goto out;
2058 }
2059 } else if (!strcmp(args[1], "show-desc")) {
2060 char *desc = NULL;
2061
2062 if (*args[2]) {
2063 int i, len=0;
2064 char *d;
2065
2066 for (i = 2; *args[i]; i++)
2067 len += strlen(args[i]) + 1;
2068
2069 desc = d = calloc(1, len);
2070
2071 d += snprintf(d, desc + len - d, "%s", args[2]);
2072 for (i = 3; *args[i]; i++)
2073 d += snprintf(d, desc + len - d, " %s", args[i]);
2074 }
2075
2076 if (!*args[2] && !global.desc)
2077 ha_warning("parsing [%s:%d]: '%s' requires a parameter or 'desc' to be set in the global section.\n",
2078 file, linenum, args[1]);
2079 else {
2080 if (!stats_set_desc(&curproxy->uri_auth, desc)) {
2081 free(desc);
2082 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2083 err_code |= ERR_ALERT | ERR_ABORT;
2084 goto out;
2085 }
2086 free(desc);
2087 }
2088 } else {
2089stats_error_parsing:
2090 ha_alert("parsing [%s:%d]: %s '%s', expects 'admin', 'uri', 'realm', 'auth', 'scope', 'enable', 'hide-version', 'show-node', 'show-desc' or 'show-legends'.\n",
2091 file, linenum, *args[1]?"unknown stats parameter":"missing keyword in", args[*args[1]?1:0]);
2092 err_code |= ERR_ALERT | ERR_FATAL;
2093 goto out;
2094 }
2095 }
2096 else if (!strcmp(args[0], "option")) {
2097 int optnum;
2098
2099 if (*(args[1]) == '\0') {
2100 ha_alert("parsing [%s:%d]: '%s' expects an option name.\n",
2101 file, linenum, args[0]);
2102 err_code |= ERR_ALERT | ERR_FATAL;
2103 goto out;
2104 }
2105
2106 for (optnum = 0; cfg_opts[optnum].name; optnum++) {
2107 if (!strcmp(args[1], cfg_opts[optnum].name)) {
2108 if (cfg_opts[optnum].cap == PR_CAP_NONE) {
2109 ha_alert("parsing [%s:%d]: option '%s' is not supported due to build options.\n",
2110 file, linenum, cfg_opts[optnum].name);
2111 err_code |= ERR_ALERT | ERR_FATAL;
2112 goto out;
2113 }
2114 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2115 goto out;
2116
2117 if (warnifnotcap(curproxy, cfg_opts[optnum].cap, file, linenum, args[1], NULL)) {
2118 err_code |= ERR_WARN;
2119 goto out;
2120 }
2121
2122 curproxy->no_options &= ~cfg_opts[optnum].val;
2123 curproxy->options &= ~cfg_opts[optnum].val;
2124
2125 switch (kwm) {
2126 case KWM_STD:
2127 curproxy->options |= cfg_opts[optnum].val;
2128 break;
2129 case KWM_NO:
2130 curproxy->no_options |= cfg_opts[optnum].val;
2131 break;
2132 case KWM_DEF: /* already cleared */
2133 break;
2134 }
2135
2136 goto out;
2137 }
2138 }
2139
2140 for (optnum = 0; cfg_opts2[optnum].name; optnum++) {
2141 if (!strcmp(args[1], cfg_opts2[optnum].name)) {
2142 if (cfg_opts2[optnum].cap == PR_CAP_NONE) {
2143 ha_alert("parsing [%s:%d]: option '%s' is not supported due to build options.\n",
2144 file, linenum, cfg_opts2[optnum].name);
2145 err_code |= ERR_ALERT | ERR_FATAL;
2146 goto out;
2147 }
2148 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2149 goto out;
2150 if (warnifnotcap(curproxy, cfg_opts2[optnum].cap, file, linenum, args[1], NULL)) {
2151 err_code |= ERR_WARN;
2152 goto out;
2153 }
2154
2155 curproxy->no_options2 &= ~cfg_opts2[optnum].val;
2156 curproxy->options2 &= ~cfg_opts2[optnum].val;
2157
2158 switch (kwm) {
2159 case KWM_STD:
2160 curproxy->options2 |= cfg_opts2[optnum].val;
2161 break;
2162 case KWM_NO:
2163 curproxy->no_options2 |= cfg_opts2[optnum].val;
2164 break;
2165 case KWM_DEF: /* already cleared */
2166 break;
2167 }
2168 goto out;
2169 }
2170 }
2171
2172 /* HTTP options override each other. They can be cancelled using
2173 * "no option xxx" which only switches to default mode if the mode
2174 * was this one (useful for cancelling options set in defaults
2175 * sections).
2176 */
2177 if (strcmp(args[1], "httpclose") == 0 || strcmp(args[1], "forceclose") == 0) {
Tim Duesterhus10c6c162019-05-14 20:58:00 +02002178 if (strcmp(args[1], "forceclose") == 0) {
2179 if (!already_warned(WARN_FORCECLOSE_DEPRECATED))
2180 ha_warning("parsing [%s:%d]: keyword '%s' is deprecated in favor of 'httpclose', and will not be supported by future versions.\n",
2181 file, linenum, args[1]);
2182 err_code |= ERR_WARN;
2183 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002184 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2185 goto out;
2186 if (kwm == KWM_STD) {
2187 curproxy->options &= ~PR_O_HTTP_MODE;
2188 curproxy->options |= PR_O_HTTP_CLO;
2189 goto out;
2190 }
2191 else if (kwm == KWM_NO) {
2192 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_CLO)
2193 curproxy->options &= ~PR_O_HTTP_MODE;
2194 goto out;
2195 }
2196 }
2197 else if (strcmp(args[1], "http-server-close") == 0) {
2198 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2199 goto out;
2200 if (kwm == KWM_STD) {
2201 curproxy->options &= ~PR_O_HTTP_MODE;
2202 curproxy->options |= PR_O_HTTP_SCL;
2203 goto out;
2204 }
2205 else if (kwm == KWM_NO) {
2206 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL)
2207 curproxy->options &= ~PR_O_HTTP_MODE;
2208 goto out;
2209 }
2210 }
2211 else if (strcmp(args[1], "http-keep-alive") == 0) {
2212 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2213 goto out;
2214 if (kwm == KWM_STD) {
2215 curproxy->options &= ~PR_O_HTTP_MODE;
2216 curproxy->options |= PR_O_HTTP_KAL;
2217 goto out;
2218 }
2219 else if (kwm == KWM_NO) {
2220 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_KAL)
2221 curproxy->options &= ~PR_O_HTTP_MODE;
2222 goto out;
2223 }
2224 }
2225 else if (strcmp(args[1], "http-tunnel") == 0) {
2226 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[1], NULL)) {
2227 err_code |= ERR_WARN;
2228 goto out;
2229 }
2230 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2231 goto out;
2232 if (kwm == KWM_STD) {
2233 curproxy->options &= ~PR_O_HTTP_MODE;
2234 curproxy->options |= PR_O_HTTP_TUN;
2235 goto out;
2236 }
2237 else if (kwm == KWM_NO) {
2238 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN)
2239 curproxy->options &= ~PR_O_HTTP_MODE;
2240 goto out;
2241 }
2242 }
2243
2244 /* Redispatch can take an integer argument that control when the
2245 * resispatch occurs. All values are relative to the retries option.
2246 * This can be cancelled using "no option xxx".
2247 */
2248 if (strcmp(args[1], "redispatch") == 0) {
2249 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL)) {
2250 err_code |= ERR_WARN;
2251 goto out;
2252 }
2253
2254 curproxy->no_options &= ~PR_O_REDISP;
2255 curproxy->options &= ~PR_O_REDISP;
2256
2257 switch (kwm) {
2258 case KWM_STD:
2259 curproxy->options |= PR_O_REDISP;
2260 curproxy->redispatch_after = -1;
2261 if(*args[2]) {
2262 curproxy->redispatch_after = atol(args[2]);
2263 }
2264 break;
2265 case KWM_NO:
2266 curproxy->no_options |= PR_O_REDISP;
2267 curproxy->redispatch_after = 0;
2268 break;
2269 case KWM_DEF: /* already cleared */
2270 break;
2271 }
2272 goto out;
2273 }
2274
2275 if (kwm != KWM_STD) {
2276 ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
2277 file, linenum, args[1]);
2278 err_code |= ERR_ALERT | ERR_FATAL;
2279 goto out;
2280 }
2281
2282 if (!strcmp(args[1], "httplog")) {
2283 char *logformat;
2284 /* generate a complete HTTP log */
2285 logformat = default_http_log_format;
2286 if (*(args[2]) != '\0') {
2287 if (!strcmp(args[2], "clf")) {
2288 curproxy->options2 |= PR_O2_CLFLOG;
2289 logformat = clf_http_log_format;
2290 } else {
2291 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'clf'.\n", file, linenum, args[1]);
2292 err_code |= ERR_ALERT | ERR_FATAL;
2293 goto out;
2294 }
2295 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
2296 goto out;
2297 }
2298 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2299 char *oldlogformat = "log-format";
2300 char *clflogformat = "";
2301
2302 if (curproxy->conf.logformat_string == default_http_log_format)
2303 oldlogformat = "option httplog";
2304 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2305 oldlogformat = "option tcplog";
2306 else if (curproxy->conf.logformat_string == clf_http_log_format)
2307 oldlogformat = "option httplog clf";
2308 if (logformat == clf_http_log_format)
2309 clflogformat = " clf";
2310 ha_warning("parsing [%s:%d]: 'option httplog%s' overrides previous '%s' in 'defaults' section.\n",
2311 file, linenum, clflogformat, oldlogformat);
2312 }
2313 if (curproxy->conf.logformat_string != default_http_log_format &&
2314 curproxy->conf.logformat_string != default_tcp_log_format &&
2315 curproxy->conf.logformat_string != clf_http_log_format)
2316 free(curproxy->conf.logformat_string);
2317 curproxy->conf.logformat_string = logformat;
2318
2319 free(curproxy->conf.lfs_file);
2320 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2321 curproxy->conf.lfs_line = curproxy->conf.args.line;
2322
2323 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2324 ha_warning("parsing [%s:%d] : backend '%s' : 'option httplog' directive is ignored in backends.\n",
2325 file, linenum, curproxy->id);
2326 err_code |= ERR_WARN;
2327 }
2328 }
2329 else if (!strcmp(args[1], "tcplog")) {
2330 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2331 char *oldlogformat = "log-format";
2332
2333 if (curproxy->conf.logformat_string == default_http_log_format)
2334 oldlogformat = "option httplog";
2335 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2336 oldlogformat = "option tcplog";
2337 else if (curproxy->conf.logformat_string == clf_http_log_format)
2338 oldlogformat = "option httplog clf";
2339 ha_warning("parsing [%s:%d]: 'option tcplog' overrides previous '%s' in 'defaults' section.\n",
2340 file, linenum, oldlogformat);
2341 }
2342 /* generate a detailed TCP log */
2343 if (curproxy->conf.logformat_string != default_http_log_format &&
2344 curproxy->conf.logformat_string != default_tcp_log_format &&
2345 curproxy->conf.logformat_string != clf_http_log_format)
2346 free(curproxy->conf.logformat_string);
2347 curproxy->conf.logformat_string = default_tcp_log_format;
2348
2349 free(curproxy->conf.lfs_file);
2350 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2351 curproxy->conf.lfs_line = curproxy->conf.args.line;
2352
2353 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2354 goto out;
2355
2356 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2357 ha_warning("parsing [%s:%d] : backend '%s' : 'option tcplog' directive is ignored in backends.\n",
2358 file, linenum, curproxy->id);
2359 err_code |= ERR_WARN;
2360 }
2361 }
2362 else if (!strcmp(args[1], "tcpka")) {
2363 /* enable TCP keep-alives on client and server streams */
2364 if (warnifnotcap(curproxy, PR_CAP_BE | PR_CAP_FE, file, linenum, args[1], NULL))
2365 err_code |= ERR_WARN;
2366
2367 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2368 goto out;
2369
2370 if (curproxy->cap & PR_CAP_FE)
2371 curproxy->options |= PR_O_TCP_CLI_KA;
2372 if (curproxy->cap & PR_CAP_BE)
2373 curproxy->options |= PR_O_TCP_SRV_KA;
2374 }
2375 else if (!strcmp(args[1], "httpchk")) {
2376 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2377 err_code |= ERR_WARN;
2378
2379 /* use HTTP request to check servers' health */
2380 free(curproxy->check_req);
2381 curproxy->check_req = NULL;
2382 curproxy->options2 &= ~PR_O2_CHK_ANY;
2383 curproxy->options2 |= PR_O2_HTTP_CHK;
2384 if (!*args[2]) { /* no argument */
2385 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
2386 curproxy->check_len = strlen(DEF_CHECK_REQ);
2387 } else if (!*args[3]) { /* one argument : URI */
2388 int reqlen = strlen(args[2]) + strlen("OPTIONS HTTP/1.0\r\n") + 1;
2389 curproxy->check_req = malloc(reqlen);
2390 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2391 "OPTIONS %s HTTP/1.0\r\n", args[2]); /* URI to use */
2392 } else { /* more arguments : METHOD URI [HTTP_VER] */
2393 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n");
2394 if (*args[4])
2395 reqlen += strlen(args[4]);
2396 else
2397 reqlen += strlen("HTTP/1.0");
2398
2399 curproxy->check_req = malloc(reqlen);
2400 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2401 "%s %s %s\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
2402 }
2403 if (alertif_too_many_args_idx(3, 1, file, linenum, args, &err_code))
2404 goto out;
2405 }
2406 else if (!strcmp(args[1], "ssl-hello-chk")) {
2407 /* use SSLv3 CLIENT HELLO to check servers' health */
2408 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2409 err_code |= ERR_WARN;
2410
2411 free(curproxy->check_req);
2412 curproxy->check_req = NULL;
2413 curproxy->options2 &= ~PR_O2_CHK_ANY;
2414 curproxy->options2 |= PR_O2_SSL3_CHK;
2415
2416 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2417 goto out;
2418 }
2419 else if (!strcmp(args[1], "smtpchk")) {
2420 /* use SMTP request to check servers' health */
2421 free(curproxy->check_req);
2422 curproxy->check_req = NULL;
2423 curproxy->options2 &= ~PR_O2_CHK_ANY;
2424 curproxy->options2 |= PR_O2_SMTP_CHK;
2425
2426 if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */
2427 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2428 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2429 } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */
2430 if (!strcmp(args[2], "EHLO") || !strcmp(args[2], "HELO")) {
2431 int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" \r\n") + 1;
2432 curproxy->check_req = malloc(reqlen);
2433 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2434 "%s %s\r\n", args[2], args[3]); /* HELO hostname */
2435 } else {
2436 /* this just hits the default for now, but you could potentially expand it to allow for other stuff
2437 though, it's unlikely you'd want to send anything other than an EHLO or HELO */
2438 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2439 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2440 }
2441 }
2442 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2443 goto out;
2444 }
2445 else if (!strcmp(args[1], "pgsql-check")) {
2446 /* use PostgreSQL request to check servers' health */
2447 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2448 err_code |= ERR_WARN;
2449
2450 free(curproxy->check_req);
2451 curproxy->check_req = NULL;
2452 curproxy->options2 &= ~PR_O2_CHK_ANY;
2453 curproxy->options2 |= PR_O2_PGSQL_CHK;
2454
2455 if (*(args[2])) {
2456 int cur_arg = 2;
2457
2458 while (*(args[cur_arg])) {
2459 if (strcmp(args[cur_arg], "user") == 0) {
2460 char * packet;
2461 uint32_t packet_len;
2462 uint32_t pv;
2463
2464 /* suboption header - needs additional argument for it */
2465 if (*(args[cur_arg+1]) == 0) {
2466 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2467 file, linenum, args[0], args[1], args[cur_arg]);
2468 err_code |= ERR_ALERT | ERR_FATAL;
2469 goto out;
2470 }
2471
2472 /* uint32_t + uint32_t + strlen("user")+1 + strlen(username)+1 + 1 */
2473 packet_len = 4 + 4 + 5 + strlen(args[cur_arg + 1])+1 +1;
2474 pv = htonl(0x30000); /* protocol version 3.0 */
2475
2476 packet = calloc(1, packet_len);
2477
2478 memcpy(packet + 4, &pv, 4);
2479
2480 /* copy "user" */
2481 memcpy(packet + 8, "user", 4);
2482
2483 /* copy username */
2484 memcpy(packet + 13, args[cur_arg+1], strlen(args[cur_arg+1]));
2485
2486 free(curproxy->check_req);
2487 curproxy->check_req = packet;
2488 curproxy->check_len = packet_len;
2489
2490 packet_len = htonl(packet_len);
2491 memcpy(packet, &packet_len, 4);
2492 cur_arg += 2;
2493 } else {
2494 /* unknown suboption - catchall */
2495 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2496 file, linenum, args[0], args[1]);
2497 err_code |= ERR_ALERT | ERR_FATAL;
2498 goto out;
2499 }
2500 } /* end while loop */
2501 }
2502 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2503 goto out;
2504 }
2505
2506 else if (!strcmp(args[1], "redis-check")) {
2507 /* use REDIS PING request to check servers' health */
2508 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2509 err_code |= ERR_WARN;
2510
2511 free(curproxy->check_req);
2512 curproxy->check_req = NULL;
2513 curproxy->options2 &= ~PR_O2_CHK_ANY;
2514 curproxy->options2 |= PR_O2_REDIS_CHK;
2515
2516 curproxy->check_req = malloc(sizeof(DEF_REDIS_CHECK_REQ) - 1);
2517 memcpy(curproxy->check_req, DEF_REDIS_CHECK_REQ, sizeof(DEF_REDIS_CHECK_REQ) - 1);
2518 curproxy->check_len = sizeof(DEF_REDIS_CHECK_REQ) - 1;
2519
2520 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2521 goto out;
2522 }
2523
2524 else if (!strcmp(args[1], "mysql-check")) {
2525 /* use MYSQL request to check servers' health */
2526 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2527 err_code |= ERR_WARN;
2528
2529 free(curproxy->check_req);
2530 curproxy->check_req = NULL;
2531 curproxy->options2 &= ~PR_O2_CHK_ANY;
2532 curproxy->options2 |= PR_O2_MYSQL_CHK;
2533
2534 /* This is an example of a MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte.
2535 * const char mysql40_client_auth_pkt[] = {
2536 * "\x0e\x00\x00" // packet length
2537 * "\x01" // packet number
2538 * "\x00\x00" // client capabilities
2539 * "\x00\x00\x01" // max packet
2540 * "haproxy\x00" // username (null terminated string)
2541 * "\x00" // filler (always 0x00)
2542 * "\x01\x00\x00" // packet length
2543 * "\x00" // packet number
2544 * "\x01" // COM_QUIT command
2545 * };
2546 */
2547
2548 /* This is an example of a MySQL >=4.1 client Authentication packet provided by Nenad Merdanovic.
2549 * const char mysql41_client_auth_pkt[] = {
2550 * "\x0e\x00\x00\" // packet length
2551 * "\x01" // packet number
2552 * "\x00\x00\x00\x00" // client capabilities
2553 * "\x00\x00\x00\x01" // max packet
2554 * "\x21" // character set (UTF-8)
2555 * char[23] // All zeroes
2556 * "haproxy\x00" // username (null terminated string)
2557 * "\x00" // filler (always 0x00)
2558 * "\x01\x00\x00" // packet length
2559 * "\x00" // packet number
2560 * "\x01" // COM_QUIT command
2561 * };
2562 */
2563
2564
2565 if (*(args[2])) {
2566 int cur_arg = 2;
2567
2568 while (*(args[cur_arg])) {
2569 if (strcmp(args[cur_arg], "user") == 0) {
2570 char *mysqluser;
2571 int packetlen, reqlen, userlen;
2572
2573 /* suboption header - needs additional argument for it */
2574 if (*(args[cur_arg+1]) == 0) {
2575 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2576 file, linenum, args[0], args[1], args[cur_arg]);
2577 err_code |= ERR_ALERT | ERR_FATAL;
2578 goto out;
2579 }
2580 mysqluser = args[cur_arg + 1];
2581 userlen = strlen(mysqluser);
2582
2583 if (*(args[cur_arg+2])) {
2584 if (!strcmp(args[cur_arg+2], "post-41")) {
2585 packetlen = userlen + 7 + 27;
2586 reqlen = packetlen + 9;
2587
2588 free(curproxy->check_req);
2589 curproxy->check_req = calloc(1, reqlen);
2590 curproxy->check_len = reqlen;
2591
2592 snprintf(curproxy->check_req, 4, "%c%c%c",
2593 ((unsigned char) packetlen & 0xff),
2594 ((unsigned char) (packetlen >> 8) & 0xff),
2595 ((unsigned char) (packetlen >> 16) & 0xff));
2596
2597 curproxy->check_req[3] = 1;
2598 curproxy->check_req[5] = 0x82; // 130
2599 curproxy->check_req[11] = 1;
2600 curproxy->check_req[12] = 33;
2601 memcpy(&curproxy->check_req[36], mysqluser, userlen);
2602 curproxy->check_req[36 + userlen + 1 + 1] = 1;
2603 curproxy->check_req[36 + userlen + 1 + 1 + 4] = 1;
2604 cur_arg += 3;
2605 } else {
2606 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'post-41'.\n", file, linenum, args[cur_arg+2]);
2607 err_code |= ERR_ALERT | ERR_FATAL;
2608 goto out;
2609 }
2610 } else {
2611 packetlen = userlen + 7;
2612 reqlen = packetlen + 9;
2613
2614 free(curproxy->check_req);
2615 curproxy->check_req = calloc(1, reqlen);
2616 curproxy->check_len = reqlen;
2617
2618 snprintf(curproxy->check_req, 4, "%c%c%c",
2619 ((unsigned char) packetlen & 0xff),
2620 ((unsigned char) (packetlen >> 8) & 0xff),
2621 ((unsigned char) (packetlen >> 16) & 0xff));
2622
2623 curproxy->check_req[3] = 1;
2624 curproxy->check_req[5] = 0x80;
2625 curproxy->check_req[8] = 1;
2626 memcpy(&curproxy->check_req[9], mysqluser, userlen);
2627 curproxy->check_req[9 + userlen + 1 + 1] = 1;
2628 curproxy->check_req[9 + userlen + 1 + 1 + 4] = 1;
2629 cur_arg += 2;
2630 }
2631 } else {
2632 /* unknown suboption - catchall */
2633 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2634 file, linenum, args[0], args[1]);
2635 err_code |= ERR_ALERT | ERR_FATAL;
2636 goto out;
2637 }
2638 } /* end while loop */
2639 }
2640 }
2641 else if (!strcmp(args[1], "ldap-check")) {
2642 /* use LDAP request to check servers' health */
2643 free(curproxy->check_req);
2644 curproxy->check_req = NULL;
2645 curproxy->options2 &= ~PR_O2_CHK_ANY;
2646 curproxy->options2 |= PR_O2_LDAP_CHK;
2647
2648 curproxy->check_req = malloc(sizeof(DEF_LDAP_CHECK_REQ) - 1);
2649 memcpy(curproxy->check_req, DEF_LDAP_CHECK_REQ, sizeof(DEF_LDAP_CHECK_REQ) - 1);
2650 curproxy->check_len = sizeof(DEF_LDAP_CHECK_REQ) - 1;
2651 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2652 goto out;
2653 }
2654 else if (!strcmp(args[1], "spop-check")) {
2655 if (curproxy == &defproxy) {
2656 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n",
2657 file, linenum, args[0], args[1]);
2658 err_code |= ERR_ALERT | ERR_FATAL;
2659 goto out;
2660 }
2661 if (curproxy->cap & PR_CAP_FE) {
2662 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'frontend' and 'listen' sections.\n",
2663 file, linenum, args[0], args[1]);
2664 err_code |= ERR_ALERT | ERR_FATAL;
2665 goto out;
2666 }
2667
2668 /* use SPOE request to check servers' health */
2669 free(curproxy->check_req);
2670 curproxy->check_req = NULL;
2671 curproxy->options2 &= ~PR_O2_CHK_ANY;
2672 curproxy->options2 |= PR_O2_SPOP_CHK;
2673
2674 if (spoe_prepare_healthcheck_request(&curproxy->check_req, &curproxy->check_len)) {
2675 ha_alert("parsing [%s:%d] : failed to prepare SPOP healthcheck request.\n", file, linenum);
2676 err_code |= ERR_ALERT | ERR_FATAL;
2677 goto out;
2678 }
2679 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2680 goto out;
2681 }
2682 else if (!strcmp(args[1], "tcp-check")) {
2683 /* use raw TCPCHK send/expect to check servers' health */
2684 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2685 err_code |= ERR_WARN;
2686
2687 free(curproxy->check_req);
2688 curproxy->check_req = NULL;
2689 curproxy->options2 &= ~PR_O2_CHK_ANY;
2690 curproxy->options2 |= PR_O2_TCPCHK_CHK;
2691 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2692 goto out;
2693 }
2694 else if (!strcmp(args[1], "external-check")) {
2695 /* excute an external command to check servers' health */
2696 free(curproxy->check_req);
2697 curproxy->check_req = NULL;
2698 curproxy->options2 &= ~PR_O2_CHK_ANY;
2699 curproxy->options2 |= PR_O2_EXT_CHK;
2700 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2701 goto out;
2702 }
2703 else if (!strcmp(args[1], "forwardfor")) {
2704 int cur_arg;
2705
2706 /* insert x-forwarded-for field, but not for the IP address listed as an except.
2707 * set default options (ie: bitfield, header name, etc)
2708 */
2709
2710 curproxy->options |= PR_O_FWDFOR | PR_O_FF_ALWAYS;
2711
2712 free(curproxy->fwdfor_hdr_name);
2713 curproxy->fwdfor_hdr_name = strdup(DEF_XFORWARDFOR_HDR);
2714 curproxy->fwdfor_hdr_len = strlen(DEF_XFORWARDFOR_HDR);
2715
2716 /* loop to go through arguments - start at 2, since 0+1 = "option" "forwardfor" */
2717 cur_arg = 2;
2718 while (*(args[cur_arg])) {
2719 if (!strcmp(args[cur_arg], "except")) {
2720 /* suboption except - needs additional argument for it */
2721 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_net, &curproxy->except_mask)) {
2722 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2723 file, linenum, args[0], args[1], args[cur_arg]);
2724 err_code |= ERR_ALERT | ERR_FATAL;
2725 goto out;
2726 }
2727 /* flush useless bits */
2728 curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
2729 cur_arg += 2;
2730 } else if (!strcmp(args[cur_arg], "header")) {
2731 /* suboption header - needs additional argument for it */
2732 if (*(args[cur_arg+1]) == 0) {
2733 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2734 file, linenum, args[0], args[1], args[cur_arg]);
2735 err_code |= ERR_ALERT | ERR_FATAL;
2736 goto out;
2737 }
2738 free(curproxy->fwdfor_hdr_name);
2739 curproxy->fwdfor_hdr_name = strdup(args[cur_arg+1]);
2740 curproxy->fwdfor_hdr_len = strlen(curproxy->fwdfor_hdr_name);
2741 cur_arg += 2;
2742 } else if (!strcmp(args[cur_arg], "if-none")) {
2743 curproxy->options &= ~PR_O_FF_ALWAYS;
2744 cur_arg += 1;
2745 } else {
2746 /* unknown suboption - catchall */
2747 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except', 'header' and 'if-none'.\n",
2748 file, linenum, args[0], args[1]);
2749 err_code |= ERR_ALERT | ERR_FATAL;
2750 goto out;
2751 }
2752 } /* end while loop */
2753 }
2754 else if (!strcmp(args[1], "originalto")) {
2755 int cur_arg;
2756
2757 /* insert x-original-to field, but not for the IP address listed as an except.
2758 * set default options (ie: bitfield, header name, etc)
2759 */
2760
2761 curproxy->options |= PR_O_ORGTO;
2762
2763 free(curproxy->orgto_hdr_name);
2764 curproxy->orgto_hdr_name = strdup(DEF_XORIGINALTO_HDR);
2765 curproxy->orgto_hdr_len = strlen(DEF_XORIGINALTO_HDR);
2766
2767 /* loop to go through arguments - start at 2, since 0+1 = "option" "originalto" */
2768 cur_arg = 2;
2769 while (*(args[cur_arg])) {
2770 if (!strcmp(args[cur_arg], "except")) {
2771 /* suboption except - needs additional argument for it */
2772 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_to, &curproxy->except_mask_to)) {
2773 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2774 file, linenum, args[0], args[1], args[cur_arg]);
2775 err_code |= ERR_ALERT | ERR_FATAL;
2776 goto out;
2777 }
2778 /* flush useless bits */
2779 curproxy->except_to.s_addr &= curproxy->except_mask_to.s_addr;
2780 cur_arg += 2;
2781 } else if (!strcmp(args[cur_arg], "header")) {
2782 /* suboption header - needs additional argument for it */
2783 if (*(args[cur_arg+1]) == 0) {
2784 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2785 file, linenum, args[0], args[1], args[cur_arg]);
2786 err_code |= ERR_ALERT | ERR_FATAL;
2787 goto out;
2788 }
2789 free(curproxy->orgto_hdr_name);
2790 curproxy->orgto_hdr_name = strdup(args[cur_arg+1]);
2791 curproxy->orgto_hdr_len = strlen(curproxy->orgto_hdr_name);
2792 cur_arg += 2;
2793 } else {
2794 /* unknown suboption - catchall */
2795 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
2796 file, linenum, args[0], args[1]);
2797 err_code |= ERR_ALERT | ERR_FATAL;
2798 goto out;
2799 }
2800 } /* end while loop */
2801 }
2802 else {
2803 ha_alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
2804 err_code |= ERR_ALERT | ERR_FATAL;
2805 goto out;
2806 }
2807 goto out;
2808 }
2809 else if (!strcmp(args[0], "default_backend")) {
2810 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
2811 err_code |= ERR_WARN;
2812
2813 if (*(args[1]) == 0) {
2814 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
2815 err_code |= ERR_ALERT | ERR_FATAL;
2816 goto out;
2817 }
2818 free(curproxy->defbe.name);
2819 curproxy->defbe.name = strdup(args[1]);
2820
2821 if (alertif_too_many_args_idx(1, 0, file, linenum, args, &err_code))
2822 goto out;
2823 }
2824 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
2825 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2826 err_code |= ERR_WARN;
2827
2828 if (!already_warned(WARN_REDISPATCH_DEPRECATED))
2829 ha_warning("parsing [%s:%d]: keyword '%s' is deprecated in favor of 'option redispatch', and will not be supported by future versions.\n",
2830 file, linenum, args[0]);
2831 err_code |= ERR_WARN;
2832 /* enable reconnections to dispatch */
2833 curproxy->options |= PR_O_REDISP;
2834
2835 if (alertif_too_many_args_idx(1, 0, file, linenum, args, &err_code))
2836 goto out;
2837 }
2838 else if (!strcmp(args[0], "http-reuse")) {
2839 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2840 err_code |= ERR_WARN;
2841
2842 if (strcmp(args[1], "never") == 0) {
2843 /* enable a graceful server shutdown on an HTTP 404 response */
2844 curproxy->options &= ~PR_O_REUSE_MASK;
2845 curproxy->options |= PR_O_REUSE_NEVR;
2846 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2847 goto out;
2848 }
2849 else if (strcmp(args[1], "safe") == 0) {
2850 /* enable a graceful server shutdown on an HTTP 404 response */
2851 curproxy->options &= ~PR_O_REUSE_MASK;
2852 curproxy->options |= PR_O_REUSE_SAFE;
2853 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2854 goto out;
2855 }
2856 else if (strcmp(args[1], "aggressive") == 0) {
2857 curproxy->options &= ~PR_O_REUSE_MASK;
2858 curproxy->options |= PR_O_REUSE_AGGR;
2859 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2860 goto out;
2861 }
2862 else if (strcmp(args[1], "always") == 0) {
2863 /* enable a graceful server shutdown on an HTTP 404 response */
2864 curproxy->options &= ~PR_O_REUSE_MASK;
2865 curproxy->options |= PR_O_REUSE_ALWS;
2866 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2867 goto out;
2868 }
2869 else {
2870 ha_alert("parsing [%s:%d] : '%s' only supports 'never', 'safe', 'aggressive', 'always'.\n", file, linenum, args[0]);
2871 err_code |= ERR_ALERT | ERR_FATAL;
2872 goto out;
2873 }
2874 }
2875 else if (!strcmp(args[0], "http-check")) {
2876 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2877 err_code |= ERR_WARN;
2878
2879 if (strcmp(args[1], "disable-on-404") == 0) {
2880 /* enable a graceful server shutdown on an HTTP 404 response */
2881 curproxy->options |= PR_O_DISABLE404;
2882 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2883 goto out;
2884 }
2885 else if (strcmp(args[1], "send-state") == 0) {
2886 /* enable emission of the apparent state of a server in HTTP checks */
2887 curproxy->options2 |= PR_O2_CHK_SNDST;
2888 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2889 goto out;
2890 }
2891 else if (strcmp(args[1], "expect") == 0) {
2892 const char *ptr_arg;
2893 int cur_arg;
2894
2895 if (curproxy->options2 & PR_O2_EXP_TYPE) {
2896 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
2897 err_code |= ERR_ALERT | ERR_FATAL;
2898 goto out;
2899 }
2900
2901 cur_arg = 2;
2902 /* consider exclamation marks, sole or at the beginning of a word */
2903 while (*(ptr_arg = args[cur_arg])) {
2904 while (*ptr_arg == '!') {
2905 curproxy->options2 ^= PR_O2_EXP_INV;
2906 ptr_arg++;
2907 }
2908 if (*ptr_arg)
2909 break;
2910 cur_arg++;
2911 }
2912 /* now ptr_arg points to the beginning of a word past any possible
2913 * exclamation mark, and cur_arg is the argument which holds this word.
2914 */
2915 if (strcmp(ptr_arg, "status") == 0) {
2916 if (!*(args[cur_arg + 1])) {
2917 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
2918 file, linenum, args[0], args[1], ptr_arg);
2919 err_code |= ERR_ALERT | ERR_FATAL;
2920 goto out;
2921 }
2922 curproxy->options2 |= PR_O2_EXP_STS;
2923 free(curproxy->expect_str);
2924 curproxy->expect_str = strdup(args[cur_arg + 1]);
2925 }
2926 else if (strcmp(ptr_arg, "string") == 0) {
2927 if (!*(args[cur_arg + 1])) {
2928 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
2929 file, linenum, args[0], args[1], ptr_arg);
2930 err_code |= ERR_ALERT | ERR_FATAL;
2931 goto out;
2932 }
2933 curproxy->options2 |= PR_O2_EXP_STR;
2934 free(curproxy->expect_str);
2935 curproxy->expect_str = strdup(args[cur_arg + 1]);
2936 }
2937 else if (strcmp(ptr_arg, "rstatus") == 0) {
2938 if (!*(args[cur_arg + 1])) {
2939 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> 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_RSTS;
2945 free(curproxy->expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +02002946 regex_free(curproxy->expect_regex);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002947 curproxy->expect_str = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002948 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02002949 if (!(curproxy->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
2950 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002951 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
2952 free(error);
2953 err_code |= ERR_ALERT | ERR_FATAL;
2954 goto out;
2955 }
2956 }
2957 else if (strcmp(ptr_arg, "rstring") == 0) {
2958 if (!*(args[cur_arg + 1])) {
2959 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
2960 file, linenum, args[0], args[1], ptr_arg);
2961 err_code |= ERR_ALERT | ERR_FATAL;
2962 goto out;
2963 }
2964 curproxy->options2 |= PR_O2_EXP_RSTR;
2965 free(curproxy->expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +02002966 regex_free(curproxy->expect_regex);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002967 curproxy->expect_str = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002968 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02002969 if (!(curproxy->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
2970 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002971 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
2972 free(error);
2973 err_code |= ERR_ALERT | ERR_FATAL;
2974 goto out;
2975 }
2976 }
2977 else {
2978 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'status', 'string', 'rstatus', 'rstring', found '%s'.\n",
2979 file, linenum, args[0], args[1], ptr_arg);
2980 err_code |= ERR_ALERT | ERR_FATAL;
2981 goto out;
2982 }
2983 }
2984 else {
2985 ha_alert("parsing [%s:%d] : '%s' only supports 'disable-on-404', 'send-state', 'expect'.\n", file, linenum, args[0]);
2986 err_code |= ERR_ALERT | ERR_FATAL;
2987 goto out;
2988 }
2989 }
2990 else if (!strcmp(args[0], "tcp-check")) {
2991 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2992 err_code |= ERR_WARN;
2993
2994 if (strcmp(args[1], "comment") == 0) {
2995 int cur_arg;
2996 struct tcpcheck_rule *tcpcheck;
2997
2998 cur_arg = 1;
2999 tcpcheck = calloc(1, sizeof(*tcpcheck));
3000 tcpcheck->action = TCPCHK_ACT_COMMENT;
3001
3002 if (!*args[cur_arg + 1]) {
3003 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3004 file, linenum, args[cur_arg]);
3005 err_code |= ERR_ALERT | ERR_FATAL;
3006 goto out;
3007 }
3008
3009 tcpcheck->comment = strdup(args[cur_arg + 1]);
3010
3011 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3012 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
3013 goto out;
3014 }
3015 else if (strcmp(args[1], "connect") == 0) {
3016 const char *ptr_arg;
3017 int cur_arg;
3018 struct tcpcheck_rule *tcpcheck;
3019
3020 /* check if first rule is also a 'connect' action */
3021 tcpcheck = LIST_NEXT(&curproxy->tcpcheck_rules, struct tcpcheck_rule *, list);
3022 while (&tcpcheck->list != &curproxy->tcpcheck_rules &&
3023 tcpcheck->action == TCPCHK_ACT_COMMENT) {
3024 tcpcheck = LIST_NEXT(&tcpcheck->list, struct tcpcheck_rule *, list);
3025 }
3026
3027 if (&tcpcheck->list != &curproxy->tcpcheck_rules
3028 && tcpcheck->action != TCPCHK_ACT_CONNECT) {
3029 ha_alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
3030 file, linenum);
3031 err_code |= ERR_ALERT | ERR_FATAL;
3032 goto out;
3033 }
3034
3035 cur_arg = 2;
3036 tcpcheck = calloc(1, sizeof(*tcpcheck));
3037 tcpcheck->action = TCPCHK_ACT_CONNECT;
3038
3039 /* parsing each parameters to fill up the rule */
3040 while (*(ptr_arg = args[cur_arg])) {
3041 /* tcp port */
3042 if (strcmp(args[cur_arg], "port") == 0) {
3043 if ( (atol(args[cur_arg + 1]) > 65535) ||
3044 (atol(args[cur_arg + 1]) < 1) ){
3045 ha_alert("parsing [%s:%d] : '%s %s %s' expects a valid TCP port (from range 1 to 65535), got %s.\n",
3046 file, linenum, args[0], args[1], "port", args[cur_arg + 1]);
3047 err_code |= ERR_ALERT | ERR_FATAL;
3048 goto out;
3049 }
3050 tcpcheck->port = atol(args[cur_arg + 1]);
3051 cur_arg += 2;
3052 }
3053 /* send proxy protocol */
3054 else if (strcmp(args[cur_arg], "send-proxy") == 0) {
3055 tcpcheck->conn_opts |= TCPCHK_OPT_SEND_PROXY;
3056 cur_arg++;
3057 }
3058#ifdef USE_OPENSSL
3059 else if (strcmp(args[cur_arg], "ssl") == 0) {
3060 curproxy->options |= PR_O_TCPCHK_SSL;
3061 tcpcheck->conn_opts |= TCPCHK_OPT_SSL;
3062 cur_arg++;
3063 }
3064#endif /* USE_OPENSSL */
3065 /* comment for this tcpcheck line */
3066 else if (strcmp(args[cur_arg], "comment") == 0) {
3067 if (!*args[cur_arg + 1]) {
3068 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3069 file, linenum, args[cur_arg]);
3070 err_code |= ERR_ALERT | ERR_FATAL;
3071 goto out;
3072 }
3073 tcpcheck->comment = strdup(args[cur_arg + 1]);
3074 cur_arg += 2;
3075 }
3076 else {
3077#ifdef USE_OPENSSL
3078 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n",
3079#else /* USE_OPENSSL */
3080 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or but got '%s' as argument.\n",
3081#endif /* USE_OPENSSL */
3082 file, linenum, args[0], args[1], args[cur_arg]);
3083 err_code |= ERR_ALERT | ERR_FATAL;
3084 goto out;
3085 }
3086
3087 }
3088
3089 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3090 }
3091 else if (strcmp(args[1], "send") == 0) {
3092 if (! *(args[2]) ) {
3093 /* SEND string expected */
3094 ha_alert("parsing [%s:%d] : '%s %s %s' expects <STRING> as argument.\n",
3095 file, linenum, args[0], args[1], args[2]);
3096 err_code |= ERR_ALERT | ERR_FATAL;
3097 goto out;
3098 } else {
3099 struct tcpcheck_rule *tcpcheck;
3100
3101 tcpcheck = calloc(1, sizeof(*tcpcheck));
3102
3103 tcpcheck->action = TCPCHK_ACT_SEND;
3104 tcpcheck->string_len = strlen(args[2]);
3105 tcpcheck->string = strdup(args[2]);
3106 tcpcheck->expect_regex = NULL;
3107
3108 /* comment for this tcpcheck line */
3109 if (strcmp(args[3], "comment") == 0) {
3110 if (!*args[4]) {
3111 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3112 file, linenum, args[3]);
3113 err_code |= ERR_ALERT | ERR_FATAL;
3114 goto out;
3115 }
3116 tcpcheck->comment = strdup(args[4]);
3117 }
3118
3119 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3120 }
3121 }
3122 else if (strcmp(args[1], "send-binary") == 0) {
3123 if (! *(args[2]) ) {
3124 /* SEND binary string expected */
3125 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument.\n",
3126 file, linenum, args[0], args[1], args[2]);
3127 err_code |= ERR_ALERT | ERR_FATAL;
3128 goto out;
3129 } else {
3130 struct tcpcheck_rule *tcpcheck;
3131 char *err = NULL;
3132
3133 tcpcheck = calloc(1, sizeof(*tcpcheck));
3134
3135 tcpcheck->action = TCPCHK_ACT_SEND;
3136 if (parse_binary(args[2], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3137 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3138 file, linenum, args[0], args[1], args[2], err);
3139 err_code |= ERR_ALERT | ERR_FATAL;
3140 goto out;
3141 }
3142 tcpcheck->expect_regex = NULL;
3143
3144 /* comment for this tcpcheck line */
3145 if (strcmp(args[3], "comment") == 0) {
3146 if (!*args[4]) {
3147 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3148 file, linenum, args[3]);
3149 err_code |= ERR_ALERT | ERR_FATAL;
3150 goto out;
3151 }
3152 tcpcheck->comment = strdup(args[4]);
3153 }
3154
3155 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3156 }
3157 }
3158 else if (strcmp(args[1], "expect") == 0) {
3159 const char *ptr_arg;
3160 int cur_arg;
3161 int inverse = 0;
3162
3163 if (curproxy->options2 & PR_O2_EXP_TYPE) {
3164 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
3165 err_code |= ERR_ALERT | ERR_FATAL;
3166 goto out;
3167 }
3168
3169 cur_arg = 2;
3170 /* consider exclamation marks, sole or at the beginning of a word */
3171 while (*(ptr_arg = args[cur_arg])) {
3172 while (*ptr_arg == '!') {
3173 inverse = !inverse;
3174 ptr_arg++;
3175 }
3176 if (*ptr_arg)
3177 break;
3178 cur_arg++;
3179 }
3180 /* now ptr_arg points to the beginning of a word past any possible
3181 * exclamation mark, and cur_arg is the argument which holds this word.
3182 */
3183 if (strcmp(ptr_arg, "binary") == 0) {
3184 struct tcpcheck_rule *tcpcheck;
3185 char *err = NULL;
3186
3187 if (!*(args[cur_arg + 1])) {
3188 ha_alert("parsing [%s:%d] : '%s %s %s' expects <binary string> as an argument.\n",
3189 file, linenum, args[0], args[1], ptr_arg);
3190 err_code |= ERR_ALERT | ERR_FATAL;
3191 goto out;
3192 }
3193
3194 tcpcheck = calloc(1, sizeof(*tcpcheck));
3195
3196 tcpcheck->action = TCPCHK_ACT_EXPECT;
3197 if (parse_binary(args[cur_arg + 1], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3198 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3199 file, linenum, args[0], args[1], args[2], err);
3200 err_code |= ERR_ALERT | ERR_FATAL;
3201 goto out;
3202 }
3203 tcpcheck->expect_regex = NULL;
3204 tcpcheck->inverse = inverse;
3205
3206 /* tcpcheck comment */
3207 cur_arg += 2;
3208 if (strcmp(args[cur_arg], "comment") == 0) {
3209 if (!*args[cur_arg + 1]) {
3210 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3211 file, linenum, args[cur_arg + 1]);
3212 err_code |= ERR_ALERT | ERR_FATAL;
3213 goto out;
3214 }
3215 tcpcheck->comment = strdup(args[cur_arg + 1]);
3216 }
3217
3218 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3219 }
3220 else if (strcmp(ptr_arg, "string") == 0) {
3221 struct tcpcheck_rule *tcpcheck;
3222
3223 if (!*(args[cur_arg + 1])) {
3224 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3225 file, linenum, args[0], args[1], ptr_arg);
3226 err_code |= ERR_ALERT | ERR_FATAL;
3227 goto out;
3228 }
3229
3230 tcpcheck = calloc(1, sizeof(*tcpcheck));
3231
3232 tcpcheck->action = TCPCHK_ACT_EXPECT;
3233 tcpcheck->string_len = strlen(args[cur_arg + 1]);
3234 tcpcheck->string = strdup(args[cur_arg + 1]);
3235 tcpcheck->expect_regex = NULL;
3236 tcpcheck->inverse = inverse;
3237
3238 /* tcpcheck comment */
3239 cur_arg += 2;
3240 if (strcmp(args[cur_arg], "comment") == 0) {
3241 if (!*args[cur_arg + 1]) {
3242 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3243 file, linenum, args[cur_arg + 1]);
3244 err_code |= ERR_ALERT | ERR_FATAL;
3245 goto out;
3246 }
3247 tcpcheck->comment = strdup(args[cur_arg + 1]);
3248 }
3249
3250 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3251 }
3252 else if (strcmp(ptr_arg, "rstring") == 0) {
3253 struct tcpcheck_rule *tcpcheck;
3254
3255 if (!*(args[cur_arg + 1])) {
3256 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3257 file, linenum, args[0], args[1], ptr_arg);
3258 err_code |= ERR_ALERT | ERR_FATAL;
3259 goto out;
3260 }
3261
3262 tcpcheck = calloc(1, sizeof(*tcpcheck));
3263
3264 tcpcheck->action = TCPCHK_ACT_EXPECT;
3265 tcpcheck->string_len = 0;
3266 tcpcheck->string = NULL;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003267 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02003268 if (!(tcpcheck->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
3269 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003270 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3271 free(error);
3272 err_code |= ERR_ALERT | ERR_FATAL;
3273 goto out;
3274 }
3275 tcpcheck->inverse = inverse;
3276
3277 /* tcpcheck comment */
3278 cur_arg += 2;
3279 if (strcmp(args[cur_arg], "comment") == 0) {
3280 if (!*args[cur_arg + 1]) {
3281 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3282 file, linenum, args[cur_arg + 1]);
3283 err_code |= ERR_ALERT | ERR_FATAL;
3284 goto out;
3285 }
3286 tcpcheck->comment = strdup(args[cur_arg + 1]);
3287 }
3288
3289 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3290 }
3291 else {
3292 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'binary', 'string', 'rstring', found '%s'.\n",
3293 file, linenum, args[0], args[1], ptr_arg);
3294 err_code |= ERR_ALERT | ERR_FATAL;
3295 goto out;
3296 }
3297 }
3298 else {
3299 ha_alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
3300 err_code |= ERR_ALERT | ERR_FATAL;
3301 goto out;
3302 }
3303 }
3304 else if (!strcmp(args[0], "monitor")) {
3305 if (curproxy == &defproxy) {
3306 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3307 err_code |= ERR_ALERT | ERR_FATAL;
3308 goto out;
3309 }
3310
3311 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3312 err_code |= ERR_WARN;
3313
3314 if (strcmp(args[1], "fail") == 0) {
3315 /* add a condition to fail monitor requests */
3316 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
3317 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
3318 file, linenum, args[0], args[1]);
3319 err_code |= ERR_ALERT | ERR_FATAL;
3320 goto out;
3321 }
3322
3323 err_code |= warnif_misplaced_monitor(curproxy, file, linenum, "monitor fail");
3324 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
3325 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
3326 file, linenum, args[0], args[1], errmsg);
3327 err_code |= ERR_ALERT | ERR_FATAL;
3328 goto out;
3329 }
3330 LIST_ADDQ(&curproxy->mon_fail_cond, &cond->list);
3331 }
3332 else {
3333 ha_alert("parsing [%s:%d] : '%s' only supports 'fail'.\n", file, linenum, args[0]);
3334 err_code |= ERR_ALERT | ERR_FATAL;
3335 goto out;
3336 }
3337 }
Willy Tarreaue5733232019-05-22 19:24:06 +02003338#ifdef USE_TPROXY
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003339 else if (!strcmp(args[0], "transparent")) {
3340 /* enable transparent proxy connections */
3341 curproxy->options |= PR_O_TRANSP;
3342 if (alertif_too_many_args(0, file, linenum, args, &err_code))
3343 goto out;
3344 }
3345#endif
3346 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3347 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
3348 err_code |= ERR_WARN;
3349
3350 if (*(args[1]) == 0) {
3351 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3352 err_code |= ERR_ALERT | ERR_FATAL;
3353 goto out;
3354 }
3355 curproxy->maxconn = atol(args[1]);
3356 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3357 goto out;
3358 }
3359 else if (!strcmp(args[0], "backlog")) { /* backlog */
3360 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3361 err_code |= ERR_WARN;
3362
3363 if (*(args[1]) == 0) {
3364 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3365 err_code |= ERR_ALERT | ERR_FATAL;
3366 goto out;
3367 }
3368 curproxy->backlog = atol(args[1]);
3369 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3370 goto out;
3371 }
3372 else if (!strcmp(args[0], "fullconn")) { /* fullconn */
3373 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
3374 err_code |= ERR_WARN;
3375
3376 if (*(args[1]) == 0) {
3377 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3378 err_code |= ERR_ALERT | ERR_FATAL;
3379 goto out;
3380 }
3381 curproxy->fullconn = atol(args[1]);
3382 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3383 goto out;
3384 }
3385 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3386 if (*(args[1]) == 0) {
3387 ha_alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
3388 err_code |= ERR_ALERT | ERR_FATAL;
3389 goto out;
3390 }
3391 err = parse_time_err(args[1], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +02003392 if (err == PARSE_TIME_OVER) {
3393 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to grace time, maximum value is 2147483647 ms (~24.8 days).\n",
3394 file, linenum, args[1]);
3395 err_code |= ERR_ALERT | ERR_FATAL;
3396 goto out;
3397 }
3398 else if (err == PARSE_TIME_UNDER) {
3399 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to grace time, minimum non-null value is 1 ms.\n",
3400 file, linenum, args[1]);
3401 err_code |= ERR_ALERT | ERR_FATAL;
3402 goto out;
3403 }
3404 else if (err) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003405 ha_alert("parsing [%s:%d] : unexpected character '%c' in grace time.\n",
3406 file, linenum, *err);
3407 err_code |= ERR_ALERT | ERR_FATAL;
3408 goto out;
3409 }
3410 curproxy->grace = val;
3411 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3412 goto out;
3413 }
3414 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3415 struct sockaddr_storage *sk;
3416 int port1, port2;
3417 struct protocol *proto;
3418
3419 if (curproxy == &defproxy) {
3420 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3421 err_code |= ERR_ALERT | ERR_FATAL;
3422 goto out;
3423 }
3424 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3425 err_code |= ERR_WARN;
3426
3427 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3428 if (!sk) {
3429 ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
3430 err_code |= ERR_ALERT | ERR_FATAL;
3431 goto out;
3432 }
3433
3434 proto = protocol_by_family(sk->ss_family);
3435 if (!proto || !proto->connect) {
3436 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3437 file, linenum, args[0], args[1]);
3438 err_code |= ERR_ALERT | ERR_FATAL;
3439 goto out;
3440 }
3441
3442 if (port1 != port2) {
3443 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'.\n",
3444 file, linenum, args[0], args[1]);
3445 err_code |= ERR_ALERT | ERR_FATAL;
3446 goto out;
3447 }
3448
3449 if (!port1) {
3450 ha_alert("parsing [%s:%d] : '%s' : missing port number in '%s', <addr:port> expected.\n",
3451 file, linenum, args[0], args[1]);
3452 err_code |= ERR_ALERT | ERR_FATAL;
3453 goto out;
3454 }
3455
3456 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3457 goto out;
3458
3459 curproxy->dispatch_addr = *sk;
3460 curproxy->options |= PR_O_DISPATCH;
3461 }
3462 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
3463 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3464 err_code |= ERR_WARN;
3465
3466 if (backend_parse_balance((const char **)args + 1, &errmsg, curproxy) < 0) {
3467 ha_alert("parsing [%s:%d] : %s %s\n", file, linenum, args[0], errmsg);
3468 err_code |= ERR_ALERT | ERR_FATAL;
3469 goto out;
3470 }
3471 }
3472 else if (!strcmp(args[0], "hash-type")) { /* set hashing method */
3473 /**
3474 * The syntax for hash-type config element is
3475 * hash-type {map-based|consistent} [[<algo>] avalanche]
3476 *
3477 * The default hash function is sdbm for map-based and sdbm+avalanche for consistent.
3478 */
3479 curproxy->lbprm.algo &= ~(BE_LB_HASH_TYPE | BE_LB_HASH_FUNC | BE_LB_HASH_MOD);
3480
3481 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3482 err_code |= ERR_WARN;
3483
3484 if (strcmp(args[1], "consistent") == 0) { /* use consistent hashing */
3485 curproxy->lbprm.algo |= BE_LB_HASH_CONS;
3486 }
3487 else if (strcmp(args[1], "map-based") == 0) { /* use map-based hashing */
3488 curproxy->lbprm.algo |= BE_LB_HASH_MAP;
3489 }
3490 else if (strcmp(args[1], "avalanche") == 0) {
3491 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]);
3492 err_code |= ERR_ALERT | ERR_FATAL;
3493 goto out;
3494 }
3495 else {
3496 ha_alert("parsing [%s:%d] : '%s' only supports 'consistent' and 'map-based'.\n", file, linenum, args[0]);
3497 err_code |= ERR_ALERT | ERR_FATAL;
3498 goto out;
3499 }
3500
3501 /* set the hash function to use */
3502 if (!*args[2]) {
3503 /* the default algo is sdbm */
3504 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3505
3506 /* if consistent with no argument, then avalanche modifier is also applied */
3507 if ((curproxy->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS)
3508 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3509 } else {
3510 /* set the hash function */
3511 if (!strcmp(args[2], "sdbm")) {
3512 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3513 }
3514 else if (!strcmp(args[2], "djb2")) {
3515 curproxy->lbprm.algo |= BE_LB_HFCN_DJB2;
3516 }
3517 else if (!strcmp(args[2], "wt6")) {
3518 curproxy->lbprm.algo |= BE_LB_HFCN_WT6;
3519 }
3520 else if (!strcmp(args[2], "crc32")) {
3521 curproxy->lbprm.algo |= BE_LB_HFCN_CRC32;
3522 }
3523 else {
3524 ha_alert("parsing [%s:%d] : '%s' only supports 'sdbm', 'djb2', 'crc32', or 'wt6' hash functions.\n", file, linenum, args[0]);
3525 err_code |= ERR_ALERT | ERR_FATAL;
3526 goto out;
3527 }
3528
3529 /* set the hash modifier */
3530 if (!strcmp(args[3], "avalanche")) {
3531 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3532 }
3533 else if (*args[3]) {
3534 ha_alert("parsing [%s:%d] : '%s' only supports 'avalanche' as a modifier for hash functions.\n", file, linenum, args[0]);
3535 err_code |= ERR_ALERT | ERR_FATAL;
3536 goto out;
3537 }
3538 }
3539 }
3540 else if (strcmp(args[0], "hash-balance-factor") == 0) {
3541 if (*(args[1]) == 0) {
3542 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3543 err_code |= ERR_ALERT | ERR_FATAL;
3544 goto out;
3545 }
Willy Tarreau76e84f52019-01-14 16:50:58 +01003546 curproxy->lbprm.hash_balance_factor = atol(args[1]);
3547 if (curproxy->lbprm.hash_balance_factor != 0 && curproxy->lbprm.hash_balance_factor <= 100) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003548 ha_alert("parsing [%s:%d] : '%s' must be 0 or greater than 100.\n", file, linenum, args[0]);
3549 err_code |= ERR_ALERT | ERR_FATAL;
3550 goto out;
3551 }
3552 }
3553 else if (strcmp(args[0], "unique-id-format") == 0) {
3554 if (!*(args[1])) {
3555 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3556 err_code |= ERR_ALERT | ERR_FATAL;
3557 goto out;
3558 }
3559 if (*(args[2])) {
3560 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3561 err_code |= ERR_ALERT | ERR_FATAL;
3562 goto out;
3563 }
3564 free(curproxy->conf.uniqueid_format_string);
3565 curproxy->conf.uniqueid_format_string = strdup(args[1]);
3566
3567 free(curproxy->conf.uif_file);
3568 curproxy->conf.uif_file = strdup(curproxy->conf.args.file);
3569 curproxy->conf.uif_line = curproxy->conf.args.line;
3570 }
3571
3572 else if (strcmp(args[0], "unique-id-header") == 0) {
3573 if (!*(args[1])) {
3574 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3575 err_code |= ERR_ALERT | ERR_FATAL;
3576 goto out;
3577 }
3578 free(curproxy->header_unique_id);
3579 curproxy->header_unique_id = strdup(args[1]);
3580 }
3581
3582 else if (strcmp(args[0], "log-format") == 0) {
3583 if (!*(args[1])) {
3584 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3585 err_code |= ERR_ALERT | ERR_FATAL;
3586 goto out;
3587 }
3588 if (*(args[2])) {
3589 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3590 err_code |= ERR_ALERT | ERR_FATAL;
3591 goto out;
3592 }
3593 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
3594 char *oldlogformat = "log-format";
3595
3596 if (curproxy->conf.logformat_string == default_http_log_format)
3597 oldlogformat = "option httplog";
3598 else if (curproxy->conf.logformat_string == default_tcp_log_format)
3599 oldlogformat = "option tcplog";
3600 else if (curproxy->conf.logformat_string == clf_http_log_format)
3601 oldlogformat = "option httplog clf";
3602 ha_warning("parsing [%s:%d]: 'log-format' overrides previous '%s' in 'defaults' section.\n",
3603 file, linenum, oldlogformat);
3604 }
3605 if (curproxy->conf.logformat_string != default_http_log_format &&
3606 curproxy->conf.logformat_string != default_tcp_log_format &&
3607 curproxy->conf.logformat_string != clf_http_log_format)
3608 free(curproxy->conf.logformat_string);
3609 curproxy->conf.logformat_string = strdup(args[1]);
3610
3611 free(curproxy->conf.lfs_file);
3612 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
3613 curproxy->conf.lfs_line = curproxy->conf.args.line;
3614
3615 /* get a chance to improve log-format error reporting by
3616 * reporting the correct line-number when possible.
3617 */
3618 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3619 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format' directive is ignored in backends.\n",
3620 file, linenum, curproxy->id);
3621 err_code |= ERR_WARN;
3622 }
3623 }
3624 else if (!strcmp(args[0], "log-format-sd")) {
3625 if (!*(args[1])) {
3626 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3627 err_code |= ERR_ALERT | ERR_FATAL;
3628 goto out;
3629 }
3630 if (*(args[2])) {
3631 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3632 err_code |= ERR_ALERT | ERR_FATAL;
3633 goto out;
3634 }
3635
3636 if (curproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
3637 free(curproxy->conf.logformat_sd_string);
3638 curproxy->conf.logformat_sd_string = strdup(args[1]);
3639
3640 free(curproxy->conf.lfsd_file);
3641 curproxy->conf.lfsd_file = strdup(curproxy->conf.args.file);
3642 curproxy->conf.lfsd_line = curproxy->conf.args.line;
3643
3644 /* get a chance to improve log-format-sd error reporting by
3645 * reporting the correct line-number when possible.
3646 */
3647 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3648 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format-sd' directive is ignored in backends.\n",
3649 file, linenum, curproxy->id);
3650 err_code |= ERR_WARN;
3651 }
3652 }
3653 else if (!strcmp(args[0], "log-tag")) { /* tag to report to syslog */
3654 if (*(args[1]) == 0) {
3655 ha_alert("parsing [%s:%d] : '%s' expects a tag for use in syslog.\n", file, linenum, args[0]);
3656 err_code |= ERR_ALERT | ERR_FATAL;
3657 goto out;
3658 }
3659 chunk_destroy(&curproxy->log_tag);
3660 chunk_initstr(&curproxy->log_tag, strdup(args[1]));
3661 }
3662 else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
3663 if (!parse_logsrv(args, &curproxy->logsrvs, (kwm == KWM_NO), &errmsg)) {
3664 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
3665 err_code |= ERR_ALERT | ERR_FATAL;
3666 goto out;
3667 }
3668 }
3669 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
3670 int cur_arg;
3671 int port1, port2;
3672 struct sockaddr_storage *sk;
3673 struct protocol *proto;
3674
3675 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3676 err_code |= ERR_WARN;
3677
3678 if (!*args[1]) {
3679 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optionally '%s' <addr>, and '%s' <name>.\n",
3680 file, linenum, "source", "usesrc", "interface");
3681 err_code |= ERR_ALERT | ERR_FATAL;
3682 goto out;
3683 }
3684
3685 /* we must first clear any optional default setting */
3686 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3687 free(curproxy->conn_src.iface_name);
3688 curproxy->conn_src.iface_name = NULL;
3689 curproxy->conn_src.iface_len = 0;
3690
3691 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3692 if (!sk) {
3693 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3694 file, linenum, args[0], args[1], errmsg);
3695 err_code |= ERR_ALERT | ERR_FATAL;
3696 goto out;
3697 }
3698
3699 proto = protocol_by_family(sk->ss_family);
3700 if (!proto || !proto->connect) {
3701 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3702 file, linenum, args[0], args[1]);
3703 err_code |= ERR_ALERT | ERR_FATAL;
3704 goto out;
3705 }
3706
3707 if (port1 != port2) {
3708 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3709 file, linenum, args[0], args[1]);
3710 err_code |= ERR_ALERT | ERR_FATAL;
3711 goto out;
3712 }
3713
3714 curproxy->conn_src.source_addr = *sk;
3715 curproxy->conn_src.opts |= CO_SRC_BIND;
3716
3717 cur_arg = 2;
3718 while (*(args[cur_arg])) {
3719 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
3720#if defined(CONFIG_HAP_TRANSPARENT)
3721 if (!*args[cur_arg + 1]) {
3722 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
3723 file, linenum, "usesrc");
3724 err_code |= ERR_ALERT | ERR_FATAL;
3725 goto out;
3726 }
3727
3728 if (!strcmp(args[cur_arg + 1], "client")) {
3729 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3730 curproxy->conn_src.opts |= CO_SRC_TPROXY_CLI;
3731 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
3732 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3733 curproxy->conn_src.opts |= CO_SRC_TPROXY_CIP;
3734 } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
3735 char *name, *end;
3736
3737 name = args[cur_arg+1] + 7;
3738 while (isspace(*name))
3739 name++;
3740
3741 end = name;
3742 while (*end && !isspace(*end) && *end != ',' && *end != ')')
3743 end++;
3744
3745 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3746 curproxy->conn_src.opts |= CO_SRC_TPROXY_DYN;
3747 curproxy->conn_src.bind_hdr_name = calloc(1, end - name + 1);
3748 curproxy->conn_src.bind_hdr_len = end - name;
3749 memcpy(curproxy->conn_src.bind_hdr_name, name, end - name);
3750 curproxy->conn_src.bind_hdr_name[end-name] = '\0';
3751 curproxy->conn_src.bind_hdr_occ = -1;
3752
3753 /* now look for an occurrence number */
3754 while (isspace(*end))
3755 end++;
3756 if (*end == ',') {
3757 end++;
3758 name = end;
3759 if (*end == '-')
3760 end++;
3761 while (isdigit((int)*end))
3762 end++;
3763 curproxy->conn_src.bind_hdr_occ = strl2ic(name, end-name);
3764 }
3765
3766 if (curproxy->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
3767 ha_alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
3768 " occurrences values smaller than %d.\n",
3769 file, linenum, MAX_HDR_HISTORY);
3770 err_code |= ERR_ALERT | ERR_FATAL;
3771 goto out;
3772 }
3773 } else {
3774 struct sockaddr_storage *sk;
3775
3776 sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3777 if (!sk) {
3778 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3779 file, linenum, args[cur_arg], args[cur_arg+1], errmsg);
3780 err_code |= ERR_ALERT | ERR_FATAL;
3781 goto out;
3782 }
3783
3784 proto = protocol_by_family(sk->ss_family);
3785 if (!proto || !proto->connect) {
3786 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3787 file, linenum, args[cur_arg], args[cur_arg+1]);
3788 err_code |= ERR_ALERT | ERR_FATAL;
3789 goto out;
3790 }
3791
3792 if (port1 != port2) {
3793 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3794 file, linenum, args[cur_arg], args[cur_arg + 1]);
3795 err_code |= ERR_ALERT | ERR_FATAL;
3796 goto out;
3797 }
3798 curproxy->conn_src.tproxy_addr = *sk;
3799 curproxy->conn_src.opts |= CO_SRC_TPROXY_ADDR;
3800 }
3801 global.last_checks |= LSTCHK_NETADM;
3802#else /* no TPROXY support */
3803 ha_alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
3804 file, linenum, "usesrc");
3805 err_code |= ERR_ALERT | ERR_FATAL;
3806 goto out;
3807#endif
3808 cur_arg += 2;
3809 continue;
3810 }
3811
3812 if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
3813#ifdef SO_BINDTODEVICE
3814 if (!*args[cur_arg + 1]) {
3815 ha_alert("parsing [%s:%d] : '%s' : missing interface name.\n",
3816 file, linenum, args[0]);
3817 err_code |= ERR_ALERT | ERR_FATAL;
3818 goto out;
3819 }
3820 free(curproxy->conn_src.iface_name);
3821 curproxy->conn_src.iface_name = strdup(args[cur_arg + 1]);
3822 curproxy->conn_src.iface_len = strlen(curproxy->conn_src.iface_name);
3823 global.last_checks |= LSTCHK_NETADM;
3824#else
3825 ha_alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
3826 file, linenum, args[0], args[cur_arg]);
3827 err_code |= ERR_ALERT | ERR_FATAL;
3828 goto out;
3829#endif
3830 cur_arg += 2;
3831 continue;
3832 }
3833 ha_alert("parsing [%s:%d] : '%s' only supports optional keywords '%s' and '%s'.\n",
3834 file, linenum, args[0], "interface", "usesrc");
3835 err_code |= ERR_ALERT | ERR_FATAL;
3836 goto out;
3837 }
3838 }
3839 else if (!strcmp(args[0], "usesrc")) { /* address to use outside: needs "source" first */
3840 ha_alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
3841 file, linenum, "usesrc", "source");
3842 err_code |= ERR_ALERT | ERR_FATAL;
3843 goto out;
3844 }
3845 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02003846 if (!already_warned(WARN_REQREP_DEPRECATED))
Willy Tarreau33810222019-06-12 17:44:02 +02003847 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 +02003848
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003849 if (*(args[2]) == 0) {
3850 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3851 file, linenum, args[0]);
3852 err_code |= ERR_ALERT | ERR_FATAL;
3853 goto out;
3854 }
3855
3856 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3857 SMP_OPT_DIR_REQ, ACT_REPLACE, 0,
3858 args[0], args[1], args[2], (const char **)args+3);
3859 if (err_code & ERR_FATAL)
3860 goto out;
3861 }
3862 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02003863 if (!already_warned(WARN_REQDEL_DEPRECATED))
3864 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]);
3865
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003866 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3867 SMP_OPT_DIR_REQ, ACT_REMOVE, 0,
3868 args[0], args[1], NULL, (const char **)args+2);
3869 if (err_code & ERR_FATAL)
3870 goto out;
3871 }
3872 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02003873 if (!already_warned(WARN_REQDENY_DEPRECATED))
3874 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]);
3875
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003876 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3877 SMP_OPT_DIR_REQ, ACT_DENY, 0,
3878 args[0], args[1], NULL, (const char **)args+2);
3879 if (err_code & ERR_FATAL)
3880 goto out;
3881 }
3882 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
Willy Tarreau96d51952019-05-22 20:34:35 +02003883 if (!already_warned(WARN_REQPASS_DEPRECATED))
3884 ha_warning("parsing [%s:%d] : The '%s' directive is deprecated and will be removed in next version.\n", file, linenum, args[0]);
3885
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003886 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3887 SMP_OPT_DIR_REQ, ACT_PASS, 0,
3888 args[0], args[1], NULL, (const char **)args+2);
3889 if (err_code & ERR_FATAL)
3890 goto out;
3891 }
3892 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02003893 if (!already_warned(WARN_REQALLOW_DEPRECATED))
3894 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]);
3895
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003896 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3897 SMP_OPT_DIR_REQ, ACT_ALLOW, 0,
3898 args[0], args[1], NULL, (const char **)args+2);
3899 if (err_code & ERR_FATAL)
3900 goto out;
3901 }
3902 else if (!strcmp(args[0], "reqtarpit")) { /* tarpit a request if a header matches this regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02003903 if (!already_warned(WARN_REQTARPIT_DEPRECATED))
3904 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]);
3905
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003906 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3907 SMP_OPT_DIR_REQ, ACT_TARPIT, 0,
3908 args[0], args[1], NULL, (const char **)args+2);
3909 if (err_code & ERR_FATAL)
3910 goto out;
3911 }
3912 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02003913 if (!already_warned(WARN_REQREP_DEPRECATED))
3914 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]);
3915
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003916 if (*(args[2]) == 0) {
3917 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3918 file, linenum, args[0]);
3919 err_code |= ERR_ALERT | ERR_FATAL;
3920 goto out;
3921 }
3922
3923 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3924 SMP_OPT_DIR_REQ, ACT_REPLACE, REG_ICASE,
3925 args[0], args[1], args[2], (const char **)args+3);
3926 if (err_code & ERR_FATAL)
3927 goto out;
3928 }
3929 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02003930 if (!already_warned(WARN_REQDEL_DEPRECATED))
3931 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]);
3932
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003933 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3934 SMP_OPT_DIR_REQ, ACT_REMOVE, REG_ICASE,
3935 args[0], args[1], NULL, (const char **)args+2);
3936 if (err_code & ERR_FATAL)
3937 goto out;
3938 }
3939 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02003940 if (!already_warned(WARN_REQDENY_DEPRECATED))
3941 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]);
3942
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003943 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3944 SMP_OPT_DIR_REQ, ACT_DENY, REG_ICASE,
3945 args[0], args[1], NULL, (const char **)args+2);
3946 if (err_code & ERR_FATAL)
3947 goto out;
3948 }
3949 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
Willy Tarreau96d51952019-05-22 20:34:35 +02003950 if (!already_warned(WARN_REQPASS_DEPRECATED))
3951 ha_warning("parsing [%s:%d] : The '%s' directive is deprecated and will be removed in next version.\n", file, linenum, args[0]);
3952
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003953 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3954 SMP_OPT_DIR_REQ, ACT_PASS, REG_ICASE,
3955 args[0], args[1], NULL, (const char **)args+2);
3956 if (err_code & ERR_FATAL)
3957 goto out;
3958 }
3959 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02003960 if (!already_warned(WARN_REQALLOW_DEPRECATED))
3961 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]);
3962
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003963 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3964 SMP_OPT_DIR_REQ, ACT_ALLOW, REG_ICASE,
3965 args[0], args[1], NULL, (const char **)args+2);
3966 if (err_code & ERR_FATAL)
3967 goto out;
3968 }
3969 else if (!strcmp(args[0], "reqitarpit")) { /* tarpit a request if a header matches this regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02003970 if (!already_warned(WARN_REQTARPIT_DEPRECATED))
3971 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]);
3972
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003973 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3974 SMP_OPT_DIR_REQ, ACT_TARPIT, REG_ICASE,
3975 args[0], args[1], NULL, (const char **)args+2);
3976 if (err_code & ERR_FATAL)
3977 goto out;
3978 }
3979 else if (!strcmp(args[0], "reqadd")) { /* add request header */
3980 struct cond_wordlist *wl;
3981
Willy Tarreau96d51952019-05-22 20:34:35 +02003982 if (!already_warned(WARN_REQADD_DEPRECATED))
3983 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]);
3984
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003985 if (curproxy == &defproxy) {
3986 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3987 err_code |= ERR_ALERT | ERR_FATAL;
3988 goto out;
3989 }
3990 else if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
3991 err_code |= ERR_WARN;
3992
3993 if (*(args[1]) == 0) {
3994 ha_alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
3995 err_code |= ERR_ALERT | ERR_FATAL;
3996 goto out;
3997 }
3998
3999 if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
4000 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args+2, &errmsg)) == NULL) {
4001 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
4002 file, linenum, args[0], errmsg);
4003 err_code |= ERR_ALERT | ERR_FATAL;
4004 goto out;
4005 }
4006 err_code |= warnif_cond_conflicts(cond,
4007 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
4008 file, linenum);
4009 }
4010 else if (*args[2]) {
4011 ha_alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
4012 file, linenum, args[0], args[2]);
4013 err_code |= ERR_ALERT | ERR_FATAL;
4014 goto out;
4015 }
4016
4017 wl = calloc(1, sizeof(*wl));
4018 wl->cond = cond;
4019 wl->s = strdup(args[1]);
4020 LIST_ADDQ(&curproxy->req_add, &wl->list);
4021 warnif_misplaced_reqadd(curproxy, file, linenum, args[0]);
4022 }
4023 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004024 if (!already_warned(WARN_RSPREP_DEPRECATED))
4025 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]);
4026
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004027 if (*(args[2]) == 0) {
4028 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4029 file, linenum, args[0]);
4030 err_code |= ERR_ALERT | ERR_FATAL;
4031 goto out;
4032 }
4033
4034 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4035 SMP_OPT_DIR_RES, ACT_REPLACE, 0,
4036 args[0], args[1], args[2], (const char **)args+3);
4037 if (err_code & ERR_FATAL)
4038 goto out;
4039 }
4040 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004041 if (!already_warned(WARN_RSPDEL_DEPRECATED))
4042 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]);
4043
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004044 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4045 SMP_OPT_DIR_RES, ACT_REMOVE, 0,
4046 args[0], args[1], NULL, (const char **)args+2);
4047 if (err_code & ERR_FATAL)
4048 goto out;
4049 }
4050 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004051 if (!already_warned(WARN_RSPDENY_DEPRECATED))
4052 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]);
4053
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004054 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4055 SMP_OPT_DIR_RES, ACT_DENY, 0,
4056 args[0], args[1], NULL, (const char **)args+2);
4057 if (err_code & ERR_FATAL)
4058 goto out;
4059 }
4060 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004061 if (!already_warned(WARN_RSPREP_DEPRECATED))
4062 ha_warning("parsing [%s:%d] : The '%s' directive is deprecated in favor of 'http-response replace-header' and will be removed in next version.\n", file, linenum, args[0]);
4063
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004064 if (*(args[2]) == 0) {
4065 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4066 file, linenum, args[0]);
4067 err_code |= ERR_ALERT | ERR_FATAL;
4068 goto out;
4069 }
4070
4071 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4072 SMP_OPT_DIR_RES, ACT_REPLACE, REG_ICASE,
4073 args[0], args[1], args[2], (const char **)args+3);
4074 if (err_code & ERR_FATAL)
4075 goto out;
4076 }
4077 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004078 if (!already_warned(WARN_RSPDEL_DEPRECATED))
4079 ha_warning("parsing [%s:%d] : The '%s' directive is deprecated in favor of 'http-response del-header' and will be removed in next version.\n", file, linenum, args[0]);
4080
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004081 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4082 SMP_OPT_DIR_RES, ACT_REMOVE, REG_ICASE,
4083 args[0], args[1], NULL, (const char **)args+2);
4084 if (err_code & ERR_FATAL)
4085 goto out;
4086 }
4087 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004088 if (!already_warned(WARN_RSPDENY_DEPRECATED))
4089 ha_warning("parsing [%s:%d] : The '%s' directive is deprecated in favor of 'http-response deny' and will be removed in next version.\n", file, linenum, args[0]);
4090
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004091 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4092 SMP_OPT_DIR_RES, ACT_DENY, REG_ICASE,
4093 args[0], args[1], NULL, (const char **)args+2);
4094 if (err_code & ERR_FATAL)
4095 goto out;
4096 }
4097 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4098 struct cond_wordlist *wl;
4099
Willy Tarreau96d51952019-05-22 20:34:35 +02004100 if (!already_warned(WARN_RSPADD_DEPRECATED))
4101 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]);
4102
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004103 if (curproxy == &defproxy) {
4104 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4105 err_code |= ERR_ALERT | ERR_FATAL;
4106 goto out;
4107 }
4108 else if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4109 err_code |= ERR_WARN;
4110
4111 if (*(args[1]) == 0) {
4112 ha_alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
4113 err_code |= ERR_ALERT | ERR_FATAL;
4114 goto out;
4115 }
4116
4117 if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
4118 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args+2, &errmsg)) == NULL) {
4119 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
4120 file, linenum, args[0], errmsg);
4121 err_code |= ERR_ALERT | ERR_FATAL;
4122 goto out;
4123 }
4124 err_code |= warnif_cond_conflicts(cond,
4125 (curproxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
4126 file, linenum);
4127 }
4128 else if (*args[2]) {
4129 ha_alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
4130 file, linenum, args[0], args[2]);
4131 err_code |= ERR_ALERT | ERR_FATAL;
4132 goto out;
4133 }
4134
4135 wl = calloc(1, sizeof(*wl));
4136 wl->cond = cond;
4137 wl->s = strdup(args[1]);
4138 LIST_ADDQ(&curproxy->rsp_add, &wl->list);
4139 }
4140 else if (!strcmp(args[0], "errorloc") ||
4141 !strcmp(args[0], "errorloc302") ||
4142 !strcmp(args[0], "errorloc303")) { /* error location */
4143 int errnum, errlen;
4144 char *err;
4145
4146 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4147 err_code |= ERR_WARN;
4148
4149 if (*(args[2]) == 0) {
4150 ha_alert("parsing [%s:%d] : <%s> expects <status_code> and <url> as arguments.\n", file, linenum, args[0]);
4151 err_code |= ERR_ALERT | ERR_FATAL;
4152 goto out;
4153 }
4154
4155 errnum = atol(args[1]);
4156 if (!strcmp(args[0], "errorloc303")) {
4157 errlen = strlen(HTTP_303) + strlen(args[2]) + 5;
4158 err = malloc(errlen);
4159 errlen = snprintf(err, errlen, "%s%s\r\n\r\n", HTTP_303, args[2]);
4160 } else {
4161 errlen = strlen(HTTP_302) + strlen(args[2]) + 5;
4162 err = malloc(errlen);
4163 errlen = snprintf(err, errlen, "%s%s\r\n\r\n", HTTP_302, args[2]);
4164 }
4165
4166 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
4167 if (http_err_codes[rc] == errnum) {
4168 chunk_destroy(&curproxy->errmsg[rc]);
4169 chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen);
4170 break;
4171 }
4172 }
4173
4174 if (rc >= HTTP_ERR_SIZE) {
4175 ha_warning("parsing [%s:%d] : status code %d not handled by '%s', error relocation will be ignored.\n",
4176 file, linenum, errnum, args[0]);
4177 free(err);
4178 }
4179 }
4180 else if (!strcmp(args[0], "errorfile")) { /* error message from a file */
4181 int errnum, errlen, fd;
4182 char *err;
4183 struct stat stat;
4184
4185 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4186 err_code |= ERR_WARN;
4187
4188 if (*(args[2]) == 0) {
4189 ha_alert("parsing [%s:%d] : <%s> expects <status_code> and <file> as arguments.\n", file, linenum, args[0]);
4190 err_code |= ERR_ALERT | ERR_FATAL;
4191 goto out;
4192 }
4193
4194 fd = open(args[2], O_RDONLY);
4195 if ((fd < 0) || (fstat(fd, &stat) < 0)) {
4196 ha_alert("parsing [%s:%d] : error opening file <%s> for custom error message <%s>.\n",
4197 file, linenum, args[2], args[1]);
4198 if (fd >= 0)
4199 close(fd);
4200 err_code |= ERR_ALERT | ERR_FATAL;
4201 goto out;
4202 }
4203
4204 if (stat.st_size <= global.tune.bufsize) {
4205 errlen = stat.st_size;
4206 } else {
4207 ha_warning("parsing [%s:%d] : custom error message file <%s> larger than %d bytes. Truncating.\n",
4208 file, linenum, args[2], global.tune.bufsize);
4209 err_code |= ERR_WARN;
4210 errlen = global.tune.bufsize;
4211 }
4212
4213 err = malloc(errlen); /* malloc() must succeed during parsing */
4214 errnum = read(fd, err, errlen);
4215 if (errnum != errlen) {
4216 ha_alert("parsing [%s:%d] : error reading file <%s> for custom error message <%s>.\n",
4217 file, linenum, args[2], args[1]);
4218 close(fd);
4219 free(err);
4220 err_code |= ERR_ALERT | ERR_FATAL;
4221 goto out;
4222 }
4223 close(fd);
4224
4225 errnum = atol(args[1]);
4226 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
4227 if (http_err_codes[rc] == errnum) {
4228 chunk_destroy(&curproxy->errmsg[rc]);
4229 chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen);
4230 break;
4231 }
4232 }
4233
4234 if (rc >= HTTP_ERR_SIZE) {
4235 ha_warning("parsing [%s:%d] : status code %d not handled by '%s', error customization will be ignored.\n",
4236 file, linenum, errnum, args[0]);
4237 err_code |= ERR_WARN;
4238 free(err);
4239 }
4240 }
4241 else {
4242 struct cfg_kw_list *kwl;
4243 int index;
4244
4245 list_for_each_entry(kwl, &cfg_keywords.list, list) {
4246 for (index = 0; kwl->kw[index].kw != NULL; index++) {
4247 if (kwl->kw[index].section != CFG_LISTEN)
4248 continue;
4249 if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
4250 /* prepare error message just in case */
4251 rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, file, linenum, &errmsg);
4252 if (rc < 0) {
4253 ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4254 err_code |= ERR_ALERT | ERR_FATAL;
4255 goto out;
4256 }
4257 else if (rc > 0) {
4258 ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4259 err_code |= ERR_WARN;
4260 goto out;
4261 }
4262 goto out;
4263 }
4264 }
4265 }
4266
4267 ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
4268 err_code |= ERR_ALERT | ERR_FATAL;
4269 goto out;
4270 }
4271 out:
4272 free(errmsg);
4273 return err_code;
4274}