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