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