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