~ubuntu-branches/ubuntu/oneiric/haproxy/oneiric-security

« back to all changes in this revision

Viewing changes to src/proto_tcp.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Cornet
  • Date: 2009-06-26 00:11:01 UTC
  • mfrom: (1.1.6 upstream) (2.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090626001101-qo261ke2mjh3d8cn
Tags: 1.3.18-1
* New Upstream Version (Closes: #534583).
* Add contrib directory in docs

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 <common/cfgparse.h>
27
28
#include <common/compat.h>
28
29
#include <common/config.h>
29
30
#include <common/debug.h>
34
35
#include <common/time.h>
35
36
#include <common/version.h>
36
37
 
37
 
#include <types/acl.h>
38
 
#include <types/client.h>
39
38
#include <types/global.h>
40
 
#include <types/polling.h>
41
 
#include <types/proxy.h>
42
 
#include <types/server.h>
43
39
 
44
40
#include <proto/acl.h>
45
41
#include <proto/backend.h>
47
43
#include <proto/fd.h>
48
44
#include <proto/protocols.h>
49
45
#include <proto/proto_tcp.h>
 
46
#include <proto/proxy.h>
50
47
#include <proto/queue.h>
51
 
#include <proto/senddata.h>
52
48
#include <proto/session.h>
53
49
#include <proto/stream_sock.h>
54
50
#include <proto/task.h>
207
203
                msg = "cannot create listening socket";
208
204
                goto tcp_return;
209
205
        }
210
 
        
 
206
 
211
207
        if (fd >= global.maxsock) {
212
208
                err |= ERR_FATAL | ERR_ABORT | ERR_ALERT;
213
209
                msg = "not enough free sockets (raise '-n' parameter)";
230
226
 
231
227
        if (listener->options & LI_O_NOLINGER)
232
228
                setsockopt(fd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
233
 
        
 
229
 
234
230
#ifdef SO_REUSEPORT
235
231
        /* OpenBSD supports this. As it's present in old libc versions of Linux,
236
232
         * it might return an error that we will silently ignore.
238
234
        setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one));
239
235
#endif
240
236
#ifdef CONFIG_HAP_LINUX_TPROXY
241
 
        if ((listener->options & LI_O_FOREIGN) 
 
237
        if ((listener->options & LI_O_FOREIGN)
242
238
            && (setsockopt(fd, SOL_IP, IP_TRANSPARENT, (char *) &one, sizeof(one)) == -1)
243
239
            && (setsockopt(fd, SOL_IP, IP_FREEBIND, (char *) &one, sizeof(one)) == -1)) {
244
240
                msg = "cannot make listening socket transparent";
245
241
                err |= ERR_ALERT;
246
242
        }
247
243
#endif
 
244
#ifdef SO_BINDTODEVICE
 
245
        /* Note: this might fail if not CAP_NET_RAW */
 
246
        if (listener->interface) {
 
247
                if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
 
248
                               listener->interface, strlen(listener->interface) + 1) == -1) {
 
249
                        msg = "cannot bind listener to device";
 
250
                        err |= ERR_WARN;
 
251
                }
 
252
        }
 
253
#endif
248
254
        if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) {
249
255
                err |= ERR_RETRYABLE | ERR_ALERT;
250
256
                msg = "cannot bind socket";
251
257
                goto tcp_close_return;
252
258
        }
253
 
        
 
259
 
254
260
        if (listen(fd, listener->backlog ? listener->backlog : listener->maxconn) == -1) {
255
261
                err |= ERR_RETRYABLE | ERR_ALERT;
256
262
                msg = "cannot listen to socket";
257
263
                goto tcp_close_return;
258
264
        }
259
 
        
 
265
 
260
266
        /* the socket is ready */
261
267
        listener->fd = fd;
262
268
        listener->state = LI_LISTEN;
266
272
        fdtab[fd].cb[DIR_RD].f = listener->accept;
267
273
        fdtab[fd].cb[DIR_WR].f = NULL; /* never called */
268
274
        fdtab[fd].cb[DIR_RD].b = fdtab[fd].cb[DIR_WR].b = NULL;
269
 
        fdtab[fd].owner = (struct task *)listener; /* reference the listener instead of a task */
 
275
        fdtab[fd].owner = listener; /* reference the listener instead of a task */
270
276
        fdtab[fd].state = FD_STLISTEN;
271
277
        fdtab[fd].peeraddr = NULL;
272
278
        fdtab[fd].peerlen = 0;
273
 
        fdtab[fd].listener = NULL;
274
279
 tcp_return:
275
280
        if (msg && errlen)
276
281
                strlcpy2(errmsg, msg, errlen);
329
334
        proto_tcpv6.nb_listeners++;
330
335
}
331
336
 
 
337
/* This function performs the TCP request analysis on the current request. It
 
338
 * returns 1 if the processing can continue on next analysers, or zero if it
 
339
 * needs more data, encounters an error, or wants to immediately abort the
 
340
 * request. It relies on buffers flags, and updates s->req->analysers. Its
 
341
 * behaviour is rather simple:
 
342
 *  - the analyser should check for errors and timeouts, and react as expected.
 
343
 *    It does not have to close anything upon error, the caller will. Note that
 
344
 *    the caller also knows how to report errors and timeouts.
 
345
 *  - if the analyser does not have enough data, it must return 0 without calling
 
346
 *    other ones. It should also probably do a buffer_write_dis() to ensure
 
347
 *    that unprocessed data will not be forwarded. But that probably depends on
 
348
 *    the protocol.
 
349
 *  - if an analyser has enough data, it just has to pass on to the next
 
350
 *    analyser without using buffer_write_dis() (enabled by default).
 
351
 *  - if an analyser thinks it has no added value anymore staying here, it must
 
352
 *    reset its bit from the analysers flags in order not to be called anymore.
 
353
 *
 
354
 * In the future, analysers should be able to indicate that they want to be
 
355
 * called after XXX bytes have been received (or transfered), and the min of
 
356
 * all's wishes will be used to ring back (unless a special condition occurs).
 
357
 */
 
358
int tcp_inspect_request(struct session *s, struct buffer *req)
 
359
{
 
360
        struct tcp_rule *rule;
 
361
        int partial;
 
362
 
 
363
        DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
 
364
                now_ms, __FUNCTION__,
 
365
                s,
 
366
                req,
 
367
                req->rex, req->wex,
 
368
                req->flags,
 
369
                req->l,
 
370
                req->analysers);
 
371
 
 
372
        /* We don't know whether we have enough data, so must proceed
 
373
         * this way :
 
374
         * - iterate through all rules in their declaration order
 
375
         * - if one rule returns MISS, it means the inspect delay is
 
376
         *   not over yet, then return immediately, otherwise consider
 
377
         *   it as a non-match.
 
378
         * - if one rule returns OK, then return OK
 
379
         * - if one rule returns KO, then return KO
 
380
         */
 
381
 
 
382
        if (req->flags & BF_SHUTR || !s->fe->tcp_req.inspect_delay || tick_is_expired(req->analyse_exp, now_ms))
 
383
                partial = 0;
 
384
        else
 
385
                partial = ACL_PARTIAL;
 
386
 
 
387
        list_for_each_entry(rule, &s->fe->tcp_req.inspect_rules, list) {
 
388
                int ret = ACL_PAT_PASS;
 
389
 
 
390
                if (rule->cond) {
 
391
                        ret = acl_exec_cond(rule->cond, s->fe, s, NULL, ACL_DIR_REQ | partial);
 
392
                        if (ret == ACL_PAT_MISS) {
 
393
                                buffer_write_dis(req);
 
394
                                /* just set the request timeout once at the beginning of the request */
 
395
                                if (!tick_isset(req->analyse_exp) && s->fe->tcp_req.inspect_delay)
 
396
                                        req->analyse_exp = tick_add_ifset(now_ms, s->fe->tcp_req.inspect_delay);
 
397
                                return 0;
 
398
                        }
 
399
 
 
400
                        ret = acl_pass(ret);
 
401
                        if (rule->cond->pol == ACL_COND_UNLESS)
 
402
                                ret = !ret;
 
403
                }
 
404
 
 
405
                if (ret) {
 
406
                        /* we have a matching rule. */
 
407
                        if (rule->action == TCP_ACT_REJECT) {
 
408
                                buffer_abort(req);
 
409
                                buffer_abort(s->rep);
 
410
                                req->analysers = 0;
 
411
                                s->fe->failed_req++;
 
412
                                if (!(s->flags & SN_ERR_MASK))
 
413
                                        s->flags |= SN_ERR_PRXCOND;
 
414
                                if (!(s->flags & SN_FINST_MASK))
 
415
                                        s->flags |= SN_FINST_R;
 
416
                                return 0;
 
417
                        }
 
418
                                /* otherwise accept */
 
419
                        break;
 
420
                }
 
421
        }
 
422
 
 
423
        /* if we get there, it means we have no rule which matches, or
 
424
         * we have an explicit accept, so we apply the default accept.
 
425
         */
 
426
        req->analysers &= ~AN_REQ_INSPECT;
 
427
        req->analyse_exp = TICK_ETERNITY;
 
428
        return 1;
 
429
}
 
430
 
 
431
 
 
432
/* This function should be called to parse a line starting with the "tcp-request"
 
433
 * keyword.
 
434
 */
 
435
static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
 
436
                             struct proxy *defpx, char *err, int errlen)
 
437
{
 
438
        const char *ptr = NULL;
 
439
        unsigned int val;
 
440
        int retlen;
 
441
 
 
442
        if (!*args[1]) {
 
443
                snprintf(err, errlen, "missing argument for '%s' in %s '%s'",
 
444
                         args[0], proxy_type_str(proxy), curpx->id);
 
445
                return -1;
 
446
        }
 
447
 
 
448
        if (!strcmp(args[1], "inspect-delay")) {
 
449
                if (curpx == defpx) {
 
450
                        snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
 
451
                                 args[0], args[1]);
 
452
                        return -1;
 
453
                }
 
454
 
 
455
                if (!(curpx->cap & PR_CAP_FE)) {
 
456
                        snprintf(err, errlen, "%s %s will be ignored because %s '%s' has no %s capability",
 
457
                                 args[0], args[1], proxy_type_str(proxy), curpx->id,
 
458
                                 "frontend");
 
459
                        return 1;
 
460
                }
 
461
 
 
462
                if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) {
 
463
                        retlen = snprintf(err, errlen,
 
464
                                          "'%s %s' expects a positive delay in milliseconds, in %s '%s'",
 
465
                                          args[0], args[1], proxy_type_str(proxy), curpx->id);
 
466
                        if (ptr && retlen < errlen)
 
467
                                retlen += snprintf(err+retlen, errlen - retlen,
 
468
                                                   " (unexpected character '%c')", *ptr);
 
469
                        return -1;
 
470
                }
 
471
 
 
472
                if (curpx->tcp_req.inspect_delay) {
 
473
                        snprintf(err, errlen, "ignoring %s %s (was already defined) in %s '%s'",
 
474
                                 args[0], args[1], proxy_type_str(proxy), curpx->id);
 
475
                        return 1;
 
476
                }
 
477
                curpx->tcp_req.inspect_delay = val;
 
478
                return 0;
 
479
        }
 
480
 
 
481
        if (!strcmp(args[1], "content")) {
 
482
                int action;
 
483
                int warn = 0;
 
484
                int pol = ACL_COND_NONE;
 
485
                struct acl_cond *cond;
 
486
                struct tcp_rule *rule;
 
487
 
 
488
                if (curpx == defpx) {
 
489
                        snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
 
490
                                 args[0], args[1]);
 
491
                        return -1;
 
492
                }
 
493
 
 
494
                if (!strcmp(args[2], "accept"))
 
495
                        action = TCP_ACT_ACCEPT;
 
496
                else if (!strcmp(args[2], "reject"))
 
497
                        action = TCP_ACT_REJECT;
 
498
                else {
 
499
                        retlen = snprintf(err, errlen,
 
500
                                          "'%s %s' expects 'accept' or 'reject', in %s '%s' (was '%s')",
 
501
                                          args[0], args[1], proxy_type_str(curpx), curpx->id, args[2]);
 
502
                        return -1;
 
503
                }
 
504
 
 
505
                pol = ACL_COND_NONE;
 
506
                cond = NULL;
 
507
 
 
508
                if (!strcmp(args[3], "if"))
 
509
                        pol = ACL_COND_IF;
 
510
                else if (!strcmp(args[3], "unless"))
 
511
                        pol = ACL_COND_UNLESS;
 
512
 
 
513
                /* Note: we consider "if TRUE" when there is no condition */
 
514
                if (pol != ACL_COND_NONE &&
 
515
                    (cond = parse_acl_cond((const char **)args+4, &curpx->acl, pol)) == NULL) {
 
516
                        retlen = snprintf(err, errlen,
 
517
                                          "error detected in %s '%s' while parsing '%s' condition",
 
518
                                          proxy_type_str(curpx), curpx->id, args[3]);
 
519
                        return -1;
 
520
                }
 
521
 
 
522
                // FIXME: how to set this ?
 
523
                // cond->line = linenum;
 
524
                if (cond && cond->requires & (ACL_USE_RTR_ANY | ACL_USE_L7_ANY)) {
 
525
                        struct acl *acl;
 
526
                        const char *name;
 
527
 
 
528
                        acl = cond_find_require(cond, ACL_USE_RTR_ANY|ACL_USE_L7_ANY);
 
529
                        name = acl ? acl->name : "(unknown)";
 
530
 
 
531
                        retlen = snprintf(err, errlen,
 
532
                                          "acl '%s' involves some %s criteria which will be ignored.",
 
533
                                          name,
 
534
                                          (acl->requires & ACL_USE_RTR_ANY) ? "response-only" : "layer 7");
 
535
                        warn++;
 
536
                }
 
537
                rule = (struct tcp_rule *)calloc(1, sizeof(*rule));
 
538
                rule->cond = cond;
 
539
                rule->action = action;
 
540
                LIST_INIT(&rule->list);
 
541
                LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list);
 
542
                return warn;
 
543
        }
 
544
 
 
545
        snprintf(err, errlen, "unknown argument '%s' after '%s' in %s '%s'",
 
546
                 args[1], args[0], proxy_type_str(proxy), curpx->id);
 
547
        return -1;
 
548
}
 
549
 
 
550
/* return the number of bytes in the request buffer */
 
551
static int
 
552
acl_fetch_req_len(struct proxy *px, struct session *l4, void *l7, int dir,
 
553
                  struct acl_expr *expr, struct acl_test *test)
 
554
{
 
555
        if (!l4 || !l4->req)
 
556
                return 0;
 
557
 
 
558
        test->i = l4->req->l;
 
559
        test->flags = ACL_TEST_F_VOLATILE | ACL_TEST_F_MAY_CHANGE;
 
560
        return 1;
 
561
}
 
562
 
 
563
/* Return the version of the SSL protocol in the request. It supports both
 
564
 * SSLv3 (TLSv1) header format for any message, and SSLv2 header format for
 
565
 * the hello message. The SSLv3 format is described in RFC 2246 p49, and the
 
566
 * SSLv2 format is described here, and completed p67 of RFC 2246 :
 
567
 *    http://wp.netscape.com/eng/security/SSL_2.html
 
568
 *
 
569
 * Note: this decoder only works with non-wrapping data.
 
570
 */
 
571
static int
 
572
acl_fetch_req_ssl_ver(struct proxy *px, struct session *l4, void *l7, int dir,
 
573
                        struct acl_expr *expr, struct acl_test *test)
 
574
{
 
575
        int version, bleft, msg_len;
 
576
        const unsigned char *data;
 
577
 
 
578
        if (!l4 || !l4->req)
 
579
                return 0;
 
580
 
 
581
        msg_len = 0;
 
582
        bleft = l4->req->l;
 
583
        if (!bleft)
 
584
                goto too_short;
 
585
 
 
586
        data = (const unsigned char *)l4->req->w;
 
587
        if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
 
588
                /* SSLv3 header format */
 
589
                if (bleft < 5)
 
590
                        goto too_short;
 
591
 
 
592
                version = (data[1] << 16) + data[2]; /* version: major, minor */
 
593
                msg_len = (data[3] <<  8) + data[4]; /* record length */
 
594
 
 
595
                /* format introduced with SSLv3 */
 
596
                if (version < 0x00030000)
 
597
                        goto not_ssl;
 
598
 
 
599
                /* message length between 1 and 2^14 + 2048 */
 
600
                if (msg_len < 1 || msg_len > ((1<<14) + 2048))
 
601
                        goto not_ssl;
 
602
 
 
603
                bleft -= 5; data += 5;
 
604
        } else {
 
605
                /* SSLv2 header format, only supported for hello (msg type 1) */
 
606
                int rlen, plen, cilen, silen, chlen;
 
607
 
 
608
                if (*data & 0x80) {
 
609
                        if (bleft < 3)
 
610
                                goto too_short;
 
611
                        /* short header format : 15 bits for length */
 
612
                        rlen = ((data[0] & 0x7F) << 8) | data[1];
 
613
                        plen = 0;
 
614
                        bleft -= 2; data += 2;
 
615
                } else {
 
616
                        if (bleft < 4)
 
617
                                goto too_short;
 
618
                        /* long header format : 14 bits for length + pad length */
 
619
                        rlen = ((data[0] & 0x3F) << 8) | data[1];
 
620
                        plen = data[2];
 
621
                        bleft -= 3; data += 2;
 
622
                }
 
623
 
 
624
                if (*data != 0x01)
 
625
                        goto not_ssl;
 
626
                bleft--; data++;
 
627
 
 
628
                if (bleft < 8)
 
629
                        goto too_short;
 
630
                version = (data[0] << 16) + data[1]; /* version: major, minor */
 
631
                cilen   = (data[2] <<  8) + data[3]; /* cipher len, multiple of 3 */
 
632
                silen   = (data[4] <<  8) + data[5]; /* session_id_len: 0 or 16 */
 
633
                chlen   = (data[6] <<  8) + data[7]; /* 16<=challenge length<=32 */
 
634
 
 
635
                bleft -= 8; data += 8;
 
636
                if (cilen % 3 != 0)
 
637
                        goto not_ssl;
 
638
                if (silen && silen != 16)
 
639
                        goto not_ssl;
 
640
                if (chlen < 16 || chlen > 32)
 
641
                        goto not_ssl;
 
642
                if (rlen != 9 + cilen + silen + chlen)
 
643
                        goto not_ssl;
 
644
 
 
645
                /* focus on the remaining data length */
 
646
                msg_len = cilen + silen + chlen + plen;
 
647
        }
 
648
        /* We could recursively check that the buffer ends exactly on an SSL
 
649
         * fragment boundary and that a possible next segment is still SSL,
 
650
         * but that's a bit pointless. However, we could still check that
 
651
         * all the part of the request which fits in a buffer is already
 
652
         * there.
 
653
         */
 
654
        if (msg_len > l4->req->max_len + l4->req->data - l4->req->w)
 
655
                msg_len = l4->req->max_len + l4->req->data - l4->req->w;
 
656
 
 
657
        if (bleft < msg_len)
 
658
                goto too_short;
 
659
 
 
660
        /* OK that's enough. We have at least the whole message, and we have
 
661
         * the protocol version.
 
662
         */
 
663
        test->i = version;
 
664
        test->flags = ACL_TEST_F_VOLATILE;
 
665
        return 1;
 
666
 
 
667
 too_short:
 
668
        test->flags = ACL_TEST_F_MAY_CHANGE;
 
669
 not_ssl:
 
670
        return 0;
 
671
}
 
672
 
 
673
 
 
674
static struct cfg_kw_list cfg_kws = {{ },{
 
675
        { CFG_LISTEN, "tcp-request", tcp_parse_tcp_req },
 
676
        { 0, NULL, NULL },
 
677
}};
 
678
 
 
679
static struct acl_kw_list acl_kws = {{ },{
 
680
        { "req_len",      acl_parse_int,        acl_fetch_req_len,     acl_match_int, ACL_USE_L4REQ_VOLATILE },
 
681
        { "req_ssl_ver",  acl_parse_dotted_ver, acl_fetch_req_ssl_ver, acl_match_int, ACL_USE_L4REQ_VOLATILE },
 
682
        { NULL, NULL, NULL, NULL },
 
683
}};
 
684
 
332
685
__attribute__((constructor))
333
686
static void __tcp_protocol_init(void)
334
687
{
335
688
        protocol_register(&proto_tcpv4);
336
689
        protocol_register(&proto_tcpv6);
 
690
        cfg_register_keywords(&cfg_kws);
 
691
        acl_register_keywords(&acl_kws);
337
692
}
338
693
 
339
694