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