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