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