blob: 70627c30a238a9b199e810ee9063586df5426243 [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 }
Christopher Faulet6d0c3df2020-01-22 09:26:35 +01001416 else if (!strcmp(args[0], "http-after-response")) {
1417 struct act_rule *rule;
1418
1419 if (curproxy == &defproxy) {
1420 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1421 err_code |= ERR_ALERT | ERR_FATAL;
1422 goto out;
1423 }
1424
1425 if (!LIST_ISEMPTY(&curproxy->http_after_res_rules) &&
1426 !LIST_PREV(&curproxy->http_after_res_rules, struct act_rule *, list)->cond &&
1427 (LIST_PREV(&curproxy->http_after_res_rules, struct act_rule *, list)->flags & ACT_FLAG_FINAL)) {
1428 ha_warning("parsing [%s:%d]: previous '%s' action is final and has no condition attached, further entries are NOOP.\n",
1429 file, linenum, args[0]);
1430 err_code |= ERR_WARN;
1431 }
1432
1433 rule = parse_http_after_res_cond((const char **)args + 1, file, linenum, curproxy);
1434
1435 if (!rule) {
1436 err_code |= ERR_ALERT | ERR_ABORT;
1437 goto out;
1438 }
1439
1440 err_code |= warnif_cond_conflicts(rule->cond,
1441 (curproxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
1442 file, linenum);
1443
1444 LIST_ADDQ(&curproxy->http_after_res_rules, &rule->list);
1445 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001446 else if (!strcmp(args[0], "http-send-name-header")) { /* send server name in request header */
1447 /* set the header name and length into the proxy structure */
1448 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1449 err_code |= ERR_WARN;
1450
1451 if (!*args[1]) {
1452 ha_alert("parsing [%s:%d] : '%s' requires a header string.\n",
1453 file, linenum, args[0]);
1454 err_code |= ERR_ALERT | ERR_FATAL;
1455 goto out;
1456 }
1457
Christopher Fauletdabcc8e2019-10-02 10:45:55 +02001458 /* set the desired header name, in lower case */
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001459 free(curproxy->server_id_hdr_name);
1460 curproxy->server_id_hdr_name = strdup(args[1]);
1461 curproxy->server_id_hdr_len = strlen(curproxy->server_id_hdr_name);
Christopher Fauletdabcc8e2019-10-02 10:45:55 +02001462 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 +01001463 }
Tim Duesterhus7b7c47f2019-05-14 20:57:57 +02001464 else if (!strcmp(args[0], "block")) {
1465 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 +01001466
Tim Duesterhus7b7c47f2019-05-14 20:57:57 +02001467 err_code |= ERR_ALERT | ERR_FATAL;
1468 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001469 }
1470 else if (!strcmp(args[0], "redirect")) {
1471 struct redirect_rule *rule;
1472
1473 if (curproxy == &defproxy) {
1474 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1475 err_code |= ERR_ALERT | ERR_FATAL;
1476 goto out;
1477 }
1478
1479 if ((rule = http_parse_redirect_rule(file, linenum, curproxy, (const char **)args + 1, &errmsg, 0, 0)) == NULL) {
1480 ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing redirect rule : %s.\n",
1481 file, linenum, proxy_type_str(curproxy), curproxy->id, errmsg);
1482 err_code |= ERR_ALERT | ERR_FATAL;
1483 goto out;
1484 }
1485
1486 LIST_ADDQ(&curproxy->redirect_rules, &rule->list);
1487 err_code |= warnif_misplaced_redirect(curproxy, file, linenum, args[0]);
1488 err_code |= warnif_cond_conflicts(rule->cond,
1489 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1490 file, linenum);
1491 }
1492 else if (!strcmp(args[0], "use_backend")) {
1493 struct switching_rule *rule;
1494
1495 if (curproxy == &defproxy) {
1496 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1497 err_code |= ERR_ALERT | ERR_FATAL;
1498 goto out;
1499 }
1500
1501 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1502 err_code |= ERR_WARN;
1503
1504 if (*(args[1]) == 0) {
1505 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
1506 err_code |= ERR_ALERT | ERR_FATAL;
1507 goto out;
1508 }
1509
1510 if (strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0) {
1511 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1512 ha_alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
1513 file, linenum, errmsg);
1514 err_code |= ERR_ALERT | ERR_FATAL;
1515 goto out;
1516 }
1517
1518 err_code |= warnif_cond_conflicts(cond, SMP_VAL_FE_SET_BCK, file, linenum);
1519 }
1520 else if (*args[2]) {
1521 ha_alert("parsing [%s:%d] : unexpected keyword '%s' after switching rule, only 'if' and 'unless' are allowed.\n",
1522 file, linenum, args[2]);
1523 err_code |= ERR_ALERT | ERR_FATAL;
1524 goto out;
1525 }
1526
1527 rule = calloc(1, sizeof(*rule));
1528 if (!rule) {
1529 ha_alert("Out of memory error.\n");
1530 goto out;
1531 }
1532 rule->cond = cond;
1533 rule->be.name = strdup(args[1]);
1534 rule->line = linenum;
1535 rule->file = strdup(file);
1536 if (!rule->file) {
1537 ha_alert("Out of memory error.\n");
1538 goto out;
1539 }
1540 LIST_INIT(&rule->list);
1541 LIST_ADDQ(&curproxy->switching_rules, &rule->list);
1542 }
1543 else if (strcmp(args[0], "use-server") == 0) {
1544 struct server_rule *rule;
1545
1546 if (curproxy == &defproxy) {
1547 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1548 err_code |= ERR_ALERT | ERR_FATAL;
1549 goto out;
1550 }
1551
1552 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1553 err_code |= ERR_WARN;
1554
1555 if (*(args[1]) == 0) {
1556 ha_alert("parsing [%s:%d] : '%s' expects a server name.\n", file, linenum, args[0]);
1557 err_code |= ERR_ALERT | ERR_FATAL;
1558 goto out;
1559 }
1560
1561 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
1562 ha_alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1563 file, linenum, args[0]);
1564 err_code |= ERR_ALERT | ERR_FATAL;
1565 goto out;
1566 }
1567
1568 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1569 ha_alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
1570 file, linenum, errmsg);
1571 err_code |= ERR_ALERT | ERR_FATAL;
1572 goto out;
1573 }
1574
1575 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, file, linenum);
1576
1577 rule = calloc(1, sizeof(*rule));
1578 rule->cond = cond;
1579 rule->srv.name = strdup(args[1]);
1580 LIST_INIT(&rule->list);
1581 LIST_ADDQ(&curproxy->server_rules, &rule->list);
1582 curproxy->be_req_ana |= AN_REQ_SRV_RULES;
1583 }
1584 else if ((!strcmp(args[0], "force-persist")) ||
1585 (!strcmp(args[0], "ignore-persist"))) {
1586 struct persist_rule *rule;
1587
1588 if (curproxy == &defproxy) {
1589 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1590 err_code |= ERR_ALERT | ERR_FATAL;
1591 goto out;
1592 }
1593
1594 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1595 err_code |= ERR_WARN;
1596
1597 if (strcmp(args[1], "if") != 0 && strcmp(args[1], "unless") != 0) {
1598 ha_alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1599 file, linenum, args[0]);
1600 err_code |= ERR_ALERT | ERR_FATAL;
1601 goto out;
1602 }
1603
1604 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 1, &errmsg)) == NULL) {
1605 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' rule : %s.\n",
1606 file, linenum, args[0], errmsg);
1607 err_code |= ERR_ALERT | ERR_FATAL;
1608 goto out;
1609 }
1610
1611 /* note: BE_REQ_CNT is the first one after FE_SET_BCK, which is
1612 * where force-persist is applied.
1613 */
1614 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_REQ_CNT, file, linenum);
1615
1616 rule = calloc(1, sizeof(*rule));
1617 rule->cond = cond;
1618 if (!strcmp(args[0], "force-persist")) {
1619 rule->type = PERSIST_TYPE_FORCE;
1620 } else {
1621 rule->type = PERSIST_TYPE_IGNORE;
1622 }
1623 LIST_INIT(&rule->list);
1624 LIST_ADDQ(&curproxy->persist_rules, &rule->list);
1625 }
1626 else if (!strcmp(args[0], "stick-table")) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001627 struct stktable *other;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001628
1629 if (curproxy == &defproxy) {
1630 ha_alert("parsing [%s:%d] : 'stick-table' is not supported in 'defaults' section.\n",
1631 file, linenum);
1632 err_code |= ERR_ALERT | ERR_FATAL;
1633 goto out;
1634 }
1635
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001636 other = stktable_find_by_name(curproxy->id);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001637 if (other) {
1638 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 +01001639 file, linenum, curproxy->id,
1640 other->proxy ? proxy_cap_str(other->proxy->cap) : "peers",
1641 other->proxy ? other->id : other->peers.p->id,
1642 other->conf.file, other->conf.line);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001643 err_code |= ERR_ALERT | ERR_FATAL;
1644 goto out;
1645 }
1646
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001647 curproxy->table = calloc(1, sizeof *curproxy->table);
1648 if (!curproxy->table) {
1649 ha_alert("parsing [%s:%d]: '%s %s' : memory allocation failed\n",
1650 file, linenum, args[0], args[1]);
1651 err_code |= ERR_ALERT | ERR_FATAL;
1652 goto out;
1653 }
1654
Frédéric Lécaillec02766a2019-03-20 15:06:55 +01001655 err_code |= parse_stick_table(file, linenum, args, curproxy->table,
1656 curproxy->id, curproxy->id, NULL);
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001657 if (err_code & ERR_FATAL)
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001658 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001659
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001660 /* Store the proxy in the stick-table. */
1661 curproxy->table->proxy = curproxy;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001662
1663 stktable_store_name(curproxy->table);
1664 curproxy->table->next = stktables_list;
1665 stktables_list = curproxy->table;
Frédéric Lécaille015e4d72019-03-19 14:55:01 +01001666
1667 /* Add this proxy to the list of proxies which refer to its stick-table. */
1668 if (curproxy->table->proxies_list != curproxy) {
1669 curproxy->next_stkt_ref = curproxy->table->proxies_list;
1670 curproxy->table->proxies_list = curproxy;
1671 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001672 }
1673 else if (!strcmp(args[0], "stick")) {
1674 struct sticking_rule *rule;
1675 struct sample_expr *expr;
1676 int myidx = 0;
1677 const char *name = NULL;
1678 int flags;
1679
1680 if (curproxy == &defproxy) {
1681 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1682 err_code |= ERR_ALERT | ERR_FATAL;
1683 goto out;
1684 }
1685
1686 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) {
1687 err_code |= ERR_WARN;
1688 goto out;
1689 }
1690
1691 myidx++;
1692 if ((strcmp(args[myidx], "store") == 0) ||
1693 (strcmp(args[myidx], "store-request") == 0)) {
1694 myidx++;
1695 flags = STK_IS_STORE;
1696 }
1697 else if (strcmp(args[myidx], "store-response") == 0) {
1698 myidx++;
1699 flags = STK_IS_STORE | STK_ON_RSP;
1700 }
1701 else if (strcmp(args[myidx], "match") == 0) {
1702 myidx++;
1703 flags = STK_IS_MATCH;
1704 }
1705 else if (strcmp(args[myidx], "on") == 0) {
1706 myidx++;
1707 flags = STK_IS_MATCH | STK_IS_STORE;
1708 }
1709 else {
1710 ha_alert("parsing [%s:%d] : '%s' expects 'on', 'match', or 'store'.\n", file, linenum, args[0]);
1711 err_code |= ERR_ALERT | ERR_FATAL;
1712 goto out;
1713 }
1714
1715 if (*(args[myidx]) == 0) {
1716 ha_alert("parsing [%s:%d] : '%s' expects a fetch method.\n", file, linenum, args[0]);
1717 err_code |= ERR_ALERT | ERR_FATAL;
1718 goto out;
1719 }
1720
1721 curproxy->conf.args.ctx = ARGC_STK;
1722 expr = sample_parse_expr(args, &myidx, file, linenum, &errmsg, &curproxy->conf.args);
1723 if (!expr) {
1724 ha_alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], errmsg);
1725 err_code |= ERR_ALERT | ERR_FATAL;
1726 goto out;
1727 }
1728
1729 if (flags & STK_ON_RSP) {
1730 if (!(expr->fetch->val & SMP_VAL_BE_STO_RUL)) {
1731 ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available for 'store-response'.\n",
1732 file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
1733 err_code |= ERR_ALERT | ERR_FATAL;
1734 free(expr);
1735 goto out;
1736 }
1737 } else {
1738 if (!(expr->fetch->val & SMP_VAL_BE_SET_SRV)) {
1739 ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available during request.\n",
1740 file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
1741 err_code |= ERR_ALERT | ERR_FATAL;
1742 free(expr);
1743 goto out;
1744 }
1745 }
1746
Christopher Faulet711ed6a2019-07-16 14:16:10 +02001747 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001748 curproxy->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
1749
1750 if (strcmp(args[myidx], "table") == 0) {
1751 myidx++;
1752 name = args[myidx++];
1753 }
1754
1755 if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) {
1756 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + myidx, &errmsg)) == NULL) {
1757 ha_alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition : %s.\n",
1758 file, linenum, args[0], errmsg);
1759 err_code |= ERR_ALERT | ERR_FATAL;
1760 free(expr);
1761 goto out;
1762 }
1763 }
1764 else if (*(args[myidx])) {
1765 ha_alert("parsing [%s:%d] : '%s': unknown keyword '%s'.\n",
1766 file, linenum, args[0], args[myidx]);
1767 err_code |= ERR_ALERT | ERR_FATAL;
1768 free(expr);
1769 goto out;
1770 }
1771 if (flags & STK_ON_RSP)
1772 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_STO_RUL, file, linenum);
1773 else
1774 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, file, linenum);
1775
1776 rule = calloc(1, sizeof(*rule));
1777 rule->cond = cond;
1778 rule->expr = expr;
1779 rule->flags = flags;
1780 rule->table.name = name ? strdup(name) : NULL;
1781 LIST_INIT(&rule->list);
1782 if (flags & STK_ON_RSP)
1783 LIST_ADDQ(&curproxy->storersp_rules, &rule->list);
1784 else
1785 LIST_ADDQ(&curproxy->sticking_rules, &rule->list);
1786 }
1787 else if (!strcmp(args[0], "stats")) {
1788 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
1789 curproxy->uri_auth = NULL; /* we must detach from the default config */
1790
1791 if (!*args[1]) {
1792 goto stats_error_parsing;
1793 } else if (!strcmp(args[1], "admin")) {
1794 struct stats_admin_rule *rule;
1795
1796 if (curproxy == &defproxy) {
1797 ha_alert("parsing [%s:%d]: '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1798 err_code |= ERR_ALERT | ERR_FATAL;
1799 goto out;
1800 }
1801
1802 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1803 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1804 err_code |= ERR_ALERT | ERR_ABORT;
1805 goto out;
1806 }
1807
1808 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
1809 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
1810 file, linenum, args[0], args[1]);
1811 err_code |= ERR_ALERT | ERR_FATAL;
1812 goto out;
1813 }
1814 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1815 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' rule : %s.\n",
1816 file, linenum, args[0], args[1], errmsg);
1817 err_code |= ERR_ALERT | ERR_FATAL;
1818 goto out;
1819 }
1820
1821 err_code |= warnif_cond_conflicts(cond,
1822 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1823 file, linenum);
1824
1825 rule = calloc(1, sizeof(*rule));
1826 rule->cond = cond;
1827 LIST_INIT(&rule->list);
1828 LIST_ADDQ(&curproxy->uri_auth->admin_rules, &rule->list);
1829 } else if (!strcmp(args[1], "uri")) {
1830 if (*(args[2]) == 0) {
1831 ha_alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
1832 err_code |= ERR_ALERT | ERR_FATAL;
1833 goto out;
1834 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
1835 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1836 err_code |= ERR_ALERT | ERR_ABORT;
1837 goto out;
1838 }
1839 } else if (!strcmp(args[1], "realm")) {
1840 if (*(args[2]) == 0) {
1841 ha_alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
1842 err_code |= ERR_ALERT | ERR_FATAL;
1843 goto out;
1844 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
1845 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1846 err_code |= ERR_ALERT | ERR_ABORT;
1847 goto out;
1848 }
1849 } else if (!strcmp(args[1], "refresh")) {
1850 unsigned interval;
1851
1852 err = parse_time_err(args[2], &interval, TIME_UNIT_S);
Willy Tarreau9faebe32019-06-07 19:00:37 +02001853 if (err == PARSE_TIME_OVER) {
1854 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to stats refresh interval, maximum value is 2147483647 s (~68 years).\n",
1855 file, linenum, args[2]);
1856 err_code |= ERR_ALERT | ERR_FATAL;
1857 goto out;
1858 }
1859 else if (err == PARSE_TIME_UNDER) {
1860 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to stats refresh interval, minimum non-null value is 1 s.\n",
1861 file, linenum, args[2]);
1862 err_code |= ERR_ALERT | ERR_FATAL;
1863 goto out;
1864 }
1865 else if (err) {
1866 ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to stats refresh interval.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001867 file, linenum, *err);
1868 err_code |= ERR_ALERT | ERR_FATAL;
1869 goto out;
1870 } else if (!stats_set_refresh(&curproxy->uri_auth, interval)) {
1871 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1872 err_code |= ERR_ALERT | ERR_ABORT;
1873 goto out;
1874 }
1875 } else if (!strcmp(args[1], "http-request")) { /* request access control: allow/deny/auth */
1876 struct act_rule *rule;
1877
1878 if (curproxy == &defproxy) {
1879 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1880 err_code |= ERR_ALERT | ERR_FATAL;
1881 goto out;
1882 }
1883
1884 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1885 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1886 err_code |= ERR_ALERT | ERR_ABORT;
1887 goto out;
1888 }
1889
1890 if (!LIST_ISEMPTY(&curproxy->uri_auth->http_req_rules) &&
1891 !LIST_PREV(&curproxy->uri_auth->http_req_rules, struct act_rule *, list)->cond) {
1892 ha_warning("parsing [%s:%d]: previous '%s' action has no condition attached, further entries are NOOP.\n",
1893 file, linenum, args[0]);
1894 err_code |= ERR_WARN;
1895 }
1896
1897 rule = parse_http_req_cond((const char **)args + 2, file, linenum, curproxy);
1898
1899 if (!rule) {
1900 err_code |= ERR_ALERT | ERR_ABORT;
1901 goto out;
1902 }
1903
1904 err_code |= warnif_cond_conflicts(rule->cond,
1905 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1906 file, linenum);
1907 LIST_ADDQ(&curproxy->uri_auth->http_req_rules, &rule->list);
1908
1909 } else if (!strcmp(args[1], "auth")) {
1910 if (*(args[2]) == 0) {
1911 ha_alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
1912 err_code |= ERR_ALERT | ERR_FATAL;
1913 goto out;
1914 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
1915 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1916 err_code |= ERR_ALERT | ERR_ABORT;
1917 goto out;
1918 }
1919 } else if (!strcmp(args[1], "scope")) {
1920 if (*(args[2]) == 0) {
1921 ha_alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
1922 err_code |= ERR_ALERT | ERR_FATAL;
1923 goto out;
1924 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
1925 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1926 err_code |= ERR_ALERT | ERR_ABORT;
1927 goto out;
1928 }
1929 } else if (!strcmp(args[1], "enable")) {
1930 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1931 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1932 err_code |= ERR_ALERT | ERR_ABORT;
1933 goto out;
1934 }
1935 } else if (!strcmp(args[1], "hide-version")) {
Willy Tarreau708c4162019-10-09 10:19:16 +02001936 if (!stats_set_flag(&curproxy->uri_auth, STAT_HIDEVER)) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001937 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1938 err_code |= ERR_ALERT | ERR_ABORT;
1939 goto out;
1940 }
1941 } else if (!strcmp(args[1], "show-legends")) {
Willy Tarreau708c4162019-10-09 10:19:16 +02001942 if (!stats_set_flag(&curproxy->uri_auth, STAT_SHLGNDS)) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001943 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1944 err_code |= ERR_ALERT | ERR_ABORT;
1945 goto out;
1946 }
1947 } else if (!strcmp(args[1], "show-node")) {
1948
1949 if (*args[2]) {
1950 int i;
1951 char c;
1952
1953 for (i=0; args[2][i]; i++) {
1954 c = args[2][i];
1955 if (!isupper((unsigned char)c) && !islower((unsigned char)c) &&
1956 !isdigit((unsigned char)c) && c != '_' && c != '-' && c != '.')
1957 break;
1958 }
1959
1960 if (!i || args[2][i]) {
1961 ha_alert("parsing [%s:%d]: '%s %s' invalid node name - should be a string"
1962 "with digits(0-9), letters(A-Z, a-z), hyphen(-) or underscode(_).\n",
1963 file, linenum, args[0], args[1]);
1964 err_code |= ERR_ALERT | ERR_FATAL;
1965 goto out;
1966 }
1967 }
1968
1969 if (!stats_set_node(&curproxy->uri_auth, args[2])) {
1970 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1971 err_code |= ERR_ALERT | ERR_ABORT;
1972 goto out;
1973 }
1974 } else if (!strcmp(args[1], "show-desc")) {
1975 char *desc = NULL;
1976
1977 if (*args[2]) {
1978 int i, len=0;
1979 char *d;
1980
1981 for (i = 2; *args[i]; i++)
1982 len += strlen(args[i]) + 1;
1983
1984 desc = d = calloc(1, len);
1985
1986 d += snprintf(d, desc + len - d, "%s", args[2]);
1987 for (i = 3; *args[i]; i++)
1988 d += snprintf(d, desc + len - d, " %s", args[i]);
1989 }
1990
1991 if (!*args[2] && !global.desc)
1992 ha_warning("parsing [%s:%d]: '%s' requires a parameter or 'desc' to be set in the global section.\n",
1993 file, linenum, args[1]);
1994 else {
1995 if (!stats_set_desc(&curproxy->uri_auth, desc)) {
1996 free(desc);
1997 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1998 err_code |= ERR_ALERT | ERR_ABORT;
1999 goto out;
2000 }
2001 free(desc);
2002 }
2003 } else {
2004stats_error_parsing:
2005 ha_alert("parsing [%s:%d]: %s '%s', expects 'admin', 'uri', 'realm', 'auth', 'scope', 'enable', 'hide-version', 'show-node', 'show-desc' or 'show-legends'.\n",
2006 file, linenum, *args[1]?"unknown stats parameter":"missing keyword in", args[*args[1]?1:0]);
2007 err_code |= ERR_ALERT | ERR_FATAL;
2008 goto out;
2009 }
2010 }
2011 else if (!strcmp(args[0], "option")) {
2012 int optnum;
2013
2014 if (*(args[1]) == '\0') {
2015 ha_alert("parsing [%s:%d]: '%s' expects an option name.\n",
2016 file, linenum, args[0]);
2017 err_code |= ERR_ALERT | ERR_FATAL;
2018 goto out;
2019 }
2020
2021 for (optnum = 0; cfg_opts[optnum].name; optnum++) {
2022 if (!strcmp(args[1], cfg_opts[optnum].name)) {
2023 if (cfg_opts[optnum].cap == PR_CAP_NONE) {
2024 ha_alert("parsing [%s:%d]: option '%s' is not supported due to build options.\n",
2025 file, linenum, cfg_opts[optnum].name);
2026 err_code |= ERR_ALERT | ERR_FATAL;
2027 goto out;
2028 }
2029 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2030 goto out;
2031
2032 if (warnifnotcap(curproxy, cfg_opts[optnum].cap, file, linenum, args[1], NULL)) {
2033 err_code |= ERR_WARN;
2034 goto out;
2035 }
2036
2037 curproxy->no_options &= ~cfg_opts[optnum].val;
2038 curproxy->options &= ~cfg_opts[optnum].val;
2039
2040 switch (kwm) {
2041 case KWM_STD:
2042 curproxy->options |= cfg_opts[optnum].val;
2043 break;
2044 case KWM_NO:
2045 curproxy->no_options |= cfg_opts[optnum].val;
2046 break;
2047 case KWM_DEF: /* already cleared */
2048 break;
2049 }
2050
2051 goto out;
2052 }
2053 }
2054
2055 for (optnum = 0; cfg_opts2[optnum].name; optnum++) {
2056 if (!strcmp(args[1], cfg_opts2[optnum].name)) {
2057 if (cfg_opts2[optnum].cap == PR_CAP_NONE) {
2058 ha_alert("parsing [%s:%d]: option '%s' is not supported due to build options.\n",
2059 file, linenum, cfg_opts2[optnum].name);
2060 err_code |= ERR_ALERT | ERR_FATAL;
2061 goto out;
2062 }
2063 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2064 goto out;
2065 if (warnifnotcap(curproxy, cfg_opts2[optnum].cap, file, linenum, args[1], NULL)) {
2066 err_code |= ERR_WARN;
2067 goto out;
2068 }
2069
Christopher Faulet31930372019-07-15 10:16:58 +02002070 /* "[no] option http-use-htx" is deprecated */
2071 if (!strcmp(cfg_opts2[optnum].name, "http-use-htx")) {
Christopher Fauletf89f0992019-07-19 11:17:38 +02002072 if (kwm ==KWM_NO) {
2073 ha_warning("parsing [%s:%d]: option '%s' is deprecated and ignored."
2074 " The HTX mode is now the only supported mode.\n",
2075 file, linenum, cfg_opts2[optnum].name);
2076 err_code |= ERR_WARN;
2077 }
Christopher Faulet31930372019-07-15 10:16:58 +02002078 goto out;
2079 }
2080
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002081 curproxy->no_options2 &= ~cfg_opts2[optnum].val;
2082 curproxy->options2 &= ~cfg_opts2[optnum].val;
2083
2084 switch (kwm) {
2085 case KWM_STD:
2086 curproxy->options2 |= cfg_opts2[optnum].val;
2087 break;
2088 case KWM_NO:
2089 curproxy->no_options2 |= cfg_opts2[optnum].val;
2090 break;
2091 case KWM_DEF: /* already cleared */
2092 break;
2093 }
2094 goto out;
2095 }
2096 }
2097
2098 /* HTTP options override each other. They can be cancelled using
2099 * "no option xxx" which only switches to default mode if the mode
2100 * was this one (useful for cancelling options set in defaults
2101 * sections).
2102 */
2103 if (strcmp(args[1], "httpclose") == 0 || strcmp(args[1], "forceclose") == 0) {
Tim Duesterhus10c6c162019-05-14 20:58:00 +02002104 if (strcmp(args[1], "forceclose") == 0) {
2105 if (!already_warned(WARN_FORCECLOSE_DEPRECATED))
2106 ha_warning("parsing [%s:%d]: keyword '%s' is deprecated in favor of 'httpclose', and will not be supported by future versions.\n",
2107 file, linenum, args[1]);
2108 err_code |= ERR_WARN;
2109 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002110 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2111 goto out;
2112 if (kwm == KWM_STD) {
2113 curproxy->options &= ~PR_O_HTTP_MODE;
2114 curproxy->options |= PR_O_HTTP_CLO;
2115 goto out;
2116 }
2117 else if (kwm == KWM_NO) {
2118 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_CLO)
2119 curproxy->options &= ~PR_O_HTTP_MODE;
2120 goto out;
2121 }
2122 }
2123 else if (strcmp(args[1], "http-server-close") == 0) {
2124 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2125 goto out;
2126 if (kwm == KWM_STD) {
2127 curproxy->options &= ~PR_O_HTTP_MODE;
2128 curproxy->options |= PR_O_HTTP_SCL;
2129 goto out;
2130 }
2131 else if (kwm == KWM_NO) {
2132 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL)
2133 curproxy->options &= ~PR_O_HTTP_MODE;
2134 goto out;
2135 }
2136 }
2137 else if (strcmp(args[1], "http-keep-alive") == 0) {
2138 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2139 goto out;
2140 if (kwm == KWM_STD) {
2141 curproxy->options &= ~PR_O_HTTP_MODE;
2142 curproxy->options |= PR_O_HTTP_KAL;
2143 goto out;
2144 }
2145 else if (kwm == KWM_NO) {
2146 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_KAL)
2147 curproxy->options &= ~PR_O_HTTP_MODE;
2148 goto out;
2149 }
2150 }
2151 else if (strcmp(args[1], "http-tunnel") == 0) {
Christopher Faulet73e8ede2019-07-16 15:04:46 +02002152 ha_warning("parsing [%s:%d]: the option '%s' is deprecated and will be removed in next version.\n",
2153 file, linenum, args[1]);
2154 err_code |= ERR_WARN;
2155 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002156 }
2157
2158 /* Redispatch can take an integer argument that control when the
2159 * resispatch occurs. All values are relative to the retries option.
2160 * This can be cancelled using "no option xxx".
2161 */
2162 if (strcmp(args[1], "redispatch") == 0) {
2163 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL)) {
2164 err_code |= ERR_WARN;
2165 goto out;
2166 }
2167
2168 curproxy->no_options &= ~PR_O_REDISP;
2169 curproxy->options &= ~PR_O_REDISP;
2170
2171 switch (kwm) {
2172 case KWM_STD:
2173 curproxy->options |= PR_O_REDISP;
2174 curproxy->redispatch_after = -1;
2175 if(*args[2]) {
2176 curproxy->redispatch_after = atol(args[2]);
2177 }
2178 break;
2179 case KWM_NO:
2180 curproxy->no_options |= PR_O_REDISP;
2181 curproxy->redispatch_after = 0;
2182 break;
2183 case KWM_DEF: /* already cleared */
2184 break;
2185 }
2186 goto out;
2187 }
2188
2189 if (kwm != KWM_STD) {
2190 ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
2191 file, linenum, args[1]);
2192 err_code |= ERR_ALERT | ERR_FATAL;
2193 goto out;
2194 }
2195
2196 if (!strcmp(args[1], "httplog")) {
2197 char *logformat;
2198 /* generate a complete HTTP log */
2199 logformat = default_http_log_format;
2200 if (*(args[2]) != '\0') {
2201 if (!strcmp(args[2], "clf")) {
2202 curproxy->options2 |= PR_O2_CLFLOG;
2203 logformat = clf_http_log_format;
2204 } else {
2205 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'clf'.\n", file, linenum, args[1]);
2206 err_code |= ERR_ALERT | ERR_FATAL;
2207 goto out;
2208 }
2209 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
2210 goto out;
2211 }
2212 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2213 char *oldlogformat = "log-format";
2214 char *clflogformat = "";
2215
2216 if (curproxy->conf.logformat_string == default_http_log_format)
2217 oldlogformat = "option httplog";
2218 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2219 oldlogformat = "option tcplog";
2220 else if (curproxy->conf.logformat_string == clf_http_log_format)
2221 oldlogformat = "option httplog clf";
2222 if (logformat == clf_http_log_format)
2223 clflogformat = " clf";
2224 ha_warning("parsing [%s:%d]: 'option httplog%s' overrides previous '%s' in 'defaults' section.\n",
2225 file, linenum, clflogformat, oldlogformat);
2226 }
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 = logformat;
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 (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2238 ha_warning("parsing [%s:%d] : backend '%s' : 'option httplog' directive is ignored in backends.\n",
2239 file, linenum, curproxy->id);
2240 err_code |= ERR_WARN;
2241 }
2242 }
2243 else if (!strcmp(args[1], "tcplog")) {
2244 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2245 char *oldlogformat = "log-format";
2246
2247 if (curproxy->conf.logformat_string == default_http_log_format)
2248 oldlogformat = "option httplog";
2249 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2250 oldlogformat = "option tcplog";
2251 else if (curproxy->conf.logformat_string == clf_http_log_format)
2252 oldlogformat = "option httplog clf";
2253 ha_warning("parsing [%s:%d]: 'option tcplog' overrides previous '%s' in 'defaults' section.\n",
2254 file, linenum, oldlogformat);
2255 }
2256 /* generate a detailed TCP log */
2257 if (curproxy->conf.logformat_string != default_http_log_format &&
2258 curproxy->conf.logformat_string != default_tcp_log_format &&
2259 curproxy->conf.logformat_string != clf_http_log_format)
2260 free(curproxy->conf.logformat_string);
2261 curproxy->conf.logformat_string = default_tcp_log_format;
2262
2263 free(curproxy->conf.lfs_file);
2264 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2265 curproxy->conf.lfs_line = curproxy->conf.args.line;
2266
2267 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2268 goto out;
2269
2270 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2271 ha_warning("parsing [%s:%d] : backend '%s' : 'option tcplog' directive is ignored in backends.\n",
2272 file, linenum, curproxy->id);
2273 err_code |= ERR_WARN;
2274 }
2275 }
2276 else if (!strcmp(args[1], "tcpka")) {
2277 /* enable TCP keep-alives on client and server streams */
2278 if (warnifnotcap(curproxy, PR_CAP_BE | PR_CAP_FE, file, linenum, args[1], NULL))
2279 err_code |= ERR_WARN;
2280
2281 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2282 goto out;
2283
2284 if (curproxy->cap & PR_CAP_FE)
2285 curproxy->options |= PR_O_TCP_CLI_KA;
2286 if (curproxy->cap & PR_CAP_BE)
2287 curproxy->options |= PR_O_TCP_SRV_KA;
2288 }
2289 else if (!strcmp(args[1], "httpchk")) {
2290 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2291 err_code |= ERR_WARN;
2292
2293 /* use HTTP request to check servers' health */
2294 free(curproxy->check_req);
2295 curproxy->check_req = NULL;
2296 curproxy->options2 &= ~PR_O2_CHK_ANY;
2297 curproxy->options2 |= PR_O2_HTTP_CHK;
2298 if (!*args[2]) { /* no argument */
2299 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
2300 curproxy->check_len = strlen(DEF_CHECK_REQ);
2301 } else if (!*args[3]) { /* one argument : URI */
2302 int reqlen = strlen(args[2]) + strlen("OPTIONS HTTP/1.0\r\n") + 1;
2303 curproxy->check_req = malloc(reqlen);
2304 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2305 "OPTIONS %s HTTP/1.0\r\n", args[2]); /* URI to use */
2306 } else { /* more arguments : METHOD URI [HTTP_VER] */
2307 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n");
2308 if (*args[4])
2309 reqlen += strlen(args[4]);
2310 else
2311 reqlen += strlen("HTTP/1.0");
2312
2313 curproxy->check_req = malloc(reqlen);
2314 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2315 "%s %s %s\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
2316 }
2317 if (alertif_too_many_args_idx(3, 1, file, linenum, args, &err_code))
2318 goto out;
2319 }
2320 else if (!strcmp(args[1], "ssl-hello-chk")) {
2321 /* use SSLv3 CLIENT HELLO to check servers' health */
2322 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2323 err_code |= ERR_WARN;
2324
2325 free(curproxy->check_req);
2326 curproxy->check_req = NULL;
2327 curproxy->options2 &= ~PR_O2_CHK_ANY;
2328 curproxy->options2 |= PR_O2_SSL3_CHK;
2329
2330 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2331 goto out;
2332 }
2333 else if (!strcmp(args[1], "smtpchk")) {
2334 /* use SMTP request to check servers' health */
2335 free(curproxy->check_req);
2336 curproxy->check_req = NULL;
2337 curproxy->options2 &= ~PR_O2_CHK_ANY;
2338 curproxy->options2 |= PR_O2_SMTP_CHK;
2339
2340 if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */
2341 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2342 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2343 } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */
2344 if (!strcmp(args[2], "EHLO") || !strcmp(args[2], "HELO")) {
2345 int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" \r\n") + 1;
2346 curproxy->check_req = malloc(reqlen);
2347 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2348 "%s %s\r\n", args[2], args[3]); /* HELO hostname */
2349 } else {
2350 /* this just hits the default for now, but you could potentially expand it to allow for other stuff
2351 though, it's unlikely you'd want to send anything other than an EHLO or HELO */
2352 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2353 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2354 }
2355 }
2356 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2357 goto out;
2358 }
2359 else if (!strcmp(args[1], "pgsql-check")) {
2360 /* use PostgreSQL request to check servers' health */
2361 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2362 err_code |= ERR_WARN;
2363
2364 free(curproxy->check_req);
2365 curproxy->check_req = NULL;
2366 curproxy->options2 &= ~PR_O2_CHK_ANY;
2367 curproxy->options2 |= PR_O2_PGSQL_CHK;
2368
2369 if (*(args[2])) {
2370 int cur_arg = 2;
2371
2372 while (*(args[cur_arg])) {
2373 if (strcmp(args[cur_arg], "user") == 0) {
2374 char * packet;
2375 uint32_t packet_len;
2376 uint32_t pv;
2377
2378 /* suboption header - needs additional argument for it */
2379 if (*(args[cur_arg+1]) == 0) {
2380 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2381 file, linenum, args[0], args[1], args[cur_arg]);
2382 err_code |= ERR_ALERT | ERR_FATAL;
2383 goto out;
2384 }
2385
2386 /* uint32_t + uint32_t + strlen("user")+1 + strlen(username)+1 + 1 */
2387 packet_len = 4 + 4 + 5 + strlen(args[cur_arg + 1])+1 +1;
2388 pv = htonl(0x30000); /* protocol version 3.0 */
2389
2390 packet = calloc(1, packet_len);
2391
2392 memcpy(packet + 4, &pv, 4);
2393
2394 /* copy "user" */
2395 memcpy(packet + 8, "user", 4);
2396
2397 /* copy username */
2398 memcpy(packet + 13, args[cur_arg+1], strlen(args[cur_arg+1]));
2399
2400 free(curproxy->check_req);
2401 curproxy->check_req = packet;
2402 curproxy->check_len = packet_len;
2403
2404 packet_len = htonl(packet_len);
2405 memcpy(packet, &packet_len, 4);
2406 cur_arg += 2;
2407 } else {
2408 /* unknown suboption - catchall */
2409 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2410 file, linenum, args[0], args[1]);
2411 err_code |= ERR_ALERT | ERR_FATAL;
2412 goto out;
2413 }
2414 } /* end while loop */
2415 }
2416 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2417 goto out;
2418 }
2419
2420 else if (!strcmp(args[1], "redis-check")) {
2421 /* use REDIS PING request to check servers' health */
2422 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2423 err_code |= ERR_WARN;
2424
2425 free(curproxy->check_req);
2426 curproxy->check_req = NULL;
2427 curproxy->options2 &= ~PR_O2_CHK_ANY;
2428 curproxy->options2 |= PR_O2_REDIS_CHK;
2429
2430 curproxy->check_req = malloc(sizeof(DEF_REDIS_CHECK_REQ) - 1);
2431 memcpy(curproxy->check_req, DEF_REDIS_CHECK_REQ, sizeof(DEF_REDIS_CHECK_REQ) - 1);
2432 curproxy->check_len = sizeof(DEF_REDIS_CHECK_REQ) - 1;
2433
2434 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2435 goto out;
2436 }
2437
2438 else if (!strcmp(args[1], "mysql-check")) {
2439 /* use MYSQL request to check servers' health */
2440 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2441 err_code |= ERR_WARN;
2442
2443 free(curproxy->check_req);
2444 curproxy->check_req = NULL;
2445 curproxy->options2 &= ~PR_O2_CHK_ANY;
2446 curproxy->options2 |= PR_O2_MYSQL_CHK;
2447
2448 /* This is an example of a MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte.
2449 * const char mysql40_client_auth_pkt[] = {
2450 * "\x0e\x00\x00" // packet length
2451 * "\x01" // packet number
2452 * "\x00\x00" // client capabilities
2453 * "\x00\x00\x01" // max packet
2454 * "haproxy\x00" // username (null terminated string)
2455 * "\x00" // filler (always 0x00)
2456 * "\x01\x00\x00" // packet length
2457 * "\x00" // packet number
2458 * "\x01" // COM_QUIT command
2459 * };
2460 */
2461
2462 /* This is an example of a MySQL >=4.1 client Authentication packet provided by Nenad Merdanovic.
2463 * const char mysql41_client_auth_pkt[] = {
2464 * "\x0e\x00\x00\" // packet length
2465 * "\x01" // packet number
2466 * "\x00\x00\x00\x00" // client capabilities
2467 * "\x00\x00\x00\x01" // max packet
2468 * "\x21" // character set (UTF-8)
2469 * char[23] // All zeroes
2470 * "haproxy\x00" // username (null terminated string)
2471 * "\x00" // filler (always 0x00)
2472 * "\x01\x00\x00" // packet length
2473 * "\x00" // packet number
2474 * "\x01" // COM_QUIT command
2475 * };
2476 */
2477
2478
2479 if (*(args[2])) {
2480 int cur_arg = 2;
2481
2482 while (*(args[cur_arg])) {
2483 if (strcmp(args[cur_arg], "user") == 0) {
2484 char *mysqluser;
2485 int packetlen, reqlen, userlen;
2486
2487 /* suboption header - needs additional argument for it */
2488 if (*(args[cur_arg+1]) == 0) {
2489 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2490 file, linenum, args[0], args[1], args[cur_arg]);
2491 err_code |= ERR_ALERT | ERR_FATAL;
2492 goto out;
2493 }
2494 mysqluser = args[cur_arg + 1];
2495 userlen = strlen(mysqluser);
2496
2497 if (*(args[cur_arg+2])) {
2498 if (!strcmp(args[cur_arg+2], "post-41")) {
2499 packetlen = userlen + 7 + 27;
2500 reqlen = packetlen + 9;
2501
2502 free(curproxy->check_req);
2503 curproxy->check_req = calloc(1, reqlen);
2504 curproxy->check_len = reqlen;
2505
2506 snprintf(curproxy->check_req, 4, "%c%c%c",
2507 ((unsigned char) packetlen & 0xff),
2508 ((unsigned char) (packetlen >> 8) & 0xff),
2509 ((unsigned char) (packetlen >> 16) & 0xff));
2510
2511 curproxy->check_req[3] = 1;
2512 curproxy->check_req[5] = 0x82; // 130
2513 curproxy->check_req[11] = 1;
2514 curproxy->check_req[12] = 33;
2515 memcpy(&curproxy->check_req[36], mysqluser, userlen);
2516 curproxy->check_req[36 + userlen + 1 + 1] = 1;
2517 curproxy->check_req[36 + userlen + 1 + 1 + 4] = 1;
2518 cur_arg += 3;
2519 } else {
2520 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'post-41'.\n", file, linenum, args[cur_arg+2]);
2521 err_code |= ERR_ALERT | ERR_FATAL;
2522 goto out;
2523 }
2524 } else {
2525 packetlen = userlen + 7;
2526 reqlen = packetlen + 9;
2527
2528 free(curproxy->check_req);
2529 curproxy->check_req = calloc(1, reqlen);
2530 curproxy->check_len = reqlen;
2531
2532 snprintf(curproxy->check_req, 4, "%c%c%c",
2533 ((unsigned char) packetlen & 0xff),
2534 ((unsigned char) (packetlen >> 8) & 0xff),
2535 ((unsigned char) (packetlen >> 16) & 0xff));
2536
2537 curproxy->check_req[3] = 1;
2538 curproxy->check_req[5] = 0x80;
2539 curproxy->check_req[8] = 1;
2540 memcpy(&curproxy->check_req[9], mysqluser, userlen);
2541 curproxy->check_req[9 + userlen + 1 + 1] = 1;
2542 curproxy->check_req[9 + userlen + 1 + 1 + 4] = 1;
2543 cur_arg += 2;
2544 }
2545 } else {
2546 /* unknown suboption - catchall */
2547 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2548 file, linenum, args[0], args[1]);
2549 err_code |= ERR_ALERT | ERR_FATAL;
2550 goto out;
2551 }
2552 } /* end while loop */
2553 }
2554 }
2555 else if (!strcmp(args[1], "ldap-check")) {
2556 /* use LDAP request to check servers' health */
2557 free(curproxy->check_req);
2558 curproxy->check_req = NULL;
2559 curproxy->options2 &= ~PR_O2_CHK_ANY;
2560 curproxy->options2 |= PR_O2_LDAP_CHK;
2561
2562 curproxy->check_req = malloc(sizeof(DEF_LDAP_CHECK_REQ) - 1);
2563 memcpy(curproxy->check_req, DEF_LDAP_CHECK_REQ, sizeof(DEF_LDAP_CHECK_REQ) - 1);
2564 curproxy->check_len = sizeof(DEF_LDAP_CHECK_REQ) - 1;
2565 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2566 goto out;
2567 }
2568 else if (!strcmp(args[1], "spop-check")) {
2569 if (curproxy == &defproxy) {
2570 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n",
2571 file, linenum, args[0], args[1]);
2572 err_code |= ERR_ALERT | ERR_FATAL;
2573 goto out;
2574 }
2575 if (curproxy->cap & PR_CAP_FE) {
2576 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'frontend' and 'listen' sections.\n",
2577 file, linenum, args[0], args[1]);
2578 err_code |= ERR_ALERT | ERR_FATAL;
2579 goto out;
2580 }
2581
2582 /* use SPOE request to check servers' health */
2583 free(curproxy->check_req);
2584 curproxy->check_req = NULL;
2585 curproxy->options2 &= ~PR_O2_CHK_ANY;
2586 curproxy->options2 |= PR_O2_SPOP_CHK;
2587
2588 if (spoe_prepare_healthcheck_request(&curproxy->check_req, &curproxy->check_len)) {
2589 ha_alert("parsing [%s:%d] : failed to prepare SPOP healthcheck request.\n", file, linenum);
2590 err_code |= ERR_ALERT | ERR_FATAL;
2591 goto out;
2592 }
2593 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2594 goto out;
2595 }
2596 else if (!strcmp(args[1], "tcp-check")) {
2597 /* use raw TCPCHK send/expect to check servers' health */
2598 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2599 err_code |= ERR_WARN;
2600
2601 free(curproxy->check_req);
2602 curproxy->check_req = NULL;
2603 curproxy->options2 &= ~PR_O2_CHK_ANY;
2604 curproxy->options2 |= PR_O2_TCPCHK_CHK;
2605 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2606 goto out;
2607 }
2608 else if (!strcmp(args[1], "external-check")) {
2609 /* excute an external command to check servers' health */
2610 free(curproxy->check_req);
2611 curproxy->check_req = NULL;
2612 curproxy->options2 &= ~PR_O2_CHK_ANY;
2613 curproxy->options2 |= PR_O2_EXT_CHK;
2614 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2615 goto out;
2616 }
2617 else if (!strcmp(args[1], "forwardfor")) {
2618 int cur_arg;
2619
2620 /* insert x-forwarded-for field, but not for the IP address listed as an except.
Christopher Faulet31930372019-07-15 10:16:58 +02002621 * set default options (ie: bitfield, header name, etc)
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002622 */
2623
2624 curproxy->options |= PR_O_FWDFOR | PR_O_FF_ALWAYS;
2625
2626 free(curproxy->fwdfor_hdr_name);
2627 curproxy->fwdfor_hdr_name = strdup(DEF_XFORWARDFOR_HDR);
2628 curproxy->fwdfor_hdr_len = strlen(DEF_XFORWARDFOR_HDR);
2629
2630 /* loop to go through arguments - start at 2, since 0+1 = "option" "forwardfor" */
2631 cur_arg = 2;
2632 while (*(args[cur_arg])) {
2633 if (!strcmp(args[cur_arg], "except")) {
2634 /* suboption except - needs additional argument for it */
2635 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_net, &curproxy->except_mask)) {
2636 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2637 file, linenum, args[0], args[1], args[cur_arg]);
2638 err_code |= ERR_ALERT | ERR_FATAL;
2639 goto out;
2640 }
2641 /* flush useless bits */
2642 curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
2643 cur_arg += 2;
2644 } else if (!strcmp(args[cur_arg], "header")) {
2645 /* suboption header - needs additional argument for it */
2646 if (*(args[cur_arg+1]) == 0) {
2647 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2648 file, linenum, args[0], args[1], args[cur_arg]);
2649 err_code |= ERR_ALERT | ERR_FATAL;
2650 goto out;
2651 }
2652 free(curproxy->fwdfor_hdr_name);
2653 curproxy->fwdfor_hdr_name = strdup(args[cur_arg+1]);
2654 curproxy->fwdfor_hdr_len = strlen(curproxy->fwdfor_hdr_name);
2655 cur_arg += 2;
2656 } else if (!strcmp(args[cur_arg], "if-none")) {
2657 curproxy->options &= ~PR_O_FF_ALWAYS;
2658 cur_arg += 1;
2659 } else {
2660 /* unknown suboption - catchall */
2661 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except', 'header' and 'if-none'.\n",
2662 file, linenum, args[0], args[1]);
2663 err_code |= ERR_ALERT | ERR_FATAL;
2664 goto out;
2665 }
2666 } /* end while loop */
2667 }
2668 else if (!strcmp(args[1], "originalto")) {
2669 int cur_arg;
2670
2671 /* insert x-original-to field, but not for the IP address listed as an except.
2672 * set default options (ie: bitfield, header name, etc)
2673 */
2674
2675 curproxy->options |= PR_O_ORGTO;
2676
2677 free(curproxy->orgto_hdr_name);
2678 curproxy->orgto_hdr_name = strdup(DEF_XORIGINALTO_HDR);
2679 curproxy->orgto_hdr_len = strlen(DEF_XORIGINALTO_HDR);
2680
2681 /* loop to go through arguments - start at 2, since 0+1 = "option" "originalto" */
2682 cur_arg = 2;
2683 while (*(args[cur_arg])) {
2684 if (!strcmp(args[cur_arg], "except")) {
2685 /* suboption except - needs additional argument for it */
2686 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_to, &curproxy->except_mask_to)) {
2687 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2688 file, linenum, args[0], args[1], args[cur_arg]);
2689 err_code |= ERR_ALERT | ERR_FATAL;
2690 goto out;
2691 }
2692 /* flush useless bits */
2693 curproxy->except_to.s_addr &= curproxy->except_mask_to.s_addr;
2694 cur_arg += 2;
2695 } else if (!strcmp(args[cur_arg], "header")) {
2696 /* suboption header - needs additional argument for it */
2697 if (*(args[cur_arg+1]) == 0) {
2698 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2699 file, linenum, args[0], args[1], args[cur_arg]);
2700 err_code |= ERR_ALERT | ERR_FATAL;
2701 goto out;
2702 }
2703 free(curproxy->orgto_hdr_name);
2704 curproxy->orgto_hdr_name = strdup(args[cur_arg+1]);
2705 curproxy->orgto_hdr_len = strlen(curproxy->orgto_hdr_name);
2706 cur_arg += 2;
2707 } else {
2708 /* unknown suboption - catchall */
2709 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
2710 file, linenum, args[0], args[1]);
2711 err_code |= ERR_ALERT | ERR_FATAL;
2712 goto out;
2713 }
2714 } /* end while loop */
2715 }
2716 else {
2717 ha_alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
2718 err_code |= ERR_ALERT | ERR_FATAL;
2719 goto out;
2720 }
2721 goto out;
2722 }
2723 else if (!strcmp(args[0], "default_backend")) {
2724 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
2725 err_code |= ERR_WARN;
2726
2727 if (*(args[1]) == 0) {
2728 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
2729 err_code |= ERR_ALERT | ERR_FATAL;
2730 goto out;
2731 }
2732 free(curproxy->defbe.name);
2733 curproxy->defbe.name = strdup(args[1]);
2734
2735 if (alertif_too_many_args_idx(1, 0, file, linenum, args, &err_code))
2736 goto out;
2737 }
2738 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
Tim Duesterhusdac168b2019-05-14 20:57:58 +02002739 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 +01002740
Tim Duesterhusdac168b2019-05-14 20:57:58 +02002741 err_code |= ERR_ALERT | ERR_FATAL;
2742 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002743 }
2744 else if (!strcmp(args[0], "http-reuse")) {
2745 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2746 err_code |= ERR_WARN;
2747
2748 if (strcmp(args[1], "never") == 0) {
2749 /* enable a graceful server shutdown on an HTTP 404 response */
2750 curproxy->options &= ~PR_O_REUSE_MASK;
2751 curproxy->options |= PR_O_REUSE_NEVR;
2752 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2753 goto out;
2754 }
2755 else if (strcmp(args[1], "safe") == 0) {
2756 /* enable a graceful server shutdown on an HTTP 404 response */
2757 curproxy->options &= ~PR_O_REUSE_MASK;
2758 curproxy->options |= PR_O_REUSE_SAFE;
2759 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2760 goto out;
2761 }
2762 else if (strcmp(args[1], "aggressive") == 0) {
2763 curproxy->options &= ~PR_O_REUSE_MASK;
2764 curproxy->options |= PR_O_REUSE_AGGR;
2765 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2766 goto out;
2767 }
2768 else if (strcmp(args[1], "always") == 0) {
2769 /* enable a graceful server shutdown on an HTTP 404 response */
2770 curproxy->options &= ~PR_O_REUSE_MASK;
2771 curproxy->options |= PR_O_REUSE_ALWS;
2772 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2773 goto out;
2774 }
2775 else {
2776 ha_alert("parsing [%s:%d] : '%s' only supports 'never', 'safe', 'aggressive', 'always'.\n", file, linenum, args[0]);
2777 err_code |= ERR_ALERT | ERR_FATAL;
2778 goto out;
2779 }
2780 }
2781 else if (!strcmp(args[0], "http-check")) {
2782 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2783 err_code |= ERR_WARN;
2784
2785 if (strcmp(args[1], "disable-on-404") == 0) {
2786 /* enable a graceful server shutdown on an HTTP 404 response */
2787 curproxy->options |= PR_O_DISABLE404;
2788 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2789 goto out;
2790 }
2791 else if (strcmp(args[1], "send-state") == 0) {
2792 /* enable emission of the apparent state of a server in HTTP checks */
2793 curproxy->options2 |= PR_O2_CHK_SNDST;
2794 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2795 goto out;
2796 }
2797 else if (strcmp(args[1], "expect") == 0) {
2798 const char *ptr_arg;
2799 int cur_arg;
2800
2801 if (curproxy->options2 & PR_O2_EXP_TYPE) {
2802 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
2803 err_code |= ERR_ALERT | ERR_FATAL;
2804 goto out;
2805 }
2806
2807 cur_arg = 2;
2808 /* consider exclamation marks, sole or at the beginning of a word */
2809 while (*(ptr_arg = args[cur_arg])) {
2810 while (*ptr_arg == '!') {
2811 curproxy->options2 ^= PR_O2_EXP_INV;
2812 ptr_arg++;
2813 }
2814 if (*ptr_arg)
2815 break;
2816 cur_arg++;
2817 }
2818 /* now ptr_arg points to the beginning of a word past any possible
2819 * exclamation mark, and cur_arg is the argument which holds this word.
2820 */
2821 if (strcmp(ptr_arg, "status") == 0) {
2822 if (!*(args[cur_arg + 1])) {
2823 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
2824 file, linenum, args[0], args[1], ptr_arg);
2825 err_code |= ERR_ALERT | ERR_FATAL;
2826 goto out;
2827 }
2828 curproxy->options2 |= PR_O2_EXP_STS;
2829 free(curproxy->expect_str);
2830 curproxy->expect_str = strdup(args[cur_arg + 1]);
2831 }
2832 else if (strcmp(ptr_arg, "string") == 0) {
2833 if (!*(args[cur_arg + 1])) {
2834 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
2835 file, linenum, args[0], args[1], ptr_arg);
2836 err_code |= ERR_ALERT | ERR_FATAL;
2837 goto out;
2838 }
2839 curproxy->options2 |= PR_O2_EXP_STR;
2840 free(curproxy->expect_str);
2841 curproxy->expect_str = strdup(args[cur_arg + 1]);
2842 }
2843 else if (strcmp(ptr_arg, "rstatus") == 0) {
2844 if (!*(args[cur_arg + 1])) {
2845 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
2846 file, linenum, args[0], args[1], ptr_arg);
2847 err_code |= ERR_ALERT | ERR_FATAL;
2848 goto out;
2849 }
2850 curproxy->options2 |= PR_O2_EXP_RSTS;
2851 free(curproxy->expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +02002852 regex_free(curproxy->expect_regex);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002853 curproxy->expect_str = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002854 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02002855 if (!(curproxy->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
2856 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002857 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
2858 free(error);
2859 err_code |= ERR_ALERT | ERR_FATAL;
2860 goto out;
2861 }
2862 }
2863 else if (strcmp(ptr_arg, "rstring") == 0) {
2864 if (!*(args[cur_arg + 1])) {
2865 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
2866 file, linenum, args[0], args[1], ptr_arg);
2867 err_code |= ERR_ALERT | ERR_FATAL;
2868 goto out;
2869 }
2870 curproxy->options2 |= PR_O2_EXP_RSTR;
2871 free(curproxy->expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +02002872 regex_free(curproxy->expect_regex);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002873 curproxy->expect_str = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002874 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02002875 if (!(curproxy->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
2876 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002877 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
2878 free(error);
2879 err_code |= ERR_ALERT | ERR_FATAL;
2880 goto out;
2881 }
2882 }
2883 else {
2884 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'status', 'string', 'rstatus', 'rstring', found '%s'.\n",
2885 file, linenum, args[0], args[1], ptr_arg);
2886 err_code |= ERR_ALERT | ERR_FATAL;
2887 goto out;
2888 }
2889 }
2890 else {
2891 ha_alert("parsing [%s:%d] : '%s' only supports 'disable-on-404', 'send-state', 'expect'.\n", file, linenum, args[0]);
2892 err_code |= ERR_ALERT | ERR_FATAL;
2893 goto out;
2894 }
2895 }
2896 else if (!strcmp(args[0], "tcp-check")) {
2897 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2898 err_code |= ERR_WARN;
2899
2900 if (strcmp(args[1], "comment") == 0) {
2901 int cur_arg;
2902 struct tcpcheck_rule *tcpcheck;
2903
2904 cur_arg = 1;
2905 tcpcheck = calloc(1, sizeof(*tcpcheck));
2906 tcpcheck->action = TCPCHK_ACT_COMMENT;
2907
2908 if (!*args[cur_arg + 1]) {
2909 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
2910 file, linenum, args[cur_arg]);
2911 err_code |= ERR_ALERT | ERR_FATAL;
2912 goto out;
2913 }
2914
2915 tcpcheck->comment = strdup(args[cur_arg + 1]);
2916
2917 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
2918 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
2919 goto out;
2920 }
2921 else if (strcmp(args[1], "connect") == 0) {
2922 const char *ptr_arg;
2923 int cur_arg;
2924 struct tcpcheck_rule *tcpcheck;
2925
2926 /* check if first rule is also a 'connect' action */
2927 tcpcheck = LIST_NEXT(&curproxy->tcpcheck_rules, struct tcpcheck_rule *, list);
2928 while (&tcpcheck->list != &curproxy->tcpcheck_rules &&
2929 tcpcheck->action == TCPCHK_ACT_COMMENT) {
2930 tcpcheck = LIST_NEXT(&tcpcheck->list, struct tcpcheck_rule *, list);
2931 }
2932
2933 if (&tcpcheck->list != &curproxy->tcpcheck_rules
2934 && tcpcheck->action != TCPCHK_ACT_CONNECT) {
2935 ha_alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
2936 file, linenum);
2937 err_code |= ERR_ALERT | ERR_FATAL;
2938 goto out;
2939 }
2940
2941 cur_arg = 2;
2942 tcpcheck = calloc(1, sizeof(*tcpcheck));
2943 tcpcheck->action = TCPCHK_ACT_CONNECT;
2944
2945 /* parsing each parameters to fill up the rule */
2946 while (*(ptr_arg = args[cur_arg])) {
2947 /* tcp port */
2948 if (strcmp(args[cur_arg], "port") == 0) {
2949 if ( (atol(args[cur_arg + 1]) > 65535) ||
2950 (atol(args[cur_arg + 1]) < 1) ){
2951 ha_alert("parsing [%s:%d] : '%s %s %s' expects a valid TCP port (from range 1 to 65535), got %s.\n",
2952 file, linenum, args[0], args[1], "port", args[cur_arg + 1]);
2953 err_code |= ERR_ALERT | ERR_FATAL;
2954 goto out;
2955 }
2956 tcpcheck->port = atol(args[cur_arg + 1]);
2957 cur_arg += 2;
2958 }
2959 /* send proxy protocol */
2960 else if (strcmp(args[cur_arg], "send-proxy") == 0) {
2961 tcpcheck->conn_opts |= TCPCHK_OPT_SEND_PROXY;
2962 cur_arg++;
2963 }
2964#ifdef USE_OPENSSL
2965 else if (strcmp(args[cur_arg], "ssl") == 0) {
2966 curproxy->options |= PR_O_TCPCHK_SSL;
2967 tcpcheck->conn_opts |= TCPCHK_OPT_SSL;
2968 cur_arg++;
2969 }
2970#endif /* USE_OPENSSL */
2971 /* comment for this tcpcheck line */
2972 else if (strcmp(args[cur_arg], "comment") == 0) {
2973 if (!*args[cur_arg + 1]) {
2974 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
2975 file, linenum, args[cur_arg]);
2976 err_code |= ERR_ALERT | ERR_FATAL;
2977 goto out;
2978 }
2979 tcpcheck->comment = strdup(args[cur_arg + 1]);
2980 cur_arg += 2;
2981 }
2982 else {
2983#ifdef USE_OPENSSL
2984 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n",
2985#else /* USE_OPENSSL */
2986 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or but got '%s' as argument.\n",
2987#endif /* USE_OPENSSL */
2988 file, linenum, args[0], args[1], args[cur_arg]);
2989 err_code |= ERR_ALERT | ERR_FATAL;
2990 goto out;
2991 }
2992
2993 }
2994
2995 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
2996 }
2997 else if (strcmp(args[1], "send") == 0) {
2998 if (! *(args[2]) ) {
2999 /* SEND string expected */
3000 ha_alert("parsing [%s:%d] : '%s %s %s' expects <STRING> as argument.\n",
3001 file, linenum, args[0], args[1], args[2]);
3002 err_code |= ERR_ALERT | ERR_FATAL;
3003 goto out;
3004 } else {
3005 struct tcpcheck_rule *tcpcheck;
3006
3007 tcpcheck = calloc(1, sizeof(*tcpcheck));
3008
3009 tcpcheck->action = TCPCHK_ACT_SEND;
3010 tcpcheck->string_len = strlen(args[2]);
3011 tcpcheck->string = strdup(args[2]);
3012 tcpcheck->expect_regex = NULL;
3013
3014 /* comment for this tcpcheck line */
3015 if (strcmp(args[3], "comment") == 0) {
3016 if (!*args[4]) {
3017 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3018 file, linenum, args[3]);
3019 err_code |= ERR_ALERT | ERR_FATAL;
3020 goto out;
3021 }
3022 tcpcheck->comment = strdup(args[4]);
3023 }
3024
3025 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3026 }
3027 }
3028 else if (strcmp(args[1], "send-binary") == 0) {
3029 if (! *(args[2]) ) {
3030 /* SEND binary string expected */
3031 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument.\n",
3032 file, linenum, args[0], args[1], args[2]);
3033 err_code |= ERR_ALERT | ERR_FATAL;
3034 goto out;
3035 } else {
3036 struct tcpcheck_rule *tcpcheck;
3037 char *err = NULL;
3038
3039 tcpcheck = calloc(1, sizeof(*tcpcheck));
3040
3041 tcpcheck->action = TCPCHK_ACT_SEND;
3042 if (parse_binary(args[2], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3043 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3044 file, linenum, args[0], args[1], args[2], err);
3045 err_code |= ERR_ALERT | ERR_FATAL;
3046 goto out;
3047 }
3048 tcpcheck->expect_regex = NULL;
3049
3050 /* comment for this tcpcheck line */
3051 if (strcmp(args[3], "comment") == 0) {
3052 if (!*args[4]) {
3053 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3054 file, linenum, args[3]);
3055 err_code |= ERR_ALERT | ERR_FATAL;
3056 goto out;
3057 }
3058 tcpcheck->comment = strdup(args[4]);
3059 }
3060
3061 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3062 }
3063 }
3064 else if (strcmp(args[1], "expect") == 0) {
3065 const char *ptr_arg;
3066 int cur_arg;
3067 int inverse = 0;
3068
3069 if (curproxy->options2 & PR_O2_EXP_TYPE) {
3070 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
3071 err_code |= ERR_ALERT | ERR_FATAL;
3072 goto out;
3073 }
3074
3075 cur_arg = 2;
3076 /* consider exclamation marks, sole or at the beginning of a word */
3077 while (*(ptr_arg = args[cur_arg])) {
3078 while (*ptr_arg == '!') {
3079 inverse = !inverse;
3080 ptr_arg++;
3081 }
3082 if (*ptr_arg)
3083 break;
3084 cur_arg++;
3085 }
3086 /* now ptr_arg points to the beginning of a word past any possible
3087 * exclamation mark, and cur_arg is the argument which holds this word.
3088 */
3089 if (strcmp(ptr_arg, "binary") == 0) {
3090 struct tcpcheck_rule *tcpcheck;
3091 char *err = NULL;
3092
3093 if (!*(args[cur_arg + 1])) {
3094 ha_alert("parsing [%s:%d] : '%s %s %s' expects <binary string> as an argument.\n",
3095 file, linenum, args[0], args[1], ptr_arg);
3096 err_code |= ERR_ALERT | ERR_FATAL;
3097 goto out;
3098 }
3099
3100 tcpcheck = calloc(1, sizeof(*tcpcheck));
3101
3102 tcpcheck->action = TCPCHK_ACT_EXPECT;
3103 if (parse_binary(args[cur_arg + 1], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3104 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3105 file, linenum, args[0], args[1], args[2], err);
3106 err_code |= ERR_ALERT | ERR_FATAL;
3107 goto out;
3108 }
3109 tcpcheck->expect_regex = NULL;
3110 tcpcheck->inverse = inverse;
3111
3112 /* tcpcheck comment */
3113 cur_arg += 2;
3114 if (strcmp(args[cur_arg], "comment") == 0) {
3115 if (!*args[cur_arg + 1]) {
3116 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3117 file, linenum, args[cur_arg + 1]);
3118 err_code |= ERR_ALERT | ERR_FATAL;
3119 goto out;
3120 }
3121 tcpcheck->comment = strdup(args[cur_arg + 1]);
3122 }
3123
3124 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3125 }
3126 else if (strcmp(ptr_arg, "string") == 0) {
3127 struct tcpcheck_rule *tcpcheck;
3128
3129 if (!*(args[cur_arg + 1])) {
3130 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3131 file, linenum, args[0], args[1], ptr_arg);
3132 err_code |= ERR_ALERT | ERR_FATAL;
3133 goto out;
3134 }
3135
3136 tcpcheck = calloc(1, sizeof(*tcpcheck));
3137
3138 tcpcheck->action = TCPCHK_ACT_EXPECT;
3139 tcpcheck->string_len = strlen(args[cur_arg + 1]);
3140 tcpcheck->string = strdup(args[cur_arg + 1]);
3141 tcpcheck->expect_regex = NULL;
3142 tcpcheck->inverse = inverse;
3143
3144 /* tcpcheck comment */
3145 cur_arg += 2;
3146 if (strcmp(args[cur_arg], "comment") == 0) {
3147 if (!*args[cur_arg + 1]) {
3148 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3149 file, linenum, args[cur_arg + 1]);
3150 err_code |= ERR_ALERT | ERR_FATAL;
3151 goto out;
3152 }
3153 tcpcheck->comment = strdup(args[cur_arg + 1]);
3154 }
3155
3156 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3157 }
3158 else if (strcmp(ptr_arg, "rstring") == 0) {
3159 struct tcpcheck_rule *tcpcheck;
3160
3161 if (!*(args[cur_arg + 1])) {
3162 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3163 file, linenum, args[0], args[1], ptr_arg);
3164 err_code |= ERR_ALERT | ERR_FATAL;
3165 goto out;
3166 }
3167
3168 tcpcheck = calloc(1, sizeof(*tcpcheck));
3169
3170 tcpcheck->action = TCPCHK_ACT_EXPECT;
3171 tcpcheck->string_len = 0;
3172 tcpcheck->string = NULL;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003173 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02003174 if (!(tcpcheck->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
3175 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003176 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3177 free(error);
3178 err_code |= ERR_ALERT | ERR_FATAL;
3179 goto out;
3180 }
3181 tcpcheck->inverse = inverse;
3182
3183 /* tcpcheck comment */
3184 cur_arg += 2;
3185 if (strcmp(args[cur_arg], "comment") == 0) {
3186 if (!*args[cur_arg + 1]) {
3187 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3188 file, linenum, args[cur_arg + 1]);
3189 err_code |= ERR_ALERT | ERR_FATAL;
3190 goto out;
3191 }
3192 tcpcheck->comment = strdup(args[cur_arg + 1]);
3193 }
3194
3195 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3196 }
3197 else {
3198 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'binary', 'string', 'rstring', found '%s'.\n",
3199 file, linenum, args[0], args[1], ptr_arg);
3200 err_code |= ERR_ALERT | ERR_FATAL;
3201 goto out;
3202 }
3203 }
3204 else {
3205 ha_alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
3206 err_code |= ERR_ALERT | ERR_FATAL;
3207 goto out;
3208 }
3209 }
3210 else if (!strcmp(args[0], "monitor")) {
3211 if (curproxy == &defproxy) {
3212 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3213 err_code |= ERR_ALERT | ERR_FATAL;
3214 goto out;
3215 }
3216
3217 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3218 err_code |= ERR_WARN;
3219
3220 if (strcmp(args[1], "fail") == 0) {
3221 /* add a condition to fail monitor requests */
3222 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
3223 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
3224 file, linenum, args[0], args[1]);
3225 err_code |= ERR_ALERT | ERR_FATAL;
3226 goto out;
3227 }
3228
3229 err_code |= warnif_misplaced_monitor(curproxy, file, linenum, "monitor fail");
3230 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
3231 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
3232 file, linenum, args[0], args[1], errmsg);
3233 err_code |= ERR_ALERT | ERR_FATAL;
3234 goto out;
3235 }
3236 LIST_ADDQ(&curproxy->mon_fail_cond, &cond->list);
3237 }
3238 else {
3239 ha_alert("parsing [%s:%d] : '%s' only supports 'fail'.\n", file, linenum, args[0]);
3240 err_code |= ERR_ALERT | ERR_FATAL;
3241 goto out;
3242 }
3243 }
Willy Tarreaue5733232019-05-22 19:24:06 +02003244#ifdef USE_TPROXY
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003245 else if (!strcmp(args[0], "transparent")) {
3246 /* enable transparent proxy connections */
3247 curproxy->options |= PR_O_TRANSP;
3248 if (alertif_too_many_args(0, file, linenum, args, &err_code))
3249 goto out;
3250 }
3251#endif
3252 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3253 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
3254 err_code |= ERR_WARN;
3255
3256 if (*(args[1]) == 0) {
3257 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3258 err_code |= ERR_ALERT | ERR_FATAL;
3259 goto out;
3260 }
3261 curproxy->maxconn = atol(args[1]);
3262 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3263 goto out;
3264 }
3265 else if (!strcmp(args[0], "backlog")) { /* backlog */
3266 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3267 err_code |= ERR_WARN;
3268
3269 if (*(args[1]) == 0) {
3270 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3271 err_code |= ERR_ALERT | ERR_FATAL;
3272 goto out;
3273 }
3274 curproxy->backlog = atol(args[1]);
3275 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3276 goto out;
3277 }
3278 else if (!strcmp(args[0], "fullconn")) { /* fullconn */
3279 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
3280 err_code |= ERR_WARN;
3281
3282 if (*(args[1]) == 0) {
3283 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3284 err_code |= ERR_ALERT | ERR_FATAL;
3285 goto out;
3286 }
3287 curproxy->fullconn = atol(args[1]);
3288 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3289 goto out;
3290 }
3291 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3292 if (*(args[1]) == 0) {
3293 ha_alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
3294 err_code |= ERR_ALERT | ERR_FATAL;
3295 goto out;
3296 }
3297 err = parse_time_err(args[1], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +02003298 if (err == PARSE_TIME_OVER) {
3299 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to grace time, maximum value is 2147483647 ms (~24.8 days).\n",
3300 file, linenum, args[1]);
3301 err_code |= ERR_ALERT | ERR_FATAL;
3302 goto out;
3303 }
3304 else if (err == PARSE_TIME_UNDER) {
3305 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to grace time, minimum non-null value is 1 ms.\n",
3306 file, linenum, args[1]);
3307 err_code |= ERR_ALERT | ERR_FATAL;
3308 goto out;
3309 }
3310 else if (err) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003311 ha_alert("parsing [%s:%d] : unexpected character '%c' in grace time.\n",
3312 file, linenum, *err);
3313 err_code |= ERR_ALERT | ERR_FATAL;
3314 goto out;
3315 }
3316 curproxy->grace = val;
3317 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3318 goto out;
3319 }
3320 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3321 struct sockaddr_storage *sk;
3322 int port1, port2;
3323 struct protocol *proto;
3324
3325 if (curproxy == &defproxy) {
3326 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3327 err_code |= ERR_ALERT | ERR_FATAL;
3328 goto out;
3329 }
3330 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3331 err_code |= ERR_WARN;
3332
3333 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3334 if (!sk) {
3335 ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
3336 err_code |= ERR_ALERT | ERR_FATAL;
3337 goto out;
3338 }
3339
3340 proto = protocol_by_family(sk->ss_family);
3341 if (!proto || !proto->connect) {
3342 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3343 file, linenum, args[0], args[1]);
3344 err_code |= ERR_ALERT | ERR_FATAL;
3345 goto out;
3346 }
3347
3348 if (port1 != port2) {
3349 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'.\n",
3350 file, linenum, args[0], args[1]);
3351 err_code |= ERR_ALERT | ERR_FATAL;
3352 goto out;
3353 }
3354
3355 if (!port1) {
3356 ha_alert("parsing [%s:%d] : '%s' : missing port number in '%s', <addr:port> expected.\n",
3357 file, linenum, args[0], args[1]);
3358 err_code |= ERR_ALERT | ERR_FATAL;
3359 goto out;
3360 }
3361
3362 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3363 goto out;
3364
3365 curproxy->dispatch_addr = *sk;
3366 curproxy->options |= PR_O_DISPATCH;
3367 }
3368 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
3369 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3370 err_code |= ERR_WARN;
3371
3372 if (backend_parse_balance((const char **)args + 1, &errmsg, curproxy) < 0) {
3373 ha_alert("parsing [%s:%d] : %s %s\n", file, linenum, args[0], errmsg);
3374 err_code |= ERR_ALERT | ERR_FATAL;
3375 goto out;
3376 }
3377 }
3378 else if (!strcmp(args[0], "hash-type")) { /* set hashing method */
3379 /**
3380 * The syntax for hash-type config element is
3381 * hash-type {map-based|consistent} [[<algo>] avalanche]
3382 *
3383 * The default hash function is sdbm for map-based and sdbm+avalanche for consistent.
3384 */
3385 curproxy->lbprm.algo &= ~(BE_LB_HASH_TYPE | BE_LB_HASH_FUNC | BE_LB_HASH_MOD);
3386
3387 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3388 err_code |= ERR_WARN;
3389
3390 if (strcmp(args[1], "consistent") == 0) { /* use consistent hashing */
3391 curproxy->lbprm.algo |= BE_LB_HASH_CONS;
3392 }
3393 else if (strcmp(args[1], "map-based") == 0) { /* use map-based hashing */
3394 curproxy->lbprm.algo |= BE_LB_HASH_MAP;
3395 }
3396 else if (strcmp(args[1], "avalanche") == 0) {
3397 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]);
3398 err_code |= ERR_ALERT | ERR_FATAL;
3399 goto out;
3400 }
3401 else {
3402 ha_alert("parsing [%s:%d] : '%s' only supports 'consistent' and 'map-based'.\n", file, linenum, args[0]);
3403 err_code |= ERR_ALERT | ERR_FATAL;
3404 goto out;
3405 }
3406
3407 /* set the hash function to use */
3408 if (!*args[2]) {
3409 /* the default algo is sdbm */
3410 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3411
3412 /* if consistent with no argument, then avalanche modifier is also applied */
3413 if ((curproxy->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS)
3414 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3415 } else {
3416 /* set the hash function */
3417 if (!strcmp(args[2], "sdbm")) {
3418 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3419 }
3420 else if (!strcmp(args[2], "djb2")) {
3421 curproxy->lbprm.algo |= BE_LB_HFCN_DJB2;
3422 }
3423 else if (!strcmp(args[2], "wt6")) {
3424 curproxy->lbprm.algo |= BE_LB_HFCN_WT6;
3425 }
3426 else if (!strcmp(args[2], "crc32")) {
3427 curproxy->lbprm.algo |= BE_LB_HFCN_CRC32;
3428 }
3429 else {
3430 ha_alert("parsing [%s:%d] : '%s' only supports 'sdbm', 'djb2', 'crc32', or 'wt6' hash functions.\n", file, linenum, args[0]);
3431 err_code |= ERR_ALERT | ERR_FATAL;
3432 goto out;
3433 }
3434
3435 /* set the hash modifier */
3436 if (!strcmp(args[3], "avalanche")) {
3437 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3438 }
3439 else if (*args[3]) {
3440 ha_alert("parsing [%s:%d] : '%s' only supports 'avalanche' as a modifier for hash functions.\n", file, linenum, args[0]);
3441 err_code |= ERR_ALERT | ERR_FATAL;
3442 goto out;
3443 }
3444 }
3445 }
3446 else if (strcmp(args[0], "hash-balance-factor") == 0) {
3447 if (*(args[1]) == 0) {
3448 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3449 err_code |= ERR_ALERT | ERR_FATAL;
3450 goto out;
3451 }
Willy Tarreau76e84f52019-01-14 16:50:58 +01003452 curproxy->lbprm.hash_balance_factor = atol(args[1]);
3453 if (curproxy->lbprm.hash_balance_factor != 0 && curproxy->lbprm.hash_balance_factor <= 100) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003454 ha_alert("parsing [%s:%d] : '%s' must be 0 or greater than 100.\n", file, linenum, args[0]);
3455 err_code |= ERR_ALERT | ERR_FATAL;
3456 goto out;
3457 }
3458 }
3459 else if (strcmp(args[0], "unique-id-format") == 0) {
3460 if (!*(args[1])) {
3461 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3462 err_code |= ERR_ALERT | ERR_FATAL;
3463 goto out;
3464 }
3465 if (*(args[2])) {
3466 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3467 err_code |= ERR_ALERT | ERR_FATAL;
3468 goto out;
3469 }
3470 free(curproxy->conf.uniqueid_format_string);
3471 curproxy->conf.uniqueid_format_string = strdup(args[1]);
3472
3473 free(curproxy->conf.uif_file);
3474 curproxy->conf.uif_file = strdup(curproxy->conf.args.file);
3475 curproxy->conf.uif_line = curproxy->conf.args.line;
3476 }
3477
3478 else if (strcmp(args[0], "unique-id-header") == 0) {
3479 if (!*(args[1])) {
3480 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3481 err_code |= ERR_ALERT | ERR_FATAL;
3482 goto out;
3483 }
3484 free(curproxy->header_unique_id);
3485 curproxy->header_unique_id = strdup(args[1]);
3486 }
3487
3488 else if (strcmp(args[0], "log-format") == 0) {
3489 if (!*(args[1])) {
3490 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3491 err_code |= ERR_ALERT | ERR_FATAL;
3492 goto out;
3493 }
3494 if (*(args[2])) {
3495 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3496 err_code |= ERR_ALERT | ERR_FATAL;
3497 goto out;
3498 }
3499 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
3500 char *oldlogformat = "log-format";
3501
3502 if (curproxy->conf.logformat_string == default_http_log_format)
3503 oldlogformat = "option httplog";
3504 else if (curproxy->conf.logformat_string == default_tcp_log_format)
3505 oldlogformat = "option tcplog";
3506 else if (curproxy->conf.logformat_string == clf_http_log_format)
3507 oldlogformat = "option httplog clf";
3508 ha_warning("parsing [%s:%d]: 'log-format' overrides previous '%s' in 'defaults' section.\n",
3509 file, linenum, oldlogformat);
3510 }
3511 if (curproxy->conf.logformat_string != default_http_log_format &&
3512 curproxy->conf.logformat_string != default_tcp_log_format &&
3513 curproxy->conf.logformat_string != clf_http_log_format)
3514 free(curproxy->conf.logformat_string);
3515 curproxy->conf.logformat_string = strdup(args[1]);
3516
3517 free(curproxy->conf.lfs_file);
3518 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
3519 curproxy->conf.lfs_line = curproxy->conf.args.line;
3520
3521 /* get a chance to improve log-format error reporting by
3522 * reporting the correct line-number when possible.
3523 */
3524 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3525 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format' directive is ignored in backends.\n",
3526 file, linenum, curproxy->id);
3527 err_code |= ERR_WARN;
3528 }
3529 }
3530 else if (!strcmp(args[0], "log-format-sd")) {
3531 if (!*(args[1])) {
3532 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3533 err_code |= ERR_ALERT | ERR_FATAL;
3534 goto out;
3535 }
3536 if (*(args[2])) {
3537 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3538 err_code |= ERR_ALERT | ERR_FATAL;
3539 goto out;
3540 }
3541
3542 if (curproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
3543 free(curproxy->conf.logformat_sd_string);
3544 curproxy->conf.logformat_sd_string = strdup(args[1]);
3545
3546 free(curproxy->conf.lfsd_file);
3547 curproxy->conf.lfsd_file = strdup(curproxy->conf.args.file);
3548 curproxy->conf.lfsd_line = curproxy->conf.args.line;
3549
3550 /* get a chance to improve log-format-sd error reporting by
3551 * reporting the correct line-number when possible.
3552 */
3553 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3554 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format-sd' directive is ignored in backends.\n",
3555 file, linenum, curproxy->id);
3556 err_code |= ERR_WARN;
3557 }
3558 }
3559 else if (!strcmp(args[0], "log-tag")) { /* tag to report to syslog */
3560 if (*(args[1]) == 0) {
3561 ha_alert("parsing [%s:%d] : '%s' expects a tag for use in syslog.\n", file, linenum, args[0]);
3562 err_code |= ERR_ALERT | ERR_FATAL;
3563 goto out;
3564 }
3565 chunk_destroy(&curproxy->log_tag);
3566 chunk_initstr(&curproxy->log_tag, strdup(args[1]));
3567 }
3568 else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
3569 if (!parse_logsrv(args, &curproxy->logsrvs, (kwm == KWM_NO), &errmsg)) {
3570 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
3571 err_code |= ERR_ALERT | ERR_FATAL;
3572 goto out;
3573 }
3574 }
3575 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
3576 int cur_arg;
3577 int port1, port2;
3578 struct sockaddr_storage *sk;
3579 struct protocol *proto;
3580
3581 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3582 err_code |= ERR_WARN;
3583
3584 if (!*args[1]) {
3585 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optionally '%s' <addr>, and '%s' <name>.\n",
3586 file, linenum, "source", "usesrc", "interface");
3587 err_code |= ERR_ALERT | ERR_FATAL;
3588 goto out;
3589 }
3590
Christopher Faulet31930372019-07-15 10:16:58 +02003591 /* we must first clear any optional default setting */
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003592 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3593 free(curproxy->conn_src.iface_name);
3594 curproxy->conn_src.iface_name = NULL;
3595 curproxy->conn_src.iface_len = 0;
3596
3597 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3598 if (!sk) {
3599 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3600 file, linenum, args[0], args[1], errmsg);
3601 err_code |= ERR_ALERT | ERR_FATAL;
3602 goto out;
3603 }
3604
3605 proto = protocol_by_family(sk->ss_family);
3606 if (!proto || !proto->connect) {
3607 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3608 file, linenum, args[0], args[1]);
3609 err_code |= ERR_ALERT | ERR_FATAL;
3610 goto out;
3611 }
3612
3613 if (port1 != port2) {
3614 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3615 file, linenum, args[0], args[1]);
3616 err_code |= ERR_ALERT | ERR_FATAL;
3617 goto out;
3618 }
3619
3620 curproxy->conn_src.source_addr = *sk;
3621 curproxy->conn_src.opts |= CO_SRC_BIND;
3622
3623 cur_arg = 2;
3624 while (*(args[cur_arg])) {
3625 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
3626#if defined(CONFIG_HAP_TRANSPARENT)
3627 if (!*args[cur_arg + 1]) {
3628 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
3629 file, linenum, "usesrc");
3630 err_code |= ERR_ALERT | ERR_FATAL;
3631 goto out;
3632 }
3633
3634 if (!strcmp(args[cur_arg + 1], "client")) {
3635 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3636 curproxy->conn_src.opts |= CO_SRC_TPROXY_CLI;
3637 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
3638 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3639 curproxy->conn_src.opts |= CO_SRC_TPROXY_CIP;
3640 } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
3641 char *name, *end;
3642
3643 name = args[cur_arg+1] + 7;
3644 while (isspace(*name))
3645 name++;
3646
3647 end = name;
3648 while (*end && !isspace(*end) && *end != ',' && *end != ')')
3649 end++;
3650
3651 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3652 curproxy->conn_src.opts |= CO_SRC_TPROXY_DYN;
3653 curproxy->conn_src.bind_hdr_name = calloc(1, end - name + 1);
3654 curproxy->conn_src.bind_hdr_len = end - name;
3655 memcpy(curproxy->conn_src.bind_hdr_name, name, end - name);
3656 curproxy->conn_src.bind_hdr_name[end-name] = '\0';
3657 curproxy->conn_src.bind_hdr_occ = -1;
3658
3659 /* now look for an occurrence number */
3660 while (isspace(*end))
3661 end++;
3662 if (*end == ',') {
3663 end++;
3664 name = end;
3665 if (*end == '-')
3666 end++;
3667 while (isdigit((int)*end))
3668 end++;
3669 curproxy->conn_src.bind_hdr_occ = strl2ic(name, end-name);
3670 }
3671
3672 if (curproxy->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
3673 ha_alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
3674 " occurrences values smaller than %d.\n",
3675 file, linenum, MAX_HDR_HISTORY);
3676 err_code |= ERR_ALERT | ERR_FATAL;
3677 goto out;
3678 }
3679 } else {
3680 struct sockaddr_storage *sk;
3681
3682 sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3683 if (!sk) {
3684 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3685 file, linenum, args[cur_arg], args[cur_arg+1], errmsg);
3686 err_code |= ERR_ALERT | ERR_FATAL;
3687 goto out;
3688 }
3689
3690 proto = protocol_by_family(sk->ss_family);
3691 if (!proto || !proto->connect) {
3692 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3693 file, linenum, args[cur_arg], args[cur_arg+1]);
3694 err_code |= ERR_ALERT | ERR_FATAL;
3695 goto out;
3696 }
3697
3698 if (port1 != port2) {
3699 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3700 file, linenum, args[cur_arg], args[cur_arg + 1]);
3701 err_code |= ERR_ALERT | ERR_FATAL;
3702 goto out;
3703 }
3704 curproxy->conn_src.tproxy_addr = *sk;
3705 curproxy->conn_src.opts |= CO_SRC_TPROXY_ADDR;
3706 }
3707 global.last_checks |= LSTCHK_NETADM;
3708#else /* no TPROXY support */
3709 ha_alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
3710 file, linenum, "usesrc");
3711 err_code |= ERR_ALERT | ERR_FATAL;
3712 goto out;
3713#endif
3714 cur_arg += 2;
3715 continue;
3716 }
3717
3718 if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
3719#ifdef SO_BINDTODEVICE
3720 if (!*args[cur_arg + 1]) {
3721 ha_alert("parsing [%s:%d] : '%s' : missing interface name.\n",
3722 file, linenum, args[0]);
3723 err_code |= ERR_ALERT | ERR_FATAL;
3724 goto out;
3725 }
3726 free(curproxy->conn_src.iface_name);
3727 curproxy->conn_src.iface_name = strdup(args[cur_arg + 1]);
3728 curproxy->conn_src.iface_len = strlen(curproxy->conn_src.iface_name);
3729 global.last_checks |= LSTCHK_NETADM;
3730#else
3731 ha_alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
3732 file, linenum, args[0], args[cur_arg]);
3733 err_code |= ERR_ALERT | ERR_FATAL;
3734 goto out;
3735#endif
3736 cur_arg += 2;
3737 continue;
3738 }
3739 ha_alert("parsing [%s:%d] : '%s' only supports optional keywords '%s' and '%s'.\n",
3740 file, linenum, args[0], "interface", "usesrc");
3741 err_code |= ERR_ALERT | ERR_FATAL;
3742 goto out;
3743 }
3744 }
3745 else if (!strcmp(args[0], "usesrc")) { /* address to use outside: needs "source" first */
3746 ha_alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
3747 file, linenum, "usesrc", "source");
3748 err_code |= ERR_ALERT | ERR_FATAL;
3749 goto out;
3750 }
3751 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a 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. "
Willy Tarreau262c3f12019-12-17 06:52:51 +01003753 "Use 'http-request replace-path', 'http-request replace-uri' or 'http-request replace-header' instead.\n",
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003754 file, linenum, args[0]);
3755 err_code |= ERR_ALERT | ERR_FATAL;
3756 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003757 }
3758 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003759 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3760 "Use 'http-request del-header' instead.\n", file, linenum, args[0]);
3761 err_code |= ERR_ALERT | ERR_FATAL;
3762 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003763 }
3764 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003765 ha_alert("parsing [%s:%d] : The '%s' not supported anymore since HAProxy 2.1. "
3766 "Use 'http-request deny' instead.\n", file, linenum, args[0]);
3767 err_code |= ERR_ALERT | ERR_FATAL;
3768 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003769 }
3770 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003771 ha_alert("parsing [%s:%d] : The '%s' not supported anymore since HAProxy 2.1.\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], "reqallow")) { /* allow a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003776 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3777 "Use 'http-request allow' instead.\n", file, linenum, args[0]);
3778 err_code |= ERR_ALERT | ERR_FATAL;
3779 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003780 }
3781 else if (!strcmp(args[0], "reqtarpit")) { /* tarpit a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003782 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3783 "Use 'http-request tarpit' instead.\n", file, linenum, args[0]);
3784 err_code |= ERR_ALERT | ERR_FATAL;
3785 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003786 }
3787 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003788 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3789 "Use 'http-request replace-header' instead.\n", file, linenum, args[0]);
3790 err_code |= ERR_ALERT | ERR_FATAL;
3791 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003792 }
3793 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003794 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3795 "Use 'http-request del-header' instead.\n", file, linenum, args[0]);
3796 err_code |= ERR_ALERT | ERR_FATAL;
3797 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003798 }
3799 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003800 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3801 "Use 'http-request deny' instead.\n", file, linenum, args[0]);
3802 err_code |= ERR_ALERT | ERR_FATAL;
3803 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003804 }
3805 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003806 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1.\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], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003811 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3812 "Use 'http-request allow' 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], "reqitarpit")) { /* tarpit a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003817 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3818 "Use 'http-request tarpit' 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], "reqadd")) { /* add request header */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003823 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3824 "Use 'http-request add-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], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
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 replace-header' 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], "rspdel")) { /* delete response header from a regex */
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 del-header' .\n", file, linenum, args[0]);
3837 err_code |= ERR_ALERT | ERR_FATAL;
3838 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003839 }
3840 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003841 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3842 "Use 'http-response deny' instead.\n", file, linenum, args[0]);
3843 err_code |= ERR_ALERT | ERR_FATAL;
3844 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003845 }
3846 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003847 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore sionce HAProxy 2.1. "
3848 "Use 'http-response replace-header' instead.\n", file, linenum, args[0]);
3849 err_code |= ERR_ALERT | ERR_FATAL;
3850 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003851 }
3852 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003853 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3854 "Use 'http-response del-header' instead.\n", file, linenum, args[0]);
3855 err_code |= ERR_ALERT | ERR_FATAL;
3856 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003857 }
3858 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003859 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3860 "Use 'http-response deny' instead.\n", file, linenum, args[0]);
3861 err_code |= ERR_ALERT | ERR_FATAL;
3862 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003863 }
3864 else if (!strcmp(args[0], "rspadd")) { /* add response header */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003865 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3866 "Use 'http-response add-header' instead.\n", file, linenum, args[0]);
3867 err_code |= ERR_ALERT | ERR_FATAL;
3868 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003869 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003870 else {
3871 struct cfg_kw_list *kwl;
3872 int index;
3873
3874 list_for_each_entry(kwl, &cfg_keywords.list, list) {
3875 for (index = 0; kwl->kw[index].kw != NULL; index++) {
3876 if (kwl->kw[index].section != CFG_LISTEN)
3877 continue;
3878 if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
3879 /* prepare error message just in case */
3880 rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, file, linenum, &errmsg);
3881 if (rc < 0) {
3882 ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
3883 err_code |= ERR_ALERT | ERR_FATAL;
3884 goto out;
3885 }
3886 else if (rc > 0) {
3887 ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
3888 err_code |= ERR_WARN;
3889 goto out;
3890 }
3891 goto out;
3892 }
3893 }
3894 }
3895
3896 ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
3897 err_code |= ERR_ALERT | ERR_FATAL;
3898 goto out;
3899 }
3900 out:
3901 free(errmsg);
3902 return err_code;
3903}