blob: 71d3ec00f74e3c6f8f9e2f096d1f35da5e62bb88 [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 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020038 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020039 smp->data.u.sint = 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +010040 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
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020053 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020054 smp->data.u.sint = 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) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200162 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200163 smp->data.u.sint = 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
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200227 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200228 smp->data.u.sint = hs_type;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100229 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 */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200341 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200342 smp->data.u.sint = version;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100343 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 FOURNIER8c542ca2015-08-19 09:00:18 +0200495 smp->data.type = SMP_T_STR;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200496 smp->data.u.str.str = (char *)data + 9;
497 smp->data.u.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;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200531 smp->data.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 */
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200583 smp->data.u.str.str = (char *)data;
584 smp->data.u.str.len = 0;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100585
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
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200597 smp->data.u.str.len = (char *)data - smp->data.u.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;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200631 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200632 smp->data.u.sint = ret;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100633 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{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200640 unsigned int len_offset = arg_p[0].data.sint;
641 unsigned int len_size = arg_p[1].data.sint;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100642 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
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200662 /* buf offset may be implicit, absolute or relative. If the LSB
663 * is set, then the offset is relative otherwise it is absolute.
664 */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100665 buf_offset = len_offset + len_size;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200666 if (arg_p[2].type == ARGT_SINT) {
667 if (arg_p[2].data.sint & 1)
668 buf_offset += arg_p[2].data.sint >> 1;
669 else
670 buf_offset = arg_p[2].data.sint >> 1;
671 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100672
Willy Tarreaud7bdcb82015-09-24 16:33:10 +0200673 if (!buf_size || buf_size > global.tune.bufsize || buf_offset + buf_size > global.tune.bufsize) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100674 /* will never match */
675 smp->flags = 0;
676 return 0;
677 }
678
679 if (buf_offset + buf_size > chn->buf->i)
680 goto too_short;
681
682 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200683 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100684 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200685 chunk_initlen(&smp->data.u.str, chn->buf->p + buf_offset, 0, buf_size);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100686 return 1;
687
688 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100689 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100690 return 0;
691}
692
693/* extracts some payload at a fixed position and length */
694static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200695smp_fetch_payload(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100696{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200697 unsigned int buf_offset = arg_p[0].data.sint;
698 unsigned int buf_size = arg_p[1].data.sint;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100699 struct channel *chn;
700
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200701 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +0100702 if (!chn->buf)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100703 return 0;
704
Willy Tarreaud7bdcb82015-09-24 16:33:10 +0200705 if (!buf_size || buf_size > global.tune.bufsize || buf_offset + buf_size > global.tune.bufsize) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100706 /* will never match */
707 smp->flags = 0;
708 return 0;
709 }
710
711 if (buf_offset + buf_size > chn->buf->i)
712 goto too_short;
713
714 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200715 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100716 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200717 chunk_initlen(&smp->data.u.str, chn->buf->p + buf_offset, 0, buf_size ? buf_size : (chn->buf->i - buf_offset));
Willy Tarreau3889fff2015-01-13 20:20:10 +0100718 if (!buf_size && channel_may_recv(chn) && !channel_input_closed(chn))
Willy Tarreau00f00842013-08-02 11:07:32 +0200719 smp->flags |= SMP_F_MAY_CHANGE;
720
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100721 return 1;
722
723 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100724 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100725 return 0;
726}
727
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100728/* This function is used to validate the arguments passed to a "payload_lv" fetch
729 * keyword. This keyword allows two positive integers and an optional signed one,
730 * with the second one being strictly positive and the third one being greater than
731 * the opposite of the two others if negative. It is assumed that the types are
732 * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> is
733 * not NULL, it will be filled with a pointer to an error message in case of
734 * error, that the caller is responsible for freeing. The initial location must
735 * either be freeable or NULL.
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200736 *
737 * Note that offset2 is stored with SINT type, but its not directly usable as is.
738 * The value is contained in the 63 MSB and the LSB is used as a flag for marking
739 * the "relative" property of the value.
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100740 */
Thierry FOURNIER49f45af2014-12-08 19:50:43 +0100741int val_payload_lv(struct arg *arg, char **err_msg)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100742{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200743 int relative = 0;
744 const char *str;
745
746 if (arg[0].data.sint < 0) {
747 memprintf(err_msg, "payload offset1 must be positive");
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100748 return 0;
749 }
750
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200751 if (!arg[1].data.sint) {
752 memprintf(err_msg, "payload length must be > 0");
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100753 return 0;
754 }
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200755
756 if (arg[2].type == ARGT_STR && arg[2].data.str.len > 0) {
757 if (arg[2].data.str.str[0] == '+' || arg[2].data.str.str[0] == '-')
758 relative = 1;
759 str = arg[2].data.str.str;
760 arg[2].type = ARGT_SINT;
761 arg[2].data.sint = read_int64(&str, str + arg[2].data.str.len);
762 if (*str != '\0') {
763 memprintf(err_msg, "payload offset2 is not a number");
764 return 0;
765 }
766 if (arg[0].data.sint + arg[1].data.sint + arg[2].data.sint < 0) {
767 memprintf(err_msg, "payload offset2 too negative");
768 return 0;
769 }
770 if (relative)
771 arg[2].data.sint = ( arg[2].data.sint << 1 ) + 1;
772 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100773 return 1;
774}
775
776/************************************************************************/
777/* All supported sample and ACL keywords must be declared here. */
778/************************************************************************/
779
780/* Note: must not be declared <const> as its list will be overwritten.
781 * Note: fetches that may return multiple types must be declared as the lowest
782 * common denominator, the type that can be casted into all other ones. For
783 * instance IPv4/IPv6 must be declared IPv4.
784 */
Willy Tarreaudc13c112013-06-21 23:16:39 +0200785static struct sample_fetch_kw_list smp_kws = {ILH, {
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200786 { "payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
787 { "payload_lv", smp_fetch_payload_lv, ARG3(2,SINT,SINT,STR), val_payload_lv, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100788 { "rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +0200789 { "rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L6REQ },
790 { "rep_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
791 { "req_len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
792 { "req_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100793 { "req_ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +0200794 { "req_ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +0100795
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +0200796 { "req.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200797 { "req.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ },
798 { "req.payload_lv", smp_fetch_payload_lv, ARG3(2,SINT,SINT,STR), val_payload_lv, SMP_T_BIN, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100799 { "req.rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +0200800 { "req.rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L6REQ },
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200801 { "req.ssl_ec_ext", smp_fetch_req_ssl_ec_ext, 0, NULL, SMP_T_BOOL, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +0200802 { "req.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100803 { "req.ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +0200804 { "req.ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
805 { "res.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200806 { "res.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6RES },
807 { "res.payload_lv", smp_fetch_payload_lv, ARG3(2,SINT,SINT,STR), val_payload_lv, SMP_T_BIN, SMP_USE_L6RES },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +0200808 { "res.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100809 { "wait_end", smp_fetch_wait_end, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
810 { /* END */ },
811}};
812
813
814/* Note: must not be declared <const> as its list will be overwritten.
815 * Please take care of keeping this list alphabetically sorted.
816 */
Willy Tarreaudc13c112013-06-21 23:16:39 +0200817static struct acl_kw_list acl_kws = {ILH, {
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +0100818 { "payload", "req.payload", PAT_MATCH_BIN },
819 { "payload_lv", "req.payload_lv", PAT_MATCH_BIN },
820 { "req_rdp_cookie", "req.rdp_cookie", PAT_MATCH_STR },
821 { "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", PAT_MATCH_INT },
822 { "req_ssl_sni", "req.ssl_sni", PAT_MATCH_STR },
823 { "req_ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
824 { "req.ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100825 { /* END */ },
826}};
827
828
829__attribute__((constructor))
830static void __payload_init(void)
831{
832 sample_register_fetches(&smp_kws);
833 acl_register_keywords(&acl_kws);
834}
835
836/*
837 * Local variables:
838 * c-indent-level: 8
839 * c-basic-offset: 8
840 * End:
841 */