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