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