blob: 0151130cd71c0e9b7a952049c7f5801406b77d46 [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
Joao Moraise1583752019-10-30 21:04:00 -0300883 if (!strchr(args[cur_arg + 1], '.')) {
884 /* rfc6265, 5.2.3 The Domain Attribute */
885 ha_warning("parsing [%s:%d]: domain '%s' contains no embedded dot,"
886 " this configuration may not work properly (see RFC6265#5.2.3).\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100887 file, linenum, args[cur_arg + 1]);
888 err_code |= ERR_WARN;
889 }
890
891 err = invalid_domainchar(args[cur_arg + 1]);
892 if (err) {
893 ha_alert("parsing [%s:%d]: character '%c' is not permitted in domain name '%s'.\n",
894 file, linenum, *err, args[cur_arg + 1]);
895 err_code |= ERR_ALERT | ERR_FATAL;
896 goto out;
897 }
898
899 if (!curproxy->cookie_domain) {
900 curproxy->cookie_domain = strdup(args[cur_arg + 1]);
901 } else {
902 /* one domain was already specified, add another one by
903 * building the string which will be returned along with
904 * the cookie.
905 */
906 char *new_ptr;
907 int new_len = strlen(curproxy->cookie_domain) +
908 strlen("; domain=") + strlen(args[cur_arg + 1]) + 1;
909 new_ptr = malloc(new_len);
910 snprintf(new_ptr, new_len, "%s; domain=%s", curproxy->cookie_domain, args[cur_arg+1]);
911 free(curproxy->cookie_domain);
912 curproxy->cookie_domain = new_ptr;
913 }
914 cur_arg++;
915 }
916 else if (!strcmp(args[cur_arg], "maxidle")) {
917 unsigned int maxidle;
918 const char *res;
919
920 if (!*args[cur_arg + 1]) {
921 ha_alert("parsing [%s:%d]: '%s' expects <idletime> in seconds as argument.\n",
922 file, linenum, args[cur_arg]);
923 err_code |= ERR_ALERT | ERR_FATAL;
924 goto out;
925 }
926
927 res = parse_time_err(args[cur_arg + 1], &maxidle, TIME_UNIT_S);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200928 if (res == PARSE_TIME_OVER) {
929 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 s (~68 years).\n",
930 file, linenum, args[cur_arg+1], args[cur_arg]);
931 err_code |= ERR_ALERT | ERR_FATAL;
932 goto out;
933 }
934 else if (res == PARSE_TIME_UNDER) {
935 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 s.\n",
936 file, linenum, args[cur_arg+1], args[cur_arg]);
937 err_code |= ERR_ALERT | ERR_FATAL;
938 goto out;
939 }
940 else if (res) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100941 ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
942 file, linenum, *res, args[cur_arg]);
943 err_code |= ERR_ALERT | ERR_FATAL;
944 goto out;
945 }
946 curproxy->cookie_maxidle = maxidle;
947 cur_arg++;
948 }
949 else if (!strcmp(args[cur_arg], "maxlife")) {
950 unsigned int maxlife;
951 const char *res;
952
953 if (!*args[cur_arg + 1]) {
954 ha_alert("parsing [%s:%d]: '%s' expects <lifetime> in seconds as argument.\n",
955 file, linenum, args[cur_arg]);
956 err_code |= ERR_ALERT | ERR_FATAL;
957 goto out;
958 }
959
Willy Tarreau9faebe32019-06-07 19:00:37 +0200960
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100961 res = parse_time_err(args[cur_arg + 1], &maxlife, TIME_UNIT_S);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200962 if (res == PARSE_TIME_OVER) {
963 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 s (~68 years).\n",
964 file, linenum, args[cur_arg+1], args[cur_arg]);
965 err_code |= ERR_ALERT | ERR_FATAL;
966 goto out;
967 }
968 else if (res == PARSE_TIME_UNDER) {
969 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 s.\n",
970 file, linenum, args[cur_arg+1], args[cur_arg]);
971 err_code |= ERR_ALERT | ERR_FATAL;
972 goto out;
973 }
974 else if (res) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +0100975 ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
976 file, linenum, *res, args[cur_arg]);
977 err_code |= ERR_ALERT | ERR_FATAL;
978 goto out;
979 }
980 curproxy->cookie_maxlife = maxlife;
981 cur_arg++;
982 }
983 else if (!strcmp(args[cur_arg], "dynamic")) { /* Dynamic persistent cookies secret key */
984
985 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[cur_arg], NULL))
986 err_code |= ERR_WARN;
987 curproxy->ck_opts |= PR_CK_DYNAMIC;
988 }
989
990 else {
991 ha_alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache', 'postonly', 'domain', 'maxidle', 'dynamic' and 'maxlife' options.\n",
992 file, linenum, args[0]);
993 err_code |= ERR_ALERT | ERR_FATAL;
994 goto out;
995 }
996 cur_arg++;
997 }
998 if (!POWEROF2(curproxy->ck_opts & (PR_CK_RW|PR_CK_IND))) {
999 ha_alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
1000 file, linenum);
1001 err_code |= ERR_ALERT | ERR_FATAL;
1002 }
1003
1004 if (!POWEROF2(curproxy->ck_opts & (PR_CK_RW|PR_CK_INS|PR_CK_PFX))) {
1005 ha_alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
1006 file, linenum);
1007 err_code |= ERR_ALERT | ERR_FATAL;
1008 }
1009
1010 if ((curproxy->ck_opts & (PR_CK_PSV | PR_CK_INS | PR_CK_IND)) == PR_CK_PSV) {
1011 ha_alert("parsing [%s:%d] : cookie 'preserve' requires at least 'insert' or 'indirect'.\n",
1012 file, linenum);
1013 err_code |= ERR_ALERT | ERR_FATAL;
1014 }
1015 }/* end else if (!strcmp(args[0], "cookie")) */
1016 else if (!strcmp(args[0], "email-alert")) {
1017 if (*(args[1]) == 0) {
1018 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1019 file, linenum, args[0]);
1020 err_code |= ERR_ALERT | ERR_FATAL;
1021 goto out;
1022 }
1023
1024 if (!strcmp(args[1], "from")) {
1025 if (*(args[1]) == 0) {
1026 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1027 file, linenum, args[1]);
1028 err_code |= ERR_ALERT | ERR_FATAL;
1029 goto out;
1030 }
1031 free(curproxy->email_alert.from);
1032 curproxy->email_alert.from = strdup(args[2]);
1033 }
1034 else if (!strcmp(args[1], "mailers")) {
1035 if (*(args[1]) == 0) {
1036 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1037 file, linenum, args[1]);
1038 err_code |= ERR_ALERT | ERR_FATAL;
1039 goto out;
1040 }
1041 free(curproxy->email_alert.mailers.name);
1042 curproxy->email_alert.mailers.name = strdup(args[2]);
1043 }
1044 else if (!strcmp(args[1], "myhostname")) {
1045 if (*(args[1]) == 0) {
1046 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1047 file, linenum, args[1]);
1048 err_code |= ERR_ALERT | ERR_FATAL;
1049 goto out;
1050 }
1051 free(curproxy->email_alert.myhostname);
1052 curproxy->email_alert.myhostname = strdup(args[2]);
1053 }
1054 else if (!strcmp(args[1], "level")) {
1055 curproxy->email_alert.level = get_log_level(args[2]);
1056 if (curproxy->email_alert.level < 0) {
1057 ha_alert("parsing [%s:%d] : unknown log level '%s' after '%s'\n",
1058 file, linenum, args[1], args[2]);
1059 err_code |= ERR_ALERT | ERR_FATAL;
1060 goto out;
1061 }
1062 }
1063 else if (!strcmp(args[1], "to")) {
1064 if (*(args[1]) == 0) {
1065 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1066 file, linenum, args[1]);
1067 err_code |= ERR_ALERT | ERR_FATAL;
1068 goto out;
1069 }
1070 free(curproxy->email_alert.to);
1071 curproxy->email_alert.to = strdup(args[2]);
1072 }
1073 else {
1074 ha_alert("parsing [%s:%d] : email-alert: unknown argument '%s'.\n",
1075 file, linenum, args[1]);
1076 err_code |= ERR_ALERT | ERR_FATAL;
1077 goto out;
1078 }
1079 /* Indicate that the email_alert is at least partially configured */
1080 curproxy->email_alert.set = 1;
1081 }/* end else if (!strcmp(args[0], "email-alert")) */
1082 else if (!strcmp(args[0], "external-check")) {
1083 if (*(args[1]) == 0) {
1084 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1085 file, linenum, args[0]);
1086 err_code |= ERR_ALERT | ERR_FATAL;
1087 goto out;
1088 }
1089
1090 if (!strcmp(args[1], "command")) {
1091 if (alertif_too_many_args(2, file, linenum, args, &err_code))
1092 goto out;
1093 if (*(args[2]) == 0) {
1094 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1095 file, linenum, args[1]);
1096 err_code |= ERR_ALERT | ERR_FATAL;
1097 goto out;
1098 }
1099 free(curproxy->check_command);
1100 curproxy->check_command = strdup(args[2]);
1101 }
1102 else if (!strcmp(args[1], "path")) {
1103 if (alertif_too_many_args(2, file, linenum, args, &err_code))
1104 goto out;
1105 if (*(args[2]) == 0) {
1106 ha_alert("parsing [%s:%d] : missing argument after '%s'.\n",
1107 file, linenum, args[1]);
1108 err_code |= ERR_ALERT | ERR_FATAL;
1109 goto out;
1110 }
1111 free(curproxy->check_path);
1112 curproxy->check_path = strdup(args[2]);
1113 }
1114 else {
1115 ha_alert("parsing [%s:%d] : external-check: unknown argument '%s'.\n",
1116 file, linenum, args[1]);
1117 err_code |= ERR_ALERT | ERR_FATAL;
1118 goto out;
1119 }
1120 }/* end else if (!strcmp(args[0], "external-check")) */
1121 else if (!strcmp(args[0], "persist")) { /* persist */
1122 if (*(args[1]) == 0) {
1123 ha_alert("parsing [%s:%d] : missing persist method.\n",
1124 file, linenum);
1125 err_code |= ERR_ALERT | ERR_FATAL;
1126 goto out;
1127 }
1128
1129 if (!strncmp(args[1], "rdp-cookie", 10)) {
1130 curproxy->options2 |= PR_O2_RDPC_PRST;
1131
1132 if (*(args[1] + 10) == '(') { /* cookie name */
1133 const char *beg, *end;
1134
1135 beg = args[1] + 11;
1136 end = strchr(beg, ')');
1137
1138 if (alertif_too_many_args(1, file, linenum, args, &err_code))
1139 goto out;
1140
1141 if (!end || end == beg) {
1142 ha_alert("parsing [%s:%d] : persist rdp-cookie(name)' requires an rdp cookie name.\n",
1143 file, linenum);
1144 err_code |= ERR_ALERT | ERR_FATAL;
1145 goto out;
1146 }
1147
1148 free(curproxy->rdp_cookie_name);
1149 curproxy->rdp_cookie_name = my_strndup(beg, end - beg);
1150 curproxy->rdp_cookie_len = end-beg;
1151 }
1152 else if (*(args[1] + 10) == '\0') { /* default cookie name 'msts' */
1153 free(curproxy->rdp_cookie_name);
1154 curproxy->rdp_cookie_name = strdup("msts");
1155 curproxy->rdp_cookie_len = strlen(curproxy->rdp_cookie_name);
1156 }
1157 else { /* syntax */
1158 ha_alert("parsing [%s:%d] : persist rdp-cookie(name)' requires an rdp cookie name.\n",
1159 file, linenum);
1160 err_code |= ERR_ALERT | ERR_FATAL;
1161 goto out;
1162 }
1163 }
1164 else {
1165 ha_alert("parsing [%s:%d] : unknown persist method.\n",
1166 file, linenum);
1167 err_code |= ERR_ALERT | ERR_FATAL;
1168 goto out;
1169 }
1170 }
1171 else if (!strcmp(args[0], "appsession")) { /* cookie name */
Tim Duesterhus473c2832019-05-06 01:19:52 +02001172 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 +01001173 err_code |= ERR_ALERT | ERR_FATAL;
1174 goto out;
1175 }
1176 else if (!strcmp(args[0], "load-server-state-from-file")) {
1177 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1178 err_code |= ERR_WARN;
1179 if (!strcmp(args[1], "global")) { /* use the file pointed to by global server-state-file directive */
1180 curproxy->load_server_state_from_file = PR_SRV_STATE_FILE_GLOBAL;
1181 }
1182 else if (!strcmp(args[1], "local")) { /* use the server-state-file-name variable to locate the server-state file */
1183 curproxy->load_server_state_from_file = PR_SRV_STATE_FILE_LOCAL;
1184 }
1185 else if (!strcmp(args[1], "none")) { /* don't use server-state-file directive for this backend */
1186 curproxy->load_server_state_from_file = PR_SRV_STATE_FILE_NONE;
1187 }
1188 else {
1189 ha_alert("parsing [%s:%d] : '%s' expects 'global', 'local' or 'none'. Got '%s'\n",
1190 file, linenum, args[0], args[1]);
1191 err_code |= ERR_ALERT | ERR_FATAL;
1192 goto out;
1193 }
1194 }
1195 else if (!strcmp(args[0], "server-state-file-name")) {
1196 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1197 err_code |= ERR_WARN;
1198 if (*(args[1]) == 0) {
1199 ha_alert("parsing [%s:%d] : '%s' expects 'use-backend-name' or a string. Got no argument\n",
1200 file, linenum, args[0]);
1201 err_code |= ERR_ALERT | ERR_FATAL;
1202 goto out;
1203 }
1204 else if (!strcmp(args[1], "use-backend-name"))
1205 curproxy->server_state_file_name = strdup(curproxy->id);
1206 else
1207 curproxy->server_state_file_name = strdup(args[1]);
1208 }
Olivier Houcharda4d4fdf2018-12-14 19:27:06 +01001209 else if (!strcmp(args[0], "max-session-srv-conns")) {
1210 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1211 err_code |= ERR_WARN;
1212 if (*(args[1]) == 0) {
1213 ha_alert("parsine [%s:%d] : '%s' expects a number. Got no argument\n",
1214 file, linenum, args[0]);
1215 err_code |= ERR_ALERT | ERR_FATAL;
1216 goto out;
1217 }
1218 curproxy->max_out_conns = atoi(args[1]);
1219 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001220 else if (!strcmp(args[0], "capture")) {
1221 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1222 err_code |= ERR_WARN;
1223
1224 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
1225 if (curproxy == &defproxy) {
1226 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1227 err_code |= ERR_ALERT | ERR_FATAL;
1228 goto out;
1229 }
1230
1231 if (alertif_too_many_args_idx(4, 1, file, linenum, args, &err_code))
1232 goto out;
1233
1234 if (*(args[4]) == 0) {
1235 ha_alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
1236 file, linenum, args[0]);
1237 err_code |= ERR_ALERT | ERR_FATAL;
1238 goto out;
1239 }
1240 free(curproxy->capture_name);
1241 curproxy->capture_name = strdup(args[2]);
1242 curproxy->capture_namelen = strlen(curproxy->capture_name);
1243 curproxy->capture_len = atol(args[4]);
1244 curproxy->to_log |= LW_COOKIE;
1245 }
1246 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
1247 struct cap_hdr *hdr;
1248
1249 if (curproxy == &defproxy) {
1250 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1251 err_code |= ERR_ALERT | ERR_FATAL;
1252 goto out;
1253 }
1254
1255 if (alertif_too_many_args_idx(4, 1, file, linenum, args, &err_code))
1256 goto out;
1257
1258 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
1259 ha_alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
1260 file, linenum, args[0], args[1]);
1261 err_code |= ERR_ALERT | ERR_FATAL;
1262 goto out;
1263 }
1264
1265 hdr = calloc(1, sizeof(*hdr));
1266 hdr->next = curproxy->req_cap;
1267 hdr->name = strdup(args[3]);
1268 hdr->namelen = strlen(args[3]);
1269 hdr->len = atol(args[5]);
1270 hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
1271 hdr->index = curproxy->nb_req_cap++;
1272 curproxy->req_cap = hdr;
1273 curproxy->to_log |= LW_REQHDR;
1274 }
1275 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
1276 struct cap_hdr *hdr;
1277
1278 if (curproxy == &defproxy) {
1279 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1280 err_code |= ERR_ALERT | ERR_FATAL;
1281 goto out;
1282 }
1283
1284 if (alertif_too_many_args_idx(4, 1, file, linenum, args, &err_code))
1285 goto out;
1286
1287 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
1288 ha_alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
1289 file, linenum, args[0], args[1]);
1290 err_code |= ERR_ALERT | ERR_FATAL;
1291 goto out;
1292 }
1293 hdr = calloc(1, sizeof(*hdr));
1294 hdr->next = curproxy->rsp_cap;
1295 hdr->name = strdup(args[3]);
1296 hdr->namelen = strlen(args[3]);
1297 hdr->len = atol(args[5]);
1298 hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
1299 hdr->index = curproxy->nb_rsp_cap++;
1300 curproxy->rsp_cap = hdr;
1301 curproxy->to_log |= LW_RSPHDR;
1302 }
1303 else {
1304 ha_alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
1305 file, linenum, args[0]);
1306 err_code |= ERR_ALERT | ERR_FATAL;
1307 goto out;
1308 }
1309 }
1310 else if (!strcmp(args[0], "retries")) { /* connection retries */
1311 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1312 err_code |= ERR_WARN;
1313
1314 if (alertif_too_many_args(1, file, linenum, args, &err_code))
1315 goto out;
1316
1317 if (*(args[1]) == 0) {
1318 ha_alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
1319 file, linenum, args[0]);
1320 err_code |= ERR_ALERT | ERR_FATAL;
1321 goto out;
1322 }
1323 curproxy->conn_retries = atol(args[1]);
1324 }
1325 else if (!strcmp(args[0], "http-request")) { /* request access control: allow/deny/auth */
1326 struct act_rule *rule;
1327
1328 if (curproxy == &defproxy) {
1329 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1330 err_code |= ERR_ALERT | ERR_FATAL;
1331 goto out;
1332 }
1333
1334 if (!LIST_ISEMPTY(&curproxy->http_req_rules) &&
1335 !LIST_PREV(&curproxy->http_req_rules, struct act_rule *, list)->cond &&
Christopher Faulet245cf792019-12-18 14:58:12 +01001336 (LIST_PREV(&curproxy->http_req_rules, struct act_rule *, list)->flags & ACT_FLAG_FINAL)) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001337 ha_warning("parsing [%s:%d]: previous '%s' action is final and has no condition attached, further entries are NOOP.\n",
1338 file, linenum, args[0]);
1339 err_code |= ERR_WARN;
1340 }
1341
1342 rule = parse_http_req_cond((const char **)args + 1, file, linenum, curproxy);
1343
1344 if (!rule) {
1345 err_code |= ERR_ALERT | ERR_ABORT;
1346 goto out;
1347 }
1348
1349 err_code |= warnif_misplaced_http_req(curproxy, file, linenum, args[0]);
1350 err_code |= warnif_cond_conflicts(rule->cond,
1351 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1352 file, linenum);
1353
1354 LIST_ADDQ(&curproxy->http_req_rules, &rule->list);
1355 }
1356 else if (!strcmp(args[0], "http-response")) { /* response access control */
1357 struct act_rule *rule;
1358
1359 if (curproxy == &defproxy) {
1360 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1361 err_code |= ERR_ALERT | ERR_FATAL;
1362 goto out;
1363 }
1364
1365 if (!LIST_ISEMPTY(&curproxy->http_res_rules) &&
1366 !LIST_PREV(&curproxy->http_res_rules, struct act_rule *, list)->cond &&
Christopher Faulet245cf792019-12-18 14:58:12 +01001367 (LIST_PREV(&curproxy->http_res_rules, struct act_rule *, list)->flags & ACT_FLAG_FINAL)) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001368 ha_warning("parsing [%s:%d]: previous '%s' action is final and has no condition attached, further entries are NOOP.\n",
1369 file, linenum, args[0]);
1370 err_code |= ERR_WARN;
1371 }
1372
1373 rule = parse_http_res_cond((const char **)args + 1, file, linenum, curproxy);
1374
1375 if (!rule) {
1376 err_code |= ERR_ALERT | ERR_ABORT;
1377 goto out;
1378 }
1379
1380 err_code |= warnif_cond_conflicts(rule->cond,
1381 (curproxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
1382 file, linenum);
1383
1384 LIST_ADDQ(&curproxy->http_res_rules, &rule->list);
1385 }
1386 else if (!strcmp(args[0], "http-send-name-header")) { /* send server name in request header */
1387 /* set the header name and length into the proxy structure */
1388 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1389 err_code |= ERR_WARN;
1390
1391 if (!*args[1]) {
1392 ha_alert("parsing [%s:%d] : '%s' requires a header string.\n",
1393 file, linenum, args[0]);
1394 err_code |= ERR_ALERT | ERR_FATAL;
1395 goto out;
1396 }
1397
Christopher Fauletdabcc8e2019-10-02 10:45:55 +02001398 /* set the desired header name, in lower case */
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001399 free(curproxy->server_id_hdr_name);
1400 curproxy->server_id_hdr_name = strdup(args[1]);
1401 curproxy->server_id_hdr_len = strlen(curproxy->server_id_hdr_name);
Christopher Fauletdabcc8e2019-10-02 10:45:55 +02001402 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 +01001403 }
Tim Duesterhus7b7c47f2019-05-14 20:57:57 +02001404 else if (!strcmp(args[0], "block")) {
1405 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 +01001406
Tim Duesterhus7b7c47f2019-05-14 20:57:57 +02001407 err_code |= ERR_ALERT | ERR_FATAL;
1408 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001409 }
1410 else if (!strcmp(args[0], "redirect")) {
1411 struct redirect_rule *rule;
1412
1413 if (curproxy == &defproxy) {
1414 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1415 err_code |= ERR_ALERT | ERR_FATAL;
1416 goto out;
1417 }
1418
1419 if ((rule = http_parse_redirect_rule(file, linenum, curproxy, (const char **)args + 1, &errmsg, 0, 0)) == NULL) {
1420 ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing redirect rule : %s.\n",
1421 file, linenum, proxy_type_str(curproxy), curproxy->id, errmsg);
1422 err_code |= ERR_ALERT | ERR_FATAL;
1423 goto out;
1424 }
1425
1426 LIST_ADDQ(&curproxy->redirect_rules, &rule->list);
1427 err_code |= warnif_misplaced_redirect(curproxy, file, linenum, args[0]);
1428 err_code |= warnif_cond_conflicts(rule->cond,
1429 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1430 file, linenum);
1431 }
1432 else if (!strcmp(args[0], "use_backend")) {
1433 struct switching_rule *rule;
1434
1435 if (curproxy == &defproxy) {
1436 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1437 err_code |= ERR_ALERT | ERR_FATAL;
1438 goto out;
1439 }
1440
1441 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1442 err_code |= ERR_WARN;
1443
1444 if (*(args[1]) == 0) {
1445 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
1446 err_code |= ERR_ALERT | ERR_FATAL;
1447 goto out;
1448 }
1449
1450 if (strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0) {
1451 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1452 ha_alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
1453 file, linenum, errmsg);
1454 err_code |= ERR_ALERT | ERR_FATAL;
1455 goto out;
1456 }
1457
1458 err_code |= warnif_cond_conflicts(cond, SMP_VAL_FE_SET_BCK, file, linenum);
1459 }
1460 else if (*args[2]) {
1461 ha_alert("parsing [%s:%d] : unexpected keyword '%s' after switching rule, only 'if' and 'unless' are allowed.\n",
1462 file, linenum, args[2]);
1463 err_code |= ERR_ALERT | ERR_FATAL;
1464 goto out;
1465 }
1466
1467 rule = calloc(1, sizeof(*rule));
1468 if (!rule) {
1469 ha_alert("Out of memory error.\n");
1470 goto out;
1471 }
1472 rule->cond = cond;
1473 rule->be.name = strdup(args[1]);
1474 rule->line = linenum;
1475 rule->file = strdup(file);
1476 if (!rule->file) {
1477 ha_alert("Out of memory error.\n");
1478 goto out;
1479 }
1480 LIST_INIT(&rule->list);
1481 LIST_ADDQ(&curproxy->switching_rules, &rule->list);
1482 }
1483 else if (strcmp(args[0], "use-server") == 0) {
1484 struct server_rule *rule;
1485
1486 if (curproxy == &defproxy) {
1487 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1488 err_code |= ERR_ALERT | ERR_FATAL;
1489 goto out;
1490 }
1491
1492 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1493 err_code |= ERR_WARN;
1494
1495 if (*(args[1]) == 0) {
1496 ha_alert("parsing [%s:%d] : '%s' expects a server name.\n", file, linenum, args[0]);
1497 err_code |= ERR_ALERT | ERR_FATAL;
1498 goto out;
1499 }
1500
1501 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
1502 ha_alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1503 file, linenum, args[0]);
1504 err_code |= ERR_ALERT | ERR_FATAL;
1505 goto out;
1506 }
1507
1508 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1509 ha_alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
1510 file, linenum, errmsg);
1511 err_code |= ERR_ALERT | ERR_FATAL;
1512 goto out;
1513 }
1514
1515 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, file, linenum);
1516
1517 rule = calloc(1, sizeof(*rule));
1518 rule->cond = cond;
1519 rule->srv.name = strdup(args[1]);
1520 LIST_INIT(&rule->list);
1521 LIST_ADDQ(&curproxy->server_rules, &rule->list);
1522 curproxy->be_req_ana |= AN_REQ_SRV_RULES;
1523 }
1524 else if ((!strcmp(args[0], "force-persist")) ||
1525 (!strcmp(args[0], "ignore-persist"))) {
1526 struct persist_rule *rule;
1527
1528 if (curproxy == &defproxy) {
1529 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1530 err_code |= ERR_ALERT | ERR_FATAL;
1531 goto out;
1532 }
1533
1534 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1535 err_code |= ERR_WARN;
1536
1537 if (strcmp(args[1], "if") != 0 && strcmp(args[1], "unless") != 0) {
1538 ha_alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1539 file, linenum, args[0]);
1540 err_code |= ERR_ALERT | ERR_FATAL;
1541 goto out;
1542 }
1543
1544 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 1, &errmsg)) == NULL) {
1545 ha_alert("parsing [%s:%d] : error detected while parsing a '%s' rule : %s.\n",
1546 file, linenum, args[0], errmsg);
1547 err_code |= ERR_ALERT | ERR_FATAL;
1548 goto out;
1549 }
1550
1551 /* note: BE_REQ_CNT is the first one after FE_SET_BCK, which is
1552 * where force-persist is applied.
1553 */
1554 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_REQ_CNT, file, linenum);
1555
1556 rule = calloc(1, sizeof(*rule));
1557 rule->cond = cond;
1558 if (!strcmp(args[0], "force-persist")) {
1559 rule->type = PERSIST_TYPE_FORCE;
1560 } else {
1561 rule->type = PERSIST_TYPE_IGNORE;
1562 }
1563 LIST_INIT(&rule->list);
1564 LIST_ADDQ(&curproxy->persist_rules, &rule->list);
1565 }
1566 else if (!strcmp(args[0], "stick-table")) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001567 struct stktable *other;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001568
1569 if (curproxy == &defproxy) {
1570 ha_alert("parsing [%s:%d] : 'stick-table' is not supported in 'defaults' section.\n",
1571 file, linenum);
1572 err_code |= ERR_ALERT | ERR_FATAL;
1573 goto out;
1574 }
1575
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001576 other = stktable_find_by_name(curproxy->id);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001577 if (other) {
1578 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 +01001579 file, linenum, curproxy->id,
1580 other->proxy ? proxy_cap_str(other->proxy->cap) : "peers",
1581 other->proxy ? other->id : other->peers.p->id,
1582 other->conf.file, other->conf.line);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001583 err_code |= ERR_ALERT | ERR_FATAL;
1584 goto out;
1585 }
1586
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001587 curproxy->table = calloc(1, sizeof *curproxy->table);
1588 if (!curproxy->table) {
1589 ha_alert("parsing [%s:%d]: '%s %s' : memory allocation failed\n",
1590 file, linenum, args[0], args[1]);
1591 err_code |= ERR_ALERT | ERR_FATAL;
1592 goto out;
1593 }
1594
Frédéric Lécaillec02766a2019-03-20 15:06:55 +01001595 err_code |= parse_stick_table(file, linenum, args, curproxy->table,
1596 curproxy->id, curproxy->id, NULL);
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001597 if (err_code & ERR_FATAL)
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001598 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001599
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001600 /* Store the proxy in the stick-table. */
1601 curproxy->table->proxy = curproxy;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001602
1603 stktable_store_name(curproxy->table);
1604 curproxy->table->next = stktables_list;
1605 stktables_list = curproxy->table;
Frédéric Lécaille015e4d72019-03-19 14:55:01 +01001606
1607 /* Add this proxy to the list of proxies which refer to its stick-table. */
1608 if (curproxy->table->proxies_list != curproxy) {
1609 curproxy->next_stkt_ref = curproxy->table->proxies_list;
1610 curproxy->table->proxies_list = curproxy;
1611 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001612 }
1613 else if (!strcmp(args[0], "stick")) {
1614 struct sticking_rule *rule;
1615 struct sample_expr *expr;
1616 int myidx = 0;
1617 const char *name = NULL;
1618 int flags;
1619
1620 if (curproxy == &defproxy) {
1621 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1622 err_code |= ERR_ALERT | ERR_FATAL;
1623 goto out;
1624 }
1625
1626 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) {
1627 err_code |= ERR_WARN;
1628 goto out;
1629 }
1630
1631 myidx++;
1632 if ((strcmp(args[myidx], "store") == 0) ||
1633 (strcmp(args[myidx], "store-request") == 0)) {
1634 myidx++;
1635 flags = STK_IS_STORE;
1636 }
1637 else if (strcmp(args[myidx], "store-response") == 0) {
1638 myidx++;
1639 flags = STK_IS_STORE | STK_ON_RSP;
1640 }
1641 else if (strcmp(args[myidx], "match") == 0) {
1642 myidx++;
1643 flags = STK_IS_MATCH;
1644 }
1645 else if (strcmp(args[myidx], "on") == 0) {
1646 myidx++;
1647 flags = STK_IS_MATCH | STK_IS_STORE;
1648 }
1649 else {
1650 ha_alert("parsing [%s:%d] : '%s' expects 'on', 'match', or 'store'.\n", file, linenum, args[0]);
1651 err_code |= ERR_ALERT | ERR_FATAL;
1652 goto out;
1653 }
1654
1655 if (*(args[myidx]) == 0) {
1656 ha_alert("parsing [%s:%d] : '%s' expects a fetch method.\n", file, linenum, args[0]);
1657 err_code |= ERR_ALERT | ERR_FATAL;
1658 goto out;
1659 }
1660
1661 curproxy->conf.args.ctx = ARGC_STK;
1662 expr = sample_parse_expr(args, &myidx, file, linenum, &errmsg, &curproxy->conf.args);
1663 if (!expr) {
1664 ha_alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], errmsg);
1665 err_code |= ERR_ALERT | ERR_FATAL;
1666 goto out;
1667 }
1668
1669 if (flags & STK_ON_RSP) {
1670 if (!(expr->fetch->val & SMP_VAL_BE_STO_RUL)) {
1671 ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available for 'store-response'.\n",
1672 file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
1673 err_code |= ERR_ALERT | ERR_FATAL;
1674 free(expr);
1675 goto out;
1676 }
1677 } else {
1678 if (!(expr->fetch->val & SMP_VAL_BE_SET_SRV)) {
1679 ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available during request.\n",
1680 file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
1681 err_code |= ERR_ALERT | ERR_FATAL;
1682 free(expr);
1683 goto out;
1684 }
1685 }
1686
Christopher Faulet711ed6a2019-07-16 14:16:10 +02001687 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001688 curproxy->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
1689
1690 if (strcmp(args[myidx], "table") == 0) {
1691 myidx++;
1692 name = args[myidx++];
1693 }
1694
1695 if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) {
1696 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + myidx, &errmsg)) == NULL) {
1697 ha_alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition : %s.\n",
1698 file, linenum, args[0], errmsg);
1699 err_code |= ERR_ALERT | ERR_FATAL;
1700 free(expr);
1701 goto out;
1702 }
1703 }
1704 else if (*(args[myidx])) {
1705 ha_alert("parsing [%s:%d] : '%s': unknown keyword '%s'.\n",
1706 file, linenum, args[0], args[myidx]);
1707 err_code |= ERR_ALERT | ERR_FATAL;
1708 free(expr);
1709 goto out;
1710 }
1711 if (flags & STK_ON_RSP)
1712 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_STO_RUL, file, linenum);
1713 else
1714 err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, file, linenum);
1715
1716 rule = calloc(1, sizeof(*rule));
1717 rule->cond = cond;
1718 rule->expr = expr;
1719 rule->flags = flags;
1720 rule->table.name = name ? strdup(name) : NULL;
1721 LIST_INIT(&rule->list);
1722 if (flags & STK_ON_RSP)
1723 LIST_ADDQ(&curproxy->storersp_rules, &rule->list);
1724 else
1725 LIST_ADDQ(&curproxy->sticking_rules, &rule->list);
1726 }
1727 else if (!strcmp(args[0], "stats")) {
1728 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
1729 curproxy->uri_auth = NULL; /* we must detach from the default config */
1730
1731 if (!*args[1]) {
1732 goto stats_error_parsing;
1733 } else if (!strcmp(args[1], "admin")) {
1734 struct stats_admin_rule *rule;
1735
1736 if (curproxy == &defproxy) {
1737 ha_alert("parsing [%s:%d]: '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
1738 err_code |= ERR_ALERT | ERR_FATAL;
1739 goto out;
1740 }
1741
1742 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1743 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1744 err_code |= ERR_ALERT | ERR_ABORT;
1745 goto out;
1746 }
1747
1748 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
1749 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
1750 file, linenum, args[0], args[1]);
1751 err_code |= ERR_ALERT | ERR_FATAL;
1752 goto out;
1753 }
1754 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
1755 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' rule : %s.\n",
1756 file, linenum, args[0], args[1], errmsg);
1757 err_code |= ERR_ALERT | ERR_FATAL;
1758 goto out;
1759 }
1760
1761 err_code |= warnif_cond_conflicts(cond,
1762 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1763 file, linenum);
1764
1765 rule = calloc(1, sizeof(*rule));
1766 rule->cond = cond;
1767 LIST_INIT(&rule->list);
1768 LIST_ADDQ(&curproxy->uri_auth->admin_rules, &rule->list);
1769 } else if (!strcmp(args[1], "uri")) {
1770 if (*(args[2]) == 0) {
1771 ha_alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
1772 err_code |= ERR_ALERT | ERR_FATAL;
1773 goto out;
1774 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
1775 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1776 err_code |= ERR_ALERT | ERR_ABORT;
1777 goto out;
1778 }
1779 } else if (!strcmp(args[1], "realm")) {
1780 if (*(args[2]) == 0) {
1781 ha_alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
1782 err_code |= ERR_ALERT | ERR_FATAL;
1783 goto out;
1784 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
1785 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1786 err_code |= ERR_ALERT | ERR_ABORT;
1787 goto out;
1788 }
1789 } else if (!strcmp(args[1], "refresh")) {
1790 unsigned interval;
1791
1792 err = parse_time_err(args[2], &interval, TIME_UNIT_S);
Willy Tarreau9faebe32019-06-07 19:00:37 +02001793 if (err == PARSE_TIME_OVER) {
1794 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to stats refresh interval, maximum value is 2147483647 s (~68 years).\n",
1795 file, linenum, args[2]);
1796 err_code |= ERR_ALERT | ERR_FATAL;
1797 goto out;
1798 }
1799 else if (err == PARSE_TIME_UNDER) {
1800 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to stats refresh interval, minimum non-null value is 1 s.\n",
1801 file, linenum, args[2]);
1802 err_code |= ERR_ALERT | ERR_FATAL;
1803 goto out;
1804 }
1805 else if (err) {
1806 ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to stats refresh interval.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001807 file, linenum, *err);
1808 err_code |= ERR_ALERT | ERR_FATAL;
1809 goto out;
1810 } else if (!stats_set_refresh(&curproxy->uri_auth, interval)) {
1811 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1812 err_code |= ERR_ALERT | ERR_ABORT;
1813 goto out;
1814 }
1815 } else if (!strcmp(args[1], "http-request")) { /* request access control: allow/deny/auth */
1816 struct act_rule *rule;
1817
1818 if (curproxy == &defproxy) {
1819 ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1820 err_code |= ERR_ALERT | ERR_FATAL;
1821 goto out;
1822 }
1823
1824 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1825 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1826 err_code |= ERR_ALERT | ERR_ABORT;
1827 goto out;
1828 }
1829
1830 if (!LIST_ISEMPTY(&curproxy->uri_auth->http_req_rules) &&
1831 !LIST_PREV(&curproxy->uri_auth->http_req_rules, struct act_rule *, list)->cond) {
1832 ha_warning("parsing [%s:%d]: previous '%s' action has no condition attached, further entries are NOOP.\n",
1833 file, linenum, args[0]);
1834 err_code |= ERR_WARN;
1835 }
1836
1837 rule = parse_http_req_cond((const char **)args + 2, file, linenum, curproxy);
1838
1839 if (!rule) {
1840 err_code |= ERR_ALERT | ERR_ABORT;
1841 goto out;
1842 }
1843
1844 err_code |= warnif_cond_conflicts(rule->cond,
1845 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
1846 file, linenum);
1847 LIST_ADDQ(&curproxy->uri_auth->http_req_rules, &rule->list);
1848
1849 } else if (!strcmp(args[1], "auth")) {
1850 if (*(args[2]) == 0) {
1851 ha_alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
1852 err_code |= ERR_ALERT | ERR_FATAL;
1853 goto out;
1854 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
1855 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1856 err_code |= ERR_ALERT | ERR_ABORT;
1857 goto out;
1858 }
1859 } else if (!strcmp(args[1], "scope")) {
1860 if (*(args[2]) == 0) {
1861 ha_alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
1862 err_code |= ERR_ALERT | ERR_FATAL;
1863 goto out;
1864 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
1865 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1866 err_code |= ERR_ALERT | ERR_ABORT;
1867 goto out;
1868 }
1869 } else if (!strcmp(args[1], "enable")) {
1870 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
1871 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1872 err_code |= ERR_ALERT | ERR_ABORT;
1873 goto out;
1874 }
1875 } else if (!strcmp(args[1], "hide-version")) {
Willy Tarreau708c4162019-10-09 10:19:16 +02001876 if (!stats_set_flag(&curproxy->uri_auth, STAT_HIDEVER)) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001877 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1878 err_code |= ERR_ALERT | ERR_ABORT;
1879 goto out;
1880 }
1881 } else if (!strcmp(args[1], "show-legends")) {
Willy Tarreau708c4162019-10-09 10:19:16 +02001882 if (!stats_set_flag(&curproxy->uri_auth, STAT_SHLGNDS)) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01001883 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1884 err_code |= ERR_ALERT | ERR_ABORT;
1885 goto out;
1886 }
1887 } else if (!strcmp(args[1], "show-node")) {
1888
1889 if (*args[2]) {
1890 int i;
1891 char c;
1892
1893 for (i=0; args[2][i]; i++) {
1894 c = args[2][i];
1895 if (!isupper((unsigned char)c) && !islower((unsigned char)c) &&
1896 !isdigit((unsigned char)c) && c != '_' && c != '-' && c != '.')
1897 break;
1898 }
1899
1900 if (!i || args[2][i]) {
1901 ha_alert("parsing [%s:%d]: '%s %s' invalid node name - should be a string"
1902 "with digits(0-9), letters(A-Z, a-z), hyphen(-) or underscode(_).\n",
1903 file, linenum, args[0], args[1]);
1904 err_code |= ERR_ALERT | ERR_FATAL;
1905 goto out;
1906 }
1907 }
1908
1909 if (!stats_set_node(&curproxy->uri_auth, args[2])) {
1910 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1911 err_code |= ERR_ALERT | ERR_ABORT;
1912 goto out;
1913 }
1914 } else if (!strcmp(args[1], "show-desc")) {
1915 char *desc = NULL;
1916
1917 if (*args[2]) {
1918 int i, len=0;
1919 char *d;
1920
1921 for (i = 2; *args[i]; i++)
1922 len += strlen(args[i]) + 1;
1923
1924 desc = d = calloc(1, len);
1925
1926 d += snprintf(d, desc + len - d, "%s", args[2]);
1927 for (i = 3; *args[i]; i++)
1928 d += snprintf(d, desc + len - d, " %s", args[i]);
1929 }
1930
1931 if (!*args[2] && !global.desc)
1932 ha_warning("parsing [%s:%d]: '%s' requires a parameter or 'desc' to be set in the global section.\n",
1933 file, linenum, args[1]);
1934 else {
1935 if (!stats_set_desc(&curproxy->uri_auth, desc)) {
1936 free(desc);
1937 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
1938 err_code |= ERR_ALERT | ERR_ABORT;
1939 goto out;
1940 }
1941 free(desc);
1942 }
1943 } else {
1944stats_error_parsing:
1945 ha_alert("parsing [%s:%d]: %s '%s', expects 'admin', 'uri', 'realm', 'auth', 'scope', 'enable', 'hide-version', 'show-node', 'show-desc' or 'show-legends'.\n",
1946 file, linenum, *args[1]?"unknown stats parameter":"missing keyword in", args[*args[1]?1:0]);
1947 err_code |= ERR_ALERT | ERR_FATAL;
1948 goto out;
1949 }
1950 }
1951 else if (!strcmp(args[0], "option")) {
1952 int optnum;
1953
1954 if (*(args[1]) == '\0') {
1955 ha_alert("parsing [%s:%d]: '%s' expects an option name.\n",
1956 file, linenum, args[0]);
1957 err_code |= ERR_ALERT | ERR_FATAL;
1958 goto out;
1959 }
1960
1961 for (optnum = 0; cfg_opts[optnum].name; optnum++) {
1962 if (!strcmp(args[1], cfg_opts[optnum].name)) {
1963 if (cfg_opts[optnum].cap == PR_CAP_NONE) {
1964 ha_alert("parsing [%s:%d]: option '%s' is not supported due to build options.\n",
1965 file, linenum, cfg_opts[optnum].name);
1966 err_code |= ERR_ALERT | ERR_FATAL;
1967 goto out;
1968 }
1969 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
1970 goto out;
1971
1972 if (warnifnotcap(curproxy, cfg_opts[optnum].cap, file, linenum, args[1], NULL)) {
1973 err_code |= ERR_WARN;
1974 goto out;
1975 }
1976
1977 curproxy->no_options &= ~cfg_opts[optnum].val;
1978 curproxy->options &= ~cfg_opts[optnum].val;
1979
1980 switch (kwm) {
1981 case KWM_STD:
1982 curproxy->options |= cfg_opts[optnum].val;
1983 break;
1984 case KWM_NO:
1985 curproxy->no_options |= cfg_opts[optnum].val;
1986 break;
1987 case KWM_DEF: /* already cleared */
1988 break;
1989 }
1990
1991 goto out;
1992 }
1993 }
1994
1995 for (optnum = 0; cfg_opts2[optnum].name; optnum++) {
1996 if (!strcmp(args[1], cfg_opts2[optnum].name)) {
1997 if (cfg_opts2[optnum].cap == PR_CAP_NONE) {
1998 ha_alert("parsing [%s:%d]: option '%s' is not supported due to build options.\n",
1999 file, linenum, cfg_opts2[optnum].name);
2000 err_code |= ERR_ALERT | ERR_FATAL;
2001 goto out;
2002 }
2003 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2004 goto out;
2005 if (warnifnotcap(curproxy, cfg_opts2[optnum].cap, file, linenum, args[1], NULL)) {
2006 err_code |= ERR_WARN;
2007 goto out;
2008 }
2009
Christopher Faulet31930372019-07-15 10:16:58 +02002010 /* "[no] option http-use-htx" is deprecated */
2011 if (!strcmp(cfg_opts2[optnum].name, "http-use-htx")) {
Christopher Fauletf89f0992019-07-19 11:17:38 +02002012 if (kwm ==KWM_NO) {
2013 ha_warning("parsing [%s:%d]: option '%s' is deprecated and ignored."
2014 " The HTX mode is now the only supported mode.\n",
2015 file, linenum, cfg_opts2[optnum].name);
2016 err_code |= ERR_WARN;
2017 }
Christopher Faulet31930372019-07-15 10:16:58 +02002018 goto out;
2019 }
2020
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002021 curproxy->no_options2 &= ~cfg_opts2[optnum].val;
2022 curproxy->options2 &= ~cfg_opts2[optnum].val;
2023
2024 switch (kwm) {
2025 case KWM_STD:
2026 curproxy->options2 |= cfg_opts2[optnum].val;
2027 break;
2028 case KWM_NO:
2029 curproxy->no_options2 |= cfg_opts2[optnum].val;
2030 break;
2031 case KWM_DEF: /* already cleared */
2032 break;
2033 }
2034 goto out;
2035 }
2036 }
2037
2038 /* HTTP options override each other. They can be cancelled using
2039 * "no option xxx" which only switches to default mode if the mode
2040 * was this one (useful for cancelling options set in defaults
2041 * sections).
2042 */
2043 if (strcmp(args[1], "httpclose") == 0 || strcmp(args[1], "forceclose") == 0) {
Tim Duesterhus10c6c162019-05-14 20:58:00 +02002044 if (strcmp(args[1], "forceclose") == 0) {
2045 if (!already_warned(WARN_FORCECLOSE_DEPRECATED))
2046 ha_warning("parsing [%s:%d]: keyword '%s' is deprecated in favor of 'httpclose', and will not be supported by future versions.\n",
2047 file, linenum, args[1]);
2048 err_code |= ERR_WARN;
2049 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002050 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2051 goto out;
2052 if (kwm == KWM_STD) {
2053 curproxy->options &= ~PR_O_HTTP_MODE;
2054 curproxy->options |= PR_O_HTTP_CLO;
2055 goto out;
2056 }
2057 else if (kwm == KWM_NO) {
2058 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_CLO)
2059 curproxy->options &= ~PR_O_HTTP_MODE;
2060 goto out;
2061 }
2062 }
2063 else if (strcmp(args[1], "http-server-close") == 0) {
2064 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2065 goto out;
2066 if (kwm == KWM_STD) {
2067 curproxy->options &= ~PR_O_HTTP_MODE;
2068 curproxy->options |= PR_O_HTTP_SCL;
2069 goto out;
2070 }
2071 else if (kwm == KWM_NO) {
2072 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL)
2073 curproxy->options &= ~PR_O_HTTP_MODE;
2074 goto out;
2075 }
2076 }
2077 else if (strcmp(args[1], "http-keep-alive") == 0) {
2078 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2079 goto out;
2080 if (kwm == KWM_STD) {
2081 curproxy->options &= ~PR_O_HTTP_MODE;
2082 curproxy->options |= PR_O_HTTP_KAL;
2083 goto out;
2084 }
2085 else if (kwm == KWM_NO) {
2086 if ((curproxy->options & PR_O_HTTP_MODE) == PR_O_HTTP_KAL)
2087 curproxy->options &= ~PR_O_HTTP_MODE;
2088 goto out;
2089 }
2090 }
2091 else if (strcmp(args[1], "http-tunnel") == 0) {
Christopher Faulet73e8ede2019-07-16 15:04:46 +02002092 ha_warning("parsing [%s:%d]: the option '%s' is deprecated and will be removed in next version.\n",
2093 file, linenum, args[1]);
2094 err_code |= ERR_WARN;
2095 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002096 }
2097
2098 /* Redispatch can take an integer argument that control when the
2099 * resispatch occurs. All values are relative to the retries option.
2100 * This can be cancelled using "no option xxx".
2101 */
2102 if (strcmp(args[1], "redispatch") == 0) {
2103 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL)) {
2104 err_code |= ERR_WARN;
2105 goto out;
2106 }
2107
2108 curproxy->no_options &= ~PR_O_REDISP;
2109 curproxy->options &= ~PR_O_REDISP;
2110
2111 switch (kwm) {
2112 case KWM_STD:
2113 curproxy->options |= PR_O_REDISP;
2114 curproxy->redispatch_after = -1;
2115 if(*args[2]) {
2116 curproxy->redispatch_after = atol(args[2]);
2117 }
2118 break;
2119 case KWM_NO:
2120 curproxy->no_options |= PR_O_REDISP;
2121 curproxy->redispatch_after = 0;
2122 break;
2123 case KWM_DEF: /* already cleared */
2124 break;
2125 }
2126 goto out;
2127 }
2128
2129 if (kwm != KWM_STD) {
2130 ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
2131 file, linenum, args[1]);
2132 err_code |= ERR_ALERT | ERR_FATAL;
2133 goto out;
2134 }
2135
2136 if (!strcmp(args[1], "httplog")) {
2137 char *logformat;
2138 /* generate a complete HTTP log */
2139 logformat = default_http_log_format;
2140 if (*(args[2]) != '\0') {
2141 if (!strcmp(args[2], "clf")) {
2142 curproxy->options2 |= PR_O2_CLFLOG;
2143 logformat = clf_http_log_format;
2144 } else {
2145 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'clf'.\n", file, linenum, args[1]);
2146 err_code |= ERR_ALERT | ERR_FATAL;
2147 goto out;
2148 }
2149 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
2150 goto out;
2151 }
2152 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2153 char *oldlogformat = "log-format";
2154 char *clflogformat = "";
2155
2156 if (curproxy->conf.logformat_string == default_http_log_format)
2157 oldlogformat = "option httplog";
2158 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2159 oldlogformat = "option tcplog";
2160 else if (curproxy->conf.logformat_string == clf_http_log_format)
2161 oldlogformat = "option httplog clf";
2162 if (logformat == clf_http_log_format)
2163 clflogformat = " clf";
2164 ha_warning("parsing [%s:%d]: 'option httplog%s' overrides previous '%s' in 'defaults' section.\n",
2165 file, linenum, clflogformat, oldlogformat);
2166 }
2167 if (curproxy->conf.logformat_string != default_http_log_format &&
2168 curproxy->conf.logformat_string != default_tcp_log_format &&
2169 curproxy->conf.logformat_string != clf_http_log_format)
2170 free(curproxy->conf.logformat_string);
2171 curproxy->conf.logformat_string = logformat;
2172
2173 free(curproxy->conf.lfs_file);
2174 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2175 curproxy->conf.lfs_line = curproxy->conf.args.line;
2176
2177 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2178 ha_warning("parsing [%s:%d] : backend '%s' : 'option httplog' directive is ignored in backends.\n",
2179 file, linenum, curproxy->id);
2180 err_code |= ERR_WARN;
2181 }
2182 }
2183 else if (!strcmp(args[1], "tcplog")) {
2184 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
2185 char *oldlogformat = "log-format";
2186
2187 if (curproxy->conf.logformat_string == default_http_log_format)
2188 oldlogformat = "option httplog";
2189 else if (curproxy->conf.logformat_string == default_tcp_log_format)
2190 oldlogformat = "option tcplog";
2191 else if (curproxy->conf.logformat_string == clf_http_log_format)
2192 oldlogformat = "option httplog clf";
2193 ha_warning("parsing [%s:%d]: 'option tcplog' overrides previous '%s' in 'defaults' section.\n",
2194 file, linenum, oldlogformat);
2195 }
2196 /* generate a detailed TCP log */
2197 if (curproxy->conf.logformat_string != default_http_log_format &&
2198 curproxy->conf.logformat_string != default_tcp_log_format &&
2199 curproxy->conf.logformat_string != clf_http_log_format)
2200 free(curproxy->conf.logformat_string);
2201 curproxy->conf.logformat_string = default_tcp_log_format;
2202
2203 free(curproxy->conf.lfs_file);
2204 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
2205 curproxy->conf.lfs_line = curproxy->conf.args.line;
2206
2207 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2208 goto out;
2209
2210 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
2211 ha_warning("parsing [%s:%d] : backend '%s' : 'option tcplog' directive is ignored in backends.\n",
2212 file, linenum, curproxy->id);
2213 err_code |= ERR_WARN;
2214 }
2215 }
2216 else if (!strcmp(args[1], "tcpka")) {
2217 /* enable TCP keep-alives on client and server streams */
2218 if (warnifnotcap(curproxy, PR_CAP_BE | PR_CAP_FE, file, linenum, args[1], NULL))
2219 err_code |= ERR_WARN;
2220
2221 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2222 goto out;
2223
2224 if (curproxy->cap & PR_CAP_FE)
2225 curproxy->options |= PR_O_TCP_CLI_KA;
2226 if (curproxy->cap & PR_CAP_BE)
2227 curproxy->options |= PR_O_TCP_SRV_KA;
2228 }
2229 else if (!strcmp(args[1], "httpchk")) {
2230 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2231 err_code |= ERR_WARN;
2232
2233 /* use HTTP request to check servers' health */
2234 free(curproxy->check_req);
2235 curproxy->check_req = NULL;
2236 curproxy->options2 &= ~PR_O2_CHK_ANY;
2237 curproxy->options2 |= PR_O2_HTTP_CHK;
2238 if (!*args[2]) { /* no argument */
2239 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
2240 curproxy->check_len = strlen(DEF_CHECK_REQ);
2241 } else if (!*args[3]) { /* one argument : URI */
2242 int reqlen = strlen(args[2]) + strlen("OPTIONS HTTP/1.0\r\n") + 1;
2243 curproxy->check_req = malloc(reqlen);
2244 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2245 "OPTIONS %s HTTP/1.0\r\n", args[2]); /* URI to use */
2246 } else { /* more arguments : METHOD URI [HTTP_VER] */
2247 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n");
2248 if (*args[4])
2249 reqlen += strlen(args[4]);
2250 else
2251 reqlen += strlen("HTTP/1.0");
2252
2253 curproxy->check_req = malloc(reqlen);
2254 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2255 "%s %s %s\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
2256 }
2257 if (alertif_too_many_args_idx(3, 1, file, linenum, args, &err_code))
2258 goto out;
2259 }
2260 else if (!strcmp(args[1], "ssl-hello-chk")) {
2261 /* use SSLv3 CLIENT HELLO to check servers' health */
2262 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2263 err_code |= ERR_WARN;
2264
2265 free(curproxy->check_req);
2266 curproxy->check_req = NULL;
2267 curproxy->options2 &= ~PR_O2_CHK_ANY;
2268 curproxy->options2 |= PR_O2_SSL3_CHK;
2269
2270 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2271 goto out;
2272 }
2273 else if (!strcmp(args[1], "smtpchk")) {
2274 /* use SMTP request to check servers' health */
2275 free(curproxy->check_req);
2276 curproxy->check_req = NULL;
2277 curproxy->options2 &= ~PR_O2_CHK_ANY;
2278 curproxy->options2 |= PR_O2_SMTP_CHK;
2279
2280 if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */
2281 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2282 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2283 } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */
2284 if (!strcmp(args[2], "EHLO") || !strcmp(args[2], "HELO")) {
2285 int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" \r\n") + 1;
2286 curproxy->check_req = malloc(reqlen);
2287 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
2288 "%s %s\r\n", args[2], args[3]); /* HELO hostname */
2289 } else {
2290 /* this just hits the default for now, but you could potentially expand it to allow for other stuff
2291 though, it's unlikely you'd want to send anything other than an EHLO or HELO */
2292 curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */
2293 curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ);
2294 }
2295 }
2296 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2297 goto out;
2298 }
2299 else if (!strcmp(args[1], "pgsql-check")) {
2300 /* use PostgreSQL request to check servers' health */
2301 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2302 err_code |= ERR_WARN;
2303
2304 free(curproxy->check_req);
2305 curproxy->check_req = NULL;
2306 curproxy->options2 &= ~PR_O2_CHK_ANY;
2307 curproxy->options2 |= PR_O2_PGSQL_CHK;
2308
2309 if (*(args[2])) {
2310 int cur_arg = 2;
2311
2312 while (*(args[cur_arg])) {
2313 if (strcmp(args[cur_arg], "user") == 0) {
2314 char * packet;
2315 uint32_t packet_len;
2316 uint32_t pv;
2317
2318 /* suboption header - needs additional argument for it */
2319 if (*(args[cur_arg+1]) == 0) {
2320 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2321 file, linenum, args[0], args[1], args[cur_arg]);
2322 err_code |= ERR_ALERT | ERR_FATAL;
2323 goto out;
2324 }
2325
2326 /* uint32_t + uint32_t + strlen("user")+1 + strlen(username)+1 + 1 */
2327 packet_len = 4 + 4 + 5 + strlen(args[cur_arg + 1])+1 +1;
2328 pv = htonl(0x30000); /* protocol version 3.0 */
2329
2330 packet = calloc(1, packet_len);
2331
2332 memcpy(packet + 4, &pv, 4);
2333
2334 /* copy "user" */
2335 memcpy(packet + 8, "user", 4);
2336
2337 /* copy username */
2338 memcpy(packet + 13, args[cur_arg+1], strlen(args[cur_arg+1]));
2339
2340 free(curproxy->check_req);
2341 curproxy->check_req = packet;
2342 curproxy->check_len = packet_len;
2343
2344 packet_len = htonl(packet_len);
2345 memcpy(packet, &packet_len, 4);
2346 cur_arg += 2;
2347 } else {
2348 /* unknown suboption - catchall */
2349 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2350 file, linenum, args[0], args[1]);
2351 err_code |= ERR_ALERT | ERR_FATAL;
2352 goto out;
2353 }
2354 } /* end while loop */
2355 }
2356 if (alertif_too_many_args_idx(2, 1, file, linenum, args, &err_code))
2357 goto out;
2358 }
2359
2360 else if (!strcmp(args[1], "redis-check")) {
2361 /* use REDIS PING request to check servers' health */
2362 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2363 err_code |= ERR_WARN;
2364
2365 free(curproxy->check_req);
2366 curproxy->check_req = NULL;
2367 curproxy->options2 &= ~PR_O2_CHK_ANY;
2368 curproxy->options2 |= PR_O2_REDIS_CHK;
2369
2370 curproxy->check_req = malloc(sizeof(DEF_REDIS_CHECK_REQ) - 1);
2371 memcpy(curproxy->check_req, DEF_REDIS_CHECK_REQ, sizeof(DEF_REDIS_CHECK_REQ) - 1);
2372 curproxy->check_len = sizeof(DEF_REDIS_CHECK_REQ) - 1;
2373
2374 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2375 goto out;
2376 }
2377
2378 else if (!strcmp(args[1], "mysql-check")) {
2379 /* use MYSQL request to check servers' health */
2380 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2381 err_code |= ERR_WARN;
2382
2383 free(curproxy->check_req);
2384 curproxy->check_req = NULL;
2385 curproxy->options2 &= ~PR_O2_CHK_ANY;
2386 curproxy->options2 |= PR_O2_MYSQL_CHK;
2387
2388 /* This is an example of a MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte.
2389 * const char mysql40_client_auth_pkt[] = {
2390 * "\x0e\x00\x00" // packet length
2391 * "\x01" // packet number
2392 * "\x00\x00" // client capabilities
2393 * "\x00\x00\x01" // max packet
2394 * "haproxy\x00" // username (null terminated string)
2395 * "\x00" // filler (always 0x00)
2396 * "\x01\x00\x00" // packet length
2397 * "\x00" // packet number
2398 * "\x01" // COM_QUIT command
2399 * };
2400 */
2401
2402 /* This is an example of a MySQL >=4.1 client Authentication packet provided by Nenad Merdanovic.
2403 * const char mysql41_client_auth_pkt[] = {
2404 * "\x0e\x00\x00\" // packet length
2405 * "\x01" // packet number
2406 * "\x00\x00\x00\x00" // client capabilities
2407 * "\x00\x00\x00\x01" // max packet
2408 * "\x21" // character set (UTF-8)
2409 * char[23] // All zeroes
2410 * "haproxy\x00" // username (null terminated string)
2411 * "\x00" // filler (always 0x00)
2412 * "\x01\x00\x00" // packet length
2413 * "\x00" // packet number
2414 * "\x01" // COM_QUIT command
2415 * };
2416 */
2417
2418
2419 if (*(args[2])) {
2420 int cur_arg = 2;
2421
2422 while (*(args[cur_arg])) {
2423 if (strcmp(args[cur_arg], "user") == 0) {
2424 char *mysqluser;
2425 int packetlen, reqlen, userlen;
2426
2427 /* suboption header - needs additional argument for it */
2428 if (*(args[cur_arg+1]) == 0) {
2429 ha_alert("parsing [%s:%d] : '%s %s %s' expects <username> as argument.\n",
2430 file, linenum, args[0], args[1], args[cur_arg]);
2431 err_code |= ERR_ALERT | ERR_FATAL;
2432 goto out;
2433 }
2434 mysqluser = args[cur_arg + 1];
2435 userlen = strlen(mysqluser);
2436
2437 if (*(args[cur_arg+2])) {
2438 if (!strcmp(args[cur_arg+2], "post-41")) {
2439 packetlen = userlen + 7 + 27;
2440 reqlen = packetlen + 9;
2441
2442 free(curproxy->check_req);
2443 curproxy->check_req = calloc(1, reqlen);
2444 curproxy->check_len = reqlen;
2445
2446 snprintf(curproxy->check_req, 4, "%c%c%c",
2447 ((unsigned char) packetlen & 0xff),
2448 ((unsigned char) (packetlen >> 8) & 0xff),
2449 ((unsigned char) (packetlen >> 16) & 0xff));
2450
2451 curproxy->check_req[3] = 1;
2452 curproxy->check_req[5] = 0x82; // 130
2453 curproxy->check_req[11] = 1;
2454 curproxy->check_req[12] = 33;
2455 memcpy(&curproxy->check_req[36], mysqluser, userlen);
2456 curproxy->check_req[36 + userlen + 1 + 1] = 1;
2457 curproxy->check_req[36 + userlen + 1 + 1 + 4] = 1;
2458 cur_arg += 3;
2459 } else {
2460 ha_alert("parsing [%s:%d] : keyword '%s' only supports option 'post-41'.\n", file, linenum, args[cur_arg+2]);
2461 err_code |= ERR_ALERT | ERR_FATAL;
2462 goto out;
2463 }
2464 } else {
2465 packetlen = userlen + 7;
2466 reqlen = packetlen + 9;
2467
2468 free(curproxy->check_req);
2469 curproxy->check_req = calloc(1, reqlen);
2470 curproxy->check_len = reqlen;
2471
2472 snprintf(curproxy->check_req, 4, "%c%c%c",
2473 ((unsigned char) packetlen & 0xff),
2474 ((unsigned char) (packetlen >> 8) & 0xff),
2475 ((unsigned char) (packetlen >> 16) & 0xff));
2476
2477 curproxy->check_req[3] = 1;
2478 curproxy->check_req[5] = 0x80;
2479 curproxy->check_req[8] = 1;
2480 memcpy(&curproxy->check_req[9], mysqluser, userlen);
2481 curproxy->check_req[9 + userlen + 1 + 1] = 1;
2482 curproxy->check_req[9 + userlen + 1 + 1 + 4] = 1;
2483 cur_arg += 2;
2484 }
2485 } else {
2486 /* unknown suboption - catchall */
2487 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
2488 file, linenum, args[0], args[1]);
2489 err_code |= ERR_ALERT | ERR_FATAL;
2490 goto out;
2491 }
2492 } /* end while loop */
2493 }
2494 }
2495 else if (!strcmp(args[1], "ldap-check")) {
2496 /* use LDAP request to check servers' health */
2497 free(curproxy->check_req);
2498 curproxy->check_req = NULL;
2499 curproxy->options2 &= ~PR_O2_CHK_ANY;
2500 curproxy->options2 |= PR_O2_LDAP_CHK;
2501
2502 curproxy->check_req = malloc(sizeof(DEF_LDAP_CHECK_REQ) - 1);
2503 memcpy(curproxy->check_req, DEF_LDAP_CHECK_REQ, sizeof(DEF_LDAP_CHECK_REQ) - 1);
2504 curproxy->check_len = sizeof(DEF_LDAP_CHECK_REQ) - 1;
2505 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2506 goto out;
2507 }
2508 else if (!strcmp(args[1], "spop-check")) {
2509 if (curproxy == &defproxy) {
2510 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n",
2511 file, linenum, args[0], args[1]);
2512 err_code |= ERR_ALERT | ERR_FATAL;
2513 goto out;
2514 }
2515 if (curproxy->cap & PR_CAP_FE) {
2516 ha_alert("parsing [%s:%d] : '%s %s' not allowed in 'frontend' and 'listen' sections.\n",
2517 file, linenum, args[0], args[1]);
2518 err_code |= ERR_ALERT | ERR_FATAL;
2519 goto out;
2520 }
2521
2522 /* use SPOE request to check servers' health */
2523 free(curproxy->check_req);
2524 curproxy->check_req = NULL;
2525 curproxy->options2 &= ~PR_O2_CHK_ANY;
2526 curproxy->options2 |= PR_O2_SPOP_CHK;
2527
2528 if (spoe_prepare_healthcheck_request(&curproxy->check_req, &curproxy->check_len)) {
2529 ha_alert("parsing [%s:%d] : failed to prepare SPOP healthcheck request.\n", file, linenum);
2530 err_code |= ERR_ALERT | ERR_FATAL;
2531 goto out;
2532 }
2533 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2534 goto out;
2535 }
2536 else if (!strcmp(args[1], "tcp-check")) {
2537 /* use raw TCPCHK send/expect to check servers' health */
2538 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL))
2539 err_code |= ERR_WARN;
2540
2541 free(curproxy->check_req);
2542 curproxy->check_req = NULL;
2543 curproxy->options2 &= ~PR_O2_CHK_ANY;
2544 curproxy->options2 |= PR_O2_TCPCHK_CHK;
2545 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2546 goto out;
2547 }
2548 else if (!strcmp(args[1], "external-check")) {
2549 /* excute an external command to check servers' health */
2550 free(curproxy->check_req);
2551 curproxy->check_req = NULL;
2552 curproxy->options2 &= ~PR_O2_CHK_ANY;
2553 curproxy->options2 |= PR_O2_EXT_CHK;
2554 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2555 goto out;
2556 }
2557 else if (!strcmp(args[1], "forwardfor")) {
2558 int cur_arg;
2559
2560 /* insert x-forwarded-for field, but not for the IP address listed as an except.
Christopher Faulet31930372019-07-15 10:16:58 +02002561 * set default options (ie: bitfield, header name, etc)
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002562 */
2563
2564 curproxy->options |= PR_O_FWDFOR | PR_O_FF_ALWAYS;
2565
2566 free(curproxy->fwdfor_hdr_name);
2567 curproxy->fwdfor_hdr_name = strdup(DEF_XFORWARDFOR_HDR);
2568 curproxy->fwdfor_hdr_len = strlen(DEF_XFORWARDFOR_HDR);
2569
2570 /* loop to go through arguments - start at 2, since 0+1 = "option" "forwardfor" */
2571 cur_arg = 2;
2572 while (*(args[cur_arg])) {
2573 if (!strcmp(args[cur_arg], "except")) {
2574 /* suboption except - needs additional argument for it */
2575 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_net, &curproxy->except_mask)) {
2576 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2577 file, linenum, args[0], args[1], args[cur_arg]);
2578 err_code |= ERR_ALERT | ERR_FATAL;
2579 goto out;
2580 }
2581 /* flush useless bits */
2582 curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
2583 cur_arg += 2;
2584 } else if (!strcmp(args[cur_arg], "header")) {
2585 /* suboption header - needs additional argument for it */
2586 if (*(args[cur_arg+1]) == 0) {
2587 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2588 file, linenum, args[0], args[1], args[cur_arg]);
2589 err_code |= ERR_ALERT | ERR_FATAL;
2590 goto out;
2591 }
2592 free(curproxy->fwdfor_hdr_name);
2593 curproxy->fwdfor_hdr_name = strdup(args[cur_arg+1]);
2594 curproxy->fwdfor_hdr_len = strlen(curproxy->fwdfor_hdr_name);
2595 cur_arg += 2;
2596 } else if (!strcmp(args[cur_arg], "if-none")) {
2597 curproxy->options &= ~PR_O_FF_ALWAYS;
2598 cur_arg += 1;
2599 } else {
2600 /* unknown suboption - catchall */
2601 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except', 'header' and 'if-none'.\n",
2602 file, linenum, args[0], args[1]);
2603 err_code |= ERR_ALERT | ERR_FATAL;
2604 goto out;
2605 }
2606 } /* end while loop */
2607 }
2608 else if (!strcmp(args[1], "originalto")) {
2609 int cur_arg;
2610
2611 /* insert x-original-to field, but not for the IP address listed as an except.
2612 * set default options (ie: bitfield, header name, etc)
2613 */
2614
2615 curproxy->options |= PR_O_ORGTO;
2616
2617 free(curproxy->orgto_hdr_name);
2618 curproxy->orgto_hdr_name = strdup(DEF_XORIGINALTO_HDR);
2619 curproxy->orgto_hdr_len = strlen(DEF_XORIGINALTO_HDR);
2620
2621 /* loop to go through arguments - start at 2, since 0+1 = "option" "originalto" */
2622 cur_arg = 2;
2623 while (*(args[cur_arg])) {
2624 if (!strcmp(args[cur_arg], "except")) {
2625 /* suboption except - needs additional argument for it */
2626 if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_to, &curproxy->except_mask_to)) {
2627 ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
2628 file, linenum, args[0], args[1], args[cur_arg]);
2629 err_code |= ERR_ALERT | ERR_FATAL;
2630 goto out;
2631 }
2632 /* flush useless bits */
2633 curproxy->except_to.s_addr &= curproxy->except_mask_to.s_addr;
2634 cur_arg += 2;
2635 } else if (!strcmp(args[cur_arg], "header")) {
2636 /* suboption header - needs additional argument for it */
2637 if (*(args[cur_arg+1]) == 0) {
2638 ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
2639 file, linenum, args[0], args[1], args[cur_arg]);
2640 err_code |= ERR_ALERT | ERR_FATAL;
2641 goto out;
2642 }
2643 free(curproxy->orgto_hdr_name);
2644 curproxy->orgto_hdr_name = strdup(args[cur_arg+1]);
2645 curproxy->orgto_hdr_len = strlen(curproxy->orgto_hdr_name);
2646 cur_arg += 2;
2647 } else {
2648 /* unknown suboption - catchall */
2649 ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
2650 file, linenum, args[0], args[1]);
2651 err_code |= ERR_ALERT | ERR_FATAL;
2652 goto out;
2653 }
2654 } /* end while loop */
2655 }
2656 else {
2657 ha_alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
2658 err_code |= ERR_ALERT | ERR_FATAL;
2659 goto out;
2660 }
2661 goto out;
2662 }
2663 else if (!strcmp(args[0], "default_backend")) {
2664 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
2665 err_code |= ERR_WARN;
2666
2667 if (*(args[1]) == 0) {
2668 ha_alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
2669 err_code |= ERR_ALERT | ERR_FATAL;
2670 goto out;
2671 }
2672 free(curproxy->defbe.name);
2673 curproxy->defbe.name = strdup(args[1]);
2674
2675 if (alertif_too_many_args_idx(1, 0, file, linenum, args, &err_code))
2676 goto out;
2677 }
2678 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
Tim Duesterhusdac168b2019-05-14 20:57:58 +02002679 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 +01002680
Tim Duesterhusdac168b2019-05-14 20:57:58 +02002681 err_code |= ERR_ALERT | ERR_FATAL;
2682 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002683 }
2684 else if (!strcmp(args[0], "http-reuse")) {
2685 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2686 err_code |= ERR_WARN;
2687
2688 if (strcmp(args[1], "never") == 0) {
2689 /* enable a graceful server shutdown on an HTTP 404 response */
2690 curproxy->options &= ~PR_O_REUSE_MASK;
2691 curproxy->options |= PR_O_REUSE_NEVR;
2692 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2693 goto out;
2694 }
2695 else if (strcmp(args[1], "safe") == 0) {
2696 /* enable a graceful server shutdown on an HTTP 404 response */
2697 curproxy->options &= ~PR_O_REUSE_MASK;
2698 curproxy->options |= PR_O_REUSE_SAFE;
2699 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2700 goto out;
2701 }
2702 else if (strcmp(args[1], "aggressive") == 0) {
2703 curproxy->options &= ~PR_O_REUSE_MASK;
2704 curproxy->options |= PR_O_REUSE_AGGR;
2705 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2706 goto out;
2707 }
2708 else if (strcmp(args[1], "always") == 0) {
2709 /* enable a graceful server shutdown on an HTTP 404 response */
2710 curproxy->options &= ~PR_O_REUSE_MASK;
2711 curproxy->options |= PR_O_REUSE_ALWS;
2712 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2713 goto out;
2714 }
2715 else {
2716 ha_alert("parsing [%s:%d] : '%s' only supports 'never', 'safe', 'aggressive', 'always'.\n", file, linenum, args[0]);
2717 err_code |= ERR_ALERT | ERR_FATAL;
2718 goto out;
2719 }
2720 }
2721 else if (!strcmp(args[0], "http-check")) {
2722 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2723 err_code |= ERR_WARN;
2724
2725 if (strcmp(args[1], "disable-on-404") == 0) {
2726 /* enable a graceful server shutdown on an HTTP 404 response */
2727 curproxy->options |= PR_O_DISABLE404;
2728 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2729 goto out;
2730 }
2731 else if (strcmp(args[1], "send-state") == 0) {
2732 /* enable emission of the apparent state of a server in HTTP checks */
2733 curproxy->options2 |= PR_O2_CHK_SNDST;
2734 if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
2735 goto out;
2736 }
2737 else if (strcmp(args[1], "expect") == 0) {
2738 const char *ptr_arg;
2739 int cur_arg;
2740
2741 if (curproxy->options2 & PR_O2_EXP_TYPE) {
2742 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
2743 err_code |= ERR_ALERT | ERR_FATAL;
2744 goto out;
2745 }
2746
2747 cur_arg = 2;
2748 /* consider exclamation marks, sole or at the beginning of a word */
2749 while (*(ptr_arg = args[cur_arg])) {
2750 while (*ptr_arg == '!') {
2751 curproxy->options2 ^= PR_O2_EXP_INV;
2752 ptr_arg++;
2753 }
2754 if (*ptr_arg)
2755 break;
2756 cur_arg++;
2757 }
2758 /* now ptr_arg points to the beginning of a word past any possible
2759 * exclamation mark, and cur_arg is the argument which holds this word.
2760 */
2761 if (strcmp(ptr_arg, "status") == 0) {
2762 if (!*(args[cur_arg + 1])) {
2763 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
2764 file, linenum, args[0], args[1], ptr_arg);
2765 err_code |= ERR_ALERT | ERR_FATAL;
2766 goto out;
2767 }
2768 curproxy->options2 |= PR_O2_EXP_STS;
2769 free(curproxy->expect_str);
2770 curproxy->expect_str = strdup(args[cur_arg + 1]);
2771 }
2772 else if (strcmp(ptr_arg, "string") == 0) {
2773 if (!*(args[cur_arg + 1])) {
2774 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
2775 file, linenum, args[0], args[1], ptr_arg);
2776 err_code |= ERR_ALERT | ERR_FATAL;
2777 goto out;
2778 }
2779 curproxy->options2 |= PR_O2_EXP_STR;
2780 free(curproxy->expect_str);
2781 curproxy->expect_str = strdup(args[cur_arg + 1]);
2782 }
2783 else if (strcmp(ptr_arg, "rstatus") == 0) {
2784 if (!*(args[cur_arg + 1])) {
2785 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
2786 file, linenum, args[0], args[1], ptr_arg);
2787 err_code |= ERR_ALERT | ERR_FATAL;
2788 goto out;
2789 }
2790 curproxy->options2 |= PR_O2_EXP_RSTS;
2791 free(curproxy->expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +02002792 regex_free(curproxy->expect_regex);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002793 curproxy->expect_str = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002794 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02002795 if (!(curproxy->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
2796 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002797 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
2798 free(error);
2799 err_code |= ERR_ALERT | ERR_FATAL;
2800 goto out;
2801 }
2802 }
2803 else if (strcmp(ptr_arg, "rstring") == 0) {
2804 if (!*(args[cur_arg + 1])) {
2805 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
2806 file, linenum, args[0], args[1], ptr_arg);
2807 err_code |= ERR_ALERT | ERR_FATAL;
2808 goto out;
2809 }
2810 curproxy->options2 |= PR_O2_EXP_RSTR;
2811 free(curproxy->expect_str);
Dragan Dosen26743032019-04-30 15:54:36 +02002812 regex_free(curproxy->expect_regex);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002813 curproxy->expect_str = strdup(args[cur_arg + 1]);
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002814 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02002815 if (!(curproxy->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
2816 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01002817 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
2818 free(error);
2819 err_code |= ERR_ALERT | ERR_FATAL;
2820 goto out;
2821 }
2822 }
2823 else {
2824 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'status', 'string', 'rstatus', 'rstring', found '%s'.\n",
2825 file, linenum, args[0], args[1], ptr_arg);
2826 err_code |= ERR_ALERT | ERR_FATAL;
2827 goto out;
2828 }
2829 }
2830 else {
2831 ha_alert("parsing [%s:%d] : '%s' only supports 'disable-on-404', 'send-state', 'expect'.\n", file, linenum, args[0]);
2832 err_code |= ERR_ALERT | ERR_FATAL;
2833 goto out;
2834 }
2835 }
2836 else if (!strcmp(args[0], "tcp-check")) {
2837 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2838 err_code |= ERR_WARN;
2839
2840 if (strcmp(args[1], "comment") == 0) {
2841 int cur_arg;
2842 struct tcpcheck_rule *tcpcheck;
2843
2844 cur_arg = 1;
2845 tcpcheck = calloc(1, sizeof(*tcpcheck));
2846 tcpcheck->action = TCPCHK_ACT_COMMENT;
2847
2848 if (!*args[cur_arg + 1]) {
2849 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
2850 file, linenum, args[cur_arg]);
2851 err_code |= ERR_ALERT | ERR_FATAL;
2852 goto out;
2853 }
2854
2855 tcpcheck->comment = strdup(args[cur_arg + 1]);
2856
2857 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
2858 if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code))
2859 goto out;
2860 }
2861 else if (strcmp(args[1], "connect") == 0) {
2862 const char *ptr_arg;
2863 int cur_arg;
2864 struct tcpcheck_rule *tcpcheck;
2865
2866 /* check if first rule is also a 'connect' action */
2867 tcpcheck = LIST_NEXT(&curproxy->tcpcheck_rules, struct tcpcheck_rule *, list);
2868 while (&tcpcheck->list != &curproxy->tcpcheck_rules &&
2869 tcpcheck->action == TCPCHK_ACT_COMMENT) {
2870 tcpcheck = LIST_NEXT(&tcpcheck->list, struct tcpcheck_rule *, list);
2871 }
2872
2873 if (&tcpcheck->list != &curproxy->tcpcheck_rules
2874 && tcpcheck->action != TCPCHK_ACT_CONNECT) {
2875 ha_alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
2876 file, linenum);
2877 err_code |= ERR_ALERT | ERR_FATAL;
2878 goto out;
2879 }
2880
2881 cur_arg = 2;
2882 tcpcheck = calloc(1, sizeof(*tcpcheck));
2883 tcpcheck->action = TCPCHK_ACT_CONNECT;
2884
2885 /* parsing each parameters to fill up the rule */
2886 while (*(ptr_arg = args[cur_arg])) {
2887 /* tcp port */
2888 if (strcmp(args[cur_arg], "port") == 0) {
2889 if ( (atol(args[cur_arg + 1]) > 65535) ||
2890 (atol(args[cur_arg + 1]) < 1) ){
2891 ha_alert("parsing [%s:%d] : '%s %s %s' expects a valid TCP port (from range 1 to 65535), got %s.\n",
2892 file, linenum, args[0], args[1], "port", args[cur_arg + 1]);
2893 err_code |= ERR_ALERT | ERR_FATAL;
2894 goto out;
2895 }
2896 tcpcheck->port = atol(args[cur_arg + 1]);
2897 cur_arg += 2;
2898 }
2899 /* send proxy protocol */
2900 else if (strcmp(args[cur_arg], "send-proxy") == 0) {
2901 tcpcheck->conn_opts |= TCPCHK_OPT_SEND_PROXY;
2902 cur_arg++;
2903 }
2904#ifdef USE_OPENSSL
2905 else if (strcmp(args[cur_arg], "ssl") == 0) {
2906 curproxy->options |= PR_O_TCPCHK_SSL;
2907 tcpcheck->conn_opts |= TCPCHK_OPT_SSL;
2908 cur_arg++;
2909 }
2910#endif /* USE_OPENSSL */
2911 /* comment for this tcpcheck line */
2912 else if (strcmp(args[cur_arg], "comment") == 0) {
2913 if (!*args[cur_arg + 1]) {
2914 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
2915 file, linenum, args[cur_arg]);
2916 err_code |= ERR_ALERT | ERR_FATAL;
2917 goto out;
2918 }
2919 tcpcheck->comment = strdup(args[cur_arg + 1]);
2920 cur_arg += 2;
2921 }
2922 else {
2923#ifdef USE_OPENSSL
2924 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n",
2925#else /* USE_OPENSSL */
2926 ha_alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or but got '%s' as argument.\n",
2927#endif /* USE_OPENSSL */
2928 file, linenum, args[0], args[1], args[cur_arg]);
2929 err_code |= ERR_ALERT | ERR_FATAL;
2930 goto out;
2931 }
2932
2933 }
2934
2935 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
2936 }
2937 else if (strcmp(args[1], "send") == 0) {
2938 if (! *(args[2]) ) {
2939 /* SEND string expected */
2940 ha_alert("parsing [%s:%d] : '%s %s %s' expects <STRING> as argument.\n",
2941 file, linenum, args[0], args[1], args[2]);
2942 err_code |= ERR_ALERT | ERR_FATAL;
2943 goto out;
2944 } else {
2945 struct tcpcheck_rule *tcpcheck;
2946
2947 tcpcheck = calloc(1, sizeof(*tcpcheck));
2948
2949 tcpcheck->action = TCPCHK_ACT_SEND;
2950 tcpcheck->string_len = strlen(args[2]);
2951 tcpcheck->string = strdup(args[2]);
2952 tcpcheck->expect_regex = NULL;
2953
2954 /* comment for this tcpcheck line */
2955 if (strcmp(args[3], "comment") == 0) {
2956 if (!*args[4]) {
2957 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
2958 file, linenum, args[3]);
2959 err_code |= ERR_ALERT | ERR_FATAL;
2960 goto out;
2961 }
2962 tcpcheck->comment = strdup(args[4]);
2963 }
2964
2965 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
2966 }
2967 }
2968 else if (strcmp(args[1], "send-binary") == 0) {
2969 if (! *(args[2]) ) {
2970 /* SEND binary string expected */
2971 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument.\n",
2972 file, linenum, args[0], args[1], args[2]);
2973 err_code |= ERR_ALERT | ERR_FATAL;
2974 goto out;
2975 } else {
2976 struct tcpcheck_rule *tcpcheck;
2977 char *err = NULL;
2978
2979 tcpcheck = calloc(1, sizeof(*tcpcheck));
2980
2981 tcpcheck->action = TCPCHK_ACT_SEND;
2982 if (parse_binary(args[2], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
2983 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
2984 file, linenum, args[0], args[1], args[2], err);
2985 err_code |= ERR_ALERT | ERR_FATAL;
2986 goto out;
2987 }
2988 tcpcheck->expect_regex = NULL;
2989
2990 /* comment for this tcpcheck line */
2991 if (strcmp(args[3], "comment") == 0) {
2992 if (!*args[4]) {
2993 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
2994 file, linenum, args[3]);
2995 err_code |= ERR_ALERT | ERR_FATAL;
2996 goto out;
2997 }
2998 tcpcheck->comment = strdup(args[4]);
2999 }
3000
3001 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3002 }
3003 }
3004 else if (strcmp(args[1], "expect") == 0) {
3005 const char *ptr_arg;
3006 int cur_arg;
3007 int inverse = 0;
3008
3009 if (curproxy->options2 & PR_O2_EXP_TYPE) {
3010 ha_alert("parsing [%s:%d] : '%s %s' already specified.\n", file, linenum, args[0], args[1]);
3011 err_code |= ERR_ALERT | ERR_FATAL;
3012 goto out;
3013 }
3014
3015 cur_arg = 2;
3016 /* consider exclamation marks, sole or at the beginning of a word */
3017 while (*(ptr_arg = args[cur_arg])) {
3018 while (*ptr_arg == '!') {
3019 inverse = !inverse;
3020 ptr_arg++;
3021 }
3022 if (*ptr_arg)
3023 break;
3024 cur_arg++;
3025 }
3026 /* now ptr_arg points to the beginning of a word past any possible
3027 * exclamation mark, and cur_arg is the argument which holds this word.
3028 */
3029 if (strcmp(ptr_arg, "binary") == 0) {
3030 struct tcpcheck_rule *tcpcheck;
3031 char *err = NULL;
3032
3033 if (!*(args[cur_arg + 1])) {
3034 ha_alert("parsing [%s:%d] : '%s %s %s' expects <binary string> as an argument.\n",
3035 file, linenum, args[0], args[1], ptr_arg);
3036 err_code |= ERR_ALERT | ERR_FATAL;
3037 goto out;
3038 }
3039
3040 tcpcheck = calloc(1, sizeof(*tcpcheck));
3041
3042 tcpcheck->action = TCPCHK_ACT_EXPECT;
3043 if (parse_binary(args[cur_arg + 1], &tcpcheck->string, &tcpcheck->string_len, &err) == 0) {
3044 ha_alert("parsing [%s:%d] : '%s %s %s' expects <BINARY STRING> as argument, but %s\n",
3045 file, linenum, args[0], args[1], args[2], err);
3046 err_code |= ERR_ALERT | ERR_FATAL;
3047 goto out;
3048 }
3049 tcpcheck->expect_regex = NULL;
3050 tcpcheck->inverse = inverse;
3051
3052 /* tcpcheck comment */
3053 cur_arg += 2;
3054 if (strcmp(args[cur_arg], "comment") == 0) {
3055 if (!*args[cur_arg + 1]) {
3056 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3057 file, linenum, args[cur_arg + 1]);
3058 err_code |= ERR_ALERT | ERR_FATAL;
3059 goto out;
3060 }
3061 tcpcheck->comment = strdup(args[cur_arg + 1]);
3062 }
3063
3064 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3065 }
3066 else if (strcmp(ptr_arg, "string") == 0) {
3067 struct tcpcheck_rule *tcpcheck;
3068
3069 if (!*(args[cur_arg + 1])) {
3070 ha_alert("parsing [%s:%d] : '%s %s %s' expects <string> as an argument.\n",
3071 file, linenum, args[0], args[1], ptr_arg);
3072 err_code |= ERR_ALERT | ERR_FATAL;
3073 goto out;
3074 }
3075
3076 tcpcheck = calloc(1, sizeof(*tcpcheck));
3077
3078 tcpcheck->action = TCPCHK_ACT_EXPECT;
3079 tcpcheck->string_len = strlen(args[cur_arg + 1]);
3080 tcpcheck->string = strdup(args[cur_arg + 1]);
3081 tcpcheck->expect_regex = NULL;
3082 tcpcheck->inverse = inverse;
3083
3084 /* tcpcheck comment */
3085 cur_arg += 2;
3086 if (strcmp(args[cur_arg], "comment") == 0) {
3087 if (!*args[cur_arg + 1]) {
3088 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3089 file, linenum, args[cur_arg + 1]);
3090 err_code |= ERR_ALERT | ERR_FATAL;
3091 goto out;
3092 }
3093 tcpcheck->comment = strdup(args[cur_arg + 1]);
3094 }
3095
3096 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3097 }
3098 else if (strcmp(ptr_arg, "rstring") == 0) {
3099 struct tcpcheck_rule *tcpcheck;
3100
3101 if (!*(args[cur_arg + 1])) {
3102 ha_alert("parsing [%s:%d] : '%s %s %s' expects <regex> as an argument.\n",
3103 file, linenum, args[0], args[1], ptr_arg);
3104 err_code |= ERR_ALERT | ERR_FATAL;
3105 goto out;
3106 }
3107
3108 tcpcheck = calloc(1, sizeof(*tcpcheck));
3109
3110 tcpcheck->action = TCPCHK_ACT_EXPECT;
3111 tcpcheck->string_len = 0;
3112 tcpcheck->string = NULL;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003113 error = NULL;
Dragan Dosen26743032019-04-30 15:54:36 +02003114 if (!(tcpcheck->expect_regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) {
3115 ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n",
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003116 file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
3117 free(error);
3118 err_code |= ERR_ALERT | ERR_FATAL;
3119 goto out;
3120 }
3121 tcpcheck->inverse = inverse;
3122
3123 /* tcpcheck comment */
3124 cur_arg += 2;
3125 if (strcmp(args[cur_arg], "comment") == 0) {
3126 if (!*args[cur_arg + 1]) {
3127 ha_alert("parsing [%s:%d] : '%s' expects a comment string.\n",
3128 file, linenum, args[cur_arg + 1]);
3129 err_code |= ERR_ALERT | ERR_FATAL;
3130 goto out;
3131 }
3132 tcpcheck->comment = strdup(args[cur_arg + 1]);
3133 }
3134
3135 LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
3136 }
3137 else {
3138 ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'binary', 'string', 'rstring', found '%s'.\n",
3139 file, linenum, args[0], args[1], ptr_arg);
3140 err_code |= ERR_ALERT | ERR_FATAL;
3141 goto out;
3142 }
3143 }
3144 else {
3145 ha_alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
3146 err_code |= ERR_ALERT | ERR_FATAL;
3147 goto out;
3148 }
3149 }
3150 else if (!strcmp(args[0], "monitor")) {
3151 if (curproxy == &defproxy) {
3152 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3153 err_code |= ERR_ALERT | ERR_FATAL;
3154 goto out;
3155 }
3156
3157 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3158 err_code |= ERR_WARN;
3159
3160 if (strcmp(args[1], "fail") == 0) {
3161 /* add a condition to fail monitor requests */
3162 if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
3163 ha_alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
3164 file, linenum, args[0], args[1]);
3165 err_code |= ERR_ALERT | ERR_FATAL;
3166 goto out;
3167 }
3168
3169 err_code |= warnif_misplaced_monitor(curproxy, file, linenum, "monitor fail");
3170 if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
3171 ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
3172 file, linenum, args[0], args[1], errmsg);
3173 err_code |= ERR_ALERT | ERR_FATAL;
3174 goto out;
3175 }
3176 LIST_ADDQ(&curproxy->mon_fail_cond, &cond->list);
3177 }
3178 else {
3179 ha_alert("parsing [%s:%d] : '%s' only supports 'fail'.\n", file, linenum, args[0]);
3180 err_code |= ERR_ALERT | ERR_FATAL;
3181 goto out;
3182 }
3183 }
Willy Tarreaue5733232019-05-22 19:24:06 +02003184#ifdef USE_TPROXY
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003185 else if (!strcmp(args[0], "transparent")) {
3186 /* enable transparent proxy connections */
3187 curproxy->options |= PR_O_TRANSP;
3188 if (alertif_too_many_args(0, file, linenum, args, &err_code))
3189 goto out;
3190 }
3191#endif
3192 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3193 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
3194 err_code |= ERR_WARN;
3195
3196 if (*(args[1]) == 0) {
3197 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3198 err_code |= ERR_ALERT | ERR_FATAL;
3199 goto out;
3200 }
3201 curproxy->maxconn = atol(args[1]);
3202 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3203 goto out;
3204 }
3205 else if (!strcmp(args[0], "backlog")) { /* backlog */
3206 if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
3207 err_code |= ERR_WARN;
3208
3209 if (*(args[1]) == 0) {
3210 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3211 err_code |= ERR_ALERT | ERR_FATAL;
3212 goto out;
3213 }
3214 curproxy->backlog = atol(args[1]);
3215 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3216 goto out;
3217 }
3218 else if (!strcmp(args[0], "fullconn")) { /* fullconn */
3219 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
3220 err_code |= ERR_WARN;
3221
3222 if (*(args[1]) == 0) {
3223 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3224 err_code |= ERR_ALERT | ERR_FATAL;
3225 goto out;
3226 }
3227 curproxy->fullconn = atol(args[1]);
3228 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3229 goto out;
3230 }
3231 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3232 if (*(args[1]) == 0) {
3233 ha_alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
3234 err_code |= ERR_ALERT | ERR_FATAL;
3235 goto out;
3236 }
3237 err = parse_time_err(args[1], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +02003238 if (err == PARSE_TIME_OVER) {
3239 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to grace time, maximum value is 2147483647 ms (~24.8 days).\n",
3240 file, linenum, args[1]);
3241 err_code |= ERR_ALERT | ERR_FATAL;
3242 goto out;
3243 }
3244 else if (err == PARSE_TIME_UNDER) {
3245 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to grace time, minimum non-null value is 1 ms.\n",
3246 file, linenum, args[1]);
3247 err_code |= ERR_ALERT | ERR_FATAL;
3248 goto out;
3249 }
3250 else if (err) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003251 ha_alert("parsing [%s:%d] : unexpected character '%c' in grace time.\n",
3252 file, linenum, *err);
3253 err_code |= ERR_ALERT | ERR_FATAL;
3254 goto out;
3255 }
3256 curproxy->grace = val;
3257 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3258 goto out;
3259 }
3260 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3261 struct sockaddr_storage *sk;
3262 int port1, port2;
3263 struct protocol *proto;
3264
3265 if (curproxy == &defproxy) {
3266 ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3267 err_code |= ERR_ALERT | ERR_FATAL;
3268 goto out;
3269 }
3270 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3271 err_code |= ERR_WARN;
3272
3273 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3274 if (!sk) {
3275 ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
3276 err_code |= ERR_ALERT | ERR_FATAL;
3277 goto out;
3278 }
3279
3280 proto = protocol_by_family(sk->ss_family);
3281 if (!proto || !proto->connect) {
3282 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3283 file, linenum, args[0], args[1]);
3284 err_code |= ERR_ALERT | ERR_FATAL;
3285 goto out;
3286 }
3287
3288 if (port1 != port2) {
3289 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'.\n",
3290 file, linenum, args[0], args[1]);
3291 err_code |= ERR_ALERT | ERR_FATAL;
3292 goto out;
3293 }
3294
3295 if (!port1) {
3296 ha_alert("parsing [%s:%d] : '%s' : missing port number in '%s', <addr:port> expected.\n",
3297 file, linenum, args[0], args[1]);
3298 err_code |= ERR_ALERT | ERR_FATAL;
3299 goto out;
3300 }
3301
3302 if (alertif_too_many_args(1, file, linenum, args, &err_code))
3303 goto out;
3304
3305 curproxy->dispatch_addr = *sk;
3306 curproxy->options |= PR_O_DISPATCH;
3307 }
3308 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
3309 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3310 err_code |= ERR_WARN;
3311
3312 if (backend_parse_balance((const char **)args + 1, &errmsg, curproxy) < 0) {
3313 ha_alert("parsing [%s:%d] : %s %s\n", file, linenum, args[0], errmsg);
3314 err_code |= ERR_ALERT | ERR_FATAL;
3315 goto out;
3316 }
3317 }
3318 else if (!strcmp(args[0], "hash-type")) { /* set hashing method */
3319 /**
3320 * The syntax for hash-type config element is
3321 * hash-type {map-based|consistent} [[<algo>] avalanche]
3322 *
3323 * The default hash function is sdbm for map-based and sdbm+avalanche for consistent.
3324 */
3325 curproxy->lbprm.algo &= ~(BE_LB_HASH_TYPE | BE_LB_HASH_FUNC | BE_LB_HASH_MOD);
3326
3327 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3328 err_code |= ERR_WARN;
3329
3330 if (strcmp(args[1], "consistent") == 0) { /* use consistent hashing */
3331 curproxy->lbprm.algo |= BE_LB_HASH_CONS;
3332 }
3333 else if (strcmp(args[1], "map-based") == 0) { /* use map-based hashing */
3334 curproxy->lbprm.algo |= BE_LB_HASH_MAP;
3335 }
3336 else if (strcmp(args[1], "avalanche") == 0) {
3337 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]);
3338 err_code |= ERR_ALERT | ERR_FATAL;
3339 goto out;
3340 }
3341 else {
3342 ha_alert("parsing [%s:%d] : '%s' only supports 'consistent' and 'map-based'.\n", file, linenum, args[0]);
3343 err_code |= ERR_ALERT | ERR_FATAL;
3344 goto out;
3345 }
3346
3347 /* set the hash function to use */
3348 if (!*args[2]) {
3349 /* the default algo is sdbm */
3350 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3351
3352 /* if consistent with no argument, then avalanche modifier is also applied */
3353 if ((curproxy->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS)
3354 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3355 } else {
3356 /* set the hash function */
3357 if (!strcmp(args[2], "sdbm")) {
3358 curproxy->lbprm.algo |= BE_LB_HFCN_SDBM;
3359 }
3360 else if (!strcmp(args[2], "djb2")) {
3361 curproxy->lbprm.algo |= BE_LB_HFCN_DJB2;
3362 }
3363 else if (!strcmp(args[2], "wt6")) {
3364 curproxy->lbprm.algo |= BE_LB_HFCN_WT6;
3365 }
3366 else if (!strcmp(args[2], "crc32")) {
3367 curproxy->lbprm.algo |= BE_LB_HFCN_CRC32;
3368 }
3369 else {
3370 ha_alert("parsing [%s:%d] : '%s' only supports 'sdbm', 'djb2', 'crc32', or 'wt6' hash functions.\n", file, linenum, args[0]);
3371 err_code |= ERR_ALERT | ERR_FATAL;
3372 goto out;
3373 }
3374
3375 /* set the hash modifier */
3376 if (!strcmp(args[3], "avalanche")) {
3377 curproxy->lbprm.algo |= BE_LB_HMOD_AVAL;
3378 }
3379 else if (*args[3]) {
3380 ha_alert("parsing [%s:%d] : '%s' only supports 'avalanche' as a modifier for hash functions.\n", file, linenum, args[0]);
3381 err_code |= ERR_ALERT | ERR_FATAL;
3382 goto out;
3383 }
3384 }
3385 }
3386 else if (strcmp(args[0], "hash-balance-factor") == 0) {
3387 if (*(args[1]) == 0) {
3388 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
3389 err_code |= ERR_ALERT | ERR_FATAL;
3390 goto out;
3391 }
Willy Tarreau76e84f52019-01-14 16:50:58 +01003392 curproxy->lbprm.hash_balance_factor = atol(args[1]);
3393 if (curproxy->lbprm.hash_balance_factor != 0 && curproxy->lbprm.hash_balance_factor <= 100) {
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003394 ha_alert("parsing [%s:%d] : '%s' must be 0 or greater than 100.\n", file, linenum, args[0]);
3395 err_code |= ERR_ALERT | ERR_FATAL;
3396 goto out;
3397 }
3398 }
3399 else if (strcmp(args[0], "unique-id-format") == 0) {
3400 if (!*(args[1])) {
3401 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3402 err_code |= ERR_ALERT | ERR_FATAL;
3403 goto out;
3404 }
3405 if (*(args[2])) {
3406 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3407 err_code |= ERR_ALERT | ERR_FATAL;
3408 goto out;
3409 }
3410 free(curproxy->conf.uniqueid_format_string);
3411 curproxy->conf.uniqueid_format_string = strdup(args[1]);
3412
3413 free(curproxy->conf.uif_file);
3414 curproxy->conf.uif_file = strdup(curproxy->conf.args.file);
3415 curproxy->conf.uif_line = curproxy->conf.args.line;
3416 }
3417
3418 else if (strcmp(args[0], "unique-id-header") == 0) {
3419 if (!*(args[1])) {
3420 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3421 err_code |= ERR_ALERT | ERR_FATAL;
3422 goto out;
3423 }
3424 free(curproxy->header_unique_id);
3425 curproxy->header_unique_id = strdup(args[1]);
3426 }
3427
3428 else if (strcmp(args[0], "log-format") == 0) {
3429 if (!*(args[1])) {
3430 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3431 err_code |= ERR_ALERT | ERR_FATAL;
3432 goto out;
3433 }
3434 if (*(args[2])) {
3435 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3436 err_code |= ERR_ALERT | ERR_FATAL;
3437 goto out;
3438 }
3439 if (curproxy->conf.logformat_string && curproxy == &defproxy) {
3440 char *oldlogformat = "log-format";
3441
3442 if (curproxy->conf.logformat_string == default_http_log_format)
3443 oldlogformat = "option httplog";
3444 else if (curproxy->conf.logformat_string == default_tcp_log_format)
3445 oldlogformat = "option tcplog";
3446 else if (curproxy->conf.logformat_string == clf_http_log_format)
3447 oldlogformat = "option httplog clf";
3448 ha_warning("parsing [%s:%d]: 'log-format' overrides previous '%s' in 'defaults' section.\n",
3449 file, linenum, oldlogformat);
3450 }
3451 if (curproxy->conf.logformat_string != default_http_log_format &&
3452 curproxy->conf.logformat_string != default_tcp_log_format &&
3453 curproxy->conf.logformat_string != clf_http_log_format)
3454 free(curproxy->conf.logformat_string);
3455 curproxy->conf.logformat_string = strdup(args[1]);
3456
3457 free(curproxy->conf.lfs_file);
3458 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
3459 curproxy->conf.lfs_line = curproxy->conf.args.line;
3460
3461 /* get a chance to improve log-format error reporting by
3462 * reporting the correct line-number when possible.
3463 */
3464 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3465 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format' directive is ignored in backends.\n",
3466 file, linenum, curproxy->id);
3467 err_code |= ERR_WARN;
3468 }
3469 }
3470 else if (!strcmp(args[0], "log-format-sd")) {
3471 if (!*(args[1])) {
3472 ha_alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
3473 err_code |= ERR_ALERT | ERR_FATAL;
3474 goto out;
3475 }
3476 if (*(args[2])) {
3477 ha_alert("parsing [%s:%d] : %s expects only one argument, don't forget to escape spaces!\n", file, linenum, args[0]);
3478 err_code |= ERR_ALERT | ERR_FATAL;
3479 goto out;
3480 }
3481
3482 if (curproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
3483 free(curproxy->conf.logformat_sd_string);
3484 curproxy->conf.logformat_sd_string = strdup(args[1]);
3485
3486 free(curproxy->conf.lfsd_file);
3487 curproxy->conf.lfsd_file = strdup(curproxy->conf.args.file);
3488 curproxy->conf.lfsd_line = curproxy->conf.args.line;
3489
3490 /* get a chance to improve log-format-sd error reporting by
3491 * reporting the correct line-number when possible.
3492 */
3493 if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
3494 ha_warning("parsing [%s:%d] : backend '%s' : 'log-format-sd' directive is ignored in backends.\n",
3495 file, linenum, curproxy->id);
3496 err_code |= ERR_WARN;
3497 }
3498 }
3499 else if (!strcmp(args[0], "log-tag")) { /* tag to report to syslog */
3500 if (*(args[1]) == 0) {
3501 ha_alert("parsing [%s:%d] : '%s' expects a tag for use in syslog.\n", file, linenum, args[0]);
3502 err_code |= ERR_ALERT | ERR_FATAL;
3503 goto out;
3504 }
3505 chunk_destroy(&curproxy->log_tag);
3506 chunk_initstr(&curproxy->log_tag, strdup(args[1]));
3507 }
3508 else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
3509 if (!parse_logsrv(args, &curproxy->logsrvs, (kwm == KWM_NO), &errmsg)) {
3510 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
3511 err_code |= ERR_ALERT | ERR_FATAL;
3512 goto out;
3513 }
3514 }
3515 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
3516 int cur_arg;
3517 int port1, port2;
3518 struct sockaddr_storage *sk;
3519 struct protocol *proto;
3520
3521 if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
3522 err_code |= ERR_WARN;
3523
3524 if (!*args[1]) {
3525 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optionally '%s' <addr>, and '%s' <name>.\n",
3526 file, linenum, "source", "usesrc", "interface");
3527 err_code |= ERR_ALERT | ERR_FATAL;
3528 goto out;
3529 }
3530
Christopher Faulet31930372019-07-15 10:16:58 +02003531 /* we must first clear any optional default setting */
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003532 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3533 free(curproxy->conn_src.iface_name);
3534 curproxy->conn_src.iface_name = NULL;
3535 curproxy->conn_src.iface_len = 0;
3536
3537 sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3538 if (!sk) {
3539 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3540 file, linenum, args[0], args[1], errmsg);
3541 err_code |= ERR_ALERT | ERR_FATAL;
3542 goto out;
3543 }
3544
3545 proto = protocol_by_family(sk->ss_family);
3546 if (!proto || !proto->connect) {
3547 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3548 file, linenum, args[0], args[1]);
3549 err_code |= ERR_ALERT | ERR_FATAL;
3550 goto out;
3551 }
3552
3553 if (port1 != port2) {
3554 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3555 file, linenum, args[0], args[1]);
3556 err_code |= ERR_ALERT | ERR_FATAL;
3557 goto out;
3558 }
3559
3560 curproxy->conn_src.source_addr = *sk;
3561 curproxy->conn_src.opts |= CO_SRC_BIND;
3562
3563 cur_arg = 2;
3564 while (*(args[cur_arg])) {
3565 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
3566#if defined(CONFIG_HAP_TRANSPARENT)
3567 if (!*args[cur_arg + 1]) {
3568 ha_alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
3569 file, linenum, "usesrc");
3570 err_code |= ERR_ALERT | ERR_FATAL;
3571 goto out;
3572 }
3573
3574 if (!strcmp(args[cur_arg + 1], "client")) {
3575 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3576 curproxy->conn_src.opts |= CO_SRC_TPROXY_CLI;
3577 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
3578 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3579 curproxy->conn_src.opts |= CO_SRC_TPROXY_CIP;
3580 } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
3581 char *name, *end;
3582
3583 name = args[cur_arg+1] + 7;
3584 while (isspace(*name))
3585 name++;
3586
3587 end = name;
3588 while (*end && !isspace(*end) && *end != ',' && *end != ')')
3589 end++;
3590
3591 curproxy->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
3592 curproxy->conn_src.opts |= CO_SRC_TPROXY_DYN;
3593 curproxy->conn_src.bind_hdr_name = calloc(1, end - name + 1);
3594 curproxy->conn_src.bind_hdr_len = end - name;
3595 memcpy(curproxy->conn_src.bind_hdr_name, name, end - name);
3596 curproxy->conn_src.bind_hdr_name[end-name] = '\0';
3597 curproxy->conn_src.bind_hdr_occ = -1;
3598
3599 /* now look for an occurrence number */
3600 while (isspace(*end))
3601 end++;
3602 if (*end == ',') {
3603 end++;
3604 name = end;
3605 if (*end == '-')
3606 end++;
3607 while (isdigit((int)*end))
3608 end++;
3609 curproxy->conn_src.bind_hdr_occ = strl2ic(name, end-name);
3610 }
3611
3612 if (curproxy->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
3613 ha_alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
3614 " occurrences values smaller than %d.\n",
3615 file, linenum, MAX_HDR_HISTORY);
3616 err_code |= ERR_ALERT | ERR_FATAL;
3617 goto out;
3618 }
3619 } else {
3620 struct sockaddr_storage *sk;
3621
3622 sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
3623 if (!sk) {
3624 ha_alert("parsing [%s:%d] : '%s %s' : %s\n",
3625 file, linenum, args[cur_arg], args[cur_arg+1], errmsg);
3626 err_code |= ERR_ALERT | ERR_FATAL;
3627 goto out;
3628 }
3629
3630 proto = protocol_by_family(sk->ss_family);
3631 if (!proto || !proto->connect) {
3632 ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
3633 file, linenum, args[cur_arg], args[cur_arg+1]);
3634 err_code |= ERR_ALERT | ERR_FATAL;
3635 goto out;
3636 }
3637
3638 if (port1 != port2) {
3639 ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
3640 file, linenum, args[cur_arg], args[cur_arg + 1]);
3641 err_code |= ERR_ALERT | ERR_FATAL;
3642 goto out;
3643 }
3644 curproxy->conn_src.tproxy_addr = *sk;
3645 curproxy->conn_src.opts |= CO_SRC_TPROXY_ADDR;
3646 }
3647 global.last_checks |= LSTCHK_NETADM;
3648#else /* no TPROXY support */
3649 ha_alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
3650 file, linenum, "usesrc");
3651 err_code |= ERR_ALERT | ERR_FATAL;
3652 goto out;
3653#endif
3654 cur_arg += 2;
3655 continue;
3656 }
3657
3658 if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
3659#ifdef SO_BINDTODEVICE
3660 if (!*args[cur_arg + 1]) {
3661 ha_alert("parsing [%s:%d] : '%s' : missing interface name.\n",
3662 file, linenum, args[0]);
3663 err_code |= ERR_ALERT | ERR_FATAL;
3664 goto out;
3665 }
3666 free(curproxy->conn_src.iface_name);
3667 curproxy->conn_src.iface_name = strdup(args[cur_arg + 1]);
3668 curproxy->conn_src.iface_len = strlen(curproxy->conn_src.iface_name);
3669 global.last_checks |= LSTCHK_NETADM;
3670#else
3671 ha_alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
3672 file, linenum, args[0], args[cur_arg]);
3673 err_code |= ERR_ALERT | ERR_FATAL;
3674 goto out;
3675#endif
3676 cur_arg += 2;
3677 continue;
3678 }
3679 ha_alert("parsing [%s:%d] : '%s' only supports optional keywords '%s' and '%s'.\n",
3680 file, linenum, args[0], "interface", "usesrc");
3681 err_code |= ERR_ALERT | ERR_FATAL;
3682 goto out;
3683 }
3684 }
3685 else if (!strcmp(args[0], "usesrc")) { /* address to use outside: needs "source" first */
3686 ha_alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
3687 file, linenum, "usesrc", "source");
3688 err_code |= ERR_ALERT | ERR_FATAL;
3689 goto out;
3690 }
3691 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003692 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
Willy Tarreau262c3f12019-12-17 06:52:51 +01003693 "Use 'http-request replace-path', 'http-request replace-uri' or 'http-request replace-header' instead.\n",
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003694 file, linenum, args[0]);
3695 err_code |= ERR_ALERT | ERR_FATAL;
3696 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003697 }
3698 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003699 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3700 "Use 'http-request del-header' instead.\n", file, linenum, args[0]);
3701 err_code |= ERR_ALERT | ERR_FATAL;
3702 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003703 }
3704 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003705 ha_alert("parsing [%s:%d] : The '%s' not supported anymore since HAProxy 2.1. "
3706 "Use 'http-request deny' instead.\n", file, linenum, args[0]);
3707 err_code |= ERR_ALERT | ERR_FATAL;
3708 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003709 }
3710 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003711 ha_alert("parsing [%s:%d] : The '%s' not supported anymore since HAProxy 2.1.\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], "reqallow")) { /* allow a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003716 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3717 "Use 'http-request allow' instead.\n", file, linenum, args[0]);
3718 err_code |= ERR_ALERT | ERR_FATAL;
3719 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003720 }
3721 else if (!strcmp(args[0], "reqtarpit")) { /* tarpit a request if a header matches this regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003722 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3723 "Use 'http-request tarpit' instead.\n", file, linenum, args[0]);
3724 err_code |= ERR_ALERT | ERR_FATAL;
3725 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003726 }
3727 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003728 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3729 "Use 'http-request replace-header' instead.\n", file, linenum, args[0]);
3730 err_code |= ERR_ALERT | ERR_FATAL;
3731 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003732 }
3733 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003734 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3735 "Use 'http-request del-header' instead.\n", file, linenum, args[0]);
3736 err_code |= ERR_ALERT | ERR_FATAL;
3737 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003738 }
3739 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003740 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3741 "Use 'http-request deny' instead.\n", file, linenum, args[0]);
3742 err_code |= ERR_ALERT | ERR_FATAL;
3743 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003744 }
3745 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003746 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1.\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], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003751 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3752 "Use 'http-request allow' instead.\n", file, linenum, args[0]);
3753 err_code |= ERR_ALERT | ERR_FATAL;
3754 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003755 }
3756 else if (!strcmp(args[0], "reqitarpit")) { /* tarpit a request if a header matches this regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003757 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3758 "Use 'http-request tarpit' instead.\n", file, linenum, args[0]);
3759 err_code |= ERR_ALERT | ERR_FATAL;
3760 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003761 }
3762 else if (!strcmp(args[0], "reqadd")) { /* add request header */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003763 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3764 "Use 'http-request add-header' instead.\n", file, linenum, args[0]);
3765 err_code |= ERR_ALERT | ERR_FATAL;
3766 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003767 }
3768 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003769 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3770 "Use 'http-response replace-header' instead.\n", file, linenum, args[0]);
3771 err_code |= ERR_ALERT | ERR_FATAL;
3772 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003773 }
3774 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003775 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3776 "Use 'http-response del-header' .\n", file, linenum, args[0]);
3777 err_code |= ERR_ALERT | ERR_FATAL;
3778 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003779 }
3780 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003781 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3782 "Use 'http-response deny' instead.\n", file, linenum, args[0]);
3783 err_code |= ERR_ALERT | ERR_FATAL;
3784 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003785 }
3786 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003787 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore sionce HAProxy 2.1. "
3788 "Use 'http-response replace-header' instead.\n", file, linenum, args[0]);
3789 err_code |= ERR_ALERT | ERR_FATAL;
3790 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003791 }
3792 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003793 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3794 "Use 'http-response del-header' instead.\n", file, linenum, args[0]);
3795 err_code |= ERR_ALERT | ERR_FATAL;
3796 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003797 }
3798 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003799 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3800 "Use 'http-response deny' instead.\n", file, linenum, args[0]);
3801 err_code |= ERR_ALERT | ERR_FATAL;
3802 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003803 }
3804 else if (!strcmp(args[0], "rspadd")) { /* add response header */
Christopher Fauleta6a56e62019-07-17 15:13:28 +02003805 ha_alert("parsing [%s:%d] : The '%s' directive is not supported anymore since HAProxy 2.1. "
3806 "Use 'http-response add-header' instead.\n", file, linenum, args[0]);
3807 err_code |= ERR_ALERT | ERR_FATAL;
3808 goto out;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003809 }
3810 else if (!strcmp(args[0], "errorloc") ||
3811 !strcmp(args[0], "errorloc302") ||
3812 !strcmp(args[0], "errorloc303")) { /* error location */
3813 int errnum, errlen;
3814 char *err;
3815
3816 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
3817 err_code |= ERR_WARN;
3818
3819 if (*(args[2]) == 0) {
3820 ha_alert("parsing [%s:%d] : <%s> expects <status_code> and <url> as arguments.\n", file, linenum, args[0]);
3821 err_code |= ERR_ALERT | ERR_FATAL;
3822 goto out;
3823 }
3824
3825 errnum = atol(args[1]);
3826 if (!strcmp(args[0], "errorloc303")) {
3827 errlen = strlen(HTTP_303) + strlen(args[2]) + 5;
3828 err = malloc(errlen);
3829 errlen = snprintf(err, errlen, "%s%s\r\n\r\n", HTTP_303, args[2]);
3830 } else {
3831 errlen = strlen(HTTP_302) + strlen(args[2]) + 5;
3832 err = malloc(errlen);
3833 errlen = snprintf(err, errlen, "%s%s\r\n\r\n", HTTP_302, args[2]);
3834 }
3835
3836 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
3837 if (http_err_codes[rc] == errnum) {
Christopher Fauletf7346382019-07-17 22:02:08 +02003838 struct buffer chk;
3839
3840 if (!http_str_to_htx(&chk, ist2(err, errlen))) {
3841 ha_alert("parsing [%s:%d] : unable to convert message in HTX for HTTP return code %d.\n",
3842 file, linenum, http_err_codes[rc]);
3843 err_code |= ERR_ALERT | ERR_FATAL;
3844 free(err);
3845 goto out;
3846 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003847 chunk_destroy(&curproxy->errmsg[rc]);
Christopher Fauletf7346382019-07-17 22:02:08 +02003848 curproxy->errmsg[rc] = chk;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003849 break;
3850 }
3851 }
3852
3853 if (rc >= HTTP_ERR_SIZE) {
3854 ha_warning("parsing [%s:%d] : status code %d not handled by '%s', error relocation will be ignored.\n",
3855 file, linenum, errnum, args[0]);
3856 free(err);
3857 }
3858 }
3859 else if (!strcmp(args[0], "errorfile")) { /* error message from a file */
3860 int errnum, errlen, fd;
3861 char *err;
3862 struct stat stat;
3863
3864 if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
3865 err_code |= ERR_WARN;
3866
3867 if (*(args[2]) == 0) {
3868 ha_alert("parsing [%s:%d] : <%s> expects <status_code> and <file> as arguments.\n", file, linenum, args[0]);
3869 err_code |= ERR_ALERT | ERR_FATAL;
3870 goto out;
3871 }
3872
3873 fd = open(args[2], O_RDONLY);
3874 if ((fd < 0) || (fstat(fd, &stat) < 0)) {
3875 ha_alert("parsing [%s:%d] : error opening file <%s> for custom error message <%s>.\n",
3876 file, linenum, args[2], args[1]);
3877 if (fd >= 0)
3878 close(fd);
3879 err_code |= ERR_ALERT | ERR_FATAL;
3880 goto out;
3881 }
3882
3883 if (stat.st_size <= global.tune.bufsize) {
3884 errlen = stat.st_size;
3885 } else {
3886 ha_warning("parsing [%s:%d] : custom error message file <%s> larger than %d bytes. Truncating.\n",
3887 file, linenum, args[2], global.tune.bufsize);
3888 err_code |= ERR_WARN;
3889 errlen = global.tune.bufsize;
3890 }
3891
3892 err = malloc(errlen); /* malloc() must succeed during parsing */
3893 errnum = read(fd, err, errlen);
3894 if (errnum != errlen) {
3895 ha_alert("parsing [%s:%d] : error reading file <%s> for custom error message <%s>.\n",
3896 file, linenum, args[2], args[1]);
3897 close(fd);
3898 free(err);
3899 err_code |= ERR_ALERT | ERR_FATAL;
3900 goto out;
3901 }
3902 close(fd);
3903
3904 errnum = atol(args[1]);
3905 for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
3906 if (http_err_codes[rc] == errnum) {
Christopher Fauletf7346382019-07-17 22:02:08 +02003907 struct buffer chk;
3908
3909 if (!http_str_to_htx(&chk, ist2(err, errlen))) {
3910 ha_alert("parsing [%s:%d] : unable to convert message in HTX for HTTP return code %d.\n",
3911 file, linenum, http_err_codes[rc]);
3912 err_code |= ERR_ALERT | ERR_FATAL;
3913 free(err);
3914 goto out;
3915 }
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003916 chunk_destroy(&curproxy->errmsg[rc]);
Christopher Fauletf7346382019-07-17 22:02:08 +02003917 curproxy->errmsg[rc] = chk;
Willy Tarreau3a1f5fd2018-11-11 15:40:36 +01003918 break;
3919 }
3920 }
3921
3922 if (rc >= HTTP_ERR_SIZE) {
3923 ha_warning("parsing [%s:%d] : status code %d not handled by '%s', error customization will be ignored.\n",
3924 file, linenum, errnum, args[0]);
3925 err_code |= ERR_WARN;
3926 free(err);
3927 }
3928 }
3929 else {
3930 struct cfg_kw_list *kwl;
3931 int index;
3932
3933 list_for_each_entry(kwl, &cfg_keywords.list, list) {
3934 for (index = 0; kwl->kw[index].kw != NULL; index++) {
3935 if (kwl->kw[index].section != CFG_LISTEN)
3936 continue;
3937 if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
3938 /* prepare error message just in case */
3939 rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, file, linenum, &errmsg);
3940 if (rc < 0) {
3941 ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
3942 err_code |= ERR_ALERT | ERR_FATAL;
3943 goto out;
3944 }
3945 else if (rc > 0) {
3946 ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
3947 err_code |= ERR_WARN;
3948 goto out;
3949 }
3950 goto out;
3951 }
3952 }
3953 }
3954
3955 ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
3956 err_code |= ERR_ALERT | ERR_FATAL;
3957 goto out;
3958 }
3959 out:
3960 free(errmsg);
3961 return err_code;
3962}