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