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