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