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