~ubuntu-branches/debian/squeeze/haproxy/squeeze

« back to all changes in this revision

Viewing changes to src/proto_tcp.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Cornet
  • Date: 2010-04-15 20:00:34 UTC
  • mfrom: (1.1.8 upstream) (2.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100415200034-is2r38tyvmtvi3ml
Tags: 1.4.4-1
* New upstream release
* Add splice and tproxy support
* Add regparm optimization on i386
* Switch to dpkg-source 3.0 (quilt) format

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
#include <sys/types.h>
25
25
#include <sys/un.h>
26
26
 
 
27
#include <netinet/tcp.h>
 
28
 
27
29
#include <common/cfgparse.h>
28
30
#include <common/compat.h>
29
31
#include <common/config.h>
36
38
#include <common/version.h>
37
39
 
38
40
#include <types/global.h>
 
41
#include <types/server.h>
39
42
 
40
43
#include <proto/acl.h>
41
44
#include <proto/backend.h>
42
45
#include <proto/buffers.h>
 
46
#include <proto/checks.h>
43
47
#include <proto/fd.h>
 
48
#include <proto/log.h>
 
49
#include <proto/port_range.h>
44
50
#include <proto/protocols.h>
45
51
#include <proto/proto_tcp.h>
46
52
#include <proto/proxy.h>
171
177
        return 0;
172
178
}
173
179
 
 
180
 
 
181
/*
 
182
 * This function initiates a connection to the server assigned to this session
 
183
 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet. A
 
184
 * source address may be pointed to by <from_addr>. Note that this is only used
 
185
 * in case of transparent proxying. Normal source bind addresses are still
 
186
 * determined locally (due to the possible need of a source port).
 
187
 *
 
188
 * It can return one of :
 
189
 *  - SN_ERR_NONE if everything's OK
 
190
 *  - SN_ERR_SRVTO if there are no more servers
 
191
 *  - SN_ERR_SRVCL if the connection was refused by the server
 
192
 *  - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
 
193
 *  - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
 
194
 *  - SN_ERR_INTERNAL for any other purely internal errors
 
195
 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
 
196
 */
 
197
int tcpv4_connect_server(struct stream_interface *si,
 
198
                         struct proxy *be, struct server *srv,
 
199
                         struct sockaddr *srv_addr, struct sockaddr *from_addr)
 
200
{
 
201
        int fd;
 
202
 
 
203
        if ((fd = si->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
 
204
                qfprintf(stderr, "Cannot get a server socket.\n");
 
205
 
 
206
                if (errno == ENFILE)
 
207
                        send_log(be, LOG_EMERG,
 
208
                                 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
 
209
                                 be->id, maxfd);
 
210
                else if (errno == EMFILE)
 
211
                        send_log(be, LOG_EMERG,
 
212
                                 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
 
213
                                 be->id, maxfd);
 
214
                else if (errno == ENOBUFS || errno == ENOMEM)
 
215
                        send_log(be, LOG_EMERG,
 
216
                                 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
 
217
                                 be->id, maxfd);
 
218
                /* this is a resource error */
 
219
                return SN_ERR_RESOURCE;
 
220
        }
 
221
 
 
222
        if (fd >= global.maxsock) {
 
223
                /* do not log anything there, it's a normal condition when this option
 
224
                 * is used to serialize connections to a server !
 
225
                 */
 
226
                Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
 
227
                close(fd);
 
228
                return SN_ERR_PRXCOND; /* it is a configuration limit */
 
229
        }
 
230
 
 
231
        if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
 
232
            (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
 
233
                qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
 
234
                close(fd);
 
235
                return SN_ERR_INTERNAL;
 
236
        }
 
237
 
 
238
        if (be->options & PR_O_TCP_SRV_KA)
 
239
                setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
 
240
 
 
241
        if (be->options & PR_O_TCP_NOLING)
 
242
                setsockopt(fd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
 
243
 
 
244
        /* allow specific binding :
 
245
         * - server-specific at first
 
246
         * - proxy-specific next
 
247
         */
 
248
        if (srv != NULL && srv->state & SRV_BIND_SRC) {
 
249
                int ret, flags = 0;
 
250
 
 
251
                switch (srv->state & SRV_TPROXY_MASK) {
 
252
                case SRV_TPROXY_ADDR:
 
253
                case SRV_TPROXY_CLI:
 
254
                        flags = 3;
 
255
                        break;
 
256
                case SRV_TPROXY_CIP:
 
257
                case SRV_TPROXY_DYN:
 
258
                        flags = 1;
 
259
                        break;
 
260
                }
 
261
 
 
262
#ifdef SO_BINDTODEVICE
 
263
                /* Note: this might fail if not CAP_NET_RAW */
 
264
                if (srv->iface_name)
 
265
                        setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, srv->iface_name, srv->iface_len + 1);
 
266
#endif
 
267
 
 
268
                if (srv->sport_range) {
 
269
                        int attempts = 10; /* should be more than enough to find a spare port */
 
270
                        struct sockaddr_in src;
 
271
 
 
272
                        ret = 1;
 
273
                        src = srv->source_addr;
 
274
 
 
275
                        do {
 
276
                                /* note: in case of retry, we may have to release a previously
 
277
                                 * allocated port, hence this loop's construct.
 
278
                                 */
 
279
                                port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
 
280
                                fdinfo[fd].port_range = NULL;
 
281
 
 
282
                                if (!attempts)
 
283
                                        break;
 
284
                                attempts--;
 
285
 
 
286
                                fdinfo[fd].local_port = port_range_alloc_port(srv->sport_range);
 
287
                                if (!fdinfo[fd].local_port)
 
288
                                        break;
 
289
 
 
290
                                fdinfo[fd].port_range = srv->sport_range;
 
291
                                src.sin_port = htons(fdinfo[fd].local_port);
 
292
 
 
293
                                ret = tcpv4_bind_socket(fd, flags, &src, (struct sockaddr_in *)from_addr);
 
294
                        } while (ret != 0); /* binding NOK */
 
295
                }
 
296
                else {
 
297
                        ret = tcpv4_bind_socket(fd, flags, &srv->source_addr, (struct sockaddr_in *)from_addr);
 
298
                }
 
299
 
 
300
                if (ret) {
 
301
                        port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
 
302
                        fdinfo[fd].port_range = NULL;
 
303
                        close(fd);
 
304
 
 
305
                        if (ret == 1) {
 
306
                                Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
 
307
                                      be->id, srv->id);
 
308
                                send_log(be, LOG_EMERG,
 
309
                                         "Cannot bind to source address before connect() for server %s/%s.\n",
 
310
                                         be->id, srv->id);
 
311
                        } else {
 
312
                                Alert("Cannot bind to tproxy source address before connect() for server %s/%s. Aborting.\n",
 
313
                                      be->id, srv->id);
 
314
                                send_log(be, LOG_EMERG,
 
315
                                         "Cannot bind to tproxy source address before connect() for server %s/%s.\n",
 
316
                                         be->id, srv->id);
 
317
                        }
 
318
                        return SN_ERR_RESOURCE;
 
319
                }
 
320
        }
 
321
        else if (be->options & PR_O_BIND_SRC) {
 
322
                int ret, flags = 0;
 
323
 
 
324
                switch (be->options & PR_O_TPXY_MASK) {
 
325
                case PR_O_TPXY_ADDR:
 
326
                case PR_O_TPXY_CLI:
 
327
                        flags = 3;
 
328
                        break;
 
329
                case PR_O_TPXY_CIP:
 
330
                case PR_O_TPXY_DYN:
 
331
                        flags = 1;
 
332
                        break;
 
333
                }
 
334
 
 
335
#ifdef SO_BINDTODEVICE
 
336
                /* Note: this might fail if not CAP_NET_RAW */
 
337
                if (be->iface_name)
 
338
                        setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, be->iface_name, be->iface_len + 1);
 
339
#endif
 
340
                ret = tcpv4_bind_socket(fd, flags, &be->source_addr, (struct sockaddr_in *)from_addr);
 
341
                if (ret) {
 
342
                        close(fd);
 
343
                        if (ret == 1) {
 
344
                                Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
 
345
                                      be->id);
 
346
                                send_log(be, LOG_EMERG,
 
347
                                         "Cannot bind to source address before connect() for proxy %s.\n",
 
348
                                         be->id);
 
349
                        } else {
 
350
                                Alert("Cannot bind to tproxy source address before connect() for proxy %s. Aborting.\n",
 
351
                                      be->id);
 
352
                                send_log(be, LOG_EMERG,
 
353
                                         "Cannot bind to tproxy source address before connect() for proxy %s.\n",
 
354
                                         be->id);
 
355
                        }
 
356
                        return SN_ERR_RESOURCE;
 
357
                }
 
358
        }
 
359
 
 
360
#if defined(TCP_QUICKACK)
 
361
        /* disabling tcp quick ack now allows the first request to leave the
 
362
         * machine with the first ACK. We only do this if there are pending
 
363
         * data in the buffer.
 
364
         */
 
365
        if ((be->options2 & PR_O2_SMARTCON) && si->ob->send_max)
 
366
                setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (char *) &zero, sizeof(zero));
 
367
#endif
 
368
 
 
369
        if (global.tune.server_sndbuf)
 
370
                setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &global.tune.server_sndbuf, sizeof(global.tune.server_sndbuf));
 
371
 
 
372
        if (global.tune.server_rcvbuf)
 
373
                setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf));
 
374
 
 
375
        if ((connect(fd, (struct sockaddr *)srv_addr, sizeof(struct sockaddr_in)) == -1) &&
 
376
            (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
 
377
 
 
378
                if (errno == EAGAIN || errno == EADDRINUSE) {
 
379
                        char *msg;
 
380
                        if (errno == EAGAIN) /* no free ports left, try again later */
 
381
                                msg = "no free ports";
 
382
                        else
 
383
                                msg = "local address already in use";
 
384
 
 
385
                        qfprintf(stderr,"Cannot connect: %s.\n",msg);
 
386
                        port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
 
387
                        fdinfo[fd].port_range = NULL;
 
388
                        close(fd);
 
389
                        send_log(be, LOG_EMERG,
 
390
                                 "Connect() failed for server %s/%s: %s.\n",
 
391
                                 be->id, srv->id, msg);
 
392
                        return SN_ERR_RESOURCE;
 
393
                } else if (errno == ETIMEDOUT) {
 
394
                        //qfprintf(stderr,"Connect(): ETIMEDOUT");
 
395
                        port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
 
396
                        fdinfo[fd].port_range = NULL;
 
397
                        close(fd);
 
398
                        return SN_ERR_SRVTO;
 
399
                } else {
 
400
                        // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
 
401
                        //qfprintf(stderr,"Connect(): %d", errno);
 
402
                        port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
 
403
                        fdinfo[fd].port_range = NULL;
 
404
                        close(fd);
 
405
                        return SN_ERR_SRVCL;
 
406
                }
 
407
        }
 
408
 
 
409
        fdtab[fd].owner = si;
 
410
        fdtab[fd].state = FD_STCONN; /* connection in progress */
 
411
        fdtab[fd].flags = FD_FL_TCP | FD_FL_TCP_NODELAY;
 
412
        fdtab[fd].cb[DIR_RD].f = &stream_sock_read;
 
413
        fdtab[fd].cb[DIR_RD].b = si->ib;
 
414
        fdtab[fd].cb[DIR_WR].f = &stream_sock_write;
 
415
        fdtab[fd].cb[DIR_WR].b = si->ob;
 
416
 
 
417
        fdinfo[fd].peeraddr = (struct sockaddr *)srv_addr;
 
418
        fdinfo[fd].peerlen = sizeof(struct sockaddr_in);
 
419
 
 
420
        fd_insert(fd);
 
421
        EV_FD_SET(fd, DIR_WR);  /* for connect status */
 
422
 
 
423
        si->state = SI_ST_CON;
 
424
        si->flags |= SI_FL_CAP_SPLTCP; /* TCP supports splicing */
 
425
        si->exp = tick_add_ifset(now_ms, be->timeout.connect);
 
426
 
 
427
        return SN_ERR_NONE;  /* connection is OK */
 
428
}
 
429
 
 
430
 
174
431
/* This function tries to bind a TCPv4/v6 listener. It may return a warning or
175
432
 * an error message in <err> if the message is at most <errlen> bytes long
176
433
 * (including '\0'). The return value is composed from ERR_ABORT, ERR_WARN,
210
467
                goto tcp_close_return;
211
468
        }
212
469
 
213
 
        if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
214
 
            (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
215
 
                        (char *) &one, sizeof(one)) == -1)) {
 
470
        if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
216
471
                err |= ERR_FATAL | ERR_ALERT;
217
472
                msg = "cannot make socket non-blocking";
218
473
                goto tcp_close_return;
251
506
                }
252
507
        }
253
508
#endif
 
509
#if defined(TCP_MAXSEG)
 
510
        if (listener->maxseg) {
 
511
                if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG,
 
512
                               &listener->maxseg, sizeof(listener->maxseg)) == -1) {
 
513
                        msg = "cannot set MSS";
 
514
                        err |= ERR_WARN;
 
515
                }
 
516
        }
 
517
#endif
 
518
#if defined(TCP_DEFER_ACCEPT)
 
519
        if (listener->options & LI_O_DEF_ACCEPT) {
 
520
                /* defer accept by up to one second */
 
521
                int accept_delay = 1;
 
522
                if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &accept_delay, sizeof(accept_delay)) == -1) {
 
523
                        msg = "cannot enable DEFER_ACCEPT";
 
524
                        err |= ERR_WARN;
 
525
                }
 
526
        }
 
527
#endif
254
528
        if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) {
255
529
                err |= ERR_RETRYABLE | ERR_ALERT;
256
530
                msg = "cannot bind socket";
263
537
                goto tcp_close_return;
264
538
        }
265
539
 
 
540
#if defined(TCP_QUICKACK)
 
541
        if (listener->options & LI_O_NOQUICKACK)
 
542
                setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (char *) &zero, sizeof(zero));
 
543
#endif
 
544
 
266
545
        /* the socket is ready */
267
546
        listener->fd = fd;
268
547
        listener->state = LI_LISTEN;
274
553
        fdtab[fd].cb[DIR_RD].b = fdtab[fd].cb[DIR_WR].b = NULL;
275
554
        fdtab[fd].owner = listener; /* reference the listener instead of a task */
276
555
        fdtab[fd].state = FD_STLISTEN;
277
 
        fdtab[fd].peeraddr = NULL;
278
 
        fdtab[fd].peerlen = 0;
 
556
        fdtab[fd].flags = FD_FL_TCP;
 
557
        if (listener->options & LI_O_NOLINGER)
 
558
                fdtab[fd].flags |= FD_FL_TCP_NOLING;
 
559
 
 
560
        fdinfo[fd].peeraddr = NULL;
 
561
        fdinfo[fd].peerlen = 0;
279
562
 tcp_return:
280
563
        if (msg && errlen)
281
564
                strlcpy2(errmsg, msg, errlen);
355
638
 * called after XXX bytes have been received (or transfered), and the min of
356
639
 * all's wishes will be used to ring back (unless a special condition occurs).
357
640
 */
358
 
int tcp_inspect_request(struct session *s, struct buffer *req)
 
641
int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit)
359
642
{
360
643
        struct tcp_rule *rule;
361
644
        int partial;
388
671
                int ret = ACL_PAT_PASS;
389
672
 
390
673
                if (rule->cond) {
391
 
                        ret = acl_exec_cond(rule->cond, s->fe, s, NULL, ACL_DIR_REQ | partial);
 
674
                        ret = acl_exec_cond(rule->cond, s->fe, s, &s->txn, ACL_DIR_REQ | partial);
392
675
                        if (ret == ACL_PAT_MISS) {
393
 
                                buffer_write_dis(req);
 
676
                                buffer_dont_connect(req);
394
677
                                /* just set the request timeout once at the beginning of the request */
395
678
                                if (!tick_isset(req->analyse_exp) && s->fe->tcp_req.inspect_delay)
396
679
                                        req->analyse_exp = tick_add_ifset(now_ms, s->fe->tcp_req.inspect_delay);
408
691
                                buffer_abort(req);
409
692
                                buffer_abort(s->rep);
410
693
                                req->analysers = 0;
411
 
                                s->fe->failed_req++;
 
694
 
 
695
                                s->fe->counters.failed_req++;
 
696
                                if (s->listener->counters)
 
697
                                        s->listener->counters->failed_req++;
 
698
 
412
699
                                if (!(s->flags & SN_ERR_MASK))
413
700
                                        s->flags |= SN_ERR_PRXCOND;
414
701
                                if (!(s->flags & SN_FINST_MASK))
423
710
        /* if we get there, it means we have no rule which matches, or
424
711
         * we have an explicit accept, so we apply the default accept.
425
712
         */
426
 
        req->analysers &= ~AN_REQ_INSPECT;
 
713
        req->analysers &= ~an_bit;
 
714
        req->analyse_exp = TICK_ETERNITY;
 
715
        return 1;
 
716
}
 
717
 
 
718
/* Apply RDP cookie persistence to the current session. For this, the function
 
719
 * tries to extract an RDP cookie from the request buffer, and look for the
 
720
 * matching server in the list. If the server is found, it is assigned to the
 
721
 * session. This always returns 1, and the analyser removes itself from the
 
722
 * list. Nothing is performed if a server was already assigned.
 
723
 */
 
724
int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit)
 
725
{
 
726
        struct proxy    *px   = s->be;
 
727
        int              ret;
 
728
        struct acl_expr  expr;
 
729
        struct acl_test  test;
 
730
        struct server *srv = px->srv;
 
731
        struct sockaddr_in addr;
 
732
        char *p;
 
733
 
 
734
        DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
 
735
                now_ms, __FUNCTION__,
 
736
                s,
 
737
                req,
 
738
                req->rex, req->wex,
 
739
                req->flags,
 
740
                req->l,
 
741
                req->analysers);
 
742
 
 
743
        if (s->flags & SN_ASSIGNED)
 
744
                goto no_cookie;
 
745
 
 
746
        memset(&expr, 0, sizeof(expr));
 
747
        memset(&test, 0, sizeof(test));
 
748
 
 
749
        expr.arg.str = s->be->rdp_cookie_name;
 
750
        expr.arg_len = s->be->rdp_cookie_len;
 
751
 
 
752
        ret = acl_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, &expr, &test);
 
753
        if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || test.len == 0)
 
754
                goto no_cookie;
 
755
 
 
756
        memset(&addr, 0, sizeof(addr));
 
757
        addr.sin_family = AF_INET;
 
758
 
 
759
        /* Considering an rdp cookie detected using acl, test.ptr ended with <cr><lf> and should return */
 
760
        addr.sin_addr.s_addr = strtoul(test.ptr, &p, 10);
 
761
        if (*p != '.')
 
762
                goto no_cookie;
 
763
        p++;
 
764
        addr.sin_port = (unsigned short)strtoul(p, &p, 10);
 
765
        if (*p != '.')
 
766
                goto no_cookie;
 
767
 
 
768
        while (srv) {
 
769
                if (memcmp(&addr, &(srv->addr), sizeof(addr)) == 0) {
 
770
                        if ((srv->state & SRV_RUNNING) || (px->options & PR_O_PERSIST)) {
 
771
                                /* we found the server and it is usable */
 
772
                                s->flags |= SN_DIRECT | SN_ASSIGNED;
 
773
                                s->srv = srv;
 
774
                                break;
 
775
                        }
 
776
                }
 
777
                srv = srv->next;
 
778
        }
 
779
 
 
780
no_cookie:
 
781
        req->analysers &= ~an_bit;
427
782
        req->analyse_exp = TICK_ETERNITY;
428
783
        return 1;
429
784
}
505
860
                pol = ACL_COND_NONE;
506
861
                cond = NULL;
507
862
 
508
 
                if (!*args[3])
509
 
                        pol = ACL_COND_NONE;
510
 
                else if (!strcmp(args[3], "if"))
511
 
                        pol = ACL_COND_IF;
512
 
                else if (!strcmp(args[3], "unless"))
513
 
                        pol = ACL_COND_UNLESS;
514
 
                else {
 
863
                if (strcmp(args[3], "if") == 0 || strcmp(args[3], "unless") == 0) {
 
864
                        if ((cond = build_acl_cond(NULL, 0, curpx, (const char **)args+3)) == NULL) {
 
865
                                retlen = snprintf(err, errlen,
 
866
                                                  "error detected in %s '%s' while parsing '%s' condition",
 
867
                                                  proxy_type_str(curpx), curpx->id, args[3]);
 
868
                                return -1;
 
869
                        }
 
870
                }
 
871
                else if (*args[3]) {
515
872
                        retlen = snprintf(err, errlen,
516
873
                                          "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
517
874
                                          args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[3]);
518
875
                        return -1;
519
876
                }
520
877
 
521
 
                /* Note: we consider "if TRUE" when there is no condition */
522
 
                if (pol != ACL_COND_NONE &&
523
 
                    (cond = parse_acl_cond((const char **)args+4, &curpx->acl, pol)) == NULL) {
524
 
                        retlen = snprintf(err, errlen,
525
 
                                          "error detected in %s '%s' while parsing '%s' condition",
526
 
                                          proxy_type_str(curpx), curpx->id, args[3]);
527
 
                        return -1;
528
 
                }
529
 
 
530
 
                // FIXME: how to set this ?
531
 
                // cond->line = linenum;
532
 
                if (cond && cond->requires & (ACL_USE_RTR_ANY | ACL_USE_L7_ANY)) {
 
878
                if (cond && (cond->requires & ACL_USE_RTR_ANY)) {
533
879
                        struct acl *acl;
534
880
                        const char *name;
535
881
 
536
 
                        acl = cond_find_require(cond, ACL_USE_RTR_ANY|ACL_USE_L7_ANY);
 
882
                        acl = cond_find_require(cond, ACL_USE_RTR_ANY);
537
883
                        name = acl ? acl->name : "(unknown)";
538
884
 
539
885
                        retlen = snprintf(err, errlen,
540
 
                                          "acl '%s' involves some %s criteria which will be ignored.",
541
 
                                          name,
542
 
                                          (acl->requires & ACL_USE_RTR_ANY) ? "response-only" : "layer 7");
 
886
                                          "acl '%s' involves some response-only criteria which will be ignored.",
 
887
                                          name);
543
888
                        warn++;
544
889
                }
545
890
                rule = (struct tcp_rule *)calloc(1, sizeof(*rule));
659
1004
         * all the part of the request which fits in a buffer is already
660
1005
         * there.
661
1006
         */
662
 
        if (msg_len > l4->req->max_len + l4->req->data - l4->req->w)
663
 
                msg_len = l4->req->max_len + l4->req->data - l4->req->w;
 
1007
        if (msg_len > buffer_max_len(l4->req) + l4->req->data - l4->req->w)
 
1008
                msg_len = buffer_max_len(l4->req) + l4->req->data - l4->req->w;
664
1009
 
665
1010
        if (bleft < msg_len)
666
1011
                goto too_short;
678
1023
        return 0;
679
1024
}
680
1025
 
 
1026
int
 
1027
acl_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
 
1028
                     struct acl_expr *expr, struct acl_test *test)
 
1029
{
 
1030
        int bleft;
 
1031
        const unsigned char *data;
 
1032
 
 
1033
        if (!l4 || !l4->req)
 
1034
                return 0;
 
1035
 
 
1036
        test->flags = 0;
 
1037
 
 
1038
        bleft = l4->req->l;
 
1039
        if (bleft <= 11)
 
1040
                goto too_short;
 
1041
 
 
1042
        data = (const unsigned char *)l4->req->w + 11;
 
1043
        bleft -= 11;
 
1044
 
 
1045
        if (bleft <= 7)
 
1046
                goto too_short;
 
1047
 
 
1048
        if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
 
1049
                goto not_cookie;
 
1050
 
 
1051
        data += 7;
 
1052
        bleft -= 7;
 
1053
 
 
1054
        while (bleft > 0 && *data == ' ') {
 
1055
                data++;
 
1056
                bleft--;
 
1057
        }
 
1058
 
 
1059
        if (expr->arg_len) {
 
1060
 
 
1061
                if (bleft <= expr->arg_len)
 
1062
                        goto too_short;
 
1063
 
 
1064
                if ((data[expr->arg_len] != '=') ||
 
1065
                    strncasecmp(expr->arg.str, (const char *)data, expr->arg_len) != 0)
 
1066
                        goto not_cookie;
 
1067
 
 
1068
                data += expr->arg_len + 1;
 
1069
                bleft -= expr->arg_len + 1;
 
1070
        } else {
 
1071
                while (bleft > 0 && *data != '=') {
 
1072
                        if (*data == '\r' || *data == '\n')
 
1073
                                goto not_cookie;
 
1074
                        data++;
 
1075
                        bleft--;
 
1076
                }
 
1077
 
 
1078
                if (bleft < 1)
 
1079
                        goto too_short;
 
1080
 
 
1081
                if (*data != '=')
 
1082
                        goto not_cookie;
 
1083
 
 
1084
                data++;
 
1085
                bleft--;
 
1086
        }
 
1087
 
 
1088
        /* data points to cookie value */
 
1089
        test->ptr = (char *)data;
 
1090
        test->len = 0;
 
1091
 
 
1092
        while (bleft > 0 && *data != '\r') {
 
1093
                data++;
 
1094
                bleft--;
 
1095
        }
 
1096
 
 
1097
        if (bleft < 2)
 
1098
                goto too_short;
 
1099
 
 
1100
        if (data[0] != '\r' || data[1] != '\n')
 
1101
                goto not_cookie;
 
1102
 
 
1103
        test->len = (char *)data - test->ptr;
 
1104
        test->flags = ACL_TEST_F_VOLATILE;
 
1105
        return 1;
 
1106
 
 
1107
 too_short:
 
1108
        test->flags = ACL_TEST_F_MAY_CHANGE;
 
1109
 not_cookie:
 
1110
        return 0;
 
1111
}
 
1112
 
 
1113
static int
 
1114
acl_fetch_rdp_cookie_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
 
1115
                        struct acl_expr *expr, struct acl_test *test)
 
1116
{
 
1117
        int ret;
 
1118
 
 
1119
        ret = acl_fetch_rdp_cookie(px, l4, l7, dir, expr, test);
 
1120
 
 
1121
        test->ptr = NULL;
 
1122
        test->len = 0;
 
1123
 
 
1124
        if (test->flags & ACL_TEST_F_MAY_CHANGE)
 
1125
                return 0;
 
1126
 
 
1127
        test->flags = ACL_TEST_F_VOLATILE;
 
1128
        test->i = ret;
 
1129
 
 
1130
        return 1;
 
1131
}
681
1132
 
682
1133
static struct cfg_kw_list cfg_kws = {{ },{
683
1134
        { CFG_LISTEN, "tcp-request", tcp_parse_tcp_req },
687
1138
static struct acl_kw_list acl_kws = {{ },{
688
1139
        { "req_len",      acl_parse_int,        acl_fetch_req_len,     acl_match_int, ACL_USE_L4REQ_VOLATILE },
689
1140
        { "req_ssl_ver",  acl_parse_dotted_ver, acl_fetch_req_ssl_ver, acl_match_int, ACL_USE_L4REQ_VOLATILE },
 
1141
        { "req_rdp_cookie",     acl_parse_str,  acl_fetch_rdp_cookie,     acl_match_str, ACL_USE_L4REQ_VOLATILE },
 
1142
        { "req_rdp_cookie_cnt", acl_parse_int,  acl_fetch_rdp_cookie_cnt, acl_match_int, ACL_USE_L4REQ_VOLATILE },
690
1143
        { NULL, NULL, NULL, NULL },
691
1144
}};
692
1145