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