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