~ubuntu-branches/ubuntu/trusty/haproxy/trusty-updates

« back to all changes in this revision

Viewing changes to src/cfgparse.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Cornet
  • Date: 2010-04-15 20:00:34 UTC
  • mfrom: (1.2.6 upstream)
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: james.westby@ubuntu.com-20100415200034-mtlky4sy39tk0dfi
Tags: upstream-1.4.4
ImportĀ upstreamĀ versionĀ 1.4.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * Configuration parser
3
3
 *
4
 
 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
 
4
 * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
5
5
 *
6
6
 * This program is free software; you can redistribute it and/or
7
7
 * modify it under the terms of the GNU General Public License
23
23
#include <fcntl.h>
24
24
#include <unistd.h>
25
25
 
 
26
#include <netinet/tcp.h>
 
27
 
26
28
#include <common/cfgparse.h>
27
29
#include <common/config.h>
28
30
#include <common/errors.h>
35
37
#include <types/global.h>
36
38
 
37
39
#include <proto/acl.h>
 
40
#include <proto/auth.h>
38
41
#include <proto/backend.h>
39
42
#include <proto/buffers.h>
40
43
#include <proto/checks.h>
41
44
#include <proto/dumpstats.h>
42
45
#include <proto/httperr.h>
 
46
#include <proto/lb_chash.h>
 
47
#include <proto/lb_fwlc.h>
 
48
#include <proto/lb_fwrr.h>
 
49
#include <proto/lb_map.h>
43
50
#include <proto/log.h>
 
51
#include <proto/pattern.h>
44
52
#include <proto/port_range.h>
45
53
#include <proto/protocols.h>
46
54
#include <proto/proto_tcp.h>
49
57
#include <proto/server.h>
50
58
#include <proto/session.h>
51
59
#include <proto/task.h>
 
60
#include <proto/stick_table.h>
52
61
 
53
62
 
54
63
/* This is the SSLv3 CLIENT HELLO packet used in conjunction with the
81
90
        "\x00"                /* Compression Type    : 0x00 = NULL compression   */
82
91
};
83
92
 
 
93
/* various keyword modifiers */
 
94
enum kw_mod {
 
95
        KWM_STD = 0,  /* normal */
 
96
        KWM_NO,       /* "no" prefixed before the keyword */
 
97
        KWM_DEF,      /* "default" prefixed before the keyword */
 
98
};
 
99
 
84
100
/* some of the most common options which are also the easiest to handle */
85
101
struct cfg_opt {
86
102
        const char *name;
87
103
        unsigned int val;
88
104
        unsigned int cap;
89
105
        unsigned int checks;
 
106
        unsigned int mode;
90
107
};
91
108
 
92
109
/* proxy->options */
93
110
static const struct cfg_opt cfg_opts[] =
94
111
{
95
 
        { "abortonclose", PR_O_ABRT_CLOSE, PR_CAP_BE, 0 },
96
 
        { "allbackups",   PR_O_USE_ALL_BK, PR_CAP_BE, 0 },
97
 
        { "checkcache",   PR_O_CHK_CACHE,  PR_CAP_BE, 0 },
98
 
        { "clitcpka",     PR_O_TCP_CLI_KA, PR_CAP_FE, 0 },
99
 
        { "contstats",    PR_O_CONTSTATS,  PR_CAP_FE, 0 },
100
 
        { "dontlognull",  PR_O_NULLNOLOG,  PR_CAP_FE, 0 },
101
 
        { "forceclose",   PR_O_FORCE_CLO,  PR_CAP_BE, 0 },
102
 
        { "http_proxy",   PR_O_HTTP_PROXY, PR_CAP_FE | PR_CAP_BE, 0 },
103
 
        { "httpclose",    PR_O_HTTP_CLOSE, PR_CAP_FE | PR_CAP_BE, 0 },
104
 
        { "keepalive",    PR_O_KEEPALIVE,  PR_CAP_NONE, 0 },
105
 
        { "logasap",      PR_O_LOGASAP,    PR_CAP_FE, 0 },
106
 
        { "nolinger",     PR_O_TCP_NOLING, PR_CAP_FE | PR_CAP_BE, 0 },
107
 
        { "persist",      PR_O_PERSIST,    PR_CAP_BE, 0 },
108
 
        { "redispatch",   PR_O_REDISP,     PR_CAP_BE, 0 },
109
 
        { "srvtcpka",     PR_O_TCP_SRV_KA, PR_CAP_BE, 0 },
110
 
#ifdef CONFIG_HAP_TCPSPLICE
111
 
        { "tcpsplice",    PR_O_TCPSPLICE,  PR_CAP_BE|PR_CAP_FE, LSTCHK_TCPSPLICE|LSTCHK_NETADM },
112
 
#endif
 
112
        { "abortonclose", PR_O_ABRT_CLOSE, PR_CAP_BE, 0, 0 },
 
113
        { "allbackups",   PR_O_USE_ALL_BK, PR_CAP_BE, 0, 0 },
 
114
        { "checkcache",   PR_O_CHK_CACHE,  PR_CAP_BE, 0, PR_MODE_HTTP },
 
115
        { "clitcpka",     PR_O_TCP_CLI_KA, PR_CAP_FE, 0, 0 },
 
116
        { "contstats",    PR_O_CONTSTATS,  PR_CAP_FE, 0, 0 },
 
117
        { "dontlognull",  PR_O_NULLNOLOG,  PR_CAP_FE, 0, 0 },
 
118
        { "forceclose",   PR_O_FORCE_CLO,  PR_CAP_FE | PR_CAP_BE, 0, PR_MODE_HTTP },
 
119
        { "http_proxy",   PR_O_HTTP_PROXY, PR_CAP_FE | PR_CAP_BE, 0, PR_MODE_HTTP },
 
120
        { "httpclose",    PR_O_HTTP_CLOSE, PR_CAP_FE | PR_CAP_BE, 0, PR_MODE_HTTP },
 
121
        { "keepalive",    PR_O_KEEPALIVE,  PR_CAP_NONE, 0, PR_MODE_HTTP },
 
122
        { "http-server-close", PR_O_SERVER_CLO,  PR_CAP_FE | PR_CAP_BE, 0, PR_MODE_HTTP },
 
123
        { "logasap",      PR_O_LOGASAP,    PR_CAP_FE, 0, 0 },
 
124
        { "nolinger",     PR_O_TCP_NOLING, PR_CAP_FE | PR_CAP_BE, 0, 0 },
 
125
        { "persist",      PR_O_PERSIST,    PR_CAP_BE, 0, 0 },
 
126
        { "redispatch",   PR_O_REDISP,     PR_CAP_BE, 0, 0 },
 
127
        { "srvtcpka",     PR_O_TCP_SRV_KA, PR_CAP_BE, 0, 0 },
113
128
#ifdef TPROXY
114
 
        { "transparent",  PR_O_TRANSP,     PR_CAP_BE, 0 },
 
129
        { "transparent",  PR_O_TRANSP,     PR_CAP_BE, 0, 0 },
115
130
#endif
116
131
 
117
 
        { NULL, 0, 0, 0 }
 
132
        { NULL, 0, 0, 0, 0 }
118
133
};
119
134
 
120
135
/* proxy->options2 */
121
136
static const struct cfg_opt cfg_opts2[] =
122
137
{
123
138
#ifdef CONFIG_HAP_LINUX_SPLICE
124
 
        { "splice-request",  PR_O2_SPLIC_REQ, PR_CAP_FE|PR_CAP_BE, 0 },
125
 
        { "splice-response", PR_O2_SPLIC_RTR, PR_CAP_FE|PR_CAP_BE, 0 },
126
 
        { "splice-auto",     PR_O2_SPLIC_AUT, PR_CAP_FE|PR_CAP_BE, 0 },
 
139
        { "splice-request",  PR_O2_SPLIC_REQ, PR_CAP_FE|PR_CAP_BE, 0, 0 },
 
140
        { "splice-response", PR_O2_SPLIC_RTR, PR_CAP_FE|PR_CAP_BE, 0, 0 },
 
141
        { "splice-auto",     PR_O2_SPLIC_AUT, PR_CAP_FE|PR_CAP_BE, 0, 0 },
127
142
#endif
128
 
        { "accept-invalid-http-request",  PR_O2_REQBUG_OK, PR_CAP_FE, 0 },
129
 
        { "accept-invalid-http-response", PR_O2_RSPBUG_OK, PR_CAP_BE, 0 },
130
 
        { "dontlog-normal",               PR_O2_NOLOGNORM, PR_CAP_FE, 0 },
131
 
        { "log-separate-errors",          PR_O2_LOGERRORS, PR_CAP_FE, 0 },
132
 
        { "independant-streams",          PR_O2_INDEPSTR,  PR_CAP_FE|PR_CAP_BE, 0 },
 
143
        { "accept-invalid-http-request",  PR_O2_REQBUG_OK, PR_CAP_FE, 0, PR_MODE_HTTP },
 
144
        { "accept-invalid-http-response", PR_O2_RSPBUG_OK, PR_CAP_BE, 0, PR_MODE_HTTP },
 
145
        { "dontlog-normal",               PR_O2_NOLOGNORM, PR_CAP_FE, 0, 0 },
 
146
        { "log-separate-errors",          PR_O2_LOGERRORS, PR_CAP_FE, 0, 0 },
 
147
        { "log-health-checks",            PR_O2_LOGHCHKS,  PR_CAP_BE, 0, 0 },
 
148
        { "socket-stats",                 PR_O2_SOCKSTAT,  PR_CAP_FE, 0, 0 },
 
149
        { "tcp-smart-accept",             PR_O2_SMARTACC,  PR_CAP_FE, 0, 0 },
 
150
        { "tcp-smart-connect",            PR_O2_SMARTCON,  PR_CAP_BE, 0, 0 },
 
151
        { "independant-streams",          PR_O2_INDEPSTR,  PR_CAP_FE|PR_CAP_BE, 0, 0 },
 
152
        { "http-use-proxy-header",        PR_O2_USE_PXHDR, PR_CAP_FE, 0, PR_MODE_HTTP },
 
153
        { "http-pretend-keepalive",       PR_O2_FAKE_KA,   PR_CAP_FE, 0, PR_MODE_HTTP },
133
154
        { NULL, 0, 0, 0 }
134
155
};
135
156
 
150
171
 *  - <port> is a numerical port from 1 to 65535 ;
151
172
 *  - <end> indicates to use the range from <port> to <end> instead (inclusive).
152
173
 * This can be repeated as many times as necessary, separated by a coma.
153
 
 * The <tail> argument is a pointer to a current list which should be appended
154
 
 * to the tail of the new list. The pointer to the new list is returned.
 
174
 * Function returns 1 for success or 0 if error.
155
175
 */
156
 
static struct listener *str2listener(char *str, struct listener *tail)
 
176
static int str2listener(char *str, struct proxy *curproxy)
157
177
{
158
178
        struct listener *l;
159
179
        char *c, *next, *range, *dupstr;
160
180
        int port, end;
161
181
 
162
182
        next = dupstr = strdup(str);
163
 
    
 
183
 
164
184
        while (next && *next) {
165
185
                struct sockaddr_storage ss;
166
186
 
231
251
 
232
252
                for (; port <= end; port++) {
233
253
                        l = (struct listener *)calloc(1, sizeof(struct listener));
234
 
                        l->next = tail;
235
 
                        tail = l;
 
254
                        l->next = curproxy->listen;
 
255
                        curproxy->listen = l;
236
256
 
237
257
                        l->fd = -1;
238
258
                        l->addr = ss;
245
265
                                ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
246
266
                                tcpv4_add_listener(l);
247
267
                        }
 
268
 
248
269
                        listeners++;
249
270
                } /* end for(port) */
250
271
        } /* end while(next) */
251
272
        free(dupstr);
252
 
        return tail;
 
273
        return 1;
253
274
 fail:
254
275
        free(dupstr);
255
 
        return NULL;
 
276
        return 0;
256
277
}
257
278
 
258
279
/*
261
282
 * of the warning to help the user. Returns 1 if a warning was emitted
262
283
 * or 0 if the condition is valid.
263
284
 */
264
 
int warnifnotcap(struct proxy *proxy, int cap, const char *file, int line, char *arg, char *hint)
 
285
int warnifnotcap(struct proxy *proxy, int cap, const char *file, int line, const char *arg, const char *hint)
265
286
{
266
287
        char *msg;
267
288
 
284
305
/* Report a warning if a rule is placed after a 'block' rule.
285
306
 * Return 1 if the warning has been emitted, otherwise 0.
286
307
 */
287
 
int warnif_rule_after_block(struct proxy *proxy, const char *file, int line, char *arg)
 
308
int warnif_rule_after_block(struct proxy *proxy, const char *file, int line, const char *arg)
288
309
{
289
310
        if (!LIST_ISEMPTY(&proxy->block_cond)) {
290
311
                Warning("parsing [%s:%d] : a '%s' rule placed after a 'block' rule will still be processed before.\n",
297
318
/* Report a warning if a rule is placed after a reqrewrite rule.
298
319
 * Return 1 if the warning has been emitted, otherwise 0.
299
320
 */
300
 
int warnif_rule_after_reqxxx(struct proxy *proxy, const char *file, int line, char *arg)
 
321
int warnif_rule_after_reqxxx(struct proxy *proxy, const char *file, int line, const char *arg)
301
322
{
302
323
        if (proxy->req_exp) {
303
324
                Warning("parsing [%s:%d] : a '%s' rule placed after a 'reqxxx' rule will still be processed before.\n",
310
331
/* Report a warning if a rule is placed after a reqadd rule.
311
332
 * Return 1 if the warning has been emitted, otherwise 0.
312
333
 */
313
 
int warnif_rule_after_reqadd(struct proxy *proxy, const char *file, int line, char *arg)
 
334
int warnif_rule_after_reqadd(struct proxy *proxy, const char *file, int line, const char *arg)
314
335
{
315
 
        if (proxy->nb_reqadd) {
 
336
        if (!LIST_ISEMPTY(&proxy->req_add)) {
316
337
                Warning("parsing [%s:%d] : a '%s' rule placed after a 'reqadd' rule will still be processed before.\n",
317
338
                        file, line, arg);
318
339
                return 1;
323
344
/* Report a warning if a rule is placed after a redirect rule.
324
345
 * Return 1 if the warning has been emitted, otherwise 0.
325
346
 */
326
 
int warnif_rule_after_redirect(struct proxy *proxy, const char *file, int line, char *arg)
 
347
int warnif_rule_after_redirect(struct proxy *proxy, const char *file, int line, const char *arg)
327
348
{
328
349
        if (!LIST_ISEMPTY(&proxy->redirect_rules)) {
329
350
                Warning("parsing [%s:%d] : a '%s' rule placed after a 'redirect' rule will still be processed before.\n",
336
357
/* Report a warning if a rule is placed after a 'use_backend' rule.
337
358
 * Return 1 if the warning has been emitted, otherwise 0.
338
359
 */
339
 
int warnif_rule_after_use_backend(struct proxy *proxy, const char *file, int line, char *arg)
 
360
int warnif_rule_after_use_backend(struct proxy *proxy, const char *file, int line, const char *arg)
340
361
{
341
362
        if (!LIST_ISEMPTY(&proxy->switching_rules)) {
342
363
                Warning("parsing [%s:%d] : a '%s' rule placed after a 'use_backend' rule will still be processed before.\n",
347
368
}
348
369
 
349
370
/* report a warning if a block rule is dangerously placed */
350
 
int warnif_misplaced_block(struct proxy *proxy, const char *file, int line, char *arg)
 
371
int warnif_misplaced_block(struct proxy *proxy, const char *file, int line, const char *arg)
351
372
{
352
373
        return  warnif_rule_after_reqxxx(proxy, file, line, arg) ||
353
374
                warnif_rule_after_reqadd(proxy, file, line, arg) ||
356
377
}
357
378
 
358
379
/* report a warning if a reqxxx rule is dangerously placed */
359
 
int warnif_misplaced_reqxxx(struct proxy *proxy, const char *file, int line, char *arg)
 
380
int warnif_misplaced_reqxxx(struct proxy *proxy, const char *file, int line, const char *arg)
360
381
{
361
382
        return  warnif_rule_after_reqadd(proxy, file, line, arg) ||
362
383
                warnif_rule_after_redirect(proxy, file, line, arg) ||
364
385
}
365
386
 
366
387
/* report a warning if a reqadd rule is dangerously placed */
367
 
int warnif_misplaced_reqadd(struct proxy *proxy, const char *file, int line, char *arg)
 
388
int warnif_misplaced_reqadd(struct proxy *proxy, const char *file, int line, const char *arg)
368
389
{
369
390
        return  warnif_rule_after_redirect(proxy, file, line, arg) ||
370
391
                warnif_rule_after_use_backend(proxy, file, line, arg);
371
392
}
372
393
 
 
394
/* Report it if a request ACL condition uses some response-only parameters. It
 
395
 * returns either 0 or ERR_WARN so that its result can be or'ed with err_code.
 
396
 * Note that <cond> may be NULL and then will be ignored.
 
397
 */
 
398
static int warnif_cond_requires_resp(const struct acl_cond *cond, const char *file, int line)
 
399
{
 
400
        struct acl *acl;
 
401
 
 
402
        if (!cond || !(cond->requires & ACL_USE_RTR_ANY))
 
403
                return 0;
 
404
 
 
405
        acl = cond_find_require(cond, ACL_USE_RTR_ANY);
 
406
        Warning("parsing [%s:%d] : acl '%s' involves some response-only criteria which will be ignored.\n",
 
407
                file, line, acl ? acl->name : "(unknown)");
 
408
        return ERR_WARN;
 
409
}
 
410
 
 
411
/* Report it if a request ACL condition uses some request-only volatile parameters.
 
412
 * It returns either 0 or ERR_WARN so that its result can be or'ed with err_code.
 
413
 * Note that <cond> may be NULL and then will be ignored.
 
414
 */
 
415
static int warnif_cond_requires_req(const struct acl_cond *cond, const char *file, int line)
 
416
{
 
417
        struct acl *acl;
 
418
 
 
419
        if (!cond || !(cond->requires & ACL_USE_REQ_VOLATILE))
 
420
                return 0;
 
421
 
 
422
        acl = cond_find_require(cond, ACL_USE_REQ_VOLATILE);
 
423
        Warning("parsing [%s:%d] : acl '%s' involves some volatile request-only criteria which will be ignored.\n",
 
424
                file, line, acl ? acl->name : "(unknown)");
 
425
        return ERR_WARN;
 
426
}
 
427
 
 
428
 
373
429
/*
374
430
 * parse a line in a <global> section. Returns the error code, 0 if OK, or
375
431
 * any combination of :
380
436
 * Only the two first ones can stop processing, the two others are just
381
437
 * indicators.
382
438
 */
383
 
int cfg_parse_global(const char *file, int linenum, char **args, int inv)
 
439
int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
384
440
{
385
441
        int err_code = 0;
386
442
 
438
494
                }
439
495
                global.tune.maxaccept = atol(args[1]);
440
496
        }
 
497
        else if (!strcmp(args[0], "tune.bufsize")) {
 
498
                if (*(args[1]) == 0) {
 
499
                        Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
 
500
                        err_code |= ERR_ALERT | ERR_FATAL;
 
501
                        goto out;
 
502
                }
 
503
                global.tune.bufsize = atol(args[1]);
 
504
                if (global.tune.maxrewrite >= global.tune.bufsize / 2)
 
505
                        global.tune.maxrewrite = global.tune.bufsize / 2;
 
506
        }
 
507
        else if (!strcmp(args[0], "tune.maxrewrite")) {
 
508
                if (*(args[1]) == 0) {
 
509
                        Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
 
510
                        err_code |= ERR_ALERT | ERR_FATAL;
 
511
                        goto out;
 
512
                }
 
513
                global.tune.maxrewrite = atol(args[1]);
 
514
                if (global.tune.maxrewrite >= global.tune.bufsize / 2)
 
515
                        global.tune.maxrewrite = global.tune.bufsize / 2;
 
516
        }
 
517
        else if (!strcmp(args[0], "tune.rcvbuf.client")) {
 
518
                if (global.tune.client_rcvbuf != 0) {
 
519
                        Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
 
520
                        err_code |= ERR_ALERT;
 
521
                        goto out;
 
522
                }
 
523
                if (*(args[1]) == 0) {
 
524
                        Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
 
525
                        err_code |= ERR_ALERT | ERR_FATAL;
 
526
                        goto out;
 
527
                }
 
528
                global.tune.client_rcvbuf = atol(args[1]);
 
529
        }
 
530
        else if (!strcmp(args[0], "tune.rcvbuf.server")) {
 
531
                if (global.tune.server_rcvbuf != 0) {
 
532
                        Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
 
533
                        err_code |= ERR_ALERT;
 
534
                        goto out;
 
535
                }
 
536
                if (*(args[1]) == 0) {
 
537
                        Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
 
538
                        err_code |= ERR_ALERT | ERR_FATAL;
 
539
                        goto out;
 
540
                }
 
541
                global.tune.server_rcvbuf = atol(args[1]);
 
542
        }
 
543
        else if (!strcmp(args[0], "tune.sndbuf.client")) {
 
544
                if (global.tune.client_sndbuf != 0) {
 
545
                        Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
 
546
                        err_code |= ERR_ALERT;
 
547
                        goto out;
 
548
                }
 
549
                if (*(args[1]) == 0) {
 
550
                        Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
 
551
                        err_code |= ERR_ALERT | ERR_FATAL;
 
552
                        goto out;
 
553
                }
 
554
                global.tune.client_sndbuf = atol(args[1]);
 
555
        }
 
556
        else if (!strcmp(args[0], "tune.sndbuf.server")) {
 
557
                if (global.tune.server_sndbuf != 0) {
 
558
                        Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
 
559
                        err_code |= ERR_ALERT;
 
560
                        goto out;
 
561
                }
 
562
                if (*(args[1]) == 0) {
 
563
                        Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
 
564
                        err_code |= ERR_ALERT | ERR_FATAL;
 
565
                        goto out;
 
566
                }
 
567
                global.tune.server_sndbuf = atol(args[1]);
 
568
        }
441
569
        else if (!strcmp(args[0], "uid")) {
442
570
                if (global.uid != 0) {
443
571
                        Alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum);
601
729
 
602
730
                for (i=0; args[1][i]; i++) {
603
731
                        c = args[1][i];
604
 
                        if (!isupper(c) && !islower(c) && !isdigit(c) && c != '_' && c != '-' && c != '.')
 
732
                        if (!isupper((unsigned char)c) && !islower((unsigned char)c) &&
 
733
                            !isdigit((unsigned char)c) && c != '_' && c != '-' && c != '.')
605
734
                                break;
606
735
                }
607
736
 
669
798
                }
670
799
 
671
800
                if (args[1][0] == '/') {
 
801
                        struct sockaddr_un *sk = str2sun(args[1]);
 
802
                        if (!sk) {
 
803
                                Alert("parsing [%s:%d] : Socket path '%s' too long (max %d)\n", file, linenum,
 
804
                                      args[1], (int)sizeof(sk->sun_path) - 1);
 
805
                                err_code |= ERR_ALERT | ERR_FATAL;
 
806
                                goto out;
 
807
                        }
 
808
                        logsrv.u.un = *sk;
672
809
                        logsrv.u.addr.sa_family = AF_UNIX;
673
 
                        logsrv.u.un = *str2sun(args[1]);
674
810
                } else {
 
811
                        struct sockaddr_in *sk = str2sa(args[1]);
 
812
                        if (!sk) {
 
813
                                Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[1]);
 
814
                                err_code |= ERR_ALERT | ERR_FATAL;
 
815
                                goto out;
 
816
                        }
 
817
                        logsrv.u.in = *sk;
675
818
                        logsrv.u.addr.sa_family = AF_INET;
676
 
                        logsrv.u.in = *str2sa(args[1]);
677
819
                        if (!logsrv.u.in.sin_port)
678
820
                                logsrv.u.in.sin_port = htons(SYSLOG_PORT);
679
821
                }
748
890
        return err_code;
749
891
}
750
892
 
 
893
/* Perform the most basic initialization of a proxy :
 
894
 * memset(), list_init(*), reset_timeouts(*).
 
895
 */
 
896
static void init_new_proxy(struct proxy *p)
 
897
{
 
898
        memset(p, 0, sizeof(struct proxy));
 
899
        LIST_INIT(&p->pendconns);
 
900
        LIST_INIT(&p->acl);
 
901
        LIST_INIT(&p->req_acl);
 
902
        LIST_INIT(&p->block_cond);
 
903
        LIST_INIT(&p->redirect_rules);
 
904
        LIST_INIT(&p->mon_fail_cond);
 
905
        LIST_INIT(&p->switching_rules);
 
906
        LIST_INIT(&p->force_persist_rules);
 
907
        LIST_INIT(&p->sticking_rules);
 
908
        LIST_INIT(&p->storersp_rules);
 
909
        LIST_INIT(&p->tcp_req.inspect_rules);
 
910
        LIST_INIT(&p->req_add);
 
911
        LIST_INIT(&p->rsp_add);
 
912
 
 
913
        /* Timeouts are defined as -1 */
 
914
        proxy_reset_timeouts(p);
 
915
}
751
916
 
752
917
void init_default_instance()
753
918
{
754
 
        memset(&defproxy, 0, sizeof(defproxy));
 
919
        init_new_proxy(&defproxy);
755
920
        defproxy.mode = PR_MODE_TCP;
756
921
        defproxy.state = PR_STNEW;
757
922
        defproxy.maxconn = cfg_maxpconn;
758
923
        defproxy.conn_retries = CONN_RETRIES;
759
924
        defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
760
925
 
761
 
        LIST_INIT(&defproxy.pendconns);
762
 
        LIST_INIT(&defproxy.acl);
763
 
        LIST_INIT(&defproxy.block_cond);
764
 
        LIST_INIT(&defproxy.mon_fail_cond);
765
 
        LIST_INIT(&defproxy.switching_rules);
766
 
 
767
 
        proxy_reset_timeouts(&defproxy);
 
926
        defproxy.defsrv.inter = DEF_CHKINTR;
 
927
        defproxy.defsrv.fastinter = 0;
 
928
        defproxy.defsrv.downinter = 0;
 
929
        defproxy.defsrv.rise = DEF_RISETIME;
 
930
        defproxy.defsrv.fall = DEF_FALLTIME;
 
931
        defproxy.defsrv.check_port = 0;
 
932
        defproxy.defsrv.maxqueue = 0;
 
933
        defproxy.defsrv.minconn = 0;
 
934
        defproxy.defsrv.maxconn = 0;
 
935
        defproxy.defsrv.slowstart = 0;
 
936
        defproxy.defsrv.onerror = DEF_HANA_ONERR;
 
937
        defproxy.defsrv.consecutive_errors_limit = DEF_HANA_ERRLIMIT;
 
938
        defproxy.defsrv.uweight = defproxy.defsrv.iweight = 1;
 
939
}
 
940
 
 
941
 
 
942
static int create_cond_regex_rule(const char *file, int line,
 
943
                                  struct proxy *px, int dir, int action, int flags,
 
944
                                  const char *cmd, const char *reg, const char *repl,
 
945
                                  const char **cond_start)
 
946
{
 
947
        regex_t *preg = NULL;
 
948
        const char *err;
 
949
        int err_code = 0;
 
950
        struct acl_cond *cond = NULL;
 
951
 
 
952
        if (px == &defproxy) {
 
953
                Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, line, cmd);
 
954
                err_code |= ERR_ALERT | ERR_FATAL;
 
955
                goto err;
 
956
        }
 
957
 
 
958
        if (*reg == 0) {
 
959
                Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, line, cmd);
 
960
                err_code |= ERR_ALERT | ERR_FATAL;
 
961
                goto err;
 
962
        }
 
963
 
 
964
        if (warnifnotcap(px, PR_CAP_RS, file, line, cmd, NULL))
 
965
                err_code |= ERR_WARN;
 
966
 
 
967
        if (cond_start &&
 
968
            (strcmp(*cond_start, "if") == 0 || strcmp(*cond_start, "unless") == 0)) {
 
969
                if ((cond = build_acl_cond(file, line, px, cond_start)) == NULL) {
 
970
                        Alert("parsing [%s:%d] : error detected while parsing a '%s' condition.\n",
 
971
                              file, line, cmd);
 
972
                        err_code |= ERR_ALERT | ERR_FATAL;
 
973
                        goto err;
 
974
                }
 
975
        }
 
976
        else if (cond_start && **cond_start) {
 
977
                Alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
 
978
                      file, line, cmd, *cond_start);
 
979
                err_code |= ERR_ALERT | ERR_FATAL;
 
980
                goto err;
 
981
        }
 
982
 
 
983
        if (dir == ACL_DIR_REQ)
 
984
                err_code |= warnif_cond_requires_resp(cond, file, line);
 
985
        else
 
986
                err_code |= warnif_cond_requires_req(cond, file, line);
 
987
 
 
988
        preg = calloc(1, sizeof(regex_t));
 
989
        if (!preg) {
 
990
                Alert("parsing [%s:%d] : '%s' : not enough memory to build regex.\n", file, line, cmd);
 
991
                err_code = ERR_ALERT | ERR_FATAL;
 
992
                goto err;
 
993
        }
 
994
 
 
995
        if (regcomp(preg, reg, REG_EXTENDED | flags) != 0) {
 
996
                Alert("parsing [%s:%d] : '%s' : bad regular expression '%s'.\n", file, line, cmd, reg);
 
997
                err_code = ERR_ALERT | ERR_FATAL;
 
998
                goto err;
 
999
        }
 
1000
 
 
1001
        err = chain_regex((dir == ACL_DIR_REQ) ? &px->req_exp : &px->rsp_exp,
 
1002
                          preg, action, repl ? strdup(repl) : NULL, cond);
 
1003
        if (repl && err) {
 
1004
                Alert("parsing [%s:%d] : '%s' : invalid character or unterminated sequence in replacement string near '%c'.\n",
 
1005
                      file, line, cmd, *err);
 
1006
                err_code |= ERR_ALERT | ERR_FATAL;
 
1007
                goto err;
 
1008
        }
 
1009
 
 
1010
        if (dir == ACL_DIR_REQ && warnif_misplaced_reqxxx(px, file, line, cmd))
 
1011
                err_code |= ERR_WARN;
 
1012
 
 
1013
        return err_code;
 
1014
 err:
 
1015
        free(preg);
 
1016
        return err_code;
768
1017
}
769
1018
 
770
1019
/*
777
1026
 * Only the two first ones can stop processing, the two others are just
778
1027
 * indicators.
779
1028
 */
780
 
int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
 
1029
int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
781
1030
{
782
1031
        static struct proxy *curproxy = NULL;
783
1032
        struct server *newsrv = NULL;
785
1034
        int rc;
786
1035
        unsigned val;
787
1036
        int err_code = 0;
 
1037
        struct acl_cond *cond = NULL;
788
1038
 
789
1039
        if (!strcmp(args[0], "listen"))
790
1040
                rc = PR_CAP_LISTEN;
828
1078
                        if (!strcmp(curproxy->id, args[1]) &&
829
1079
                                (rc!=(PR_CAP_FE|PR_CAP_RS) || curproxy->cap!=(PR_CAP_BE|PR_CAP_RS)) &&
830
1080
                                (rc!=(PR_CAP_BE|PR_CAP_RS) || curproxy->cap!=(PR_CAP_FE|PR_CAP_RS))) {
831
 
                                Warning("Parsing [%s:%d]: %s '%s' has same name as another %s.\n",
832
 
                                        file, linenum, proxy_cap_str(rc), args[1], proxy_type_str(curproxy));
 
1081
                                Warning("Parsing [%s:%d]: %s '%s' has same name as another %s (declared at %s:%d).\n",
 
1082
                                        file, linenum, proxy_cap_str(rc), args[1], proxy_type_str(curproxy),
 
1083
                                        curproxy->conf.file, curproxy->conf.line);
833
1084
                                err_code |= ERR_WARN;
834
1085
                        }
835
1086
                }
840
1091
                        goto out;
841
1092
                }
842
1093
 
 
1094
                init_new_proxy(curproxy);
843
1095
                curproxy->next = proxy;
844
1096
                proxy = curproxy;
845
 
                LIST_INIT(&curproxy->pendconns);
846
 
                LIST_INIT(&curproxy->acl);
847
 
                LIST_INIT(&curproxy->block_cond);
848
 
                LIST_INIT(&curproxy->redirect_rules);
849
 
                LIST_INIT(&curproxy->mon_fail_cond);
850
 
                LIST_INIT(&curproxy->switching_rules);
851
 
                LIST_INIT(&curproxy->tcp_req.inspect_rules);
852
 
 
853
 
                /* Timeouts are defined as -1, so we cannot use the zeroed area
854
 
                 * as a default value.
855
 
                 */
856
 
                proxy_reset_timeouts(curproxy);
857
 
 
 
1097
                curproxy->conf.file = file;
 
1098
                curproxy->conf.line = linenum;
858
1099
                curproxy->last_change = now.tv_sec;
859
1100
                curproxy->id = strdup(args[1]);
860
1101
                curproxy->cap = rc;
861
1102
 
862
1103
                /* parse the listener address if any */
863
1104
                if ((curproxy->cap & PR_CAP_FE) && *args[2]) {
864
 
                        curproxy->listen = str2listener(args[2], curproxy->listen);
865
 
                        if (!curproxy->listen) {
 
1105
                        struct listener *new, *last = curproxy->listen;
 
1106
                        if (!str2listener(args[2], curproxy)) {
866
1107
                                err_code |= ERR_FATAL;
867
1108
                                goto out;
868
1109
                        }
 
1110
                        new = curproxy->listen;
 
1111
                        while (new != last) {
 
1112
                                new->conf.file = file;
 
1113
                                new->conf.line = linenum;
 
1114
                                new = new->next;
 
1115
                        }
869
1116
                        global.maxsock++;
870
1117
                }
871
1118
 
872
1119
                /* set default values */
 
1120
                memcpy(&curproxy->defsrv, &defproxy.defsrv, sizeof(curproxy->defsrv));
 
1121
                curproxy->defsrv.id = "default-server";
 
1122
 
873
1123
                curproxy->state = defproxy.state;
874
1124
                curproxy->options = defproxy.options;
875
1125
                curproxy->options2 = defproxy.options2;
 
1126
                curproxy->no_options = defproxy.no_options;
 
1127
                curproxy->no_options2 = defproxy.no_options2;
876
1128
                curproxy->bind_proc = defproxy.bind_proc;
877
1129
                curproxy->lbprm.algo = defproxy.lbprm.algo;
878
1130
                curproxy->except_net = defproxy.except_net;
885
1137
                        curproxy->fwdfor_hdr_name = strdup(defproxy.fwdfor_hdr_name);
886
1138
                }
887
1139
 
 
1140
                if (defproxy.orgto_hdr_len) {
 
1141
                        curproxy->orgto_hdr_len  = defproxy.orgto_hdr_len;
 
1142
                        curproxy->orgto_hdr_name = strdup(defproxy.orgto_hdr_name);
 
1143
                }
 
1144
 
888
1145
                if (curproxy->cap & PR_CAP_FE) {
889
1146
                        curproxy->maxconn = defproxy.maxconn;
890
1147
                        curproxy->backlog = defproxy.backlog;
891
1148
                        curproxy->fe_sps_lim = defproxy.fe_sps_lim;
892
1149
 
893
1150
                        /* initialize error relocations */
894
 
                        for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
895
 
                                if (defproxy.errmsg[rc].str)
896
 
                                        chunk_dup(&curproxy->errmsg[rc], &defproxy.errmsg[rc]);
897
 
                        }
 
1151
                        for (rc = 0; rc < HTTP_ERR_SIZE; rc++)
 
1152
                                chunk_dup(&curproxy->errmsg[rc], &defproxy.errmsg[rc]);
898
1153
 
899
1154
                        curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
900
1155
                }
910
1165
                        if (defproxy.cookie_name)
911
1166
                                curproxy->cookie_name = strdup(defproxy.cookie_name);
912
1167
                        curproxy->cookie_len = defproxy.cookie_len;
 
1168
                        if (defproxy.cookie_domain)
 
1169
                                curproxy->cookie_domain = strdup(defproxy.cookie_domain);
 
1170
 
 
1171
                        if (defproxy.rdp_cookie_name)
 
1172
                                 curproxy->rdp_cookie_name = strdup(defproxy.rdp_cookie_name);
 
1173
                        curproxy->rdp_cookie_len = defproxy.rdp_cookie_len;
913
1174
 
914
1175
                        if (defproxy.url_param_name)
915
1176
                                curproxy->url_param_name = strdup(defproxy.url_param_name);
936
1197
                        curproxy->timeout.client = defproxy.timeout.client;
937
1198
                        curproxy->timeout.tarpit = defproxy.timeout.tarpit;
938
1199
                        curproxy->timeout.httpreq = defproxy.timeout.httpreq;
 
1200
                        curproxy->timeout.httpka = defproxy.timeout.httpka;
939
1201
                        curproxy->uri_auth  = defproxy.uri_auth;
940
1202
                        curproxy->mon_net = defproxy.mon_net;
941
1203
                        curproxy->mon_mask = defproxy.mon_mask;
952
1214
                        curproxy->timeout.check = defproxy.timeout.check;
953
1215
                        curproxy->timeout.queue = defproxy.timeout.queue;
954
1216
                        curproxy->timeout.tarpit = defproxy.timeout.tarpit;
 
1217
                        curproxy->timeout.httpreq = defproxy.timeout.httpreq;
 
1218
                        curproxy->timeout.httpka = defproxy.timeout.httpka;
955
1219
                        curproxy->source_addr = defproxy.source_addr;
956
1220
                }
957
1221
 
965
1229
                curproxy->loglev2 = defproxy.loglev2;
966
1230
                curproxy->minlvl2 = defproxy.minlvl2;
967
1231
                curproxy->grace  = defproxy.grace;
968
 
                curproxy->uuid = next_pxid++;   /* generate a uuid for this proxy */
969
 
                curproxy->next_svid = 1;        /* server id 0 is reserved */
 
1232
                curproxy->conf.used_listener_id = EB_ROOT;
 
1233
                curproxy->conf.used_server_id = EB_ROOT;
970
1234
 
971
1235
                goto out;
972
1236
        }
977
1241
                 */
978
1242
                free(defproxy.check_req);
979
1243
                free(defproxy.cookie_name);
 
1244
                free(defproxy.rdp_cookie_name);
 
1245
                free(defproxy.cookie_domain);
980
1246
                free(defproxy.url_param_name);
981
1247
                free(defproxy.hh_name);
982
1248
                free(defproxy.capture_name);
985
1251
                free(defproxy.iface_name);
986
1252
                free(defproxy.fwdfor_hdr_name);
987
1253
                defproxy.fwdfor_hdr_len = 0;
 
1254
                free(defproxy.orgto_hdr_name);
 
1255
                defproxy.orgto_hdr_len = 0;
988
1256
 
989
1257
                for (rc = 0; rc < HTTP_ERR_SIZE; rc++)
990
 
                        free(defproxy.errmsg[rc].str);
 
1258
                        chunk_destroy(&defproxy.errmsg[rc]);
991
1259
 
992
1260
                /* we cannot free uri_auth because it might already be used */
993
1261
                init_default_instance();
1004
1272
 
1005
1273
        /* Now let's parse the proxy-specific keywords */
1006
1274
        if (!strcmp(args[0], "bind")) {  /* new listen addresses */
1007
 
                struct listener *last_listen;
 
1275
                struct listener *new_listen, *last_listen;
1008
1276
                int cur_arg;
1009
1277
 
1010
1278
                if (curproxy == &defproxy) {
1023
1291
                }
1024
1292
 
1025
1293
                last_listen = curproxy->listen;
1026
 
                curproxy->listen = str2listener(args[1], last_listen);
1027
 
                if (!curproxy->listen) {
 
1294
                if (!str2listener(args[1], curproxy)) {
1028
1295
                        err_code |= ERR_ALERT | ERR_FATAL;
1029
1296
                        goto out;
1030
1297
                }
1031
1298
 
 
1299
                new_listen = curproxy->listen;
 
1300
                while (new_listen != last_listen) {
 
1301
                        new_listen->conf.file = file;
 
1302
                        new_listen->conf.line = linenum;
 
1303
                        new_listen = new_listen->next;
 
1304
                }
 
1305
 
1032
1306
                cur_arg = 2;
1033
1307
                while (*(args[cur_arg])) {
1034
1308
                        if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
1056
1330
                                goto out;
1057
1331
#endif
1058
1332
                        }
 
1333
                        if (!strcmp(args[cur_arg], "mss")) { /* set MSS of listening socket */
 
1334
#ifdef TCP_MAXSEG
 
1335
                                struct listener *l;
 
1336
                                int mss;
 
1337
 
 
1338
                                if (!*args[cur_arg + 1]) {
 
1339
                                        Alert("parsing [%s:%d] : '%s' : missing MSS value.\n",
 
1340
                                              file, linenum, args[0]);
 
1341
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
1342
                                        goto out;
 
1343
                                }
 
1344
 
 
1345
                                mss = str2uic(args[cur_arg + 1]);
 
1346
                                if (mss < 1 || mss > 65535) {
 
1347
                                        Alert("parsing [%s:%d]: %s expects an MSS value between 1 and 65535.\n",
 
1348
                                              file, linenum, args[0]);
 
1349
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
1350
                                        goto out;
 
1351
                                }
 
1352
 
 
1353
                                for (l = curproxy->listen; l != last_listen; l = l->next)
 
1354
                                        l->maxseg = mss;
 
1355
 
 
1356
                                cur_arg += 2;
 
1357
                                continue;
 
1358
#else
 
1359
                                Alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
 
1360
                                      file, linenum, args[0], args[cur_arg]);
 
1361
                                err_code |= ERR_ALERT | ERR_FATAL;
 
1362
                                goto out;
 
1363
#endif
 
1364
                        }
 
1365
 
 
1366
                        if (!strcmp(args[cur_arg], "defer-accept")) { /* wait for some data for 1 second max before doing accept */
 
1367
#ifdef TCP_DEFER_ACCEPT
 
1368
                                struct listener *l;
 
1369
 
 
1370
                                for (l = curproxy->listen; l != last_listen; l = l->next)
 
1371
                                        l->options |= LI_O_DEF_ACCEPT;
 
1372
 
 
1373
                                cur_arg ++;
 
1374
                                continue;
 
1375
#else
 
1376
                                Alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
 
1377
                                      file, linenum, args[0], args[cur_arg]);
 
1378
                                err_code |= ERR_ALERT | ERR_FATAL;
 
1379
                                goto out;
 
1380
#endif
 
1381
                        }
 
1382
 
1059
1383
                        if (!strcmp(args[cur_arg], "transparent")) { /* transparently bind to these addresses */
1060
1384
#ifdef CONFIG_HAP_LINUX_TPROXY
1061
1385
                                struct listener *l;
1072
1396
                                goto out;
1073
1397
#endif
1074
1398
                        }
1075
 
                        Alert("parsing [%s:%d] : '%s' only supports the 'transparent' and 'interface' options.\n",
 
1399
 
 
1400
                        if (!strcmp(args[cur_arg], "name")) {
 
1401
                                struct listener *l;
 
1402
 
 
1403
                                for (l = curproxy->listen; l != last_listen; l = l->next)
 
1404
                                        l->name = strdup(args[cur_arg + 1]);
 
1405
 
 
1406
                                cur_arg += 2;
 
1407
                                continue;
 
1408
                        }
 
1409
 
 
1410
                        if (!strcmp(args[cur_arg], "id")) {
 
1411
                                struct eb32_node *node;
 
1412
                                struct listener *l;
 
1413
 
 
1414
                                if (curproxy->listen->next != last_listen) {
 
1415
                                        Alert("parsing [%s:%d]: '%s' can be only used with a single socket.\n",
 
1416
                                                file, linenum, args[cur_arg]);
 
1417
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
1418
                                        goto out;
 
1419
                                }
 
1420
 
 
1421
                                if (!*args[cur_arg + 1]) {
 
1422
                                        Alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
 
1423
                                                file, linenum, args[cur_arg]);
 
1424
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
1425
                                        goto out;
 
1426
                                }
 
1427
 
 
1428
                                curproxy->listen->luid = atol(args[cur_arg + 1]);
 
1429
                                curproxy->listen->conf.id.key = curproxy->listen->luid;
 
1430
 
 
1431
                                if (curproxy->listen->luid <= 0) {
 
1432
                                        Alert("parsing [%s:%d]: custom id has to be > 0\n",
 
1433
                                                file, linenum);
 
1434
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
1435
                                        goto out;
 
1436
                                }
 
1437
 
 
1438
                                node = eb32_lookup(&curproxy->conf.used_listener_id, curproxy->listen->luid);
 
1439
                                if (node) {
 
1440
                                        l = container_of(node, struct listener, conf.id);
 
1441
                                        Alert("parsing [%s:%d]: custom id %d for socket '%s' already used at %s:%d.\n",
 
1442
                                              file, linenum, l->luid, args[1], l->conf.file, l->conf.line);
 
1443
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
1444
                                        goto out;
 
1445
                                }
 
1446
                                eb32_insert(&curproxy->conf.used_listener_id, &curproxy->listen->conf.id);
 
1447
 
 
1448
                                cur_arg += 2;
 
1449
                                continue;
 
1450
                        }
 
1451
 
 
1452
                        Alert("parsing [%s:%d] : '%s' only supports the 'transparent', 'defer-accept', 'name', 'id', 'mss' and 'interface' options.\n",
1076
1453
                              file, linenum, args[0]);
1077
1454
                        err_code |= ERR_ALERT | ERR_FATAL;
1078
1455
                        goto out;
1124
1501
                }
1125
1502
        }
1126
1503
        else if (!strcmp(args[0], "id")) {
1127
 
                struct proxy *target;
 
1504
                struct eb32_node *node;
1128
1505
 
1129
1506
                if (curproxy == &defproxy) {
1130
1507
                        Alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n",
1141
1518
                }
1142
1519
 
1143
1520
                curproxy->uuid = atol(args[1]);
 
1521
                curproxy->conf.id.key = curproxy->uuid;
1144
1522
 
1145
 
                if (curproxy->uuid < 1001) {
1146
 
                        Alert("parsing [%s:%d]: custom id has to be > 1000.\n",
 
1523
                if (curproxy->uuid <= 0) {
 
1524
                        Alert("parsing [%s:%d]: custom id has to be > 0.\n",
1147
1525
                                file, linenum);
1148
1526
                        err_code |= ERR_ALERT | ERR_FATAL;
1149
1527
                        goto out;
1150
1528
                }
1151
1529
 
1152
 
                for (target = proxy; target; target = target->next)
1153
 
                        if (curproxy != target && curproxy->uuid == target->uuid) {
1154
 
                                Alert("parsing [%s:%d]: custom id has to be unique but is duplicated in %s and %s.\n",
1155
 
                                        file, linenum, curproxy->id, target->id);
1156
 
                                err_code |= ERR_ALERT | ERR_FATAL;
1157
 
                                goto out;
1158
 
                        }
 
1530
                node = eb32_lookup(&used_proxy_id, curproxy->uuid);
 
1531
                if (node) {
 
1532
                        struct proxy *target = container_of(node, struct proxy, conf.id);
 
1533
                        Alert("parsing [%s:%d]: %s %s reuses same custom id as %s %s (declared at %s:%d).\n",
 
1534
                              file, linenum, proxy_type_str(curproxy), curproxy->id,
 
1535
                              proxy_type_str(target), target->id, target->conf.file, target->conf.line);
 
1536
                        err_code |= ERR_ALERT | ERR_FATAL;
 
1537
                        goto out;
 
1538
                }
 
1539
                eb32_insert(&used_proxy_id, &curproxy->conf.id);
1159
1540
        }
1160
1541
        else if (!strcmp(args[0], "description")) {
1161
1542
                int i, len=0;
1162
1543
                char *d;
1163
1544
 
 
1545
                if (curproxy == &defproxy) {
 
1546
                        Alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n",
 
1547
                                 file, linenum, args[0]);
 
1548
                        err_code |= ERR_ALERT | ERR_FATAL;
 
1549
                        goto out;
 
1550
                }
 
1551
 
1164
1552
                if (!*args[1]) {
1165
1553
                        Alert("parsing [%s:%d]: '%s' expects a string argument.\n",
1166
1554
                                file, linenum, args[0]);
1253
1641
                        goto out;
1254
1642
                }
1255
1643
 
 
1644
                free(curproxy->cookie_domain); curproxy->cookie_domain = NULL;
1256
1645
                free(curproxy->cookie_name);
1257
1646
                curproxy->cookie_name = strdup(args[1]);
1258
1647
                curproxy->cookie_len = strlen(curproxy->cookie_name);
1287
1676
 
1288
1677
                                if (*args[cur_arg + 1] != '.' || !strchr(args[cur_arg + 1] + 1, '.')) {
1289
1678
                                        /* rfc2109, 4.3.2 Rejecting Cookies */
1290
 
                                        Alert("parsing [%s:%d]: domain '%s' contains no embedded"
1291
 
                                                " dots or does not start with a dot.\n",
 
1679
                                        Warning("parsing [%s:%d]: domain '%s' contains no embedded"
 
1680
                                                " dots nor does not start with a dot."
 
1681
                                                " RFC forbids it, this configuration may not work properly.\n",
1292
1682
                                                file, linenum, args[cur_arg + 1]);
1293
 
                                        err_code |= ERR_ALERT | ERR_FATAL;
1294
 
                                        goto out;
 
1683
                                        err_code |= ERR_WARN;
1295
1684
                                }
1296
1685
 
1297
1686
                                err = invalid_domainchar(args[cur_arg + 1]);
1302
1691
                                        goto out;
1303
1692
                                }
1304
1693
 
1305
 
                                curproxy->cookie_domain = strdup(args[cur_arg + 1]);
 
1694
                                if (!curproxy->cookie_domain) {
 
1695
                                        curproxy->cookie_domain = strdup(args[cur_arg + 1]);
 
1696
                                } else {
 
1697
                                        /* one domain was already specified, add another one by
 
1698
                                         * building the string which will be returned along with
 
1699
                                         * the cookie.
 
1700
                                         */
 
1701
                                        char *new_ptr;
 
1702
                                        int new_len = strlen(curproxy->cookie_domain) +
 
1703
                                                strlen("; domain=") + strlen(args[cur_arg + 1]) + 1;
 
1704
                                        new_ptr = malloc(new_len);
 
1705
                                        snprintf(new_ptr, new_len, "%s; domain=%s", curproxy->cookie_domain, args[cur_arg+1]);
 
1706
                                        free(curproxy->cookie_domain);
 
1707
                                        curproxy->cookie_domain = new_ptr;
 
1708
                                }
1306
1709
                                cur_arg++;
1307
1710
                        }
1308
1711
                        else {
1325
1728
                        err_code |= ERR_ALERT | ERR_FATAL;
1326
1729
                }
1327
1730
        }/* end else if (!strcmp(args[0], "cookie"))  */
 
1731
        else if (!strcmp(args[0], "persist")) {  /* persist */
 
1732
                if (*(args[1]) == 0) {
 
1733
                        Alert("parsing [%s:%d] : missing persist method.\n",
 
1734
                                file, linenum);
 
1735
                        err_code |= ERR_ALERT | ERR_FATAL;
 
1736
                        goto out;
 
1737
                }
 
1738
 
 
1739
                if (!strncmp(args[1], "rdp-cookie", 10)) {
 
1740
                        curproxy->options2 |= PR_O2_RDPC_PRST;
 
1741
 
 
1742
                        if (*(args[1] + 10) == '(') { /* cookie name */
 
1743
                                const char *beg, *end;
 
1744
 
 
1745
                                beg = args[1] + 11;
 
1746
                                end = strchr(beg, ')');
 
1747
 
 
1748
                                if (!end || end == beg) {
 
1749
                                        Alert("parsing [%s:%d] : persist rdp-cookie(name)' requires an rdp cookie name.\n",
 
1750
                                              file, linenum);
 
1751
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
1752
                                        goto out;
 
1753
                                }
 
1754
 
 
1755
                                free(curproxy->rdp_cookie_name);
 
1756
                                curproxy->rdp_cookie_name = my_strndup(beg, end - beg);
 
1757
                                curproxy->rdp_cookie_len = end-beg;
 
1758
                        }
 
1759
                        else if (*(args[1] + 10) == '\0') { /* default cookie name 'msts' */
 
1760
                                free(curproxy->rdp_cookie_name);
 
1761
                                curproxy->rdp_cookie_name = strdup("msts");
 
1762
                                curproxy->rdp_cookie_len = strlen(curproxy->rdp_cookie_name);
 
1763
                        }
 
1764
                        else { /* syntax */
 
1765
                                Alert("parsing [%s:%d] : persist rdp-cookie(name)' requires an rdp cookie name.\n",
 
1766
                                      file, linenum);
 
1767
                                err_code |= ERR_ALERT | ERR_FATAL;
 
1768
                                goto out;
 
1769
                        }
 
1770
                }
 
1771
                else {
 
1772
                        Alert("parsing [%s:%d] : unknown persist method.\n",
 
1773
                              file, linenum);
 
1774
                        err_code |= ERR_ALERT | ERR_FATAL;
 
1775
                        goto out;
 
1776
                }
 
1777
        }
1328
1778
        else if (!strcmp(args[0], "appsession")) {  /* cookie name */
 
1779
                int cur_arg;
 
1780
 
 
1781
                if (curproxy == &defproxy) {
 
1782
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
 
1783
                        err_code |= ERR_ALERT | ERR_FATAL;
 
1784
                        goto out;
 
1785
                }
1329
1786
 
1330
1787
                if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1331
1788
                        err_code |= ERR_WARN;
1332
1789
 
1333
1790
                if (*(args[5]) == 0) {
1334
 
                        Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
 
1791
                        Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout> [options*].\n",
1335
1792
                              file, linenum, args[0]);
1336
1793
                        err_code |= ERR_ALERT | ERR_FATAL;
1337
1794
                        goto out;
1355
1812
                        err_code |= ERR_ALERT | ERR_ABORT;
1356
1813
                        goto out;
1357
1814
                }
 
1815
 
 
1816
                cur_arg = 6;
 
1817
                curproxy->options2 &= ~PR_O2_AS_REQL;
 
1818
                curproxy->options2 &= ~PR_O2_AS_M_ANY;
 
1819
                curproxy->options2 |= PR_O2_AS_M_PP;
 
1820
                while (*(args[cur_arg])) {
 
1821
                        if (!strcmp(args[cur_arg], "request-learn")) {
 
1822
                                curproxy->options2 |= PR_O2_AS_REQL;
 
1823
                        } else if (!strcmp(args[cur_arg], "prefix")) {
 
1824
                                curproxy->options2 |= PR_O2_AS_PFX;
 
1825
                        } else if (!strcmp(args[cur_arg], "mode")) {
 
1826
                                if (!*args[cur_arg + 1]) {
 
1827
                                        Alert("parsing [%s:%d] : '%s': missing argument for '%s'.\n",
 
1828
                                              file, linenum, args[0], args[cur_arg]);
 
1829
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
1830
                                        goto out;
 
1831
                                }
 
1832
 
 
1833
                                cur_arg++;
 
1834
                                if (!strcmp(args[cur_arg], "query-string")) {
 
1835
                                        curproxy->options2 &= ~PR_O2_AS_M_ANY;
 
1836
                                        curproxy->options2 |= PR_O2_AS_M_QS;
 
1837
                                } else if (!strcmp(args[cur_arg], "path-parameters")) {
 
1838
                                        curproxy->options2 &= ~PR_O2_AS_M_ANY;
 
1839
                                        curproxy->options2 |= PR_O2_AS_M_PP;
 
1840
                                } else {
 
1841
                                        Alert("parsing [%s:%d] : unknown mode '%s'\n", file, linenum, args[cur_arg]);
 
1842
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
1843
                                        goto out;
 
1844
                                }
 
1845
                        }
 
1846
                        cur_arg++;
 
1847
                }
1358
1848
        } /* Url App Session */
1359
1849
        else if (!strcmp(args[0], "capture")) {
1360
1850
                if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
1361
1851
                        err_code |= ERR_WARN;
1362
1852
 
1363
1853
                if (!strcmp(args[1], "cookie")) {  /* name of a cookie to capture */
 
1854
                        if (curproxy == &defproxy) {
 
1855
                                Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
 
1856
                                err_code |= ERR_ALERT | ERR_FATAL;
 
1857
                                goto out;
 
1858
                        }
 
1859
 
1364
1860
                        if (*(args[4]) == 0) {
1365
1861
                                Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
1366
1862
                                      file, linenum, args[0]);
1449
1945
                }
1450
1946
                curproxy->conn_retries = atol(args[1]);
1451
1947
        }
 
1948
        else if (!strcmp(args[0], "http-request")) {    /* request access control: allow/deny/auth */
 
1949
                struct req_acl_rule *req_acl;
 
1950
 
 
1951
                if (curproxy == &defproxy) {
 
1952
                        Alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
 
1953
                        err_code |= ERR_ALERT | ERR_FATAL;
 
1954
                        goto out;
 
1955
                }
 
1956
 
 
1957
 
 
1958
                if (!LIST_ISEMPTY(&curproxy->req_acl) && !LIST_PREV(&curproxy->req_acl, struct req_acl_rule *, list)->cond) {
 
1959
                        Warning("parsing [%s:%d]: previous '%s' action has no condition attached, further entries are NOOP.\n",
 
1960
                                file, linenum, args[0]);
 
1961
                        err_code |= ERR_WARN;
 
1962
                }
 
1963
 
 
1964
                req_acl = parse_auth_cond((const char **)args + 1, file, linenum, curproxy);
 
1965
 
 
1966
                if (!req_acl) {
 
1967
                        err_code |= ERR_ALERT | ERR_ABORT;
 
1968
                        goto out;
 
1969
                }
 
1970
 
 
1971
                err_code |= warnif_cond_requires_resp(req_acl->cond, file, linenum);
 
1972
                LIST_ADDQ(&curproxy->req_acl, &req_acl->list);
 
1973
        }
1452
1974
        else if (!strcmp(args[0], "block")) {  /* early blocking based on ACLs */
1453
 
                int pol = ACL_COND_NONE;
1454
 
                struct acl_cond *cond;
1455
 
 
1456
1975
                if (curproxy == &defproxy) {
1457
1976
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1458
1977
                        err_code |= ERR_ALERT | ERR_FATAL;
1459
1978
                        goto out;
1460
1979
                }
1461
1980
 
1462
 
                if (!strcmp(args[1], "if"))
1463
 
                        pol = ACL_COND_IF;
1464
 
                else if (!strcmp(args[1], "unless"))
1465
 
                        pol = ACL_COND_UNLESS;
1466
 
 
1467
 
                if (pol == ACL_COND_NONE) {
 
1981
                if (strcmp(args[1], "if") != 0 && strcmp(args[1], "unless") != 0) {
1468
1982
                        Alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1469
1983
                              file, linenum, args[0]);
1470
1984
                        err_code |= ERR_ALERT | ERR_FATAL;
1471
1985
                        goto out;
1472
1986
                }
1473
1987
 
1474
 
                if ((cond = parse_acl_cond((const char **)args + 2, &curproxy->acl, pol)) == NULL) {
 
1988
                if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1)) == NULL) {
1475
1989
                        Alert("parsing [%s:%d] : error detected while parsing blocking condition.\n",
1476
1990
                              file, linenum);
1477
1991
                        err_code |= ERR_ALERT | ERR_FATAL;
1478
1992
                        goto out;
1479
1993
                }
1480
 
                cond->line = linenum;
 
1994
 
1481
1995
                LIST_ADDQ(&curproxy->block_cond, &cond->list);
1482
1996
                warnif_misplaced_block(curproxy, file, linenum, args[0]);
1483
1997
        }
1484
1998
        else if (!strcmp(args[0], "redirect")) {
1485
 
                int pol = ACL_COND_NONE;
1486
 
                struct acl_cond *cond;
1487
1999
                struct redirect_rule *rule;
1488
2000
                int cur_arg;
1489
2001
                int type = REDIRECT_TYPE_NONE;
1493
2005
                int cookie_set = 0;
1494
2006
                unsigned int flags = REDIRECT_FLAG_NONE;
1495
2007
 
 
2008
                if (curproxy == &defproxy) {
 
2009
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
 
2010
                        err_code |= ERR_ALERT | ERR_FATAL;
 
2011
                        goto out;
 
2012
                }
 
2013
 
1496
2014
                cur_arg = 1;
1497
2015
                while (*(args[cur_arg])) {
1498
2016
                        if (!strcmp(args[cur_arg], "location")) {
1562
2080
                        else if (!strcmp(args[cur_arg],"drop-query")) {
1563
2081
                                flags |= REDIRECT_FLAG_DROP_QS;
1564
2082
                        }
1565
 
                        else if (!strcmp(args[cur_arg], "if")) {
1566
 
                                pol = ACL_COND_IF;
1567
 
                                cur_arg++;
1568
 
                                break;
 
2083
                        else if (!strcmp(args[cur_arg],"append-slash")) {
 
2084
                                flags |= REDIRECT_FLAG_APPEND_SLASH;
1569
2085
                        }
1570
 
                        else if (!strcmp(args[cur_arg], "unless")) {
1571
 
                                pol = ACL_COND_UNLESS;
1572
 
                                cur_arg++;
 
2086
                        else if (strcmp(args[cur_arg], "if") == 0 ||
 
2087
                                 strcmp(args[cur_arg], "unless") == 0) {
 
2088
                                cond = build_acl_cond(file, linenum, curproxy, (const char **)args + cur_arg);
 
2089
                                if (!cond) {
 
2090
                                        Alert("parsing [%s:%d] : '%s': error detected while parsing redirect condition.\n",
 
2091
                                              file, linenum, args[0]);
 
2092
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
2093
                                        goto out;
 
2094
                                }
1573
2095
                                break;
1574
2096
                        }
1575
2097
                        else {
1576
 
                                Alert("parsing [%s:%d] : '%s' expects 'code', 'prefix' or 'location' (was '%s').\n",
 
2098
                                Alert("parsing [%s:%d] : '%s' expects 'code', 'prefix', 'location', 'set-cookie', 'clear-cookie', 'drop-query' or 'append-slash' (was '%s').\n",
1577
2099
                                      file, linenum, args[0], args[cur_arg]);
1578
2100
                                err_code |= ERR_ALERT | ERR_FATAL;
1579
2101
                                goto out;
1588
2110
                        goto out;
1589
2111
                }
1590
2112
 
1591
 
                if (pol == ACL_COND_NONE) {
1592
 
                        Alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1593
 
                              file, linenum, args[0]);
1594
 
                        err_code |= ERR_ALERT | ERR_FATAL;
1595
 
                        goto out;
1596
 
                }
1597
 
 
1598
 
                if ((cond = parse_acl_cond((const char **)args + cur_arg, &curproxy->acl, pol)) == NULL) {
1599
 
                        Alert("parsing [%s:%d] : '%s': error detected while parsing redirect condition.\n",
1600
 
                              file, linenum, args[0]);
1601
 
                        err_code |= ERR_ALERT | ERR_FATAL;
1602
 
                        goto out;
1603
 
                }
1604
 
 
1605
 
                cond->line = linenum;
1606
2113
                rule = (struct redirect_rule *)calloc(1, sizeof(*rule));
1607
2114
                rule->cond = cond;
1608
2115
                rule->rdr_str = strdup(destination);
1609
2116
                rule->rdr_len = strlen(destination);
1610
2117
                if (cookie) {
1611
2118
                        /* depending on cookie_set, either we want to set the cookie, or to clear it.
1612
 
                         * a clear consists in appending "; Max-Age=0" at the end.
 
2119
                         * a clear consists in appending "; path=/; Max-Age=0;" at the end.
1613
2120
                         */
1614
2121
                        rule->cookie_len = strlen(cookie);
1615
 
                        if (cookie_set)
1616
 
                                rule->cookie_str = strdup(cookie);
1617
 
                        else {
1618
 
                                rule->cookie_str = malloc(rule->cookie_len + 12);
1619
 
                                memcpy(rule->cookie_str, cookie, rule->cookie_len);
1620
 
                                memcpy(rule->cookie_str + rule->cookie_len, "; Max-Age=0", 12);
1621
 
                                rule->cookie_len += 11;
 
2122
                        if (cookie_set) {
 
2123
                                rule->cookie_str = malloc(rule->cookie_len + 10);
 
2124
                                memcpy(rule->cookie_str, cookie, rule->cookie_len);
 
2125
                                memcpy(rule->cookie_str + rule->cookie_len, "; path=/;", 10);
 
2126
                                rule->cookie_len += 9;
 
2127
                        } else {
 
2128
                                rule->cookie_str = malloc(rule->cookie_len + 21);
 
2129
                                memcpy(rule->cookie_str, cookie, rule->cookie_len);
 
2130
                                memcpy(rule->cookie_str + rule->cookie_len, "; path=/; Max-Age=0;", 21);
 
2131
                                rule->cookie_len += 20;
1622
2132
                        }
1623
2133
                }
1624
2134
                rule->type = type;
1629
2139
                warnif_rule_after_use_backend(curproxy, file, linenum, args[0]);
1630
2140
        }
1631
2141
        else if (!strcmp(args[0], "use_backend")) {
1632
 
                int pol = ACL_COND_NONE;
1633
 
                struct acl_cond *cond;
1634
2142
                struct switching_rule *rule;
1635
2143
 
1636
2144
                if (curproxy == &defproxy) {
1648
2156
                        goto out;
1649
2157
                }
1650
2158
 
1651
 
                if (!strcmp(args[2], "if"))
1652
 
                        pol = ACL_COND_IF;
1653
 
                else if (!strcmp(args[2], "unless"))
1654
 
                        pol = ACL_COND_UNLESS;
1655
 
 
1656
 
                if (pol == ACL_COND_NONE) {
 
2159
                if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
1657
2160
                        Alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
1658
2161
                              file, linenum, args[0]);
1659
2162
                        err_code |= ERR_ALERT | ERR_FATAL;
1660
2163
                        goto out;
1661
2164
                }
1662
2165
 
1663
 
                if ((cond = parse_acl_cond((const char **)args + 3, &curproxy->acl, pol)) == NULL) {
 
2166
                if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) {
1664
2167
                        Alert("parsing [%s:%d] : error detected while parsing switching rule.\n",
1665
2168
                              file, linenum);
1666
2169
                        err_code |= ERR_ALERT | ERR_FATAL;
1667
2170
                        goto out;
1668
2171
                }
1669
2172
 
1670
 
                cond->line = linenum;
1671
 
                if (cond->requires & ACL_USE_RTR_ANY) {
1672
 
                        struct acl *acl;
1673
 
                        const char *name;
1674
 
 
1675
 
                        acl = cond_find_require(cond, ACL_USE_RTR_ANY);
1676
 
                        name = acl ? acl->name : "(unknown)";
1677
 
                        Warning("parsing [%s:%d] : acl '%s' involves some response-only criteria which will be ignored.\n",
1678
 
                                file, linenum, name);
1679
 
                        err_code |= ERR_WARN;
1680
 
                }
 
2173
                err_code |= warnif_cond_requires_resp(cond, file, linenum);
1681
2174
 
1682
2175
                rule = (struct switching_rule *)calloc(1, sizeof(*rule));
1683
2176
                rule->cond = cond;
1685
2178
                LIST_INIT(&rule->list);
1686
2179
                LIST_ADDQ(&curproxy->switching_rules, &rule->list);
1687
2180
        }
 
2181
        else if (!strcmp(args[0], "force-persist")) {
 
2182
                struct force_persist_rule *rule;
 
2183
 
 
2184
                if (curproxy == &defproxy) {
 
2185
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
 
2186
                        err_code |= ERR_ALERT | ERR_FATAL;
 
2187
                        goto out;
 
2188
                }
 
2189
 
 
2190
                if (warnifnotcap(curproxy, PR_CAP_FE|PR_CAP_BE, file, linenum, args[0], NULL))
 
2191
                        err_code |= ERR_WARN;
 
2192
 
 
2193
                if (strcmp(args[1], "if") != 0 && strcmp(args[1], "unless") != 0) {
 
2194
                        Alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
 
2195
                              file, linenum, args[0]);
 
2196
                        err_code |= ERR_ALERT | ERR_FATAL;
 
2197
                        goto out;
 
2198
                }
 
2199
 
 
2200
                if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1)) == NULL) {
 
2201
                        Alert("parsing [%s:%d] : error detected while parsing a 'force-persist' rule.\n",
 
2202
                              file, linenum);
 
2203
                        err_code |= ERR_ALERT | ERR_FATAL;
 
2204
                        goto out;
 
2205
                }
 
2206
 
 
2207
                err_code |= warnif_cond_requires_resp(cond, file, linenum);
 
2208
 
 
2209
                rule = (struct force_persist_rule *)calloc(1, sizeof(*rule));
 
2210
                rule->cond = cond;
 
2211
                LIST_INIT(&rule->list);
 
2212
                LIST_ADDQ(&curproxy->force_persist_rules, &rule->list);
 
2213
        }
 
2214
        else if (!strcmp(args[0], "stick-table")) {
 
2215
                int myidx = 1;
 
2216
 
 
2217
                curproxy->table.type = (unsigned int)-1;
 
2218
                while (*args[myidx]) {
 
2219
                        const char *err;
 
2220
 
 
2221
                        if (strcmp(args[myidx], "size") == 0) {
 
2222
                                myidx++;
 
2223
                                if (!*(args[myidx])) {
 
2224
                                        Alert("parsing [%s:%d] : stick-table: missing argument after '%s'.\n",
 
2225
                                              file, linenum, args[myidx-1]);
 
2226
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
2227
                                        goto out;
 
2228
                                }
 
2229
                                if ((err = parse_size_err(args[myidx], &curproxy->table.size))) {
 
2230
                                        Alert("parsing [%s:%d] : stick-table: unexpected character '%c' in argument of '%s'.\n",
 
2231
                                              file, linenum, *err, args[myidx-1]);
 
2232
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
2233
                                        goto out;
 
2234
                                }
 
2235
                                myidx++;
 
2236
                        }
 
2237
                        else if (strcmp(args[myidx], "expire") == 0) {
 
2238
                                myidx++;
 
2239
                                if (!*(args[myidx])) {
 
2240
                                        Alert("parsing [%s:%d] : stick-table: missing argument after '%s'.\n",
 
2241
                                              file, linenum, args[myidx-1]);
 
2242
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
2243
                                        goto out;
 
2244
                                }
 
2245
                                err = parse_time_err(args[myidx], &val, TIME_UNIT_MS);
 
2246
                                if (err) {
 
2247
                                        Alert("parsing [%s:%d] : stick-table: unexpected character '%c' in argument of '%s'.\n",
 
2248
                                              file, linenum, *err, args[myidx-1]);
 
2249
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
2250
                                        goto out;
 
2251
                                }
 
2252
                                curproxy->table.expire = val;
 
2253
                                myidx++;
 
2254
                        }
 
2255
                        else if (strcmp(args[myidx], "nopurge") == 0) {
 
2256
                                curproxy->table.nopurge = 1;
 
2257
                                myidx++;
 
2258
                        }
 
2259
                        else if (strcmp(args[myidx], "type") == 0) {
 
2260
                                myidx++;
 
2261
                                if (stktable_parse_type(args, &myidx, &curproxy->table.type, &curproxy->table.key_size) != 0) {
 
2262
                                        Alert("parsing [%s:%d] : stick-table: unknown type '%s'.\n",
 
2263
                                              file, linenum, args[myidx]);
 
2264
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
2265
                                        goto out;
 
2266
                                }
 
2267
                                /* myidx already points to next arg */
 
2268
                        }
 
2269
                        else {
 
2270
                                Alert("parsing [%s:%d] : stick-table: unknown argument '%s'.\n",
 
2271
                                      file, linenum, args[myidx]);
 
2272
                                err_code |= ERR_ALERT | ERR_FATAL;
 
2273
                                goto out;
 
2274
                        }
 
2275
                }
 
2276
 
 
2277
                if (!curproxy->table.size) {
 
2278
                        Alert("parsing [%s:%d] : stick-table: missing size.\n",
 
2279
                               file, linenum);
 
2280
                        err_code |= ERR_ALERT | ERR_FATAL;
 
2281
                        goto out;
 
2282
                }
 
2283
 
 
2284
                if (curproxy->table.type == (unsigned int)-1) {
 
2285
                        Alert("parsing [%s:%d] : stick-table: missing type.\n",
 
2286
                               file, linenum);
 
2287
                        err_code |= ERR_ALERT | ERR_FATAL;
 
2288
                        goto out;
 
2289
                }
 
2290
        }
 
2291
        else if (!strcmp(args[0], "stick")) {
 
2292
                struct sticking_rule *rule;
 
2293
                struct pattern_expr *expr;
 
2294
                int myidx = 0;
 
2295
                const char *name = NULL;
 
2296
                int flags;
 
2297
 
 
2298
                if (curproxy == &defproxy) {
 
2299
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
 
2300
                        err_code |= ERR_ALERT | ERR_FATAL;
 
2301
                        goto out;
 
2302
                }
 
2303
 
 
2304
                if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) {
 
2305
                        err_code |= ERR_WARN;
 
2306
                        goto out;
 
2307
                }
 
2308
 
 
2309
                myidx++;
 
2310
                if ((strcmp(args[myidx], "store") == 0) ||
 
2311
                    (strcmp(args[myidx], "store-request") == 0)) {
 
2312
                        myidx++;
 
2313
                        flags = STK_IS_STORE;
 
2314
                }
 
2315
                else if (strcmp(args[myidx], "store-response") == 0) {
 
2316
                        myidx++;
 
2317
                        flags = STK_IS_STORE | STK_ON_RSP;
 
2318
                }
 
2319
                else if (strcmp(args[myidx], "match") == 0) {
 
2320
                        myidx++;
 
2321
                        flags = STK_IS_MATCH;
 
2322
                }
 
2323
                else if (strcmp(args[myidx], "on") == 0) {
 
2324
                        myidx++;
 
2325
                        flags = STK_IS_MATCH | STK_IS_STORE;
 
2326
                }
 
2327
                else {
 
2328
                        Alert("parsing [%s:%d] : '%s' expects 'on', 'match', or 'store'.\n", file, linenum, args[0]);
 
2329
                        err_code |= ERR_ALERT | ERR_FATAL;
 
2330
                        goto out;
 
2331
                }
 
2332
 
 
2333
                if (*(args[myidx]) == 0) {
 
2334
                        Alert("parsing [%s:%d] : '%s' expects a fetch method.\n", file, linenum, args[0]);
 
2335
                        err_code |= ERR_ALERT | ERR_FATAL;
 
2336
                        goto out;
 
2337
                }
 
2338
 
 
2339
                expr = pattern_parse_expr(args, &myidx);
 
2340
                if (!expr) {
 
2341
                        Alert("parsing [%s:%d] : '%s': unknown fetch method '%s'.\n", file, linenum, args[0], args[myidx]);
 
2342
                        err_code |= ERR_ALERT | ERR_FATAL;
 
2343
                        goto out;
 
2344
                }
 
2345
 
 
2346
                if (flags & STK_ON_RSP) {
 
2347
                        if (!(expr->fetch->dir & PATTERN_FETCH_RTR)) {
 
2348
                                Alert("parsing [%s:%d] : '%s': fetch method '%s' can not be used on response.\n",
 
2349
                                      file, linenum, args[0], expr->fetch->kw);
 
2350
                                err_code |= ERR_ALERT | ERR_FATAL;
 
2351
                                goto out;
 
2352
                        }
 
2353
                } else {
 
2354
                        if (!(expr->fetch->dir & PATTERN_FETCH_REQ)) {
 
2355
                                Alert("parsing [%s:%d] : '%s': fetch method '%s' can not be used on request.\n",
 
2356
                                      file, linenum, args[0], expr->fetch->kw);
 
2357
                                err_code |= ERR_ALERT | ERR_FATAL;
 
2358
                                goto out;
 
2359
                        }
 
2360
                }
 
2361
 
 
2362
                if (strcmp(args[myidx], "table") == 0) {
 
2363
                        myidx++;
 
2364
                        name = args[myidx++];
 
2365
                }
 
2366
 
 
2367
                if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) {
 
2368
                        if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + myidx)) == NULL) {
 
2369
                                Alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition.\n",
 
2370
                                      file, linenum, args[0]);
 
2371
                                err_code |= ERR_ALERT | ERR_FATAL;
 
2372
                                goto out;
 
2373
                        }
 
2374
                }
 
2375
                else if (*(args[myidx])) {
 
2376
                        Alert("parsing [%s:%d] : '%s': unknown keyword '%s'.\n",
 
2377
                              file, linenum, args[0], args[myidx]);
 
2378
                        err_code |= ERR_ALERT | ERR_FATAL;
 
2379
                        goto out;
 
2380
                }
 
2381
 
 
2382
                err_code |= warnif_cond_requires_resp(cond, file, linenum);
 
2383
 
 
2384
                rule = (struct sticking_rule *)calloc(1, sizeof(*rule));
 
2385
                rule->cond = cond;
 
2386
                rule->expr = expr;
 
2387
                rule->flags = flags;
 
2388
                rule->table.name = name ? strdup(name) : NULL;
 
2389
                LIST_INIT(&rule->list);
 
2390
                if (flags & STK_ON_RSP)
 
2391
                        LIST_ADDQ(&curproxy->storersp_rules, &rule->list);
 
2392
                else
 
2393
                        LIST_ADDQ(&curproxy->sticking_rules, &rule->list);
 
2394
        }
1688
2395
        else if (!strcmp(args[0], "stats")) {
1689
2396
                if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1690
2397
                        err_code |= ERR_WARN;
1692
2399
                if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
1693
2400
                        curproxy->uri_auth = NULL; /* we must detach from the default config */
1694
2401
 
1695
 
                if (*(args[1]) == 0) {
1696
 
                        Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable', 'hide-version', 'show-node', 'show-desc'.\n", file, linenum, args[0]);
1697
 
                        err_code |= ERR_ALERT | ERR_FATAL;
1698
 
                        goto out;
 
2402
                if (!*args[1]) {
 
2403
                        goto stats_error_parsing;
1699
2404
                } else if (!strcmp(args[1], "uri")) {
1700
2405
                        if (*(args[2]) == 0) {
1701
2406
                                Alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
1730
2435
                                err_code |= ERR_ALERT | ERR_ABORT;
1731
2436
                                goto out;
1732
2437
                        }
 
2438
                } else if (!strcmp(args[1], "http-request")) {    /* request access control: allow/deny/auth */
 
2439
                        struct req_acl_rule *req_acl;
 
2440
 
 
2441
                        if (curproxy == &defproxy) {
 
2442
                                Alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
 
2443
                                err_code |= ERR_ALERT | ERR_FATAL;
 
2444
                                goto out;
 
2445
                        }
 
2446
 
 
2447
                        if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
 
2448
                                Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
 
2449
                                err_code |= ERR_ALERT | ERR_ABORT;
 
2450
                                goto out;
 
2451
                        }
 
2452
 
 
2453
                        if (!LIST_ISEMPTY(&curproxy->uri_auth->req_acl) &&
 
2454
                            !LIST_PREV(&curproxy->uri_auth->req_acl, struct req_acl_rule *, list)->cond) {
 
2455
                                Warning("parsing [%s:%d]: previous '%s' action has no condition attached, further entries are NOOP.\n",
 
2456
                                        file, linenum, args[0]);
 
2457
                                err_code |= ERR_WARN;
 
2458
                        }
 
2459
 
 
2460
                        req_acl = parse_auth_cond((const char **)args + 2, file, linenum, curproxy);
 
2461
 
 
2462
                        if (!req_acl) {
 
2463
                                err_code |= ERR_ALERT | ERR_ABORT;
 
2464
                                goto out;
 
2465
                        }
 
2466
 
 
2467
                        err_code |= warnif_cond_requires_resp(req_acl->cond, file, linenum);
 
2468
                        LIST_ADDQ(&curproxy->uri_auth->req_acl, &req_acl->list);
 
2469
 
1733
2470
                } else if (!strcmp(args[1], "auth")) {
1734
2471
                        if (*(args[2]) == 0) {
1735
2472
                                Alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
1762
2499
                                err_code |= ERR_ALERT | ERR_ABORT;
1763
2500
                                goto out;
1764
2501
                        }
 
2502
                } else if (!strcmp(args[1], "show-legends")) {
 
2503
                        if (!stats_set_flag(&curproxy->uri_auth, ST_SHLGNDS)) {
 
2504
                                Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
 
2505
                                err_code |= ERR_ALERT | ERR_ABORT;
 
2506
                                goto out;
 
2507
                        }
1765
2508
                } else if (!strcmp(args[1], "show-node")) {
1766
2509
 
1767
2510
                        if (*args[2]) {
1770
2513
 
1771
2514
                                for (i=0; args[2][i]; i++) {
1772
2515
                                        c = args[2][i];
1773
 
                                        if (!isupper(c) && !islower(c) && !isdigit(c) && c != '_' && c != '-' && c != '.')
 
2516
                                        if (!isupper((unsigned char)c) && !islower((unsigned char)c) &&
 
2517
                                            !isdigit((unsigned char)c) && c != '_' && c != '-' && c != '.')
1774
2518
                                                break;
1775
2519
                                }
1776
2520
 
1818
2562
                                free(desc);
1819
2563
                        }
1820
2564
                } else {
1821
 
                        Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'hide-version', 'uri', 'realm', 'auth' or 'enable').\n",
1822
 
                              file, linenum, args[0]);
 
2565
stats_error_parsing:
 
2566
                        Alert("parsing [%s:%d]: %s '%s', expects 'uri', 'realm', 'auth', 'scope', 'enable', 'hide-version', 'show-node', 'show-desc' or 'show-legends'.\n",
 
2567
                              file, linenum, *args[1]?"unknown stats parameter":"missing keyword in", args[*args[1]?1:0]);
1823
2568
                        err_code |= ERR_ALERT | ERR_FATAL;
1824
2569
                        goto out;
1825
2570
                }
1841
2586
                                        goto out;
1842
2587
                                }
1843
2588
 
1844
 
                                if (!inv)
 
2589
                                curproxy->no_options &= ~cfg_opts[optnum].val;
 
2590
                                curproxy->options    &= ~cfg_opts[optnum].val;
 
2591
 
 
2592
                                switch (kwm) {
 
2593
                                case KWM_STD:
1845
2594
                                        curproxy->options |= cfg_opts[optnum].val;
1846
 
                                else
1847
 
                                        curproxy->options &= ~cfg_opts[optnum].val;
 
2595
                                        break;
 
2596
                                case KWM_NO:
 
2597
                                        curproxy->no_options |= cfg_opts[optnum].val;
 
2598
                                        break;
 
2599
                                case KWM_DEF: /* already cleared */
 
2600
                                        break;
 
2601
                                }
1848
2602
 
1849
2603
                                goto out;
1850
2604
                        }
1857
2611
                                        goto out;
1858
2612
                                }
1859
2613
 
1860
 
                                if (!inv)
 
2614
                                curproxy->no_options2 &= ~cfg_opts2[optnum].val;
 
2615
                                curproxy->options2    &= ~cfg_opts2[optnum].val;
 
2616
 
 
2617
                                switch (kwm) {
 
2618
                                case KWM_STD:
1861
2619
                                        curproxy->options2 |= cfg_opts2[optnum].val;
1862
 
                                else
1863
 
                                        curproxy->options2 &= ~cfg_opts2[optnum].val;
1864
 
 
 
2620
                                        break;
 
2621
                                case KWM_NO:
 
2622
                                        curproxy->no_options2 |= cfg_opts2[optnum].val;
 
2623
                                        break;
 
2624
                                case KWM_DEF: /* already cleared */
 
2625
                                        break;
 
2626
                                }
1865
2627
                                goto out;
1866
2628
                        }
1867
2629
                }
1868
2630
 
1869
 
                if (inv) {
1870
 
                        Alert("parsing [%s:%d]: negation is not supported for option '%s'.\n",
 
2631
                if (kwm != KWM_STD) {
 
2632
                        Alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
1871
2633
                                file, linenum, args[1]);
1872
2634
                        err_code |= ERR_ALERT | ERR_FATAL;
1873
2635
                        goto out;
1874
2636
                }
1875
2637
 
1876
 
                if (!strcmp(args[1], "httplog"))
 
2638
                if (!strcmp(args[1], "httplog")) {
1877
2639
                        /* generate a complete HTTP log */
 
2640
                        curproxy->options2 &= ~PR_O2_CLFLOG;
1878
2641
                        curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
 
2642
                        if (*(args[2]) != '\0') {
 
2643
                                if (!strcmp(args[2], "clf")) {
 
2644
                                        curproxy->options2 |= PR_O2_CLFLOG;
 
2645
                                } else {
 
2646
                                        Alert("parsing [%s:%d] : keyword '%s' only supports option 'clf'.\n", file, linenum, args[2]);
 
2647
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
2648
                                        goto out;
 
2649
                                }
 
2650
                        }
 
2651
                }
1879
2652
                else if (!strcmp(args[1], "tcplog"))
1880
2653
                        /* generate a detailed TCP log */
1881
2654
                        curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
1895
2668
 
1896
2669
                        /* use HTTP request to check servers' health */
1897
2670
                        free(curproxy->check_req);
1898
 
                        curproxy->options &= ~PR_O_SSL3_CHK;
 
2671
                        curproxy->check_req = NULL;
1899
2672
                        curproxy->options &= ~PR_O_SMTP_CHK;
 
2673
                        curproxy->options2 &= ~PR_O2_SSL3_CHK;
 
2674
                        curproxy->options2 &= ~PR_O2_MYSQL_CHK;
1900
2675
                        curproxy->options |= PR_O_HTTP_CHK;
1901
2676
                        if (!*args[2]) { /* no argument */
1902
2677
                                curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
1903
2678
                                curproxy->check_len = strlen(DEF_CHECK_REQ);
1904
2679
                        } else if (!*args[3]) { /* one argument : URI */
1905
 
                                int reqlen = strlen(args[2]) + strlen("OPTIONS  HTTP/1.0\r\n\r\n") + 1;
 
2680
                                int reqlen = strlen(args[2]) + strlen("OPTIONS  HTTP/1.0\r\n") + 1;
1906
2681
                                curproxy->check_req = (char *)malloc(reqlen);
1907
2682
                                curproxy->check_len = snprintf(curproxy->check_req, reqlen,
1908
 
                                                               "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
 
2683
                                                               "OPTIONS %s HTTP/1.0\r\n", args[2]); /* URI to use */
1909
2684
                        } else { /* more arguments : METHOD URI [HTTP_VER] */
1910
 
                                int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
 
2685
                                int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n");
1911
2686
                                if (*args[4])
1912
2687
                                        reqlen += strlen(args[4]);
1913
2688
                                else
1915
2690
                    
1916
2691
                                curproxy->check_req = (char *)malloc(reqlen);
1917
2692
                                curproxy->check_len = snprintf(curproxy->check_req, reqlen,
1918
 
                                                               "%s %s %s\r\n\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
 
2693
                                                               "%s %s %s\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
1919
2694
                        }
1920
2695
                }
1921
2696
                else if (!strcmp(args[1], "ssl-hello-chk")) {
1924
2699
                                err_code |= ERR_WARN;
1925
2700
 
1926
2701
                        free(curproxy->check_req);
 
2702
                        curproxy->check_req = NULL;
1927
2703
                        curproxy->options &= ~PR_O_HTTP_CHK;
1928
2704
                        curproxy->options &= ~PR_O_SMTP_CHK;
1929
 
                        curproxy->options |= PR_O_SSL3_CHK;
 
2705
                        curproxy->options2 &= ~PR_O2_MYSQL_CHK;
 
2706
                        curproxy->options2 |= PR_O2_SSL3_CHK;
1930
2707
                }
1931
2708
                else if (!strcmp(args[1], "smtpchk")) {
1932
2709
                        /* use SMTP request to check servers' health */
1933
2710
                        free(curproxy->check_req);
 
2711
                        curproxy->check_req = NULL;
1934
2712
                        curproxy->options &= ~PR_O_HTTP_CHK;
1935
 
                        curproxy->options &= ~PR_O_SSL3_CHK;
 
2713
                        curproxy->options2 &= ~PR_O2_SSL3_CHK;
 
2714
                        curproxy->options2 &= ~PR_O2_MYSQL_CHK;
1936
2715
                        curproxy->options |= PR_O_SMTP_CHK;
1937
2716
 
1938
2717
                        if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */
1952
2731
                                }
1953
2732
                        }
1954
2733
                }
 
2734
                else if (!strcmp(args[1], "mysql-check")) {
 
2735
                        /* use MYSQL request to check servers' health */
 
2736
                        free(curproxy->check_req);
 
2737
                        curproxy->check_req = NULL;
 
2738
                        curproxy->options &= ~PR_O_HTTP_CHK;
 
2739
                        curproxy->options &= ~PR_O_SMTP_CHK;
 
2740
                        curproxy->options2 &= ~PR_O2_SSL3_CHK;
 
2741
                        curproxy->options2 |= PR_O2_MYSQL_CHK;
 
2742
                }
1955
2743
                else if (!strcmp(args[1], "forwardfor")) {
1956
2744
                        int cur_arg;
1957
2745
 
2085
2873
                        /* enable a graceful server shutdown on an HTTP 404 response */
2086
2874
                        curproxy->options |= PR_O_DISABLE404;
2087
2875
                }
 
2876
                else if (strcmp(args[1], "send-state") == 0) {
 
2877
                        /* enable emission of the apparent state of a server in HTTP checks */
 
2878
                        curproxy->options2 |= PR_O2_CHK_SNDST;
 
2879
                }
2088
2880
                else {
2089
2881
                        Alert("parsing [%s:%d] : '%s' only supports 'disable-on-404'.\n", file, linenum, args[0]);
2090
2882
                        err_code |= ERR_ALERT | ERR_FATAL;
2103
2895
 
2104
2896
                if (strcmp(args[1], "fail") == 0) {
2105
2897
                        /* add a condition to fail monitor requests */
2106
 
                        int pol = ACL_COND_NONE;
2107
 
                        struct acl_cond *cond;
2108
 
 
2109
 
                        if (!strcmp(args[2], "if"))
2110
 
                                pol = ACL_COND_IF;
2111
 
                        else if (!strcmp(args[2], "unless"))
2112
 
                                pol = ACL_COND_UNLESS;
2113
 
 
2114
 
                        if (pol == ACL_COND_NONE) {
 
2898
                        if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
2115
2899
                                Alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
2116
2900
                                      file, linenum, args[0], args[1]);
2117
2901
                                err_code |= ERR_ALERT | ERR_FATAL;
2118
2902
                                goto out;
2119
2903
                        }
2120
2904
 
2121
 
                        if ((cond = parse_acl_cond((const char **)args + 3, &curproxy->acl, pol)) == NULL) {
 
2905
                        if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) {
2122
2906
                                Alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition.\n",
2123
2907
                                      file, linenum, args[0], args[1]);
2124
2908
                                err_code |= ERR_ALERT | ERR_FATAL;
2125
2909
                                goto out;
2126
2910
                        }
2127
 
                        cond->line = linenum;
2128
2911
                        LIST_ADDQ(&curproxy->mon_fail_cond, &cond->list);
2129
2912
                }
2130
2913
                else {
2188
2971
                curproxy->grace = val;
2189
2972
        }
2190
2973
        else if (!strcmp(args[0], "dispatch")) {  /* dispatch address */
 
2974
                struct sockaddr_in *sk;
2191
2975
                if (curproxy == &defproxy) {
2192
2976
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2193
2977
                        err_code |= ERR_ALERT | ERR_FATAL;
2201
2985
                        err_code |= ERR_ALERT | ERR_FATAL;
2202
2986
                        goto out;
2203
2987
                }
2204
 
                curproxy->dispatch_addr = *str2sa(args[1]);
 
2988
                sk = str2sa(args[1]);
 
2989
                if (!sk) {
 
2990
                        Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[1]);
 
2991
                        err_code |= ERR_ALERT | ERR_FATAL;
 
2992
                        goto out;
 
2993
                }
 
2994
                curproxy->dispatch_addr = *sk;
2205
2995
        }
2206
2996
        else if (!strcmp(args[0], "balance")) {  /* set balancing with optional algorithm */
2207
2997
                if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2214
3004
                        goto out;
2215
3005
                }
2216
3006
        }
2217
 
        else if (!strcmp(args[0], "server")) {  /* server address */
 
3007
        else if (!strcmp(args[0], "hash-type")) { /* set hashing method */
 
3008
                if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
 
3009
                        err_code |= ERR_WARN;
 
3010
 
 
3011
                if (strcmp(args[1], "consistent") == 0) {       /* use consistent hashing */
 
3012
                        curproxy->lbprm.algo &= ~BE_LB_HASH_TYPE;
 
3013
                        curproxy->lbprm.algo |= BE_LB_HASH_CONS;
 
3014
                }
 
3015
                else if (strcmp(args[1], "map-based") == 0) {   /* use map-based hashing */
 
3016
                        curproxy->lbprm.algo &= ~BE_LB_HASH_TYPE;
 
3017
                        curproxy->lbprm.algo |= BE_LB_HASH_MAP;
 
3018
                }
 
3019
                else {
 
3020
                        Alert("parsing [%s:%d] : '%s' only supports 'consistent' and 'map-based'.\n", file, linenum, args[0]);
 
3021
                        err_code |= ERR_ALERT | ERR_FATAL;
 
3022
                        goto out;
 
3023
                }
 
3024
        }
 
3025
        else if (!strcmp(args[0], "server") || !strcmp(args[0], "default-server")) {  /* server address */
2218
3026
                int cur_arg;
2219
 
                char *rport;
2220
 
                char *raddr;
2221
 
                short realport;
2222
 
                int do_check;
 
3027
                char *rport, *raddr;
 
3028
                short realport = 0;
 
3029
                int do_check = 0, defsrv = (*args[0] == 'd');
2223
3030
 
2224
 
                if (curproxy == &defproxy) {
 
3031
                if (!defsrv && curproxy == &defproxy) {
2225
3032
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2226
3033
                        err_code |= ERR_ALERT | ERR_FATAL;
2227
3034
                        goto out;
2244
3051
                        goto out;
2245
3052
                }
2246
3053
 
2247
 
                if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
2248
 
                        Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
2249
 
                        err_code |= ERR_ALERT | ERR_ABORT;
2250
 
                        goto out;
2251
 
                }
2252
 
 
2253
 
                /* the servers are linked backwards first */
2254
 
                newsrv->next = curproxy->srv;
2255
 
                curproxy->srv = newsrv;
2256
 
                newsrv->proxy = curproxy;
2257
 
                newsrv->puid = curproxy->next_svid++;
2258
 
 
2259
 
                LIST_INIT(&newsrv->pendconns);
2260
 
                do_check = 0;
2261
 
                newsrv->state = SRV_RUNNING; /* early server setup */
2262
 
                newsrv->last_change = now.tv_sec;
2263
 
                newsrv->id = strdup(args[1]);
2264
 
 
2265
 
                /* several ways to check the port component :
2266
 
                 *  - IP    => port=+0, relative
2267
 
                 *  - IP:   => port=+0, relative
2268
 
                 *  - IP:N  => port=N, absolute
2269
 
                 *  - IP:+N => port=+N, relative
2270
 
                 *  - IP:-N => port=-N, relative
2271
 
                 */
2272
 
                raddr = strdup(args[2]);
2273
 
                rport = strchr(raddr, ':');
2274
 
                if (rport) {
2275
 
                        *rport++ = 0;
2276
 
                        realport = atol(rport);
2277
 
                        if (!isdigit((unsigned char)*rport))
 
3054
                if (!defsrv) {
 
3055
                        struct sockaddr_in *sk;
 
3056
 
 
3057
                        if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
 
3058
                                Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
 
3059
                                err_code |= ERR_ALERT | ERR_ABORT;
 
3060
                                goto out;
 
3061
                        }
 
3062
 
 
3063
                        /* the servers are linked backwards first */
 
3064
                        newsrv->next = curproxy->srv;
 
3065
                        curproxy->srv = newsrv;
 
3066
                        newsrv->proxy = curproxy;
 
3067
                        newsrv->conf.file = file;
 
3068
                        newsrv->conf.line = linenum;
 
3069
 
 
3070
                        LIST_INIT(&newsrv->pendconns);
 
3071
                        do_check = 0;
 
3072
                        newsrv->state = SRV_RUNNING; /* early server setup */
 
3073
                        newsrv->last_change = now.tv_sec;
 
3074
                        newsrv->id = strdup(args[1]);
 
3075
 
 
3076
                        /* several ways to check the port component :
 
3077
                         *  - IP    => port=+0, relative
 
3078
                         *  - IP:   => port=+0, relative
 
3079
                         *  - IP:N  => port=N, absolute
 
3080
                         *  - IP:+N => port=+N, relative
 
3081
                         *  - IP:-N => port=-N, relative
 
3082
                         */
 
3083
                        raddr = strdup(args[2]);
 
3084
                        rport = strchr(raddr, ':');
 
3085
                        if (rport) {
 
3086
                                *rport++ = 0;
 
3087
                                realport = atol(rport);
 
3088
                                if (!isdigit((unsigned char)*rport))
 
3089
                                        newsrv->state |= SRV_MAPPORTS;
 
3090
                        } else
2278
3091
                                newsrv->state |= SRV_MAPPORTS;
 
3092
 
 
3093
                        sk = str2sa(raddr);
 
3094
                        free(raddr);
 
3095
                        if (!sk) {
 
3096
                                Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[2]);
 
3097
                                err_code |= ERR_ALERT | ERR_FATAL;
 
3098
                                goto out;
 
3099
                        }
 
3100
                        newsrv->addr = *sk;
 
3101
                        newsrv->addr.sin_port = htons(realport);
 
3102
 
 
3103
                        newsrv->check_port      = curproxy->defsrv.check_port;
 
3104
                        newsrv->inter           = curproxy->defsrv.inter;
 
3105
                        newsrv->fastinter       = curproxy->defsrv.fastinter;
 
3106
                        newsrv->downinter       = curproxy->defsrv.downinter;
 
3107
                        newsrv->rise            = curproxy->defsrv.rise;
 
3108
                        newsrv->fall            = curproxy->defsrv.fall;
 
3109
                        newsrv->maxqueue        = curproxy->defsrv.maxqueue;
 
3110
                        newsrv->minconn         = curproxy->defsrv.minconn;
 
3111
                        newsrv->maxconn         = curproxy->defsrv.maxconn;
 
3112
                        newsrv->slowstart       = curproxy->defsrv.slowstart;
 
3113
                        newsrv->onerror         = curproxy->defsrv.onerror;
 
3114
                        newsrv->consecutive_errors_limit
 
3115
                                                = curproxy->defsrv.consecutive_errors_limit;
 
3116
                        newsrv->uweight = newsrv->iweight
 
3117
                                                = curproxy->defsrv.iweight;
 
3118
 
 
3119
                        newsrv->curfd = -1;             /* no health-check in progress */
 
3120
                        newsrv->health = newsrv->rise;  /* up, but will fall down at first failure */
 
3121
 
 
3122
                        cur_arg = 3;
2279
3123
                } else {
2280
 
                        realport = 0;
2281
 
                        newsrv->state |= SRV_MAPPORTS;
2282
 
                }           
2283
 
 
2284
 
                newsrv->addr = *str2sa(raddr);
2285
 
                newsrv->addr.sin_port = htons(realport);
2286
 
                free(raddr);
2287
 
 
2288
 
                newsrv->curfd = -1; /* no health-check in progress */
2289
 
                newsrv->inter = DEF_CHKINTR;
2290
 
                newsrv->fastinter = 0;          /* 0 => use newsrv->inter instead */
2291
 
                newsrv->downinter = 0;          /* 0 => use newsrv->inter instead */
2292
 
                newsrv->rise = DEF_RISETIME;
2293
 
                newsrv->fall = DEF_FALLTIME;
2294
 
                newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
2295
 
                newsrv->uweight = 1;
2296
 
                newsrv->maxqueue = 0;
2297
 
                newsrv->slowstart = 0;
2298
 
 
2299
 
                cur_arg = 3;
 
3124
                        newsrv = &curproxy->defsrv;
 
3125
                        cur_arg = 1;
 
3126
                }
 
3127
 
2300
3128
                while (*args[cur_arg]) {
2301
 
                        if (!strcmp(args[cur_arg], "id")) {
2302
 
                                struct server *target;
 
3129
                        if (!defsrv && !strcmp(args[cur_arg], "id")) {
 
3130
                                struct eb32_node *node;
2303
3131
 
2304
3132
                                if (!*args[cur_arg + 1]) {
2305
3133
                                        Alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
2309
3137
                                }
2310
3138
 
2311
3139
                                newsrv->puid = atol(args[cur_arg + 1]);
 
3140
                                newsrv->conf.id.key = newsrv->puid;
2312
3141
 
2313
 
                                if (newsrv->puid< 1001) {
2314
 
                                        Alert("parsing [%s:%d]: custom id has to be > 1000.\n",
 
3142
                                if (newsrv->puid <= 0) {
 
3143
                                        Alert("parsing [%s:%d]: custom id has to be > 0.\n",
2315
3144
                                                file, linenum);
2316
3145
                                        err_code |= ERR_ALERT | ERR_FATAL;
2317
3146
                                        goto out;
2318
3147
                                }
2319
3148
 
2320
 
                                for (target = proxy->srv; target; target = target->next)
2321
 
                                        if (newsrv != target && newsrv->puid == target->puid) {
2322
 
                                                Alert("parsing [%s:%d]: custom id has to be unique but is duplicated in %s and %s.\n",
2323
 
                                                        file, linenum, newsrv->id, target->id);
2324
 
                                                err_code |= ERR_ALERT | ERR_FATAL;
2325
 
                                                goto out;
2326
 
                                        }
 
3149
                                node = eb32_lookup(&curproxy->conf.used_server_id, newsrv->puid);
 
3150
                                if (node) {
 
3151
                                        struct server *target = container_of(node, struct server, conf.id);
 
3152
                                        Alert("parsing [%s:%d]: server %s reuses same custom id as server %s (declared at %s:%d).\n",
 
3153
                                              file, linenum, newsrv->id, target->id, target->conf.file, target->conf.line);
 
3154
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
3155
                                        goto out;
 
3156
                                }
 
3157
                                eb32_insert(&curproxy->conf.used_server_id, &newsrv->conf.id);
2327
3158
                                cur_arg += 2;
2328
3159
                        }
2329
 
                        else if (!strcmp(args[cur_arg], "cookie")) {
 
3160
                        else if (!defsrv && !strcmp(args[cur_arg], "cookie")) {
2330
3161
                                newsrv->cookie = strdup(args[cur_arg + 1]);
2331
3162
                                newsrv->cklen = strlen(args[cur_arg + 1]);
2332
3163
                                cur_arg += 2;
2333
3164
                        }
2334
 
                        else if (!strcmp(args[cur_arg], "redir")) {
 
3165
                        else if (!defsrv && !strcmp(args[cur_arg], "redir")) {
2335
3166
                                newsrv->rdr_pfx = strdup(args[cur_arg + 1]);
2336
3167
                                newsrv->rdr_len = strlen(args[cur_arg + 1]);
2337
3168
                                cur_arg += 2;
2352
3183
                                        goto out;
2353
3184
                                }
2354
3185
 
2355
 
                                newsrv->health = newsrv->rise;
 
3186
                                if (newsrv->health)
 
3187
                                        newsrv->health = newsrv->rise;
2356
3188
                                cur_arg += 2;
2357
3189
                        }
2358
3190
                        else if (!strcmp(args[cur_arg], "fall")) {
2425
3257
                                newsrv->downinter = val;
2426
3258
                                cur_arg += 2;
2427
3259
                        }
2428
 
                        else if (!strcmp(args[cur_arg], "addr")) {
2429
 
                                newsrv->check_addr = *str2sa(args[cur_arg + 1]);
 
3260
                        else if (!defsrv && !strcmp(args[cur_arg], "addr")) {
 
3261
                                struct sockaddr_in *sk = str2sa(args[cur_arg + 1]);
 
3262
                                if (!sk) {
 
3263
                                        Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[cur_arg + 1]);
 
3264
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
3265
                                        goto out;
 
3266
                                }
 
3267
                                newsrv->check_addr = *sk;
2430
3268
                                cur_arg += 2;
2431
3269
                        }
2432
3270
                        else if (!strcmp(args[cur_arg], "port")) {
2433
3271
                                newsrv->check_port = atol(args[cur_arg + 1]);
2434
3272
                                cur_arg += 2;
2435
3273
                        }
2436
 
                        else if (!strcmp(args[cur_arg], "backup")) {
 
3274
                        else if (!defsrv && !strcmp(args[cur_arg], "backup")) {
2437
3275
                                newsrv->state |= SRV_BACKUP;
2438
3276
                                cur_arg ++;
2439
3277
                        }
2446
3284
                                        err_code |= ERR_ALERT | ERR_FATAL;
2447
3285
                                        goto out;
2448
3286
                                }
2449
 
                                newsrv->uweight = w;
 
3287
                                newsrv->uweight = newsrv->iweight = w;
2450
3288
                                cur_arg += 2;
2451
3289
                        }
2452
3290
                        else if (!strcmp(args[cur_arg], "minconn")) {
2470
3308
                                        err_code |= ERR_ALERT | ERR_FATAL;
2471
3309
                                        goto out;
2472
3310
                                }
2473
 
                                if (val <= 0) {
 
3311
                                if (val < 0) {
2474
3312
                                        Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n",
2475
3313
                                              file, linenum, val, args[cur_arg], newsrv->id);
2476
3314
                                        err_code |= ERR_ALERT | ERR_FATAL;
2479
3317
                                newsrv->slowstart = (val + 999) / 1000;
2480
3318
                                cur_arg += 2;
2481
3319
                        }
2482
 
                        else if (!strcmp(args[cur_arg], "track")) {
 
3320
                        else if (!defsrv && !strcmp(args[cur_arg], "track")) {
2483
3321
 
2484
3322
                                if (!*args[cur_arg + 1]) {
2485
3323
                                        Alert("parsing [%s:%d]: 'track' expects [<proxy>/]<server> as argument.\n",
2492
3330
 
2493
3331
                                cur_arg += 2;
2494
3332
                        }
2495
 
                        else if (!strcmp(args[cur_arg], "check")) {
 
3333
                        else if (!defsrv && !strcmp(args[cur_arg], "check")) {
2496
3334
                                global.maxsock++;
2497
3335
                                do_check = 1;
2498
3336
                                cur_arg += 1;
2499
3337
                        }
2500
 
                        else if (!strcmp(args[cur_arg], "source")) {  /* address to which we bind when connecting */
 
3338
                        else if (!defsrv && !strcmp(args[cur_arg], "disabled")) {
 
3339
                                newsrv->state |= SRV_MAINTAIN;
 
3340
                                newsrv->state &= ~SRV_RUNNING;
 
3341
                                newsrv->health = 0;
 
3342
                                cur_arg += 1;
 
3343
                        }
 
3344
                        else if (!defsrv && !strcmp(args[cur_arg], "observe")) {
 
3345
                                if (!strcmp(args[cur_arg + 1], "none"))
 
3346
                                        newsrv->observe = HANA_OBS_NONE;
 
3347
                                else if (!strcmp(args[cur_arg + 1], "layer4"))
 
3348
                                        newsrv->observe = HANA_OBS_LAYER4;
 
3349
                                else if (!strcmp(args[cur_arg + 1], "layer7")) {
 
3350
                                        if (curproxy->mode != PR_MODE_HTTP) {
 
3351
                                                Alert("parsing [%s:%d]: '%s' can only be used in http proxies.\n",
 
3352
                                                        file, linenum, args[cur_arg + 1]);
 
3353
                                                err_code |= ERR_ALERT;
 
3354
                                        }
 
3355
                                        newsrv->observe = HANA_OBS_LAYER7;
 
3356
                                }
 
3357
                                else {
 
3358
                                        Alert("parsing [%s:%d]: '%s' expects one of 'none', "
 
3359
                                                "'l4events', 'http-responses' but get '%s'\n",
 
3360
                                                file, linenum, args[cur_arg], args[cur_arg + 1]);
 
3361
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
3362
                                        goto out;
 
3363
                                }
 
3364
 
 
3365
                                cur_arg += 2;
 
3366
                        }
 
3367
                        else if (!strcmp(args[cur_arg], "on-error")) {
 
3368
                                if (!strcmp(args[cur_arg + 1], "fastinter"))
 
3369
                                        newsrv->onerror = HANA_ONERR_FASTINTER;
 
3370
                                else if (!strcmp(args[cur_arg + 1], "fail-check"))
 
3371
                                        newsrv->onerror = HANA_ONERR_FAILCHK;
 
3372
                                else if (!strcmp(args[cur_arg + 1], "sudden-death"))
 
3373
                                        newsrv->onerror = HANA_ONERR_SUDDTH;
 
3374
                                else if (!strcmp(args[cur_arg + 1], "mark-down"))
 
3375
                                        newsrv->onerror = HANA_ONERR_MARKDWN;
 
3376
                                else {
 
3377
                                        Alert("parsing [%s:%d]: '%s' expects one of 'fastinter', "
 
3378
                                                "'fail-check', 'sudden-death' or 'mark-down' but get '%s'\n",
 
3379
                                                file, linenum, args[cur_arg], args[cur_arg + 1]);
 
3380
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
3381
                                        goto out;
 
3382
                                }
 
3383
 
 
3384
                                cur_arg += 2;
 
3385
                        }
 
3386
                        else if (!strcmp(args[cur_arg], "error-limit")) {
 
3387
                                if (!*args[cur_arg + 1]) {
 
3388
                                        Alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
 
3389
                                                file, linenum, args[cur_arg]);
 
3390
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
3391
                                        goto out;
 
3392
                                }
 
3393
 
 
3394
                                newsrv->consecutive_errors_limit = atoi(args[cur_arg + 1]);
 
3395
 
 
3396
                                if (newsrv->consecutive_errors_limit <= 0) {
 
3397
                                        Alert("parsing [%s:%d]: %s has to be > 0.\n",
 
3398
                                                file, linenum, args[cur_arg]);
 
3399
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
3400
                                        goto out;
 
3401
                                }
 
3402
                                cur_arg += 2;
 
3403
                        }
 
3404
                        else if (!defsrv && !strcmp(args[cur_arg], "source")) {  /* address to which we bind when connecting */
2501
3405
                                int port_low, port_high;
 
3406
                                struct sockaddr_in *sk;
 
3407
 
2502
3408
                                if (!*args[cur_arg + 1]) {
2503
3409
#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
2504
3410
                                        Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>[-<port>]], and optional '%s' <addr> as argument.\n",
2511
3417
                                        goto out;
2512
3418
                                }
2513
3419
                                newsrv->state |= SRV_BIND_SRC;
2514
 
                                newsrv->source_addr = *str2sa_range(args[cur_arg + 1], &port_low, &port_high);
 
3420
                                sk = str2sa_range(args[cur_arg + 1], &port_low, &port_high);
 
3421
                                if (!sk) {
 
3422
                                        Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[cur_arg + 1]);
 
3423
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
3424
                                        goto out;
 
3425
                                }
 
3426
                                newsrv->source_addr = *sk;
2515
3427
 
2516
3428
                                if (port_low != port_high) {
2517
3429
                                        int i;
2541
3453
                                                }
2542
3454
#endif
2543
3455
                                                if (!*args[cur_arg + 1]) {
2544
 
                                                        Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
 
3456
                                                        Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', 'clientip', or 'hdr_ip(name,#)' as argument.\n",
2545
3457
                                                              file, linenum, "usesrc");
2546
3458
                                                        err_code |= ERR_ALERT | ERR_FATAL;
2547
3459
                                                        goto out;
2548
3460
                                                }
2549
3461
                                                if (!strcmp(args[cur_arg + 1], "client")) {
 
3462
                                                        newsrv->state &= ~SRV_TPROXY_MASK;
2550
3463
                                                        newsrv->state |= SRV_TPROXY_CLI;
2551
3464
                                                } else if (!strcmp(args[cur_arg + 1], "clientip")) {
 
3465
                                                        newsrv->state &= ~SRV_TPROXY_MASK;
2552
3466
                                                        newsrv->state |= SRV_TPROXY_CIP;
 
3467
                                                } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
 
3468
                                                        char *name, *end;
 
3469
 
 
3470
                                                        name = args[cur_arg+1] + 7;
 
3471
                                                        while (isspace(*name))
 
3472
                                                                name++;
 
3473
 
 
3474
                                                        end = name;
 
3475
                                                        while (*end && !isspace(*end) && *end != ',' && *end != ')')
 
3476
                                                                end++;
 
3477
 
 
3478
                                                        newsrv->state &= ~SRV_TPROXY_MASK;
 
3479
                                                        newsrv->state |= SRV_TPROXY_DYN;
 
3480
                                                        newsrv->bind_hdr_name = calloc(1, end - name + 1);
 
3481
                                                        newsrv->bind_hdr_len = end - name;
 
3482
                                                        memcpy(newsrv->bind_hdr_name, name, end - name);
 
3483
                                                        newsrv->bind_hdr_name[end-name] = '\0';
 
3484
                                                        newsrv->bind_hdr_occ = -1;
 
3485
 
 
3486
                                                        /* now look for an occurrence number */
 
3487
                                                        while (isspace(*end))
 
3488
                                                                end++;
 
3489
                                                        if (*end == ',') {
 
3490
                                                                end++;
 
3491
                                                                name = end;
 
3492
                                                                if (*end == '-')
 
3493
                                                                        end++;
 
3494
                                                                while (isdigit(*end))
 
3495
                                                                        end++;
 
3496
                                                                newsrv->bind_hdr_occ = strl2ic(name, end-name);
 
3497
                                                        }
 
3498
 
 
3499
                                                        if (newsrv->bind_hdr_occ < -MAX_HDR_HISTORY) {
 
3500
                                                                Alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
 
3501
                                                                      " occurrences values smaller than %d.\n",
 
3502
                                                                      file, linenum, MAX_HDR_HISTORY);
 
3503
                                                                err_code |= ERR_ALERT | ERR_FATAL;
 
3504
                                                                goto out;
 
3505
                                                        }
2553
3506
                                                } else {
 
3507
                                                        struct sockaddr_in *sk = str2sa(args[cur_arg + 1]);
 
3508
                                                        if (!sk) {
 
3509
                                                                Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[cur_arg + 1]);
 
3510
                                                                err_code |= ERR_ALERT | ERR_FATAL;
 
3511
                                                                goto out;
 
3512
                                                        }
 
3513
                                                        newsrv->tproxy_addr = *sk;
2554
3514
                                                        newsrv->state |= SRV_TPROXY_ADDR;
2555
 
                                                        newsrv->tproxy_addr = *str2sa(args[cur_arg + 1]);
2556
3515
                                                }
2557
3516
                                                global.last_checks |= LSTCHK_NETADM;
2558
3517
#if !defined(CONFIG_HAP_LINUX_TPROXY)
2595
3554
                                        break;
2596
3555
                                } /* while */
2597
3556
                        }
2598
 
                        else if (!strcmp(args[cur_arg], "usesrc")) {  /* address to use outside: needs "source" first */
 
3557
                        else if (!defsrv && !strcmp(args[cur_arg], "usesrc")) {  /* address to use outside: needs "source" first */
2599
3558
                                Alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
2600
3559
                                      file, linenum, "usesrc", "source");
2601
3560
                                err_code |= ERR_ALERT | ERR_FATAL;
2602
3561
                                goto out;
2603
3562
                        }
2604
3563
                        else {
2605
 
                                Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'redir', 'check', 'track', 'id', 'inter', 'fastinter', 'downinter', 'rise', 'fall', 'addr', 'port', 'source', 'minconn', 'maxconn', 'maxqueue', 'slowstart' and 'weight'.\n",
2606
 
                                      file, linenum, newsrv->id);
 
3564
                                if (!defsrv)
 
3565
                                        Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'redir', 'observer', 'on-error', 'error-limit', 'check', 'disabled', 'track', 'id', 'inter', 'fastinter', 'downinter', 'rise', 'fall', 'addr', 'port', 'source', 'minconn', 'maxconn', 'maxqueue', 'slowstart' and 'weight'.\n",
 
3566
                                              file, linenum, newsrv->id);
 
3567
                                else
 
3568
                                        Alert("parsing [%s:%d]: default-server only supports options 'on-error', 'error-limit', 'inter', 'fastinter', 'downinter', 'rise', 'fall', 'port', 'minconn', 'maxconn', 'maxqueue', 'slowstart' and 'weight'.\n",
 
3569
                                              file, linenum);
 
3570
 
2607
3571
                                err_code |= ERR_ALERT | ERR_FATAL;
2608
3572
                                goto out;
2609
3573
                        }
2643
3607
                                err_code |= ERR_ALERT | ERR_FATAL;
2644
3608
                                goto out;
2645
3609
                        }
 
3610
 
 
3611
                        /* Allocate buffer for partial check results... */
 
3612
                        if ((newsrv->check_data = calloc(BUFSIZE, sizeof(char))) == NULL) {
 
3613
                                Alert("parsing [%s:%d] : out of memory while allocating check buffer.\n", file, linenum);
 
3614
                                err_code |= ERR_ALERT | ERR_ABORT;
 
3615
                                goto out;
 
3616
                        }
 
3617
 
 
3618
                        newsrv->check_status = HCHK_STATUS_INI;
2646
3619
                        newsrv->state |= SRV_CHECKED;
2647
3620
                }
2648
3621
 
2649
 
                if (newsrv->state & SRV_BACKUP)
2650
 
                        curproxy->srv_bck++;
2651
 
                else
2652
 
                        curproxy->srv_act++;
 
3622
                if (!defsrv) {
 
3623
                        if (newsrv->state & SRV_BACKUP)
 
3624
                                curproxy->srv_bck++;
 
3625
                        else
 
3626
                                curproxy->srv_act++;
2653
3627
 
2654
 
                newsrv->prev_state = newsrv->state;
 
3628
                        newsrv->prev_state = newsrv->state;
 
3629
                }
2655
3630
        }
2656
3631
        else if (!strcmp(args[0], "log")) {  /* syslog server address */
2657
3632
                struct logsrv logsrv;
2695
3670
                        }
2696
3671
 
2697
3672
                        if (args[1][0] == '/') {
 
3673
                                struct sockaddr_un *sk = str2sun(args[1]);
 
3674
                                if (!sk) {
 
3675
                                        Alert("parsing [%s:%d] : Socket path '%s' too long (max %d)\n", file, linenum,
 
3676
                                              args[1], (int)sizeof(sk->sun_path) - 1);
 
3677
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
3678
                                        goto out;
 
3679
                                }
 
3680
                                logsrv.u.un = *sk;
2698
3681
                                logsrv.u.addr.sa_family = AF_UNIX;
2699
 
                                logsrv.u.un = *str2sun(args[1]);
2700
3682
                        } else {
 
3683
                                struct sockaddr_in *sk = str2sa(args[1]);
 
3684
                                if (!sk) {
 
3685
                                        Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[1]);
 
3686
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
3687
                                        goto out;
 
3688
                                }
 
3689
                                logsrv.u.in = *sk;
2701
3690
                                logsrv.u.addr.sa_family = AF_INET;
2702
 
                                logsrv.u.in = *str2sa(args[1]);
2703
3691
                                if (!logsrv.u.in.sin_port) {
2704
3692
                                        logsrv.u.in.sin_port =
2705
3693
                                                htons(SYSLOG_PORT);
2733
3721
        }
2734
3722
        else if (!strcmp(args[0], "source")) {  /* address to which we bind when connecting */
2735
3723
                int cur_arg;
 
3724
                struct sockaddr_in *sk;
2736
3725
 
2737
3726
                if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
2738
3727
                        err_code |= ERR_WARN;
2750
3739
                curproxy->iface_name = NULL;
2751
3740
                curproxy->iface_len = 0;
2752
3741
 
2753
 
                curproxy->source_addr = *str2sa(args[1]);
 
3742
                sk = str2sa(args[1]);
 
3743
                if (!sk) {
 
3744
                        Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[1]);
 
3745
                        err_code |= ERR_ALERT | ERR_FATAL;
 
3746
                        goto out;
 
3747
                }
 
3748
                curproxy->source_addr = *sk;
2754
3749
                curproxy->options |= PR_O_BIND_SRC;
2755
3750
 
2756
3751
                cur_arg = 2;
2773
3768
                                }
2774
3769
 
2775
3770
                                if (!strcmp(args[cur_arg + 1], "client")) {
 
3771
                                        curproxy->options &= ~PR_O_TPXY_MASK;
2776
3772
                                        curproxy->options |= PR_O_TPXY_CLI;
2777
3773
                                } else if (!strcmp(args[cur_arg + 1], "clientip")) {
 
3774
                                        curproxy->options &= ~PR_O_TPXY_MASK;
2778
3775
                                        curproxy->options |= PR_O_TPXY_CIP;
 
3776
                                } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
 
3777
                                        char *name, *end;
 
3778
 
 
3779
                                        name = args[cur_arg+1] + 7;
 
3780
                                        while (isspace(*name))
 
3781
                                                name++;
 
3782
 
 
3783
                                        end = name;
 
3784
                                        while (*end && !isspace(*end) && *end != ',' && *end != ')')
 
3785
                                                end++;
 
3786
 
 
3787
                                        curproxy->options &= ~PR_O_TPXY_MASK;
 
3788
                                        curproxy->options |= PR_O_TPXY_DYN;
 
3789
                                        curproxy->bind_hdr_name = calloc(1, end - name + 1);
 
3790
                                        curproxy->bind_hdr_len = end - name;
 
3791
                                        memcpy(curproxy->bind_hdr_name, name, end - name);
 
3792
                                        curproxy->bind_hdr_name[end-name] = '\0';
 
3793
                                        curproxy->bind_hdr_occ = -1;
 
3794
 
 
3795
                                        /* now look for an occurrence number */
 
3796
                                        while (isspace(*end))
 
3797
                                                end++;
 
3798
                                        if (*end == ',') {
 
3799
                                                end++;
 
3800
                                                name = end;
 
3801
                                                if (*end == '-')
 
3802
                                                        end++;
 
3803
                                                while (isdigit(*end))
 
3804
                                                        end++;
 
3805
                                                curproxy->bind_hdr_occ = strl2ic(name, end-name);
 
3806
                                        }
 
3807
 
 
3808
                                        if (curproxy->bind_hdr_occ < -MAX_HDR_HISTORY) {
 
3809
                                                Alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
 
3810
                                                      " occurrences values smaller than %d.\n",
 
3811
                                                      file, linenum, MAX_HDR_HISTORY);
 
3812
                                                err_code |= ERR_ALERT | ERR_FATAL;
 
3813
                                                goto out;
 
3814
                                        }
2779
3815
                                } else {
 
3816
                                        struct sockaddr_in *sk = str2sa(args[cur_arg + 1]);
 
3817
                                        if (!sk) {
 
3818
                                                Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[cur_arg + 1]);
 
3819
                                                err_code |= ERR_ALERT | ERR_FATAL;
 
3820
                                                goto out;
 
3821
                                        }
 
3822
                                        curproxy->tproxy_addr = *sk;
2780
3823
                                        curproxy->options |= PR_O_TPXY_ADDR;
2781
 
                                        curproxy->tproxy_addr = *str2sa(args[cur_arg + 1]);
2782
3824
                                }
2783
3825
                                global.last_checks |= LSTCHK_NETADM;
2784
3826
#if !defined(CONFIG_HAP_LINUX_TPROXY)
2830
3872
                goto out;
2831
3873
        }
2832
3874
        else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) {  /* replace request header from a regex */
2833
 
                regex_t *preg;
2834
 
                if (curproxy == &defproxy) {
2835
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2836
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2837
 
                        goto out;
2838
 
                }
2839
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2840
 
                        err_code |= ERR_WARN;
2841
 
 
2842
 
                if (*(args[1]) == 0 || *(args[2]) == 0) {
 
3875
                if (*(args[2]) == 0) {
2843
3876
                        Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
2844
3877
                              file, linenum, args[0]);
2845
3878
                        err_code |= ERR_ALERT | ERR_FATAL;
2846
3879
                        goto out;
2847
3880
                }
2848
 
        
2849
 
                preg = calloc(1, sizeof(regex_t));
2850
 
                if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
2851
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2852
 
                        err_code |= ERR_ALERT | ERR_FATAL;
 
3881
 
 
3882
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3883
                                                   ACL_DIR_REQ, ACT_REPLACE, 0,
 
3884
                                                   args[0], args[1], args[2], (const char **)args+3);
 
3885
                if (err_code & ERR_FATAL)
2853
3886
                        goto out;
2854
 
                }
2855
 
        
2856
 
                err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
2857
 
                if (err) {
2858
 
                        Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
2859
 
                              file, linenum, *err);
2860
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2861
 
                }
2862
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
2863
3887
        }
2864
3888
        else if (!strcmp(args[0], "reqdel")) {  /* delete request header from a regex */
2865
 
                regex_t *preg;
2866
 
                if (curproxy == &defproxy) {
2867
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2868
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2869
 
                        goto out;
2870
 
                }
2871
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2872
 
                        err_code |= ERR_WARN;
2873
 
 
2874
 
                if (*(args[1]) == 0) {
2875
 
                        Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
2876
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2877
 
                        goto out;
2878
 
                }
2879
 
        
2880
 
                preg = calloc(1, sizeof(regex_t));
2881
 
                if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
2882
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2883
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2884
 
                        goto out;
2885
 
                }
2886
 
        
2887
 
                chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
2888
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3889
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3890
                                                   ACL_DIR_REQ, ACT_REMOVE, 0,
 
3891
                                                   args[0], args[1], NULL, (const char **)args+2);
 
3892
                if (err_code & ERR_FATAL)
 
3893
                        goto out;
2889
3894
        }
2890
3895
        else if (!strcmp(args[0], "reqdeny")) {  /* deny a request if a header matches this regex */
2891
 
                regex_t *preg;
2892
 
                if (curproxy == &defproxy) {
2893
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2894
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2895
 
                        goto out;
2896
 
                }
2897
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2898
 
                        err_code |= ERR_WARN;
2899
 
 
2900
 
                if (*(args[1]) == 0) {
2901
 
                        Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
2902
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2903
 
                        goto out;
2904
 
                }
2905
 
        
2906
 
                preg = calloc(1, sizeof(regex_t));
2907
 
                if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
2908
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2909
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2910
 
                        goto out;
2911
 
                }
2912
 
        
2913
 
                chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
2914
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3896
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3897
                                                   ACL_DIR_REQ, ACT_DENY, 0,
 
3898
                                                   args[0], args[1], NULL, (const char **)args+2);
 
3899
                if (err_code & ERR_FATAL)
 
3900
                        goto out;
2915
3901
        }
2916
3902
        else if (!strcmp(args[0], "reqpass")) {  /* pass this header without allowing or denying the request */
2917
 
                regex_t *preg;
2918
 
                if (curproxy == &defproxy) {
2919
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2920
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2921
 
                        goto out;
2922
 
                }
2923
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2924
 
                        err_code |= ERR_WARN;
2925
 
 
2926
 
                if (*(args[1]) == 0) {
2927
 
                        Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
2928
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2929
 
                        goto out;
2930
 
                }
2931
 
        
2932
 
                preg = calloc(1, sizeof(regex_t));
2933
 
                if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
2934
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2935
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2936
 
                        goto out;
2937
 
                }
2938
 
        
2939
 
                chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
2940
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3903
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3904
                                                   ACL_DIR_REQ, ACT_PASS, 0,
 
3905
                                                   args[0], args[1], NULL, (const char **)args+2);
 
3906
                if (err_code & ERR_FATAL)
 
3907
                        goto out;
2941
3908
        }
2942
3909
        else if (!strcmp(args[0], "reqallow")) {  /* allow a request if a header matches this regex */
2943
 
                regex_t *preg;
2944
 
                if (curproxy == &defproxy) {
2945
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2946
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2947
 
                        goto out;
2948
 
                }
2949
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2950
 
                        err_code |= ERR_WARN;
2951
 
 
2952
 
                if (*(args[1]) == 0) {
2953
 
                        Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
2954
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2955
 
                        goto out;
2956
 
                }
2957
 
        
2958
 
                preg = calloc(1, sizeof(regex_t));
2959
 
                if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
2960
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2961
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2962
 
                        goto out;
2963
 
                }
2964
 
        
2965
 
                chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
2966
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3910
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3911
                                                   ACL_DIR_REQ, ACT_ALLOW, 0,
 
3912
                                                   args[0], args[1], NULL, (const char **)args+2);
 
3913
                if (err_code & ERR_FATAL)
 
3914
                        goto out;
2967
3915
        }
2968
3916
        else if (!strcmp(args[0], "reqtarpit")) {  /* tarpit a request if a header matches this regex */
2969
 
                regex_t *preg;
2970
 
                if (curproxy == &defproxy) {
2971
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2972
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2973
 
                        goto out;
2974
 
                }
2975
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
2976
 
                        err_code |= ERR_WARN;
2977
 
 
2978
 
                if (*(args[1]) == 0) {
2979
 
                        Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
2980
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2981
 
                        goto out;
2982
 
                }
2983
 
        
2984
 
                preg = calloc(1, sizeof(regex_t));
2985
 
                if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
2986
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
2987
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2988
 
                        goto out;
2989
 
                }
2990
 
        
2991
 
                chain_regex(&curproxy->req_exp, preg, ACT_TARPIT, NULL);
2992
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3917
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3918
                                                   ACL_DIR_REQ, ACT_TARPIT, 0,
 
3919
                                                   args[0], args[1], NULL, (const char **)args+2);
 
3920
                if (err_code & ERR_FATAL)
 
3921
                        goto out;
2993
3922
        }
2994
3923
        else if (!strcmp(args[0], "reqsetbe")) { /* switch the backend from a regex, respecting case */
2995
 
                regex_t *preg;
2996
 
                if (curproxy == &defproxy) {
2997
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
2998
 
                        err_code |= ERR_ALERT | ERR_FATAL;
2999
 
                        goto out;
3000
 
                }
3001
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3002
 
                        err_code |= ERR_WARN;
3003
 
 
3004
 
                if (*(args[1]) == 0 || *(args[2]) == 0) {
3005
 
                        Alert("parsing [%s:%d] : '%s' expects <search> and <target> as arguments.\n", 
3006
 
                                file, linenum, args[0]);
3007
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3008
 
                        goto out;
3009
 
                }
3010
 
                
3011
 
                preg = calloc(1, sizeof(regex_t));
3012
 
                if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3013
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3014
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3015
 
                        goto out;
3016
 
                }
3017
 
 
3018
 
                chain_regex(&curproxy->req_exp, preg, ACT_SETBE, strdup(args[2]));
3019
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3924
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3925
                                                   ACL_DIR_REQ, ACT_SETBE, 0,
 
3926
                                                   args[0], args[1], args[2], (const char **)args+3);
 
3927
                if (err_code & ERR_FATAL)
 
3928
                        goto out;
3020
3929
        }
3021
3930
        else if (!strcmp(args[0], "reqisetbe")) { /* switch the backend from a regex, ignoring case */
3022
 
                regex_t *preg;
3023
 
                if (curproxy == &defproxy) {
3024
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3025
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3026
 
                        goto out;
3027
 
                }
3028
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3029
 
                        err_code |= ERR_WARN;
3030
 
 
3031
 
                if (*(args[1]) == 0 || *(args[2]) == 0) {
3032
 
                        Alert("parsing [%s:%d] : '%s' expects <search> and <target> as arguments.\n", 
3033
 
                              file, linenum, args[0]);
3034
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3035
 
                        goto out;
3036
 
                }
3037
 
                
3038
 
                preg = calloc(1, sizeof(regex_t));
3039
 
                if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
3040
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3041
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3042
 
                        goto out;
3043
 
                }
3044
 
 
3045
 
                chain_regex(&curproxy->req_exp, preg, ACT_SETBE, strdup(args[2]));
3046
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3931
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3932
                                                   ACL_DIR_REQ, ACT_SETBE, REG_ICASE,
 
3933
                                                   args[0], args[1], args[2], (const char **)args+3);
 
3934
                if (err_code & ERR_FATAL)
 
3935
                        goto out;
3047
3936
        }
3048
3937
        else if (!strcmp(args[0], "reqirep")) {  /* replace request header from a regex, ignoring case */
3049
 
                regex_t *preg;
3050
 
                if (curproxy == &defproxy) {
3051
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3052
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3053
 
                        goto out;
3054
 
                }
3055
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3056
 
                        err_code |= ERR_WARN;
3057
 
 
3058
 
                if (*(args[1]) == 0 || *(args[2]) == 0) {
 
3938
                if (*(args[2]) == 0) {
3059
3939
                        Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3060
3940
                              file, linenum, args[0]);
3061
3941
                        err_code |= ERR_ALERT | ERR_FATAL;
3062
3942
                        goto out;
3063
3943
                }
3064
 
        
3065
 
                preg = calloc(1, sizeof(regex_t));
3066
 
                if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
3067
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3068
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3069
 
                        goto out;
3070
 
                }
3071
 
        
3072
 
                err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
3073
 
                if (err) {
3074
 
                        Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
3075
 
                              file, linenum, *err);
3076
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3077
 
                        goto out;
3078
 
                }
3079
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3944
 
 
3945
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3946
                                                   ACL_DIR_REQ, ACT_REPLACE, REG_ICASE,
 
3947
                                                   args[0], args[1], args[2], (const char **)args+3);
 
3948
                if (err_code & ERR_FATAL)
 
3949
                        goto out;
3080
3950
        }
3081
3951
        else if (!strcmp(args[0], "reqidel")) {  /* delete request header from a regex ignoring case */
3082
 
                regex_t *preg;
3083
 
                if (curproxy == &defproxy) {
3084
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3085
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3086
 
                        goto out;
3087
 
                }
3088
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3089
 
                        err_code |= ERR_WARN;
3090
 
 
3091
 
                if (*(args[1]) == 0) {
3092
 
                        Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
3093
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3094
 
                        goto out;
3095
 
                }
3096
 
        
3097
 
                preg = calloc(1, sizeof(regex_t));
3098
 
                if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
3099
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3100
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3101
 
                        goto out;
3102
 
                }
3103
 
        
3104
 
                chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
3105
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3952
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3953
                                                   ACL_DIR_REQ, ACT_REMOVE, REG_ICASE,
 
3954
                                                   args[0], args[1], NULL, (const char **)args+2);
 
3955
                if (err_code & ERR_FATAL)
 
3956
                        goto out;
3106
3957
        }
3107
3958
        else if (!strcmp(args[0], "reqideny")) {  /* deny a request if a header matches this regex ignoring case */
3108
 
                regex_t *preg;
3109
 
                if (curproxy == &defproxy) {
3110
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3111
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3112
 
                        goto out;
3113
 
                }
3114
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3115
 
                        err_code |= ERR_WARN;
3116
 
 
3117
 
                if (*(args[1]) == 0) {
3118
 
                        Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
3119
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3120
 
                        goto out;
3121
 
                }
3122
 
        
3123
 
                preg = calloc(1, sizeof(regex_t));
3124
 
                if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
3125
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3126
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3127
 
                        goto out;
3128
 
                }
3129
 
        
3130
 
                chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
3131
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3959
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3960
                                                   ACL_DIR_REQ, ACT_DENY, REG_ICASE,
 
3961
                                                   args[0], args[1], NULL, (const char **)args+2);
 
3962
                if (err_code & ERR_FATAL)
 
3963
                        goto out;
3132
3964
        }
3133
3965
        else if (!strcmp(args[0], "reqipass")) {  /* pass this header without allowing or denying the request */
3134
 
                regex_t *preg;
3135
 
                if (curproxy == &defproxy) {
3136
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3137
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3138
 
                        goto out;
3139
 
                }
3140
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3141
 
                        err_code |= ERR_WARN;
3142
 
 
3143
 
                if (*(args[1]) == 0) {
3144
 
                        Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
3145
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3146
 
                        goto out;
3147
 
                }
3148
 
        
3149
 
                preg = calloc(1, sizeof(regex_t));
3150
 
                if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
3151
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3152
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3153
 
                        goto out;
3154
 
                }
3155
 
        
3156
 
                chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
3157
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3966
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3967
                                                   ACL_DIR_REQ, ACT_PASS, REG_ICASE,
 
3968
                                                   args[0], args[1], NULL, (const char **)args+2);
 
3969
                if (err_code & ERR_FATAL)
 
3970
                        goto out;
3158
3971
        }
3159
3972
        else if (!strcmp(args[0], "reqiallow")) {  /* allow a request if a header matches this regex ignoring case */
3160
 
                regex_t *preg;
3161
 
                if (curproxy == &defproxy) {
3162
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3163
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3164
 
                        goto out;
3165
 
                }
3166
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3167
 
                        err_code |= ERR_WARN;
3168
 
 
3169
 
                if (*(args[1]) == 0) {
3170
 
                        Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
3171
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3172
 
                        goto out;
3173
 
                }
3174
 
        
3175
 
                preg = calloc(1, sizeof(regex_t));
3176
 
                if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
3177
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3178
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3179
 
                        goto out;
3180
 
                }
3181
 
        
3182
 
                chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
3183
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3973
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3974
                                                   ACL_DIR_REQ, ACT_ALLOW, REG_ICASE,
 
3975
                                                   args[0], args[1], NULL, (const char **)args+2);
 
3976
                if (err_code & ERR_FATAL)
 
3977
                        goto out;
3184
3978
        }
3185
3979
        else if (!strcmp(args[0], "reqitarpit")) {  /* tarpit a request if a header matches this regex ignoring case */
3186
 
                regex_t *preg;
3187
 
                if (curproxy == &defproxy) {
3188
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3189
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3190
 
                        goto out;
3191
 
                }
3192
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3193
 
                        err_code |= ERR_WARN;
3194
 
 
3195
 
                if (*(args[1]) == 0) {
3196
 
                        Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
3197
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3198
 
                        goto out;
3199
 
                }
3200
 
        
3201
 
                preg = calloc(1, sizeof(regex_t));
3202
 
                if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
3203
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3204
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3205
 
                        goto out;
3206
 
                }
3207
 
        
3208
 
                chain_regex(&curproxy->req_exp, preg, ACT_TARPIT, NULL);
3209
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
3980
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
3981
                                                   ACL_DIR_REQ, ACT_TARPIT, REG_ICASE,
 
3982
                                                   args[0], args[1], NULL, (const char **)args+2);
 
3983
                if (err_code & ERR_FATAL)
 
3984
                        goto out;
3210
3985
        }
3211
3986
        else if (!strcmp(args[0], "reqadd")) {  /* add request header */
 
3987
                struct cond_wordlist *wl;
 
3988
 
3212
3989
                if (curproxy == &defproxy) {
3213
3990
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3214
3991
                        err_code |= ERR_ALERT | ERR_FATAL;
3217
3994
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3218
3995
                        err_code |= ERR_WARN;
3219
3996
 
3220
 
                if (curproxy->nb_reqadd >= MAX_NEWHDR) {
3221
 
                        Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
3222
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3223
 
                        goto out;
3224
 
                }
3225
 
        
3226
3997
                if (*(args[1]) == 0) {
3227
3998
                        Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
3228
3999
                        err_code |= ERR_ALERT | ERR_FATAL;
3229
4000
                        goto out;
3230
4001
                }
3231
 
        
3232
 
                curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
 
4002
 
 
4003
                if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
 
4004
                        if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2)) == NULL) {
 
4005
                                Alert("parsing [%s:%d] : error detected while parsing a '%s' condition.\n",
 
4006
                                      file, linenum, args[0]);
 
4007
                                err_code |= ERR_ALERT | ERR_FATAL;
 
4008
                                goto out;
 
4009
                        }
 
4010
                        err_code |= warnif_cond_requires_resp(cond, file, linenum);
 
4011
                }
 
4012
                else if (*args[2]) {
 
4013
                        Alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
 
4014
                              file, linenum, args[0], args[2]);
 
4015
                        err_code |= ERR_ALERT | ERR_FATAL;
 
4016
                        goto out;
 
4017
                }
 
4018
 
 
4019
                wl = calloc(1, sizeof(*wl));
 
4020
                wl->cond = cond;
 
4021
                wl->s = strdup(args[1]);
 
4022
                LIST_ADDQ(&curproxy->req_add, &wl->list);
3233
4023
                warnif_misplaced_reqadd(curproxy, file, linenum, args[0]);
3234
4024
        }
3235
4025
        else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) {  /* replace response header from a regex */
3236
 
                regex_t *preg;
3237
 
        
3238
 
                if (*(args[1]) == 0 || *(args[2]) == 0) {
 
4026
                if (*(args[2]) == 0) {
3239
4027
                        Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3240
4028
                              file, linenum, args[0]);
3241
4029
                        err_code |= ERR_ALERT | ERR_FATAL;
3242
4030
                        goto out;
3243
4031
                }
3244
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3245
 
                        err_code |= ERR_WARN;
3246
4032
 
3247
 
                preg = calloc(1, sizeof(regex_t));
3248
 
                if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3249
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3250
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3251
 
                        goto out;
3252
 
                }
3253
 
        
3254
 
                err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
3255
 
                if (err) {
3256
 
                        Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
3257
 
                              file, linenum, *err);
3258
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3259
 
                        goto out;
3260
 
                }
3261
 
                warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 
4033
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
4034
                                                   ACL_DIR_RTR, ACT_REPLACE, 0,
 
4035
                                                   args[0], args[1], args[2], (const char **)args+3);
 
4036
                if (err_code & ERR_FATAL)
 
4037
                        goto out;
3262
4038
        }
3263
4039
        else if (!strcmp(args[0], "rspdel")) {  /* delete response header from a regex */
3264
 
                regex_t *preg;
3265
 
                if (curproxy == &defproxy) {
3266
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3267
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3268
 
                        goto out;
3269
 
                }
3270
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3271
 
                        err_code |= ERR_WARN;
3272
 
 
3273
 
                if (*(args[1]) == 0) {
3274
 
                        Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
3275
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3276
 
                        goto out;
3277
 
                }
3278
 
 
3279
 
                preg = calloc(1, sizeof(regex_t));
3280
 
                if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3281
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3282
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3283
 
                        goto out;
3284
 
                }
3285
 
        
3286
 
                err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
3287
 
                if (err) {
3288
 
                        Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
3289
 
                              file, linenum, *err);
3290
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3291
 
                        goto out;
3292
 
                }
 
4040
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
4041
                                                   ACL_DIR_RTR, ACT_REMOVE, 0,
 
4042
                                                   args[0], args[1], NULL, (const char **)args+2);
 
4043
                if (err_code & ERR_FATAL)
 
4044
                        goto out;
3293
4045
        }
3294
4046
        else if (!strcmp(args[0], "rspdeny")) {  /* block response header from a regex */
3295
 
                regex_t *preg;
3296
 
                if (curproxy == &defproxy) {
3297
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3298
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3299
 
                        goto out;
3300
 
                }
3301
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3302
 
                        err_code |= ERR_WARN;
3303
 
 
3304
 
                if (*(args[1]) == 0) {
3305
 
                        Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
3306
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3307
 
                        goto out;
3308
 
                }
3309
 
 
3310
 
                preg = calloc(1, sizeof(regex_t));
3311
 
                if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3312
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3313
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3314
 
                        goto out;
3315
 
                }
3316
 
        
3317
 
                err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
3318
 
                if (err) {
3319
 
                        Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
3320
 
                              file, linenum, *err);
3321
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3322
 
                        goto out;
3323
 
                }
 
4047
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
4048
                                                   ACL_DIR_RTR, ACT_DENY, 0,
 
4049
                                                   args[0], args[1], NULL, (const char **)args+2);
 
4050
                if (err_code & ERR_FATAL)
 
4051
                        goto out;
3324
4052
        }
3325
4053
        else if (!strcmp(args[0], "rspirep")) {  /* replace response header from a regex ignoring case */
3326
 
                regex_t *preg;
3327
 
                if (curproxy == &defproxy) {
3328
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3329
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3330
 
                        goto out;
3331
 
                }
3332
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3333
 
                        err_code |= ERR_WARN;
3334
 
 
3335
 
                if (*(args[1]) == 0 || *(args[2]) == 0) {
 
4054
                if (*(args[2]) == 0) {
3336
4055
                        Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
3337
4056
                              file, linenum, args[0]);
3338
4057
                        err_code |= ERR_ALERT | ERR_FATAL;
3339
4058
                        goto out;
3340
4059
                }
3341
4060
 
3342
 
                preg = calloc(1, sizeof(regex_t));
3343
 
                if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
3344
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3345
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3346
 
                        goto out;
3347
 
                }
3348
 
            
3349
 
                err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
3350
 
                if (err) {
3351
 
                        Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
3352
 
                              file, linenum, *err);
3353
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3354
 
                        goto out;
3355
 
                }
 
4061
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
4062
                                                   ACL_DIR_RTR, ACT_REPLACE, REG_ICASE,
 
4063
                                                   args[0], args[1], args[2], (const char **)args+3);
 
4064
                if (err_code & ERR_FATAL)
 
4065
                        goto out;
3356
4066
        }
3357
4067
        else if (!strcmp(args[0], "rspidel")) {  /* delete response header from a regex ignoring case */
3358
 
                regex_t *preg;
3359
 
                if (curproxy == &defproxy) {
3360
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3361
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3362
 
                        goto out;
3363
 
                }
3364
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3365
 
                        err_code |= ERR_WARN;
3366
 
 
3367
 
                if (*(args[1]) == 0) {
3368
 
                        Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
3369
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3370
 
                        goto out;
3371
 
                }
3372
 
 
3373
 
                preg = calloc(1, sizeof(regex_t));
3374
 
                if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
3375
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3376
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3377
 
                        goto out;
3378
 
                }
3379
 
        
3380
 
                err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
3381
 
                if (err) {
3382
 
                        Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
3383
 
                              file, linenum, *err);
3384
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3385
 
                        goto out;
3386
 
                }
 
4068
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
4069
                                                   ACL_DIR_RTR, ACT_REMOVE, REG_ICASE,
 
4070
                                                   args[0], args[1], NULL, (const char **)args+2);
 
4071
                if (err_code & ERR_FATAL)
 
4072
                        goto out;
3387
4073
        }
3388
4074
        else if (!strcmp(args[0], "rspideny")) {  /* block response header from a regex ignoring case */
3389
 
                regex_t *preg;
3390
 
                if (curproxy == &defproxy) {
3391
 
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3392
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3393
 
                        goto out;
3394
 
                }
3395
 
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3396
 
                        err_code |= ERR_WARN;
3397
 
 
3398
 
                if (*(args[1]) == 0) {
3399
 
                        Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
3400
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3401
 
                        goto out;
3402
 
                }
3403
 
 
3404
 
                preg = calloc(1, sizeof(regex_t));
3405
 
                if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
3406
 
                        Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
3407
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3408
 
                        goto out;
3409
 
                }
3410
 
        
3411
 
                err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
3412
 
                if (err) {
3413
 
                        Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
3414
 
                              file, linenum, *err);
3415
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3416
 
                        goto out;
3417
 
                }
 
4075
                err_code |= create_cond_regex_rule(file, linenum, curproxy,
 
4076
                                                   ACL_DIR_RTR, ACT_DENY, REG_ICASE,
 
4077
                                                   args[0], args[1], NULL, (const char **)args+2);
 
4078
                if (err_code & ERR_FATAL)
 
4079
                        goto out;
3418
4080
        }
3419
4081
        else if (!strcmp(args[0], "rspadd")) {  /* add response header */
 
4082
                struct cond_wordlist *wl;
 
4083
 
3420
4084
                if (curproxy == &defproxy) {
3421
4085
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
3422
4086
                        err_code |= ERR_ALERT | ERR_FATAL;
3425
4089
                else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
3426
4090
                        err_code |= ERR_WARN;
3427
4091
 
3428
 
                if (curproxy->nb_rspadd >= MAX_NEWHDR) {
3429
 
                        Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
3430
 
                        err_code |= ERR_ALERT | ERR_FATAL;
3431
 
                        goto out;
3432
 
                }
3433
 
        
3434
4092
                if (*(args[1]) == 0) {
3435
4093
                        Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
3436
4094
                        err_code |= ERR_ALERT | ERR_FATAL;
3437
4095
                        goto out;
3438
4096
                }
3439
4097
        
3440
 
                curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
 
4098
                if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
 
4099
                        if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2)) == NULL) {
 
4100
                                Alert("parsing [%s:%d] : error detected while parsing a '%s' condition.\n",
 
4101
                                      file, linenum, args[0]);
 
4102
                                err_code |= ERR_ALERT | ERR_FATAL;
 
4103
                                goto out;
 
4104
                        }
 
4105
                        err_code |= warnif_cond_requires_req(cond, file, linenum);
 
4106
                }
 
4107
                else if (*args[2]) {
 
4108
                        Alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n",
 
4109
                              file, linenum, args[0], args[2]);
 
4110
                        err_code |= ERR_ALERT | ERR_FATAL;
 
4111
                        goto out;
 
4112
                }
 
4113
 
 
4114
                wl = calloc(1, sizeof(*wl));
 
4115
                wl->cond = cond;
 
4116
                wl->s = strdup(args[1]);
 
4117
                LIST_ADDQ(&curproxy->rsp_add, &wl->list);
3441
4118
        }
3442
4119
        else if (!strcmp(args[0], "errorloc") ||
3443
4120
                 !strcmp(args[0], "errorloc302") ||
3465
4142
 
3466
4143
                for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
3467
4144
                        if (http_err_codes[rc] == errnum) {
3468
 
                                free(curproxy->errmsg[rc].str);
3469
 
                                curproxy->errmsg[rc].str = err;
3470
 
                                curproxy->errmsg[rc].len = errlen;
 
4145
                                chunk_destroy(&curproxy->errmsg[rc]);
 
4146
                                chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen);
3471
4147
                                break;
3472
4148
                        }
3473
4149
                }
3502
4178
                        goto out;
3503
4179
                }
3504
4180
 
3505
 
                if (stat.st_size <= BUFSIZE) {
 
4181
                if (stat.st_size <= global.tune.bufsize) {
3506
4182
                        errlen = stat.st_size;
3507
4183
                } else {
3508
4184
                        Warning("parsing [%s:%d] : custom error message file <%s> larger than %d bytes. Truncating.\n",
3509
 
                                file, linenum, args[2], BUFSIZE);
 
4185
                                file, linenum, args[2], global.tune.bufsize);
3510
4186
                        err_code |= ERR_WARN;
3511
 
                        errlen = BUFSIZE;
 
4187
                        errlen = global.tune.bufsize;
3512
4188
                }
3513
4189
 
3514
4190
                err = malloc(errlen); /* malloc() must succeed during parsing */
3526
4202
                errnum = atol(args[1]);
3527
4203
                for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
3528
4204
                        if (http_err_codes[rc] == errnum) {
3529
 
                                free(curproxy->errmsg[rc].str);
3530
 
                                curproxy->errmsg[rc].str = err;
3531
 
                                curproxy->errmsg[rc].len = errlen;
 
4205
                                chunk_destroy(&curproxy->errmsg[rc]);
 
4206
                                chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen);
3532
4207
                                break;
3533
4208
                        }
3534
4209
                }
3576
4251
        return err_code;
3577
4252
}
3578
4253
 
 
4254
int
 
4255
cfg_parse_users(const char *file, int linenum, char **args, int kwm)
 
4256
{
 
4257
 
 
4258
        int err_code = 0;
 
4259
        const char *err;
 
4260
 
 
4261
        if (!strcmp(args[0], "userlist")) {             /* new userlist */
 
4262
                struct userlist *newul;
 
4263
 
 
4264
                if (!*args[1]) {
 
4265
                        Alert("parsing [%s:%d]: '%s' expects <name> as arguments.\n",
 
4266
                              file, linenum, args[0]);
 
4267
                        err_code |= ERR_ALERT | ERR_FATAL;
 
4268
                        goto out;
 
4269
                }
 
4270
 
 
4271
                err = invalid_char(args[1]);
 
4272
                if (err) {
 
4273
                        Alert("parsing [%s:%d]: character '%c' is not permitted in '%s' name '%s'.\n",
 
4274
                              file, linenum, *err, args[0], args[1]);
 
4275
                        err_code |= ERR_ALERT | ERR_FATAL;
 
4276
                        goto out;
 
4277
                }
 
4278
 
 
4279
                for (newul = userlist; newul; newul = newul->next)
 
4280
                        if (!strcmp(newul->name, args[1])) {
 
4281
                                Warning("parsing [%s:%d]: ignoring duplicated userlist '%s'.\n",
 
4282
                                        file, linenum, args[1]);
 
4283
                                err_code |= ERR_WARN;
 
4284
                                goto out;
 
4285
                        }
 
4286
 
 
4287
                newul = (struct userlist *)calloc(1, sizeof(struct userlist));
 
4288
                if (!newul) {
 
4289
                        Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
 
4290
                        err_code |= ERR_ALERT | ERR_ABORT;
 
4291
                        goto out;
 
4292
                }
 
4293
 
 
4294
                newul->groupusers = calloc(MAX_AUTH_GROUPS, sizeof(char *));
 
4295
                newul->name = strdup(args[1]);
 
4296
 
 
4297
                if (!newul->groupusers | !newul->name) {
 
4298
                        Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
 
4299
                        err_code |= ERR_ALERT | ERR_ABORT;
 
4300
                        goto out;
 
4301
                }
 
4302
 
 
4303
                newul->next = userlist;
 
4304
                userlist = newul;
 
4305
 
 
4306
        } else if (!strcmp(args[0], "group")) {         /* new group */
 
4307
                int cur_arg, i;
 
4308
                const char *err;
 
4309
 
 
4310
                if (!*args[1]) {
 
4311
                        Alert("parsing [%s:%d]: '%s' expects <name> as arguments.\n",
 
4312
                              file, linenum, args[0]);
 
4313
                        err_code |= ERR_ALERT | ERR_FATAL;
 
4314
                        goto out;
 
4315
                }
 
4316
 
 
4317
                err = invalid_char(args[1]);
 
4318
                if (err) {
 
4319
                        Alert("parsing [%s:%d]: character '%c' is not permitted in '%s' name '%s'.\n",
 
4320
                              file, linenum, *err, args[0], args[1]);
 
4321
                        err_code |= ERR_ALERT | ERR_FATAL;
 
4322
                        goto out;
 
4323
                }
 
4324
 
 
4325
                for(i = 0; i < userlist->grpcnt; i++)
 
4326
                        if (!strcmp(userlist->groups[i], args[1])) {
 
4327
                                Warning("parsing [%s:%d]: ignoring duplicated group '%s' in userlist '%s'.\n",
 
4328
                                      file, linenum, args[1], userlist->name);
 
4329
                                err_code |= ERR_ALERT;
 
4330
                                goto out;
 
4331
                        }
 
4332
 
 
4333
                if (userlist->grpcnt >= MAX_AUTH_GROUPS) {
 
4334
                        Alert("parsing [%s:%d]: too many groups (%u) in in userlist '%s' while adding group '%s'.\n",
 
4335
                              file, linenum, MAX_AUTH_GROUPS, userlist->name, args[1]);
 
4336
                        err_code |= ERR_ALERT | ERR_FATAL;
 
4337
                        goto out;
 
4338
                }
 
4339
 
 
4340
                cur_arg = 2;
 
4341
 
 
4342
                while (*args[cur_arg]) {
 
4343
                        if (!strcmp(args[cur_arg], "users")) {
 
4344
                                userlist->groupusers[userlist->grpcnt] = strdup(args[cur_arg + 1]);
 
4345
                                cur_arg += 2;
 
4346
                                continue;
 
4347
                        } else {
 
4348
                                Alert("parsing [%s:%d]: '%s' only supports 'users' option.\n",
 
4349
                                      file, linenum, args[0]);
 
4350
                                err_code |= ERR_ALERT | ERR_FATAL;
 
4351
                                goto out;
 
4352
                        }
 
4353
                }
 
4354
 
 
4355
                userlist->groups[userlist->grpcnt++] = strdup(args[1]);
 
4356
        } else if (!strcmp(args[0], "user")) {          /* new user */
 
4357
                struct auth_users *newuser;
 
4358
                int cur_arg;
 
4359
 
 
4360
                if (!*args[1]) {
 
4361
                        Alert("parsing [%s:%d]: '%s' expects <name> as arguments.\n",
 
4362
                              file, linenum, args[0]);
 
4363
                        err_code |= ERR_ALERT | ERR_FATAL;
 
4364
                        goto out;
 
4365
                }
 
4366
 
 
4367
                for (newuser = userlist->users; newuser; newuser = newuser->next)
 
4368
                        if (!strcmp(newuser->user, args[1])) {
 
4369
                                Warning("parsing [%s:%d]: ignoring duplicated user '%s' in userlist '%s'.\n",
 
4370
                                      file, linenum, args[1], userlist->name);
 
4371
                                err_code |= ERR_ALERT;
 
4372
                                goto out;
 
4373
                        }
 
4374
 
 
4375
                newuser = (struct auth_users *)calloc(1, sizeof(struct auth_users));
 
4376
                if (!newuser) {
 
4377
                        Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
 
4378
                        err_code |= ERR_ALERT | ERR_ABORT;
 
4379
                        goto out;
 
4380
                }
 
4381
 
 
4382
                newuser->user = strdup(args[1]);
 
4383
 
 
4384
                newuser->next = userlist->users;
 
4385
                userlist->users = newuser;
 
4386
 
 
4387
                cur_arg = 2;
 
4388
 
 
4389
                while (*args[cur_arg]) {
 
4390
                        if (!strcmp(args[cur_arg], "password")) {
 
4391
#ifndef CONFIG_HAP_CRYPT
 
4392
                                Warning("parsing [%s:%d]: no crypt(3) support compiled, encrypted passwords will not work.\n",
 
4393
                                        file, linenum);
 
4394
                                err_code |= ERR_ALERT;
 
4395
#endif
 
4396
                                newuser->pass = strdup(args[cur_arg + 1]);
 
4397
                                cur_arg += 2;
 
4398
                                continue;
 
4399
                        } else if (!strcmp(args[cur_arg], "insecure-password")) {
 
4400
                                newuser->pass = strdup(args[cur_arg + 1]);
 
4401
                                newuser->flags |= AU_O_INSECURE;
 
4402
                                cur_arg += 2;
 
4403
                                continue;
 
4404
                        } else if (!strcmp(args[cur_arg], "groups")) {
 
4405
                                newuser->u.groups = strdup(args[cur_arg + 1]);
 
4406
                                cur_arg += 2;
 
4407
                                continue;
 
4408
                        } else {
 
4409
                                Alert("parsing [%s:%d]: '%s' only supports 'password', 'insecure-password' and 'groups' options.\n",
 
4410
                                      file, linenum, args[0]);
 
4411
                                err_code |= ERR_ALERT | ERR_FATAL;
 
4412
                                goto out;
 
4413
                        }
 
4414
                }
 
4415
        } else {
 
4416
                Alert("parsing [%s:%d]: unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "users");
 
4417
                err_code |= ERR_ALERT | ERR_FATAL;
 
4418
        }
 
4419
 
 
4420
out:
 
4421
        return err_code;
 
4422
}
3579
4423
 
3580
4424
/*
3581
4425
 * This function reads and parses the configuration file given in the argument.
3599
4443
                return -1;
3600
4444
 
3601
4445
        while (fgets(thisline, sizeof(thisline), f) != NULL) {
3602
 
                int arg, inv = 0 ;
 
4446
                int arg, kwm = KWM_STD;
3603
4447
                char *end;
3604
4448
                char *args[MAX_LINE_ARGS + 1];
3605
4449
                char *line = thisline;
3647
4491
                                        skip = 1;
3648
4492
                                }
3649
4493
                                else if (line[1] == 'x') {
3650
 
                                        if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
 
4494
                                        if ((line + 3 < end) && ishex(line[2]) && ishex(line[3])) {
3651
4495
                                                unsigned char hex1, hex2;
3652
4496
                                                hex1 = toupper(line[2]) - '0';
3653
4497
                                                hex2 = toupper(line[3]) - '0';
3662
4506
                                        }
3663
4507
                                }
3664
4508
                                if (skip) {
3665
 
                                        memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
 
4509
                                        memmove(line + 1, line + 1 + skip, end - (line + skip));
3666
4510
                                        end -= skip;
3667
4511
                                }
3668
4512
                                line++;
3688
4532
                if (!**args)
3689
4533
                        continue;
3690
4534
 
 
4535
                if (*line) {
 
4536
                        /* we had to stop due to too many args.
 
4537
                         * Let's terminate the string, print the offending part then cut the
 
4538
                         * last arg.
 
4539
                         */
 
4540
                        while (*line && *line != '#' && *line != '\n' && *line != '\r')
 
4541
                                line++;
 
4542
                        *line = '\0';
 
4543
 
 
4544
                        Alert("parsing [%s:%d]: line too long, truncating at word %d, position %ld: <%s>.\n",
 
4545
                              file, linenum, arg + 1, (long)(args[arg] - thisline + 1), args[arg]);
 
4546
                        err_code |= ERR_ALERT | ERR_FATAL;
 
4547
                        args[arg] = line;
 
4548
                }
 
4549
 
3691
4550
                /* zero out remaining args and ensure that at least one entry
3692
4551
                 * is zeroed out.
3693
4552
                 */
3695
4554
                        args[arg] = line;
3696
4555
                }
3697
4556
 
 
4557
                /* check for keyword modifiers "no" and "default" */
3698
4558
                if (!strcmp(args[0], "no")) {
3699
 
                        inv = 1;
 
4559
                        kwm = KWM_NO;
 
4560
                        for (arg=0; *args[arg+1]; arg++)
 
4561
                                args[arg] = args[arg+1];                // shift args after inversion
 
4562
                }
 
4563
                else if (!strcmp(args[0], "default")) {
 
4564
                        kwm = KWM_DEF;
3700
4565
                        for (arg=0; *args[arg+1]; arg++)
3701
4566
                                args[arg] = args[arg+1];                // shift args after inversion
3702
4567
                }
3703
4568
 
3704
 
                if (inv && strcmp(args[0], "option")) {
3705
 
                        Alert("parsing [%s:%d]: negation currently supported only for options.\n", file, linenum);
 
4569
                if (kwm != KWM_STD && strcmp(args[0], "option") != 0) {
 
4570
                        Alert("parsing [%s:%d]: negation/default currently supported only for options.\n", file, linenum);
3706
4571
                        err_code |= ERR_ALERT | ERR_FATAL;
3707
4572
                }
3708
4573
 
3719
4584
                        confsect = CFG_GLOBAL;
3720
4585
                        free(cursection);
3721
4586
                        cursection = strdup(args[0]);
 
4587
                } else if (!strcmp(args[0], "userlist")) {
 
4588
                        confsect = CFG_USERLIST;
 
4589
                        free(cursection);
 
4590
                        cursection = strdup(args[0]);
3722
4591
                }
3723
4592
                /* else it's a section keyword */
3724
4593
 
3725
4594
                switch (confsect) {
3726
4595
                case CFG_LISTEN:
3727
 
                        err_code |= cfg_parse_listen(file, linenum, args, inv);
 
4596
                        err_code |= cfg_parse_listen(file, linenum, args, kwm);
3728
4597
                        break;
3729
4598
                case CFG_GLOBAL:
3730
 
                        err_code |= cfg_parse_global(file, linenum, args, inv);
 
4599
                        err_code |= cfg_parse_global(file, linenum, args, kwm);
 
4600
                        break;
 
4601
                case CFG_USERLIST:
 
4602
                        err_code |= cfg_parse_users(file, linenum, args, kwm);
3731
4603
                        break;
3732
4604
                default:
3733
 
                        Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
 
4605
                        Alert("parsing [%s:%d]: unknown keyword '%s' out of section.\n", file, linenum, args[0]);
3734
4606
                        err_code |= ERR_ALERT | ERR_FATAL;
3735
4607
                }
3736
4608
 
3757
4629
        int cfgerr = 0;
3758
4630
        struct proxy *curproxy = NULL;
3759
4631
        struct server *newsrv = NULL;
 
4632
        struct userlist *curuserlist = NULL;
3760
4633
        int err_code = 0;
 
4634
        unsigned int next_pxid = 1;
3761
4635
 
3762
4636
        /*
3763
4637
         * Now, check for the integrity of all that we have collected.
3787
4661
 
3788
4662
        while (curproxy != NULL) {
3789
4663
                struct switching_rule *rule;
 
4664
                struct sticking_rule *mrule;
3790
4665
                struct listener *listener;
 
4666
                unsigned int next_id;
 
4667
 
 
4668
                if (!curproxy->uuid) {
 
4669
                        /* proxy ID not set, use automatic numbering with first
 
4670
                         * spare entry starting with next_pxid.
 
4671
                         */
 
4672
                        next_pxid = get_next_id(&used_proxy_id, next_pxid);
 
4673
                        curproxy->conf.id.key = curproxy->uuid = next_pxid;
 
4674
                        eb32_insert(&used_proxy_id, &curproxy->conf.id);
 
4675
                }
 
4676
                next_pxid++;
 
4677
 
3791
4678
 
3792
4679
                if (curproxy->state == PR_STSTOPPED) {
3793
4680
                        /* ensure we don't keep listeners uselessly bound */
3815
4702
                        break;
3816
4703
 
3817
4704
                case PR_MODE_HTTP:
 
4705
                        curproxy->acl_requires |= ACL_USE_L7_ANY;
3818
4706
                        if ((curproxy->cookie_name != NULL) && (curproxy->srv == NULL)) {
3819
4707
                                Alert("config : HTTP proxy %s has a cookie but no server list !\n",
3820
4708
                                      curproxy->id);
3830
4718
                }
3831
4719
 
3832
4720
                if ((curproxy->cap & PR_CAP_BE) && (curproxy->mode != PR_MODE_HEALTH)) {
3833
 
                        if (curproxy->lbprm.algo & BE_LB_ALGO) {
 
4721
                        if (curproxy->lbprm.algo & BE_LB_KIND) {
3834
4722
                                if (curproxy->options & PR_O_TRANSP) {
3835
4723
                                        Alert("config : %s '%s' cannot use both transparent and balance mode.\n",
3836
4724
                                              proxy_type_str(curproxy), curproxy->id);
3867
4755
                        err_code |= ERR_WARN;
3868
4756
                }
3869
4757
 
 
4758
                if ((curproxy->options2 & PR_O2_CHK_SNDST) && !(curproxy->options & PR_O_HTTP_CHK)) {
 
4759
                        curproxy->options &= ~PR_O2_CHK_SNDST;
 
4760
                        Warning("config : '%s' will be ignored for %s '%s' (requires 'option httpchk').\n",
 
4761
                                "send-state", proxy_type_str(curproxy), curproxy->id);
 
4762
                        err_code |= ERR_WARN;
 
4763
                }
 
4764
 
3870
4765
                /* if a default backend was specified, let's find it */
3871
4766
                if (curproxy->defbe.name) {
3872
4767
                        struct proxy *target;
3873
4768
 
3874
 
                        target = findproxy(curproxy->defbe.name, curproxy->mode, PR_CAP_BE);
 
4769
                        target = findproxy_mode(curproxy->defbe.name, curproxy->mode, PR_CAP_BE);
3875
4770
                        if (!target) {
3876
4771
                                Alert("Proxy '%s': unable to find required default_backend: '%s'.\n",
3877
4772
                                        curproxy->id, curproxy->defbe.name);
3901
4796
                                if (exp->action != ACT_SETBE)
3902
4797
                                        continue;
3903
4798
 
3904
 
                                target = findproxy(exp->replace, PR_MODE_HTTP, PR_CAP_BE);
 
4799
                                target = findproxy_mode(exp->replace, PR_MODE_HTTP, PR_CAP_BE);
3905
4800
                                if (!target) {
3906
4801
                                        Alert("Proxy '%s': unable to find required setbe: '%s'.\n",
3907
4802
                                                curproxy->id, exp->replace);
3926
4821
                list_for_each_entry(rule, &curproxy->switching_rules, list) {
3927
4822
                        struct proxy *target;
3928
4823
 
3929
 
                        target = findproxy(rule->be.name, curproxy->mode, PR_CAP_BE);
 
4824
                        target = findproxy_mode(rule->be.name, curproxy->mode, PR_CAP_BE);
3930
4825
 
3931
4826
                        if (!target) {
3932
4827
                                Alert("Proxy '%s': unable to find required use_backend: '%s'.\n",
3947
4842
                        }
3948
4843
                }
3949
4844
 
 
4845
                /* find the target table for 'stick' rules */
 
4846
                list_for_each_entry(mrule, &curproxy->sticking_rules, list) {
 
4847
                        struct proxy *target;
 
4848
 
 
4849
                        curproxy->be_req_ana |= AN_REQ_STICKING_RULES;
 
4850
                        if (mrule->flags & STK_IS_STORE)
 
4851
                                curproxy->be_rsp_ana |= AN_RES_STORE_RULES;
 
4852
 
 
4853
                        if (mrule->table.name)
 
4854
                                target = findproxy(mrule->table.name, PR_CAP_BE);
 
4855
                        else
 
4856
                                target = curproxy;
 
4857
 
 
4858
                        if (!target) {
 
4859
                                Alert("Proxy '%s': unable to find stick-table '%s'.\n",
 
4860
                                      curproxy->id, mrule->table.name);
 
4861
                                cfgerr++;
 
4862
                        }
 
4863
                        else if (target->table.size == 0) {
 
4864
                                Alert("Proxy '%s': stick-table '%s' used but not configured.\n",
 
4865
                                      curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
 
4866
                                cfgerr++;
 
4867
                        }
 
4868
                        else if (pattern_notusable_key(mrule->expr,  target->table.type)) {
 
4869
                                Alert("Proxy '%s': type of pattern not usable with type of stick-table '%s'.\n",
 
4870
                                      curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
 
4871
                                cfgerr++;
 
4872
                        }
 
4873
                        else {
 
4874
                                free((void *)mrule->table.name);
 
4875
                                mrule->table.t = &(target->table);
 
4876
                        }
 
4877
                }
 
4878
 
 
4879
                /* find the target table for 'store response' rules */
 
4880
                list_for_each_entry(mrule, &curproxy->storersp_rules, list) {
 
4881
                        struct proxy *target;
 
4882
 
 
4883
                        curproxy->be_rsp_ana |= AN_RES_STORE_RULES;
 
4884
 
 
4885
                        if (mrule->table.name)
 
4886
                                target = findproxy(mrule->table.name, PR_CAP_BE);
 
4887
                        else
 
4888
                                target = curproxy;
 
4889
 
 
4890
                        if (!target) {
 
4891
                                Alert("Proxy '%s': unable to find store table '%s'.\n",
 
4892
                                      curproxy->id, mrule->table.name);
 
4893
                                cfgerr++;
 
4894
                        }
 
4895
                        else if (target->table.size == 0) {
 
4896
                                Alert("Proxy '%s': stick-table '%s' used but not configured.\n",
 
4897
                                      curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
 
4898
                                cfgerr++;
 
4899
                        }
 
4900
                        else if (pattern_notusable_key(mrule->expr, target->table.type)) {
 
4901
                                Alert("Proxy '%s': type of pattern not usable with type of stick-table '%s'.\n",
 
4902
                                      curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
 
4903
                                cfgerr++;
 
4904
                        }
 
4905
                        else {
 
4906
                                free((void *)mrule->table.name);
 
4907
                                mrule->table.t = &(target->table);
 
4908
                        }
 
4909
                }
 
4910
 
 
4911
                if (curproxy->uri_auth && !(curproxy->uri_auth->flags & ST_CONVDONE) &&
 
4912
                    !LIST_ISEMPTY(&curproxy->uri_auth->req_acl) &&
 
4913
                    (curproxy->uri_auth->userlist || curproxy->uri_auth->auth_realm )) {
 
4914
                        Alert("%s '%s': stats 'auth'/'realm' and 'http-request' can't be used at the same time.\n",
 
4915
                              "proxy", curproxy->id);
 
4916
                        cfgerr++;
 
4917
                        goto out_uri_auth_compat;
 
4918
                }
 
4919
 
 
4920
                if (curproxy->uri_auth && curproxy->uri_auth->userlist && !(curproxy->uri_auth->flags & ST_CONVDONE)) {
 
4921
                        const char *uri_auth_compat_req[10];
 
4922
                        struct req_acl_rule *req_acl;
 
4923
                        int i = 0;
 
4924
 
 
4925
                        /* build the ACL condition from scratch. We're relying on anonymous ACLs for that */
 
4926
                        uri_auth_compat_req[i++] = "auth";
 
4927
 
 
4928
                        if (curproxy->uri_auth->auth_realm) {
 
4929
                                uri_auth_compat_req[i++] = "realm";
 
4930
                                uri_auth_compat_req[i++] = curproxy->uri_auth->auth_realm;
 
4931
                        }
 
4932
 
 
4933
                        uri_auth_compat_req[i++] = "unless";
 
4934
                        uri_auth_compat_req[i++] = "{";
 
4935
                        uri_auth_compat_req[i++] = "http_auth(.internal-stats-userlist)";
 
4936
                        uri_auth_compat_req[i++] = "}";
 
4937
                        uri_auth_compat_req[i++] = "";
 
4938
 
 
4939
                        req_acl = parse_auth_cond(uri_auth_compat_req, "internal-stats-auth-compat", 0, curproxy);
 
4940
                        if (!req_acl) {
 
4941
                                cfgerr++;
 
4942
                                break;
 
4943
                        }
 
4944
 
 
4945
                        LIST_ADDQ(&curproxy->uri_auth->req_acl, &req_acl->list);
 
4946
 
 
4947
                        if (curproxy->uri_auth->auth_realm) {
 
4948
                                free(curproxy->uri_auth->auth_realm);
 
4949
                                curproxy->uri_auth->auth_realm = NULL;
 
4950
                        }
 
4951
 
 
4952
                        curproxy->uri_auth->flags |= ST_CONVDONE;
 
4953
                }
 
4954
out_uri_auth_compat:
 
4955
 
 
4956
                cfgerr += acl_find_targets(curproxy);
 
4957
 
3950
4958
                if ((curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HTTP) &&
3951
4959
                    (((curproxy->cap & PR_CAP_FE) && !curproxy->timeout.client) ||
3952
4960
                     ((curproxy->cap & PR_CAP_BE) && (curproxy->srv) &&
3991
4999
                        }
3992
5000
                }
3993
5001
 
3994
 
                if (curproxy->options & PR_O_SSL3_CHK) {
3995
 
                        curproxy->check_len = sizeof(sslv3_client_hello_pkt);
3996
 
                        curproxy->check_req = (char *)malloc(sizeof(sslv3_client_hello_pkt));
3997
 
                        memcpy(curproxy->check_req, sslv3_client_hello_pkt, sizeof(sslv3_client_hello_pkt));
 
5002
                if (curproxy->options2 & PR_O2_SSL3_CHK) {
 
5003
                        curproxy->check_len = sizeof(sslv3_client_hello_pkt) - 1;
 
5004
                        curproxy->check_req = (char *)malloc(curproxy->check_len);
 
5005
                        memcpy(curproxy->check_req, sslv3_client_hello_pkt, curproxy->check_len);
3998
5006
                }
3999
5007
 
4000
5008
                /* The small pools required for the capture lists */
4034
5042
                curproxy->lbprm.wmult = 1; /* default weight multiplier */
4035
5043
                curproxy->lbprm.wdiv  = 1; /* default weight divider */
4036
5044
 
4037
 
                /* round robin relies on a weight tree */
4038
 
                if ((curproxy->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_RR)
4039
 
                        fwrr_init_server_groups(curproxy);
4040
 
                else if ((curproxy->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_LC)
 
5045
                /* We have to initialize the server lookup mechanism depending
 
5046
                 * on what LB algorithm was choosen.
 
5047
                 */
 
5048
 
 
5049
                curproxy->lbprm.algo &= ~(BE_LB_LKUP | BE_LB_PROP_DYN);
 
5050
                switch (curproxy->lbprm.algo & BE_LB_KIND) {
 
5051
                case BE_LB_KIND_RR:
 
5052
                        if ((curproxy->lbprm.algo & BE_LB_PARM) == BE_LB_RR_STATIC) {
 
5053
                                curproxy->lbprm.algo |= BE_LB_LKUP_MAP;
 
5054
                                init_server_map(curproxy);
 
5055
                        } else {
 
5056
                                curproxy->lbprm.algo |= BE_LB_LKUP_RRTREE | BE_LB_PROP_DYN;
 
5057
                                fwrr_init_server_groups(curproxy);
 
5058
                        }
 
5059
                        break;
 
5060
 
 
5061
                case BE_LB_KIND_LC:
 
5062
                        curproxy->lbprm.algo |= BE_LB_LKUP_LCTREE | BE_LB_PROP_DYN;
4041
5063
                        fwlc_init_server_tree(curproxy);
4042
 
                else
4043
 
                        init_server_map(curproxy);
 
5064
                        break;
 
5065
 
 
5066
                case BE_LB_KIND_HI:
 
5067
                        if ((curproxy->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS) {
 
5068
                                curproxy->lbprm.algo |= BE_LB_LKUP_CHTREE | BE_LB_PROP_DYN;
 
5069
                                chash_init_server_tree(curproxy);
 
5070
                        } else {
 
5071
                                curproxy->lbprm.algo |= BE_LB_LKUP_MAP;
 
5072
                                init_server_map(curproxy);
 
5073
                        }
 
5074
                        break;
 
5075
                }
4044
5076
 
4045
5077
                if (curproxy->options & PR_O_LOGASAP)
4046
5078
                        curproxy->to_log &= ~LW_BYTES;
4052
5084
                        err_code |= ERR_WARN;
4053
5085
                }
4054
5086
 
 
5087
                if (curproxy->mode != PR_MODE_HTTP) {
 
5088
                        int optnum;
 
5089
 
 
5090
                        if (curproxy->options & PR_O_COOK_ANY) {
 
5091
                                Warning("config : 'cookie' statement ignored for %s '%s' as it requires HTTP mode.\n",
 
5092
                                        proxy_type_str(curproxy), curproxy->id);
 
5093
                                err_code |= ERR_WARN;
 
5094
                        }
 
5095
 
 
5096
                        if (curproxy->uri_auth) {
 
5097
                                Warning("config : 'stats' statement ignored for %s '%s' as it requires HTTP mode.\n",
 
5098
                                        proxy_type_str(curproxy), curproxy->id);
 
5099
                                err_code |= ERR_WARN;
 
5100
                                curproxy->uri_auth = NULL;
 
5101
                        }
 
5102
 
 
5103
                        if (curproxy->options & PR_O_FWDFOR) {
 
5104
                                Warning("config : 'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
 
5105
                                        "forwardfor", proxy_type_str(curproxy), curproxy->id);
 
5106
                                err_code |= ERR_WARN;
 
5107
                                curproxy->options &= ~PR_O_FWDFOR;
 
5108
                        }
 
5109
 
 
5110
                        if (curproxy->options & PR_O_ORGTO) {
 
5111
                                Warning("config : 'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
 
5112
                                        "originalto", proxy_type_str(curproxy), curproxy->id);
 
5113
                                err_code |= ERR_WARN;
 
5114
                                curproxy->options &= ~PR_O_ORGTO;
 
5115
                        }
 
5116
 
 
5117
                        for (optnum = 0; cfg_opts[optnum].name; optnum++) {
 
5118
                                if (cfg_opts[optnum].mode == PR_MODE_HTTP &&
 
5119
                                    (curproxy->cap & cfg_opts[optnum].cap) &&
 
5120
                                    (curproxy->options & cfg_opts[optnum].val)) {
 
5121
                                        Warning("config : 'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
 
5122
                                                cfg_opts[optnum].name, proxy_type_str(curproxy), curproxy->id);
 
5123
                                        err_code |= ERR_WARN;
 
5124
                                        curproxy->options &= ~cfg_opts[optnum].val;
 
5125
                                }
 
5126
                        }
 
5127
 
 
5128
                        for (optnum = 0; cfg_opts2[optnum].name; optnum++) {
 
5129
                                if (cfg_opts2[optnum].mode == PR_MODE_HTTP &&
 
5130
                                    (curproxy->cap & cfg_opts2[optnum].cap) &&
 
5131
                                    (curproxy->options2 & cfg_opts2[optnum].val)) {
 
5132
                                        Warning("config : 'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
 
5133
                                                cfg_opts2[optnum].name, proxy_type_str(curproxy), curproxy->id);
 
5134
                                        err_code |= ERR_WARN;
 
5135
                                        curproxy->options2 &= ~cfg_opts2[optnum].val;
 
5136
                                }
 
5137
                        }
 
5138
 
 
5139
#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
 
5140
                        if (curproxy->bind_hdr_occ) {
 
5141
                                curproxy->bind_hdr_occ = 0;
 
5142
                                Warning("config : %s '%s' : ignoring use of header %s as source IP in non-HTTP mode.\n",
 
5143
                                        proxy_type_str(curproxy), curproxy->id, curproxy->bind_hdr_name);
 
5144
                                err_code |= ERR_WARN;
 
5145
                        }
 
5146
#endif
 
5147
                }
 
5148
 
4055
5149
                /*
4056
5150
                 * ensure that we're not cross-dressing a TCP server into HTTP.
4057
5151
                 */
 
5152
                next_id = 1;
4058
5153
                newsrv = curproxy->srv;
4059
5154
                while (newsrv != NULL) {
 
5155
                        if (!newsrv->puid) {
 
5156
                                /* server ID not set, use automatic numbering with first
 
5157
                                 * spare entry starting with next_svid.
 
5158
                                 */
 
5159
                                next_id = get_next_id(&curproxy->conf.used_server_id, next_id);
 
5160
                                newsrv->conf.id.key = newsrv->puid = next_id;
 
5161
                                eb32_insert(&curproxy->conf.used_server_id, &newsrv->conf.id);
 
5162
                        }
 
5163
                        next_id++;
 
5164
 
4060
5165
                        if ((curproxy->mode != PR_MODE_HTTP) && (newsrv->rdr_len || newsrv->cklen)) {
4061
5166
                                Alert("config : %s '%s' : server cannot have cookie or redirect prefix in non-HTTP mode.\n",
4062
5167
                                      proxy_type_str(curproxy), curproxy->id);
4063
5168
                                cfgerr++;
4064
5169
                        }
 
5170
 
 
5171
#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
 
5172
                        if (curproxy->mode != PR_MODE_HTTP && newsrv->bind_hdr_occ) {
 
5173
                                newsrv->bind_hdr_occ = 0;
 
5174
                                Warning("config : %s '%s' : server %s cannot use header %s as source IP in non-HTTP mode.\n",
 
5175
                                        proxy_type_str(curproxy), curproxy->id, newsrv->id, newsrv->bind_hdr_name);
 
5176
                                err_code |= ERR_WARN;
 
5177
                        }
 
5178
#endif
4065
5179
                        newsrv = newsrv->next;
4066
5180
                }
4067
5181
 
4103
5217
                                }
4104
5218
 
4105
5219
                                if (pname) {
4106
 
                                        px = findproxy(pname, curproxy->mode, PR_CAP_BE);
 
5220
                                        px = findproxy(pname, PR_CAP_BE);
4107
5221
                                        if (!px) {
4108
5222
                                                Alert("config : %s '%s', server '%s': unable to find required proxy '%s' for tracking.\n",
4109
5223
                                                        proxy_type_str(curproxy), curproxy->id,
4125
5239
 
4126
5240
                                if (!(srv->state & SRV_CHECKED)) {
4127
5241
                                        Alert("config : %s '%s', server '%s': unable to use %s/%s for "
4128
 
                                                "tracing as it does not have checks enabled.\n",
 
5242
                                                "tracking as it does not have checks enabled.\n",
4129
5243
                                                proxy_type_str(curproxy), curproxy->id,
4130
5244
                                                newsrv->id, px->id, srv->id);
4131
5245
                                        cfgerr++;
4135
5249
                                if (curproxy != px &&
4136
5250
                                        (curproxy->options & PR_O_DISABLE404) != (px->options & PR_O_DISABLE404)) {
4137
5251
                                        Alert("config : %s '%s', server '%s': unable to use %s/%s for"
4138
 
                                                "tracing: disable-on-404 option inconsistency.\n",
 
5252
                                                "tracking: disable-on-404 option inconsistency.\n",
4139
5253
                                                proxy_type_str(curproxy), curproxy->id,
4140
5254
                                                newsrv->id, px->id, srv->id);
4141
5255
                                        cfgerr++;
4152
5266
                        newsrv = newsrv->next;
4153
5267
                }
4154
5268
 
 
5269
                if (curproxy->cap & PR_CAP_FE) {
 
5270
                        if (curproxy->tcp_req.inspect_delay ||
 
5271
                            !LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules))
 
5272
                                curproxy->fe_req_ana |= AN_REQ_INSPECT;
 
5273
 
 
5274
                        if (curproxy->mode == PR_MODE_HTTP) {
 
5275
                                curproxy->fe_req_ana |= AN_REQ_WAIT_HTTP | AN_REQ_HTTP_PROCESS_FE;
 
5276
                                curproxy->fe_rsp_ana |= AN_RES_WAIT_HTTP | AN_RES_HTTP_PROCESS_FE;
 
5277
                        }
 
5278
 
 
5279
                        /* both TCP and HTTP must check switching rules */
 
5280
                        curproxy->fe_req_ana |= AN_REQ_SWITCHING_RULES;
 
5281
                }
 
5282
 
 
5283
                if (curproxy->cap & PR_CAP_BE) {
 
5284
                        if (curproxy->mode == PR_MODE_HTTP) {
 
5285
                                curproxy->be_req_ana |= AN_REQ_WAIT_HTTP | AN_REQ_HTTP_INNER | AN_REQ_HTTP_PROCESS_BE;
 
5286
                                curproxy->be_rsp_ana |= AN_RES_WAIT_HTTP | AN_RES_HTTP_PROCESS_BE;
 
5287
                        }
 
5288
 
 
5289
                        /* init table on backend capabilities proxy */
 
5290
                        stktable_init(&curproxy->table);
 
5291
 
 
5292
                        /* If the backend does requires RDP cookie persistence, we have to
 
5293
                         * enable the corresponding analyser.
 
5294
                         */
 
5295
                        if (curproxy->options2 & PR_O2_RDPC_PRST)
 
5296
                                curproxy->be_req_ana |= AN_REQ_PRST_RDP_COOKIE;
 
5297
                }
 
5298
 
 
5299
                listener = NULL;
 
5300
                while (curproxy->listen) {
 
5301
                        struct listener *next;
 
5302
 
 
5303
                        next = curproxy->listen->next;
 
5304
                        curproxy->listen->next = listener;
 
5305
                        listener = curproxy->listen;
 
5306
 
 
5307
                        if (!next)
 
5308
                                break;
 
5309
 
 
5310
                        curproxy->listen = next;
 
5311
                }
 
5312
 
4155
5313
                /* adjust this proxy's listeners */
 
5314
                next_id = 1;
4156
5315
                listener = curproxy->listen;
4157
5316
                while (listener) {
 
5317
                        if (!listener->luid) {
 
5318
                                /* listener ID not set, use automatic numbering with first
 
5319
                                 * spare entry starting with next_luid.
 
5320
                                 */
 
5321
                                next_id = get_next_id(&curproxy->conf.used_listener_id, next_id);
 
5322
                                listener->conf.id.key = listener->luid = next_id;
 
5323
                                eb32_insert(&curproxy->conf.used_listener_id, &listener->conf.id);
 
5324
                        }
 
5325
                        next_id++;
 
5326
 
 
5327
                        /* enable separate counters */
 
5328
                        if (curproxy->options2 & PR_O2_SOCKSTAT) {
 
5329
                                listener->counters = (struct licounters *)calloc(1, sizeof(struct licounters));
 
5330
                                if (!listener->name) {
 
5331
                                        sprintf(trash, "sock-%d", listener->luid);
 
5332
                                        listener->name = strdup(trash);
 
5333
                                }
 
5334
                        }
 
5335
 
4158
5336
                        if (curproxy->options & PR_O_TCP_NOLING)
4159
5337
                                listener->options |= LI_O_NOLINGER;
4160
5338
                        listener->maxconn = curproxy->maxconn;
4163
5341
                        listener->accept = event_accept;
4164
5342
                        listener->private = curproxy;
4165
5343
                        listener->handler = process_session;
4166
 
 
4167
 
                        if (curproxy->mode == PR_MODE_HTTP)
4168
 
                                listener->analysers |= AN_REQ_HTTP_HDR;
4169
 
 
4170
 
                        if (curproxy->tcp_req.inspect_delay ||
4171
 
                            !LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules))
4172
 
                                listener->analysers |= AN_REQ_INSPECT;
4173
 
 
 
5344
                        listener->analysers |= curproxy->fe_req_ana;
 
5345
 
 
5346
                        /* smart accept mode is automatic in HTTP mode */
 
5347
                        if ((curproxy->options2 & PR_O2_SMARTACC) ||
 
5348
                            (curproxy->mode == PR_MODE_HTTP &&
 
5349
                             !(curproxy->no_options2 & PR_O2_SMARTACC)))
 
5350
                                listener->options |= LI_O_NOQUICKACK;
 
5351
 
 
5352
                        /* We want the use_backend and default_backend rules to apply */
4174
5353
                        listener = listener->next;
4175
5354
                }
4176
5355
 
4177
5356
                curproxy = curproxy->next;
4178
5357
        }
4179
5358
 
 
5359
        for (curuserlist = userlist; curuserlist; curuserlist = curuserlist->next) {
 
5360
                struct auth_users *curuser;
 
5361
                int g;
 
5362
 
 
5363
                for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
 
5364
                        unsigned int group_mask = 0;
 
5365
                        char *group = NULL;
 
5366
 
 
5367
                        if (!curuser->u.groups)
 
5368
                                continue;
 
5369
 
 
5370
                        while ((group = strtok(group?NULL:curuser->u.groups, ","))) {
 
5371
 
 
5372
                                for (g = 0; g < curuserlist->grpcnt; g++)
 
5373
                                        if (!strcmp(curuserlist->groups[g], group))
 
5374
                                                break;
 
5375
 
 
5376
                                if (g == curuserlist->grpcnt) {
 
5377
                                        Alert("userlist '%s': no such group '%s' specified in user '%s'\n",
 
5378
                                              curuserlist->name, group, curuser->user);
 
5379
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
5380
                                        goto out;
 
5381
                                }
 
5382
 
 
5383
                                group_mask |= (1 << g);
 
5384
                        }
 
5385
 
 
5386
                        free(curuser->u.groups);
 
5387
                        curuser->u.group_mask = group_mask;
 
5388
                }
 
5389
 
 
5390
                for (g = 0; g < curuserlist->grpcnt; g++) {
 
5391
                        char *user = NULL;
 
5392
 
 
5393
                        if (!curuserlist->groupusers[g])
 
5394
                                continue;
 
5395
 
 
5396
                        while ((user = strtok(user?NULL:curuserlist->groupusers[g], ","))) {
 
5397
                                for (curuser = curuserlist->users; curuser; curuser = curuser->next)
 
5398
                                        if (!strcmp(curuser->user, user))
 
5399
                                                break;
 
5400
 
 
5401
                                if (!curuser) {
 
5402
                                        Alert("userlist '%s': no such user '%s' specified in group '%s'\n",
 
5403
                                              curuserlist->name, user, curuserlist->groups[g]);
 
5404
                                        err_code |= ERR_ALERT | ERR_FATAL;
 
5405
                                        goto out;
 
5406
                                }
 
5407
 
 
5408
                                curuser->u.group_mask |= (1 << g);
 
5409
                        }
 
5410
 
 
5411
                        free(curuserlist->groupusers[g]);
 
5412
                }
 
5413
 
 
5414
                free(curuserlist->groupusers);
 
5415
 
 
5416
#ifdef DEBUG_AUTH
 
5417
                for (g = 0; g < curuserlist->grpcnt; g++) {
 
5418
                        fprintf(stderr, "group %s, id %d, mask %08X, users:", curuserlist->groups[g], g , 1 << g);
 
5419
 
 
5420
                        for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
 
5421
                                if (curuser->group_mask & (1 << g))
 
5422
                                        fprintf(stderr, " %s", curuser->user);
 
5423
                        }
 
5424
 
 
5425
                        fprintf(stderr, "\n");
 
5426
                }
 
5427
#endif
 
5428
 
 
5429
        }
 
5430
 
4180
5431
        /*
4181
5432
         * Recount currently required checks.
4182
5433
         */