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