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