blob: b3a8c8d3d0429209defb0298bb43467d90841175 [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
Christopher Faulet31930372019-07-15 10:16:58 +02002155 /* "[no] option http-use-htx" is deprecated */
2156 if (!strcmp(cfg_opts2[optnum].name, "http-use-htx")) {
2157 ha_warning("parsing [%s:%d]: option '%s' is deprecated and ignored."
2158 " The HTX mode is now the only supported mode.\n",
2159 file, linenum, cfg_opts2[optnum].name);
2160 err_code |= ERR_WARN;
2161 goto out;
2162 }
2163
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002164 curproxy->no_options2 &= ~cfg_opts2[optnum].val;
2165 curproxy->options2 &= ~cfg_opts2[optnum].val;
2166
2167 switch (kwm) {
2168 case KWM_STD:
2169 curproxy->options2 |= cfg_opts2[optnum].val;
2170 break;
2171 case KWM_NO:
2172 curproxy->no_options2 |= cfg_opts2[optnum].val;
2173 break;
2174 case KWM_DEF: /* already cleared */
2175 break;
2176 }
2177 goto out;
2178 }
2179 }
2180
2181 /* HTTP options override each other. They can be cancelled using
2182 * "no option xxx" which only switches to default mode if the mode
2183 * was this one (useful for cancelling options set in defaults
2184 * sections).
2185 */
2186 if (strcmp(args[1], "httpclose") == 0 || strcmp(args[1], "forceclose") == 0) {
Tim Duesterhus10c6c162019-05-14 20:58:00 +02002187 if (strcmp(args[1], "forceclose") == 0) {
2188 if (!already_warned(WARN_FORCECLOSE_DEPRECATED))
2189 ha_warning("parsing [%s:%d]: keyword '%s' is deprecated in favor of 'httpclose', and will not be supported by future versions.\n",
2190 file, linenum, args[1]);
2191 err_code |= ERR_WARN;
2192 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002193 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2194 goto out;
2195 if (kwm == KWM_STD) {
2196 curproxy->options &= ~PR_O_HTTP_MODE;
2197 curproxy->options |= PR_O_HTTP_CLO;
2198 goto out;
2199 }
2200 else if (kwm == KWM_NO) {
2201 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_CLO)
2202 curproxy->options &= ~PR_O_HTTP_MODE;
2203 goto out;
2204 }
2205 }
2206 else if (strcmp(args[1], "http-server-close") == 0) {
2207 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2208 goto out;
2209 if (kwm == KWM_STD) {
2210 curproxy->options &= ~PR_O_HTTP_MODE;
2211 curproxy->options |= PR_O_HTTP_SCL;
2212 goto out;
2213 }
2214 else if (kwm == KWM_NO) {
2215 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL)
2216 curproxy->options &= ~PR_O_HTTP_MODE;
2217 goto out;
2218 }
2219 }
2220 else if (strcmp(args[1], "http-keep-alive") == 0) {
2221 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2222 goto out;
2223 if (kwm == KWM_STD) {
2224 curproxy->options &= ~PR_O_HTTP_MODE;
2225 curproxy->options |= PR_O_HTTP_KAL;
2226 goto out;
2227 }
2228 else if (kwm == KWM_NO) {
2229 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_KAL)
2230 curproxy->options &= ~PR_O_HTTP_MODE;
2231 goto out;
2232 }
2233 }
2234 else if (strcmp(args[1], "http-tunnel") == 0) {
2235 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[1], NULL)) {
2236 err_code |= ERR_WARN;
2237 goto out;
2238 }
2239 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2240 goto out;
2241 if (kwm == KWM_STD) {
2242 curproxy->options &= ~PR_O_HTTP_MODE;
2243 curproxy->options |= PR_O_HTTP_TUN;
2244 goto out;
2245 }
2246 else if (kwm == KWM_NO) {
2247 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN)
2248 curproxy->options &= ~PR_O_HTTP_MODE;
2249 goto out;
2250 }
2251 }
2252
2253 /* Redispatch can take an integer argument that control when the
2254 * resispatch occurs. All values are relative to the retries option.
2255 * This can be cancelled using "no option xxx".
2256 */
2257 if (strcmp(args[1], "redispatch") == 0) {
2258 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL)) {
2259 err_code |= ERR_WARN;
2260 goto out;
2261 }
2262
2263 curproxy->no_options &= ~PR_O_REDISP;
2264 curproxy->options &= ~PR_O_REDISP;
2265
2266 switch (kwm) {
2267 case KWM_STD:
2268 curproxy->options |= PR_O_REDISP;
2269 curproxy->redispatch_after = -1;
2270 if(*args[2]) {
2271 curproxy->redispatch_after = atol(args[2]);
2272 }
2273 break;
2274 case KWM_NO:
2275 curproxy->no_options |= PR_O_REDISP;
2276 curproxy->redispatch_after = 0;
2277 break;
2278 case KWM_DEF: /* already cleared */
2279 break;
2280 }
2281 goto out;
2282 }
2283
2284 if (kwm != KWM_STD) {
2285 ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
2286 file, linenum, args[1]);
2287 err_code |= ERR_ALERT | ERR_FATAL;
2288 goto out;
2289 }
2290
2291 if (!strcmp(args[1], "httplog")) {
2292 char *logformat;
2293 /* generate a complete HTTP log */
2294 logformat = default_http_log_format;
2295 if (*(args[2]) != '\0') {
2296 if (!strcmp(args[2], "clf")) {
2297 curproxy->options2 |= PR_O2_CLFLOG;
2298 logformat = clf_http_log_format;
2299 } else {
2300 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'clf'.\n", file, linenum, args[1]);
2301 err_code |= ERR_ALERT | ERR_FATAL;
2302 goto out;
2303 }
2304 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
2305 goto out;
2306 }
2307 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2308 char *oldlogformat = "log-format";
2309 char *clflogformat = "";
2310
2311 if (curproxy->conf.logformat_string == default_http_log_format)
2312 oldlogformat = "option httplog";
2313 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2314 oldlogformat = "option tcplog";
2315 else if (curproxy->conf.logformat_string == clf_http_log_format)
2316 oldlogformat = "option httplog clf";
2317 if (logformat == clf_http_log_format)
2318 clflogformat = " clf";
2319 ha_warning("parsing [%s:%d]: 'option httplog%s' overrides previous '%s' in 'defaults' section.\n",
2320 file, linenum, clflogformat, oldlogformat);
2321 }
2322 if (curproxy->conf.logformat_string != default_http_log_format &&
2323 curproxy->conf.logformat_string != default_tcp_log_format &&
2324 curproxy->conf.logformat_string != clf_http_log_format)
2325 free(curproxy->conf.logformat_string);
2326 curproxy->conf.logformat_string = logformat;
2327
2328 free(curproxy->conf.lfs_file);
2329 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2330 curproxy->conf.lfs_line = curproxy->conf.args.line;
2331
2332 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2333 ha_warning("parsing [%s:%d] : backend '%s' : 'option httplog' directive is ignored in backends.\n",
2334 file, linenum, curproxy->id);
2335 err_code |= ERR_WARN;
2336 }
2337 }
2338 else if (!strcmp(args[1], "tcplog")) {
2339 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2340 char *oldlogformat = "log-format";
2341
2342 if (curproxy->conf.logformat_string == default_http_log_format)
2343 oldlogformat = "option httplog";
2344 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2345 oldlogformat = "option tcplog";
2346 else if (curproxy->conf.logformat_string == clf_http_log_format)
2347 oldlogformat = "option httplog clf";
2348 ha_warning("parsing [%s:%d]: 'option tcplog' overrides previous '%s' in 'defaults' section.\n",
2349 file, linenum, oldlogformat);
2350 }
2351 /* generate a detailed TCP log */
2352 if (curproxy->conf.logformat_string != default_http_log_format &&
2353 curproxy->conf.logformat_string != default_tcp_log_format &&
2354 curproxy->conf.logformat_string != clf_http_log_format)
2355 free(curproxy->conf.logformat_string);
2356 curproxy->conf.logformat_string = default_tcp_log_format;
2357
2358 free(curproxy->conf.lfs_file);
2359 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2360 curproxy->conf.lfs_line = curproxy->conf.args.line;
2361
2362 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2363 goto out;
2364
2365 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2366 ha_warning("parsing [%s:%d] : backend '%s' : 'option tcplog' directive is ignored in backends.\n",
2367 file, linenum, curproxy->id);
2368 err_code |= ERR_WARN;
2369 }
2370 }
2371 else if (!strcmp(args[1], "tcpka")) {
2372 /* enable TCP keep-alives on client and server streams */
2373 if (warnifnotcap(curproxy, PR_CAP_BE | PR_CAP_FE, file, linenum, args[1], NULL))
2374 err_code |= ERR_WARN;
2375
2376 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2377 goto out;
2378
2379 if (curproxy->cap & PR_CAP_FE)
2380 curproxy->options |= PR_O_TCP_CLI_KA;
2381 if (curproxy->cap & PR_CAP_BE)
2382 curproxy->options |= PR_O_TCP_SRV_KA;
2383 }
2384 else if (!strcmp(args[1], "httpchk")) {
2385 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2386 err_code |= ERR_WARN;
2387
2388 /* use HTTP request to check servers' health */
2389 free(curproxy->check_req);
2390 curproxy->check_req = NULL;
2391 curproxy->options2 &= ~PR_O2_CHK_ANY;
2392 curproxy->options2 |= PR_O2_HTTP_CHK;
2393 if (!*args[2]) { /* no argument */
2394 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
2395 curproxy->check_len = strlen(DEF_CHECK_REQ);
2396 } else if (!*args[3]) { /* one argument : URI */
2397 int reqlen = strlen(args[2]) + strlen("OPTIONS HTTP/1.0\r\n") + 1;
2398 curproxy->check_req = malloc(reqlen);
2399 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2400 "OPTIONS %s HTTP/1.0\r\n", args[2]); /* URI to use */
2401 } else { /* more arguments : METHOD URI [HTTP_VER] */
2402 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n");
2403 if (*args[4])
2404 reqlen += strlen(args[4]);
2405 else
2406 reqlen += strlen("HTTP/1.0");
2407
2408 curproxy->check_req = malloc(reqlen);
2409 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2410 "%s %s %s\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
2411 }
2412 if (alertif_too_many_args_idx(3, 1, file, linenum, args, &err_code))
2413 goto out;
2414 }
2415 else if (!strcmp(args[1], "ssl-hello-chk")) {
2416 /* use SSLv3 CLIENT HELLO to check servers' health */
2417 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2418 err_code |= ERR_WARN;
2419
2420 free(curproxy->check_req);
2421 curproxy->check_req = NULL;
2422 curproxy->options2 &= ~PR_O2_CHK_ANY;
2423 curproxy->options2 |= PR_O2_SSL3_CHK;
2424
2425 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2426 goto out;
2427 }
2428 else if (!strcmp(args[1], "smtpchk")) {
2429 /* use SMTP request to check servers' health */
2430 free(curproxy->check_req);
2431 curproxy->check_req = NULL;
2432 curproxy->options2 &= ~PR_O2_CHK_ANY;
2433 curproxy->options2 |= PR_O2_SMTP_CHK;
2434
2435 if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */
2436 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2437 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2438 } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */
2439 if (!strcmp(args[2], "EHLO") || !strcmp(args[2], "HELO")) {
2440 int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" \r\n") + 1;
2441 curproxy->check_req = malloc(reqlen);
2442 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2443 "%s %s\r\n", args[2], args[3]); /* HELO hostname */
2444 } else {
2445 /* this just hits the default for now, but you could potentially expand it to allow for other stuff
2446 though, it's unlikely you'd want to send anything other than an EHLO or HELO */
2447 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2448 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2449 }
2450 }
2451 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2452 goto out;
2453 }
2454 else if (!strcmp(args[1], "pgsql-check")) {
2455 /* use PostgreSQL request to check servers' health */
2456 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2457 err_code |= ERR_WARN;
2458
2459 free(curproxy->check_req);
2460 curproxy->check_req = NULL;
2461 curproxy->options2 &= ~PR_O2_CHK_ANY;
2462 curproxy->options2 |= PR_O2_PGSQL_CHK;
2463
2464 if (*(args[2])) {
2465 int cur_arg = 2;
2466
2467 while (*(args[cur_arg])) {
2468 if (strcmp(args[cur_arg], "user") == 0) {
2469 char * packet;
2470 uint32_t packet_len;
2471 uint32_t pv;
2472
2473 /* suboption header - needs additional argument for it */
2474 if (*(args[cur_arg+1]) == 0) {
2475 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2476 file, linenum, args[0], args[1], args[cur_arg]);
2477 err_code |= ERR_ALERT | ERR_FATAL;
2478 goto out;
2479 }
2480
2481 /* uint32_t + uint32_t + strlen("user")+1 + strlen(username)+1 + 1 */
2482 packet_len = 4 + 4 + 5 + strlen(args[cur_arg + 1])+1 +1;
2483 pv = htonl(0x30000); /* protocol version 3.0 */
2484
2485 packet = calloc(1, packet_len);
2486
2487 memcpy(packet + 4, &pv, 4);
2488
2489 /* copy "user" */
2490 memcpy(packet + 8, "user", 4);
2491
2492 /* copy username */
2493 memcpy(packet + 13, args[cur_arg+1], strlen(args[cur_arg+1]));
2494
2495 free(curproxy->check_req);
2496 curproxy->check_req = packet;
2497 curproxy->check_len = packet_len;
2498
2499 packet_len = htonl(packet_len);
2500 memcpy(packet, &packet_len, 4);
2501 cur_arg += 2;
2502 } else {
2503 /* unknown suboption - catchall */
2504 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2505 file, linenum, args[0], args[1]);
2506 err_code |= ERR_ALERT | ERR_FATAL;
2507 goto out;
2508 }
2509 } /* end while loop */
2510 }
2511 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2512 goto out;
2513 }
2514
2515 else if (!strcmp(args[1], "redis-check")) {
2516 /* use REDIS PING request to check servers' health */
2517 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2518 err_code |= ERR_WARN;
2519
2520 free(curproxy->check_req);
2521 curproxy->check_req = NULL;
2522 curproxy->options2 &= ~PR_O2_CHK_ANY;
2523 curproxy->options2 |= PR_O2_REDIS_CHK;
2524
2525 curproxy->check_req = malloc(sizeof(DEF_REDIS_CHECK_REQ) - 1);
2526 memcpy(curproxy->check_req, DEF_REDIS_CHECK_REQ, sizeof(DEF_REDIS_CHECK_REQ) - 1);
2527 curproxy->check_len = sizeof(DEF_REDIS_CHECK_REQ) - 1;
2528
2529 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2530 goto out;
2531 }
2532
2533 else if (!strcmp(args[1], "mysql-check")) {
2534 /* use MYSQL request to check servers' health */
2535 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2536 err_code |= ERR_WARN;
2537
2538 free(curproxy->check_req);
2539 curproxy->check_req = NULL;
2540 curproxy->options2 &= ~PR_O2_CHK_ANY;
2541 curproxy->options2 |= PR_O2_MYSQL_CHK;
2542
2543 /* This is an example of a MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte.
2544 * const char mysql40_client_auth_pkt[] = {
2545 * "\x0e\x00\x00" // packet length
2546 * "\x01" // packet number
2547 * "\x00\x00" // client capabilities
2548 * "\x00\x00\x01" // max packet
2549 * "haproxy\x00" // username (null terminated string)
2550 * "\x00" // filler (always 0x00)
2551 * "\x01\x00\x00" // packet length
2552 * "\x00" // packet number
2553 * "\x01" // COM_QUIT command
2554 * };
2555 */
2556
2557 /* This is an example of a MySQL >=4.1 client Authentication packet provided by Nenad Merdanovic.
2558 * const char mysql41_client_auth_pkt[] = {
2559 * "\x0e\x00\x00\" // packet length
2560 * "\x01" // packet number
2561 * "\x00\x00\x00\x00" // client capabilities
2562 * "\x00\x00\x00\x01" // max packet
2563 * "\x21" // character set (UTF-8)
2564 * char[23] // All zeroes
2565 * "haproxy\x00" // username (null terminated string)
2566 * "\x00" // filler (always 0x00)
2567 * "\x01\x00\x00" // packet length
2568 * "\x00" // packet number
2569 * "\x01" // COM_QUIT command
2570 * };
2571 */
2572
2573
2574 if (*(args[2])) {
2575 int cur_arg = 2;
2576
2577 while (*(args[cur_arg])) {
2578 if (strcmp(args[cur_arg], "user") == 0) {
2579 char *mysqluser;
2580 int packetlen, reqlen, userlen;
2581
2582 /* suboption header - needs additional argument for it */
2583 if (*(args[cur_arg+1]) == 0) {
2584 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2585 file, linenum, args[0], args[1], args[cur_arg]);
2586 err_code |= ERR_ALERT | ERR_FATAL;
2587 goto out;
2588 }
2589 mysqluser = args[cur_arg + 1];
2590 userlen = strlen(mysqluser);
2591
2592 if (*(args[cur_arg+2])) {
2593 if (!strcmp(args[cur_arg+2], "post-41")) {
2594 packetlen = userlen + 7 + 27;
2595 reqlen = packetlen + 9;
2596
2597 free(curproxy->check_req);
2598 curproxy->check_req = calloc(1, reqlen);
2599 curproxy->check_len = reqlen;
2600
2601 snprintf(curproxy->check_req, 4, "%c%c%c",
2602 ((unsigned char) packetlen & 0xff),
2603 ((unsigned char) (packetlen >> 8) & 0xff),
2604 ((unsigned char) (packetlen >> 16) & 0xff));
2605
2606 curproxy->check_req[3] = 1;
2607 curproxy->check_req[5] = 0x82; // 130
2608 curproxy->check_req[11] = 1;
2609 curproxy->check_req[12] = 33;
2610 memcpy(&curproxy->check_req[36], mysqluser, userlen);
2611 curproxy->check_req[36 + userlen + 1 + 1] = 1;
2612 curproxy->check_req[36 + userlen + 1 + 1 + 4] = 1;
2613 cur_arg += 3;
2614 } else {
2615 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'post-41'.\n", file, linenum, args[cur_arg+2]);
2616 err_code |= ERR_ALERT | ERR_FATAL;
2617 goto out;
2618 }
2619 } else {
2620 packetlen = userlen + 7;
2621 reqlen = packetlen + 9;
2622
2623 free(curproxy->check_req);
2624 curproxy->check_req = calloc(1, reqlen);
2625 curproxy->check_len = reqlen;
2626
2627 snprintf(curproxy->check_req, 4, "%c%c%c",
2628 ((unsigned char) packetlen & 0xff),
2629 ((unsigned char) (packetlen >> 8) & 0xff),
2630 ((unsigned char) (packetlen >> 16) & 0xff));
2631
2632 curproxy->check_req[3] = 1;
2633 curproxy->check_req[5] = 0x80;
2634 curproxy->check_req[8] = 1;
2635 memcpy(&curproxy->check_req[9], mysqluser, userlen);
2636 curproxy->check_req[9 + userlen + 1 + 1] = 1;
2637 curproxy->check_req[9 + userlen + 1 + 1 + 4] = 1;
2638 cur_arg += 2;
2639 }
2640 } else {
2641 /* unknown suboption - catchall */
2642 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2643 file, linenum, args[0], args[1]);
2644 err_code |= ERR_ALERT | ERR_FATAL;
2645 goto out;
2646 }
2647 } /* end while loop */
2648 }
2649 }
2650 else if (!strcmp(args[1], "ldap-check")) {
2651 /* use LDAP request to check servers' health */
2652 free(curproxy->check_req);
2653 curproxy->check_req = NULL;
2654 curproxy->options2 &= ~PR_O2_CHK_ANY;
2655 curproxy->options2 |= PR_O2_LDAP_CHK;
2656
2657 curproxy->check_req = malloc(sizeof(DEF_LDAP_CHECK_REQ) - 1);
2658 memcpy(curproxy->check_req, DEF_LDAP_CHECK_REQ, sizeof(DEF_LDAP_CHECK_REQ) - 1);
2659 curproxy->check_len = sizeof(DEF_LDAP_CHECK_REQ) - 1;
2660 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2661 goto out;
2662 }
2663 else if (!strcmp(args[1], "spop-check")) {
2664 if (curproxy == &defproxy) {
2665 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n",
2666 file, linenum, args[0], args[1]);
2667 err_code |= ERR_ALERT | ERR_FATAL;
2668 goto out;
2669 }
2670 if (curproxy->cap & PR_CAP_FE) {
2671 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'frontend' and 'listen' sections.\n",
2672 file, linenum, args[0], args[1]);
2673 err_code |= ERR_ALERT | ERR_FATAL;
2674 goto out;
2675 }
2676
2677 /* use SPOE request to check servers' health */
2678 free(curproxy->check_req);
2679 curproxy->check_req = NULL;
2680 curproxy->options2 &= ~PR_O2_CHK_ANY;
2681 curproxy->options2 |= PR_O2_SPOP_CHK;
2682
2683 if (spoe_prepare_healthcheck_request(&curproxy->check_req, &curproxy->check_len)) {
2684 ha_alert("parsing [%s:%d] : failed to prepare SPOP healthcheck request.\n", file, linenum);
2685 err_code |= ERR_ALERT | ERR_FATAL;
2686 goto out;
2687 }
2688 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2689 goto out;
2690 }
2691 else if (!strcmp(args[1], "tcp-check")) {
2692 /* use raw TCPCHK send/expect to check servers' health */
2693 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2694 err_code |= ERR_WARN;
2695
2696 free(curproxy->check_req);
2697 curproxy->check_req = NULL;
2698 curproxy->options2 &= ~PR_O2_CHK_ANY;
2699 curproxy->options2 |= PR_O2_TCPCHK_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], "external-check")) {
2704 /* excute an external command to check servers' health */
2705 free(curproxy->check_req);
2706 curproxy->check_req = NULL;
2707 curproxy->options2 &= ~PR_O2_CHK_ANY;
2708 curproxy->options2 |= PR_O2_EXT_CHK;
2709 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2710 goto out;
2711 }
2712 else if (!strcmp(args[1], "forwardfor")) {
2713 int cur_arg;
2714
2715 /* insert x-forwarded-for field, but not for the IP address listed as an except.
Christopher Faulet31930372019-07-15 10:16:58 +02002716 * set default options (ie: bitfield, header name, etc)
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002717 */
2718
2719 curproxy->options |= PR_O_FWDFOR | PR_O_FF_ALWAYS;
2720
2721 free(curproxy->fwdfor_hdr_name);
2722 curproxy->fwdfor_hdr_name = strdup(DEF_XFORWARDFOR_HDR);
2723 curproxy->fwdfor_hdr_len = strlen(DEF_XFORWARDFOR_HDR);
2724
2725 /* loop to go through arguments - start at 2, since 0+1 = "option" "forwardfor" */
2726 cur_arg = 2;
2727 while (*(args[cur_arg])) {
2728 if (!strcmp(args[cur_arg], "except")) {
2729 /* suboption except - needs additional argument for it */
2730 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_net, &curproxy->except_mask)) {
2731 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2732 file, linenum, args[0], args[1], args[cur_arg]);
2733 err_code |= ERR_ALERT | ERR_FATAL;
2734 goto out;
2735 }
2736 /* flush useless bits */
2737 curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
2738 cur_arg += 2;
2739 } else if (!strcmp(args[cur_arg], "header")) {
2740 /* suboption header - needs additional argument for it */
2741 if (*(args[cur_arg+1]) == 0) {
2742 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2743 file, linenum, args[0], args[1], args[cur_arg]);
2744 err_code |= ERR_ALERT | ERR_FATAL;
2745 goto out;
2746 }
2747 free(curproxy->fwdfor_hdr_name);
2748 curproxy->fwdfor_hdr_name = strdup(args[cur_arg+1]);
2749 curproxy->fwdfor_hdr_len = strlen(curproxy->fwdfor_hdr_name);
2750 cur_arg += 2;
2751 } else if (!strcmp(args[cur_arg], "if-none")) {
2752 curproxy->options &= ~PR_O_FF_ALWAYS;
2753 cur_arg += 1;
2754 } else {
2755 /* unknown suboption - catchall */
2756 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except', 'header' and 'if-none'.\n",
2757 file, linenum, args[0], args[1]);
2758 err_code |= ERR_ALERT | ERR_FATAL;
2759 goto out;
2760 }
2761 } /* end while loop */
2762 }
2763 else if (!strcmp(args[1], "originalto")) {
2764 int cur_arg;
2765
2766 /* insert x-original-to field, but not for the IP address listed as an except.
2767 * set default options (ie: bitfield, header name, etc)
2768 */
2769
2770 curproxy->options |= PR_O_ORGTO;
2771
2772 free(curproxy->orgto_hdr_name);
2773 curproxy->orgto_hdr_name = strdup(DEF_XORIGINALTO_HDR);
2774 curproxy->orgto_hdr_len = strlen(DEF_XORIGINALTO_HDR);
2775
2776 /* loop to go through arguments - start at 2, since 0+1 = "option" "originalto" */
2777 cur_arg = 2;
2778 while (*(args[cur_arg])) {
2779 if (!strcmp(args[cur_arg], "except")) {
2780 /* suboption except - needs additional argument for it */
2781 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_to, &curproxy->except_mask_to)) {
2782 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2783 file, linenum, args[0], args[1], args[cur_arg]);
2784 err_code |= ERR_ALERT | ERR_FATAL;
2785 goto out;
2786 }
2787 /* flush useless bits */
2788 curproxy->except_to.s_addr &= curproxy->except_mask_to.s_addr;
2789 cur_arg += 2;
2790 } else if (!strcmp(args[cur_arg], "header")) {
2791 /* suboption header - needs additional argument for it */
2792 if (*(args[cur_arg+1]) == 0) {
2793 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2794 file, linenum, args[0], args[1], args[cur_arg]);
2795 err_code |= ERR_ALERT | ERR_FATAL;
2796 goto out;
2797 }
2798 free(curproxy->orgto_hdr_name);
2799 curproxy->orgto_hdr_name = strdup(args[cur_arg+1]);
2800 curproxy->orgto_hdr_len = strlen(curproxy->orgto_hdr_name);
2801 cur_arg += 2;
2802 } else {
2803 /* unknown suboption - catchall */
2804 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
2805 file, linenum, args[0], args[1]);
2806 err_code |= ERR_ALERT | ERR_FATAL;
2807 goto out;
2808 }
2809 } /* end while loop */
2810 }
2811 else {
2812 ha_alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
2813 err_code |= ERR_ALERT | ERR_FATAL;
2814 goto out;
2815 }
2816 goto out;
2817 }
2818 else if (!strcmp(args[0], "default_backend")) {
2819 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
2820 err_code |= ERR_WARN;
2821
2822 if (*(args[1]) == 0) {
2823 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
2824 err_code |= ERR_ALERT | ERR_FATAL;
2825 goto out;
2826 }
2827 free(curproxy->defbe.name);
2828 curproxy->defbe.name = strdup(args[1]);
2829
2830 if (alertif_too_many_args_idx(1, 0, file, linenum, args, &err_code))
2831 goto out;
2832 }
2833 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
Tim Duesterhusdac168b2019-05-14 20:57:58 +02002834 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 +01002835
Tim Duesterhusdac168b2019-05-14 20:57:58 +02002836 err_code |= ERR_ALERT | ERR_FATAL;
2837 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002838 }
2839 else if (!strcmp(args[0], "http-reuse")) {
2840 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2841 err_code |= ERR_WARN;
2842
2843 if (strcmp(args[1], "never") == 0) {
2844 /* enable a graceful server shutdown on an HTTP 404 response */
2845 curproxy->options &= ~PR_O_REUSE_MASK;
2846 curproxy->options |= PR_O_REUSE_NEVR;
2847 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2848 goto out;
2849 }
2850 else if (strcmp(args[1], "safe") == 0) {
2851 /* enable a graceful server shutdown on an HTTP 404 response */
2852 curproxy->options &= ~PR_O_REUSE_MASK;
2853 curproxy->options |= PR_O_REUSE_SAFE;
2854 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2855 goto out;
2856 }
2857 else if (strcmp(args[1], "aggressive") == 0) {
2858 curproxy->options &= ~PR_O_REUSE_MASK;
2859 curproxy->options |= PR_O_REUSE_AGGR;
2860 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2861 goto out;
2862 }
2863 else if (strcmp(args[1], "always") == 0) {
2864 /* enable a graceful server shutdown on an HTTP 404 response */
2865 curproxy->options &= ~PR_O_REUSE_MASK;
2866 curproxy->options |= PR_O_REUSE_ALWS;
2867 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2868 goto out;
2869 }
2870 else {
2871 ha_alert("parsing [%s:%d] : '%s' only supports 'never', 'safe', 'aggressive', 'always'.\n", file, linenum, args[0]);
2872 err_code |= ERR_ALERT | ERR_FATAL;
2873 goto out;
2874 }
2875 }
2876 else if (!strcmp(args[0], "http-check")) {
2877 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2878 err_code |= ERR_WARN;
2879
2880 if (strcmp(args[1], "disable-on-404") == 0) {
2881 /* enable a graceful server shutdown on an HTTP 404 response */
2882 curproxy->options |= PR_O_DISABLE404;
2883 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2884 goto out;
2885 }
2886 else if (strcmp(args[1], "send-state") == 0) {
2887 /* enable emission of the apparent state of a server in HTTP checks */
2888 curproxy->options2 |= PR_O2_CHK_SNDST;
2889 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2890 goto out;
2891 }
2892 else if (strcmp(args[1], "expect") == 0) {
2893 const char *ptr_arg;
2894 int cur_arg;
2895
2896 if (curproxy->options2 & PR_O2_EXP_TYPE) {
2897 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
2898 err_code |= ERR_ALERT | ERR_FATAL;
2899 goto out;
2900 }
2901
2902 cur_arg = 2;
2903 /* consider exclamation marks, sole or at the beginning of a word */
2904 while (*(ptr_arg = args[cur_arg])) {
2905 while (*ptr_arg == '!') {
2906 curproxy->options2 ^= PR_O2_EXP_INV;
2907 ptr_arg++;
2908 }
2909 if (*ptr_arg)
2910 break;
2911 cur_arg++;
2912 }
2913 /* now ptr_arg points to the beginning of a word past any possible
2914 * exclamation mark, and cur_arg is the argument which holds this word.
2915 */
2916 if (strcmp(ptr_arg, "status") == 0) {
2917 if (!*(args[cur_arg + 1])) {
2918 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
2919 file, linenum, args[0], args[1], ptr_arg);
2920 err_code |= ERR_ALERT | ERR_FATAL;
2921 goto out;
2922 }
2923 curproxy->options2 |= PR_O2_EXP_STS;
2924 free(curproxy->expect_str);
2925 curproxy->expect_str = strdup(args[cur_arg + 1]);
2926 }
2927 else if (strcmp(ptr_arg, "string") == 0) {
2928 if (!*(args[cur_arg + 1])) {
2929 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
2930 file, linenum, args[0], args[1], ptr_arg);
2931 err_code |= ERR_ALERT | ERR_FATAL;
2932 goto out;
2933 }
2934 curproxy->options2 |= PR_O2_EXP_STR;
2935 free(curproxy->expect_str);
2936 curproxy->expect_str = strdup(args[cur_arg + 1]);
2937 }
2938 else if (strcmp(ptr_arg, "rstatus") == 0) {
2939 if (!*(args[cur_arg + 1])) {
2940 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
2941 file, linenum, args[0], args[1], ptr_arg);
2942 err_code |= ERR_ALERT | ERR_FATAL;
2943 goto out;
2944 }
2945 curproxy->options2 |= PR_O2_EXP_RSTS;
2946 free(curproxy->expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +02002947 regex_free(curproxy->expect_regex);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002948 curproxy->expect_str = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002949 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02002950 if (!(curproxy->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
2951 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002952 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
2953 free(error);
2954 err_code |= ERR_ALERT | ERR_FATAL;
2955 goto out;
2956 }
2957 }
2958 else if (strcmp(ptr_arg, "rstring") == 0) {
2959 if (!*(args[cur_arg + 1])) {
2960 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
2961 file, linenum, args[0], args[1], ptr_arg);
2962 err_code |= ERR_ALERT | ERR_FATAL;
2963 goto out;
2964 }
2965 curproxy->options2 |= PR_O2_EXP_RSTR;
2966 free(curproxy->expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +02002967 regex_free(curproxy->expect_regex);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002968 curproxy->expect_str = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002969 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02002970 if (!(curproxy->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
2971 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002972 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
2973 free(error);
2974 err_code |= ERR_ALERT | ERR_FATAL;
2975 goto out;
2976 }
2977 }
2978 else {
2979 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'status', 'string', 'rstatus', 'rstring', found '%s'.\n",
2980 file, linenum, args[0], args[1], ptr_arg);
2981 err_code |= ERR_ALERT | ERR_FATAL;
2982 goto out;
2983 }
2984 }
2985 else {
2986 ha_alert("parsing [%s:%d] : '%s' only supports 'disable-on-404', 'send-state', 'expect'.\n", file, linenum, args[0]);
2987 err_code |= ERR_ALERT | ERR_FATAL;
2988 goto out;
2989 }
2990 }
2991 else if (!strcmp(args[0], "tcp-check")) {
2992 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2993 err_code |= ERR_WARN;
2994
2995 if (strcmp(args[1], "comment") == 0) {
2996 int cur_arg;
2997 struct tcpcheck_rule *tcpcheck;
2998
2999 cur_arg = 1;
3000 tcpcheck = calloc(1, sizeof(*tcpcheck));
3001 tcpcheck->action = TCPCHK_ACT_COMMENT;
3002
3003 if (!*args[cur_arg + 1]) {
3004 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3005 file, linenum, args[cur_arg]);
3006 err_code |= ERR_ALERT | ERR_FATAL;
3007 goto out;
3008 }
3009
3010 tcpcheck->comment = strdup(args[cur_arg + 1]);
3011
3012 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3013 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
3014 goto out;
3015 }
3016 else if (strcmp(args[1], "connect") == 0) {
3017 const char *ptr_arg;
3018 int cur_arg;
3019 struct tcpcheck_rule *tcpcheck;
3020
3021 /* check if first rule is also a 'connect' action */
3022 tcpcheck = LIST_NEXT(&curproxy->tcpcheck_rules, struct tcpcheck_rule *, list);
3023 while (&tcpcheck->list != &curproxy->tcpcheck_rules &&
3024 tcpcheck->action == TCPCHK_ACT_COMMENT) {
3025 tcpcheck = LIST_NEXT(&tcpcheck->list, struct tcpcheck_rule *, list);
3026 }
3027
3028 if (&tcpcheck->list != &curproxy->tcpcheck_rules
3029 && tcpcheck->action != TCPCHK_ACT_CONNECT) {
3030 ha_alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
3031 file, linenum);
3032 err_code |= ERR_ALERT | ERR_FATAL;
3033 goto out;
3034 }
3035
3036 cur_arg = 2;
3037 tcpcheck = calloc(1, sizeof(*tcpcheck));
3038 tcpcheck->action = TCPCHK_ACT_CONNECT;
3039
3040 /* parsing each parameters to fill up the rule */
3041 while (*(ptr_arg = args[cur_arg])) {
3042 /* tcp port */
3043 if (strcmp(args[cur_arg], "port") == 0) {
3044 if ( (atol(args[cur_arg + 1]) > 65535) ||
3045 (atol(args[cur_arg + 1]) < 1) ){
3046 ha_alert("parsing [%s:%d] : '%s %s %s' expects a valid TCP port (from range 1 to 65535), got %s.\n",
3047 file, linenum, args[0], args[1], "port", args[cur_arg + 1]);
3048 err_code |= ERR_ALERT | ERR_FATAL;
3049 goto out;
3050 }
3051 tcpcheck->port = atol(args[cur_arg + 1]);
3052 cur_arg += 2;
3053 }
3054 /* send proxy protocol */
3055 else if (strcmp(args[cur_arg], "send-proxy") == 0) {
3056 tcpcheck->conn_opts |= TCPCHK_OPT_SEND_PROXY;
3057 cur_arg++;
3058 }
3059#ifdef USE_OPENSSL
3060 else if (strcmp(args[cur_arg], "ssl") == 0) {
3061 curproxy->options |= PR_O_TCPCHK_SSL;
3062 tcpcheck->conn_opts |= TCPCHK_OPT_SSL;
3063 cur_arg++;
3064 }
3065#endif /* USE_OPENSSL */
3066 /* comment for this tcpcheck line */
3067 else if (strcmp(args[cur_arg], "comment") == 0) {
3068 if (!*args[cur_arg + 1]) {
3069 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3070 file, linenum, args[cur_arg]);
3071 err_code |= ERR_ALERT | ERR_FATAL;
3072 goto out;
3073 }
3074 tcpcheck->comment = strdup(args[cur_arg + 1]);
3075 cur_arg += 2;
3076 }
3077 else {
3078#ifdef USE_OPENSSL
3079 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n",
3080#else /* USE_OPENSSL */
3081 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or but got '%s' as argument.\n",
3082#endif /* USE_OPENSSL */
3083 file, linenum, args[0], args[1], args[cur_arg]);
3084 err_code |= ERR_ALERT | ERR_FATAL;
3085 goto out;
3086 }
3087
3088 }
3089
3090 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3091 }
3092 else if (strcmp(args[1], "send") == 0) {
3093 if (! *(args[2]) ) {
3094 /* SEND string expected */
3095 ha_alert("parsing [%s:%d] : '%s %s %s' expects <STRING> as argument.\n",
3096 file, linenum, args[0], args[1], args[2]);
3097 err_code |= ERR_ALERT | ERR_FATAL;
3098 goto out;
3099 } else {
3100 struct tcpcheck_rule *tcpcheck;
3101
3102 tcpcheck = calloc(1, sizeof(*tcpcheck));
3103
3104 tcpcheck->action = TCPCHK_ACT_SEND;
3105 tcpcheck->string_len = strlen(args[2]);
3106 tcpcheck->string = strdup(args[2]);
3107 tcpcheck->expect_regex = NULL;
3108
3109 /* comment for this tcpcheck line */
3110 if (strcmp(args[3], "comment") == 0) {
3111 if (!*args[4]) {
3112 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3113 file, linenum, args[3]);
3114 err_code |= ERR_ALERT | ERR_FATAL;
3115 goto out;
3116 }
3117 tcpcheck->comment = strdup(args[4]);
3118 }
3119
3120 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3121 }
3122 }
3123 else if (strcmp(args[1], "send-binary") == 0) {
3124 if (! *(args[2]) ) {
3125 /* SEND binary string expected */
3126 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument.\n",
3127 file, linenum, args[0], args[1], args[2]);
3128 err_code |= ERR_ALERT | ERR_FATAL;
3129 goto out;
3130 } else {
3131 struct tcpcheck_rule *tcpcheck;
3132 char *err = NULL;
3133
3134 tcpcheck = calloc(1, sizeof(*tcpcheck));
3135
3136 tcpcheck->action = TCPCHK_ACT_SEND;
3137 if (parse_binary(args[2], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3138 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3139 file, linenum, args[0], args[1], args[2], err);
3140 err_code |= ERR_ALERT | ERR_FATAL;
3141 goto out;
3142 }
3143 tcpcheck->expect_regex = NULL;
3144
3145 /* comment for this tcpcheck line */
3146 if (strcmp(args[3], "comment") == 0) {
3147 if (!*args[4]) {
3148 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3149 file, linenum, args[3]);
3150 err_code |= ERR_ALERT | ERR_FATAL;
3151 goto out;
3152 }
3153 tcpcheck->comment = strdup(args[4]);
3154 }
3155
3156 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3157 }
3158 }
3159 else if (strcmp(args[1], "expect") == 0) {
3160 const char *ptr_arg;
3161 int cur_arg;
3162 int inverse = 0;
3163
3164 if (curproxy->options2 & PR_O2_EXP_TYPE) {
3165 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
3166 err_code |= ERR_ALERT | ERR_FATAL;
3167 goto out;
3168 }
3169
3170 cur_arg = 2;
3171 /* consider exclamation marks, sole or at the beginning of a word */
3172 while (*(ptr_arg = args[cur_arg])) {
3173 while (*ptr_arg == '!') {
3174 inverse = !inverse;
3175 ptr_arg++;
3176 }
3177 if (*ptr_arg)
3178 break;
3179 cur_arg++;
3180 }
3181 /* now ptr_arg points to the beginning of a word past any possible
3182 * exclamation mark, and cur_arg is the argument which holds this word.
3183 */
3184 if (strcmp(ptr_arg, "binary") == 0) {
3185 struct tcpcheck_rule *tcpcheck;
3186 char *err = NULL;
3187
3188 if (!*(args[cur_arg + 1])) {
3189 ha_alert("parsing [%s:%d] : '%s %s %s' expects <binary string> as an argument.\n",
3190 file, linenum, args[0], args[1], ptr_arg);
3191 err_code |= ERR_ALERT | ERR_FATAL;
3192 goto out;
3193 }
3194
3195 tcpcheck = calloc(1, sizeof(*tcpcheck));
3196
3197 tcpcheck->action = TCPCHK_ACT_EXPECT;
3198 if (parse_binary(args[cur_arg + 1], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3199 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3200 file, linenum, args[0], args[1], args[2], err);
3201 err_code |= ERR_ALERT | ERR_FATAL;
3202 goto out;
3203 }
3204 tcpcheck->expect_regex = NULL;
3205 tcpcheck->inverse = inverse;
3206
3207 /* tcpcheck comment */
3208 cur_arg += 2;
3209 if (strcmp(args[cur_arg], "comment") == 0) {
3210 if (!*args[cur_arg + 1]) {
3211 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3212 file, linenum, args[cur_arg + 1]);
3213 err_code |= ERR_ALERT | ERR_FATAL;
3214 goto out;
3215 }
3216 tcpcheck->comment = strdup(args[cur_arg + 1]);
3217 }
3218
3219 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3220 }
3221 else if (strcmp(ptr_arg, "string") == 0) {
3222 struct tcpcheck_rule *tcpcheck;
3223
3224 if (!*(args[cur_arg + 1])) {
3225 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3226 file, linenum, args[0], args[1], ptr_arg);
3227 err_code |= ERR_ALERT | ERR_FATAL;
3228 goto out;
3229 }
3230
3231 tcpcheck = calloc(1, sizeof(*tcpcheck));
3232
3233 tcpcheck->action = TCPCHK_ACT_EXPECT;
3234 tcpcheck->string_len = strlen(args[cur_arg + 1]);
3235 tcpcheck->string = strdup(args[cur_arg + 1]);
3236 tcpcheck->expect_regex = NULL;
3237 tcpcheck->inverse = inverse;
3238
3239 /* tcpcheck comment */
3240 cur_arg += 2;
3241 if (strcmp(args[cur_arg], "comment") == 0) {
3242 if (!*args[cur_arg + 1]) {
3243 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3244 file, linenum, args[cur_arg + 1]);
3245 err_code |= ERR_ALERT | ERR_FATAL;
3246 goto out;
3247 }
3248 tcpcheck->comment = strdup(args[cur_arg + 1]);
3249 }
3250
3251 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3252 }
3253 else if (strcmp(ptr_arg, "rstring") == 0) {
3254 struct tcpcheck_rule *tcpcheck;
3255
3256 if (!*(args[cur_arg + 1])) {
3257 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3258 file, linenum, args[0], args[1], ptr_arg);
3259 err_code |= ERR_ALERT | ERR_FATAL;
3260 goto out;
3261 }
3262
3263 tcpcheck = calloc(1, sizeof(*tcpcheck));
3264
3265 tcpcheck->action = TCPCHK_ACT_EXPECT;
3266 tcpcheck->string_len = 0;
3267 tcpcheck->string = NULL;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003268 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02003269 if (!(tcpcheck->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
3270 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003271 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3272 free(error);
3273 err_code |= ERR_ALERT | ERR_FATAL;
3274 goto out;
3275 }
3276 tcpcheck->inverse = inverse;
3277
3278 /* tcpcheck comment */
3279 cur_arg += 2;
3280 if (strcmp(args[cur_arg], "comment") == 0) {
3281 if (!*args[cur_arg + 1]) {
3282 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3283 file, linenum, args[cur_arg + 1]);
3284 err_code |= ERR_ALERT | ERR_FATAL;
3285 goto out;
3286 }
3287 tcpcheck->comment = strdup(args[cur_arg + 1]);
3288 }
3289
3290 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3291 }
3292 else {
3293 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'binary', 'string', 'rstring', found '%s'.\n",
3294 file, linenum, args[0], args[1], ptr_arg);
3295 err_code |= ERR_ALERT | ERR_FATAL;
3296 goto out;
3297 }
3298 }
3299 else {
3300 ha_alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
3301 err_code |= ERR_ALERT | ERR_FATAL;
3302 goto out;
3303 }
3304 }
3305 else if (!strcmp(args[0], "monitor")) {
3306 if (curproxy == &defproxy) {
3307 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3308 err_code |= ERR_ALERT | ERR_FATAL;
3309 goto out;
3310 }
3311
3312 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3313 err_code |= ERR_WARN;
3314
3315 if (strcmp(args[1], "fail") == 0) {
3316 /* add a condition to fail monitor requests */
3317 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
3318 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
3319 file, linenum, args[0], args[1]);
3320 err_code |= ERR_ALERT | ERR_FATAL;
3321 goto out;
3322 }
3323
3324 err_code |= warnif_misplaced_monitor(curproxy, file, linenum, "monitor fail");
3325 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
3326 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
3327 file, linenum, args[0], args[1], errmsg);
3328 err_code |= ERR_ALERT | ERR_FATAL;
3329 goto out;
3330 }
3331 LIST_ADDQ(&curproxy->mon_fail_cond, &cond->list);
3332 }
3333 else {
3334 ha_alert("parsing [%s:%d] : '%s' only supports 'fail'.\n", file, linenum, args[0]);
3335 err_code |= ERR_ALERT | ERR_FATAL;
3336 goto out;
3337 }
3338 }
Willy Tarreaue5733232019-05-22 19:24:06 +02003339#ifdef USE_TPROXY
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003340 else if (!strcmp(args[0], "transparent")) {
3341 /* enable transparent proxy connections */
3342 curproxy->options |= PR_O_TRANSP;
3343 if (alertif_too_many_args(0, file, linenum, args, &err_code))
3344 goto out;
3345 }
3346#endif
3347 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3348 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
3349 err_code |= ERR_WARN;
3350
3351 if (*(args[1]) == 0) {
3352 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3353 err_code |= ERR_ALERT | ERR_FATAL;
3354 goto out;
3355 }
3356 curproxy->maxconn = atol(args[1]);
3357 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3358 goto out;
3359 }
3360 else if (!strcmp(args[0], "backlog")) { /* backlog */
3361 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3362 err_code |= ERR_WARN;
3363
3364 if (*(args[1]) == 0) {
3365 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3366 err_code |= ERR_ALERT | ERR_FATAL;
3367 goto out;
3368 }
3369 curproxy->backlog = atol(args[1]);
3370 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3371 goto out;
3372 }
3373 else if (!strcmp(args[0], "fullconn")) { /* fullconn */
3374 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
3375 err_code |= ERR_WARN;
3376
3377 if (*(args[1]) == 0) {
3378 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3379 err_code |= ERR_ALERT | ERR_FATAL;
3380 goto out;
3381 }
3382 curproxy->fullconn = atol(args[1]);
3383 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3384 goto out;
3385 }
3386 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3387 if (*(args[1]) == 0) {
3388 ha_alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
3389 err_code |= ERR_ALERT | ERR_FATAL;
3390 goto out;
3391 }
3392 err = parse_time_err(args[1], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +02003393 if (err == PARSE_TIME_OVER) {
3394 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to grace time, maximum value is 2147483647 ms (~24.8 days).\n",
3395 file, linenum, args[1]);
3396 err_code |= ERR_ALERT | ERR_FATAL;
3397 goto out;
3398 }
3399 else if (err == PARSE_TIME_UNDER) {
3400 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to grace time, minimum non-null value is 1 ms.\n",
3401 file, linenum, args[1]);
3402 err_code |= ERR_ALERT | ERR_FATAL;
3403 goto out;
3404 }
3405 else if (err) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003406 ha_alert("parsing [%s:%d] : unexpected character '%c' in grace time.\n",
3407 file, linenum, *err);
3408 err_code |= ERR_ALERT | ERR_FATAL;
3409 goto out;
3410 }
3411 curproxy->grace = val;
3412 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3413 goto out;
3414 }
3415 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3416 struct sockaddr_storage *sk;
3417 int port1, port2;
3418 struct protocol *proto;
3419
3420 if (curproxy == &defproxy) {
3421 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3422 err_code |= ERR_ALERT | ERR_FATAL;
3423 goto out;
3424 }
3425 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3426 err_code |= ERR_WARN;
3427
3428 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3429 if (!sk) {
3430 ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
3431 err_code |= ERR_ALERT | ERR_FATAL;
3432 goto out;
3433 }
3434
3435 proto = protocol_by_family(sk->ss_family);
3436 if (!proto || !proto->connect) {
3437 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3438 file, linenum, args[0], args[1]);
3439 err_code |= ERR_ALERT | ERR_FATAL;
3440 goto out;
3441 }
3442
3443 if (port1 != port2) {
3444 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'.\n",
3445 file, linenum, args[0], args[1]);
3446 err_code |= ERR_ALERT | ERR_FATAL;
3447 goto out;
3448 }
3449
3450 if (!port1) {
3451 ha_alert("parsing [%s:%d] : '%s' : missing port number in '%s', <addr:port> expected.\n",
3452 file, linenum, args[0], args[1]);
3453 err_code |= ERR_ALERT | ERR_FATAL;
3454 goto out;
3455 }
3456
3457 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3458 goto out;
3459
3460 curproxy->dispatch_addr = *sk;
3461 curproxy->options |= PR_O_DISPATCH;
3462 }
3463 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
3464 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3465 err_code |= ERR_WARN;
3466
3467 if (backend_parse_balance((const char **)args + 1, &errmsg, curproxy) < 0) {
3468 ha_alert("parsing [%s:%d] : %s %s\n", file, linenum, args[0], errmsg);
3469 err_code |= ERR_ALERT | ERR_FATAL;
3470 goto out;
3471 }
3472 }
3473 else if (!strcmp(args[0], "hash-type")) { /* set hashing method */
3474 /**
3475 * The syntax for hash-type config element is
3476 * hash-type {map-based|consistent} [[<algo>] avalanche]
3477 *
3478 * The default hash function is sdbm for map-based and sdbm+avalanche for consistent.
3479 */
3480 curproxy->lbprm.algo &= ~(BE_LB_HASH_TYPE | BE_LB_HASH_FUNC | BE_LB_HASH_MOD);
3481
3482 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3483 err_code |= ERR_WARN;
3484
3485 if (strcmp(args[1], "consistent") == 0) { /* use consistent hashing */
3486 curproxy->lbprm.algo |= BE_LB_HASH_CONS;
3487 }
3488 else if (strcmp(args[1], "map-based") == 0) { /* use map-based hashing */
3489 curproxy->lbprm.algo |= BE_LB_HASH_MAP;
3490 }
3491 else if (strcmp(args[1], "avalanche") == 0) {
3492 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]);
3493 err_code |= ERR_ALERT | ERR_FATAL;
3494 goto out;
3495 }
3496 else {
3497 ha_alert("parsing [%s:%d] : '%s' only supports 'consistent' and 'map-based'.\n", file, linenum, args[0]);
3498 err_code |= ERR_ALERT | ERR_FATAL;
3499 goto out;
3500 }
3501
3502 /* set the hash function to use */
3503 if (!*args[2]) {
3504 /* the default algo is sdbm */
3505 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3506
3507 /* if consistent with no argument, then avalanche modifier is also applied */
3508 if ((curproxy->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS)
3509 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3510 } else {
3511 /* set the hash function */
3512 if (!strcmp(args[2], "sdbm")) {
3513 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3514 }
3515 else if (!strcmp(args[2], "djb2")) {
3516 curproxy->lbprm.algo |= BE_LB_HFCN_DJB2;
3517 }
3518 else if (!strcmp(args[2], "wt6")) {
3519 curproxy->lbprm.algo |= BE_LB_HFCN_WT6;
3520 }
3521 else if (!strcmp(args[2], "crc32")) {
3522 curproxy->lbprm.algo |= BE_LB_HFCN_CRC32;
3523 }
3524 else {
3525 ha_alert("parsing [%s:%d] : '%s' only supports 'sdbm', 'djb2', 'crc32', or 'wt6' hash functions.\n", file, linenum, args[0]);
3526 err_code |= ERR_ALERT | ERR_FATAL;
3527 goto out;
3528 }
3529
3530 /* set the hash modifier */
3531 if (!strcmp(args[3], "avalanche")) {
3532 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3533 }
3534 else if (*args[3]) {
3535 ha_alert("parsing [%s:%d] : '%s' only supports 'avalanche' as a modifier for hash functions.\n", file, linenum, args[0]);
3536 err_code |= ERR_ALERT | ERR_FATAL;
3537 goto out;
3538 }
3539 }
3540 }
3541 else if (strcmp(args[0], "hash-balance-factor") == 0) {
3542 if (*(args[1]) == 0) {
3543 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3544 err_code |= ERR_ALERT | ERR_FATAL;
3545 goto out;
3546 }
Willy Tarreau76e84f52019-01-14 16:50:58 +01003547 curproxy->lbprm.hash_balance_factor = atol(args[1]);
3548 if (curproxy->lbprm.hash_balance_factor != 0 && curproxy->lbprm.hash_balance_factor <= 100) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003549 ha_alert("parsing [%s:%d] : '%s' must be 0 or greater than 100.\n", file, linenum, args[0]);
3550 err_code |= ERR_ALERT | ERR_FATAL;
3551 goto out;
3552 }
3553 }
3554 else if (strcmp(args[0], "unique-id-format") == 0) {
3555 if (!*(args[1])) {
3556 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3557 err_code |= ERR_ALERT | ERR_FATAL;
3558 goto out;
3559 }
3560 if (*(args[2])) {
3561 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3562 err_code |= ERR_ALERT | ERR_FATAL;
3563 goto out;
3564 }
3565 free(curproxy->conf.uniqueid_format_string);
3566 curproxy->conf.uniqueid_format_string = strdup(args[1]);
3567
3568 free(curproxy->conf.uif_file);
3569 curproxy->conf.uif_file = strdup(curproxy->conf.args.file);
3570 curproxy->conf.uif_line = curproxy->conf.args.line;
3571 }
3572
3573 else if (strcmp(args[0], "unique-id-header") == 0) {
3574 if (!*(args[1])) {
3575 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3576 err_code |= ERR_ALERT | ERR_FATAL;
3577 goto out;
3578 }
3579 free(curproxy->header_unique_id);
3580 curproxy->header_unique_id = strdup(args[1]);
3581 }
3582
3583 else if (strcmp(args[0], "log-format") == 0) {
3584 if (!*(args[1])) {
3585 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3586 err_code |= ERR_ALERT | ERR_FATAL;
3587 goto out;
3588 }
3589 if (*(args[2])) {
3590 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3591 err_code |= ERR_ALERT | ERR_FATAL;
3592 goto out;
3593 }
3594 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
3595 char *oldlogformat = "log-format";
3596
3597 if (curproxy->conf.logformat_string == default_http_log_format)
3598 oldlogformat = "option httplog";
3599 else if (curproxy->conf.logformat_string == default_tcp_log_format)
3600 oldlogformat = "option tcplog";
3601 else if (curproxy->conf.logformat_string == clf_http_log_format)
3602 oldlogformat = "option httplog clf";
3603 ha_warning("parsing [%s:%d]: 'log-format' overrides previous '%s' in 'defaults' section.\n",
3604 file, linenum, oldlogformat);
3605 }
3606 if (curproxy->conf.logformat_string != default_http_log_format &&
3607 curproxy->conf.logformat_string != default_tcp_log_format &&
3608 curproxy->conf.logformat_string != clf_http_log_format)
3609 free(curproxy->conf.logformat_string);
3610 curproxy->conf.logformat_string = strdup(args[1]);
3611
3612 free(curproxy->conf.lfs_file);
3613 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
3614 curproxy->conf.lfs_line = curproxy->conf.args.line;
3615
3616 /* get a chance to improve log-format error reporting by
3617 * reporting the correct line-number when possible.
3618 */
3619 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3620 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format' directive is ignored in backends.\n",
3621 file, linenum, curproxy->id);
3622 err_code |= ERR_WARN;
3623 }
3624 }
3625 else if (!strcmp(args[0], "log-format-sd")) {
3626 if (!*(args[1])) {
3627 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3628 err_code |= ERR_ALERT | ERR_FATAL;
3629 goto out;
3630 }
3631 if (*(args[2])) {
3632 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3633 err_code |= ERR_ALERT | ERR_FATAL;
3634 goto out;
3635 }
3636
3637 if (curproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
3638 free(curproxy->conf.logformat_sd_string);
3639 curproxy->conf.logformat_sd_string = strdup(args[1]);
3640
3641 free(curproxy->conf.lfsd_file);
3642 curproxy->conf.lfsd_file = strdup(curproxy->conf.args.file);
3643 curproxy->conf.lfsd_line = curproxy->conf.args.line;
3644
3645 /* get a chance to improve log-format-sd error reporting by
3646 * reporting the correct line-number when possible.
3647 */
3648 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3649 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format-sd' directive is ignored in backends.\n",
3650 file, linenum, curproxy->id);
3651 err_code |= ERR_WARN;
3652 }
3653 }
3654 else if (!strcmp(args[0], "log-tag")) { /* tag to report to syslog */
3655 if (*(args[1]) == 0) {
3656 ha_alert("parsing [%s:%d] : '%s' expects a tag for use in syslog.\n", file, linenum, args[0]);
3657 err_code |= ERR_ALERT | ERR_FATAL;
3658 goto out;
3659 }
3660 chunk_destroy(&curproxy->log_tag);
3661 chunk_initstr(&curproxy->log_tag, strdup(args[1]));
3662 }
3663 else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
3664 if (!parse_logsrv(args, &curproxy->logsrvs, (kwm == KWM_NO), &errmsg)) {
3665 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
3666 err_code |= ERR_ALERT | ERR_FATAL;
3667 goto out;
3668 }
3669 }
3670 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
3671 int cur_arg;
3672 int port1, port2;
3673 struct sockaddr_storage *sk;
3674 struct protocol *proto;
3675
3676 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3677 err_code |= ERR_WARN;
3678
3679 if (!*args[1]) {
3680 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optionally '%s' <addr>, and '%s' <name>.\n",
3681 file, linenum, "source", "usesrc", "interface");
3682 err_code |= ERR_ALERT | ERR_FATAL;
3683 goto out;
3684 }
3685
Christopher Faulet31930372019-07-15 10:16:58 +02003686 /* we must first clear any optional default setting */
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003687 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3688 free(curproxy->conn_src.iface_name);
3689 curproxy->conn_src.iface_name = NULL;
3690 curproxy->conn_src.iface_len = 0;
3691
3692 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3693 if (!sk) {
3694 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3695 file, linenum, args[0], args[1], errmsg);
3696 err_code |= ERR_ALERT | ERR_FATAL;
3697 goto out;
3698 }
3699
3700 proto = protocol_by_family(sk->ss_family);
3701 if (!proto || !proto->connect) {
3702 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3703 file, linenum, args[0], args[1]);
3704 err_code |= ERR_ALERT | ERR_FATAL;
3705 goto out;
3706 }
3707
3708 if (port1 != port2) {
3709 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3710 file, linenum, args[0], args[1]);
3711 err_code |= ERR_ALERT | ERR_FATAL;
3712 goto out;
3713 }
3714
3715 curproxy->conn_src.source_addr = *sk;
3716 curproxy->conn_src.opts |= CO_SRC_BIND;
3717
3718 cur_arg = 2;
3719 while (*(args[cur_arg])) {
3720 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
3721#if defined(CONFIG_HAP_TRANSPARENT)
3722 if (!*args[cur_arg + 1]) {
3723 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
3724 file, linenum, "usesrc");
3725 err_code |= ERR_ALERT | ERR_FATAL;
3726 goto out;
3727 }
3728
3729 if (!strcmp(args[cur_arg + 1], "client")) {
3730 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3731 curproxy->conn_src.opts |= CO_SRC_TPROXY_CLI;
3732 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
3733 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3734 curproxy->conn_src.opts |= CO_SRC_TPROXY_CIP;
3735 } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
3736 char *name, *end;
3737
3738 name = args[cur_arg+1] + 7;
3739 while (isspace(*name))
3740 name++;
3741
3742 end = name;
3743 while (*end && !isspace(*end) && *end != ',' && *end != ')')
3744 end++;
3745
3746 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3747 curproxy->conn_src.opts |= CO_SRC_TPROXY_DYN;
3748 curproxy->conn_src.bind_hdr_name = calloc(1, end - name + 1);
3749 curproxy->conn_src.bind_hdr_len = end - name;
3750 memcpy(curproxy->conn_src.bind_hdr_name, name, end - name);
3751 curproxy->conn_src.bind_hdr_name[end-name] = '\0';
3752 curproxy->conn_src.bind_hdr_occ = -1;
3753
3754 /* now look for an occurrence number */
3755 while (isspace(*end))
3756 end++;
3757 if (*end == ',') {
3758 end++;
3759 name = end;
3760 if (*end == '-')
3761 end++;
3762 while (isdigit((int)*end))
3763 end++;
3764 curproxy->conn_src.bind_hdr_occ = strl2ic(name, end-name);
3765 }
3766
3767 if (curproxy->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
3768 ha_alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
3769 " occurrences values smaller than %d.\n",
3770 file, linenum, MAX_HDR_HISTORY);
3771 err_code |= ERR_ALERT | ERR_FATAL;
3772 goto out;
3773 }
3774 } else {
3775 struct sockaddr_storage *sk;
3776
3777 sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3778 if (!sk) {
3779 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3780 file, linenum, args[cur_arg], args[cur_arg+1], errmsg);
3781 err_code |= ERR_ALERT | ERR_FATAL;
3782 goto out;
3783 }
3784
3785 proto = protocol_by_family(sk->ss_family);
3786 if (!proto || !proto->connect) {
3787 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3788 file, linenum, args[cur_arg], args[cur_arg+1]);
3789 err_code |= ERR_ALERT | ERR_FATAL;
3790 goto out;
3791 }
3792
3793 if (port1 != port2) {
3794 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3795 file, linenum, args[cur_arg], args[cur_arg + 1]);
3796 err_code |= ERR_ALERT | ERR_FATAL;
3797 goto out;
3798 }
3799 curproxy->conn_src.tproxy_addr = *sk;
3800 curproxy->conn_src.opts |= CO_SRC_TPROXY_ADDR;
3801 }
3802 global.last_checks |= LSTCHK_NETADM;
3803#else /* no TPROXY support */
3804 ha_alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
3805 file, linenum, "usesrc");
3806 err_code |= ERR_ALERT | ERR_FATAL;
3807 goto out;
3808#endif
3809 cur_arg += 2;
3810 continue;
3811 }
3812
3813 if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
3814#ifdef SO_BINDTODEVICE
3815 if (!*args[cur_arg + 1]) {
3816 ha_alert("parsing [%s:%d] : '%s' : missing interface name.\n",
3817 file, linenum, args[0]);
3818 err_code |= ERR_ALERT | ERR_FATAL;
3819 goto out;
3820 }
3821 free(curproxy->conn_src.iface_name);
3822 curproxy->conn_src.iface_name = strdup(args[cur_arg + 1]);
3823 curproxy->conn_src.iface_len = strlen(curproxy->conn_src.iface_name);
3824 global.last_checks |= LSTCHK_NETADM;
3825#else
3826 ha_alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
3827 file, linenum, args[0], args[cur_arg]);
3828 err_code |= ERR_ALERT | ERR_FATAL;
3829 goto out;
3830#endif
3831 cur_arg += 2;
3832 continue;
3833 }
3834 ha_alert("parsing [%s:%d] : '%s' only supports optional keywords '%s' and '%s'.\n",
3835 file, linenum, args[0], "interface", "usesrc");
3836 err_code |= ERR_ALERT | ERR_FATAL;
3837 goto out;
3838 }
3839 }
3840 else if (!strcmp(args[0], "usesrc")) { /* address to use outside: needs "source" first */
3841 ha_alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
3842 file, linenum, "usesrc", "source");
3843 err_code |= ERR_ALERT | ERR_FATAL;
3844 goto out;
3845 }
3846 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02003847 if (!already_warned(WARN_REQREP_DEPRECATED))
Willy Tarreau33810222019-06-12 17:44:02 +02003848 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 +02003849
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003850 if (*(args[2]) == 0) {
3851 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3852 file, linenum, args[0]);
3853 err_code |= ERR_ALERT | ERR_FATAL;
3854 goto out;
3855 }
3856
3857 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3858 SMP_OPT_DIR_REQ, ACT_REPLACE, 0,
3859 args[0], args[1], args[2], (const char **)args+3);
3860 if (err_code & ERR_FATAL)
3861 goto out;
3862 }
3863 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02003864 if (!already_warned(WARN_REQDEL_DEPRECATED))
3865 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]);
3866
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003867 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3868 SMP_OPT_DIR_REQ, ACT_REMOVE, 0,
3869 args[0], args[1], NULL, (const char **)args+2);
3870 if (err_code & ERR_FATAL)
3871 goto out;
3872 }
3873 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02003874 if (!already_warned(WARN_REQDENY_DEPRECATED))
3875 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]);
3876
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003877 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3878 SMP_OPT_DIR_REQ, ACT_DENY, 0,
3879 args[0], args[1], NULL, (const char **)args+2);
3880 if (err_code & ERR_FATAL)
3881 goto out;
3882 }
3883 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
Willy Tarreau96d51952019-05-22 20:34:35 +02003884 if (!already_warned(WARN_REQPASS_DEPRECATED))
3885 ha_warning("parsing [%s:%d] : The '%s' directive is deprecated and will be removed in next version.\n", file, linenum, args[0]);
3886
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003887 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3888 SMP_OPT_DIR_REQ, ACT_PASS, 0,
3889 args[0], args[1], NULL, (const char **)args+2);
3890 if (err_code & ERR_FATAL)
3891 goto out;
3892 }
3893 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02003894 if (!already_warned(WARN_REQALLOW_DEPRECATED))
3895 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]);
3896
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003897 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3898 SMP_OPT_DIR_REQ, ACT_ALLOW, 0,
3899 args[0], args[1], NULL, (const char **)args+2);
3900 if (err_code & ERR_FATAL)
3901 goto out;
3902 }
3903 else if (!strcmp(args[0], "reqtarpit")) { /* tarpit a request if a header matches this regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02003904 if (!already_warned(WARN_REQTARPIT_DEPRECATED))
3905 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]);
3906
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003907 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3908 SMP_OPT_DIR_REQ, ACT_TARPIT, 0,
3909 args[0], args[1], NULL, (const char **)args+2);
3910 if (err_code & ERR_FATAL)
3911 goto out;
3912 }
3913 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02003914 if (!already_warned(WARN_REQREP_DEPRECATED))
3915 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]);
3916
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003917 if (*(args[2]) == 0) {
3918 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3919 file, linenum, args[0]);
3920 err_code |= ERR_ALERT | ERR_FATAL;
3921 goto out;
3922 }
3923
3924 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3925 SMP_OPT_DIR_REQ, ACT_REPLACE, REG_ICASE,
3926 args[0], args[1], args[2], (const char **)args+3);
3927 if (err_code & ERR_FATAL)
3928 goto out;
3929 }
3930 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02003931 if (!already_warned(WARN_REQDEL_DEPRECATED))
3932 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]);
3933
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003934 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3935 SMP_OPT_DIR_REQ, ACT_REMOVE, REG_ICASE,
3936 args[0], args[1], NULL, (const char **)args+2);
3937 if (err_code & ERR_FATAL)
3938 goto out;
3939 }
3940 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02003941 if (!already_warned(WARN_REQDENY_DEPRECATED))
3942 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]);
3943
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003944 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3945 SMP_OPT_DIR_REQ, ACT_DENY, REG_ICASE,
3946 args[0], args[1], NULL, (const char **)args+2);
3947 if (err_code & ERR_FATAL)
3948 goto out;
3949 }
3950 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
Willy Tarreau96d51952019-05-22 20:34:35 +02003951 if (!already_warned(WARN_REQPASS_DEPRECATED))
3952 ha_warning("parsing [%s:%d] : The '%s' directive is deprecated and will be removed in next version.\n", file, linenum, args[0]);
3953
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003954 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3955 SMP_OPT_DIR_REQ, ACT_PASS, REG_ICASE,
3956 args[0], args[1], NULL, (const char **)args+2);
3957 if (err_code & ERR_FATAL)
3958 goto out;
3959 }
3960 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02003961 if (!already_warned(WARN_REQALLOW_DEPRECATED))
3962 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]);
3963
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003964 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3965 SMP_OPT_DIR_REQ, ACT_ALLOW, REG_ICASE,
3966 args[0], args[1], NULL, (const char **)args+2);
3967 if (err_code & ERR_FATAL)
3968 goto out;
3969 }
3970 else if (!strcmp(args[0], "reqitarpit")) { /* tarpit a request if a header matches this regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02003971 if (!already_warned(WARN_REQTARPIT_DEPRECATED))
3972 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]);
3973
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003974 err_code |= create_cond_regex_rule(file, linenum, curproxy,
3975 SMP_OPT_DIR_REQ, ACT_TARPIT, REG_ICASE,
3976 args[0], args[1], NULL, (const char **)args+2);
3977 if (err_code & ERR_FATAL)
3978 goto out;
3979 }
3980 else if (!strcmp(args[0], "reqadd")) { /* add request header */
3981 struct cond_wordlist *wl;
3982
Willy Tarreau96d51952019-05-22 20:34:35 +02003983 if (!already_warned(WARN_REQADD_DEPRECATED))
3984 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]);
3985
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003986 if (curproxy == &defproxy) {
3987 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3988 err_code |= ERR_ALERT | ERR_FATAL;
3989 goto out;
3990 }
3991 else if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
3992 err_code |= ERR_WARN;
3993
3994 if (*(args[1]) == 0) {
3995 ha_alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
3996 err_code |= ERR_ALERT | ERR_FATAL;
3997 goto out;
3998 }
3999
4000 if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
4001 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args+2, &errmsg)) == NULL) {
4002 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
4003 file, linenum, args[0], errmsg);
4004 err_code |= ERR_ALERT | ERR_FATAL;
4005 goto out;
4006 }
4007 err_code |= warnif_cond_conflicts(cond,
4008 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
4009 file, linenum);
4010 }
4011 else if (*args[2]) {
4012 ha_alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
4013 file, linenum, args[0], args[2]);
4014 err_code |= ERR_ALERT | ERR_FATAL;
4015 goto out;
4016 }
4017
4018 wl = calloc(1, sizeof(*wl));
4019 wl->cond = cond;
4020 wl->s = strdup(args[1]);
4021 LIST_ADDQ(&curproxy->req_add, &wl->list);
4022 warnif_misplaced_reqadd(curproxy, file, linenum, args[0]);
4023 }
4024 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004025 if (!already_warned(WARN_RSPREP_DEPRECATED))
4026 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]);
4027
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004028 if (*(args[2]) == 0) {
4029 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4030 file, linenum, args[0]);
4031 err_code |= ERR_ALERT | ERR_FATAL;
4032 goto out;
4033 }
4034
4035 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4036 SMP_OPT_DIR_RES, ACT_REPLACE, 0,
4037 args[0], args[1], args[2], (const char **)args+3);
4038 if (err_code & ERR_FATAL)
4039 goto out;
4040 }
4041 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004042 if (!already_warned(WARN_RSPDEL_DEPRECATED))
4043 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]);
4044
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004045 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4046 SMP_OPT_DIR_RES, ACT_REMOVE, 0,
4047 args[0], args[1], NULL, (const char **)args+2);
4048 if (err_code & ERR_FATAL)
4049 goto out;
4050 }
4051 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
Willy Tarreau96d51952019-05-22 20:34:35 +02004052 if (!already_warned(WARN_RSPDENY_DEPRECATED))
4053 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]);
4054
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004055 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4056 SMP_OPT_DIR_RES, ACT_DENY, 0,
4057 args[0], args[1], NULL, (const char **)args+2);
4058 if (err_code & ERR_FATAL)
4059 goto out;
4060 }
4061 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004062 if (!already_warned(WARN_RSPREP_DEPRECATED))
4063 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]);
4064
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004065 if (*(args[2]) == 0) {
4066 ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4067 file, linenum, args[0]);
4068 err_code |= ERR_ALERT | ERR_FATAL;
4069 goto out;
4070 }
4071
4072 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4073 SMP_OPT_DIR_RES, ACT_REPLACE, REG_ICASE,
4074 args[0], args[1], args[2], (const char **)args+3);
4075 if (err_code & ERR_FATAL)
4076 goto out;
4077 }
4078 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004079 if (!already_warned(WARN_RSPDEL_DEPRECATED))
4080 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]);
4081
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004082 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4083 SMP_OPT_DIR_RES, ACT_REMOVE, REG_ICASE,
4084 args[0], args[1], NULL, (const char **)args+2);
4085 if (err_code & ERR_FATAL)
4086 goto out;
4087 }
4088 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
Willy Tarreau96d51952019-05-22 20:34:35 +02004089 if (!already_warned(WARN_RSPDENY_DEPRECATED))
4090 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]);
4091
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004092 err_code |= create_cond_regex_rule(file, linenum, curproxy,
4093 SMP_OPT_DIR_RES, ACT_DENY, REG_ICASE,
4094 args[0], args[1], NULL, (const char **)args+2);
4095 if (err_code & ERR_FATAL)
4096 goto out;
4097 }
4098 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4099 struct cond_wordlist *wl;
4100
Willy Tarreau96d51952019-05-22 20:34:35 +02004101 if (!already_warned(WARN_RSPADD_DEPRECATED))
4102 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]);
4103
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004104 if (curproxy == &defproxy) {
4105 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4106 err_code |= ERR_ALERT | ERR_FATAL;
4107 goto out;
4108 }
4109 else if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4110 err_code |= ERR_WARN;
4111
4112 if (*(args[1]) == 0) {
4113 ha_alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
4114 err_code |= ERR_ALERT | ERR_FATAL;
4115 goto out;
4116 }
4117
4118 if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
4119 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args+2, &errmsg)) == NULL) {
4120 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
4121 file, linenum, args[0], errmsg);
4122 err_code |= ERR_ALERT | ERR_FATAL;
4123 goto out;
4124 }
4125 err_code |= warnif_cond_conflicts(cond,
4126 (curproxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
4127 file, linenum);
4128 }
4129 else if (*args[2]) {
4130 ha_alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
4131 file, linenum, args[0], args[2]);
4132 err_code |= ERR_ALERT | ERR_FATAL;
4133 goto out;
4134 }
4135
4136 wl = calloc(1, sizeof(*wl));
4137 wl->cond = cond;
4138 wl->s = strdup(args[1]);
4139 LIST_ADDQ(&curproxy->rsp_add, &wl->list);
4140 }
4141 else if (!strcmp(args[0], "errorloc") ||
4142 !strcmp(args[0], "errorloc302") ||
4143 !strcmp(args[0], "errorloc303")) { /* error location */
4144 int errnum, errlen;
4145 char *err;
4146
4147 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4148 err_code |= ERR_WARN;
4149
4150 if (*(args[2]) == 0) {
4151 ha_alert("parsing [%s:%d] : <%s> expects <status_code> and <url> as arguments.\n", file, linenum, args[0]);
4152 err_code |= ERR_ALERT | ERR_FATAL;
4153 goto out;
4154 }
4155
4156 errnum = atol(args[1]);
4157 if (!strcmp(args[0], "errorloc303")) {
4158 errlen = strlen(HTTP_303) + strlen(args[2]) + 5;
4159 err = malloc(errlen);
4160 errlen = snprintf(err, errlen, "%s%s\r\n\r\n", HTTP_303, args[2]);
4161 } else {
4162 errlen = strlen(HTTP_302) + strlen(args[2]) + 5;
4163 err = malloc(errlen);
4164 errlen = snprintf(err, errlen, "%s%s\r\n\r\n", HTTP_302, args[2]);
4165 }
4166
4167 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
4168 if (http_err_codes[rc] == errnum) {
4169 chunk_destroy(&curproxy->errmsg[rc]);
4170 chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen);
4171 break;
4172 }
4173 }
4174
4175 if (rc >= HTTP_ERR_SIZE) {
4176 ha_warning("parsing [%s:%d] : status code %d not handled by '%s', error relocation will be ignored.\n",
4177 file, linenum, errnum, args[0]);
4178 free(err);
4179 }
4180 }
4181 else if (!strcmp(args[0], "errorfile")) { /* error message from a file */
4182 int errnum, errlen, fd;
4183 char *err;
4184 struct stat stat;
4185
4186 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
4187 err_code |= ERR_WARN;
4188
4189 if (*(args[2]) == 0) {
4190 ha_alert("parsing [%s:%d] : <%s> expects <status_code> and <file> as arguments.\n", file, linenum, args[0]);
4191 err_code |= ERR_ALERT | ERR_FATAL;
4192 goto out;
4193 }
4194
4195 fd = open(args[2], O_RDONLY);
4196 if ((fd < 0) || (fstat(fd, &stat) < 0)) {
4197 ha_alert("parsing [%s:%d] : error opening file <%s> for custom error message <%s>.\n",
4198 file, linenum, args[2], args[1]);
4199 if (fd >= 0)
4200 close(fd);
4201 err_code |= ERR_ALERT | ERR_FATAL;
4202 goto out;
4203 }
4204
4205 if (stat.st_size <= global.tune.bufsize) {
4206 errlen = stat.st_size;
4207 } else {
4208 ha_warning("parsing [%s:%d] : custom error message file <%s> larger than %d bytes. Truncating.\n",
4209 file, linenum, args[2], global.tune.bufsize);
4210 err_code |= ERR_WARN;
4211 errlen = global.tune.bufsize;
4212 }
4213
4214 err = malloc(errlen); /* malloc() must succeed during parsing */
4215 errnum = read(fd, err, errlen);
4216 if (errnum != errlen) {
4217 ha_alert("parsing [%s:%d] : error reading file <%s> for custom error message <%s>.\n",
4218 file, linenum, args[2], args[1]);
4219 close(fd);
4220 free(err);
4221 err_code |= ERR_ALERT | ERR_FATAL;
4222 goto out;
4223 }
4224 close(fd);
4225
4226 errnum = atol(args[1]);
4227 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
4228 if (http_err_codes[rc] == errnum) {
4229 chunk_destroy(&curproxy->errmsg[rc]);
4230 chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen);
4231 break;
4232 }
4233 }
4234
4235 if (rc >= HTTP_ERR_SIZE) {
4236 ha_warning("parsing [%s:%d] : status code %d not handled by '%s', error customization will be ignored.\n",
4237 file, linenum, errnum, args[0]);
4238 err_code |= ERR_WARN;
4239 free(err);
4240 }
4241 }
4242 else {
4243 struct cfg_kw_list *kwl;
4244 int index;
4245
4246 list_for_each_entry(kwl, &cfg_keywords.list, list) {
4247 for (index = 0; kwl->kw[index].kw != NULL; index++) {
4248 if (kwl->kw[index].section != CFG_LISTEN)
4249 continue;
4250 if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
4251 /* prepare error message just in case */
4252 rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, file, linenum, &errmsg);
4253 if (rc < 0) {
4254 ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4255 err_code |= ERR_ALERT | ERR_FATAL;
4256 goto out;
4257 }
4258 else if (rc > 0) {
4259 ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4260 err_code |= ERR_WARN;
4261 goto out;
4262 }
4263 goto out;
4264 }
4265 }
4266 }
4267
4268 ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
4269 err_code |= ERR_ALERT | ERR_FATAL;
4270 goto out;
4271 }
4272 out:
4273 free(errmsg);
4274 return err_code;
4275}