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