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