~ubuntu-branches/ubuntu/vivid/haproxy/vivid

« back to all changes in this revision

Viewing changes to src/payload.c

  • Committer: Package Import Robot
  • Author(s): Apollon Oikonomopoulos
  • Date: 2014-06-20 11:05:17 UTC
  • mfrom: (1.1.15) (15.1.12 experimental)
  • Revision ID: package-import@ubuntu.com-20140620110517-u6q5p9kyy2f3ozw9
Tags: 1.5.0-1
* New upstream stable series. Notable changes since the 1.4 series:
  + Native SSL support on both sides with SNI/NPN/ALPN and OCSP stapling.
  + IPv6 and UNIX sockets are supported everywhere
  + End-to-end HTTP keep-alive for better support of NTLM and improved
    efficiency in static farms
  + HTTP/1.1 response compression (deflate, gzip) to save bandwidth
  + PROXY protocol versions 1 and 2 on both sides
  + Data sampling on everything in request or response, including payload
  + ACLs can use any matching method with any input sample
  + Maps and dynamic ACLs updatable from the CLI
  + Stick-tables support counters to track activity on any input sample
  + Custom format for logs, unique-id, header rewriting, and redirects
  + Improved health checks (SSL, scripted TCP, check agent, ...)
  + Much more scalable configuration supports hundreds of thousands of
    backends and certificates without sweating

* Upload to unstable, merge all 1.5 work from experimental. Most important
  packaging changes since 1.4.25-1 include:
  + systemd support.
  + A more sane default config file.
  + Zero-downtime upgrades between 1.5 releases by gracefully reloading
    HAProxy during upgrades.
  + HTML documentation shipped in the haproxy-doc package.
  + kqueue support for kfreebsd.

* Packaging changes since 1.5~dev26-2:
  + Drop patches merged upstream:
    o Fix-reference-location-in-manpage.patch
    o 0001-BUILD-stats-workaround-stupid-and-bogus-Werror-forma.patch
  + d/watch: look for stable 1.5 releases
  + systemd: respect CONFIG and EXTRAOPTS when specified in
    /etc/default/haproxy.
  + initscript: test the configuration before start or reload.
  + initscript: remove the ENABLED flag and logic.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * General protocol-agnostic payload-based sample fetches and ACLs
 
3
 *
 
4
 * Copyright 2000-2013 Willy Tarreau <w@1wt.eu>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU General Public License
 
8
 * as published by the Free Software Foundation; either version
 
9
 * 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 */
 
12
 
 
13
#include <stdlib.h>
 
14
#include <string.h>
 
15
 
 
16
#include <proto/acl.h>
 
17
#include <proto/arg.h>
 
18
#include <proto/channel.h>
 
19
#include <proto/pattern.h>
 
20
#include <proto/payload.h>
 
21
#include <proto/sample.h>
 
22
 
 
23
 
 
24
/************************************************************************/
 
25
/*       All supported sample fetch functions must be declared here     */
 
26
/************************************************************************/
 
27
 
 
28
/* wait for more data as long as possible, then return TRUE. This should be
 
29
 * used with content inspection.
 
30
 */
 
31
static int
 
32
smp_fetch_wait_end(struct proxy *px, struct session *s, void *l7, unsigned int opt,
 
33
                   const struct arg *args, struct sample *smp, const char *kw)
 
34
{
 
35
        if (!(opt & SMP_OPT_FINAL)) {
 
36
                smp->flags |= SMP_F_MAY_CHANGE;
 
37
                return 0;
 
38
        }
 
39
        smp->type = SMP_T_BOOL;
 
40
        smp->data.uint = 1;
 
41
        return 1;
 
42
}
 
43
 
 
44
/* return the number of bytes in the request buffer */
 
45
static int
 
46
smp_fetch_len(struct proxy *px, struct session *s, void *l7, unsigned int opt,
 
47
                  const struct arg *args, struct sample *smp, const char *kw)
 
48
{
 
49
        struct channel *chn = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? s->rep : s->req;
 
50
 
 
51
        if (!s || !chn)
 
52
                return 0;
 
53
 
 
54
        smp->type = SMP_T_UINT;
 
55
        smp->data.uint = chn->buf->i;
 
56
        smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
 
57
        return 1;
 
58
}
 
59
 
 
60
/* returns the type of SSL hello message (mainly used to detect an SSL hello) */
 
61
static int
 
62
smp_fetch_ssl_hello_type(struct proxy *px, struct session *s, void *l7, unsigned int opt,
 
63
                         const struct arg *args, struct sample *smp, const char *kw)
 
64
{
 
65
        int hs_len;
 
66
        int hs_type, bleft;
 
67
        struct channel *chn;
 
68
        const unsigned char *data;
 
69
 
 
70
        if (!s)
 
71
                goto not_ssl_hello;
 
72
 
 
73
        chn = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? s->rep : s->req;
 
74
 
 
75
        bleft = chn->buf->i;
 
76
        data = (const unsigned char *)chn->buf->p;
 
77
 
 
78
        if (!bleft)
 
79
                goto too_short;
 
80
 
 
81
        if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
 
82
                /* SSLv3 header format */
 
83
                if (bleft < 9)
 
84
                        goto too_short;
 
85
 
 
86
                /* ssl version 3 */
 
87
                if ((data[1] << 16) + data[2] < 0x00030000)
 
88
                        goto not_ssl_hello;
 
89
 
 
90
                /* ssl message len must present handshake type and len */
 
91
                if ((data[3] << 8) + data[4] < 4)
 
92
                        goto not_ssl_hello;
 
93
 
 
94
                /* format introduced with SSLv3 */
 
95
 
 
96
                hs_type = (int)data[5];
 
97
                hs_len = ( data[6] << 16 ) + ( data[7] << 8 ) + data[8];
 
98
 
 
99
                /* not a full handshake */
 
100
                if (bleft < (9 + hs_len))
 
101
                        goto too_short;
 
102
 
 
103
        }
 
104
        else {
 
105
                goto not_ssl_hello;
 
106
        }
 
107
 
 
108
        smp->type = SMP_T_UINT;
 
109
        smp->data.uint = hs_type;
 
110
        smp->flags = SMP_F_VOLATILE;
 
111
 
 
112
        return 1;
 
113
 
 
114
 too_short:
 
115
        smp->flags = SMP_F_MAY_CHANGE;
 
116
 
 
117
 not_ssl_hello:
 
118
 
 
119
        return 0;
 
120
}
 
121
 
 
122
/* Return the version of the SSL protocol in the request. It supports both
 
123
 * SSLv3 (TLSv1) header format for any message, and SSLv2 header format for
 
124
 * the hello message. The SSLv3 format is described in RFC 2246 p49, and the
 
125
 * SSLv2 format is described here, and completed p67 of RFC 2246 :
 
126
 *    http://wp.netscape.com/eng/security/SSL_2.html
 
127
 *
 
128
 * Note: this decoder only works with non-wrapping data.
 
129
 */
 
130
static int
 
131
smp_fetch_req_ssl_ver(struct proxy *px, struct session *s, void *l7, unsigned int opt,
 
132
                      const struct arg *args, struct sample *smp, const char *kw)
 
133
{
 
134
        int version, bleft, msg_len;
 
135
        const unsigned char *data;
 
136
 
 
137
        if (!s || !s->req)
 
138
                return 0;
 
139
 
 
140
        msg_len = 0;
 
141
        bleft = s->req->buf->i;
 
142
        if (!bleft)
 
143
                goto too_short;
 
144
 
 
145
        data = (const unsigned char *)s->req->buf->p;
 
146
        if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
 
147
                /* SSLv3 header format */
 
148
                if (bleft < 5)
 
149
                        goto too_short;
 
150
 
 
151
                version = (data[1] << 16) + data[2]; /* version: major, minor */
 
152
                msg_len = (data[3] <<  8) + data[4]; /* record length */
 
153
 
 
154
                /* format introduced with SSLv3 */
 
155
                if (version < 0x00030000)
 
156
                        goto not_ssl;
 
157
 
 
158
                /* message length between 1 and 2^14 + 2048 */
 
159
                if (msg_len < 1 || msg_len > ((1<<14) + 2048))
 
160
                        goto not_ssl;
 
161
 
 
162
                bleft -= 5; data += 5;
 
163
        } else {
 
164
                /* SSLv2 header format, only supported for hello (msg type 1) */
 
165
                int rlen, plen, cilen, silen, chlen;
 
166
 
 
167
                if (*data & 0x80) {
 
168
                        if (bleft < 3)
 
169
                                goto too_short;
 
170
                        /* short header format : 15 bits for length */
 
171
                        rlen = ((data[0] & 0x7F) << 8) | data[1];
 
172
                        plen = 0;
 
173
                        bleft -= 2; data += 2;
 
174
                } else {
 
175
                        if (bleft < 4)
 
176
                                goto too_short;
 
177
                        /* long header format : 14 bits for length + pad length */
 
178
                        rlen = ((data[0] & 0x3F) << 8) | data[1];
 
179
                        plen = data[2];
 
180
                        bleft -= 3; data += 2;
 
181
                }
 
182
 
 
183
                if (*data != 0x01)
 
184
                        goto not_ssl;
 
185
                bleft--; data++;
 
186
 
 
187
                if (bleft < 8)
 
188
                        goto too_short;
 
189
                version = (data[0] << 16) + data[1]; /* version: major, minor */
 
190
                cilen   = (data[2] <<  8) + data[3]; /* cipher len, multiple of 3 */
 
191
                silen   = (data[4] <<  8) + data[5]; /* session_id_len: 0 or 16 */
 
192
                chlen   = (data[6] <<  8) + data[7]; /* 16<=challenge length<=32 */
 
193
 
 
194
                bleft -= 8; data += 8;
 
195
                if (cilen % 3 != 0)
 
196
                        goto not_ssl;
 
197
                if (silen && silen != 16)
 
198
                        goto not_ssl;
 
199
                if (chlen < 16 || chlen > 32)
 
200
                        goto not_ssl;
 
201
                if (rlen != 9 + cilen + silen + chlen)
 
202
                        goto not_ssl;
 
203
 
 
204
                /* focus on the remaining data length */
 
205
                msg_len = cilen + silen + chlen + plen;
 
206
        }
 
207
        /* We could recursively check that the buffer ends exactly on an SSL
 
208
         * fragment boundary and that a possible next segment is still SSL,
 
209
         * but that's a bit pointless. However, we could still check that
 
210
         * all the part of the request which fits in a buffer is already
 
211
         * there.
 
212
         */
 
213
        if (msg_len > buffer_max_len(s->req) + s->req->buf->data - s->req->buf->p)
 
214
                msg_len = buffer_max_len(s->req) + s->req->buf->data - s->req->buf->p;
 
215
 
 
216
        if (bleft < msg_len)
 
217
                goto too_short;
 
218
 
 
219
        /* OK that's enough. We have at least the whole message, and we have
 
220
         * the protocol version.
 
221
         */
 
222
        smp->type = SMP_T_UINT;
 
223
        smp->data.uint = version;
 
224
        smp->flags = SMP_F_VOLATILE;
 
225
        return 1;
 
226
 
 
227
 too_short:
 
228
        smp->flags = SMP_F_MAY_CHANGE;
 
229
 not_ssl:
 
230
        return 0;
 
231
}
 
232
 
 
233
/* Try to extract the Server Name Indication that may be presented in a TLS
 
234
 * client hello handshake message. The format of the message is the following
 
235
 * (cf RFC5246 + RFC6066) :
 
236
 * TLS frame :
 
237
 *   - uint8  type                            = 0x16   (Handshake)
 
238
 *   - uint16 version                        >= 0x0301 (TLSv1)
 
239
 *   - uint16 length                                   (frame length)
 
240
 *   - TLS handshake :
 
241
 *     - uint8  msg_type                      = 0x01   (ClientHello)
 
242
 *     - uint24 length                                 (handshake message length)
 
243
 *     - ClientHello :
 
244
 *       - uint16 client_version             >= 0x0301 (TLSv1)
 
245
 *       - uint8 Random[32]                  (4 first ones are timestamp)
 
246
 *       - SessionID :
 
247
 *         - uint8 session_id_len (0..32)              (SessionID len in bytes)
 
248
 *         - uint8 session_id[session_id_len]
 
249
 *       - CipherSuite :
 
250
 *         - uint16 cipher_len               >= 2      (Cipher length in bytes)
 
251
 *         - uint16 ciphers[cipher_len/2]
 
252
 *       - CompressionMethod :
 
253
 *         - uint8 compression_len           >= 1      (# of supported methods)
 
254
 *         - uint8 compression_methods[compression_len]
 
255
 *       - optional client_extension_len               (in bytes)
 
256
 *       - optional sequence of ClientHelloExtensions  (as many bytes as above):
 
257
 *         - uint16 extension_type            = 0 for server_name
 
258
 *         - uint16 extension_len
 
259
 *         - opaque extension_data[extension_len]
 
260
 *           - uint16 server_name_list_len             (# of bytes here)
 
261
 *           - opaque server_names[server_name_list_len bytes]
 
262
 *             - uint8 name_type              = 0 for host_name
 
263
 *             - uint16 name_len
 
264
 *             - opaque hostname[name_len bytes]
 
265
 */
 
266
static int
 
267
smp_fetch_ssl_hello_sni(struct proxy *px, struct session *s, void *l7, unsigned int opt,
 
268
                        const struct arg *args, struct sample *smp, const char *kw)
 
269
{
 
270
        int hs_len, ext_len, bleft;
 
271
        struct channel *chn;
 
272
        unsigned char *data;
 
273
 
 
274
        if (!s)
 
275
                goto not_ssl_hello;
 
276
 
 
277
        chn = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? s->rep : s->req;
 
278
 
 
279
        bleft = chn->buf->i;
 
280
        data = (unsigned char *)chn->buf->p;
 
281
 
 
282
        /* Check for SSL/TLS Handshake */
 
283
        if (!bleft)
 
284
                goto too_short;
 
285
        if (*data != 0x16)
 
286
                goto not_ssl_hello;
 
287
 
 
288
        /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
 
289
        if (bleft < 3)
 
290
                goto too_short;
 
291
        if (data[1] < 0x03)
 
292
                goto not_ssl_hello;
 
293
 
 
294
        if (bleft < 5)
 
295
                goto too_short;
 
296
        hs_len = (data[3] << 8) + data[4];
 
297
        if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
 
298
                goto not_ssl_hello; /* too short to have an extension */
 
299
 
 
300
        data += 5; /* enter TLS handshake */
 
301
        bleft -= 5;
 
302
 
 
303
        /* Check for a complete client hello starting at <data> */
 
304
        if (bleft < 1)
 
305
                goto too_short;
 
306
        if (data[0] != 0x01) /* msg_type = Client Hello */
 
307
                goto not_ssl_hello;
 
308
 
 
309
        /* Check the Hello's length */
 
310
        if (bleft < 4)
 
311
                goto too_short;
 
312
        hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
 
313
        if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
 
314
                goto not_ssl_hello; /* too short to have an extension */
 
315
 
 
316
        /* We want the full handshake here */
 
317
        if (bleft < hs_len)
 
318
                goto too_short;
 
319
 
 
320
        data += 4;
 
321
        /* Start of the ClientHello message */
 
322
        if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
 
323
                goto not_ssl_hello;
 
324
 
 
325
        ext_len = data[34]; /* session_id_len */
 
326
        if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
 
327
                goto not_ssl_hello;
 
328
 
 
329
        /* Jump to cipher suite */
 
330
        hs_len -= 35 + ext_len;
 
331
        data   += 35 + ext_len;
 
332
 
 
333
        if (hs_len < 4 ||                               /* minimum one cipher */
 
334
            (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
 
335
            ext_len > hs_len)
 
336
                goto not_ssl_hello;
 
337
 
 
338
        /* Jump to the compression methods */
 
339
        hs_len -= 2 + ext_len;
 
340
        data   += 2 + ext_len;
 
341
 
 
342
        if (hs_len < 2 ||                       /* minimum one compression method */
 
343
            data[0] < 1 || data[0] > hs_len)    /* minimum 1 bytes for a method */
 
344
                goto not_ssl_hello;
 
345
 
 
346
        /* Jump to the extensions */
 
347
        hs_len -= 1 + data[0];
 
348
        data   += 1 + data[0];
 
349
 
 
350
        if (hs_len < 2 ||                       /* minimum one extension list length */
 
351
            (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
 
352
                goto not_ssl_hello;
 
353
 
 
354
        hs_len = ext_len; /* limit ourselves to the extension length */
 
355
        data += 2;
 
356
 
 
357
        while (hs_len >= 4) {
 
358
                int ext_type, name_type, srv_len, name_len;
 
359
 
 
360
                ext_type = (data[0] << 8) + data[1];
 
361
                ext_len  = (data[2] << 8) + data[3];
 
362
 
 
363
                if (ext_len > hs_len - 4) /* Extension too long */
 
364
                        goto not_ssl_hello;
 
365
 
 
366
                if (ext_type == 0) { /* Server name */
 
367
                        if (ext_len < 2) /* need one list length */
 
368
                                goto not_ssl_hello;
 
369
 
 
370
                        srv_len = (data[4] << 8) + data[5];
 
371
                        if (srv_len < 4 || srv_len > hs_len - 6)
 
372
                                goto not_ssl_hello; /* at least 4 bytes per server name */
 
373
 
 
374
                        name_type = data[6];
 
375
                        name_len = (data[7] << 8) + data[8];
 
376
 
 
377
                        if (name_type == 0) { /* hostname */
 
378
                                smp->type = SMP_T_STR;
 
379
                                smp->data.str.str = (char *)data + 9;
 
380
                                smp->data.str.len = name_len;
 
381
                                smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
 
382
                                return 1;
 
383
                        }
 
384
                }
 
385
 
 
386
                hs_len -= 4 + ext_len;
 
387
                data   += 4 + ext_len;
 
388
        }
 
389
        /* server name not found */
 
390
        goto not_ssl_hello;
 
391
 
 
392
 too_short:
 
393
        smp->flags = SMP_F_MAY_CHANGE;
 
394
 
 
395
 not_ssl_hello:
 
396
 
 
397
        return 0;
 
398
}
 
399
 
 
400
/* Fetch the request RDP cookie identified in <cname>:<clen>, or any cookie if
 
401
 * <clen> is empty (cname is then ignored). It returns the data into sample <smp>
 
402
 * of type SMP_T_CSTR. Note: this decoder only works with non-wrapping data.
 
403
 */
 
404
int
 
405
fetch_rdp_cookie_name(struct session *s, struct sample *smp, const char *cname, int clen)
 
406
{
 
407
        int bleft;
 
408
        const unsigned char *data;
 
409
 
 
410
        if (!s || !s->req)
 
411
                return 0;
 
412
 
 
413
        smp->flags = SMP_F_CONST;
 
414
        smp->type = SMP_T_STR;
 
415
 
 
416
        bleft = s->req->buf->i;
 
417
        if (bleft <= 11)
 
418
                goto too_short;
 
419
 
 
420
        data = (const unsigned char *)s->req->buf->p + 11;
 
421
        bleft -= 11;
 
422
 
 
423
        if (bleft <= 7)
 
424
                goto too_short;
 
425
 
 
426
        if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
 
427
                goto not_cookie;
 
428
 
 
429
        data += 7;
 
430
        bleft -= 7;
 
431
 
 
432
        while (bleft > 0 && *data == ' ') {
 
433
                data++;
 
434
                bleft--;
 
435
        }
 
436
 
 
437
        if (clen) {
 
438
                if (bleft <= clen)
 
439
                        goto too_short;
 
440
 
 
441
                if ((data[clen] != '=') ||
 
442
                    strncasecmp(cname, (const char *)data, clen) != 0)
 
443
                        goto not_cookie;
 
444
 
 
445
                data += clen + 1;
 
446
                bleft -= clen + 1;
 
447
        } else {
 
448
                while (bleft > 0 && *data != '=') {
 
449
                        if (*data == '\r' || *data == '\n')
 
450
                                goto not_cookie;
 
451
                        data++;
 
452
                        bleft--;
 
453
                }
 
454
 
 
455
                if (bleft < 1)
 
456
                        goto too_short;
 
457
 
 
458
                if (*data != '=')
 
459
                        goto not_cookie;
 
460
 
 
461
                data++;
 
462
                bleft--;
 
463
        }
 
464
 
 
465
        /* data points to cookie value */
 
466
        smp->data.str.str = (char *)data;
 
467
        smp->data.str.len = 0;
 
468
 
 
469
        while (bleft > 0 && *data != '\r') {
 
470
                data++;
 
471
                bleft--;
 
472
        }
 
473
 
 
474
        if (bleft < 2)
 
475
                goto too_short;
 
476
 
 
477
        if (data[0] != '\r' || data[1] != '\n')
 
478
                goto not_cookie;
 
479
 
 
480
        smp->data.str.len = (char *)data - smp->data.str.str;
 
481
        smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
 
482
        return 1;
 
483
 
 
484
 too_short:
 
485
        smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
 
486
 not_cookie:
 
487
        return 0;
 
488
}
 
489
 
 
490
/* Fetch the request RDP cookie identified in the args, or any cookie if no arg
 
491
 * is passed. It is usable both for ACL and for samples. Note: this decoder
 
492
 * only works with non-wrapping data. Accepts either 0 or 1 argument. Argument
 
493
 * is a string (cookie name), other types will lead to undefined behaviour. The
 
494
 * returned sample has type SMP_T_CSTR.
 
495
 */
 
496
int
 
497
smp_fetch_rdp_cookie(struct proxy *px, struct session *s, void *l7, unsigned int opt,
 
498
                     const struct arg *args, struct sample *smp, const char *kw)
 
499
{
 
500
        return fetch_rdp_cookie_name(s, smp, args ? args->data.str.str : NULL, args ? args->data.str.len : 0);
 
501
}
 
502
 
 
503
/* returns either 1 or 0 depending on whether an RDP cookie is found or not */
 
504
static int
 
505
smp_fetch_rdp_cookie_cnt(struct proxy *px, struct session *s, void *l7, unsigned int opt,
 
506
                         const struct arg *args, struct sample *smp, const char *kw)
 
507
{
 
508
        int ret;
 
509
 
 
510
        ret = smp_fetch_rdp_cookie(px, s, l7, opt, args, smp, kw);
 
511
 
 
512
        if (smp->flags & SMP_F_MAY_CHANGE)
 
513
                return 0;
 
514
 
 
515
        smp->flags = SMP_F_VOLATILE;
 
516
        smp->type = SMP_T_UINT;
 
517
        smp->data.uint = ret;
 
518
        return 1;
 
519
}
 
520
 
 
521
/* extracts part of a payload with offset and length at a given position */
 
522
static int
 
523
smp_fetch_payload_lv(struct proxy *px, struct session *s, void *l7, unsigned int opt,
 
524
                     const struct arg *arg_p, struct sample *smp, const char *kw)
 
525
{
 
526
        unsigned int len_offset = arg_p[0].data.uint;
 
527
        unsigned int len_size = arg_p[1].data.uint;
 
528
        unsigned int buf_offset;
 
529
        unsigned int buf_size = 0;
 
530
        struct channel *chn;
 
531
        int i;
 
532
 
 
533
        /* Format is (len offset, len size, buf offset) or (len offset, len size) */
 
534
        /* by default buf offset == len offset + len size */
 
535
        /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
 
536
 
 
537
        if (!s)
 
538
                return 0;
 
539
 
 
540
        chn = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? s->rep : s->req;
 
541
 
 
542
        if (!chn)
 
543
                return 0;
 
544
 
 
545
        if (len_offset + len_size > chn->buf->i)
 
546
                goto too_short;
 
547
 
 
548
        for (i = 0; i < len_size; i++) {
 
549
                buf_size = (buf_size << 8) + ((unsigned char *)chn->buf->p)[i + len_offset];
 
550
        }
 
551
 
 
552
        /* buf offset may be implicit, absolute or relative */
 
553
        buf_offset = len_offset + len_size;
 
554
        if (arg_p[2].type == ARGT_UINT)
 
555
                buf_offset = arg_p[2].data.uint;
 
556
        else if (arg_p[2].type == ARGT_SINT)
 
557
                buf_offset += arg_p[2].data.sint;
 
558
 
 
559
        if (!buf_size || buf_size > chn->buf->size || buf_offset + buf_size > chn->buf->size) {
 
560
                /* will never match */
 
561
                smp->flags = 0;
 
562
                return 0;
 
563
        }
 
564
 
 
565
        if (buf_offset + buf_size > chn->buf->i)
 
566
                goto too_short;
 
567
 
 
568
        /* init chunk as read only */
 
569
        smp->type = SMP_T_BIN;
 
570
        smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
 
571
        chunk_initlen(&smp->data.str, chn->buf->p + buf_offset, 0, buf_size);
 
572
        return 1;
 
573
 
 
574
 too_short:
 
575
        smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
 
576
        return 0;
 
577
}
 
578
 
 
579
/* extracts some payload at a fixed position and length */
 
580
static int
 
581
smp_fetch_payload(struct proxy *px, struct session *s, void *l7, unsigned int opt,
 
582
                  const struct arg *arg_p, struct sample *smp, const char *kw)
 
583
{
 
584
        unsigned int buf_offset = arg_p[0].data.uint;
 
585
        unsigned int buf_size = arg_p[1].data.uint;
 
586
        struct channel *chn;
 
587
 
 
588
        if (!s)
 
589
                return 0;
 
590
 
 
591
        chn = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? s->rep : s->req;
 
592
 
 
593
        if (!chn)
 
594
                return 0;
 
595
 
 
596
        if (buf_size > chn->buf->size || buf_offset + buf_size > chn->buf->size) {
 
597
                /* will never match */
 
598
                smp->flags = 0;
 
599
                return 0;
 
600
        }
 
601
 
 
602
        if (buf_offset + buf_size > chn->buf->i)
 
603
                goto too_short;
 
604
 
 
605
        /* init chunk as read only */
 
606
        smp->type = SMP_T_BIN;
 
607
        smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
 
608
        chunk_initlen(&smp->data.str, chn->buf->p + buf_offset, 0, buf_size ? buf_size : (chn->buf->i - buf_offset));
 
609
        if (!buf_size && !channel_full(chn) && !channel_input_closed(chn))
 
610
                smp->flags |= SMP_F_MAY_CHANGE;
 
611
 
 
612
        return 1;
 
613
 
 
614
 too_short:
 
615
        smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
 
616
        return 0;
 
617
}
 
618
 
 
619
/* This function is used to validate the arguments passed to a "payload_lv" fetch
 
620
 * keyword. This keyword allows two positive integers and an optional signed one,
 
621
 * with the second one being strictly positive and the third one being greater than
 
622
 * the opposite of the two others if negative. It is assumed that the types are
 
623
 * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> is
 
624
 * not NULL, it will be filled with a pointer to an error message in case of
 
625
 * error, that the caller is responsible for freeing. The initial location must
 
626
 * either be freeable or NULL.
 
627
 */
 
628
static int val_payload_lv(struct arg *arg, char **err_msg)
 
629
{
 
630
        if (!arg[1].data.uint) {
 
631
                memprintf(err_msg, "payload length must be > 0");
 
632
                return 0;
 
633
        }
 
634
 
 
635
        if (arg[2].type == ARGT_SINT &&
 
636
            (int)(arg[0].data.uint + arg[1].data.uint + arg[2].data.sint) < 0) {
 
637
                memprintf(err_msg, "payload offset too negative");
 
638
                return 0;
 
639
        }
 
640
        return 1;
 
641
}
 
642
 
 
643
/************************************************************************/
 
644
/*      All supported sample and ACL keywords must be declared here.    */
 
645
/************************************************************************/
 
646
 
 
647
/* Note: must not be declared <const> as its list will be overwritten.
 
648
 * Note: fetches that may return multiple types must be declared as the lowest
 
649
 * common denominator, the type that can be casted into all other ones. For
 
650
 * instance IPv4/IPv6 must be declared IPv4.
 
651
 */
 
652
static struct sample_fetch_kw_list smp_kws = {ILH, {
 
653
        { "payload",             smp_fetch_payload,        ARG2(2,UINT,UINT),      NULL,           SMP_T_BIN,  SMP_USE_L6REQ|SMP_USE_L6RES },
 
654
        { "payload_lv",          smp_fetch_payload_lv,     ARG3(2,UINT,UINT,SINT), val_payload_lv, SMP_T_BIN,  SMP_USE_L6REQ|SMP_USE_L6RES },
 
655
        { "rdp_cookie",          smp_fetch_rdp_cookie,     ARG1(0,STR),            NULL,           SMP_T_STR,  SMP_USE_L6REQ },
 
656
        { "rdp_cookie_cnt",      smp_fetch_rdp_cookie_cnt, ARG1(0,STR),            NULL,           SMP_T_UINT, SMP_USE_L6REQ },
 
657
        { "rep_ssl_hello_type",  smp_fetch_ssl_hello_type, 0,                      NULL,           SMP_T_UINT, SMP_USE_L6RES },
 
658
        { "req_len",             smp_fetch_len,            0,                      NULL,           SMP_T_UINT, SMP_USE_L6REQ },
 
659
        { "req_ssl_hello_type",  smp_fetch_ssl_hello_type, 0,                      NULL,           SMP_T_UINT, SMP_USE_L6REQ },
 
660
        { "req_ssl_sni",         smp_fetch_ssl_hello_sni,  0,                      NULL,           SMP_T_STR,  SMP_USE_L6REQ },
 
661
        { "req_ssl_ver",         smp_fetch_req_ssl_ver,    0,                      NULL,           SMP_T_UINT, SMP_USE_L6REQ },
 
662
 
 
663
        { "req.len",             smp_fetch_len,            0,                      NULL,           SMP_T_UINT, SMP_USE_L6REQ },
 
664
        { "req.payload",         smp_fetch_payload,        ARG2(2,UINT,UINT),      NULL,           SMP_T_BIN,  SMP_USE_L6REQ },
 
665
        { "req.payload_lv",      smp_fetch_payload_lv,     ARG3(2,UINT,UINT,SINT), val_payload_lv, SMP_T_BIN,  SMP_USE_L6REQ },
 
666
        { "req.rdp_cookie",      smp_fetch_rdp_cookie,     ARG1(0,STR),            NULL,           SMP_T_STR,  SMP_USE_L6REQ },
 
667
        { "req.rdp_cookie_cnt",  smp_fetch_rdp_cookie_cnt, ARG1(0,STR),            NULL,           SMP_T_UINT, SMP_USE_L6REQ },
 
668
        { "req.ssl_hello_type",  smp_fetch_ssl_hello_type, 0,                      NULL,           SMP_T_UINT, SMP_USE_L6REQ },
 
669
        { "req.ssl_sni",         smp_fetch_ssl_hello_sni,  0,                      NULL,           SMP_T_STR,  SMP_USE_L6REQ },
 
670
        { "req.ssl_ver",         smp_fetch_req_ssl_ver,    0,                      NULL,           SMP_T_UINT, SMP_USE_L6REQ },
 
671
        { "res.len",             smp_fetch_len,            0,                      NULL,           SMP_T_UINT, SMP_USE_L6RES },
 
672
        { "res.payload",         smp_fetch_payload,        ARG2(2,UINT,UINT),      NULL,           SMP_T_BIN,  SMP_USE_L6RES },
 
673
        { "res.payload_lv",      smp_fetch_payload_lv,     ARG3(2,UINT,UINT,SINT), val_payload_lv, SMP_T_BIN,  SMP_USE_L6RES },
 
674
        { "res.ssl_hello_type",  smp_fetch_ssl_hello_type, 0,                      NULL,           SMP_T_UINT, SMP_USE_L6RES },
 
675
        { "wait_end",            smp_fetch_wait_end,       0,                      NULL,           SMP_T_BOOL, SMP_USE_INTRN },
 
676
        { /* END */ },
 
677
}};
 
678
 
 
679
 
 
680
/* Note: must not be declared <const> as its list will be overwritten.
 
681
 * Please take care of keeping this list alphabetically sorted.
 
682
 */
 
683
static struct acl_kw_list acl_kws = {ILH, {
 
684
        { "payload",            "req.payload",        PAT_MATCH_BIN },
 
685
        { "payload_lv",         "req.payload_lv",     PAT_MATCH_BIN },
 
686
        { "req_rdp_cookie",     "req.rdp_cookie",     PAT_MATCH_STR },
 
687
        { "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", PAT_MATCH_INT },
 
688
        { "req_ssl_sni",        "req.ssl_sni",        PAT_MATCH_STR },
 
689
        { "req_ssl_ver",        "req.ssl_ver",        PAT_MATCH_INT, pat_parse_dotted_ver },
 
690
        { "req.ssl_ver",        "req.ssl_ver",        PAT_MATCH_INT, pat_parse_dotted_ver },
 
691
        { /* END */ },
 
692
}};
 
693
 
 
694
 
 
695
__attribute__((constructor))
 
696
static void __payload_init(void)
 
697
{
 
698
        sample_register_fetches(&smp_kws);
 
699
        acl_register_keywords(&acl_kws);
 
700
}
 
701
 
 
702
/*
 
703
 * Local variables:
 
704
 *  c-indent-level: 8
 
705
 *  c-basic-offset: 8
 
706
 * End:
 
707
 */