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