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