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