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