blob: 1f74ddbe4ea6b6174ff595c60ff7554c652a16d1 [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]);
3145 tcpcheck->expect_regex = NULL;
3146
3147 /* comment for this tcpcheck line */
3148 if (strcmp(args[3], "comment") == 0) {
3149 if (!*args[4]) {
3150 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3151 file, linenum, args[3]);
3152 err_code |= ERR_ALERT | ERR_FATAL;
3153 goto out;
3154 }
3155 tcpcheck->comment = strdup(args[4]);
3156 }
3157
3158 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3159 }
3160 }
3161 else if (strcmp(args[1], "send-binary") == 0) {
3162 if (! *(args[2]) ) {
3163 /* SEND binary string expected */
3164 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument.\n",
3165 file, linenum, args[0], args[1], args[2]);
3166 err_code |= ERR_ALERT | ERR_FATAL;
3167 goto out;
3168 } else {
3169 struct tcpcheck_rule *tcpcheck;
3170 char *err = NULL;
3171
3172 tcpcheck = calloc(1, sizeof(*tcpcheck));
3173
3174 tcpcheck->action = TCPCHK_ACT_SEND;
3175 if (parse_binary(args[2], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3176 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3177 file, linenum, args[0], args[1], args[2], err);
3178 err_code |= ERR_ALERT | ERR_FATAL;
3179 goto out;
3180 }
3181 tcpcheck->expect_regex = NULL;
3182
3183 /* comment for this tcpcheck line */
3184 if (strcmp(args[3], "comment") == 0) {
3185 if (!*args[4]) {
3186 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3187 file, linenum, args[3]);
3188 err_code |= ERR_ALERT | ERR_FATAL;
3189 goto out;
3190 }
3191 tcpcheck->comment = strdup(args[4]);
3192 }
3193
3194 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3195 }
3196 }
3197 else if (strcmp(args[1], "expect") == 0) {
Gaetan Rivet4038b942020-02-26 16:19:40 +01003198 struct tcpcheck_rule *tcpcheck, *prev_check;
Gaetan Rivet1afd8262020-02-07 15:37:17 +01003199 long min_recv = -1;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003200 const char *ptr_arg;
3201 int cur_arg;
3202 int inverse = 0;
3203
3204 if (curproxy->options2 & PR_O2_EXP_TYPE) {
3205 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
3206 err_code |= ERR_ALERT | ERR_FATAL;
3207 goto out;
3208 }
3209
3210 cur_arg = 2;
Gaetan Rivet1afd8262020-02-07 15:37:17 +01003211
3212 /* Parse potential the minimum amount of data
3213 * required before proceeding with the match.
3214 */
3215 if (strcmp(args[cur_arg], "min-recv") == 0) {
3216 if (!*(args[cur_arg + 1])) {
3217 ha_alert("parsing [%s:%d] : '%s %s %s' expects an integer as an argument.\n",
3218 file, linenum, args[0], args[1], args[2]);
3219 err_code |= ERR_ALERT | ERR_FATAL;
3220 goto out;
3221 }
3222
3223 /* Use an signed integer here because of chksize */
3224 min_recv = atol(args[cur_arg + 1]);
3225 if (min_recv < -1 || min_recv > INT_MAX) {
3226 ha_alert("parsing [%s:%d] : '%s %s %s' expects -1 or an integer from 0 to INT_MAX.\n",
3227 file, linenum, args[0], args[1], args[2]);
3228 err_code |= ERR_ALERT | ERR_FATAL;
3229 goto out;
3230 }
3231
3232 cur_arg += 2;
3233 }
3234
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003235 /* consider exclamation marks, sole or at the beginning of a word */
3236 while (*(ptr_arg = args[cur_arg])) {
3237 while (*ptr_arg == '!') {
3238 inverse = !inverse;
3239 ptr_arg++;
3240 }
3241 if (*ptr_arg)
3242 break;
3243 cur_arg++;
3244 }
Gaetan Rivet8b00b362020-02-07 15:37:17 +01003245
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003246 /* now ptr_arg points to the beginning of a word past any possible
3247 * exclamation mark, and cur_arg is the argument which holds this word.
3248 */
Gaetan Rivet8b00b362020-02-07 15:37:17 +01003249
3250 tcpcheck = calloc(1, sizeof(*tcpcheck));
3251 tcpcheck->action = TCPCHK_ACT_EXPECT;
3252 tcpcheck->inverse = inverse;
Gaetan Rivet1afd8262020-02-07 15:37:17 +01003253 tcpcheck->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
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003265 if (parse_binary(args[cur_arg + 1], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3266 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3267 file, linenum, args[0], args[1], args[2], err);
3268 err_code |= ERR_ALERT | ERR_FATAL;
3269 goto out;
3270 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003271 }
3272 else if (strcmp(ptr_arg, "string") == 0) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003273 if (!*(args[cur_arg + 1])) {
3274 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3275 file, linenum, args[0], args[1], ptr_arg);
3276 err_code |= ERR_ALERT | ERR_FATAL;
3277 goto out;
3278 }
3279
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003280 tcpcheck->string_len = strlen(args[cur_arg + 1]);
3281 tcpcheck->string = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003282 }
3283 else if (strcmp(ptr_arg, "rstring") == 0) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003284 if (!*(args[cur_arg + 1])) {
3285 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3286 file, linenum, args[0], args[1], ptr_arg);
3287 err_code |= ERR_ALERT | ERR_FATAL;
3288 goto out;
3289 }
3290
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003291 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02003292 if (!(tcpcheck->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
3293 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003294 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3295 free(error);
3296 err_code |= ERR_ALERT | ERR_FATAL;
3297 goto out;
3298 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003299 }
3300 else {
3301 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'binary', 'string', 'rstring', found '%s'.\n",
3302 file, linenum, args[0], args[1], ptr_arg);
3303 err_code |= ERR_ALERT | ERR_FATAL;
3304 goto out;
3305 }
Gaetan Rivet4038b942020-02-26 16:19:40 +01003306
Gaetan Rivet8b00b362020-02-07 15:37:17 +01003307 /* tcpcheck comment */
3308 cur_arg += 2;
3309 if (strcmp(args[cur_arg], "comment") == 0) {
3310 if (!*args[cur_arg + 1]) {
3311 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3312 file, linenum, args[cur_arg + 1]);
3313 err_code |= ERR_ALERT | ERR_FATAL;
3314 goto out;
3315 }
3316 tcpcheck->comment = strdup(args[cur_arg + 1]);
3317 }
3318
Gaetan Rivet4038b942020-02-26 16:19:40 +01003319 /* All tcp-check expect points back to the first inverse expect rule
3320 * in a chain of one or more expect rule, potentially itself.
3321 */
3322 tcpcheck->expect_head = tcpcheck;
3323 list_for_each_entry_rev(prev_check, &curproxy->tcpcheck_rules, list) {
3324 if (prev_check->action == TCPCHK_ACT_EXPECT) {
3325 if (prev_check->inverse)
3326 tcpcheck->expect_head = prev_check;
3327 continue;
3328 }
3329 if (prev_check->action != TCPCHK_ACT_COMMENT)
3330 break;
3331 }
3332 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003333 }
3334 else {
3335 ha_alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
3336 err_code |= ERR_ALERT | ERR_FATAL;
3337 goto out;
3338 }
3339 }
3340 else if (!strcmp(args[0], "monitor")) {
3341 if (curproxy == &defproxy) {
3342 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3343 err_code |= ERR_ALERT | ERR_FATAL;
3344 goto out;
3345 }
3346
3347 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3348 err_code |= ERR_WARN;
3349
3350 if (strcmp(args[1], "fail") == 0) {
3351 /* add a condition to fail monitor requests */
3352 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
3353 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
3354 file, linenum, args[0], args[1]);
3355 err_code |= ERR_ALERT | ERR_FATAL;
3356 goto out;
3357 }
3358
3359 err_code |= warnif_misplaced_monitor(curproxy, file, linenum, "monitor fail");
3360 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
3361 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
3362 file, linenum, args[0], args[1], errmsg);
3363 err_code |= ERR_ALERT | ERR_FATAL;
3364 goto out;
3365 }
3366 LIST_ADDQ(&curproxy->mon_fail_cond, &cond->list);
3367 }
3368 else {
3369 ha_alert("parsing [%s:%d] : '%s' only supports 'fail'.\n", file, linenum, args[0]);
3370 err_code |= ERR_ALERT | ERR_FATAL;
3371 goto out;
3372 }
3373 }
Willy Tarreaue5733232019-05-22 19:24:06 +02003374#ifdef USE_TPROXY
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003375 else if (!strcmp(args[0], "transparent")) {
3376 /* enable transparent proxy connections */
3377 curproxy->options |= PR_O_TRANSP;
3378 if (alertif_too_many_args(0, file, linenum, args, &err_code))
3379 goto out;
3380 }
3381#endif
3382 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3383 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
3384 err_code |= ERR_WARN;
3385
3386 if (*(args[1]) == 0) {
3387 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3388 err_code |= ERR_ALERT | ERR_FATAL;
3389 goto out;
3390 }
3391 curproxy->maxconn = atol(args[1]);
3392 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3393 goto out;
3394 }
3395 else if (!strcmp(args[0], "backlog")) { /* backlog */
3396 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3397 err_code |= ERR_WARN;
3398
3399 if (*(args[1]) == 0) {
3400 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3401 err_code |= ERR_ALERT | ERR_FATAL;
3402 goto out;
3403 }
3404 curproxy->backlog = atol(args[1]);
3405 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3406 goto out;
3407 }
3408 else if (!strcmp(args[0], "fullconn")) { /* fullconn */
3409 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
3410 err_code |= ERR_WARN;
3411
3412 if (*(args[1]) == 0) {
3413 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3414 err_code |= ERR_ALERT | ERR_FATAL;
3415 goto out;
3416 }
3417 curproxy->fullconn = atol(args[1]);
3418 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3419 goto out;
3420 }
3421 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3422 if (*(args[1]) == 0) {
3423 ha_alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
3424 err_code |= ERR_ALERT | ERR_FATAL;
3425 goto out;
3426 }
3427 err = parse_time_err(args[1], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +02003428 if (err == PARSE_TIME_OVER) {
3429 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to grace time, maximum value is 2147483647 ms (~24.8 days).\n",
3430 file, linenum, args[1]);
3431 err_code |= ERR_ALERT | ERR_FATAL;
3432 goto out;
3433 }
3434 else if (err == PARSE_TIME_UNDER) {
3435 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to grace time, minimum non-null value is 1 ms.\n",
3436 file, linenum, args[1]);
3437 err_code |= ERR_ALERT | ERR_FATAL;
3438 goto out;
3439 }
3440 else if (err) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003441 ha_alert("parsing [%s:%d] : unexpected character '%c' in grace time.\n",
3442 file, linenum, *err);
3443 err_code |= ERR_ALERT | ERR_FATAL;
3444 goto out;
3445 }
3446 curproxy->grace = val;
3447 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3448 goto out;
3449 }
3450 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3451 struct sockaddr_storage *sk;
3452 int port1, port2;
3453 struct protocol *proto;
3454
3455 if (curproxy == &defproxy) {
3456 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3457 err_code |= ERR_ALERT | ERR_FATAL;
3458 goto out;
3459 }
3460 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3461 err_code |= ERR_WARN;
3462
3463 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3464 if (!sk) {
3465 ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
3466 err_code |= ERR_ALERT | ERR_FATAL;
3467 goto out;
3468 }
3469
3470 proto = protocol_by_family(sk->ss_family);
3471 if (!proto || !proto->connect) {
3472 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3473 file, linenum, args[0], args[1]);
3474 err_code |= ERR_ALERT | ERR_FATAL;
3475 goto out;
3476 }
3477
3478 if (port1 != port2) {
3479 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'.\n",
3480 file, linenum, args[0], args[1]);
3481 err_code |= ERR_ALERT | ERR_FATAL;
3482 goto out;
3483 }
3484
3485 if (!port1) {
3486 ha_alert("parsing [%s:%d] : '%s' : missing port number in '%s', <addr:port> expected.\n",
3487 file, linenum, args[0], args[1]);
3488 err_code |= ERR_ALERT | ERR_FATAL;
3489 goto out;
3490 }
3491
3492 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3493 goto out;
3494
3495 curproxy->dispatch_addr = *sk;
3496 curproxy->options |= PR_O_DISPATCH;
3497 }
3498 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
3499 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3500 err_code |= ERR_WARN;
3501
3502 if (backend_parse_balance((const char **)args + 1, &errmsg, curproxy) < 0) {
3503 ha_alert("parsing [%s:%d] : %s %s\n", file, linenum, args[0], errmsg);
3504 err_code |= ERR_ALERT | ERR_FATAL;
3505 goto out;
3506 }
3507 }
3508 else if (!strcmp(args[0], "hash-type")) { /* set hashing method */
3509 /**
3510 * The syntax for hash-type config element is
3511 * hash-type {map-based|consistent} [[<algo>] avalanche]
3512 *
3513 * The default hash function is sdbm for map-based and sdbm+avalanche for consistent.
3514 */
3515 curproxy->lbprm.algo &= ~(BE_LB_HASH_TYPE | BE_LB_HASH_FUNC | BE_LB_HASH_MOD);
3516
3517 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3518 err_code |= ERR_WARN;
3519
3520 if (strcmp(args[1], "consistent") == 0) { /* use consistent hashing */
3521 curproxy->lbprm.algo |= BE_LB_HASH_CONS;
3522 }
3523 else if (strcmp(args[1], "map-based") == 0) { /* use map-based hashing */
3524 curproxy->lbprm.algo |= BE_LB_HASH_MAP;
3525 }
3526 else if (strcmp(args[1], "avalanche") == 0) {
3527 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]);
3528 err_code |= ERR_ALERT | ERR_FATAL;
3529 goto out;
3530 }
3531 else {
3532 ha_alert("parsing [%s:%d] : '%s' only supports 'consistent' and 'map-based'.\n", file, linenum, args[0]);
3533 err_code |= ERR_ALERT | ERR_FATAL;
3534 goto out;
3535 }
3536
3537 /* set the hash function to use */
3538 if (!*args[2]) {
3539 /* the default algo is sdbm */
3540 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3541
3542 /* if consistent with no argument, then avalanche modifier is also applied */
3543 if ((curproxy->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS)
3544 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3545 } else {
3546 /* set the hash function */
3547 if (!strcmp(args[2], "sdbm")) {
3548 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3549 }
3550 else if (!strcmp(args[2], "djb2")) {
3551 curproxy->lbprm.algo |= BE_LB_HFCN_DJB2;
3552 }
3553 else if (!strcmp(args[2], "wt6")) {
3554 curproxy->lbprm.algo |= BE_LB_HFCN_WT6;
3555 }
3556 else if (!strcmp(args[2], "crc32")) {
3557 curproxy->lbprm.algo |= BE_LB_HFCN_CRC32;
3558 }
3559 else {
3560 ha_alert("parsing [%s:%d] : '%s' only supports 'sdbm', 'djb2', 'crc32', or 'wt6' hash functions.\n", file, linenum, args[0]);
3561 err_code |= ERR_ALERT | ERR_FATAL;
3562 goto out;
3563 }
3564
3565 /* set the hash modifier */
3566 if (!strcmp(args[3], "avalanche")) {
3567 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3568 }
3569 else if (*args[3]) {
3570 ha_alert("parsing [%s:%d] : '%s' only supports 'avalanche' as a modifier for hash functions.\n", file, linenum, args[0]);
3571 err_code |= ERR_ALERT | ERR_FATAL;
3572 goto out;
3573 }
3574 }
3575 }
3576 else if (strcmp(args[0], "hash-balance-factor") == 0) {
3577 if (*(args[1]) == 0) {
3578 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3579 err_code |= ERR_ALERT | ERR_FATAL;
3580 goto out;
3581 }
Willy Tarreau76e84f52019-01-14 16:50:58 +01003582 curproxy->lbprm.hash_balance_factor = atol(args[1]);
3583 if (curproxy->lbprm.hash_balance_factor != 0 && curproxy->lbprm.hash_balance_factor <= 100) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003584 ha_alert("parsing [%s:%d] : '%s' must be 0 or greater than 100.\n", file, linenum, args[0]);
3585 err_code |= ERR_ALERT | ERR_FATAL;
3586 goto out;
3587 }
3588 }
3589 else if (strcmp(args[0], "unique-id-format") == 0) {
3590 if (!*(args[1])) {
3591 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3592 err_code |= ERR_ALERT | ERR_FATAL;
3593 goto out;
3594 }
3595 if (*(args[2])) {
3596 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3597 err_code |= ERR_ALERT | ERR_FATAL;
3598 goto out;
3599 }
3600 free(curproxy->conf.uniqueid_format_string);
3601 curproxy->conf.uniqueid_format_string = strdup(args[1]);
3602
3603 free(curproxy->conf.uif_file);
3604 curproxy->conf.uif_file = strdup(curproxy->conf.args.file);
3605 curproxy->conf.uif_line = curproxy->conf.args.line;
3606 }
3607
3608 else if (strcmp(args[0], "unique-id-header") == 0) {
Tim Duesterhus0643b0e2020-03-05 17:56:35 +01003609 char *copy;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003610 if (!*(args[1])) {
3611 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3612 err_code |= ERR_ALERT | ERR_FATAL;
3613 goto out;
3614 }
Tim Duesterhus0643b0e2020-03-05 17:56:35 +01003615 copy = strdup(args[1]);
3616 if (copy == NULL) {
3617 ha_alert("parsing [%s:%d] : failed to allocate memory for unique-id-header\n", file, linenum);
3618 err_code |= ERR_ALERT | ERR_FATAL;
3619 goto out;
3620 }
3621
3622 istfree(&curproxy->header_unique_id);
3623 curproxy->header_unique_id = ist(copy);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003624 }
3625
3626 else if (strcmp(args[0], "log-format") == 0) {
3627 if (!*(args[1])) {
3628 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3629 err_code |= ERR_ALERT | ERR_FATAL;
3630 goto out;
3631 }
3632 if (*(args[2])) {
3633 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3634 err_code |= ERR_ALERT | ERR_FATAL;
3635 goto out;
3636 }
3637 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
3638 char *oldlogformat = "log-format";
3639
3640 if (curproxy->conf.logformat_string == default_http_log_format)
3641 oldlogformat = "option httplog";
3642 else if (curproxy->conf.logformat_string == default_tcp_log_format)
3643 oldlogformat = "option tcplog";
3644 else if (curproxy->conf.logformat_string == clf_http_log_format)
3645 oldlogformat = "option httplog clf";
3646 ha_warning("parsing [%s:%d]: 'log-format' overrides previous '%s' in 'defaults' section.\n",
3647 file, linenum, oldlogformat);
3648 }
3649 if (curproxy->conf.logformat_string != default_http_log_format &&
3650 curproxy->conf.logformat_string != default_tcp_log_format &&
3651 curproxy->conf.logformat_string != clf_http_log_format)
3652 free(curproxy->conf.logformat_string);
3653 curproxy->conf.logformat_string = strdup(args[1]);
3654
3655 free(curproxy->conf.lfs_file);
3656 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
3657 curproxy->conf.lfs_line = curproxy->conf.args.line;
3658
3659 /* get a chance to improve log-format error reporting by
3660 * reporting the correct line-number when possible.
3661 */
3662 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3663 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format' directive is ignored in backends.\n",
3664 file, linenum, curproxy->id);
3665 err_code |= ERR_WARN;
3666 }
3667 }
3668 else if (!strcmp(args[0], "log-format-sd")) {
3669 if (!*(args[1])) {
3670 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3671 err_code |= ERR_ALERT | ERR_FATAL;
3672 goto out;
3673 }
3674 if (*(args[2])) {
3675 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3676 err_code |= ERR_ALERT | ERR_FATAL;
3677 goto out;
3678 }
3679
3680 if (curproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
3681 free(curproxy->conf.logformat_sd_string);
3682 curproxy->conf.logformat_sd_string = strdup(args[1]);
3683
3684 free(curproxy->conf.lfsd_file);
3685 curproxy->conf.lfsd_file = strdup(curproxy->conf.args.file);
3686 curproxy->conf.lfsd_line = curproxy->conf.args.line;
3687
3688 /* get a chance to improve log-format-sd error reporting by
3689 * reporting the correct line-number when possible.
3690 */
3691 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3692 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format-sd' directive is ignored in backends.\n",
3693 file, linenum, curproxy->id);
3694 err_code |= ERR_WARN;
3695 }
3696 }
3697 else if (!strcmp(args[0], "log-tag")) { /* tag to report to syslog */
3698 if (*(args[1]) == 0) {
3699 ha_alert("parsing [%s:%d] : '%s' expects a tag for use in syslog.\n", file, linenum, args[0]);
3700 err_code |= ERR_ALERT | ERR_FATAL;
3701 goto out;
3702 }
3703 chunk_destroy(&curproxy->log_tag);
3704 chunk_initstr(&curproxy->log_tag, strdup(args[1]));
3705 }
3706 else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
3707 if (!parse_logsrv(args, &curproxy->logsrvs, (kwm == KWM_NO), &errmsg)) {
3708 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
3709 err_code |= ERR_ALERT | ERR_FATAL;
3710 goto out;
3711 }
3712 }
3713 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
3714 int cur_arg;
3715 int port1, port2;
3716 struct sockaddr_storage *sk;
3717 struct protocol *proto;
3718
3719 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3720 err_code |= ERR_WARN;
3721
3722 if (!*args[1]) {
3723 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optionally '%s' <addr>, and '%s' <name>.\n",
3724 file, linenum, "source", "usesrc", "interface");
3725 err_code |= ERR_ALERT | ERR_FATAL;
3726 goto out;
3727 }
3728
Christopher Faulet31930372019-07-15 10:16:58 +02003729 /* we must first clear any optional default setting */
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003730 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3731 free(curproxy->conn_src.iface_name);
3732 curproxy->conn_src.iface_name = NULL;
3733 curproxy->conn_src.iface_len = 0;
3734
3735 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3736 if (!sk) {
3737 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3738 file, linenum, args[0], args[1], errmsg);
3739 err_code |= ERR_ALERT | ERR_FATAL;
3740 goto out;
3741 }
3742
3743 proto = protocol_by_family(sk->ss_family);
3744 if (!proto || !proto->connect) {
3745 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3746 file, linenum, args[0], args[1]);
3747 err_code |= ERR_ALERT | ERR_FATAL;
3748 goto out;
3749 }
3750
3751 if (port1 != port2) {
3752 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3753 file, linenum, args[0], args[1]);
3754 err_code |= ERR_ALERT | ERR_FATAL;
3755 goto out;
3756 }
3757
3758 curproxy->conn_src.source_addr = *sk;
3759 curproxy->conn_src.opts |= CO_SRC_BIND;
3760
3761 cur_arg = 2;
3762 while (*(args[cur_arg])) {
3763 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
3764#if defined(CONFIG_HAP_TRANSPARENT)
3765 if (!*args[cur_arg + 1]) {
3766 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
3767 file, linenum, "usesrc");
3768 err_code |= ERR_ALERT | ERR_FATAL;
3769 goto out;
3770 }
3771
3772 if (!strcmp(args[cur_arg + 1], "client")) {
3773 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3774 curproxy->conn_src.opts |= CO_SRC_TPROXY_CLI;
3775 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
3776 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3777 curproxy->conn_src.opts |= CO_SRC_TPROXY_CIP;
3778 } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
3779 char *name, *end;
3780
3781 name = args[cur_arg+1] + 7;
Willy Tarreau90807112020-02-25 08:16:33 +01003782 while (isspace((unsigned char)*name))
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003783 name++;
3784
3785 end = name;
Willy Tarreau90807112020-02-25 08:16:33 +01003786 while (*end && !isspace((unsigned char)*end) && *end != ',' && *end != ')')
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003787 end++;
3788
3789 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3790 curproxy->conn_src.opts |= CO_SRC_TPROXY_DYN;
3791 curproxy->conn_src.bind_hdr_name = calloc(1, end - name + 1);
3792 curproxy->conn_src.bind_hdr_len = end - name;
3793 memcpy(curproxy->conn_src.bind_hdr_name, name, end - name);
3794 curproxy->conn_src.bind_hdr_name[end-name] = '\0';
3795 curproxy->conn_src.bind_hdr_occ = -1;
3796
3797 /* now look for an occurrence number */
Willy Tarreau90807112020-02-25 08:16:33 +01003798 while (isspace((unsigned char)*end))
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003799 end++;
3800 if (*end == ',') {
3801 end++;
3802 name = end;
3803 if (*end == '-')
3804 end++;
Willy Tarreau90807112020-02-25 08:16:33 +01003805 while (isdigit((unsigned char)*end))
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003806 end++;
3807 curproxy->conn_src.bind_hdr_occ = strl2ic(name, end-name);
3808 }
3809
3810 if (curproxy->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
3811 ha_alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
3812 " occurrences values smaller than %d.\n",
3813 file, linenum, MAX_HDR_HISTORY);
3814 err_code |= ERR_ALERT | ERR_FATAL;
3815 goto out;
3816 }
3817 } else {
3818 struct sockaddr_storage *sk;
3819
3820 sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3821 if (!sk) {
3822 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3823 file, linenum, args[cur_arg], args[cur_arg+1], errmsg);
3824 err_code |= ERR_ALERT | ERR_FATAL;
3825 goto out;
3826 }
3827
3828 proto = protocol_by_family(sk->ss_family);
3829 if (!proto || !proto->connect) {
3830 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3831 file, linenum, args[cur_arg], args[cur_arg+1]);
3832 err_code |= ERR_ALERT | ERR_FATAL;
3833 goto out;
3834 }
3835
3836 if (port1 != port2) {
3837 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3838 file, linenum, args[cur_arg], args[cur_arg + 1]);
3839 err_code |= ERR_ALERT | ERR_FATAL;
3840 goto out;
3841 }
3842 curproxy->conn_src.tproxy_addr = *sk;
3843 curproxy->conn_src.opts |= CO_SRC_TPROXY_ADDR;
3844 }
3845 global.last_checks |= LSTCHK_NETADM;
3846#else /* no TPROXY support */
3847 ha_alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
3848 file, linenum, "usesrc");
3849 err_code |= ERR_ALERT | ERR_FATAL;
3850 goto out;
3851#endif
3852 cur_arg += 2;
3853 continue;
3854 }
3855
3856 if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
3857#ifdef SO_BINDTODEVICE
3858 if (!*args[cur_arg + 1]) {
3859 ha_alert("parsing [%s:%d] : '%s' : missing interface name.\n",
3860 file, linenum, args[0]);
3861 err_code |= ERR_ALERT | ERR_FATAL;
3862 goto out;
3863 }
3864 free(curproxy->conn_src.iface_name);
3865 curproxy->conn_src.iface_name = strdup(args[cur_arg + 1]);
3866 curproxy->conn_src.iface_len = strlen(curproxy->conn_src.iface_name);
3867 global.last_checks |= LSTCHK_NETADM;
3868#else
3869 ha_alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
3870 file, linenum, args[0], args[cur_arg]);
3871 err_code |= ERR_ALERT | ERR_FATAL;
3872 goto out;
3873#endif
3874 cur_arg += 2;
3875 continue;
3876 }
3877 ha_alert("parsing [%s:%d] : '%s' only supports optional keywords '%s' and '%s'.\n",
3878 file, linenum, args[0], "interface", "usesrc");
3879 err_code |= ERR_ALERT | ERR_FATAL;
3880 goto out;
3881 }
3882 }
3883 else if (!strcmp(args[0], "usesrc")) { /* address to use outside: needs "source" first */
3884 ha_alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
3885 file, linenum, "usesrc", "source");
3886 err_code |= ERR_ALERT | ERR_FATAL;
3887 goto out;
3888 }
3889 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003890 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
Willy Tarreau262c3f12019-12-17 06:52:51 +01003891 "Use 'http-request replace-path', 'http-request replace-uri' or 'http-request replace-header' instead.\n",
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003892 file, linenum, args[0]);
3893 err_code |= ERR_ALERT | ERR_FATAL;
3894 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003895 }
3896 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003897 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3898 "Use 'http-request del-header' instead.\n", file, linenum, args[0]);
3899 err_code |= ERR_ALERT | ERR_FATAL;
3900 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003901 }
3902 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003903 ha_alert("parsing [%s:%d] : The '%s' not supported anymore since HAProxy 2.1. "
3904 "Use 'http-request deny' instead.\n", file, linenum, args[0]);
3905 err_code |= ERR_ALERT | ERR_FATAL;
3906 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003907 }
3908 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003909 ha_alert("parsing [%s:%d] : The '%s' not supported anymore since HAProxy 2.1.\n", file, linenum, args[0]);
3910 err_code |= ERR_ALERT | ERR_FATAL;
3911 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003912 }
3913 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003914 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3915 "Use 'http-request allow' instead.\n", file, linenum, args[0]);
3916 err_code |= ERR_ALERT | ERR_FATAL;
3917 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003918 }
3919 else if (!strcmp(args[0], "reqtarpit")) { /* tarpit a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003920 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3921 "Use 'http-request tarpit' instead.\n", file, linenum, args[0]);
3922 err_code |= ERR_ALERT | ERR_FATAL;
3923 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003924 }
3925 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003926 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3927 "Use 'http-request replace-header' instead.\n", file, linenum, args[0]);
3928 err_code |= ERR_ALERT | ERR_FATAL;
3929 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003930 }
3931 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003932 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3933 "Use 'http-request del-header' instead.\n", file, linenum, args[0]);
3934 err_code |= ERR_ALERT | ERR_FATAL;
3935 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003936 }
3937 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003938 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3939 "Use 'http-request deny' instead.\n", file, linenum, args[0]);
3940 err_code |= ERR_ALERT | ERR_FATAL;
3941 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003942 }
3943 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003944 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1.\n", file, linenum, args[0]);
3945 err_code |= ERR_ALERT | ERR_FATAL;
3946 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003947 }
3948 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003949 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3950 "Use 'http-request allow' instead.\n", file, linenum, args[0]);
3951 err_code |= ERR_ALERT | ERR_FATAL;
3952 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003953 }
3954 else if (!strcmp(args[0], "reqitarpit")) { /* tarpit a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003955 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3956 "Use 'http-request tarpit' instead.\n", file, linenum, args[0]);
3957 err_code |= ERR_ALERT | ERR_FATAL;
3958 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003959 }
3960 else if (!strcmp(args[0], "reqadd")) { /* add request header */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003961 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3962 "Use 'http-request add-header' instead.\n", file, linenum, args[0]);
3963 err_code |= ERR_ALERT | ERR_FATAL;
3964 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003965 }
3966 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003967 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3968 "Use 'http-response replace-header' instead.\n", file, linenum, args[0]);
3969 err_code |= ERR_ALERT | ERR_FATAL;
3970 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003971 }
3972 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003973 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3974 "Use 'http-response del-header' .\n", file, linenum, args[0]);
3975 err_code |= ERR_ALERT | ERR_FATAL;
3976 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003977 }
3978 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003979 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3980 "Use 'http-response deny' instead.\n", file, linenum, args[0]);
3981 err_code |= ERR_ALERT | ERR_FATAL;
3982 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003983 }
3984 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
Balvinder Singh Rawatdef595e2020-03-14 12:11:50 +05303985 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003986 "Use 'http-response replace-header' instead.\n", file, linenum, args[0]);
3987 err_code |= ERR_ALERT | ERR_FATAL;
3988 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003989 }
3990 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003991 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3992 "Use 'http-response del-header' instead.\n", file, linenum, args[0]);
3993 err_code |= ERR_ALERT | ERR_FATAL;
3994 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003995 }
3996 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003997 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3998 "Use 'http-response deny' instead.\n", file, linenum, args[0]);
3999 err_code |= ERR_ALERT | ERR_FATAL;
4000 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004001 }
4002 else if (!strcmp(args[0], "rspadd")) { /* add response header */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02004003 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
4004 "Use 'http-response add-header' instead.\n", file, linenum, args[0]);
4005 err_code |= ERR_ALERT | ERR_FATAL;
4006 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004007 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01004008 else {
4009 struct cfg_kw_list *kwl;
4010 int index;
4011
4012 list_for_each_entry(kwl, &cfg_keywords.list, list) {
4013 for (index = 0; kwl->kw[index].kw != NULL; index++) {
4014 if (kwl->kw[index].section != CFG_LISTEN)
4015 continue;
4016 if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
4017 /* prepare error message just in case */
4018 rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, file, linenum, &errmsg);
4019 if (rc < 0) {
4020 ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4021 err_code |= ERR_ALERT | ERR_FATAL;
4022 goto out;
4023 }
4024 else if (rc > 0) {
4025 ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
4026 err_code |= ERR_WARN;
4027 goto out;
4028 }
4029 goto out;
4030 }
4031 }
4032 }
4033
4034 ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
4035 err_code |= ERR_ALERT | ERR_FATAL;
4036 goto out;
4037 }
4038 out:
4039 free(errmsg);
4040 return err_code;
4041}