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