blob: 4b099c181d03a2e6315a6439bdb0fd6f4d603ee7 [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
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100165int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
166{
167 static struct proxy *curproxy = NULL;
168 const char *err;
169 char *error;
170 int rc;
171 unsigned val;
172 int err_code = 0;
173 struct acl_cond *cond = NULL;
174 struct logsrv *tmplogsrv;
175 char *errmsg = NULL;
176 struct bind_conf *bind_conf;
177
178 if (!strcmp(args[0], "listen"))
179 rc = PR_CAP_LISTEN;
180 else if (!strcmp(args[0], "frontend"))
181 rc = PR_CAP_FE;
182 else if (!strcmp(args[0], "backend"))
183 rc = PR_CAP_BE;
184 else
185 rc = PR_CAP_NONE;
186
187 if (rc != PR_CAP_NONE) { /* new proxy */
188 if (!*args[1]) {
189 ha_alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
190 " optionally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
191 file, linenum, args[0]);
192 err_code |= ERR_ALERT | ERR_ABORT;
193 goto out;
194 }
195
196 err = invalid_char(args[1]);
197 if (err) {
198 ha_alert("parsing [%s:%d] : character '%c' is not permitted in '%s' name '%s'.\n",
199 file, linenum, *err, args[0], args[1]);
200 err_code |= ERR_ALERT | ERR_FATAL;
201 }
202
203 curproxy = (rc & PR_CAP_FE) ? proxy_fe_by_name(args[1]) : proxy_be_by_name(args[1]);
204 if (curproxy) {
205 ha_alert("Parsing [%s:%d]: %s '%s' has the same name as %s '%s' declared at %s:%d.\n",
206 file, linenum, proxy_cap_str(rc), args[1], proxy_type_str(curproxy),
207 curproxy->id, curproxy->conf.file, curproxy->conf.line);
208 err_code |= ERR_ALERT | ERR_FATAL;
209 }
210
211 if ((curproxy = calloc(1, sizeof(*curproxy))) == NULL) {
212 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
213 err_code |= ERR_ALERT | ERR_ABORT;
214 goto out;
215 }
216
217 init_new_proxy(curproxy);
218 curproxy->next = proxies_list;
219 proxies_list = curproxy;
220 curproxy->conf.args.file = curproxy->conf.file = strdup(file);
221 curproxy->conf.args.line = curproxy->conf.line = linenum;
222 curproxy->last_change = now.tv_sec;
223 curproxy->id = strdup(args[1]);
224 curproxy->cap = rc;
225 proxy_store_name(curproxy);
226
227 if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
228 if (curproxy->cap & PR_CAP_FE)
229 ha_alert("parsing [%s:%d] : please use the 'bind' keyword for listening addresses.\n", file, linenum);
230 goto out;
231 }
232
233 /* set default values */
234 memcpy(&curproxy->defsrv, &defproxy.defsrv, sizeof(curproxy->defsrv));
235 curproxy->defsrv.id = "default-server";
236
237 curproxy->state = defproxy.state;
238 curproxy->options = defproxy.options;
239 curproxy->options2 = defproxy.options2;
240 curproxy->no_options = defproxy.no_options;
241 curproxy->no_options2 = defproxy.no_options2;
242 curproxy->bind_proc = defproxy.bind_proc;
243 curproxy->except_net = defproxy.except_net;
244 curproxy->except_mask = defproxy.except_mask;
245 curproxy->except_to = defproxy.except_to;
246 curproxy->except_mask_to = defproxy.except_mask_to;
Olivier Houcharda254a372019-04-05 15:30:12 +0200247 curproxy->retry_type = defproxy.retry_type;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100248
249 if (defproxy.fwdfor_hdr_len) {
250 curproxy->fwdfor_hdr_len = defproxy.fwdfor_hdr_len;
251 curproxy->fwdfor_hdr_name = strdup(defproxy.fwdfor_hdr_name);
252 }
253
254 if (defproxy.orgto_hdr_len) {
255 curproxy->orgto_hdr_len = defproxy.orgto_hdr_len;
256 curproxy->orgto_hdr_name = strdup(defproxy.orgto_hdr_name);
257 }
258
259 if (defproxy.server_id_hdr_len) {
260 curproxy->server_id_hdr_len = defproxy.server_id_hdr_len;
261 curproxy->server_id_hdr_name = strdup(defproxy.server_id_hdr_name);
262 }
263
264 /* initialize error relocations */
Christopher Faulet76edc0f2020-01-13 15:52:01 +0100265 if (!proxy_dup_default_conf_errors(curproxy, &defproxy, &errmsg)) {
266 ha_alert("parsing [%s:%d] : proxy '%s' : %s\n", file, linenum, curproxy->id, errmsg);
267 err_code |= ERR_ALERT | ERR_FATAL;
268 goto out;
269 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100270
271 if (curproxy->cap & PR_CAP_FE) {
272 curproxy->maxconn = defproxy.maxconn;
273 curproxy->backlog = defproxy.backlog;
274 curproxy->fe_sps_lim = defproxy.fe_sps_lim;
275
276 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
Olivier Houcharda4d4fdf2018-12-14 19:27:06 +0100277 curproxy->max_out_conns = defproxy.max_out_conns;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100278 }
279
280 if (curproxy->cap & PR_CAP_BE) {
281 curproxy->lbprm.algo = defproxy.lbprm.algo;
Willy Tarreau76e84f52019-01-14 16:50:58 +0100282 curproxy->lbprm.hash_balance_factor = defproxy.lbprm.hash_balance_factor;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100283 curproxy->fullconn = defproxy.fullconn;
284 curproxy->conn_retries = defproxy.conn_retries;
285 curproxy->redispatch_after = defproxy.redispatch_after;
286 curproxy->max_ka_queue = defproxy.max_ka_queue;
287
288 if (defproxy.check_req) {
289 curproxy->check_req = calloc(1, defproxy.check_len);
290 memcpy(curproxy->check_req, defproxy.check_req, defproxy.check_len);
291 }
292 curproxy->check_len = defproxy.check_len;
293
Christopher Faulet8acb1282020-04-09 08:44:06 +0200294 if (defproxy.check_hdrs) {
295 curproxy->check_hdrs = calloc(1, defproxy.check_hdrs_len);
296 memcpy(curproxy->check_hdrs, defproxy.check_hdrs, defproxy.check_hdrs_len);
297 }
298 curproxy->check_hdrs_len = defproxy.check_hdrs_len;
299
300 if (defproxy.check_body) {
301 curproxy->check_body = calloc(1, defproxy.check_body_len);
302 memcpy(curproxy->check_body, defproxy.check_body, defproxy.check_body_len);
303 }
304 curproxy->check_body_len = defproxy.check_body_len;
305
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100306 if (defproxy.expect_str) {
307 curproxy->expect_str = strdup(defproxy.expect_str);
308 if (defproxy.expect_regex) {
309 /* note: this regex is known to be valid */
Dragan Dosen26743032019-04-30 15:54:36 +0200310 error = NULL;
311 if (!(curproxy->expect_regex = regex_comp(defproxy.expect_str, 1, 1, &error))) {
312 ha_alert("parsing [%s:%d] : regular expression '%s' : %s\n", file, linenum,
313 defproxy.expect_str, error);
314 free(error);
315 err_code |= ERR_ALERT | ERR_FATAL;
316 goto out;
317 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100318 }
319 }
320
321 curproxy->ck_opts = defproxy.ck_opts;
322 if (defproxy.cookie_name)
323 curproxy->cookie_name = strdup(defproxy.cookie_name);
324 curproxy->cookie_len = defproxy.cookie_len;
325
326 if (defproxy.dyncookie_key)
327 curproxy->dyncookie_key = strdup(defproxy.dyncookie_key);
328 if (defproxy.cookie_domain)
329 curproxy->cookie_domain = strdup(defproxy.cookie_domain);
330
331 if (defproxy.cookie_maxidle)
332 curproxy->cookie_maxidle = defproxy.cookie_maxidle;
333
334 if (defproxy.cookie_maxlife)
335 curproxy->cookie_maxlife = defproxy.cookie_maxlife;
336
337 if (defproxy.rdp_cookie_name)
338 curproxy->rdp_cookie_name = strdup(defproxy.rdp_cookie_name);
339 curproxy->rdp_cookie_len = defproxy.rdp_cookie_len;
340
Christopher Faulet2f533902020-01-21 11:06:48 +0100341 if (defproxy.cookie_attrs)
342 curproxy->cookie_attrs = strdup(defproxy.cookie_attrs);
Willy Tarreau20e68372019-01-14 16:04:01 +0100343
Willy Tarreau4c03d1c2019-01-14 15:23:54 +0100344 if (defproxy.lbprm.arg_str)
345 curproxy->lbprm.arg_str = strdup(defproxy.lbprm.arg_str);
346 curproxy->lbprm.arg_len = defproxy.lbprm.arg_len;
Willy Tarreau20e68372019-01-14 16:04:01 +0100347 curproxy->lbprm.arg_opt1 = defproxy.lbprm.arg_opt1;
348 curproxy->lbprm.arg_opt2 = defproxy.lbprm.arg_opt2;
349 curproxy->lbprm.arg_opt3 = defproxy.lbprm.arg_opt3;
350
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100351 if (defproxy.conn_src.iface_name)
352 curproxy->conn_src.iface_name = strdup(defproxy.conn_src.iface_name);
353 curproxy->conn_src.iface_len = defproxy.conn_src.iface_len;
354 curproxy->conn_src.opts = defproxy.conn_src.opts;
355#if defined(CONFIG_HAP_TRANSPARENT)
356 curproxy->conn_src.tproxy_addr = defproxy.conn_src.tproxy_addr;
357#endif
358 curproxy->load_server_state_from_file = defproxy.load_server_state_from_file;
359 }
360
361 if (curproxy->cap & PR_CAP_FE) {
362 if (defproxy.capture_name)
363 curproxy->capture_name = strdup(defproxy.capture_name);
364 curproxy->capture_namelen = defproxy.capture_namelen;
365 curproxy->capture_len = defproxy.capture_len;
366 }
367
368 if (curproxy->cap & PR_CAP_FE) {
369 curproxy->timeout.client = defproxy.timeout.client;
370 curproxy->timeout.clientfin = defproxy.timeout.clientfin;
371 curproxy->timeout.tarpit = defproxy.timeout.tarpit;
372 curproxy->timeout.httpreq = defproxy.timeout.httpreq;
373 curproxy->timeout.httpka = defproxy.timeout.httpka;
374 curproxy->mon_net = defproxy.mon_net;
375 curproxy->mon_mask = defproxy.mon_mask;
376 if (defproxy.monitor_uri)
377 curproxy->monitor_uri = strdup(defproxy.monitor_uri);
378 curproxy->monitor_uri_len = defproxy.monitor_uri_len;
379 if (defproxy.defbe.name)
380 curproxy->defbe.name = strdup(defproxy.defbe.name);
381
382 /* get either a pointer to the logformat string or a copy of it */
383 curproxy->conf.logformat_string = defproxy.conf.logformat_string;
384 if (curproxy->conf.logformat_string &&
385 curproxy->conf.logformat_string != default_http_log_format &&
386 curproxy->conf.logformat_string != default_tcp_log_format &&
387 curproxy->conf.logformat_string != clf_http_log_format)
388 curproxy->conf.logformat_string = strdup(curproxy->conf.logformat_string);
389
390 if (defproxy.conf.lfs_file) {
391 curproxy->conf.lfs_file = strdup(defproxy.conf.lfs_file);
392 curproxy->conf.lfs_line = defproxy.conf.lfs_line;
393 }
394
395 /* get either a pointer to the logformat string for RFC5424 structured-data or a copy of it */
396 curproxy->conf.logformat_sd_string = defproxy.conf.logformat_sd_string;
397 if (curproxy->conf.logformat_sd_string &&
398 curproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
399 curproxy->conf.logformat_sd_string = strdup(curproxy->conf.logformat_sd_string);
400
401 if (defproxy.conf.lfsd_file) {
402 curproxy->conf.lfsd_file = strdup(defproxy.conf.lfsd_file);
403 curproxy->conf.lfsd_line = defproxy.conf.lfsd_line;
404 }
405 }
406
407 if (curproxy->cap & PR_CAP_BE) {
408 curproxy->timeout.connect = defproxy.timeout.connect;
409 curproxy->timeout.server = defproxy.timeout.server;
410 curproxy->timeout.serverfin = defproxy.timeout.serverfin;
411 curproxy->timeout.check = defproxy.timeout.check;
412 curproxy->timeout.queue = defproxy.timeout.queue;
413 curproxy->timeout.tarpit = defproxy.timeout.tarpit;
414 curproxy->timeout.httpreq = defproxy.timeout.httpreq;
415 curproxy->timeout.httpka = defproxy.timeout.httpka;
416 curproxy->timeout.tunnel = defproxy.timeout.tunnel;
417 curproxy->conn_src.source_addr = defproxy.conn_src.source_addr;
418 }
419
420 curproxy->mode = defproxy.mode;
421 curproxy->uri_auth = defproxy.uri_auth; /* for stats */
422
423 /* copy default logsrvs to curproxy */
424 list_for_each_entry(tmplogsrv, &defproxy.logsrvs, list) {
425 struct logsrv *node = malloc(sizeof(*node));
426 memcpy(node, tmplogsrv, sizeof(struct logsrv));
427 node->ref = tmplogsrv->ref;
428 LIST_INIT(&node->list);
429 LIST_ADDQ(&curproxy->logsrvs, &node->list);
430 }
431
432 curproxy->conf.uniqueid_format_string = defproxy.conf.uniqueid_format_string;
433 if (curproxy->conf.uniqueid_format_string)
434 curproxy->conf.uniqueid_format_string = strdup(curproxy->conf.uniqueid_format_string);
435
436 chunk_dup(&curproxy->log_tag, &defproxy.log_tag);
437
438 if (defproxy.conf.uif_file) {
439 curproxy->conf.uif_file = strdup(defproxy.conf.uif_file);
440 curproxy->conf.uif_line = defproxy.conf.uif_line;
441 }
442
443 /* copy default header unique id */
Tim Duesterhus0643b0e2020-03-05 17:56:35 +0100444 if (isttest(defproxy.header_unique_id)) {
445 const struct ist copy = istdup(defproxy.header_unique_id);
446 if (!isttest(copy)) {
447 ha_alert("parsing [%s:%d] : failed to allocate memory for unique-id-header\n", file, linenum);
448 err_code |= ERR_ALERT | ERR_FATAL;
449 goto out;
450 }
451 curproxy->header_unique_id = copy;
452 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100453
454 /* default compression options */
455 if (defproxy.comp != NULL) {
456 curproxy->comp = calloc(1, sizeof(struct comp));
457 curproxy->comp->algos = defproxy.comp->algos;
458 curproxy->comp->types = defproxy.comp->types;
459 }
460
461 curproxy->grace = defproxy.grace;
462 curproxy->conf.used_listener_id = EB_ROOT;
463 curproxy->conf.used_server_id = EB_ROOT;
464
465 if (defproxy.check_path)
466 curproxy->check_path = strdup(defproxy.check_path);
467 if (defproxy.check_command)
468 curproxy->check_command = strdup(defproxy.check_command);
469
470 if (defproxy.email_alert.mailers.name)
471 curproxy->email_alert.mailers.name = strdup(defproxy.email_alert.mailers.name);
472 if (defproxy.email_alert.from)
473 curproxy->email_alert.from = strdup(defproxy.email_alert.from);
474 if (defproxy.email_alert.to)
475 curproxy->email_alert.to = strdup(defproxy.email_alert.to);
476 if (defproxy.email_alert.myhostname)
477 curproxy->email_alert.myhostname = strdup(defproxy.email_alert.myhostname);
478 curproxy->email_alert.level = defproxy.email_alert.level;
479 curproxy->email_alert.set = defproxy.email_alert.set;
480
481 goto out;
482 }
483 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
484 /* some variables may have already been initialized earlier */
485 /* FIXME-20070101: we should do this too at the end of the
486 * config parsing to free all default values.
487 */
488 if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
489 err_code |= ERR_ABORT;
490 goto out;
491 }
492
493 free(defproxy.check_req);
494 free(defproxy.check_command);
495 free(defproxy.check_path);
496 free(defproxy.cookie_name);
497 free(defproxy.rdp_cookie_name);
498 free(defproxy.dyncookie_key);
499 free(defproxy.cookie_domain);
Christopher Faulet2f533902020-01-21 11:06:48 +0100500 free(defproxy.cookie_attrs);
Willy Tarreau4c03d1c2019-01-14 15:23:54 +0100501 free(defproxy.lbprm.arg_str);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100502 free(defproxy.capture_name);
503 free(defproxy.monitor_uri);
504 free(defproxy.defbe.name);
505 free(defproxy.conn_src.iface_name);
506 free(defproxy.fwdfor_hdr_name);
507 defproxy.fwdfor_hdr_len = 0;
508 free(defproxy.orgto_hdr_name);
509 defproxy.orgto_hdr_len = 0;
510 free(defproxy.server_id_hdr_name);
511 defproxy.server_id_hdr_len = 0;
512 free(defproxy.expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +0200513 regex_free(defproxy.expect_regex);
514 defproxy.expect_regex = NULL;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100515
516 if (defproxy.conf.logformat_string != default_http_log_format &&
517 defproxy.conf.logformat_string != default_tcp_log_format &&
518 defproxy.conf.logformat_string != clf_http_log_format)
519 free(defproxy.conf.logformat_string);
520
521 free(defproxy.conf.uniqueid_format_string);
522 free(defproxy.conf.lfs_file);
523 free(defproxy.conf.uif_file);
524 chunk_destroy(&defproxy.log_tag);
525 free_email_alert(&defproxy);
526
527 if (defproxy.conf.logformat_sd_string != default_rfc5424_sd_log_format)
528 free(defproxy.conf.logformat_sd_string);
529 free(defproxy.conf.lfsd_file);
530
Christopher Faulet76edc0f2020-01-13 15:52:01 +0100531 proxy_release_conf_errors(&defproxy);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100532
533 /* we cannot free uri_auth because it might already be used */
534 init_default_instance();
535 curproxy = &defproxy;
536 curproxy->conf.args.file = curproxy->conf.file = strdup(file);
537 curproxy->conf.args.line = curproxy->conf.line = linenum;
538 defproxy.cap = PR_CAP_LISTEN; /* all caps for now */
539 goto out;
540 }
541 else if (curproxy == NULL) {
542 ha_alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
543 err_code |= ERR_ALERT | ERR_FATAL;
544 goto out;
545 }
546
547 /* update the current file and line being parsed */
548 curproxy->conf.args.file = curproxy->conf.file;
549 curproxy->conf.args.line = linenum;
550
551 /* Now let's parse the proxy-specific keywords */
552 if (!strcmp(args[0], "server") ||
553 !strcmp(args[0], "default-server") ||
554 !strcmp(args[0], "server-template")) {
Frédéric Lécaille8ba10fe2020-04-03 09:43:47 +0200555 err_code |= parse_server(file, linenum, args, curproxy, &defproxy, 1, 0);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100556 if (err_code & ERR_FATAL)
557 goto out;
558 }
559 else if (!strcmp(args[0], "bind")) { /* new listen addresses */
560 struct listener *l;
561 int cur_arg;
562
563 if (curproxy == &defproxy) {
564 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
565 err_code |= ERR_ALERT | ERR_FATAL;
566 goto out;
567 }
568 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
569 err_code |= ERR_WARN;
570
571 if (!*(args[1])) {
572 ha_alert("parsing [%s:%d] : '%s' expects {<path>|[addr1]:port1[-end1]}{,[addr]:port[-end]}... as arguments.\n",
573 file, linenum, args[0]);
574 err_code |= ERR_ALERT | ERR_FATAL;
575 goto out;
576 }
577
578 bind_conf = bind_conf_alloc(curproxy, file, linenum, args[1], xprt_get(XPRT_RAW));
579
580 /* use default settings for unix sockets */
581 bind_conf->ux.uid = global.unix_bind.ux.uid;
582 bind_conf->ux.gid = global.unix_bind.ux.gid;
583 bind_conf->ux.mode = global.unix_bind.ux.mode;
584
585 /* NOTE: the following line might create several listeners if there
586 * are comma-separated IPs or port ranges. So all further processing
587 * will have to be applied to all listeners created after last_listen.
588 */
589 if (!str2listener(args[1], curproxy, bind_conf, file, linenum, &errmsg)) {
590 if (errmsg && *errmsg) {
591 indent_msg(&errmsg, 2);
592 ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
593 }
594 else
595 ha_alert("parsing [%s:%d] : '%s' : error encountered while parsing listening address '%s'.\n",
596 file, linenum, args[0], args[1]);
597 err_code |= ERR_ALERT | ERR_FATAL;
598 goto out;
599 }
600
601 list_for_each_entry(l, &bind_conf->listeners, by_bind) {
602 /* Set default global rights and owner for unix bind */
603 global.maxsock++;
604 }
605
606 cur_arg = 2;
607 while (*(args[cur_arg])) {
608 static int bind_dumped;
609 struct bind_kw *kw;
610 char *err;
611
612 kw = bind_find_kw(args[cur_arg]);
613 if (kw) {
614 char *err = NULL;
615 int code;
616
617 if (!kw->parse) {
618 ha_alert("parsing [%s:%d] : '%s %s' : '%s' option is not implemented in this version (check build options).\n",
619 file, linenum, args[0], args[1], args[cur_arg]);
620 cur_arg += 1 + kw->skip ;
621 err_code |= ERR_ALERT | ERR_FATAL;
622 goto out;
623 }
624
625 code = kw->parse(args, cur_arg, curproxy, bind_conf, &err);
626 err_code |= code;
627
628 if (code) {
629 if (err && *err) {
630 indent_msg(&err, 2);
Emeric Brun0655c9b2019-10-17 16:45:56 +0200631 if (((code & (ERR_WARN|ERR_ALERT)) == ERR_WARN))
632 ha_warning("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], err);
633 else
634 ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], err);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100635 }
636 else
637 ha_alert("parsing [%s:%d] : '%s %s' : error encountered while processing '%s'.\n",
638 file, linenum, args[0], args[1], args[cur_arg]);
639 if (code & ERR_FATAL) {
640 free(err);
641 cur_arg += 1 + kw->skip;
642 goto out;
643 }
644 }
645 free(err);
646 cur_arg += 1 + kw->skip;
647 continue;
648 }
649
650 err = NULL;
651 if (!bind_dumped) {
652 bind_dump_kws(&err);
653 indent_msg(&err, 4);
654 bind_dumped = 1;
655 }
656
657 ha_alert("parsing [%s:%d] : '%s %s' unknown keyword '%s'.%s%s\n",
658 file, linenum, args[0], args[1], args[cur_arg],
659 err ? " Registered keywords :" : "", err ? err : "");
660 free(err);
661
662 err_code |= ERR_ALERT | ERR_FATAL;
663 goto out;
664 }
665 goto out;
666 }
667 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
668 if (!*args[1] || !str2net(args[1], 1, &curproxy->mon_net, &curproxy->mon_mask)) {
669 ha_alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
670 file, linenum, args[0]);
671 err_code |= ERR_ALERT | ERR_FATAL;
672 goto out;
673 }
674 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
675 err_code |= ERR_WARN;
676
677 /* flush useless bits */
678 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
679 goto out;
680 }
681 else if (!strcmp(args[0], "monitor-uri")) { /* set the URI to intercept */
682 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
683 err_code |= ERR_WARN;
684
685 if (alertif_too_many_args(1, file, linenum, args, &err_code))
686 goto out;
687
688 if (!*args[1]) {
689 ha_alert("parsing [%s:%d] : '%s' expects an URI.\n",
690 file, linenum, args[0]);
691 err_code |= ERR_ALERT | ERR_FATAL;
692 goto out;
693 }
694
695 free(curproxy->monitor_uri);
696 curproxy->monitor_uri_len = strlen(args[1]);
697 curproxy->monitor_uri = calloc(1, curproxy->monitor_uri_len + 1);
698 memcpy(curproxy->monitor_uri, args[1], curproxy->monitor_uri_len);
699 curproxy->monitor_uri[curproxy->monitor_uri_len] = '\0';
700
701 goto out;
702 }
703 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
704 if (alertif_too_many_args(1, file, linenum, args, &err_code))
705 goto out;
706
707 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
708 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
709 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
710 else {
711 ha_alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
712 err_code |= ERR_ALERT | ERR_FATAL;
713 goto out;
714 }
715 }
716 else if (!strcmp(args[0], "id")) {
717 struct eb32_node *node;
718
719 if (curproxy == &defproxy) {
720 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n",
721 file, linenum, args[0]);
722 err_code |= ERR_ALERT | ERR_FATAL;
723 goto out;
724 }
725
726 if (alertif_too_many_args(1, file, linenum, args, &err_code))
727 goto out;
728
729 if (!*args[1]) {
730 ha_alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
731 file, linenum, args[0]);
732 err_code |= ERR_ALERT | ERR_FATAL;
733 goto out;
734 }
735
736 curproxy->uuid = atol(args[1]);
737 curproxy->conf.id.key = curproxy->uuid;
738 curproxy->options |= PR_O_FORCED_ID;
739
740 if (curproxy->uuid <= 0) {
741 ha_alert("parsing [%s:%d]: custom id has to be > 0.\n",
742 file, linenum);
743 err_code |= ERR_ALERT | ERR_FATAL;
744 goto out;
745 }
746
747 node = eb32_lookup(&used_proxy_id, curproxy->uuid);
748 if (node) {
749 struct proxy *target = container_of(node, struct proxy, conf.id);
750 ha_alert("parsing [%s:%d]: %s %s reuses same custom id as %s %s (declared at %s:%d).\n",
751 file, linenum, proxy_type_str(curproxy), curproxy->id,
752 proxy_type_str(target), target->id, target->conf.file, target->conf.line);
753 err_code |= ERR_ALERT | ERR_FATAL;
754 goto out;
755 }
756 eb32_insert(&used_proxy_id, &curproxy->conf.id);
757 }
758 else if (!strcmp(args[0], "description")) {
759 int i, len=0;
760 char *d;
761
762 if (curproxy == &defproxy) {
763 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n",
764 file, linenum, args[0]);
765 err_code |= ERR_ALERT | ERR_FATAL;
766 goto out;
767 }
768
769 if (!*args[1]) {
770 ha_alert("parsing [%s:%d]: '%s' expects a string argument.\n",
771 file, linenum, args[0]);
772 return -1;
773 }
774
775 for (i = 1; *args[i]; i++)
776 len += strlen(args[i]) + 1;
777
778 d = calloc(1, len);
779 curproxy->desc = d;
780
781 d += snprintf(d, curproxy->desc + len - d, "%s", args[1]);
782 for (i = 2; *args[i]; i++)
783 d += snprintf(d, curproxy->desc + len - d, " %s", args[i]);
784
785 }
786 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
787 if (alertif_too_many_args(0, file, linenum, args, &err_code))
788 goto out;
789 curproxy->state = PR_STSTOPPED;
790 }
791 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
792 if (alertif_too_many_args(0, file, linenum, args, &err_code))
793 goto out;
794 curproxy->state = PR_STNEW;
795 }
796 else if (!strcmp(args[0], "bind-process")) { /* enable this proxy only on some processes */
797 int cur_arg = 1;
798 unsigned long set = 0;
799
800 while (*args[cur_arg]) {
801 if (strcmp(args[cur_arg], "all") == 0) {
802 set = 0;
803 break;
804 }
Willy Tarreauff9c9142019-02-07 10:39:36 +0100805 if (parse_process_number(args[cur_arg], &set, MAX_PROCS, NULL, &errmsg)) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100806 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
807 err_code |= ERR_ALERT | ERR_FATAL;
808 goto out;
809 }
810 cur_arg++;
811 }
812 curproxy->bind_proc = set;
813 }
814 else if (!strcmp(args[0], "acl")) { /* add an ACL */
815 if (curproxy == &defproxy) {
816 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
817 err_code |= ERR_ALERT | ERR_FATAL;
818 goto out;
819 }
820
821 err = invalid_char(args[1]);
822 if (err) {
823 ha_alert("parsing [%s:%d] : character '%c' is not permitted in acl name '%s'.\n",
824 file, linenum, *err, args[1]);
825 err_code |= ERR_ALERT | ERR_FATAL;
826 goto out;
827 }
828
Tim Duesterhus0cf811a2020-02-05 21:00:50 +0100829 if (strcasecmp(args[1], "or") == 0) {
Tim Duesterhusf1bc24c2020-02-06 22:04:03 +0100830 ha_alert("parsing [%s:%d] : acl name '%s' will never match. 'or' is used to express a "
Tim Duesterhus0cf811a2020-02-05 21:00:50 +0100831 "logical disjunction within a condition.\n",
832 file, linenum, args[1]);
833 err_code |= ERR_ALERT | ERR_FATAL;
834 goto out;
835 }
836
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100837 if (parse_acl((const char **)args + 1, &curproxy->acl, &errmsg, &curproxy->conf.args, file, linenum) == NULL) {
838 ha_alert("parsing [%s:%d] : error detected while parsing ACL '%s' : %s.\n",
839 file, linenum, args[1], errmsg);
840 err_code |= ERR_ALERT | ERR_FATAL;
841 goto out;
842 }
843 }
844 else if (!strcmp(args[0], "dynamic-cookie-key")) { /* Dynamic cookies secret key */
845
846 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
847 err_code |= ERR_WARN;
848
849 if (*(args[1]) == 0) {
850 ha_alert("parsing [%s:%d] : '%s' expects <secret_key> as argument.\n",
851 file, linenum, args[0]);
852 err_code |= ERR_ALERT | ERR_FATAL;
853 goto out;
854 }
855 free(curproxy->dyncookie_key);
856 curproxy->dyncookie_key = strdup(args[1]);
857 }
858 else if (!strcmp(args[0], "cookie")) { /* cookie name */
859 int cur_arg;
860
861 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
862 err_code |= ERR_WARN;
863
864 if (*(args[1]) == 0) {
865 ha_alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
866 file, linenum, args[0]);
867 err_code |= ERR_ALERT | ERR_FATAL;
868 goto out;
869 }
870
871 curproxy->ck_opts = 0;
872 curproxy->cookie_maxidle = curproxy->cookie_maxlife = 0;
873 free(curproxy->cookie_domain); curproxy->cookie_domain = NULL;
874 free(curproxy->cookie_name);
875 curproxy->cookie_name = strdup(args[1]);
876 curproxy->cookie_len = strlen(curproxy->cookie_name);
877
878 cur_arg = 2;
879 while (*(args[cur_arg])) {
880 if (!strcmp(args[cur_arg], "rewrite")) {
881 curproxy->ck_opts |= PR_CK_RW;
882 }
883 else if (!strcmp(args[cur_arg], "indirect")) {
884 curproxy->ck_opts |= PR_CK_IND;
885 }
886 else if (!strcmp(args[cur_arg], "insert")) {
887 curproxy->ck_opts |= PR_CK_INS;
888 }
889 else if (!strcmp(args[cur_arg], "nocache")) {
890 curproxy->ck_opts |= PR_CK_NOC;
891 }
892 else if (!strcmp(args[cur_arg], "postonly")) {
893 curproxy->ck_opts |= PR_CK_POST;
894 }
895 else if (!strcmp(args[cur_arg], "preserve")) {
896 curproxy->ck_opts |= PR_CK_PSV;
897 }
898 else if (!strcmp(args[cur_arg], "prefix")) {
899 curproxy->ck_opts |= PR_CK_PFX;
900 }
901 else if (!strcmp(args[cur_arg], "httponly")) {
902 curproxy->ck_opts |= PR_CK_HTTPONLY;
903 }
904 else if (!strcmp(args[cur_arg], "secure")) {
905 curproxy->ck_opts |= PR_CK_SECURE;
906 }
907 else if (!strcmp(args[cur_arg], "domain")) {
908 if (!*args[cur_arg + 1]) {
909 ha_alert("parsing [%s:%d]: '%s' expects <domain> as argument.\n",
910 file, linenum, args[cur_arg]);
911 err_code |= ERR_ALERT | ERR_FATAL;
912 goto out;
913 }
914
Joao Moraise1583752019-10-30 21:04:00 -0300915 if (!strchr(args[cur_arg + 1], '.')) {
916 /* rfc6265, 5.2.3 The Domain Attribute */
917 ha_warning("parsing [%s:%d]: domain '%s' contains no embedded dot,"
918 " this configuration may not work properly (see RFC6265#5.2.3).\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100919 file, linenum, args[cur_arg + 1]);
920 err_code |= ERR_WARN;
921 }
922
923 err = invalid_domainchar(args[cur_arg + 1]);
924 if (err) {
925 ha_alert("parsing [%s:%d]: character '%c' is not permitted in domain name '%s'.\n",
926 file, linenum, *err, args[cur_arg + 1]);
927 err_code |= ERR_ALERT | ERR_FATAL;
928 goto out;
929 }
930
931 if (!curproxy->cookie_domain) {
932 curproxy->cookie_domain = strdup(args[cur_arg + 1]);
933 } else {
934 /* one domain was already specified, add another one by
935 * building the string which will be returned along with
936 * the cookie.
937 */
938 char *new_ptr;
939 int new_len = strlen(curproxy->cookie_domain) +
940 strlen("; domain=") + strlen(args[cur_arg + 1]) + 1;
941 new_ptr = malloc(new_len);
942 snprintf(new_ptr, new_len, "%s; domain=%s", curproxy->cookie_domain, args[cur_arg+1]);
943 free(curproxy->cookie_domain);
944 curproxy->cookie_domain = new_ptr;
945 }
946 cur_arg++;
947 }
948 else if (!strcmp(args[cur_arg], "maxidle")) {
949 unsigned int maxidle;
950 const char *res;
951
952 if (!*args[cur_arg + 1]) {
953 ha_alert("parsing [%s:%d]: '%s' expects <idletime> in seconds as argument.\n",
954 file, linenum, args[cur_arg]);
955 err_code |= ERR_ALERT | ERR_FATAL;
956 goto out;
957 }
958
959 res = parse_time_err(args[cur_arg + 1], &maxidle, TIME_UNIT_S);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200960 if (res == PARSE_TIME_OVER) {
961 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 s (~68 years).\n",
962 file, linenum, args[cur_arg+1], args[cur_arg]);
963 err_code |= ERR_ALERT | ERR_FATAL;
964 goto out;
965 }
966 else if (res == PARSE_TIME_UNDER) {
967 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 s.\n",
968 file, linenum, args[cur_arg+1], args[cur_arg]);
969 err_code |= ERR_ALERT | ERR_FATAL;
970 goto out;
971 }
972 else if (res) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100973 ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
974 file, linenum, *res, args[cur_arg]);
975 err_code |= ERR_ALERT | ERR_FATAL;
976 goto out;
977 }
978 curproxy->cookie_maxidle = maxidle;
979 cur_arg++;
980 }
981 else if (!strcmp(args[cur_arg], "maxlife")) {
982 unsigned int maxlife;
983 const char *res;
984
985 if (!*args[cur_arg + 1]) {
986 ha_alert("parsing [%s:%d]: '%s' expects <lifetime> in seconds as argument.\n",
987 file, linenum, args[cur_arg]);
988 err_code |= ERR_ALERT | ERR_FATAL;
989 goto out;
990 }
991
Willy Tarreau9faebe32019-06-07 19:00:37 +0200992
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100993 res = parse_time_err(args[cur_arg + 1], &maxlife, TIME_UNIT_S);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200994 if (res == PARSE_TIME_OVER) {
995 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 s (~68 years).\n",
996 file, linenum, args[cur_arg+1], args[cur_arg]);
997 err_code |= ERR_ALERT | ERR_FATAL;
998 goto out;
999 }
1000 else if (res == PARSE_TIME_UNDER) {
1001 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 s.\n",
1002 file, linenum, args[cur_arg+1], args[cur_arg]);
1003 err_code |= ERR_ALERT | ERR_FATAL;
1004 goto out;
1005 }
1006 else if (res) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001007 ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
1008 file, linenum, *res, args[cur_arg]);
1009 err_code |= ERR_ALERT | ERR_FATAL;
1010 goto out;
1011 }
1012 curproxy->cookie_maxlife = maxlife;
1013 cur_arg++;
1014 }
1015 else if (!strcmp(args[cur_arg], "dynamic")) { /* Dynamic persistent cookies secret key */
1016
1017 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[cur_arg], NULL))
1018 err_code |= ERR_WARN;
1019 curproxy->ck_opts |= PR_CK_DYNAMIC;
1020 }
Christopher Faulet2f533902020-01-21 11:06:48 +01001021 else if (!strcmp(args[cur_arg], "attr")) {
1022 char *val;
1023 if (!*args[cur_arg + 1]) {
1024 ha_alert("parsing [%s:%d]: '%s' expects <value> as argument.\n",
1025 file, linenum, args[cur_arg]);
1026 err_code |= ERR_ALERT | ERR_FATAL;
1027 goto out;
1028 }
1029 val = args[cur_arg + 1];
1030 while (*val) {
Willy Tarreau90807112020-02-25 08:16:33 +01001031 if (iscntrl((unsigned char)*val) || *val == ';') {
Christopher Faulet2f533902020-01-21 11:06:48 +01001032 ha_alert("parsing [%s:%d]: character '%%x%02X' is not permitted in attribute value.\n",
1033 file, linenum, *val);
1034 err_code |= ERR_ALERT | ERR_FATAL;
1035 goto out;
1036 }
1037 val++;
1038 }
1039 /* don't add ';' for the first attribute */
1040 if (!curproxy->cookie_attrs)
1041 curproxy->cookie_attrs = strdup(args[cur_arg + 1]);
1042 else
1043 memprintf(&curproxy->cookie_attrs, "%s; %s", curproxy->cookie_attrs, args[cur_arg + 1]);
1044 cur_arg++;
1045 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001046
1047 else {
Christopher Faulet2f533902020-01-21 11:06:48 +01001048 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 +01001049 file, linenum, args[0]);
1050 err_code |= ERR_ALERT | ERR_FATAL;
1051 goto out;
1052 }
1053 cur_arg++;
1054 }
1055 if (!POWEROF2(curproxy->ck_opts & (PR_CK_RW|PR_CK_IND))) {
1056 ha_alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
1057 file, linenum);
1058 err_code |= ERR_ALERT | ERR_FATAL;
1059 }
1060
1061 if (!POWEROF2(curproxy->ck_opts & (PR_CK_RW|PR_CK_INS|PR_CK_PFX))) {
1062 ha_alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
1063 file, linenum);
1064 err_code |= ERR_ALERT | ERR_FATAL;
1065 }
1066
1067 if ((curproxy->ck_opts & (PR_CK_PSV | PR_CK_INS | PR_CK_IND)) == PR_CK_PSV) {
1068 ha_alert("parsing [%s:%d] : cookie 'preserve' requires at least 'insert' or 'indirect'.\n",
1069 file, linenum);
1070 err_code |= ERR_ALERT | ERR_FATAL;
1071 }
1072 }/* end else if (!strcmp(args[0], "cookie")) */
1073 else if (!strcmp(args[0], "email-alert")) {
1074 if (*(args[1]) == 0) {
1075 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1076 file, linenum, args[0]);
1077 err_code |= ERR_ALERT | ERR_FATAL;
1078 goto out;
1079 }
1080
1081 if (!strcmp(args[1], "from")) {
1082 if (*(args[1]) == 0) {
1083 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1084 file, linenum, args[1]);
1085 err_code |= ERR_ALERT | ERR_FATAL;
1086 goto out;
1087 }
1088 free(curproxy->email_alert.from);
1089 curproxy->email_alert.from = strdup(args[2]);
1090 }
1091 else if (!strcmp(args[1], "mailers")) {
1092 if (*(args[1]) == 0) {
1093 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1094 file, linenum, args[1]);
1095 err_code |= ERR_ALERT | ERR_FATAL;
1096 goto out;
1097 }
1098 free(curproxy->email_alert.mailers.name);
1099 curproxy->email_alert.mailers.name = strdup(args[2]);
1100 }
1101 else if (!strcmp(args[1], "myhostname")) {
1102 if (*(args[1]) == 0) {
1103 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1104 file, linenum, args[1]);
1105 err_code |= ERR_ALERT | ERR_FATAL;
1106 goto out;
1107 }
1108 free(curproxy->email_alert.myhostname);
1109 curproxy->email_alert.myhostname = strdup(args[2]);
1110 }
1111 else if (!strcmp(args[1], "level")) {
1112 curproxy->email_alert.level = get_log_level(args[2]);
1113 if (curproxy->email_alert.level < 0) {
1114 ha_alert("parsing [%s:%d] : unknown log level '%s' after '%s'\n",
1115 file, linenum, args[1], args[2]);
1116 err_code |= ERR_ALERT | ERR_FATAL;
1117 goto out;
1118 }
1119 }
1120 else if (!strcmp(args[1], "to")) {
1121 if (*(args[1]) == 0) {
1122 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1123 file, linenum, args[1]);
1124 err_code |= ERR_ALERT | ERR_FATAL;
1125 goto out;
1126 }
1127 free(curproxy->email_alert.to);
1128 curproxy->email_alert.to = strdup(args[2]);
1129 }
1130 else {
1131 ha_alert("parsing [%s:%d] : email-alert: unknown argument '%s'.\n",
1132 file, linenum, args[1]);
1133 err_code |= ERR_ALERT | ERR_FATAL;
1134 goto out;
1135 }
1136 /* Indicate that the email_alert is at least partially configured */
1137 curproxy->email_alert.set = 1;
1138 }/* end else if (!strcmp(args[0], "email-alert")) */
1139 else if (!strcmp(args[0], "external-check")) {
1140 if (*(args[1]) == 0) {
1141 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1142 file, linenum, args[0]);
1143 err_code |= ERR_ALERT | ERR_FATAL;
1144 goto out;
1145 }
1146
1147 if (!strcmp(args[1], "command")) {
1148 if (alertif_too_many_args(2, file, linenum, args, &err_code))
1149 goto out;
1150 if (*(args[2]) == 0) {
1151 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1152 file, linenum, args[1]);
1153 err_code |= ERR_ALERT | ERR_FATAL;
1154 goto out;
1155 }
1156 free(curproxy->check_command);
1157 curproxy->check_command = strdup(args[2]);
1158 }
1159 else if (!strcmp(args[1], "path")) {
1160 if (alertif_too_many_args(2, file, linenum, args, &err_code))
1161 goto out;
1162 if (*(args[2]) == 0) {
1163 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1164 file, linenum, args[1]);
1165 err_code |= ERR_ALERT | ERR_FATAL;
1166 goto out;
1167 }
1168 free(curproxy->check_path);
1169 curproxy->check_path = strdup(args[2]);
1170 }
1171 else {
1172 ha_alert("parsing [%s:%d] : external-check: unknown argument '%s'.\n",
1173 file, linenum, args[1]);
1174 err_code |= ERR_ALERT | ERR_FATAL;
1175 goto out;
1176 }
1177 }/* end else if (!strcmp(args[0], "external-check")) */
1178 else if (!strcmp(args[0], "persist")) { /* persist */
1179 if (*(args[1]) == 0) {
1180 ha_alert("parsing [%s:%d] : missing persist method.\n",
1181 file, linenum);
1182 err_code |= ERR_ALERT | ERR_FATAL;
1183 goto out;
1184 }
1185
1186 if (!strncmp(args[1], "rdp-cookie", 10)) {
1187 curproxy->options2 |= PR_O2_RDPC_PRST;
1188
1189 if (*(args[1] + 10) == '(') { /* cookie name */
1190 const char *beg, *end;
1191
1192 beg = args[1] + 11;
1193 end = strchr(beg, ')');
1194
1195 if (alertif_too_many_args(1, file, linenum, args, &err_code))
1196 goto out;
1197
1198 if (!end || end == beg) {
1199 ha_alert("parsing [%s:%d] : persist rdp-cookie(name)' requires an rdp cookie name.\n",
1200 file, linenum);
1201 err_code |= ERR_ALERT | ERR_FATAL;
1202 goto out;
1203 }
1204
1205 free(curproxy->rdp_cookie_name);
1206 curproxy->rdp_cookie_name = my_strndup(beg, end - beg);
1207 curproxy->rdp_cookie_len = end-beg;
1208 }
1209 else if (*(args[1] + 10) == '\0') { /* default cookie name 'msts' */
1210 free(curproxy->rdp_cookie_name);
1211 curproxy->rdp_cookie_name = strdup("msts");
1212 curproxy->rdp_cookie_len = strlen(curproxy->rdp_cookie_name);
1213 }
1214 else { /* syntax */
1215 ha_alert("parsing [%s:%d] : persist rdp-cookie(name)' requires an rdp cookie name.\n",
1216 file, linenum);
1217 err_code |= ERR_ALERT | ERR_FATAL;
1218 goto out;
1219 }
1220 }
1221 else {
1222 ha_alert("parsing [%s:%d] : unknown persist method.\n",
1223 file, linenum);
1224 err_code |= ERR_ALERT | ERR_FATAL;
1225 goto out;
1226 }
1227 }
1228 else if (!strcmp(args[0], "appsession")) { /* cookie name */
Tim Duesterhus473c2832019-05-06 01:19:52 +02001229 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 +01001230 err_code |= ERR_ALERT | ERR_FATAL;
1231 goto out;
1232 }
1233 else if (!strcmp(args[0], "load-server-state-from-file")) {
1234 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1235 err_code |= ERR_WARN;
1236 if (!strcmp(args[1], "global")) { /* use the file pointed to by global server-state-file directive */
1237 curproxy->load_server_state_from_file = PR_SRV_STATE_FILE_GLOBAL;
1238 }
1239 else if (!strcmp(args[1], "local")) { /* use the server-state-file-name variable to locate the server-state file */
1240 curproxy->load_server_state_from_file = PR_SRV_STATE_FILE_LOCAL;
1241 }
1242 else if (!strcmp(args[1], "none")) { /* don't use server-state-file directive for this backend */
1243 curproxy->load_server_state_from_file = PR_SRV_STATE_FILE_NONE;
1244 }
1245 else {
1246 ha_alert("parsing [%s:%d] : '%s' expects 'global', 'local' or 'none'. Got '%s'\n",
1247 file, linenum, args[0], args[1]);
1248 err_code |= ERR_ALERT | ERR_FATAL;
1249 goto out;
1250 }
1251 }
1252 else if (!strcmp(args[0], "server-state-file-name")) {
1253 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1254 err_code |= ERR_WARN;
1255 if (*(args[1]) == 0) {
1256 ha_alert("parsing [%s:%d] : '%s' expects 'use-backend-name' or a string. Got no argument\n",
1257 file, linenum, args[0]);
1258 err_code |= ERR_ALERT | ERR_FATAL;
1259 goto out;
1260 }
1261 else if (!strcmp(args[1], "use-backend-name"))
1262 curproxy->server_state_file_name = strdup(curproxy->id);
1263 else
1264 curproxy->server_state_file_name = strdup(args[1]);
1265 }
Olivier Houcharda4d4fdf2018-12-14 19:27:06 +01001266 else if (!strcmp(args[0], "max-session-srv-conns")) {
1267 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1268 err_code |= ERR_WARN;
1269 if (*(args[1]) == 0) {
1270 ha_alert("parsine [%s:%d] : '%s' expects a number. Got no argument\n",
1271 file, linenum, args[0]);
1272 err_code |= ERR_ALERT | ERR_FATAL;
1273 goto out;
1274 }
1275 curproxy->max_out_conns = atoi(args[1]);
1276 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001277 else if (!strcmp(args[0], "capture")) {
1278 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1279 err_code |= ERR_WARN;
1280
1281 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
1282 if (curproxy == &defproxy) {
1283 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1284 err_code |= ERR_ALERT | ERR_FATAL;
1285 goto out;
1286 }
1287
1288 if (alertif_too_many_args_idx(4, 1, file, linenum, args, &err_code))
1289 goto out;
1290
1291 if (*(args[4]) == 0) {
1292 ha_alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
1293 file, linenum, args[0]);
1294 err_code |= ERR_ALERT | ERR_FATAL;
1295 goto out;
1296 }
1297 free(curproxy->capture_name);
1298 curproxy->capture_name = strdup(args[2]);
1299 curproxy->capture_namelen = strlen(curproxy->capture_name);
1300 curproxy->capture_len = atol(args[4]);
1301 curproxy->to_log |= LW_COOKIE;
1302 }
1303 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
1304 struct cap_hdr *hdr;
1305
1306 if (curproxy == &defproxy) {
1307 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1308 err_code |= ERR_ALERT | ERR_FATAL;
1309 goto out;
1310 }
1311
1312 if (alertif_too_many_args_idx(4, 1, file, linenum, args, &err_code))
1313 goto out;
1314
1315 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
1316 ha_alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
1317 file, linenum, args[0], args[1]);
1318 err_code |= ERR_ALERT | ERR_FATAL;
1319 goto out;
1320 }
1321
1322 hdr = calloc(1, sizeof(*hdr));
1323 hdr->next = curproxy->req_cap;
1324 hdr->name = strdup(args[3]);
1325 hdr->namelen = strlen(args[3]);
1326 hdr->len = atol(args[5]);
1327 hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
1328 hdr->index = curproxy->nb_req_cap++;
1329 curproxy->req_cap = hdr;
1330 curproxy->to_log |= LW_REQHDR;
1331 }
1332 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
1333 struct cap_hdr *hdr;
1334
1335 if (curproxy == &defproxy) {
1336 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1337 err_code |= ERR_ALERT | ERR_FATAL;
1338 goto out;
1339 }
1340
1341 if (alertif_too_many_args_idx(4, 1, file, linenum, args, &err_code))
1342 goto out;
1343
1344 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
1345 ha_alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
1346 file, linenum, args[0], args[1]);
1347 err_code |= ERR_ALERT | ERR_FATAL;
1348 goto out;
1349 }
1350 hdr = calloc(1, sizeof(*hdr));
1351 hdr->next = curproxy->rsp_cap;
1352 hdr->name = strdup(args[3]);
1353 hdr->namelen = strlen(args[3]);
1354 hdr->len = atol(args[5]);
1355 hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
1356 hdr->index = curproxy->nb_rsp_cap++;
1357 curproxy->rsp_cap = hdr;
1358 curproxy->to_log |= LW_RSPHDR;
1359 }
1360 else {
1361 ha_alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
1362 file, linenum, args[0]);
1363 err_code |= ERR_ALERT | ERR_FATAL;
1364 goto out;
1365 }
1366 }
1367 else if (!strcmp(args[0], "retries")) { /* connection retries */
1368 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1369 err_code |= ERR_WARN;
1370
1371 if (alertif_too_many_args(1, file, linenum, args, &err_code))
1372 goto out;
1373
1374 if (*(args[1]) == 0) {
1375 ha_alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
1376 file, linenum, args[0]);
1377 err_code |= ERR_ALERT | ERR_FATAL;
1378 goto out;
1379 }
1380 curproxy->conn_retries = atol(args[1]);
1381 }
1382 else if (!strcmp(args[0], "http-request")) { /* request access control: allow/deny/auth */
1383 struct act_rule *rule;
1384
1385 if (curproxy == &defproxy) {
1386 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1387 err_code |= ERR_ALERT | ERR_FATAL;
1388 goto out;
1389 }
1390
1391 if (!LIST_ISEMPTY(&curproxy->http_req_rules) &&
1392 !LIST_PREV(&curproxy->http_req_rules, struct act_rule *, list)->cond &&
Christopher Faulet245cf792019-12-18 14:58:12 +01001393 (LIST_PREV(&curproxy->http_req_rules, struct act_rule *, list)->flags & ACT_FLAG_FINAL)) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001394 ha_warning("parsing [%s:%d]: previous '%s' action is final and has no condition attached, further entries are NOOP.\n",
1395 file, linenum, args[0]);
1396 err_code |= ERR_WARN;
1397 }
1398
1399 rule = parse_http_req_cond((const char **)args + 1, file, linenum, curproxy);
1400
1401 if (!rule) {
1402 err_code |= ERR_ALERT | ERR_ABORT;
1403 goto out;
1404 }
1405
1406 err_code |= warnif_misplaced_http_req(curproxy, file, linenum, args[0]);
1407 err_code |= warnif_cond_conflicts(rule->cond,
1408 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1409 file, linenum);
1410
1411 LIST_ADDQ(&curproxy->http_req_rules, &rule->list);
1412 }
1413 else if (!strcmp(args[0], "http-response")) { /* response access control */
1414 struct act_rule *rule;
1415
1416 if (curproxy == &defproxy) {
1417 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1418 err_code |= ERR_ALERT | ERR_FATAL;
1419 goto out;
1420 }
1421
1422 if (!LIST_ISEMPTY(&curproxy->http_res_rules) &&
1423 !LIST_PREV(&curproxy->http_res_rules, struct act_rule *, list)->cond &&
Christopher Faulet245cf792019-12-18 14:58:12 +01001424 (LIST_PREV(&curproxy->http_res_rules, struct act_rule *, list)->flags & ACT_FLAG_FINAL)) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001425 ha_warning("parsing [%s:%d]: previous '%s' action is final and has no condition attached, further entries are NOOP.\n",
1426 file, linenum, args[0]);
1427 err_code |= ERR_WARN;
1428 }
1429
1430 rule = parse_http_res_cond((const char **)args + 1, file, linenum, curproxy);
1431
1432 if (!rule) {
1433 err_code |= ERR_ALERT | ERR_ABORT;
1434 goto out;
1435 }
1436
1437 err_code |= warnif_cond_conflicts(rule->cond,
1438 (curproxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
1439 file, linenum);
1440
1441 LIST_ADDQ(&curproxy->http_res_rules, &rule->list);
1442 }
Christopher Faulet6d0c3df2020-01-22 09:26:35 +01001443 else if (!strcmp(args[0], "http-after-response")) {
1444 struct act_rule *rule;
1445
1446 if (curproxy == &defproxy) {
1447 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1448 err_code |= ERR_ALERT | ERR_FATAL;
1449 goto out;
1450 }
1451
1452 if (!LIST_ISEMPTY(&curproxy->http_after_res_rules) &&
1453 !LIST_PREV(&curproxy->http_after_res_rules, struct act_rule *, list)->cond &&
1454 (LIST_PREV(&curproxy->http_after_res_rules, struct act_rule *, list)->flags & ACT_FLAG_FINAL)) {
1455 ha_warning("parsing [%s:%d]: previous '%s' action is final and has no condition attached, further entries are NOOP.\n",
1456 file, linenum, args[0]);
1457 err_code |= ERR_WARN;
1458 }
1459
1460 rule = parse_http_after_res_cond((const char **)args + 1, file, linenum, curproxy);
1461
1462 if (!rule) {
1463 err_code |= ERR_ALERT | ERR_ABORT;
1464 goto out;
1465 }
1466
1467 err_code |= warnif_cond_conflicts(rule->cond,
1468 (curproxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
1469 file, linenum);
1470
1471 LIST_ADDQ(&curproxy->http_after_res_rules, &rule->list);
1472 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001473 else if (!strcmp(args[0], "http-send-name-header")) { /* send server name in request header */
1474 /* set the header name and length into the proxy structure */
1475 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1476 err_code |= ERR_WARN;
1477
1478 if (!*args[1]) {
1479 ha_alert("parsing [%s:%d] : '%s' requires a header string.\n",
1480 file, linenum, args[0]);
1481 err_code |= ERR_ALERT | ERR_FATAL;
1482 goto out;
1483 }
1484
Christopher Fauletdabcc8e2019-10-02 10:45:55 +02001485 /* set the desired header name, in lower case */
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001486 free(curproxy->server_id_hdr_name);
1487 curproxy->server_id_hdr_name = strdup(args[1]);
1488 curproxy->server_id_hdr_len = strlen(curproxy->server_id_hdr_name);
Christopher Fauletdabcc8e2019-10-02 10:45:55 +02001489 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 +01001490 }
Tim Duesterhus7b7c47f2019-05-14 20:57:57 +02001491 else if (!strcmp(args[0], "block")) {
1492 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 +01001493
Tim Duesterhus7b7c47f2019-05-14 20:57:57 +02001494 err_code |= ERR_ALERT | ERR_FATAL;
1495 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001496 }
1497 else if (!strcmp(args[0], "redirect")) {
1498 struct redirect_rule *rule;
1499
1500 if (curproxy == &defproxy) {
1501 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1502 err_code |= ERR_ALERT | ERR_FATAL;
1503 goto out;
1504 }
1505
1506 if ((rule = http_parse_redirect_rule(file, linenum, curproxy, (const char **)args + 1, &errmsg, 0, 0)) == NULL) {
1507 ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing redirect rule : %s.\n",
1508 file, linenum, proxy_type_str(curproxy), curproxy->id, errmsg);
1509 err_code |= ERR_ALERT | ERR_FATAL;
1510 goto out;
1511 }
1512
1513 LIST_ADDQ(&curproxy->redirect_rules, &rule->list);
1514 err_code |= warnif_misplaced_redirect(curproxy, file, linenum, args[0]);
1515 err_code |= warnif_cond_conflicts(rule->cond,
1516 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1517 file, linenum);
1518 }
1519 else if (!strcmp(args[0], "use_backend")) {
1520 struct switching_rule *rule;
1521
1522 if (curproxy == &defproxy) {
1523 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1524 err_code |= ERR_ALERT | ERR_FATAL;
1525 goto out;
1526 }
1527
1528 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1529 err_code |= ERR_WARN;
1530
1531 if (*(args[1]) == 0) {
1532 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
1533 err_code |= ERR_ALERT | ERR_FATAL;
1534 goto out;
1535 }
1536
1537 if (strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0) {
1538 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1539 ha_alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
1540 file, linenum, errmsg);
1541 err_code |= ERR_ALERT | ERR_FATAL;
1542 goto out;
1543 }
1544
1545 err_code |= warnif_cond_conflicts(cond, SMP_VAL_FE_SET_BCK, file, linenum);
1546 }
1547 else if (*args[2]) {
1548 ha_alert("parsing [%s:%d] : unexpected keyword '%s' after switching rule, only 'if' and 'unless' are allowed.\n",
1549 file, linenum, args[2]);
1550 err_code |= ERR_ALERT | ERR_FATAL;
1551 goto out;
1552 }
1553
1554 rule = calloc(1, sizeof(*rule));
1555 if (!rule) {
1556 ha_alert("Out of memory error.\n");
1557 goto out;
1558 }
1559 rule->cond = cond;
1560 rule->be.name = strdup(args[1]);
1561 rule->line = linenum;
1562 rule->file = strdup(file);
1563 if (!rule->file) {
1564 ha_alert("Out of memory error.\n");
1565 goto out;
1566 }
1567 LIST_INIT(&rule->list);
1568 LIST_ADDQ(&curproxy->switching_rules, &rule->list);
1569 }
1570 else if (strcmp(args[0], "use-server") == 0) {
1571 struct server_rule *rule;
1572
1573 if (curproxy == &defproxy) {
1574 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1575 err_code |= ERR_ALERT | ERR_FATAL;
1576 goto out;
1577 }
1578
1579 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1580 err_code |= ERR_WARN;
1581
1582 if (*(args[1]) == 0) {
1583 ha_alert("parsing [%s:%d] : '%s' expects a server name.\n", file, linenum, args[0]);
1584 err_code |= ERR_ALERT | ERR_FATAL;
1585 goto out;
1586 }
1587
1588 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
1589 ha_alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1590 file, linenum, args[0]);
1591 err_code |= ERR_ALERT | ERR_FATAL;
1592 goto out;
1593 }
1594
1595 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1596 ha_alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
1597 file, linenum, errmsg);
1598 err_code |= ERR_ALERT | ERR_FATAL;
1599 goto out;
1600 }
1601
1602 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, file, linenum);
1603
1604 rule = calloc(1, sizeof(*rule));
1605 rule->cond = cond;
1606 rule->srv.name = strdup(args[1]);
Jerome Magnin824186b2020-03-29 09:37:12 +02001607 rule->line = linenum;
1608 rule->file = strdup(file);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001609 LIST_INIT(&rule->list);
1610 LIST_ADDQ(&curproxy->server_rules, &rule->list);
1611 curproxy->be_req_ana |= AN_REQ_SRV_RULES;
1612 }
1613 else if ((!strcmp(args[0], "force-persist")) ||
1614 (!strcmp(args[0], "ignore-persist"))) {
1615 struct persist_rule *rule;
1616
1617 if (curproxy == &defproxy) {
1618 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1619 err_code |= ERR_ALERT | ERR_FATAL;
1620 goto out;
1621 }
1622
1623 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1624 err_code |= ERR_WARN;
1625
1626 if (strcmp(args[1], "if") != 0 && strcmp(args[1], "unless") != 0) {
1627 ha_alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1628 file, linenum, args[0]);
1629 err_code |= ERR_ALERT | ERR_FATAL;
1630 goto out;
1631 }
1632
1633 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 1, &errmsg)) == NULL) {
1634 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' rule : %s.\n",
1635 file, linenum, args[0], errmsg);
1636 err_code |= ERR_ALERT | ERR_FATAL;
1637 goto out;
1638 }
1639
1640 /* note: BE_REQ_CNT is the first one after FE_SET_BCK, which is
1641 * where force-persist is applied.
1642 */
1643 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_REQ_CNT, file, linenum);
1644
1645 rule = calloc(1, sizeof(*rule));
1646 rule->cond = cond;
1647 if (!strcmp(args[0], "force-persist")) {
1648 rule->type = PERSIST_TYPE_FORCE;
1649 } else {
1650 rule->type = PERSIST_TYPE_IGNORE;
1651 }
1652 LIST_INIT(&rule->list);
1653 LIST_ADDQ(&curproxy->persist_rules, &rule->list);
1654 }
1655 else if (!strcmp(args[0], "stick-table")) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001656 struct stktable *other;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001657
1658 if (curproxy == &defproxy) {
1659 ha_alert("parsing [%s:%d] : 'stick-table' is not supported in 'defaults' section.\n",
1660 file, linenum);
1661 err_code |= ERR_ALERT | ERR_FATAL;
1662 goto out;
1663 }
1664
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001665 other = stktable_find_by_name(curproxy->id);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001666 if (other) {
1667 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 +01001668 file, linenum, curproxy->id,
1669 other->proxy ? proxy_cap_str(other->proxy->cap) : "peers",
1670 other->proxy ? other->id : other->peers.p->id,
1671 other->conf.file, other->conf.line);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001672 err_code |= ERR_ALERT | ERR_FATAL;
1673 goto out;
1674 }
1675
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001676 curproxy->table = calloc(1, sizeof *curproxy->table);
1677 if (!curproxy->table) {
1678 ha_alert("parsing [%s:%d]: '%s %s' : memory allocation failed\n",
1679 file, linenum, args[0], args[1]);
1680 err_code |= ERR_ALERT | ERR_FATAL;
1681 goto out;
1682 }
1683
Frédéric Lécaillec02766a2019-03-20 15:06:55 +01001684 err_code |= parse_stick_table(file, linenum, args, curproxy->table,
1685 curproxy->id, curproxy->id, NULL);
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001686 if (err_code & ERR_FATAL)
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001687 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001688
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001689 /* Store the proxy in the stick-table. */
1690 curproxy->table->proxy = curproxy;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001691
1692 stktable_store_name(curproxy->table);
1693 curproxy->table->next = stktables_list;
1694 stktables_list = curproxy->table;
Frédéric Lécaille015e4d72019-03-19 14:55:01 +01001695
1696 /* Add this proxy to the list of proxies which refer to its stick-table. */
1697 if (curproxy->table->proxies_list != curproxy) {
1698 curproxy->next_stkt_ref = curproxy->table->proxies_list;
1699 curproxy->table->proxies_list = curproxy;
1700 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001701 }
1702 else if (!strcmp(args[0], "stick")) {
1703 struct sticking_rule *rule;
1704 struct sample_expr *expr;
1705 int myidx = 0;
1706 const char *name = NULL;
1707 int flags;
1708
1709 if (curproxy == &defproxy) {
1710 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1711 err_code |= ERR_ALERT | ERR_FATAL;
1712 goto out;
1713 }
1714
1715 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) {
1716 err_code |= ERR_WARN;
1717 goto out;
1718 }
1719
1720 myidx++;
1721 if ((strcmp(args[myidx], "store") == 0) ||
1722 (strcmp(args[myidx], "store-request") == 0)) {
1723 myidx++;
1724 flags = STK_IS_STORE;
1725 }
1726 else if (strcmp(args[myidx], "store-response") == 0) {
1727 myidx++;
1728 flags = STK_IS_STORE | STK_ON_RSP;
1729 }
1730 else if (strcmp(args[myidx], "match") == 0) {
1731 myidx++;
1732 flags = STK_IS_MATCH;
1733 }
1734 else if (strcmp(args[myidx], "on") == 0) {
1735 myidx++;
1736 flags = STK_IS_MATCH | STK_IS_STORE;
1737 }
1738 else {
1739 ha_alert("parsing [%s:%d] : '%s' expects 'on', 'match', or 'store'.\n", file, linenum, args[0]);
1740 err_code |= ERR_ALERT | ERR_FATAL;
1741 goto out;
1742 }
1743
1744 if (*(args[myidx]) == 0) {
1745 ha_alert("parsing [%s:%d] : '%s' expects a fetch method.\n", file, linenum, args[0]);
1746 err_code |= ERR_ALERT | ERR_FATAL;
1747 goto out;
1748 }
1749
1750 curproxy->conf.args.ctx = ARGC_STK;
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01001751 expr = sample_parse_expr(args, &myidx, file, linenum, &errmsg, &curproxy->conf.args, NULL);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001752 if (!expr) {
1753 ha_alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], errmsg);
1754 err_code |= ERR_ALERT | ERR_FATAL;
1755 goto out;
1756 }
1757
1758 if (flags & STK_ON_RSP) {
1759 if (!(expr->fetch->val & SMP_VAL_BE_STO_RUL)) {
1760 ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available for 'store-response'.\n",
1761 file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
1762 err_code |= ERR_ALERT | ERR_FATAL;
1763 free(expr);
1764 goto out;
1765 }
1766 } else {
1767 if (!(expr->fetch->val & SMP_VAL_BE_SET_SRV)) {
1768 ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available during request.\n",
1769 file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
1770 err_code |= ERR_ALERT | ERR_FATAL;
1771 free(expr);
1772 goto out;
1773 }
1774 }
1775
Christopher Faulet711ed6a2019-07-16 14:16:10 +02001776 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001777 curproxy->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
1778
1779 if (strcmp(args[myidx], "table") == 0) {
1780 myidx++;
1781 name = args[myidx++];
1782 }
1783
1784 if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) {
1785 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + myidx, &errmsg)) == NULL) {
1786 ha_alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition : %s.\n",
1787 file, linenum, args[0], errmsg);
1788 err_code |= ERR_ALERT | ERR_FATAL;
1789 free(expr);
1790 goto out;
1791 }
1792 }
1793 else if (*(args[myidx])) {
1794 ha_alert("parsing [%s:%d] : '%s': unknown keyword '%s'.\n",
1795 file, linenum, args[0], args[myidx]);
1796 err_code |= ERR_ALERT | ERR_FATAL;
1797 free(expr);
1798 goto out;
1799 }
1800 if (flags & STK_ON_RSP)
1801 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_STO_RUL, file, linenum);
1802 else
1803 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, file, linenum);
1804
1805 rule = calloc(1, sizeof(*rule));
1806 rule->cond = cond;
1807 rule->expr = expr;
1808 rule->flags = flags;
1809 rule->table.name = name ? strdup(name) : NULL;
1810 LIST_INIT(&rule->list);
1811 if (flags & STK_ON_RSP)
1812 LIST_ADDQ(&curproxy->storersp_rules, &rule->list);
1813 else
1814 LIST_ADDQ(&curproxy->sticking_rules, &rule->list);
1815 }
1816 else if (!strcmp(args[0], "stats")) {
1817 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
1818 curproxy->uri_auth = NULL; /* we must detach from the default config */
1819
1820 if (!*args[1]) {
1821 goto stats_error_parsing;
1822 } else if (!strcmp(args[1], "admin")) {
1823 struct stats_admin_rule *rule;
1824
1825 if (curproxy == &defproxy) {
1826 ha_alert("parsing [%s:%d]: '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1827 err_code |= ERR_ALERT | ERR_FATAL;
1828 goto out;
1829 }
1830
1831 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1832 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1833 err_code |= ERR_ALERT | ERR_ABORT;
1834 goto out;
1835 }
1836
1837 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
1838 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
1839 file, linenum, args[0], args[1]);
1840 err_code |= ERR_ALERT | ERR_FATAL;
1841 goto out;
1842 }
1843 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1844 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' rule : %s.\n",
1845 file, linenum, args[0], args[1], errmsg);
1846 err_code |= ERR_ALERT | ERR_FATAL;
1847 goto out;
1848 }
1849
1850 err_code |= warnif_cond_conflicts(cond,
1851 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1852 file, linenum);
1853
1854 rule = calloc(1, sizeof(*rule));
1855 rule->cond = cond;
1856 LIST_INIT(&rule->list);
1857 LIST_ADDQ(&curproxy->uri_auth->admin_rules, &rule->list);
1858 } else if (!strcmp(args[1], "uri")) {
1859 if (*(args[2]) == 0) {
1860 ha_alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
1861 err_code |= ERR_ALERT | ERR_FATAL;
1862 goto out;
1863 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
1864 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1865 err_code |= ERR_ALERT | ERR_ABORT;
1866 goto out;
1867 }
1868 } else if (!strcmp(args[1], "realm")) {
1869 if (*(args[2]) == 0) {
1870 ha_alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
1871 err_code |= ERR_ALERT | ERR_FATAL;
1872 goto out;
1873 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
1874 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1875 err_code |= ERR_ALERT | ERR_ABORT;
1876 goto out;
1877 }
1878 } else if (!strcmp(args[1], "refresh")) {
1879 unsigned interval;
1880
1881 err = parse_time_err(args[2], &interval, TIME_UNIT_S);
Willy Tarreau9faebe32019-06-07 19:00:37 +02001882 if (err == PARSE_TIME_OVER) {
1883 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to stats refresh interval, maximum value is 2147483647 s (~68 years).\n",
1884 file, linenum, args[2]);
1885 err_code |= ERR_ALERT | ERR_FATAL;
1886 goto out;
1887 }
1888 else if (err == PARSE_TIME_UNDER) {
1889 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to stats refresh interval, minimum non-null value is 1 s.\n",
1890 file, linenum, args[2]);
1891 err_code |= ERR_ALERT | ERR_FATAL;
1892 goto out;
1893 }
1894 else if (err) {
1895 ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to stats refresh interval.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001896 file, linenum, *err);
1897 err_code |= ERR_ALERT | ERR_FATAL;
1898 goto out;
1899 } else if (!stats_set_refresh(&curproxy->uri_auth, interval)) {
1900 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1901 err_code |= ERR_ALERT | ERR_ABORT;
1902 goto out;
1903 }
1904 } else if (!strcmp(args[1], "http-request")) { /* request access control: allow/deny/auth */
1905 struct act_rule *rule;
1906
1907 if (curproxy == &defproxy) {
1908 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1909 err_code |= ERR_ALERT | ERR_FATAL;
1910 goto out;
1911 }
1912
1913 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1914 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1915 err_code |= ERR_ALERT | ERR_ABORT;
1916 goto out;
1917 }
1918
1919 if (!LIST_ISEMPTY(&curproxy->uri_auth->http_req_rules) &&
1920 !LIST_PREV(&curproxy->uri_auth->http_req_rules, struct act_rule *, list)->cond) {
1921 ha_warning("parsing [%s:%d]: previous '%s' action has no condition attached, further entries are NOOP.\n",
1922 file, linenum, args[0]);
1923 err_code |= ERR_WARN;
1924 }
1925
1926 rule = parse_http_req_cond((const char **)args + 2, file, linenum, curproxy);
1927
1928 if (!rule) {
1929 err_code |= ERR_ALERT | ERR_ABORT;
1930 goto out;
1931 }
1932
1933 err_code |= warnif_cond_conflicts(rule->cond,
1934 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1935 file, linenum);
1936 LIST_ADDQ(&curproxy->uri_auth->http_req_rules, &rule->list);
1937
1938 } else if (!strcmp(args[1], "auth")) {
1939 if (*(args[2]) == 0) {
1940 ha_alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
1941 err_code |= ERR_ALERT | ERR_FATAL;
1942 goto out;
1943 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
1944 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1945 err_code |= ERR_ALERT | ERR_ABORT;
1946 goto out;
1947 }
1948 } else if (!strcmp(args[1], "scope")) {
1949 if (*(args[2]) == 0) {
1950 ha_alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
1951 err_code |= ERR_ALERT | ERR_FATAL;
1952 goto out;
1953 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
1954 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1955 err_code |= ERR_ALERT | ERR_ABORT;
1956 goto out;
1957 }
1958 } else if (!strcmp(args[1], "enable")) {
1959 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1960 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1961 err_code |= ERR_ALERT | ERR_ABORT;
1962 goto out;
1963 }
1964 } else if (!strcmp(args[1], "hide-version")) {
Willy Tarreau708c4162019-10-09 10:19:16 +02001965 if (!stats_set_flag(&curproxy->uri_auth, STAT_HIDEVER)) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001966 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1967 err_code |= ERR_ALERT | ERR_ABORT;
1968 goto out;
1969 }
1970 } else if (!strcmp(args[1], "show-legends")) {
Willy Tarreau708c4162019-10-09 10:19:16 +02001971 if (!stats_set_flag(&curproxy->uri_auth, STAT_SHLGNDS)) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001972 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1973 err_code |= ERR_ALERT | ERR_ABORT;
1974 goto out;
1975 }
1976 } else if (!strcmp(args[1], "show-node")) {
1977
1978 if (*args[2]) {
1979 int i;
1980 char c;
1981
1982 for (i=0; args[2][i]; i++) {
1983 c = args[2][i];
1984 if (!isupper((unsigned char)c) && !islower((unsigned char)c) &&
1985 !isdigit((unsigned char)c) && c != '_' && c != '-' && c != '.')
1986 break;
1987 }
1988
1989 if (!i || args[2][i]) {
1990 ha_alert("parsing [%s:%d]: '%s %s' invalid node name - should be a string"
1991 "with digits(0-9), letters(A-Z, a-z), hyphen(-) or underscode(_).\n",
1992 file, linenum, args[0], args[1]);
1993 err_code |= ERR_ALERT | ERR_FATAL;
1994 goto out;
1995 }
1996 }
1997
1998 if (!stats_set_node(&curproxy->uri_auth, args[2])) {
1999 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2000 err_code |= ERR_ALERT | ERR_ABORT;
2001 goto out;
2002 }
2003 } else if (!strcmp(args[1], "show-desc")) {
2004 char *desc = NULL;
2005
2006 if (*args[2]) {
2007 int i, len=0;
2008 char *d;
2009
2010 for (i = 2; *args[i]; i++)
2011 len += strlen(args[i]) + 1;
2012
2013 desc = d = calloc(1, len);
2014
2015 d += snprintf(d, desc + len - d, "%s", args[2]);
2016 for (i = 3; *args[i]; i++)
2017 d += snprintf(d, desc + len - d, " %s", args[i]);
2018 }
2019
2020 if (!*args[2] && !global.desc)
2021 ha_warning("parsing [%s:%d]: '%s' requires a parameter or 'desc' to be set in the global section.\n",
2022 file, linenum, args[1]);
2023 else {
2024 if (!stats_set_desc(&curproxy->uri_auth, desc)) {
2025 free(desc);
2026 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2027 err_code |= ERR_ALERT | ERR_ABORT;
2028 goto out;
2029 }
2030 free(desc);
2031 }
2032 } else {
2033stats_error_parsing:
2034 ha_alert("parsing [%s:%d]: %s '%s', expects 'admin', 'uri', 'realm', 'auth', 'scope', 'enable', 'hide-version', 'show-node', 'show-desc' or 'show-legends'.\n",
2035 file, linenum, *args[1]?"unknown stats parameter":"missing keyword in", args[*args[1]?1:0]);
2036 err_code |= ERR_ALERT | ERR_FATAL;
2037 goto out;
2038 }
2039 }
2040 else if (!strcmp(args[0], "option")) {
2041 int optnum;
2042
2043 if (*(args[1]) == '\0') {
2044 ha_alert("parsing [%s:%d]: '%s' expects an option name.\n",
2045 file, linenum, args[0]);
2046 err_code |= ERR_ALERT | ERR_FATAL;
2047 goto out;
2048 }
2049
2050 for (optnum = 0; cfg_opts[optnum].name; optnum++) {
2051 if (!strcmp(args[1], cfg_opts[optnum].name)) {
2052 if (cfg_opts[optnum].cap == PR_CAP_NONE) {
2053 ha_alert("parsing [%s:%d]: option '%s' is not supported due to build options.\n",
2054 file, linenum, cfg_opts[optnum].name);
2055 err_code |= ERR_ALERT | ERR_FATAL;
2056 goto out;
2057 }
2058 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2059 goto out;
2060
2061 if (warnifnotcap(curproxy, cfg_opts[optnum].cap, file, linenum, args[1], NULL)) {
2062 err_code |= ERR_WARN;
2063 goto out;
2064 }
2065
2066 curproxy->no_options &= ~cfg_opts[optnum].val;
2067 curproxy->options &= ~cfg_opts[optnum].val;
2068
2069 switch (kwm) {
2070 case KWM_STD:
2071 curproxy->options |= cfg_opts[optnum].val;
2072 break;
2073 case KWM_NO:
2074 curproxy->no_options |= cfg_opts[optnum].val;
2075 break;
2076 case KWM_DEF: /* already cleared */
2077 break;
2078 }
2079
2080 goto out;
2081 }
2082 }
2083
2084 for (optnum = 0; cfg_opts2[optnum].name; optnum++) {
2085 if (!strcmp(args[1], cfg_opts2[optnum].name)) {
2086 if (cfg_opts2[optnum].cap == PR_CAP_NONE) {
2087 ha_alert("parsing [%s:%d]: option '%s' is not supported due to build options.\n",
2088 file, linenum, cfg_opts2[optnum].name);
2089 err_code |= ERR_ALERT | ERR_FATAL;
2090 goto out;
2091 }
2092 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2093 goto out;
2094 if (warnifnotcap(curproxy, cfg_opts2[optnum].cap, file, linenum, args[1], NULL)) {
2095 err_code |= ERR_WARN;
2096 goto out;
2097 }
2098
Christopher Faulet31930372019-07-15 10:16:58 +02002099 /* "[no] option http-use-htx" is deprecated */
2100 if (!strcmp(cfg_opts2[optnum].name, "http-use-htx")) {
Christopher Fauletf89f0992019-07-19 11:17:38 +02002101 if (kwm ==KWM_NO) {
2102 ha_warning("parsing [%s:%d]: option '%s' is deprecated and ignored."
2103 " The HTX mode is now the only supported mode.\n",
2104 file, linenum, cfg_opts2[optnum].name);
2105 err_code |= ERR_WARN;
2106 }
Christopher Faulet31930372019-07-15 10:16:58 +02002107 goto out;
2108 }
2109
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002110 curproxy->no_options2 &= ~cfg_opts2[optnum].val;
2111 curproxy->options2 &= ~cfg_opts2[optnum].val;
2112
2113 switch (kwm) {
2114 case KWM_STD:
2115 curproxy->options2 |= cfg_opts2[optnum].val;
2116 break;
2117 case KWM_NO:
2118 curproxy->no_options2 |= cfg_opts2[optnum].val;
2119 break;
2120 case KWM_DEF: /* already cleared */
2121 break;
2122 }
2123 goto out;
2124 }
2125 }
2126
2127 /* HTTP options override each other. They can be cancelled using
2128 * "no option xxx" which only switches to default mode if the mode
2129 * was this one (useful for cancelling options set in defaults
2130 * sections).
2131 */
2132 if (strcmp(args[1], "httpclose") == 0 || strcmp(args[1], "forceclose") == 0) {
Tim Duesterhus10c6c162019-05-14 20:58:00 +02002133 if (strcmp(args[1], "forceclose") == 0) {
2134 if (!already_warned(WARN_FORCECLOSE_DEPRECATED))
2135 ha_warning("parsing [%s:%d]: keyword '%s' is deprecated in favor of 'httpclose', and will not be supported by future versions.\n",
2136 file, linenum, args[1]);
2137 err_code |= ERR_WARN;
2138 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002139 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2140 goto out;
2141 if (kwm == KWM_STD) {
2142 curproxy->options &= ~PR_O_HTTP_MODE;
2143 curproxy->options |= PR_O_HTTP_CLO;
2144 goto out;
2145 }
2146 else if (kwm == KWM_NO) {
2147 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_CLO)
2148 curproxy->options &= ~PR_O_HTTP_MODE;
2149 goto out;
2150 }
2151 }
2152 else if (strcmp(args[1], "http-server-close") == 0) {
2153 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2154 goto out;
2155 if (kwm == KWM_STD) {
2156 curproxy->options &= ~PR_O_HTTP_MODE;
2157 curproxy->options |= PR_O_HTTP_SCL;
2158 goto out;
2159 }
2160 else if (kwm == KWM_NO) {
2161 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL)
2162 curproxy->options &= ~PR_O_HTTP_MODE;
2163 goto out;
2164 }
2165 }
2166 else if (strcmp(args[1], "http-keep-alive") == 0) {
2167 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2168 goto out;
2169 if (kwm == KWM_STD) {
2170 curproxy->options &= ~PR_O_HTTP_MODE;
2171 curproxy->options |= PR_O_HTTP_KAL;
2172 goto out;
2173 }
2174 else if (kwm == KWM_NO) {
2175 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_KAL)
2176 curproxy->options &= ~PR_O_HTTP_MODE;
2177 goto out;
2178 }
2179 }
2180 else if (strcmp(args[1], "http-tunnel") == 0) {
Christopher Faulet73e8ede2019-07-16 15:04:46 +02002181 ha_warning("parsing [%s:%d]: the option '%s' is deprecated and will be removed in next version.\n",
2182 file, linenum, args[1]);
2183 err_code |= ERR_WARN;
2184 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002185 }
2186
2187 /* Redispatch can take an integer argument that control when the
2188 * resispatch occurs. All values are relative to the retries option.
2189 * This can be cancelled using "no option xxx".
2190 */
2191 if (strcmp(args[1], "redispatch") == 0) {
2192 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL)) {
2193 err_code |= ERR_WARN;
2194 goto out;
2195 }
2196
2197 curproxy->no_options &= ~PR_O_REDISP;
2198 curproxy->options &= ~PR_O_REDISP;
2199
2200 switch (kwm) {
2201 case KWM_STD:
2202 curproxy->options |= PR_O_REDISP;
2203 curproxy->redispatch_after = -1;
2204 if(*args[2]) {
2205 curproxy->redispatch_after = atol(args[2]);
2206 }
2207 break;
2208 case KWM_NO:
2209 curproxy->no_options |= PR_O_REDISP;
2210 curproxy->redispatch_after = 0;
2211 break;
2212 case KWM_DEF: /* already cleared */
2213 break;
2214 }
2215 goto out;
2216 }
2217
2218 if (kwm != KWM_STD) {
2219 ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
2220 file, linenum, args[1]);
2221 err_code |= ERR_ALERT | ERR_FATAL;
2222 goto out;
2223 }
2224
2225 if (!strcmp(args[1], "httplog")) {
2226 char *logformat;
2227 /* generate a complete HTTP log */
2228 logformat = default_http_log_format;
2229 if (*(args[2]) != '\0') {
2230 if (!strcmp(args[2], "clf")) {
2231 curproxy->options2 |= PR_O2_CLFLOG;
2232 logformat = clf_http_log_format;
2233 } else {
2234 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'clf'.\n", file, linenum, args[1]);
2235 err_code |= ERR_ALERT | ERR_FATAL;
2236 goto out;
2237 }
2238 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
2239 goto out;
2240 }
2241 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2242 char *oldlogformat = "log-format";
2243 char *clflogformat = "";
2244
2245 if (curproxy->conf.logformat_string == default_http_log_format)
2246 oldlogformat = "option httplog";
2247 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2248 oldlogformat = "option tcplog";
2249 else if (curproxy->conf.logformat_string == clf_http_log_format)
2250 oldlogformat = "option httplog clf";
2251 if (logformat == clf_http_log_format)
2252 clflogformat = " clf";
2253 ha_warning("parsing [%s:%d]: 'option httplog%s' overrides previous '%s' in 'defaults' section.\n",
2254 file, linenum, clflogformat, oldlogformat);
2255 }
2256 if (curproxy->conf.logformat_string != default_http_log_format &&
2257 curproxy->conf.logformat_string != default_tcp_log_format &&
2258 curproxy->conf.logformat_string != clf_http_log_format)
2259 free(curproxy->conf.logformat_string);
2260 curproxy->conf.logformat_string = logformat;
2261
2262 free(curproxy->conf.lfs_file);
2263 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2264 curproxy->conf.lfs_line = curproxy->conf.args.line;
2265
2266 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2267 ha_warning("parsing [%s:%d] : backend '%s' : 'option httplog' directive is ignored in backends.\n",
2268 file, linenum, curproxy->id);
2269 err_code |= ERR_WARN;
2270 }
2271 }
2272 else if (!strcmp(args[1], "tcplog")) {
2273 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2274 char *oldlogformat = "log-format";
2275
2276 if (curproxy->conf.logformat_string == default_http_log_format)
2277 oldlogformat = "option httplog";
2278 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2279 oldlogformat = "option tcplog";
2280 else if (curproxy->conf.logformat_string == clf_http_log_format)
2281 oldlogformat = "option httplog clf";
2282 ha_warning("parsing [%s:%d]: 'option tcplog' overrides previous '%s' in 'defaults' section.\n",
2283 file, linenum, oldlogformat);
2284 }
2285 /* generate a detailed TCP log */
2286 if (curproxy->conf.logformat_string != default_http_log_format &&
2287 curproxy->conf.logformat_string != default_tcp_log_format &&
2288 curproxy->conf.logformat_string != clf_http_log_format)
2289 free(curproxy->conf.logformat_string);
2290 curproxy->conf.logformat_string = default_tcp_log_format;
2291
2292 free(curproxy->conf.lfs_file);
2293 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2294 curproxy->conf.lfs_line = curproxy->conf.args.line;
2295
2296 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2297 goto out;
2298
2299 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2300 ha_warning("parsing [%s:%d] : backend '%s' : 'option tcplog' directive is ignored in backends.\n",
2301 file, linenum, curproxy->id);
2302 err_code |= ERR_WARN;
2303 }
2304 }
2305 else if (!strcmp(args[1], "tcpka")) {
2306 /* enable TCP keep-alives on client and server streams */
2307 if (warnifnotcap(curproxy, PR_CAP_BE | PR_CAP_FE, file, linenum, args[1], NULL))
2308 err_code |= ERR_WARN;
2309
2310 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2311 goto out;
2312
2313 if (curproxy->cap & PR_CAP_FE)
2314 curproxy->options |= PR_O_TCP_CLI_KA;
2315 if (curproxy->cap & PR_CAP_BE)
2316 curproxy->options |= PR_O_TCP_SRV_KA;
2317 }
2318 else if (!strcmp(args[1], "httpchk")) {
2319 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2320 err_code |= ERR_WARN;
2321
2322 /* use HTTP request to check servers' health */
2323 free(curproxy->check_req);
Christopher Faulet8acb1282020-04-09 08:44:06 +02002324 free(curproxy->check_hdrs);
2325 free(curproxy->check_body);
2326 curproxy->check_req = curproxy->check_hdrs = curproxy->check_body = NULL;
2327 curproxy->check_len = curproxy->check_hdrs_len = curproxy->check_body_len = 0;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002328 curproxy->options2 &= ~PR_O2_CHK_ANY;
2329 curproxy->options2 |= PR_O2_HTTP_CHK;
2330 if (!*args[2]) { /* no argument */
2331 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
2332 curproxy->check_len = strlen(DEF_CHECK_REQ);
2333 } else if (!*args[3]) { /* one argument : URI */
2334 int reqlen = strlen(args[2]) + strlen("OPTIONS HTTP/1.0\r\n") + 1;
2335 curproxy->check_req = malloc(reqlen);
2336 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2337 "OPTIONS %s HTTP/1.0\r\n", args[2]); /* URI to use */
Christopher Faulet8acb1282020-04-09 08:44:06 +02002338 } else if (!*args[4]) { /* two arguments : METHOD URI */
2339 int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" HTTP/1.0\r\n") + 1;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002340
2341 curproxy->check_req = malloc(reqlen);
2342 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
Christopher Faulet8acb1282020-04-09 08:44:06 +02002343 "%s %s HTTP/1.0\r\n", args[2], args[3]);
2344 } else { /* 3 arguments : METHOD URI HTTP_VER */
2345 char *vsn = args[4];
2346 char *hdrs = strstr(vsn, "\r\n");
2347 char *body = strstr(vsn, "\r\n\r\n");
2348
2349 if (hdrs || body) {
2350 ha_warning("parsing [%s:%d]: '%s %s' : hiding headers or body at the end of the version string is deprecated."
2351 " Please, consider to use 'http-check send' directive instead.\n",
2352 file, linenum, args[0], args[1]);
2353 err_code |= ERR_WARN;
2354 }
2355
2356 if (hdrs == body)
2357 hdrs = NULL;
2358 if (hdrs) {
2359 *hdrs = '\0';
2360 hdrs += 2;
2361 }
2362 if (body) {
2363 *body = '\0';
2364 body += 4;
2365 }
2366
2367 curproxy->check_len = strlen(args[2]) + strlen(args[3]) + strlen(vsn) + 4;
2368 curproxy->check_req = malloc(curproxy->check_len+1);
2369 snprintf(curproxy->check_req, curproxy->check_len+1, "%s %s %s\r\n", args[2], args[3], vsn);
2370
2371 if (hdrs) {
2372 curproxy->check_hdrs_len = strlen(hdrs) + 2;
2373 curproxy->check_hdrs = malloc(curproxy->check_hdrs_len+1);
2374 snprintf(curproxy->check_hdrs, curproxy->check_hdrs_len+1, "%s\r\n", hdrs);
2375 }
2376
2377 if (body) {
2378 curproxy->check_body_len = strlen(body);
2379 curproxy->check_body = strdup(body);
2380 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002381 }
2382 if (alertif_too_many_args_idx(3, 1, file, linenum, args, &err_code))
2383 goto out;
2384 }
2385 else if (!strcmp(args[1], "ssl-hello-chk")) {
2386 /* use SSLv3 CLIENT HELLO to check servers' health */
2387 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2388 err_code |= ERR_WARN;
2389
2390 free(curproxy->check_req);
2391 curproxy->check_req = NULL;
2392 curproxy->options2 &= ~PR_O2_CHK_ANY;
2393 curproxy->options2 |= PR_O2_SSL3_CHK;
2394
2395 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2396 goto out;
2397 }
2398 else if (!strcmp(args[1], "smtpchk")) {
2399 /* use SMTP request to check servers' health */
2400 free(curproxy->check_req);
2401 curproxy->check_req = NULL;
2402 curproxy->options2 &= ~PR_O2_CHK_ANY;
2403 curproxy->options2 |= PR_O2_SMTP_CHK;
2404
2405 if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */
2406 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2407 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2408 } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */
2409 if (!strcmp(args[2], "EHLO") || !strcmp(args[2], "HELO")) {
2410 int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" \r\n") + 1;
2411 curproxy->check_req = malloc(reqlen);
2412 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2413 "%s %s\r\n", args[2], args[3]); /* HELO hostname */
2414 } else {
2415 /* this just hits the default for now, but you could potentially expand it to allow for other stuff
2416 though, it's unlikely you'd want to send anything other than an EHLO or HELO */
2417 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2418 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2419 }
2420 }
2421 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2422 goto out;
2423 }
2424 else if (!strcmp(args[1], "pgsql-check")) {
2425 /* use PostgreSQL request to check servers' health */
2426 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2427 err_code |= ERR_WARN;
2428
2429 free(curproxy->check_req);
2430 curproxy->check_req = NULL;
2431 curproxy->options2 &= ~PR_O2_CHK_ANY;
2432 curproxy->options2 |= PR_O2_PGSQL_CHK;
2433
2434 if (*(args[2])) {
2435 int cur_arg = 2;
2436
2437 while (*(args[cur_arg])) {
2438 if (strcmp(args[cur_arg], "user") == 0) {
2439 char * packet;
2440 uint32_t packet_len;
2441 uint32_t pv;
2442
2443 /* suboption header - needs additional argument for it */
2444 if (*(args[cur_arg+1]) == 0) {
2445 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2446 file, linenum, args[0], args[1], args[cur_arg]);
2447 err_code |= ERR_ALERT | ERR_FATAL;
2448 goto out;
2449 }
2450
2451 /* uint32_t + uint32_t + strlen("user")+1 + strlen(username)+1 + 1 */
2452 packet_len = 4 + 4 + 5 + strlen(args[cur_arg + 1])+1 +1;
2453 pv = htonl(0x30000); /* protocol version 3.0 */
2454
2455 packet = calloc(1, packet_len);
2456
2457 memcpy(packet + 4, &pv, 4);
2458
2459 /* copy "user" */
2460 memcpy(packet + 8, "user", 4);
2461
2462 /* copy username */
2463 memcpy(packet + 13, args[cur_arg+1], strlen(args[cur_arg+1]));
2464
2465 free(curproxy->check_req);
2466 curproxy->check_req = packet;
2467 curproxy->check_len = packet_len;
2468
2469 packet_len = htonl(packet_len);
2470 memcpy(packet, &packet_len, 4);
2471 cur_arg += 2;
2472 } else {
2473 /* unknown suboption - catchall */
2474 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2475 file, linenum, args[0], args[1]);
2476 err_code |= ERR_ALERT | ERR_FATAL;
2477 goto out;
2478 }
2479 } /* end while loop */
2480 }
2481 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2482 goto out;
2483 }
2484
2485 else if (!strcmp(args[1], "redis-check")) {
2486 /* use REDIS PING request to check servers' health */
2487 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2488 err_code |= ERR_WARN;
2489
2490 free(curproxy->check_req);
2491 curproxy->check_req = NULL;
2492 curproxy->options2 &= ~PR_O2_CHK_ANY;
2493 curproxy->options2 |= PR_O2_REDIS_CHK;
2494
2495 curproxy->check_req = malloc(sizeof(DEF_REDIS_CHECK_REQ) - 1);
2496 memcpy(curproxy->check_req, DEF_REDIS_CHECK_REQ, sizeof(DEF_REDIS_CHECK_REQ) - 1);
2497 curproxy->check_len = sizeof(DEF_REDIS_CHECK_REQ) - 1;
2498
2499 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2500 goto out;
2501 }
2502
2503 else if (!strcmp(args[1], "mysql-check")) {
2504 /* use MYSQL request to check servers' health */
2505 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2506 err_code |= ERR_WARN;
2507
2508 free(curproxy->check_req);
2509 curproxy->check_req = NULL;
2510 curproxy->options2 &= ~PR_O2_CHK_ANY;
2511 curproxy->options2 |= PR_O2_MYSQL_CHK;
2512
2513 /* This is an example of a MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte.
2514 * const char mysql40_client_auth_pkt[] = {
2515 * "\x0e\x00\x00" // packet length
2516 * "\x01" // packet number
2517 * "\x00\x00" // client capabilities
2518 * "\x00\x00\x01" // max packet
2519 * "haproxy\x00" // username (null terminated string)
2520 * "\x00" // filler (always 0x00)
2521 * "\x01\x00\x00" // packet length
2522 * "\x00" // packet number
2523 * "\x01" // COM_QUIT command
2524 * };
2525 */
2526
2527 /* This is an example of a MySQL >=4.1 client Authentication packet provided by Nenad Merdanovic.
2528 * const char mysql41_client_auth_pkt[] = {
2529 * "\x0e\x00\x00\" // packet length
2530 * "\x01" // packet number
2531 * "\x00\x00\x00\x00" // client capabilities
2532 * "\x00\x00\x00\x01" // max packet
2533 * "\x21" // character set (UTF-8)
2534 * char[23] // All zeroes
2535 * "haproxy\x00" // username (null terminated string)
2536 * "\x00" // filler (always 0x00)
2537 * "\x01\x00\x00" // packet length
2538 * "\x00" // packet number
2539 * "\x01" // COM_QUIT command
2540 * };
2541 */
2542
2543
2544 if (*(args[2])) {
2545 int cur_arg = 2;
2546
2547 while (*(args[cur_arg])) {
2548 if (strcmp(args[cur_arg], "user") == 0) {
2549 char *mysqluser;
2550 int packetlen, reqlen, userlen;
2551
2552 /* suboption header - needs additional argument for it */
2553 if (*(args[cur_arg+1]) == 0) {
2554 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2555 file, linenum, args[0], args[1], args[cur_arg]);
2556 err_code |= ERR_ALERT | ERR_FATAL;
2557 goto out;
2558 }
2559 mysqluser = args[cur_arg + 1];
2560 userlen = strlen(mysqluser);
2561
2562 if (*(args[cur_arg+2])) {
2563 if (!strcmp(args[cur_arg+2], "post-41")) {
2564 packetlen = userlen + 7 + 27;
2565 reqlen = packetlen + 9;
2566
2567 free(curproxy->check_req);
2568 curproxy->check_req = calloc(1, reqlen);
2569 curproxy->check_len = reqlen;
2570
2571 snprintf(curproxy->check_req, 4, "%c%c%c",
2572 ((unsigned char) packetlen & 0xff),
2573 ((unsigned char) (packetlen >> 8) & 0xff),
2574 ((unsigned char) (packetlen >> 16) & 0xff));
2575
2576 curproxy->check_req[3] = 1;
2577 curproxy->check_req[5] = 0x82; // 130
2578 curproxy->check_req[11] = 1;
2579 curproxy->check_req[12] = 33;
2580 memcpy(&curproxy->check_req[36], mysqluser, userlen);
2581 curproxy->check_req[36 + userlen + 1 + 1] = 1;
2582 curproxy->check_req[36 + userlen + 1 + 1 + 4] = 1;
2583 cur_arg += 3;
2584 } else {
2585 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'post-41'.\n", file, linenum, args[cur_arg+2]);
2586 err_code |= ERR_ALERT | ERR_FATAL;
2587 goto out;
2588 }
2589 } else {
2590 packetlen = userlen + 7;
2591 reqlen = packetlen + 9;
2592
2593 free(curproxy->check_req);
2594 curproxy->check_req = calloc(1, reqlen);
2595 curproxy->check_len = reqlen;
2596
2597 snprintf(curproxy->check_req, 4, "%c%c%c",
2598 ((unsigned char) packetlen & 0xff),
2599 ((unsigned char) (packetlen >> 8) & 0xff),
2600 ((unsigned char) (packetlen >> 16) & 0xff));
2601
2602 curproxy->check_req[3] = 1;
2603 curproxy->check_req[5] = 0x80;
2604 curproxy->check_req[8] = 1;
2605 memcpy(&curproxy->check_req[9], mysqluser, userlen);
2606 curproxy->check_req[9 + userlen + 1 + 1] = 1;
2607 curproxy->check_req[9 + userlen + 1 + 1 + 4] = 1;
2608 cur_arg += 2;
2609 }
2610 } else {
2611 /* unknown suboption - catchall */
2612 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2613 file, linenum, args[0], args[1]);
2614 err_code |= ERR_ALERT | ERR_FATAL;
2615 goto out;
2616 }
2617 } /* end while loop */
2618 }
2619 }
2620 else if (!strcmp(args[1], "ldap-check")) {
2621 /* use LDAP request to check servers' health */
2622 free(curproxy->check_req);
2623 curproxy->check_req = NULL;
2624 curproxy->options2 &= ~PR_O2_CHK_ANY;
2625 curproxy->options2 |= PR_O2_LDAP_CHK;
2626
2627 curproxy->check_req = malloc(sizeof(DEF_LDAP_CHECK_REQ) - 1);
2628 memcpy(curproxy->check_req, DEF_LDAP_CHECK_REQ, sizeof(DEF_LDAP_CHECK_REQ) - 1);
2629 curproxy->check_len = sizeof(DEF_LDAP_CHECK_REQ) - 1;
2630 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2631 goto out;
2632 }
2633 else if (!strcmp(args[1], "spop-check")) {
2634 if (curproxy == &defproxy) {
2635 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n",
2636 file, linenum, args[0], args[1]);
2637 err_code |= ERR_ALERT | ERR_FATAL;
2638 goto out;
2639 }
2640 if (curproxy->cap & PR_CAP_FE) {
2641 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'frontend' and 'listen' sections.\n",
2642 file, linenum, args[0], args[1]);
2643 err_code |= ERR_ALERT | ERR_FATAL;
2644 goto out;
2645 }
2646
2647 /* use SPOE request to check servers' health */
2648 free(curproxy->check_req);
2649 curproxy->check_req = NULL;
2650 curproxy->options2 &= ~PR_O2_CHK_ANY;
2651 curproxy->options2 |= PR_O2_SPOP_CHK;
2652
2653 if (spoe_prepare_healthcheck_request(&curproxy->check_req, &curproxy->check_len)) {
2654 ha_alert("parsing [%s:%d] : failed to prepare SPOP healthcheck request.\n", file, linenum);
2655 err_code |= ERR_ALERT | ERR_FATAL;
2656 goto out;
2657 }
2658 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2659 goto out;
2660 }
2661 else if (!strcmp(args[1], "tcp-check")) {
2662 /* use raw TCPCHK send/expect to check servers' health */
2663 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2664 err_code |= ERR_WARN;
2665
2666 free(curproxy->check_req);
2667 curproxy->check_req = NULL;
2668 curproxy->options2 &= ~PR_O2_CHK_ANY;
2669 curproxy->options2 |= PR_O2_TCPCHK_CHK;
2670 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2671 goto out;
2672 }
2673 else if (!strcmp(args[1], "external-check")) {
2674 /* excute an external command to check servers' health */
2675 free(curproxy->check_req);
2676 curproxy->check_req = NULL;
2677 curproxy->options2 &= ~PR_O2_CHK_ANY;
2678 curproxy->options2 |= PR_O2_EXT_CHK;
2679 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2680 goto out;
2681 }
2682 else if (!strcmp(args[1], "forwardfor")) {
2683 int cur_arg;
2684
2685 /* insert x-forwarded-for field, but not for the IP address listed as an except.
Christopher Faulet31930372019-07-15 10:16:58 +02002686 * set default options (ie: bitfield, header name, etc)
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002687 */
2688
2689 curproxy->options |= PR_O_FWDFOR | PR_O_FF_ALWAYS;
2690
2691 free(curproxy->fwdfor_hdr_name);
2692 curproxy->fwdfor_hdr_name = strdup(DEF_XFORWARDFOR_HDR);
2693 curproxy->fwdfor_hdr_len = strlen(DEF_XFORWARDFOR_HDR);
2694
2695 /* loop to go through arguments - start at 2, since 0+1 = "option" "forwardfor" */
2696 cur_arg = 2;
2697 while (*(args[cur_arg])) {
2698 if (!strcmp(args[cur_arg], "except")) {
2699 /* suboption except - needs additional argument for it */
2700 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_net, &curproxy->except_mask)) {
2701 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2702 file, linenum, args[0], args[1], args[cur_arg]);
2703 err_code |= ERR_ALERT | ERR_FATAL;
2704 goto out;
2705 }
2706 /* flush useless bits */
2707 curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
2708 cur_arg += 2;
2709 } else if (!strcmp(args[cur_arg], "header")) {
2710 /* suboption header - needs additional argument for it */
2711 if (*(args[cur_arg+1]) == 0) {
2712 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2713 file, linenum, args[0], args[1], args[cur_arg]);
2714 err_code |= ERR_ALERT | ERR_FATAL;
2715 goto out;
2716 }
2717 free(curproxy->fwdfor_hdr_name);
2718 curproxy->fwdfor_hdr_name = strdup(args[cur_arg+1]);
2719 curproxy->fwdfor_hdr_len = strlen(curproxy->fwdfor_hdr_name);
2720 cur_arg += 2;
2721 } else if (!strcmp(args[cur_arg], "if-none")) {
2722 curproxy->options &= ~PR_O_FF_ALWAYS;
2723 cur_arg += 1;
2724 } else {
2725 /* unknown suboption - catchall */
2726 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except', 'header' and 'if-none'.\n",
2727 file, linenum, args[0], args[1]);
2728 err_code |= ERR_ALERT | ERR_FATAL;
2729 goto out;
2730 }
2731 } /* end while loop */
2732 }
2733 else if (!strcmp(args[1], "originalto")) {
2734 int cur_arg;
2735
2736 /* insert x-original-to field, but not for the IP address listed as an except.
2737 * set default options (ie: bitfield, header name, etc)
2738 */
2739
2740 curproxy->options |= PR_O_ORGTO;
2741
2742 free(curproxy->orgto_hdr_name);
2743 curproxy->orgto_hdr_name = strdup(DEF_XORIGINALTO_HDR);
2744 curproxy->orgto_hdr_len = strlen(DEF_XORIGINALTO_HDR);
2745
2746 /* loop to go through arguments - start at 2, since 0+1 = "option" "originalto" */
2747 cur_arg = 2;
2748 while (*(args[cur_arg])) {
2749 if (!strcmp(args[cur_arg], "except")) {
2750 /* suboption except - needs additional argument for it */
2751 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_to, &curproxy->except_mask_to)) {
2752 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2753 file, linenum, args[0], args[1], args[cur_arg]);
2754 err_code |= ERR_ALERT | ERR_FATAL;
2755 goto out;
2756 }
2757 /* flush useless bits */
2758 curproxy->except_to.s_addr &= curproxy->except_mask_to.s_addr;
2759 cur_arg += 2;
2760 } else if (!strcmp(args[cur_arg], "header")) {
2761 /* suboption header - needs additional argument for it */
2762 if (*(args[cur_arg+1]) == 0) {
2763 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2764 file, linenum, args[0], args[1], args[cur_arg]);
2765 err_code |= ERR_ALERT | ERR_FATAL;
2766 goto out;
2767 }
2768 free(curproxy->orgto_hdr_name);
2769 curproxy->orgto_hdr_name = strdup(args[cur_arg+1]);
2770 curproxy->orgto_hdr_len = strlen(curproxy->orgto_hdr_name);
2771 cur_arg += 2;
2772 } else {
2773 /* unknown suboption - catchall */
2774 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
2775 file, linenum, args[0], args[1]);
2776 err_code |= ERR_ALERT | ERR_FATAL;
2777 goto out;
2778 }
2779 } /* end while loop */
2780 }
2781 else {
2782 ha_alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
2783 err_code |= ERR_ALERT | ERR_FATAL;
2784 goto out;
2785 }
2786 goto out;
2787 }
2788 else if (!strcmp(args[0], "default_backend")) {
2789 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
2790 err_code |= ERR_WARN;
2791
2792 if (*(args[1]) == 0) {
2793 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
2794 err_code |= ERR_ALERT | ERR_FATAL;
2795 goto out;
2796 }
2797 free(curproxy->defbe.name);
2798 curproxy->defbe.name = strdup(args[1]);
2799
2800 if (alertif_too_many_args_idx(1, 0, file, linenum, args, &err_code))
2801 goto out;
2802 }
2803 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
Tim Duesterhusdac168b2019-05-14 20:57:58 +02002804 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 +01002805
Tim Duesterhusdac168b2019-05-14 20:57:58 +02002806 err_code |= ERR_ALERT | ERR_FATAL;
2807 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002808 }
2809 else if (!strcmp(args[0], "http-reuse")) {
2810 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2811 err_code |= ERR_WARN;
2812
2813 if (strcmp(args[1], "never") == 0) {
2814 /* enable a graceful server shutdown on an HTTP 404 response */
2815 curproxy->options &= ~PR_O_REUSE_MASK;
2816 curproxy->options |= PR_O_REUSE_NEVR;
2817 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2818 goto out;
2819 }
2820 else if (strcmp(args[1], "safe") == 0) {
2821 /* enable a graceful server shutdown on an HTTP 404 response */
2822 curproxy->options &= ~PR_O_REUSE_MASK;
2823 curproxy->options |= PR_O_REUSE_SAFE;
2824 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2825 goto out;
2826 }
2827 else if (strcmp(args[1], "aggressive") == 0) {
2828 curproxy->options &= ~PR_O_REUSE_MASK;
2829 curproxy->options |= PR_O_REUSE_AGGR;
2830 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2831 goto out;
2832 }
2833 else if (strcmp(args[1], "always") == 0) {
2834 /* enable a graceful server shutdown on an HTTP 404 response */
2835 curproxy->options &= ~PR_O_REUSE_MASK;
2836 curproxy->options |= PR_O_REUSE_ALWS;
2837 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2838 goto out;
2839 }
2840 else {
2841 ha_alert("parsing [%s:%d] : '%s' only supports 'never', 'safe', 'aggressive', 'always'.\n", file, linenum, args[0]);
2842 err_code |= ERR_ALERT | ERR_FATAL;
2843 goto out;
2844 }
2845 }
2846 else if (!strcmp(args[0], "http-check")) {
2847 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2848 err_code |= ERR_WARN;
2849
2850 if (strcmp(args[1], "disable-on-404") == 0) {
2851 /* enable a graceful server shutdown on an HTTP 404 response */
2852 curproxy->options |= PR_O_DISABLE404;
2853 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2854 goto out;
2855 }
2856 else if (strcmp(args[1], "send-state") == 0) {
2857 /* enable emission of the apparent state of a server in HTTP checks */
2858 curproxy->options2 |= PR_O2_CHK_SNDST;
2859 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2860 goto out;
2861 }
Christopher Faulet8acb1282020-04-09 08:44:06 +02002862 else if (strcmp(args[1], "send") == 0) {
2863 int cur_arg = 2;
2864
2865 free(curproxy->check_hdrs);
2866 free(curproxy->check_body);
2867 curproxy->check_hdrs = curproxy->check_body = NULL;
2868 curproxy->check_hdrs_len = curproxy->check_body_len = 0;
2869 while (*(args[cur_arg])) {
2870 if (strcmp(args[cur_arg], "hdr") == 0) {
2871 int hdr_len;
2872 if (!*(args[cur_arg+1]) || !*(args[cur_arg+2])) {
2873 ha_alert("parsing [%s:%d] : '%s %s' : %s expects a name and a value as parameter.\n",
2874 file, linenum, args[0], args[1], args[cur_arg]);
2875 err_code |= ERR_ALERT | ERR_FATAL;
2876 goto out;
2877 }
2878
2879 cur_arg++;
2880 hdr_len = strlen(args[cur_arg]) + strlen(args[cur_arg+1]) + 4;
2881 curproxy->check_hdrs = my_realloc2(curproxy->check_hdrs, curproxy->check_hdrs_len+hdr_len+1);
2882 if (curproxy->check_hdrs == NULL) {
2883 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2884 err_code |= ERR_ALERT | ERR_FATAL;
2885 goto out;
2886 }
2887 snprintf(curproxy->check_hdrs + curproxy->check_hdrs_len, hdr_len+1, "%s: %s\r\n", args[cur_arg], args[cur_arg+1]);
2888 curproxy->check_hdrs_len += hdr_len;
2889
2890 cur_arg++;
2891 }
2892 else if (strcmp(args[cur_arg], "body") == 0) {
2893 if (!*(args[cur_arg+1])) {
2894 ha_alert("parsing [%s:%d] : '%s %s' : %s expects a string as parameter.\n",
2895 file, linenum, args[0], args[1], args[cur_arg]);
2896 err_code |= ERR_ALERT | ERR_FATAL;
2897 goto out;
2898 }
2899 cur_arg++;
2900 free(curproxy->check_body);
2901 curproxy->check_body = strdup(args[cur_arg]);
2902 curproxy->check_body_len = strlen(args[cur_arg]);
2903 if (curproxy->check_body == NULL) {
2904 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2905 err_code |= ERR_ALERT | ERR_FATAL;
2906 goto out;
2907 }
2908 }
2909 else {
2910 ha_alert("parsing [%s:%d] : '%s %s' only supports 'hdr' and 'body', found '%s'.\n",
2911 file, linenum, args[0], args[1], args[cur_arg]);
2912 err_code |= ERR_ALERT | ERR_FATAL;
2913 goto out;
2914 }
2915 cur_arg++;
2916 }
2917
2918 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002919 else if (strcmp(args[1], "expect") == 0) {
2920 const char *ptr_arg;
2921 int cur_arg;
2922
2923 if (curproxy->options2 & PR_O2_EXP_TYPE) {
2924 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
2925 err_code |= ERR_ALERT | ERR_FATAL;
2926 goto out;
2927 }
2928
2929 cur_arg = 2;
2930 /* consider exclamation marks, sole or at the beginning of a word */
2931 while (*(ptr_arg = args[cur_arg])) {
2932 while (*ptr_arg == '!') {
2933 curproxy->options2 ^= PR_O2_EXP_INV;
2934 ptr_arg++;
2935 }
2936 if (*ptr_arg)
2937 break;
2938 cur_arg++;
2939 }
2940 /* now ptr_arg points to the beginning of a word past any possible
2941 * exclamation mark, and cur_arg is the argument which holds this word.
2942 */
2943 if (strcmp(ptr_arg, "status") == 0) {
2944 if (!*(args[cur_arg + 1])) {
2945 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
2946 file, linenum, args[0], args[1], ptr_arg);
2947 err_code |= ERR_ALERT | ERR_FATAL;
2948 goto out;
2949 }
2950 curproxy->options2 |= PR_O2_EXP_STS;
2951 free(curproxy->expect_str);
2952 curproxy->expect_str = strdup(args[cur_arg + 1]);
2953 }
2954 else if (strcmp(ptr_arg, "string") == 0) {
2955 if (!*(args[cur_arg + 1])) {
2956 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
2957 file, linenum, args[0], args[1], ptr_arg);
2958 err_code |= ERR_ALERT | ERR_FATAL;
2959 goto out;
2960 }
2961 curproxy->options2 |= PR_O2_EXP_STR;
2962 free(curproxy->expect_str);
2963 curproxy->expect_str = strdup(args[cur_arg + 1]);
2964 }
2965 else if (strcmp(ptr_arg, "rstatus") == 0) {
2966 if (!*(args[cur_arg + 1])) {
2967 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
2968 file, linenum, args[0], args[1], ptr_arg);
2969 err_code |= ERR_ALERT | ERR_FATAL;
2970 goto out;
2971 }
2972 curproxy->options2 |= PR_O2_EXP_RSTS;
2973 free(curproxy->expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +02002974 regex_free(curproxy->expect_regex);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002975 curproxy->expect_str = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002976 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02002977 if (!(curproxy->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
2978 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002979 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
2980 free(error);
2981 err_code |= ERR_ALERT | ERR_FATAL;
2982 goto out;
2983 }
2984 }
2985 else if (strcmp(ptr_arg, "rstring") == 0) {
2986 if (!*(args[cur_arg + 1])) {
2987 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
2988 file, linenum, args[0], args[1], ptr_arg);
2989 err_code |= ERR_ALERT | ERR_FATAL;
2990 goto out;
2991 }
2992 curproxy->options2 |= PR_O2_EXP_RSTR;
2993 free(curproxy->expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +02002994 regex_free(curproxy->expect_regex);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002995 curproxy->expect_str = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002996 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02002997 if (!(curproxy->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
2998 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002999 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3000 free(error);
3001 err_code |= ERR_ALERT | ERR_FATAL;
3002 goto out;
3003 }
3004 }
3005 else {
3006 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'status', 'string', 'rstatus', 'rstring', found '%s'.\n",
3007 file, linenum, args[0], args[1], ptr_arg);
3008 err_code |= ERR_ALERT | ERR_FATAL;
3009 goto out;
3010 }
3011 }
3012 else {
3013 ha_alert("parsing [%s:%d] : '%s' only supports 'disable-on-404', 'send-state', 'expect'.\n", file, linenum, args[0]);
3014 err_code |= ERR_ALERT | ERR_FATAL;
3015 goto out;
3016 }
3017 }
3018 else if (!strcmp(args[0], "tcp-check")) {
3019 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3020 err_code |= ERR_WARN;
3021
Christopher Faulet11ef1492020-04-06 07:49:19 +02003022 if (curproxy == &defproxy) {
3023 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n",
3024 file, linenum, args[0]);
3025 err_code |= ERR_ALERT | ERR_FATAL;
3026 goto out;
3027 }
3028
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003029 if (strcmp(args[1], "comment") == 0) {
3030 int cur_arg;
3031 struct tcpcheck_rule *tcpcheck;
3032
3033 cur_arg = 1;
3034 tcpcheck = calloc(1, sizeof(*tcpcheck));
3035 tcpcheck->action = TCPCHK_ACT_COMMENT;
3036
3037 if (!*args[cur_arg + 1]) {
3038 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3039 file, linenum, args[cur_arg]);
3040 err_code |= ERR_ALERT | ERR_FATAL;
3041 goto out;
3042 }
3043
3044 tcpcheck->comment = strdup(args[cur_arg + 1]);
3045
3046 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3047 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
3048 goto out;
3049 }
3050 else if (strcmp(args[1], "connect") == 0) {
3051 const char *ptr_arg;
3052 int cur_arg;
3053 struct tcpcheck_rule *tcpcheck;
3054
3055 /* check if first rule is also a 'connect' action */
3056 tcpcheck = LIST_NEXT(&curproxy->tcpcheck_rules, struct tcpcheck_rule *, list);
3057 while (&tcpcheck->list != &curproxy->tcpcheck_rules &&
3058 tcpcheck->action == TCPCHK_ACT_COMMENT) {
3059 tcpcheck = LIST_NEXT(&tcpcheck->list, struct tcpcheck_rule *, list);
3060 }
3061
3062 if (&tcpcheck->list != &curproxy->tcpcheck_rules
3063 && tcpcheck->action != TCPCHK_ACT_CONNECT) {
3064 ha_alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
3065 file, linenum);
3066 err_code |= ERR_ALERT | ERR_FATAL;
3067 goto out;
3068 }
3069
3070 cur_arg = 2;
3071 tcpcheck = calloc(1, sizeof(*tcpcheck));
3072 tcpcheck->action = TCPCHK_ACT_CONNECT;
3073
3074 /* parsing each parameters to fill up the rule */
3075 while (*(ptr_arg = args[cur_arg])) {
3076 /* tcp port */
3077 if (strcmp(args[cur_arg], "port") == 0) {
3078 if ( (atol(args[cur_arg + 1]) > 65535) ||
3079 (atol(args[cur_arg + 1]) < 1) ){
3080 ha_alert("parsing [%s:%d] : '%s %s %s' expects a valid TCP port (from range 1 to 65535), got %s.\n",
3081 file, linenum, args[0], args[1], "port", args[cur_arg + 1]);
3082 err_code |= ERR_ALERT | ERR_FATAL;
3083 goto out;
3084 }
3085 tcpcheck->port = atol(args[cur_arg + 1]);
3086 cur_arg += 2;
3087 }
3088 /* send proxy protocol */
3089 else if (strcmp(args[cur_arg], "send-proxy") == 0) {
3090 tcpcheck->conn_opts |= TCPCHK_OPT_SEND_PROXY;
3091 cur_arg++;
3092 }
3093#ifdef USE_OPENSSL
3094 else if (strcmp(args[cur_arg], "ssl") == 0) {
3095 curproxy->options |= PR_O_TCPCHK_SSL;
3096 tcpcheck->conn_opts |= TCPCHK_OPT_SSL;
3097 cur_arg++;
3098 }
3099#endif /* USE_OPENSSL */
3100 /* comment for this tcpcheck line */
3101 else if (strcmp(args[cur_arg], "comment") == 0) {
3102 if (!*args[cur_arg + 1]) {
3103 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3104 file, linenum, args[cur_arg]);
3105 err_code |= ERR_ALERT | ERR_FATAL;
3106 goto out;
3107 }
3108 tcpcheck->comment = strdup(args[cur_arg + 1]);
3109 cur_arg += 2;
3110 }
3111 else {
3112#ifdef USE_OPENSSL
3113 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n",
3114#else /* USE_OPENSSL */
3115 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or but got '%s' as argument.\n",
3116#endif /* USE_OPENSSL */
3117 file, linenum, args[0], args[1], args[cur_arg]);
3118 err_code |= ERR_ALERT | ERR_FATAL;
3119 goto out;
3120 }
3121
3122 }
3123
3124 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3125 }
3126 else if (strcmp(args[1], "send") == 0) {
3127 if (! *(args[2]) ) {
3128 /* SEND string expected */
3129 ha_alert("parsing [%s:%d] : '%s %s %s' expects <STRING> as argument.\n",
3130 file, linenum, args[0], args[1], args[2]);
3131 err_code |= ERR_ALERT | ERR_FATAL;
3132 goto out;
3133 } else {
3134 struct tcpcheck_rule *tcpcheck;
3135
3136 tcpcheck = calloc(1, sizeof(*tcpcheck));
3137
3138 tcpcheck->action = TCPCHK_ACT_SEND;
3139 tcpcheck->string_len = strlen(args[2]);
3140 tcpcheck->string = strdup(args[2]);
3141 tcpcheck->expect_regex = NULL;
3142
3143 /* comment for this tcpcheck line */
3144 if (strcmp(args[3], "comment") == 0) {
3145 if (!*args[4]) {
3146 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3147 file, linenum, args[3]);
3148 err_code |= ERR_ALERT | ERR_FATAL;
3149 goto out;
3150 }
3151 tcpcheck->comment = strdup(args[4]);
3152 }
3153
3154 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3155 }
3156 }
3157 else if (strcmp(args[1], "send-binary") == 0) {
3158 if (! *(args[2]) ) {
3159 /* SEND binary string expected */
3160 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument.\n",
3161 file, linenum, args[0], args[1], args[2]);
3162 err_code |= ERR_ALERT | ERR_FATAL;
3163 goto out;
3164 } else {
3165 struct tcpcheck_rule *tcpcheck;
3166 char *err = NULL;
3167
3168 tcpcheck = calloc(1, sizeof(*tcpcheck));
3169
3170 tcpcheck->action = TCPCHK_ACT_SEND;
3171 if (parse_binary(args[2], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3172 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3173 file, linenum, args[0], args[1], args[2], err);
3174 err_code |= ERR_ALERT | ERR_FATAL;
3175 goto out;
3176 }
3177 tcpcheck->expect_regex = NULL;
3178
3179 /* comment for this tcpcheck line */
3180 if (strcmp(args[3], "comment") == 0) {
3181 if (!*args[4]) {
3182 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3183 file, linenum, args[3]);
3184 err_code |= ERR_ALERT | ERR_FATAL;
3185 goto out;
3186 }
3187 tcpcheck->comment = strdup(args[4]);
3188 }
3189
3190 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3191 }
3192 }
3193 else if (strcmp(args[1], "expect") == 0) {
Gaetan Rivet4038b942020-02-26 16:19:40 +01003194 struct tcpcheck_rule *tcpcheck, *prev_check;
Gaetan Rivet1afd8262020-02-07 15:37:17 +01003195 long min_recv = -1;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003196 const char *ptr_arg;
3197 int cur_arg;
3198 int inverse = 0;
3199
3200 if (curproxy->options2 & PR_O2_EXP_TYPE) {
3201 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
3202 err_code |= ERR_ALERT | ERR_FATAL;
3203 goto out;
3204 }
3205
3206 cur_arg = 2;
Gaetan Rivet1afd8262020-02-07 15:37:17 +01003207
3208 /* Parse potential the minimum amount of data
3209 * required before proceeding with the match.
3210 */
3211 if (strcmp(args[cur_arg], "min-recv") == 0) {
3212 if (!*(args[cur_arg + 1])) {
3213 ha_alert("parsing [%s:%d] : '%s %s %s' expects an integer as an argument.\n",
3214 file, linenum, args[0], args[1], args[2]);
3215 err_code |= ERR_ALERT | ERR_FATAL;
3216 goto out;
3217 }
3218
3219 /* Use an signed integer here because of chksize */
3220 min_recv = atol(args[cur_arg + 1]);
3221 if (min_recv < -1 || min_recv > INT_MAX) {
3222 ha_alert("parsing [%s:%d] : '%s %s %s' expects -1 or an integer from 0 to INT_MAX.\n",
3223 file, linenum, args[0], args[1], args[2]);
3224 err_code |= ERR_ALERT | ERR_FATAL;
3225 goto out;
3226 }
3227
3228 cur_arg += 2;
3229 }
3230
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003231 /* consider exclamation marks, sole or at the beginning of a word */
3232 while (*(ptr_arg = args[cur_arg])) {
3233 while (*ptr_arg == '!') {
3234 inverse = !inverse;
3235 ptr_arg++;
3236 }
3237 if (*ptr_arg)
3238 break;
3239 cur_arg++;
3240 }
Gaetan Rivet8b00b362020-02-07 15:37:17 +01003241
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003242 /* now ptr_arg points to the beginning of a word past any possible
3243 * exclamation mark, and cur_arg is the argument which holds this word.
3244 */
Gaetan Rivet8b00b362020-02-07 15:37:17 +01003245
3246 tcpcheck = calloc(1, sizeof(*tcpcheck));
3247 tcpcheck->action = TCPCHK_ACT_EXPECT;
3248 tcpcheck->inverse = inverse;
Gaetan Rivet1afd8262020-02-07 15:37:17 +01003249 tcpcheck->min_recv = min_recv;
Gaetan Rivet8b00b362020-02-07 15:37:17 +01003250
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003251 if (strcmp(ptr_arg, "binary") == 0) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003252 char *err = NULL;
3253
3254 if (!*(args[cur_arg + 1])) {
3255 ha_alert("parsing [%s:%d] : '%s %s %s' expects <binary string> as an argument.\n",
3256 file, linenum, args[0], args[1], ptr_arg);
3257 err_code |= ERR_ALERT | ERR_FATAL;
3258 goto out;
3259 }
3260
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003261 if (parse_binary(args[cur_arg + 1], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3262 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3263 file, linenum, args[0], args[1], args[2], err);
3264 err_code |= ERR_ALERT | ERR_FATAL;
3265 goto out;
3266 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003267 }
3268 else if (strcmp(ptr_arg, "string") == 0) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003269 if (!*(args[cur_arg + 1])) {
3270 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3271 file, linenum, args[0], args[1], ptr_arg);
3272 err_code |= ERR_ALERT | ERR_FATAL;
3273 goto out;
3274 }
3275
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003276 tcpcheck->string_len = strlen(args[cur_arg + 1]);
3277 tcpcheck->string = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003278 }
3279 else if (strcmp(ptr_arg, "rstring") == 0) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003280 if (!*(args[cur_arg + 1])) {
3281 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3282 file, linenum, args[0], args[1], ptr_arg);
3283 err_code |= ERR_ALERT | ERR_FATAL;
3284 goto out;
3285 }
3286
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003287 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02003288 if (!(tcpcheck->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
3289 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003290 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3291 free(error);
3292 err_code |= ERR_ALERT | ERR_FATAL;
3293 goto out;
3294 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003295 }
3296 else {
3297 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'binary', 'string', 'rstring', found '%s'.\n",
3298 file, linenum, args[0], args[1], ptr_arg);
3299 err_code |= ERR_ALERT | ERR_FATAL;
3300 goto out;
3301 }
Gaetan Rivet4038b942020-02-26 16:19:40 +01003302
Gaetan Rivet8b00b362020-02-07 15:37:17 +01003303 /* tcpcheck comment */
3304 cur_arg += 2;
3305 if (strcmp(args[cur_arg], "comment") == 0) {
3306 if (!*args[cur_arg + 1]) {
3307 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3308 file, linenum, args[cur_arg + 1]);
3309 err_code |= ERR_ALERT | ERR_FATAL;
3310 goto out;
3311 }
3312 tcpcheck->comment = strdup(args[cur_arg + 1]);
3313 }
3314
Gaetan Rivet4038b942020-02-26 16:19:40 +01003315 /* All tcp-check expect points back to the first inverse expect rule
3316 * in a chain of one or more expect rule, potentially itself.
3317 */
3318 tcpcheck->expect_head = tcpcheck;
3319 list_for_each_entry_rev(prev_check, &curproxy->tcpcheck_rules, list) {
3320 if (prev_check->action == TCPCHK_ACT_EXPECT) {
3321 if (prev_check->inverse)
3322 tcpcheck->expect_head = prev_check;
3323 continue;
3324 }
3325 if (prev_check->action != TCPCHK_ACT_COMMENT)
3326 break;
3327 }
3328 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003329 }
3330 else {
3331 ha_alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
3332 err_code |= ERR_ALERT | ERR_FATAL;
3333 goto out;
3334 }
3335 }
3336 else if (!strcmp(args[0], "monitor")) {
3337 if (curproxy == &defproxy) {
3338 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3339 err_code |= ERR_ALERT | ERR_FATAL;
3340 goto out;
3341 }
3342
3343 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3344 err_code |= ERR_WARN;
3345
3346 if (strcmp(args[1], "fail") == 0) {
3347 /* add a condition to fail monitor requests */
3348 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
3349 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
3350 file, linenum, args[0], args[1]);
3351 err_code |= ERR_ALERT | ERR_FATAL;
3352 goto out;
3353 }
3354
3355 err_code |= warnif_misplaced_monitor(curproxy, file, linenum, "monitor fail");
3356 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
3357 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
3358 file, linenum, args[0], args[1], errmsg);
3359 err_code |= ERR_ALERT | ERR_FATAL;
3360 goto out;
3361 }
3362 LIST_ADDQ(&curproxy->mon_fail_cond, &cond->list);
3363 }
3364 else {
3365 ha_alert("parsing [%s:%d] : '%s' only supports 'fail'.\n", file, linenum, args[0]);
3366 err_code |= ERR_ALERT | ERR_FATAL;
3367 goto out;
3368 }
3369 }
Willy Tarreaue5733232019-05-22 19:24:06 +02003370#ifdef USE_TPROXY
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003371 else if (!strcmp(args[0], "transparent")) {
3372 /* enable transparent proxy connections */
3373 curproxy->options |= PR_O_TRANSP;
3374 if (alertif_too_many_args(0, file, linenum, args, &err_code))
3375 goto out;
3376 }
3377#endif
3378 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3379 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
3380 err_code |= ERR_WARN;
3381
3382 if (*(args[1]) == 0) {
3383 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3384 err_code |= ERR_ALERT | ERR_FATAL;
3385 goto out;
3386 }
3387 curproxy->maxconn = atol(args[1]);
3388 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3389 goto out;
3390 }
3391 else if (!strcmp(args[0], "backlog")) { /* backlog */
3392 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3393 err_code |= ERR_WARN;
3394
3395 if (*(args[1]) == 0) {
3396 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3397 err_code |= ERR_ALERT | ERR_FATAL;
3398 goto out;
3399 }
3400 curproxy->backlog = atol(args[1]);
3401 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3402 goto out;
3403 }
3404 else if (!strcmp(args[0], "fullconn")) { /* fullconn */
3405 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
3406 err_code |= ERR_WARN;
3407
3408 if (*(args[1]) == 0) {
3409 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3410 err_code |= ERR_ALERT | ERR_FATAL;
3411 goto out;
3412 }
3413 curproxy->fullconn = atol(args[1]);
3414 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3415 goto out;
3416 }
3417 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3418 if (*(args[1]) == 0) {
3419 ha_alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
3420 err_code |= ERR_ALERT | ERR_FATAL;
3421 goto out;
3422 }
3423 err = parse_time_err(args[1], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +02003424 if (err == PARSE_TIME_OVER) {
3425 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to grace time, maximum value is 2147483647 ms (~24.8 days).\n",
3426 file, linenum, args[1]);
3427 err_code |= ERR_ALERT | ERR_FATAL;
3428 goto out;
3429 }
3430 else if (err == PARSE_TIME_UNDER) {
3431 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to grace time, minimum non-null value is 1 ms.\n",
3432 file, linenum, args[1]);
3433 err_code |= ERR_ALERT | ERR_FATAL;
3434 goto out;
3435 }
3436 else if (err) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003437 ha_alert("parsing [%s:%d] : unexpected character '%c' in grace time.\n",
3438 file, linenum, *err);
3439 err_code |= ERR_ALERT | ERR_FATAL;
3440 goto out;
3441 }
3442 curproxy->grace = val;
3443 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3444 goto out;
3445 }
3446 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3447 struct sockaddr_storage *sk;
3448 int port1, port2;
3449 struct protocol *proto;
3450
3451 if (curproxy == &defproxy) {
3452 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3453 err_code |= ERR_ALERT | ERR_FATAL;
3454 goto out;
3455 }
3456 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3457 err_code |= ERR_WARN;
3458
3459 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3460 if (!sk) {
3461 ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
3462 err_code |= ERR_ALERT | ERR_FATAL;
3463 goto out;
3464 }
3465
3466 proto = protocol_by_family(sk->ss_family);
3467 if (!proto || !proto->connect) {
3468 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3469 file, linenum, args[0], args[1]);
3470 err_code |= ERR_ALERT | ERR_FATAL;
3471 goto out;
3472 }
3473
3474 if (port1 != port2) {
3475 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'.\n",
3476 file, linenum, args[0], args[1]);
3477 err_code |= ERR_ALERT | ERR_FATAL;
3478 goto out;
3479 }
3480
3481 if (!port1) {
3482 ha_alert("parsing [%s:%d] : '%s' : missing port number in '%s', <addr:port> expected.\n",
3483 file, linenum, args[0], args[1]);
3484 err_code |= ERR_ALERT | ERR_FATAL;
3485 goto out;
3486 }
3487
3488 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3489 goto out;
3490
3491 curproxy->dispatch_addr = *sk;
3492 curproxy->options |= PR_O_DISPATCH;
3493 }
3494 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
3495 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3496 err_code |= ERR_WARN;
3497
3498 if (backend_parse_balance((const char **)args + 1, &errmsg, curproxy) < 0) {
3499 ha_alert("parsing [%s:%d] : %s %s\n", file, linenum, args[0], errmsg);
3500 err_code |= ERR_ALERT | ERR_FATAL;
3501 goto out;
3502 }
3503 }
3504 else if (!strcmp(args[0], "hash-type")) { /* set hashing method */
3505 /**
3506 * The syntax for hash-type config element is
3507 * hash-type {map-based|consistent} [[<algo>] avalanche]
3508 *
3509 * The default hash function is sdbm for map-based and sdbm+avalanche for consistent.
3510 */
3511 curproxy->lbprm.algo &= ~(BE_LB_HASH_TYPE | BE_LB_HASH_FUNC | BE_LB_HASH_MOD);
3512
3513 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3514 err_code |= ERR_WARN;
3515
3516 if (strcmp(args[1], "consistent") == 0) { /* use consistent hashing */
3517 curproxy->lbprm.algo |= BE_LB_HASH_CONS;
3518 }
3519 else if (strcmp(args[1], "map-based") == 0) { /* use map-based hashing */
3520 curproxy->lbprm.algo |= BE_LB_HASH_MAP;
3521 }
3522 else if (strcmp(args[1], "avalanche") == 0) {
3523 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]);
3524 err_code |= ERR_ALERT | ERR_FATAL;
3525 goto out;
3526 }
3527 else {
3528 ha_alert("parsing [%s:%d] : '%s' only supports 'consistent' and 'map-based'.\n", file, linenum, args[0]);
3529 err_code |= ERR_ALERT | ERR_FATAL;
3530 goto out;
3531 }
3532
3533 /* set the hash function to use */
3534 if (!*args[2]) {
3535 /* the default algo is sdbm */
3536 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3537
3538 /* if consistent with no argument, then avalanche modifier is also applied */
3539 if ((curproxy->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS)
3540 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3541 } else {
3542 /* set the hash function */
3543 if (!strcmp(args[2], "sdbm")) {
3544 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3545 }
3546 else if (!strcmp(args[2], "djb2")) {
3547 curproxy->lbprm.algo |= BE_LB_HFCN_DJB2;
3548 }
3549 else if (!strcmp(args[2], "wt6")) {
3550 curproxy->lbprm.algo |= BE_LB_HFCN_WT6;
3551 }
3552 else if (!strcmp(args[2], "crc32")) {
3553 curproxy->lbprm.algo |= BE_LB_HFCN_CRC32;
3554 }
3555 else {
3556 ha_alert("parsing [%s:%d] : '%s' only supports 'sdbm', 'djb2', 'crc32', or 'wt6' hash functions.\n", file, linenum, args[0]);
3557 err_code |= ERR_ALERT | ERR_FATAL;
3558 goto out;
3559 }
3560
3561 /* set the hash modifier */
3562 if (!strcmp(args[3], "avalanche")) {
3563 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3564 }
3565 else if (*args[3]) {
3566 ha_alert("parsing [%s:%d] : '%s' only supports 'avalanche' as a modifier for hash functions.\n", file, linenum, args[0]);
3567 err_code |= ERR_ALERT | ERR_FATAL;
3568 goto out;
3569 }
3570 }
3571 }
3572 else if (strcmp(args[0], "hash-balance-factor") == 0) {
3573 if (*(args[1]) == 0) {
3574 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3575 err_code |= ERR_ALERT | ERR_FATAL;
3576 goto out;
3577 }
Willy Tarreau76e84f52019-01-14 16:50:58 +01003578 curproxy->lbprm.hash_balance_factor = atol(args[1]);
3579 if (curproxy->lbprm.hash_balance_factor != 0 && curproxy->lbprm.hash_balance_factor <= 100) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003580 ha_alert("parsing [%s:%d] : '%s' must be 0 or greater than 100.\n", file, linenum, args[0]);
3581 err_code |= ERR_ALERT | ERR_FATAL;
3582 goto out;
3583 }
3584 }
3585 else if (strcmp(args[0], "unique-id-format") == 0) {
3586 if (!*(args[1])) {
3587 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3588 err_code |= ERR_ALERT | ERR_FATAL;
3589 goto out;
3590 }
3591 if (*(args[2])) {
3592 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3593 err_code |= ERR_ALERT | ERR_FATAL;
3594 goto out;
3595 }
3596 free(curproxy->conf.uniqueid_format_string);
3597 curproxy->conf.uniqueid_format_string = strdup(args[1]);
3598
3599 free(curproxy->conf.uif_file);
3600 curproxy->conf.uif_file = strdup(curproxy->conf.args.file);
3601 curproxy->conf.uif_line = curproxy->conf.args.line;
3602 }
3603
3604 else if (strcmp(args[0], "unique-id-header") == 0) {
Tim Duesterhus0643b0e2020-03-05 17:56:35 +01003605 char *copy;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003606 if (!*(args[1])) {
3607 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3608 err_code |= ERR_ALERT | ERR_FATAL;
3609 goto out;
3610 }
Tim Duesterhus0643b0e2020-03-05 17:56:35 +01003611 copy = strdup(args[1]);
3612 if (copy == NULL) {
3613 ha_alert("parsing [%s:%d] : failed to allocate memory for unique-id-header\n", file, linenum);
3614 err_code |= ERR_ALERT | ERR_FATAL;
3615 goto out;
3616 }
3617
3618 istfree(&curproxy->header_unique_id);
3619 curproxy->header_unique_id = ist(copy);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003620 }
3621
3622 else if (strcmp(args[0], "log-format") == 0) {
3623 if (!*(args[1])) {
3624 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3625 err_code |= ERR_ALERT | ERR_FATAL;
3626 goto out;
3627 }
3628 if (*(args[2])) {
3629 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3630 err_code |= ERR_ALERT | ERR_FATAL;
3631 goto out;
3632 }
3633 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
3634 char *oldlogformat = "log-format";
3635
3636 if (curproxy->conf.logformat_string == default_http_log_format)
3637 oldlogformat = "option httplog";
3638 else if (curproxy->conf.logformat_string == default_tcp_log_format)
3639 oldlogformat = "option tcplog";
3640 else if (curproxy->conf.logformat_string == clf_http_log_format)
3641 oldlogformat = "option httplog clf";
3642 ha_warning("parsing [%s:%d]: 'log-format' overrides previous '%s' in 'defaults' section.\n",
3643 file, linenum, oldlogformat);
3644 }
3645 if (curproxy->conf.logformat_string != default_http_log_format &&
3646 curproxy->conf.logformat_string != default_tcp_log_format &&
3647 curproxy->conf.logformat_string != clf_http_log_format)
3648 free(curproxy->conf.logformat_string);
3649 curproxy->conf.logformat_string = strdup(args[1]);
3650
3651 free(curproxy->conf.lfs_file);
3652 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
3653 curproxy->conf.lfs_line = curproxy->conf.args.line;
3654
3655 /* get a chance to improve log-format error reporting by
3656 * reporting the correct line-number when possible.
3657 */
3658 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3659 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format' directive is ignored in backends.\n",
3660 file, linenum, curproxy->id);
3661 err_code |= ERR_WARN;
3662 }
3663 }
3664 else if (!strcmp(args[0], "log-format-sd")) {
3665 if (!*(args[1])) {
3666 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3667 err_code |= ERR_ALERT | ERR_FATAL;
3668 goto out;
3669 }
3670 if (*(args[2])) {
3671 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3672 err_code |= ERR_ALERT | ERR_FATAL;
3673 goto out;
3674 }
3675
3676 if (curproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
3677 free(curproxy->conf.logformat_sd_string);
3678 curproxy->conf.logformat_sd_string = strdup(args[1]);
3679
3680 free(curproxy->conf.lfsd_file);
3681 curproxy->conf.lfsd_file = strdup(curproxy->conf.args.file);
3682 curproxy->conf.lfsd_line = curproxy->conf.args.line;
3683
3684 /* get a chance to improve log-format-sd error reporting by
3685 * reporting the correct line-number when possible.
3686 */
3687 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3688 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format-sd' directive is ignored in backends.\n",
3689 file, linenum, curproxy->id);
3690 err_code |= ERR_WARN;
3691 }
3692 }
3693 else if (!strcmp(args[0], "log-tag")) { /* tag to report to syslog */
3694 if (*(args[1]) == 0) {
3695 ha_alert("parsing [%s:%d] : '%s' expects a tag for use in syslog.\n", file, linenum, args[0]);
3696 err_code |= ERR_ALERT | ERR_FATAL;
3697 goto out;
3698 }
3699 chunk_destroy(&curproxy->log_tag);
3700 chunk_initstr(&curproxy->log_tag, strdup(args[1]));
3701 }
3702 else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
3703 if (!parse_logsrv(args, &curproxy->logsrvs, (kwm == KWM_NO), &errmsg)) {
3704 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
3705 err_code |= ERR_ALERT | ERR_FATAL;
3706 goto out;
3707 }
3708 }
3709 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
3710 int cur_arg;
3711 int port1, port2;
3712 struct sockaddr_storage *sk;
3713 struct protocol *proto;
3714
3715 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3716 err_code |= ERR_WARN;
3717
3718 if (!*args[1]) {
3719 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optionally '%s' <addr>, and '%s' <name>.\n",
3720 file, linenum, "source", "usesrc", "interface");
3721 err_code |= ERR_ALERT | ERR_FATAL;
3722 goto out;
3723 }
3724
Christopher Faulet31930372019-07-15 10:16:58 +02003725 /* we must first clear any optional default setting */
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003726 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3727 free(curproxy->conn_src.iface_name);
3728 curproxy->conn_src.iface_name = NULL;
3729 curproxy->conn_src.iface_len = 0;
3730
3731 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3732 if (!sk) {
3733 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3734 file, linenum, args[0], args[1], errmsg);
3735 err_code |= ERR_ALERT | ERR_FATAL;
3736 goto out;
3737 }
3738
3739 proto = protocol_by_family(sk->ss_family);
3740 if (!proto || !proto->connect) {
3741 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3742 file, linenum, args[0], args[1]);
3743 err_code |= ERR_ALERT | ERR_FATAL;
3744 goto out;
3745 }
3746
3747 if (port1 != port2) {
3748 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3749 file, linenum, args[0], args[1]);
3750 err_code |= ERR_ALERT | ERR_FATAL;
3751 goto out;
3752 }
3753
3754 curproxy->conn_src.source_addr = *sk;
3755 curproxy->conn_src.opts |= CO_SRC_BIND;
3756
3757 cur_arg = 2;
3758 while (*(args[cur_arg])) {
3759 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
3760#if defined(CONFIG_HAP_TRANSPARENT)
3761 if (!*args[cur_arg + 1]) {
3762 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
3763 file, linenum, "usesrc");
3764 err_code |= ERR_ALERT | ERR_FATAL;
3765 goto out;
3766 }
3767
3768 if (!strcmp(args[cur_arg + 1], "client")) {
3769 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3770 curproxy->conn_src.opts |= CO_SRC_TPROXY_CLI;
3771 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
3772 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3773 curproxy->conn_src.opts |= CO_SRC_TPROXY_CIP;
3774 } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
3775 char *name, *end;
3776
3777 name = args[cur_arg+1] + 7;
Willy Tarreau90807112020-02-25 08:16:33 +01003778 while (isspace((unsigned char)*name))
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003779 name++;
3780
3781 end = name;
Willy Tarreau90807112020-02-25 08:16:33 +01003782 while (*end && !isspace((unsigned char)*end) && *end != ',' && *end != ')')
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003783 end++;
3784
3785 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3786 curproxy->conn_src.opts |= CO_SRC_TPROXY_DYN;
3787 curproxy->conn_src.bind_hdr_name = calloc(1, end - name + 1);
3788 curproxy->conn_src.bind_hdr_len = end - name;
3789 memcpy(curproxy->conn_src.bind_hdr_name, name, end - name);
3790 curproxy->conn_src.bind_hdr_name[end-name] = '\0';
3791 curproxy->conn_src.bind_hdr_occ = -1;
3792
3793 /* now look for an occurrence number */
Willy Tarreau90807112020-02-25 08:16:33 +01003794 while (isspace((unsigned char)*end))
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003795 end++;
3796 if (*end == ',') {
3797 end++;
3798 name = end;
3799 if (*end == '-')
3800 end++;
Willy Tarreau90807112020-02-25 08:16:33 +01003801 while (isdigit((unsigned char)*end))
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003802 end++;
3803 curproxy->conn_src.bind_hdr_occ = strl2ic(name, end-name);
3804 }
3805
3806 if (curproxy->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
3807 ha_alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
3808 " occurrences values smaller than %d.\n",
3809 file, linenum, MAX_HDR_HISTORY);
3810 err_code |= ERR_ALERT | ERR_FATAL;
3811 goto out;
3812 }
3813 } else {
3814 struct sockaddr_storage *sk;
3815
3816 sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3817 if (!sk) {
3818 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3819 file, linenum, args[cur_arg], args[cur_arg+1], errmsg);
3820 err_code |= ERR_ALERT | ERR_FATAL;
3821 goto out;
3822 }
3823
3824 proto = protocol_by_family(sk->ss_family);
3825 if (!proto || !proto->connect) {
3826 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3827 file, linenum, args[cur_arg], args[cur_arg+1]);
3828 err_code |= ERR_ALERT | ERR_FATAL;
3829 goto out;
3830 }
3831
3832 if (port1 != port2) {
3833 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3834 file, linenum, args[cur_arg], args[cur_arg + 1]);
3835 err_code |= ERR_ALERT | ERR_FATAL;
3836 goto out;
3837 }
3838 curproxy->conn_src.tproxy_addr = *sk;
3839 curproxy->conn_src.opts |= CO_SRC_TPROXY_ADDR;
3840 }
3841 global.last_checks |= LSTCHK_NETADM;
3842#else /* no TPROXY support */
3843 ha_alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
3844 file, linenum, "usesrc");
3845 err_code |= ERR_ALERT | ERR_FATAL;
3846 goto out;
3847#endif
3848 cur_arg += 2;
3849 continue;
3850 }
3851
3852 if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
3853#ifdef SO_BINDTODEVICE
3854 if (!*args[cur_arg + 1]) {
3855 ha_alert("parsing [%s:%d] : '%s' : missing interface name.\n",
3856 file, linenum, args[0]);
3857 err_code |= ERR_ALERT | ERR_FATAL;
3858 goto out;
3859 }
3860 free(curproxy->conn_src.iface_name);
3861 curproxy->conn_src.iface_name = strdup(args[cur_arg + 1]);
3862 curproxy->conn_src.iface_len = strlen(curproxy->conn_src.iface_name);
3863 global.last_checks |= LSTCHK_NETADM;
3864#else
3865 ha_alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
3866 file, linenum, args[0], args[cur_arg]);
3867 err_code |= ERR_ALERT | ERR_FATAL;
3868 goto out;
3869#endif
3870 cur_arg += 2;
3871 continue;
3872 }
3873 ha_alert("parsing [%s:%d] : '%s' only supports optional keywords '%s' and '%s'.\n",
3874 file, linenum, args[0], "interface", "usesrc");
3875 err_code |= ERR_ALERT | ERR_FATAL;
3876 goto out;
3877 }
3878 }
3879 else if (!strcmp(args[0], "usesrc")) { /* address to use outside: needs "source" first */
3880 ha_alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
3881 file, linenum, "usesrc", "source");
3882 err_code |= ERR_ALERT | ERR_FATAL;
3883 goto out;
3884 }
3885 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003886 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
Willy Tarreau262c3f12019-12-17 06:52:51 +01003887 "Use 'http-request replace-path', 'http-request replace-uri' or 'http-request replace-header' instead.\n",
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003888 file, linenum, args[0]);
3889 err_code |= ERR_ALERT | ERR_FATAL;
3890 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003891 }
3892 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003893 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3894 "Use 'http-request del-header' instead.\n", file, linenum, args[0]);
3895 err_code |= ERR_ALERT | ERR_FATAL;
3896 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003897 }
3898 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003899 ha_alert("parsing [%s:%d] : The '%s' not supported anymore since HAProxy 2.1. "
3900 "Use 'http-request deny' instead.\n", file, linenum, args[0]);
3901 err_code |= ERR_ALERT | ERR_FATAL;
3902 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003903 }
3904 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003905 ha_alert("parsing [%s:%d] : The '%s' not supported anymore since HAProxy 2.1.\n", file, linenum, args[0]);
3906 err_code |= ERR_ALERT | ERR_FATAL;
3907 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003908 }
3909 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003910 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3911 "Use 'http-request allow' instead.\n", file, linenum, args[0]);
3912 err_code |= ERR_ALERT | ERR_FATAL;
3913 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003914 }
3915 else if (!strcmp(args[0], "reqtarpit")) { /* tarpit a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003916 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3917 "Use 'http-request tarpit' instead.\n", file, linenum, args[0]);
3918 err_code |= ERR_ALERT | ERR_FATAL;
3919 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003920 }
3921 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003922 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3923 "Use 'http-request replace-header' instead.\n", file, linenum, args[0]);
3924 err_code |= ERR_ALERT | ERR_FATAL;
3925 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003926 }
3927 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003928 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3929 "Use 'http-request del-header' instead.\n", file, linenum, args[0]);
3930 err_code |= ERR_ALERT | ERR_FATAL;
3931 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003932 }
3933 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003934 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3935 "Use 'http-request deny' instead.\n", file, linenum, args[0]);
3936 err_code |= ERR_ALERT | ERR_FATAL;
3937 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003938 }
3939 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003940 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1.\n", file, linenum, args[0]);
3941 err_code |= ERR_ALERT | ERR_FATAL;
3942 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003943 }
3944 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003945 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3946 "Use 'http-request allow' instead.\n", file, linenum, args[0]);
3947 err_code |= ERR_ALERT | ERR_FATAL;
3948 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003949 }
3950 else if (!strcmp(args[0], "reqitarpit")) { /* tarpit a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003951 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3952 "Use 'http-request tarpit' instead.\n", file, linenum, args[0]);
3953 err_code |= ERR_ALERT | ERR_FATAL;
3954 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003955 }
3956 else if (!strcmp(args[0], "reqadd")) { /* add request header */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003957 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3958 "Use 'http-request add-header' instead.\n", file, linenum, args[0]);
3959 err_code |= ERR_ALERT | ERR_FATAL;
3960 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003961 }
3962 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003963 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3964 "Use 'http-response replace-header' instead.\n", file, linenum, args[0]);
3965 err_code |= ERR_ALERT | ERR_FATAL;
3966 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003967 }
3968 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003969 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3970 "Use 'http-response del-header' .\n", file, linenum, args[0]);
3971 err_code |= ERR_ALERT | ERR_FATAL;
3972 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003973 }
3974 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003975 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3976 "Use 'http-response deny' instead.\n", file, linenum, args[0]);
3977 err_code |= ERR_ALERT | ERR_FATAL;
3978 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003979 }
3980 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
Balvinder Singh Rawatdef595e2020-03-14 12:11:50 +05303981 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003982 "Use 'http-response replace-header' instead.\n", file, linenum, args[0]);
3983 err_code |= ERR_ALERT | ERR_FATAL;
3984 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003985 }
3986 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003987 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3988 "Use 'http-response del-header' instead.\n", file, linenum, args[0]);
3989 err_code |= ERR_ALERT | ERR_FATAL;
3990 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003991 }
3992 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003993 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3994 "Use 'http-response deny' instead.\n", file, linenum, args[0]);
3995 err_code |= ERR_ALERT | ERR_FATAL;
3996 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003997 }
3998 else if (!strcmp(args[0], "rspadd")) { /* add response header */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003999 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
4000 "Use 'http-response add-header' instead.\n", file, linenum, args[0]);
4001 err_code |= ERR_ALERT | ERR_FATAL;
4002 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004003 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004004 else {
4005 struct cfg_kw_list *kwl;
4006 int index;
4007
4008 list_for_each_entry(kwl, &cfg_keywords.list, list) {
4009 for (index = 0; kwl->kw[index].kw != NULL; index++) {
4010 if (kwl->kw[index].section != CFG_LISTEN)
4011 continue;
4012 if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
4013 /* prepare error message just in case */
4014 rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, file, linenum, &errmsg);
4015 if (rc < 0) {
4016 ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4017 err_code |= ERR_ALERT | ERR_FATAL;
4018 goto out;
4019 }
4020 else if (rc > 0) {
4021 ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4022 err_code |= ERR_WARN;
4023 goto out;
4024 }
4025 goto out;
4026 }
4027 }
4028 }
4029
4030 ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
4031 err_code |= ERR_ALERT | ERR_FATAL;
4032 goto out;
4033 }
4034 out:
4035 free(errmsg);
4036 return err_code;
4037}