blob: 13ce19c2b5e233f463ae5bf826cc2cf494b6d865 [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 */
Gaetan Rivetf8ba6772020-02-07 15:37:17 +01003100 else if (strcmp(args[cur_arg], "linger") == 0) {
3101 tcpcheck->conn_opts |= TCPCHK_OPT_LINGER;
3102 cur_arg++;
3103 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003104 /* comment for this tcpcheck line */
3105 else if (strcmp(args[cur_arg], "comment") == 0) {
3106 if (!*args[cur_arg + 1]) {
3107 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3108 file, linenum, args[cur_arg]);
3109 err_code |= ERR_ALERT | ERR_FATAL;
3110 goto out;
3111 }
3112 tcpcheck->comment = strdup(args[cur_arg + 1]);
3113 cur_arg += 2;
3114 }
3115 else {
3116#ifdef USE_OPENSSL
Gaetan Rivetf8ba6772020-02-07 15:37:17 +01003117 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy', 'ssl' or 'linger' but got '%s' as argument.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003118#else /* USE_OPENSSL */
Gaetan Rivetf8ba6772020-02-07 15:37:17 +01003119 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or 'linger' but got '%s' as argument.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003120#endif /* USE_OPENSSL */
3121 file, linenum, args[0], args[1], args[cur_arg]);
3122 err_code |= ERR_ALERT | ERR_FATAL;
3123 goto out;
3124 }
3125
3126 }
3127
3128 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3129 }
3130 else if (strcmp(args[1], "send") == 0) {
3131 if (! *(args[2]) ) {
3132 /* SEND string expected */
3133 ha_alert("parsing [%s:%d] : '%s %s %s' expects <STRING> as argument.\n",
3134 file, linenum, args[0], args[1], args[2]);
3135 err_code |= ERR_ALERT | ERR_FATAL;
3136 goto out;
3137 } else {
3138 struct tcpcheck_rule *tcpcheck;
3139
3140 tcpcheck = calloc(1, sizeof(*tcpcheck));
3141
3142 tcpcheck->action = TCPCHK_ACT_SEND;
3143 tcpcheck->string_len = strlen(args[2]);
3144 tcpcheck->string = strdup(args[2]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003145
3146 /* comment for this tcpcheck line */
3147 if (strcmp(args[3], "comment") == 0) {
3148 if (!*args[4]) {
3149 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3150 file, linenum, args[3]);
3151 err_code |= ERR_ALERT | ERR_FATAL;
3152 goto out;
3153 }
3154 tcpcheck->comment = strdup(args[4]);
3155 }
3156
3157 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3158 }
3159 }
3160 else if (strcmp(args[1], "send-binary") == 0) {
3161 if (! *(args[2]) ) {
3162 /* SEND binary string expected */
3163 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument.\n",
3164 file, linenum, args[0], args[1], args[2]);
3165 err_code |= ERR_ALERT | ERR_FATAL;
3166 goto out;
3167 } else {
3168 struct tcpcheck_rule *tcpcheck;
3169 char *err = NULL;
3170
3171 tcpcheck = calloc(1, sizeof(*tcpcheck));
3172
3173 tcpcheck->action = TCPCHK_ACT_SEND;
3174 if (parse_binary(args[2], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3175 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3176 file, linenum, args[0], args[1], args[2], err);
3177 err_code |= ERR_ALERT | ERR_FATAL;
3178 goto out;
3179 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003180
3181 /* comment for this tcpcheck line */
3182 if (strcmp(args[3], "comment") == 0) {
3183 if (!*args[4]) {
3184 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3185 file, linenum, args[3]);
3186 err_code |= ERR_ALERT | ERR_FATAL;
3187 goto out;
3188 }
3189 tcpcheck->comment = strdup(args[4]);
3190 }
3191
3192 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3193 }
3194 }
3195 else if (strcmp(args[1], "expect") == 0) {
Gaetan Rivet4038b942020-02-26 16:19:40 +01003196 struct tcpcheck_rule *tcpcheck, *prev_check;
Gaetan Rivetb616add2020-02-07 15:37:17 +01003197 struct tcpcheck_expect *expect;
Gaetan Rivet1afd8262020-02-07 15:37:17 +01003198 long min_recv = -1;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003199 const char *ptr_arg;
3200 int cur_arg;
3201 int inverse = 0;
3202
3203 if (curproxy->options2 & PR_O2_EXP_TYPE) {
3204 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
3205 err_code |= ERR_ALERT | ERR_FATAL;
3206 goto out;
3207 }
3208
3209 cur_arg = 2;
Gaetan Rivet1afd8262020-02-07 15:37:17 +01003210
3211 /* Parse potential the minimum amount of data
3212 * required before proceeding with the match.
3213 */
3214 if (strcmp(args[cur_arg], "min-recv") == 0) {
3215 if (!*(args[cur_arg + 1])) {
3216 ha_alert("parsing [%s:%d] : '%s %s %s' expects an integer as an argument.\n",
3217 file, linenum, args[0], args[1], args[2]);
3218 err_code |= ERR_ALERT | ERR_FATAL;
3219 goto out;
3220 }
3221
3222 /* Use an signed integer here because of chksize */
3223 min_recv = atol(args[cur_arg + 1]);
3224 if (min_recv < -1 || min_recv > INT_MAX) {
3225 ha_alert("parsing [%s:%d] : '%s %s %s' expects -1 or an integer from 0 to INT_MAX.\n",
3226 file, linenum, args[0], args[1], args[2]);
3227 err_code |= ERR_ALERT | ERR_FATAL;
3228 goto out;
3229 }
3230
3231 cur_arg += 2;
3232 }
3233
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003234 /* consider exclamation marks, sole or at the beginning of a word */
3235 while (*(ptr_arg = args[cur_arg])) {
3236 while (*ptr_arg == '!') {
3237 inverse = !inverse;
3238 ptr_arg++;
3239 }
3240 if (*ptr_arg)
3241 break;
3242 cur_arg++;
3243 }
Gaetan Rivet8b00b362020-02-07 15:37:17 +01003244
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003245 /* now ptr_arg points to the beginning of a word past any possible
3246 * exclamation mark, and cur_arg is the argument which holds this word.
3247 */
Gaetan Rivet8b00b362020-02-07 15:37:17 +01003248
3249 tcpcheck = calloc(1, sizeof(*tcpcheck));
3250 tcpcheck->action = TCPCHK_ACT_EXPECT;
Gaetan Rivetb616add2020-02-07 15:37:17 +01003251 expect = &tcpcheck->expect;
3252 expect->inverse = inverse;
3253 expect->min_recv = min_recv;
Gaetan Rivet8b00b362020-02-07 15:37:17 +01003254
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003255 if (strcmp(ptr_arg, "binary") == 0) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003256 char *err = NULL;
3257
3258 if (!*(args[cur_arg + 1])) {
3259 ha_alert("parsing [%s:%d] : '%s %s %s' expects <binary string> as an argument.\n",
3260 file, linenum, args[0], args[1], ptr_arg);
3261 err_code |= ERR_ALERT | ERR_FATAL;
3262 goto out;
3263 }
3264
Gaetan Rivetb616add2020-02-07 15:37:17 +01003265 expect->type = TCPCHK_EXPECT_BINARY;
3266 if (parse_binary(args[cur_arg + 1], &expect->string, &expect->length, &err) == 0) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003267 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3268 file, linenum, args[0], args[1], args[2], err);
3269 err_code |= ERR_ALERT | ERR_FATAL;
3270 goto out;
3271 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003272 }
3273 else if (strcmp(ptr_arg, "string") == 0) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003274 if (!*(args[cur_arg + 1])) {
3275 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3276 file, linenum, args[0], args[1], ptr_arg);
3277 err_code |= ERR_ALERT | ERR_FATAL;
3278 goto out;
3279 }
3280
Gaetan Rivetb616add2020-02-07 15:37:17 +01003281 expect->type = TCPCHK_EXPECT_STRING;
3282 expect->string = strdup(args[cur_arg + 1]);
3283 expect->length = strlen(expect->string);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003284 }
Gaetan Rivetefab6c62020-02-07 15:37:17 +01003285 else if (strcmp(ptr_arg, "rstring") == 0 ||
3286 strcmp(ptr_arg, "rbinary") == 0) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003287 if (!*(args[cur_arg + 1])) {
3288 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3289 file, linenum, args[0], args[1], ptr_arg);
3290 err_code |= ERR_ALERT | ERR_FATAL;
3291 goto out;
3292 }
3293
Gaetan Rivetefab6c62020-02-07 15:37:17 +01003294 expect->type = ((strcmp(ptr_arg, "rbinary") == 0) ? TCPCHK_EXPECT_REGEX_BINARY : TCPCHK_EXPECT_REGEX);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003295 error = NULL;
Gaetan Rivetb616add2020-02-07 15:37:17 +01003296 if (!(expect->regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
Dragan Dosen26743032019-04-30 15:54:36 +02003297 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003298 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3299 free(error);
3300 err_code |= ERR_ALERT | ERR_FATAL;
3301 goto out;
3302 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003303 }
3304 else {
Gaetan Rivetefab6c62020-02-07 15:37:17 +01003305 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'binary', 'string', 'rstring', 'rbinary', found '%s'.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003306 file, linenum, args[0], args[1], ptr_arg);
3307 err_code |= ERR_ALERT | ERR_FATAL;
3308 goto out;
3309 }
Gaetan Rivet4038b942020-02-26 16:19:40 +01003310
Gaetan Rivet8b00b362020-02-07 15:37:17 +01003311 /* tcpcheck comment */
3312 cur_arg += 2;
3313 if (strcmp(args[cur_arg], "comment") == 0) {
3314 if (!*args[cur_arg + 1]) {
3315 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3316 file, linenum, args[cur_arg + 1]);
3317 err_code |= ERR_ALERT | ERR_FATAL;
3318 goto out;
3319 }
3320 tcpcheck->comment = strdup(args[cur_arg + 1]);
3321 }
3322
Gaetan Rivet4038b942020-02-26 16:19:40 +01003323 /* All tcp-check expect points back to the first inverse expect rule
3324 * in a chain of one or more expect rule, potentially itself.
3325 */
Gaetan Rivetb616add2020-02-07 15:37:17 +01003326 tcpcheck->expect.head = tcpcheck;
Gaetan Rivet4038b942020-02-26 16:19:40 +01003327 list_for_each_entry_rev(prev_check, &curproxy->tcpcheck_rules, list) {
3328 if (prev_check->action == TCPCHK_ACT_EXPECT) {
Gaetan Rivetb616add2020-02-07 15:37:17 +01003329 if (prev_check->expect.inverse)
3330 tcpcheck->expect.head = prev_check;
Gaetan Rivet4038b942020-02-26 16:19:40 +01003331 continue;
3332 }
3333 if (prev_check->action != TCPCHK_ACT_COMMENT)
3334 break;
3335 }
3336 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003337 }
3338 else {
3339 ha_alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
3340 err_code |= ERR_ALERT | ERR_FATAL;
3341 goto out;
3342 }
3343 }
3344 else if (!strcmp(args[0], "monitor")) {
3345 if (curproxy == &defproxy) {
3346 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3347 err_code |= ERR_ALERT | ERR_FATAL;
3348 goto out;
3349 }
3350
3351 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3352 err_code |= ERR_WARN;
3353
3354 if (strcmp(args[1], "fail") == 0) {
3355 /* add a condition to fail monitor requests */
3356 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
3357 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
3358 file, linenum, args[0], args[1]);
3359 err_code |= ERR_ALERT | ERR_FATAL;
3360 goto out;
3361 }
3362
3363 err_code |= warnif_misplaced_monitor(curproxy, file, linenum, "monitor fail");
3364 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
3365 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
3366 file, linenum, args[0], args[1], errmsg);
3367 err_code |= ERR_ALERT | ERR_FATAL;
3368 goto out;
3369 }
3370 LIST_ADDQ(&curproxy->mon_fail_cond, &cond->list);
3371 }
3372 else {
3373 ha_alert("parsing [%s:%d] : '%s' only supports 'fail'.\n", file, linenum, args[0]);
3374 err_code |= ERR_ALERT | ERR_FATAL;
3375 goto out;
3376 }
3377 }
Willy Tarreaue5733232019-05-22 19:24:06 +02003378#ifdef USE_TPROXY
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003379 else if (!strcmp(args[0], "transparent")) {
3380 /* enable transparent proxy connections */
3381 curproxy->options |= PR_O_TRANSP;
3382 if (alertif_too_many_args(0, file, linenum, args, &err_code))
3383 goto out;
3384 }
3385#endif
3386 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3387 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
3388 err_code |= ERR_WARN;
3389
3390 if (*(args[1]) == 0) {
3391 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3392 err_code |= ERR_ALERT | ERR_FATAL;
3393 goto out;
3394 }
3395 curproxy->maxconn = atol(args[1]);
3396 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3397 goto out;
3398 }
3399 else if (!strcmp(args[0], "backlog")) { /* backlog */
3400 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3401 err_code |= ERR_WARN;
3402
3403 if (*(args[1]) == 0) {
3404 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3405 err_code |= ERR_ALERT | ERR_FATAL;
3406 goto out;
3407 }
3408 curproxy->backlog = atol(args[1]);
3409 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3410 goto out;
3411 }
3412 else if (!strcmp(args[0], "fullconn")) { /* fullconn */
3413 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
3414 err_code |= ERR_WARN;
3415
3416 if (*(args[1]) == 0) {
3417 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3418 err_code |= ERR_ALERT | ERR_FATAL;
3419 goto out;
3420 }
3421 curproxy->fullconn = atol(args[1]);
3422 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3423 goto out;
3424 }
3425 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3426 if (*(args[1]) == 0) {
3427 ha_alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
3428 err_code |= ERR_ALERT | ERR_FATAL;
3429 goto out;
3430 }
3431 err = parse_time_err(args[1], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +02003432 if (err == PARSE_TIME_OVER) {
3433 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to grace time, maximum value is 2147483647 ms (~24.8 days).\n",
3434 file, linenum, args[1]);
3435 err_code |= ERR_ALERT | ERR_FATAL;
3436 goto out;
3437 }
3438 else if (err == PARSE_TIME_UNDER) {
3439 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to grace time, minimum non-null value is 1 ms.\n",
3440 file, linenum, args[1]);
3441 err_code |= ERR_ALERT | ERR_FATAL;
3442 goto out;
3443 }
3444 else if (err) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003445 ha_alert("parsing [%s:%d] : unexpected character '%c' in grace time.\n",
3446 file, linenum, *err);
3447 err_code |= ERR_ALERT | ERR_FATAL;
3448 goto out;
3449 }
3450 curproxy->grace = val;
3451 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3452 goto out;
3453 }
3454 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3455 struct sockaddr_storage *sk;
3456 int port1, port2;
3457 struct protocol *proto;
3458
3459 if (curproxy == &defproxy) {
3460 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3461 err_code |= ERR_ALERT | ERR_FATAL;
3462 goto out;
3463 }
3464 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3465 err_code |= ERR_WARN;
3466
3467 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3468 if (!sk) {
3469 ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
3470 err_code |= ERR_ALERT | ERR_FATAL;
3471 goto out;
3472 }
3473
3474 proto = protocol_by_family(sk->ss_family);
3475 if (!proto || !proto->connect) {
3476 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3477 file, linenum, args[0], args[1]);
3478 err_code |= ERR_ALERT | ERR_FATAL;
3479 goto out;
3480 }
3481
3482 if (port1 != port2) {
3483 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'.\n",
3484 file, linenum, args[0], args[1]);
3485 err_code |= ERR_ALERT | ERR_FATAL;
3486 goto out;
3487 }
3488
3489 if (!port1) {
3490 ha_alert("parsing [%s:%d] : '%s' : missing port number in '%s', <addr:port> expected.\n",
3491 file, linenum, args[0], args[1]);
3492 err_code |= ERR_ALERT | ERR_FATAL;
3493 goto out;
3494 }
3495
3496 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3497 goto out;
3498
3499 curproxy->dispatch_addr = *sk;
3500 curproxy->options |= PR_O_DISPATCH;
3501 }
3502 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
3503 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3504 err_code |= ERR_WARN;
3505
3506 if (backend_parse_balance((const char **)args + 1, &errmsg, curproxy) < 0) {
3507 ha_alert("parsing [%s:%d] : %s %s\n", file, linenum, args[0], errmsg);
3508 err_code |= ERR_ALERT | ERR_FATAL;
3509 goto out;
3510 }
3511 }
3512 else if (!strcmp(args[0], "hash-type")) { /* set hashing method */
3513 /**
3514 * The syntax for hash-type config element is
3515 * hash-type {map-based|consistent} [[<algo>] avalanche]
3516 *
3517 * The default hash function is sdbm for map-based and sdbm+avalanche for consistent.
3518 */
3519 curproxy->lbprm.algo &= ~(BE_LB_HASH_TYPE | BE_LB_HASH_FUNC | BE_LB_HASH_MOD);
3520
3521 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3522 err_code |= ERR_WARN;
3523
3524 if (strcmp(args[1], "consistent") == 0) { /* use consistent hashing */
3525 curproxy->lbprm.algo |= BE_LB_HASH_CONS;
3526 }
3527 else if (strcmp(args[1], "map-based") == 0) { /* use map-based hashing */
3528 curproxy->lbprm.algo |= BE_LB_HASH_MAP;
3529 }
3530 else if (strcmp(args[1], "avalanche") == 0) {
3531 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]);
3532 err_code |= ERR_ALERT | ERR_FATAL;
3533 goto out;
3534 }
3535 else {
3536 ha_alert("parsing [%s:%d] : '%s' only supports 'consistent' and 'map-based'.\n", file, linenum, args[0]);
3537 err_code |= ERR_ALERT | ERR_FATAL;
3538 goto out;
3539 }
3540
3541 /* set the hash function to use */
3542 if (!*args[2]) {
3543 /* the default algo is sdbm */
3544 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3545
3546 /* if consistent with no argument, then avalanche modifier is also applied */
3547 if ((curproxy->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS)
3548 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3549 } else {
3550 /* set the hash function */
3551 if (!strcmp(args[2], "sdbm")) {
3552 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3553 }
3554 else if (!strcmp(args[2], "djb2")) {
3555 curproxy->lbprm.algo |= BE_LB_HFCN_DJB2;
3556 }
3557 else if (!strcmp(args[2], "wt6")) {
3558 curproxy->lbprm.algo |= BE_LB_HFCN_WT6;
3559 }
3560 else if (!strcmp(args[2], "crc32")) {
3561 curproxy->lbprm.algo |= BE_LB_HFCN_CRC32;
3562 }
3563 else {
3564 ha_alert("parsing [%s:%d] : '%s' only supports 'sdbm', 'djb2', 'crc32', or 'wt6' hash functions.\n", file, linenum, args[0]);
3565 err_code |= ERR_ALERT | ERR_FATAL;
3566 goto out;
3567 }
3568
3569 /* set the hash modifier */
3570 if (!strcmp(args[3], "avalanche")) {
3571 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3572 }
3573 else if (*args[3]) {
3574 ha_alert("parsing [%s:%d] : '%s' only supports 'avalanche' as a modifier for hash functions.\n", file, linenum, args[0]);
3575 err_code |= ERR_ALERT | ERR_FATAL;
3576 goto out;
3577 }
3578 }
3579 }
3580 else if (strcmp(args[0], "hash-balance-factor") == 0) {
3581 if (*(args[1]) == 0) {
3582 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3583 err_code |= ERR_ALERT | ERR_FATAL;
3584 goto out;
3585 }
Willy Tarreau76e84f52019-01-14 16:50:58 +01003586 curproxy->lbprm.hash_balance_factor = atol(args[1]);
3587 if (curproxy->lbprm.hash_balance_factor != 0 && curproxy->lbprm.hash_balance_factor <= 100) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003588 ha_alert("parsing [%s:%d] : '%s' must be 0 or greater than 100.\n", file, linenum, args[0]);
3589 err_code |= ERR_ALERT | ERR_FATAL;
3590 goto out;
3591 }
3592 }
3593 else if (strcmp(args[0], "unique-id-format") == 0) {
3594 if (!*(args[1])) {
3595 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3596 err_code |= ERR_ALERT | ERR_FATAL;
3597 goto out;
3598 }
3599 if (*(args[2])) {
3600 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3601 err_code |= ERR_ALERT | ERR_FATAL;
3602 goto out;
3603 }
3604 free(curproxy->conf.uniqueid_format_string);
3605 curproxy->conf.uniqueid_format_string = strdup(args[1]);
3606
3607 free(curproxy->conf.uif_file);
3608 curproxy->conf.uif_file = strdup(curproxy->conf.args.file);
3609 curproxy->conf.uif_line = curproxy->conf.args.line;
3610 }
3611
3612 else if (strcmp(args[0], "unique-id-header") == 0) {
Tim Duesterhus0643b0e2020-03-05 17:56:35 +01003613 char *copy;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003614 if (!*(args[1])) {
3615 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3616 err_code |= ERR_ALERT | ERR_FATAL;
3617 goto out;
3618 }
Tim Duesterhus0643b0e2020-03-05 17:56:35 +01003619 copy = strdup(args[1]);
3620 if (copy == NULL) {
3621 ha_alert("parsing [%s:%d] : failed to allocate memory for unique-id-header\n", file, linenum);
3622 err_code |= ERR_ALERT | ERR_FATAL;
3623 goto out;
3624 }
3625
3626 istfree(&curproxy->header_unique_id);
3627 curproxy->header_unique_id = ist(copy);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003628 }
3629
3630 else if (strcmp(args[0], "log-format") == 0) {
3631 if (!*(args[1])) {
3632 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3633 err_code |= ERR_ALERT | ERR_FATAL;
3634 goto out;
3635 }
3636 if (*(args[2])) {
3637 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3638 err_code |= ERR_ALERT | ERR_FATAL;
3639 goto out;
3640 }
3641 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
3642 char *oldlogformat = "log-format";
3643
3644 if (curproxy->conf.logformat_string == default_http_log_format)
3645 oldlogformat = "option httplog";
3646 else if (curproxy->conf.logformat_string == default_tcp_log_format)
3647 oldlogformat = "option tcplog";
3648 else if (curproxy->conf.logformat_string == clf_http_log_format)
3649 oldlogformat = "option httplog clf";
3650 ha_warning("parsing [%s:%d]: 'log-format' overrides previous '%s' in 'defaults' section.\n",
3651 file, linenum, oldlogformat);
3652 }
3653 if (curproxy->conf.logformat_string != default_http_log_format &&
3654 curproxy->conf.logformat_string != default_tcp_log_format &&
3655 curproxy->conf.logformat_string != clf_http_log_format)
3656 free(curproxy->conf.logformat_string);
3657 curproxy->conf.logformat_string = strdup(args[1]);
3658
3659 free(curproxy->conf.lfs_file);
3660 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
3661 curproxy->conf.lfs_line = curproxy->conf.args.line;
3662
3663 /* get a chance to improve log-format error reporting by
3664 * reporting the correct line-number when possible.
3665 */
3666 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3667 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format' directive is ignored in backends.\n",
3668 file, linenum, curproxy->id);
3669 err_code |= ERR_WARN;
3670 }
3671 }
3672 else if (!strcmp(args[0], "log-format-sd")) {
3673 if (!*(args[1])) {
3674 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3675 err_code |= ERR_ALERT | ERR_FATAL;
3676 goto out;
3677 }
3678 if (*(args[2])) {
3679 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3680 err_code |= ERR_ALERT | ERR_FATAL;
3681 goto out;
3682 }
3683
3684 if (curproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
3685 free(curproxy->conf.logformat_sd_string);
3686 curproxy->conf.logformat_sd_string = strdup(args[1]);
3687
3688 free(curproxy->conf.lfsd_file);
3689 curproxy->conf.lfsd_file = strdup(curproxy->conf.args.file);
3690 curproxy->conf.lfsd_line = curproxy->conf.args.line;
3691
3692 /* get a chance to improve log-format-sd error reporting by
3693 * reporting the correct line-number when possible.
3694 */
3695 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3696 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format-sd' directive is ignored in backends.\n",
3697 file, linenum, curproxy->id);
3698 err_code |= ERR_WARN;
3699 }
3700 }
3701 else if (!strcmp(args[0], "log-tag")) { /* tag to report to syslog */
3702 if (*(args[1]) == 0) {
3703 ha_alert("parsing [%s:%d] : '%s' expects a tag for use in syslog.\n", file, linenum, args[0]);
3704 err_code |= ERR_ALERT | ERR_FATAL;
3705 goto out;
3706 }
3707 chunk_destroy(&curproxy->log_tag);
3708 chunk_initstr(&curproxy->log_tag, strdup(args[1]));
3709 }
3710 else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
3711 if (!parse_logsrv(args, &curproxy->logsrvs, (kwm == KWM_NO), &errmsg)) {
3712 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
3713 err_code |= ERR_ALERT | ERR_FATAL;
3714 goto out;
3715 }
3716 }
3717 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
3718 int cur_arg;
3719 int port1, port2;
3720 struct sockaddr_storage *sk;
3721 struct protocol *proto;
3722
3723 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3724 err_code |= ERR_WARN;
3725
3726 if (!*args[1]) {
3727 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optionally '%s' <addr>, and '%s' <name>.\n",
3728 file, linenum, "source", "usesrc", "interface");
3729 err_code |= ERR_ALERT | ERR_FATAL;
3730 goto out;
3731 }
3732
Christopher Faulet31930372019-07-15 10:16:58 +02003733 /* we must first clear any optional default setting */
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003734 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3735 free(curproxy->conn_src.iface_name);
3736 curproxy->conn_src.iface_name = NULL;
3737 curproxy->conn_src.iface_len = 0;
3738
3739 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3740 if (!sk) {
3741 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3742 file, linenum, args[0], args[1], errmsg);
3743 err_code |= ERR_ALERT | ERR_FATAL;
3744 goto out;
3745 }
3746
3747 proto = protocol_by_family(sk->ss_family);
3748 if (!proto || !proto->connect) {
3749 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3750 file, linenum, args[0], args[1]);
3751 err_code |= ERR_ALERT | ERR_FATAL;
3752 goto out;
3753 }
3754
3755 if (port1 != port2) {
3756 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3757 file, linenum, args[0], args[1]);
3758 err_code |= ERR_ALERT | ERR_FATAL;
3759 goto out;
3760 }
3761
3762 curproxy->conn_src.source_addr = *sk;
3763 curproxy->conn_src.opts |= CO_SRC_BIND;
3764
3765 cur_arg = 2;
3766 while (*(args[cur_arg])) {
3767 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
3768#if defined(CONFIG_HAP_TRANSPARENT)
3769 if (!*args[cur_arg + 1]) {
3770 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
3771 file, linenum, "usesrc");
3772 err_code |= ERR_ALERT | ERR_FATAL;
3773 goto out;
3774 }
3775
3776 if (!strcmp(args[cur_arg + 1], "client")) {
3777 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3778 curproxy->conn_src.opts |= CO_SRC_TPROXY_CLI;
3779 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
3780 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3781 curproxy->conn_src.opts |= CO_SRC_TPROXY_CIP;
3782 } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
3783 char *name, *end;
3784
3785 name = args[cur_arg+1] + 7;
Willy Tarreau90807112020-02-25 08:16:33 +01003786 while (isspace((unsigned char)*name))
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003787 name++;
3788
3789 end = name;
Willy Tarreau90807112020-02-25 08:16:33 +01003790 while (*end && !isspace((unsigned char)*end) && *end != ',' && *end != ')')
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003791 end++;
3792
3793 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3794 curproxy->conn_src.opts |= CO_SRC_TPROXY_DYN;
3795 curproxy->conn_src.bind_hdr_name = calloc(1, end - name + 1);
3796 curproxy->conn_src.bind_hdr_len = end - name;
3797 memcpy(curproxy->conn_src.bind_hdr_name, name, end - name);
3798 curproxy->conn_src.bind_hdr_name[end-name] = '\0';
3799 curproxy->conn_src.bind_hdr_occ = -1;
3800
3801 /* now look for an occurrence number */
Willy Tarreau90807112020-02-25 08:16:33 +01003802 while (isspace((unsigned char)*end))
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003803 end++;
3804 if (*end == ',') {
3805 end++;
3806 name = end;
3807 if (*end == '-')
3808 end++;
Willy Tarreau90807112020-02-25 08:16:33 +01003809 while (isdigit((unsigned char)*end))
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003810 end++;
3811 curproxy->conn_src.bind_hdr_occ = strl2ic(name, end-name);
3812 }
3813
3814 if (curproxy->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
3815 ha_alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
3816 " occurrences values smaller than %d.\n",
3817 file, linenum, MAX_HDR_HISTORY);
3818 err_code |= ERR_ALERT | ERR_FATAL;
3819 goto out;
3820 }
3821 } else {
3822 struct sockaddr_storage *sk;
3823
3824 sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3825 if (!sk) {
3826 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3827 file, linenum, args[cur_arg], args[cur_arg+1], errmsg);
3828 err_code |= ERR_ALERT | ERR_FATAL;
3829 goto out;
3830 }
3831
3832 proto = protocol_by_family(sk->ss_family);
3833 if (!proto || !proto->connect) {
3834 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3835 file, linenum, args[cur_arg], args[cur_arg+1]);
3836 err_code |= ERR_ALERT | ERR_FATAL;
3837 goto out;
3838 }
3839
3840 if (port1 != port2) {
3841 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3842 file, linenum, args[cur_arg], args[cur_arg + 1]);
3843 err_code |= ERR_ALERT | ERR_FATAL;
3844 goto out;
3845 }
3846 curproxy->conn_src.tproxy_addr = *sk;
3847 curproxy->conn_src.opts |= CO_SRC_TPROXY_ADDR;
3848 }
3849 global.last_checks |= LSTCHK_NETADM;
3850#else /* no TPROXY support */
3851 ha_alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
3852 file, linenum, "usesrc");
3853 err_code |= ERR_ALERT | ERR_FATAL;
3854 goto out;
3855#endif
3856 cur_arg += 2;
3857 continue;
3858 }
3859
3860 if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
3861#ifdef SO_BINDTODEVICE
3862 if (!*args[cur_arg + 1]) {
3863 ha_alert("parsing [%s:%d] : '%s' : missing interface name.\n",
3864 file, linenum, args[0]);
3865 err_code |= ERR_ALERT | ERR_FATAL;
3866 goto out;
3867 }
3868 free(curproxy->conn_src.iface_name);
3869 curproxy->conn_src.iface_name = strdup(args[cur_arg + 1]);
3870 curproxy->conn_src.iface_len = strlen(curproxy->conn_src.iface_name);
3871 global.last_checks |= LSTCHK_NETADM;
3872#else
3873 ha_alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
3874 file, linenum, args[0], args[cur_arg]);
3875 err_code |= ERR_ALERT | ERR_FATAL;
3876 goto out;
3877#endif
3878 cur_arg += 2;
3879 continue;
3880 }
3881 ha_alert("parsing [%s:%d] : '%s' only supports optional keywords '%s' and '%s'.\n",
3882 file, linenum, args[0], "interface", "usesrc");
3883 err_code |= ERR_ALERT | ERR_FATAL;
3884 goto out;
3885 }
3886 }
3887 else if (!strcmp(args[0], "usesrc")) { /* address to use outside: needs "source" first */
3888 ha_alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
3889 file, linenum, "usesrc", "source");
3890 err_code |= ERR_ALERT | ERR_FATAL;
3891 goto out;
3892 }
3893 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003894 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
Willy Tarreau262c3f12019-12-17 06:52:51 +01003895 "Use 'http-request replace-path', 'http-request replace-uri' or 'http-request replace-header' instead.\n",
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003896 file, linenum, args[0]);
3897 err_code |= ERR_ALERT | ERR_FATAL;
3898 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003899 }
3900 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003901 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3902 "Use 'http-request del-header' instead.\n", file, linenum, args[0]);
3903 err_code |= ERR_ALERT | ERR_FATAL;
3904 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003905 }
3906 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003907 ha_alert("parsing [%s:%d] : The '%s' not supported anymore since HAProxy 2.1. "
3908 "Use 'http-request deny' instead.\n", file, linenum, args[0]);
3909 err_code |= ERR_ALERT | ERR_FATAL;
3910 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003911 }
3912 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003913 ha_alert("parsing [%s:%d] : The '%s' not supported anymore since HAProxy 2.1.\n", file, linenum, args[0]);
3914 err_code |= ERR_ALERT | ERR_FATAL;
3915 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003916 }
3917 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003918 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3919 "Use 'http-request allow' instead.\n", file, linenum, args[0]);
3920 err_code |= ERR_ALERT | ERR_FATAL;
3921 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003922 }
3923 else if (!strcmp(args[0], "reqtarpit")) { /* tarpit a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003924 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3925 "Use 'http-request tarpit' instead.\n", file, linenum, args[0]);
3926 err_code |= ERR_ALERT | ERR_FATAL;
3927 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003928 }
3929 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003930 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3931 "Use 'http-request replace-header' instead.\n", file, linenum, args[0]);
3932 err_code |= ERR_ALERT | ERR_FATAL;
3933 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003934 }
3935 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003936 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3937 "Use 'http-request del-header' instead.\n", file, linenum, args[0]);
3938 err_code |= ERR_ALERT | ERR_FATAL;
3939 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003940 }
3941 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003942 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3943 "Use 'http-request deny' instead.\n", file, linenum, args[0]);
3944 err_code |= ERR_ALERT | ERR_FATAL;
3945 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003946 }
3947 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003948 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1.\n", file, linenum, args[0]);
3949 err_code |= ERR_ALERT | ERR_FATAL;
3950 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003951 }
3952 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003953 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3954 "Use 'http-request allow' instead.\n", file, linenum, args[0]);
3955 err_code |= ERR_ALERT | ERR_FATAL;
3956 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003957 }
3958 else if (!strcmp(args[0], "reqitarpit")) { /* tarpit a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003959 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3960 "Use 'http-request tarpit' instead.\n", file, linenum, args[0]);
3961 err_code |= ERR_ALERT | ERR_FATAL;
3962 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003963 }
3964 else if (!strcmp(args[0], "reqadd")) { /* add request header */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003965 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3966 "Use 'http-request add-header' instead.\n", file, linenum, args[0]);
3967 err_code |= ERR_ALERT | ERR_FATAL;
3968 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003969 }
3970 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003971 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3972 "Use 'http-response replace-header' instead.\n", file, linenum, args[0]);
3973 err_code |= ERR_ALERT | ERR_FATAL;
3974 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003975 }
3976 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003977 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3978 "Use 'http-response del-header' .\n", file, linenum, args[0]);
3979 err_code |= ERR_ALERT | ERR_FATAL;
3980 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003981 }
3982 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003983 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3984 "Use 'http-response deny' instead.\n", file, linenum, args[0]);
3985 err_code |= ERR_ALERT | ERR_FATAL;
3986 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003987 }
3988 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
Balvinder Singh Rawatdef595e2020-03-14 12:11:50 +05303989 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003990 "Use 'http-response replace-header' instead.\n", file, linenum, args[0]);
3991 err_code |= ERR_ALERT | ERR_FATAL;
3992 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003993 }
3994 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003995 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3996 "Use 'http-response del-header' instead.\n", file, linenum, args[0]);
3997 err_code |= ERR_ALERT | ERR_FATAL;
3998 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003999 }
4000 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02004001 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
4002 "Use 'http-response deny' instead.\n", file, linenum, args[0]);
4003 err_code |= ERR_ALERT | ERR_FATAL;
4004 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004005 }
4006 else if (!strcmp(args[0], "rspadd")) { /* add response header */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02004007 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
4008 "Use 'http-response add-header' instead.\n", file, linenum, args[0]);
4009 err_code |= ERR_ALERT | ERR_FATAL;
4010 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004011 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004012 else {
4013 struct cfg_kw_list *kwl;
4014 int index;
4015
4016 list_for_each_entry(kwl, &cfg_keywords.list, list) {
4017 for (index = 0; kwl->kw[index].kw != NULL; index++) {
4018 if (kwl->kw[index].section != CFG_LISTEN)
4019 continue;
4020 if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
4021 /* prepare error message just in case */
4022 rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, file, linenum, &errmsg);
4023 if (rc < 0) {
4024 ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4025 err_code |= ERR_ALERT | ERR_FATAL;
4026 goto out;
4027 }
4028 else if (rc > 0) {
4029 ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4030 err_code |= ERR_WARN;
4031 goto out;
4032 }
4033 goto out;
4034 }
4035 }
4036 }
4037
4038 ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
4039 err_code |= ERR_ALERT | ERR_FATAL;
4040 goto out;
4041 }
4042 out:
4043 free(errmsg);
4044 return err_code;
4045}