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