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