blob: 852727a639819dd4cc4bb0cd8ca048a5f87d4299 [file] [log] [blame]
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001/*
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>
Thierry FOURNIERed66c292013-11-28 11:05:19 +010019#include <proto/pattern.h>
Willy Tarreaud4c33c82013-01-07 21:59:07 +010020#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 */
31static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020032smp_fetch_wait_end(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010033{
Thierry FOURNIER0786d052015-05-11 15:42:45 +020034 if (!(smp->opt & SMP_OPT_FINAL)) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +010035 smp->flags |= SMP_F_MAY_CHANGE;
36 return 0;
37 }
38 smp->type = SMP_T_BOOL;
39 smp->data.uint = 1;
40 return 1;
41}
42
43/* return the number of bytes in the request buffer */
44static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020045smp_fetch_len(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010046{
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010047 struct channel *chn;
48
Thierry FOURNIER0786d052015-05-11 15:42:45 +020049 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010050 if (!chn->buf)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010051 return 0;
52
53 smp->type = SMP_T_UINT;
Willy Tarreau47e8eba2013-09-11 23:28:46 +020054 smp->data.uint = chn->buf->i;
Willy Tarreaud4c33c82013-01-07 21:59:07 +010055 smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
56 return 1;
57}
58
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +020059/* Returns TRUE if the client sent Supported Elliptic Curves Extension (0x000a)
60 * Mainly used to detect if client supports ECC cipher suites.
61 */
62static int
63smp_fetch_req_ssl_ec_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
64{
65 int hs_len, ext_len, bleft;
66 struct channel *chn;
67 unsigned char *data;
68
69 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
70 if (!chn->buf)
71 goto not_ssl_hello;
72
73 bleft = chn->buf->i;
74 data = (unsigned char *)chn->buf->p;
75
76 /* Check for SSL/TLS Handshake */
77 if (!bleft)
78 goto too_short;
79 if (*data != 0x16)
80 goto not_ssl_hello;
81
82 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
83 if (bleft < 3)
84 goto too_short;
85 if (data[1] < 0x03)
86 goto not_ssl_hello;
87
88 if (bleft < 5)
89 goto too_short;
90 hs_len = (data[3] << 8) + data[4];
91 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
92 goto not_ssl_hello; /* too short to have an extension */
93
94 data += 5; /* enter TLS handshake */
95 bleft -= 5;
96
97 /* Check for a complete client hello starting at <data> */
98 if (bleft < 1)
99 goto too_short;
100 if (data[0] != 0x01) /* msg_type = Client Hello */
101 goto not_ssl_hello;
102
103 /* Check the Hello's length */
104 if (bleft < 4)
105 goto too_short;
106 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
107 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
108 goto not_ssl_hello; /* too short to have an extension */
109
110 /* We want the full handshake here */
111 if (bleft < hs_len)
112 goto too_short;
113
114 data += 4;
115 /* Start of the ClientHello message */
116 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
117 goto not_ssl_hello;
118
119 ext_len = data[34]; /* session_id_len */
120 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
121 goto not_ssl_hello;
122
123 /* Jump to cipher suite */
124 hs_len -= 35 + ext_len;
125 data += 35 + ext_len;
126
127 if (hs_len < 4 || /* minimum one cipher */
128 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
129 ext_len > hs_len)
130 goto not_ssl_hello;
131
132 /* Jump to the compression methods */
133 hs_len -= 2 + ext_len;
134 data += 2 + ext_len;
135
136 if (hs_len < 2 || /* minimum one compression method */
137 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
138 goto not_ssl_hello;
139
140 /* Jump to the extensions */
141 hs_len -= 1 + data[0];
142 data += 1 + data[0];
143
144 if (hs_len < 2 || /* minimum one extension list length */
145 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
146 goto not_ssl_hello;
147
148 hs_len = ext_len; /* limit ourselves to the extension length */
149 data += 2;
150
151 while (hs_len >= 4) {
152 int ext_type, ext_len;
153
154 ext_type = (data[0] << 8) + data[1];
155 ext_len = (data[2] << 8) + data[3];
156
157 if (ext_len > hs_len - 4) /* Extension too long */
158 goto not_ssl_hello;
159
160 /* Elliptic curves extension */
161 if (ext_type == 10) {
162 smp->type = SMP_T_BOOL;
163 smp->data.uint = 1;
Nenad Merdanovic8a39a1f2015-07-15 12:51:11 +0200164 smp->flags = SMP_F_VOLATILE;
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200165 return 1;
166 }
167
168 hs_len -= 4 + ext_len;
169 data += 4 + ext_len;
170 }
171 /* server name not found */
172 goto not_ssl_hello;
173
174 too_short:
175 smp->flags = SMP_F_MAY_CHANGE;
176
177 not_ssl_hello:
178
179 return 0;
180}
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100181/* returns the type of SSL hello message (mainly used to detect an SSL hello) */
182static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200183smp_fetch_ssl_hello_type(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100184{
185 int hs_len;
186 int hs_type, bleft;
187 struct channel *chn;
188 const unsigned char *data;
189
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200190 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +0100191 if (!chn->buf)
Willy Tarreau83f25922014-11-26 13:24:24 +0100192 goto not_ssl_hello;
193
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100194 bleft = chn->buf->i;
195 data = (const unsigned char *)chn->buf->p;
196
197 if (!bleft)
198 goto too_short;
199
200 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
201 /* SSLv3 header format */
202 if (bleft < 9)
203 goto too_short;
204
205 /* ssl version 3 */
206 if ((data[1] << 16) + data[2] < 0x00030000)
207 goto not_ssl_hello;
208
209 /* ssl message len must present handshake type and len */
210 if ((data[3] << 8) + data[4] < 4)
211 goto not_ssl_hello;
212
213 /* format introduced with SSLv3 */
214
215 hs_type = (int)data[5];
216 hs_len = ( data[6] << 16 ) + ( data[7] << 8 ) + data[8];
217
218 /* not a full handshake */
219 if (bleft < (9 + hs_len))
220 goto too_short;
221
222 }
223 else {
224 goto not_ssl_hello;
225 }
226
227 smp->type = SMP_T_UINT;
228 smp->data.uint = hs_type;
229 smp->flags = SMP_F_VOLATILE;
230
231 return 1;
232
233 too_short:
234 smp->flags = SMP_F_MAY_CHANGE;
235
236 not_ssl_hello:
237
238 return 0;
239}
240
241/* Return the version of the SSL protocol in the request. It supports both
242 * SSLv3 (TLSv1) header format for any message, and SSLv2 header format for
243 * the hello message. The SSLv3 format is described in RFC 2246 p49, and the
244 * SSLv2 format is described here, and completed p67 of RFC 2246 :
245 * http://wp.netscape.com/eng/security/SSL_2.html
246 *
247 * Note: this decoder only works with non-wrapping data.
248 */
249static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200250smp_fetch_req_ssl_ver(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100251{
252 int version, bleft, msg_len;
253 const unsigned char *data;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200254 struct channel *req = &smp->strm->req;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100255
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200256 if (!req->buf)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100257 return 0;
258
259 msg_len = 0;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200260 bleft = req->buf->i;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100261 if (!bleft)
262 goto too_short;
263
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200264 data = (const unsigned char *)req->buf->p;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100265 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
266 /* SSLv3 header format */
267 if (bleft < 5)
268 goto too_short;
269
270 version = (data[1] << 16) + data[2]; /* version: major, minor */
271 msg_len = (data[3] << 8) + data[4]; /* record length */
272
273 /* format introduced with SSLv3 */
274 if (version < 0x00030000)
275 goto not_ssl;
276
277 /* message length between 1 and 2^14 + 2048 */
278 if (msg_len < 1 || msg_len > ((1<<14) + 2048))
279 goto not_ssl;
280
281 bleft -= 5; data += 5;
282 } else {
283 /* SSLv2 header format, only supported for hello (msg type 1) */
284 int rlen, plen, cilen, silen, chlen;
285
286 if (*data & 0x80) {
287 if (bleft < 3)
288 goto too_short;
289 /* short header format : 15 bits for length */
290 rlen = ((data[0] & 0x7F) << 8) | data[1];
291 plen = 0;
292 bleft -= 2; data += 2;
293 } else {
294 if (bleft < 4)
295 goto too_short;
296 /* long header format : 14 bits for length + pad length */
297 rlen = ((data[0] & 0x3F) << 8) | data[1];
298 plen = data[2];
299 bleft -= 3; data += 2;
300 }
301
302 if (*data != 0x01)
303 goto not_ssl;
304 bleft--; data++;
305
306 if (bleft < 8)
307 goto too_short;
308 version = (data[0] << 16) + data[1]; /* version: major, minor */
309 cilen = (data[2] << 8) + data[3]; /* cipher len, multiple of 3 */
310 silen = (data[4] << 8) + data[5]; /* session_id_len: 0 or 16 */
311 chlen = (data[6] << 8) + data[7]; /* 16<=challenge length<=32 */
312
313 bleft -= 8; data += 8;
314 if (cilen % 3 != 0)
315 goto not_ssl;
316 if (silen && silen != 16)
317 goto not_ssl;
318 if (chlen < 16 || chlen > 32)
319 goto not_ssl;
320 if (rlen != 9 + cilen + silen + chlen)
321 goto not_ssl;
322
323 /* focus on the remaining data length */
324 msg_len = cilen + silen + chlen + plen;
325 }
326 /* We could recursively check that the buffer ends exactly on an SSL
327 * fragment boundary and that a possible next segment is still SSL,
328 * but that's a bit pointless. However, we could still check that
329 * all the part of the request which fits in a buffer is already
330 * there.
331 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200332 if (msg_len > channel_recv_limit(req) + req->buf->data - req->buf->p)
333 msg_len = channel_recv_limit(req) + req->buf->data - req->buf->p;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100334
335 if (bleft < msg_len)
336 goto too_short;
337
338 /* OK that's enough. We have at least the whole message, and we have
339 * the protocol version.
340 */
341 smp->type = SMP_T_UINT;
342 smp->data.uint = version;
343 smp->flags = SMP_F_VOLATILE;
344 return 1;
345
346 too_short:
347 smp->flags = SMP_F_MAY_CHANGE;
348 not_ssl:
349 return 0;
350}
351
352/* Try to extract the Server Name Indication that may be presented in a TLS
353 * client hello handshake message. The format of the message is the following
354 * (cf RFC5246 + RFC6066) :
355 * TLS frame :
356 * - uint8 type = 0x16 (Handshake)
357 * - uint16 version >= 0x0301 (TLSv1)
358 * - uint16 length (frame length)
359 * - TLS handshake :
360 * - uint8 msg_type = 0x01 (ClientHello)
361 * - uint24 length (handshake message length)
362 * - ClientHello :
363 * - uint16 client_version >= 0x0301 (TLSv1)
364 * - uint8 Random[32] (4 first ones are timestamp)
365 * - SessionID :
366 * - uint8 session_id_len (0..32) (SessionID len in bytes)
367 * - uint8 session_id[session_id_len]
368 * - CipherSuite :
369 * - uint16 cipher_len >= 2 (Cipher length in bytes)
370 * - uint16 ciphers[cipher_len/2]
371 * - CompressionMethod :
372 * - uint8 compression_len >= 1 (# of supported methods)
373 * - uint8 compression_methods[compression_len]
374 * - optional client_extension_len (in bytes)
375 * - optional sequence of ClientHelloExtensions (as many bytes as above):
376 * - uint16 extension_type = 0 for server_name
377 * - uint16 extension_len
378 * - opaque extension_data[extension_len]
379 * - uint16 server_name_list_len (# of bytes here)
380 * - opaque server_names[server_name_list_len bytes]
381 * - uint8 name_type = 0 for host_name
382 * - uint16 name_len
383 * - opaque hostname[name_len bytes]
384 */
385static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200386smp_fetch_ssl_hello_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100387{
388 int hs_len, ext_len, bleft;
389 struct channel *chn;
390 unsigned char *data;
391
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200392 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +0100393 if (!chn->buf)
Willy Tarreau83f25922014-11-26 13:24:24 +0100394 goto not_ssl_hello;
395
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100396 bleft = chn->buf->i;
397 data = (unsigned char *)chn->buf->p;
398
399 /* Check for SSL/TLS Handshake */
400 if (!bleft)
401 goto too_short;
402 if (*data != 0x16)
403 goto not_ssl_hello;
404
Lukas Tribus57d22972014-04-10 21:36:22 +0200405 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100406 if (bleft < 3)
407 goto too_short;
Lukas Tribus57d22972014-04-10 21:36:22 +0200408 if (data[1] < 0x03)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100409 goto not_ssl_hello;
410
411 if (bleft < 5)
412 goto too_short;
413 hs_len = (data[3] << 8) + data[4];
414 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
415 goto not_ssl_hello; /* too short to have an extension */
416
417 data += 5; /* enter TLS handshake */
418 bleft -= 5;
419
420 /* Check for a complete client hello starting at <data> */
421 if (bleft < 1)
422 goto too_short;
423 if (data[0] != 0x01) /* msg_type = Client Hello */
424 goto not_ssl_hello;
425
426 /* Check the Hello's length */
427 if (bleft < 4)
428 goto too_short;
429 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
430 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
431 goto not_ssl_hello; /* too short to have an extension */
432
433 /* We want the full handshake here */
434 if (bleft < hs_len)
435 goto too_short;
436
437 data += 4;
438 /* Start of the ClientHello message */
439 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
440 goto not_ssl_hello;
441
442 ext_len = data[34]; /* session_id_len */
443 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
444 goto not_ssl_hello;
445
446 /* Jump to cipher suite */
447 hs_len -= 35 + ext_len;
448 data += 35 + ext_len;
449
450 if (hs_len < 4 || /* minimum one cipher */
451 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
452 ext_len > hs_len)
453 goto not_ssl_hello;
454
455 /* Jump to the compression methods */
456 hs_len -= 2 + ext_len;
457 data += 2 + ext_len;
458
459 if (hs_len < 2 || /* minimum one compression method */
460 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
461 goto not_ssl_hello;
462
463 /* Jump to the extensions */
464 hs_len -= 1 + data[0];
465 data += 1 + data[0];
466
467 if (hs_len < 2 || /* minimum one extension list length */
468 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
469 goto not_ssl_hello;
470
471 hs_len = ext_len; /* limit ourselves to the extension length */
472 data += 2;
473
474 while (hs_len >= 4) {
475 int ext_type, name_type, srv_len, name_len;
476
477 ext_type = (data[0] << 8) + data[1];
478 ext_len = (data[2] << 8) + data[3];
479
480 if (ext_len > hs_len - 4) /* Extension too long */
481 goto not_ssl_hello;
482
483 if (ext_type == 0) { /* Server name */
484 if (ext_len < 2) /* need one list length */
485 goto not_ssl_hello;
486
487 srv_len = (data[4] << 8) + data[5];
488 if (srv_len < 4 || srv_len > hs_len - 6)
489 goto not_ssl_hello; /* at least 4 bytes per server name */
490
491 name_type = data[6];
492 name_len = (data[7] << 8) + data[8];
493
494 if (name_type == 0) { /* hostname */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100495 smp->type = SMP_T_STR;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100496 smp->data.str.str = (char *)data + 9;
497 smp->data.str.len = name_len;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100498 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100499 return 1;
500 }
501 }
502
503 hs_len -= 4 + ext_len;
504 data += 4 + ext_len;
505 }
506 /* server name not found */
507 goto not_ssl_hello;
508
509 too_short:
510 smp->flags = SMP_F_MAY_CHANGE;
511
512 not_ssl_hello:
513
514 return 0;
515}
516
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200517/* Fetch the request RDP cookie identified in <cname>:<clen>, or any cookie if
Willy Tarreaub169eba2013-12-16 15:14:43 +0100518 * <clen> is empty (cname is then ignored). It returns the data into sample <smp>
519 * of type SMP_T_CSTR. Note: this decoder only works with non-wrapping data.
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100520 */
521int
Willy Tarreau87b09662015-04-03 00:22:06 +0200522fetch_rdp_cookie_name(struct stream *s, struct sample *smp, const char *cname, int clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100523{
524 int bleft;
525 const unsigned char *data;
526
Willy Tarreau53c9b4d2015-04-03 21:38:18 +0200527 if (!s->req.buf)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100528 return 0;
529
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100530 smp->flags = SMP_F_CONST;
531 smp->type = SMP_T_STR;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100532
Willy Tarreau22ec1ea2014-11-27 20:45:39 +0100533 bleft = s->req.buf->i;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100534 if (bleft <= 11)
535 goto too_short;
536
Willy Tarreau22ec1ea2014-11-27 20:45:39 +0100537 data = (const unsigned char *)s->req.buf->p + 11;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100538 bleft -= 11;
539
540 if (bleft <= 7)
541 goto too_short;
542
543 if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
544 goto not_cookie;
545
546 data += 7;
547 bleft -= 7;
548
549 while (bleft > 0 && *data == ' ') {
550 data++;
551 bleft--;
552 }
553
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200554 if (clen) {
555 if (bleft <= clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100556 goto too_short;
557
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200558 if ((data[clen] != '=') ||
559 strncasecmp(cname, (const char *)data, clen) != 0)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100560 goto not_cookie;
561
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200562 data += clen + 1;
563 bleft -= clen + 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100564 } else {
565 while (bleft > 0 && *data != '=') {
566 if (*data == '\r' || *data == '\n')
567 goto not_cookie;
568 data++;
569 bleft--;
570 }
571
572 if (bleft < 1)
573 goto too_short;
574
575 if (*data != '=')
576 goto not_cookie;
577
578 data++;
579 bleft--;
580 }
581
582 /* data points to cookie value */
583 smp->data.str.str = (char *)data;
584 smp->data.str.len = 0;
585
586 while (bleft > 0 && *data != '\r') {
587 data++;
588 bleft--;
589 }
590
591 if (bleft < 2)
592 goto too_short;
593
594 if (data[0] != '\r' || data[1] != '\n')
595 goto not_cookie;
596
597 smp->data.str.len = (char *)data - smp->data.str.str;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100598 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100599 return 1;
600
601 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100602 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100603 not_cookie:
604 return 0;
605}
606
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200607/* Fetch the request RDP cookie identified in the args, or any cookie if no arg
608 * is passed. It is usable both for ACL and for samples. Note: this decoder
609 * only works with non-wrapping data. Accepts either 0 or 1 argument. Argument
Willy Tarreaub169eba2013-12-16 15:14:43 +0100610 * is a string (cookie name), other types will lead to undefined behaviour. The
611 * returned sample has type SMP_T_CSTR.
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200612 */
613int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200614smp_fetch_rdp_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200615{
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200616 return fetch_rdp_cookie_name(smp->strm, smp, args ? args->data.str.str : NULL, args ? args->data.str.len : 0);
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200617}
618
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100619/* returns either 1 or 0 depending on whether an RDP cookie is found or not */
620static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200621smp_fetch_rdp_cookie_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100622{
623 int ret;
624
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200625 ret = smp_fetch_rdp_cookie(args, smp, kw, private);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100626
627 if (smp->flags & SMP_F_MAY_CHANGE)
628 return 0;
629
630 smp->flags = SMP_F_VOLATILE;
631 smp->type = SMP_T_UINT;
632 smp->data.uint = ret;
633 return 1;
634}
635
636/* extracts part of a payload with offset and length at a given position */
637static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200638smp_fetch_payload_lv(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100639{
640 unsigned int len_offset = arg_p[0].data.uint;
641 unsigned int len_size = arg_p[1].data.uint;
642 unsigned int buf_offset;
643 unsigned int buf_size = 0;
644 struct channel *chn;
645 int i;
646
647 /* Format is (len offset, len size, buf offset) or (len offset, len size) */
648 /* by default buf offset == len offset + len size */
649 /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
650
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200651 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +0100652 if (!chn->buf)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100653 return 0;
654
655 if (len_offset + len_size > chn->buf->i)
656 goto too_short;
657
658 for (i = 0; i < len_size; i++) {
659 buf_size = (buf_size << 8) + ((unsigned char *)chn->buf->p)[i + len_offset];
660 }
661
662 /* buf offset may be implicit, absolute or relative */
663 buf_offset = len_offset + len_size;
664 if (arg_p[2].type == ARGT_UINT)
665 buf_offset = arg_p[2].data.uint;
666 else if (arg_p[2].type == ARGT_SINT)
667 buf_offset += arg_p[2].data.sint;
668
669 if (!buf_size || buf_size > chn->buf->size || buf_offset + buf_size > chn->buf->size) {
670 /* will never match */
671 smp->flags = 0;
672 return 0;
673 }
674
675 if (buf_offset + buf_size > chn->buf->i)
676 goto too_short;
677
678 /* init chunk as read only */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100679 smp->type = SMP_T_BIN;
680 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100681 chunk_initlen(&smp->data.str, chn->buf->p + buf_offset, 0, buf_size);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100682 return 1;
683
684 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100685 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100686 return 0;
687}
688
689/* extracts some payload at a fixed position and length */
690static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200691smp_fetch_payload(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100692{
693 unsigned int buf_offset = arg_p[0].data.uint;
694 unsigned int buf_size = arg_p[1].data.uint;
695 struct channel *chn;
696
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200697 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +0100698 if (!chn->buf)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100699 return 0;
700
Willy Tarreau00f00842013-08-02 11:07:32 +0200701 if (buf_size > chn->buf->size || buf_offset + buf_size > chn->buf->size) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100702 /* will never match */
703 smp->flags = 0;
704 return 0;
705 }
706
707 if (buf_offset + buf_size > chn->buf->i)
708 goto too_short;
709
710 /* init chunk as read only */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100711 smp->type = SMP_T_BIN;
712 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreau00f00842013-08-02 11:07:32 +0200713 chunk_initlen(&smp->data.str, chn->buf->p + buf_offset, 0, buf_size ? buf_size : (chn->buf->i - buf_offset));
Willy Tarreau3889fff2015-01-13 20:20:10 +0100714 if (!buf_size && channel_may_recv(chn) && !channel_input_closed(chn))
Willy Tarreau00f00842013-08-02 11:07:32 +0200715 smp->flags |= SMP_F_MAY_CHANGE;
716
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100717 return 1;
718
719 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100720 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100721 return 0;
722}
723
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100724/* This function is used to validate the arguments passed to a "payload_lv" fetch
725 * keyword. This keyword allows two positive integers and an optional signed one,
726 * with the second one being strictly positive and the third one being greater than
727 * the opposite of the two others if negative. It is assumed that the types are
728 * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> is
729 * not NULL, it will be filled with a pointer to an error message in case of
730 * error, that the caller is responsible for freeing. The initial location must
731 * either be freeable or NULL.
732 */
Thierry FOURNIER49f45af2014-12-08 19:50:43 +0100733int val_payload_lv(struct arg *arg, char **err_msg)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100734{
735 if (!arg[1].data.uint) {
736 memprintf(err_msg, "payload length must be > 0");
737 return 0;
738 }
739
740 if (arg[2].type == ARGT_SINT &&
741 (int)(arg[0].data.uint + arg[1].data.uint + arg[2].data.sint) < 0) {
742 memprintf(err_msg, "payload offset too negative");
743 return 0;
744 }
745 return 1;
746}
747
748/************************************************************************/
749/* All supported sample and ACL keywords must be declared here. */
750/************************************************************************/
751
752/* Note: must not be declared <const> as its list will be overwritten.
753 * Note: fetches that may return multiple types must be declared as the lowest
754 * common denominator, the type that can be casted into all other ones. For
755 * instance IPv4/IPv6 must be declared IPv4.
756 */
Willy Tarreaudc13c112013-06-21 23:16:39 +0200757static struct sample_fetch_kw_list smp_kws = {ILH, {
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100758 { "payload", smp_fetch_payload, ARG2(2,UINT,UINT), NULL, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
759 { "payload_lv", smp_fetch_payload_lv, ARG3(2,UINT,UINT,SINT), val_payload_lv, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
760 { "rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100761 { "rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_L6REQ },
762 { "rep_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_UINT, SMP_USE_L6RES },
Willy Tarreau47e8eba2013-09-11 23:28:46 +0200763 { "req_len", smp_fetch_len, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100764 { "req_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100765 { "req_ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100766 { "req_ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +0100767
Willy Tarreau47e8eba2013-09-11 23:28:46 +0200768 { "req.len", smp_fetch_len, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100769 { "req.payload", smp_fetch_payload, ARG2(2,UINT,UINT), NULL, SMP_T_BIN, SMP_USE_L6REQ },
770 { "req.payload_lv", smp_fetch_payload_lv, ARG3(2,UINT,UINT,SINT), val_payload_lv, SMP_T_BIN, SMP_USE_L6REQ },
771 { "req.rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +0100772 { "req.rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_L6REQ },
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200773 { "req.ssl_ec_ext", smp_fetch_req_ssl_ec_ext, 0, NULL, SMP_T_BOOL, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +0100774 { "req.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100775 { "req.ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +0100776 { "req.ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
Willy Tarreau47e8eba2013-09-11 23:28:46 +0200777 { "res.len", smp_fetch_len, 0, NULL, SMP_T_UINT, SMP_USE_L6RES },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100778 { "res.payload", smp_fetch_payload, ARG2(2,UINT,UINT), NULL, SMP_T_BIN, SMP_USE_L6RES },
779 { "res.payload_lv", smp_fetch_payload_lv, ARG3(2,UINT,UINT,SINT), val_payload_lv, SMP_T_BIN, SMP_USE_L6RES },
Willy Tarreaufa957342013-01-14 16:07:52 +0100780 { "res.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_UINT, SMP_USE_L6RES },
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100781 { "wait_end", smp_fetch_wait_end, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
782 { /* END */ },
783}};
784
785
786/* Note: must not be declared <const> as its list will be overwritten.
787 * Please take care of keeping this list alphabetically sorted.
788 */
Willy Tarreaudc13c112013-06-21 23:16:39 +0200789static struct acl_kw_list acl_kws = {ILH, {
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +0100790 { "payload", "req.payload", PAT_MATCH_BIN },
791 { "payload_lv", "req.payload_lv", PAT_MATCH_BIN },
792 { "req_rdp_cookie", "req.rdp_cookie", PAT_MATCH_STR },
793 { "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", PAT_MATCH_INT },
794 { "req_ssl_sni", "req.ssl_sni", PAT_MATCH_STR },
795 { "req_ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
796 { "req.ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100797 { /* END */ },
798}};
799
800
801__attribute__((constructor))
802static void __payload_init(void)
803{
804 sample_register_fetches(&smp_kws);
805 acl_register_keywords(&acl_kws);
806}
807
808/*
809 * Local variables:
810 * c-indent-level: 8
811 * c-basic-offset: 8
812 * End:
813 */