blob: 9bf2d88599becb66b6a06f9241c7da5c927097d9 [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
59/* returns the type of SSL hello message (mainly used to detect an SSL hello) */
60static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020061smp_fetch_ssl_hello_type(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010062{
63 int hs_len;
64 int hs_type, bleft;
65 struct channel *chn;
66 const unsigned char *data;
67
Thierry FOURNIER0786d052015-05-11 15:42:45 +020068 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010069 if (!chn->buf)
Willy Tarreau83f25922014-11-26 13:24:24 +010070 goto not_ssl_hello;
71
Willy Tarreaud4c33c82013-01-07 21:59:07 +010072 bleft = chn->buf->i;
73 data = (const unsigned char *)chn->buf->p;
74
75 if (!bleft)
76 goto too_short;
77
78 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
79 /* SSLv3 header format */
80 if (bleft < 9)
81 goto too_short;
82
83 /* ssl version 3 */
84 if ((data[1] << 16) + data[2] < 0x00030000)
85 goto not_ssl_hello;
86
87 /* ssl message len must present handshake type and len */
88 if ((data[3] << 8) + data[4] < 4)
89 goto not_ssl_hello;
90
91 /* format introduced with SSLv3 */
92
93 hs_type = (int)data[5];
94 hs_len = ( data[6] << 16 ) + ( data[7] << 8 ) + data[8];
95
96 /* not a full handshake */
97 if (bleft < (9 + hs_len))
98 goto too_short;
99
100 }
101 else {
102 goto not_ssl_hello;
103 }
104
105 smp->type = SMP_T_UINT;
106 smp->data.uint = hs_type;
107 smp->flags = SMP_F_VOLATILE;
108
109 return 1;
110
111 too_short:
112 smp->flags = SMP_F_MAY_CHANGE;
113
114 not_ssl_hello:
115
116 return 0;
117}
118
119/* Return the version of the SSL protocol in the request. It supports both
120 * SSLv3 (TLSv1) header format for any message, and SSLv2 header format for
121 * the hello message. The SSLv3 format is described in RFC 2246 p49, and the
122 * SSLv2 format is described here, and completed p67 of RFC 2246 :
123 * http://wp.netscape.com/eng/security/SSL_2.html
124 *
125 * Note: this decoder only works with non-wrapping data.
126 */
127static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200128smp_fetch_req_ssl_ver(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100129{
130 int version, bleft, msg_len;
131 const unsigned char *data;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200132 struct channel *req = &smp->strm->req;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100133
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200134 if (!req->buf)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100135 return 0;
136
137 msg_len = 0;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200138 bleft = req->buf->i;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100139 if (!bleft)
140 goto too_short;
141
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200142 data = (const unsigned char *)req->buf->p;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100143 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
144 /* SSLv3 header format */
145 if (bleft < 5)
146 goto too_short;
147
148 version = (data[1] << 16) + data[2]; /* version: major, minor */
149 msg_len = (data[3] << 8) + data[4]; /* record length */
150
151 /* format introduced with SSLv3 */
152 if (version < 0x00030000)
153 goto not_ssl;
154
155 /* message length between 1 and 2^14 + 2048 */
156 if (msg_len < 1 || msg_len > ((1<<14) + 2048))
157 goto not_ssl;
158
159 bleft -= 5; data += 5;
160 } else {
161 /* SSLv2 header format, only supported for hello (msg type 1) */
162 int rlen, plen, cilen, silen, chlen;
163
164 if (*data & 0x80) {
165 if (bleft < 3)
166 goto too_short;
167 /* short header format : 15 bits for length */
168 rlen = ((data[0] & 0x7F) << 8) | data[1];
169 plen = 0;
170 bleft -= 2; data += 2;
171 } else {
172 if (bleft < 4)
173 goto too_short;
174 /* long header format : 14 bits for length + pad length */
175 rlen = ((data[0] & 0x3F) << 8) | data[1];
176 plen = data[2];
177 bleft -= 3; data += 2;
178 }
179
180 if (*data != 0x01)
181 goto not_ssl;
182 bleft--; data++;
183
184 if (bleft < 8)
185 goto too_short;
186 version = (data[0] << 16) + data[1]; /* version: major, minor */
187 cilen = (data[2] << 8) + data[3]; /* cipher len, multiple of 3 */
188 silen = (data[4] << 8) + data[5]; /* session_id_len: 0 or 16 */
189 chlen = (data[6] << 8) + data[7]; /* 16<=challenge length<=32 */
190
191 bleft -= 8; data += 8;
192 if (cilen % 3 != 0)
193 goto not_ssl;
194 if (silen && silen != 16)
195 goto not_ssl;
196 if (chlen < 16 || chlen > 32)
197 goto not_ssl;
198 if (rlen != 9 + cilen + silen + chlen)
199 goto not_ssl;
200
201 /* focus on the remaining data length */
202 msg_len = cilen + silen + chlen + plen;
203 }
204 /* We could recursively check that the buffer ends exactly on an SSL
205 * fragment boundary and that a possible next segment is still SSL,
206 * but that's a bit pointless. However, we could still check that
207 * all the part of the request which fits in a buffer is already
208 * there.
209 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200210 if (msg_len > channel_recv_limit(req) + req->buf->data - req->buf->p)
211 msg_len = channel_recv_limit(req) + req->buf->data - req->buf->p;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100212
213 if (bleft < msg_len)
214 goto too_short;
215
216 /* OK that's enough. We have at least the whole message, and we have
217 * the protocol version.
218 */
219 smp->type = SMP_T_UINT;
220 smp->data.uint = version;
221 smp->flags = SMP_F_VOLATILE;
222 return 1;
223
224 too_short:
225 smp->flags = SMP_F_MAY_CHANGE;
226 not_ssl:
227 return 0;
228}
229
230/* Try to extract the Server Name Indication that may be presented in a TLS
231 * client hello handshake message. The format of the message is the following
232 * (cf RFC5246 + RFC6066) :
233 * TLS frame :
234 * - uint8 type = 0x16 (Handshake)
235 * - uint16 version >= 0x0301 (TLSv1)
236 * - uint16 length (frame length)
237 * - TLS handshake :
238 * - uint8 msg_type = 0x01 (ClientHello)
239 * - uint24 length (handshake message length)
240 * - ClientHello :
241 * - uint16 client_version >= 0x0301 (TLSv1)
242 * - uint8 Random[32] (4 first ones are timestamp)
243 * - SessionID :
244 * - uint8 session_id_len (0..32) (SessionID len in bytes)
245 * - uint8 session_id[session_id_len]
246 * - CipherSuite :
247 * - uint16 cipher_len >= 2 (Cipher length in bytes)
248 * - uint16 ciphers[cipher_len/2]
249 * - CompressionMethod :
250 * - uint8 compression_len >= 1 (# of supported methods)
251 * - uint8 compression_methods[compression_len]
252 * - optional client_extension_len (in bytes)
253 * - optional sequence of ClientHelloExtensions (as many bytes as above):
254 * - uint16 extension_type = 0 for server_name
255 * - uint16 extension_len
256 * - opaque extension_data[extension_len]
257 * - uint16 server_name_list_len (# of bytes here)
258 * - opaque server_names[server_name_list_len bytes]
259 * - uint8 name_type = 0 for host_name
260 * - uint16 name_len
261 * - opaque hostname[name_len bytes]
262 */
263static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200264smp_fetch_ssl_hello_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100265{
266 int hs_len, ext_len, bleft;
267 struct channel *chn;
268 unsigned char *data;
269
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200270 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +0100271 if (!chn->buf)
Willy Tarreau83f25922014-11-26 13:24:24 +0100272 goto not_ssl_hello;
273
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100274 bleft = chn->buf->i;
275 data = (unsigned char *)chn->buf->p;
276
277 /* Check for SSL/TLS Handshake */
278 if (!bleft)
279 goto too_short;
280 if (*data != 0x16)
281 goto not_ssl_hello;
282
Lukas Tribus57d22972014-04-10 21:36:22 +0200283 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100284 if (bleft < 3)
285 goto too_short;
Lukas Tribus57d22972014-04-10 21:36:22 +0200286 if (data[1] < 0x03)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100287 goto not_ssl_hello;
288
289 if (bleft < 5)
290 goto too_short;
291 hs_len = (data[3] << 8) + data[4];
292 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
293 goto not_ssl_hello; /* too short to have an extension */
294
295 data += 5; /* enter TLS handshake */
296 bleft -= 5;
297
298 /* Check for a complete client hello starting at <data> */
299 if (bleft < 1)
300 goto too_short;
301 if (data[0] != 0x01) /* msg_type = Client Hello */
302 goto not_ssl_hello;
303
304 /* Check the Hello's length */
305 if (bleft < 4)
306 goto too_short;
307 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
308 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
309 goto not_ssl_hello; /* too short to have an extension */
310
311 /* We want the full handshake here */
312 if (bleft < hs_len)
313 goto too_short;
314
315 data += 4;
316 /* Start of the ClientHello message */
317 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
318 goto not_ssl_hello;
319
320 ext_len = data[34]; /* session_id_len */
321 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
322 goto not_ssl_hello;
323
324 /* Jump to cipher suite */
325 hs_len -= 35 + ext_len;
326 data += 35 + ext_len;
327
328 if (hs_len < 4 || /* minimum one cipher */
329 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
330 ext_len > hs_len)
331 goto not_ssl_hello;
332
333 /* Jump to the compression methods */
334 hs_len -= 2 + ext_len;
335 data += 2 + ext_len;
336
337 if (hs_len < 2 || /* minimum one compression method */
338 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
339 goto not_ssl_hello;
340
341 /* Jump to the extensions */
342 hs_len -= 1 + data[0];
343 data += 1 + data[0];
344
345 if (hs_len < 2 || /* minimum one extension list length */
346 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
347 goto not_ssl_hello;
348
349 hs_len = ext_len; /* limit ourselves to the extension length */
350 data += 2;
351
352 while (hs_len >= 4) {
353 int ext_type, name_type, srv_len, name_len;
354
355 ext_type = (data[0] << 8) + data[1];
356 ext_len = (data[2] << 8) + data[3];
357
358 if (ext_len > hs_len - 4) /* Extension too long */
359 goto not_ssl_hello;
360
361 if (ext_type == 0) { /* Server name */
362 if (ext_len < 2) /* need one list length */
363 goto not_ssl_hello;
364
365 srv_len = (data[4] << 8) + data[5];
366 if (srv_len < 4 || srv_len > hs_len - 6)
367 goto not_ssl_hello; /* at least 4 bytes per server name */
368
369 name_type = data[6];
370 name_len = (data[7] << 8) + data[8];
371
372 if (name_type == 0) { /* hostname */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100373 smp->type = SMP_T_STR;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100374 smp->data.str.str = (char *)data + 9;
375 smp->data.str.len = name_len;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100376 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100377 return 1;
378 }
379 }
380
381 hs_len -= 4 + ext_len;
382 data += 4 + ext_len;
383 }
384 /* server name not found */
385 goto not_ssl_hello;
386
387 too_short:
388 smp->flags = SMP_F_MAY_CHANGE;
389
390 not_ssl_hello:
391
392 return 0;
393}
394
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200395/* Fetch the request RDP cookie identified in <cname>:<clen>, or any cookie if
Willy Tarreaub169eba2013-12-16 15:14:43 +0100396 * <clen> is empty (cname is then ignored). It returns the data into sample <smp>
397 * of type SMP_T_CSTR. Note: this decoder only works with non-wrapping data.
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100398 */
399int
Willy Tarreau87b09662015-04-03 00:22:06 +0200400fetch_rdp_cookie_name(struct stream *s, struct sample *smp, const char *cname, int clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100401{
402 int bleft;
403 const unsigned char *data;
404
Willy Tarreau53c9b4d2015-04-03 21:38:18 +0200405 if (!s->req.buf)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100406 return 0;
407
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100408 smp->flags = SMP_F_CONST;
409 smp->type = SMP_T_STR;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100410
Willy Tarreau22ec1ea2014-11-27 20:45:39 +0100411 bleft = s->req.buf->i;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100412 if (bleft <= 11)
413 goto too_short;
414
Willy Tarreau22ec1ea2014-11-27 20:45:39 +0100415 data = (const unsigned char *)s->req.buf->p + 11;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100416 bleft -= 11;
417
418 if (bleft <= 7)
419 goto too_short;
420
421 if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
422 goto not_cookie;
423
424 data += 7;
425 bleft -= 7;
426
427 while (bleft > 0 && *data == ' ') {
428 data++;
429 bleft--;
430 }
431
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200432 if (clen) {
433 if (bleft <= clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100434 goto too_short;
435
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200436 if ((data[clen] != '=') ||
437 strncasecmp(cname, (const char *)data, clen) != 0)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100438 goto not_cookie;
439
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200440 data += clen + 1;
441 bleft -= clen + 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100442 } else {
443 while (bleft > 0 && *data != '=') {
444 if (*data == '\r' || *data == '\n')
445 goto not_cookie;
446 data++;
447 bleft--;
448 }
449
450 if (bleft < 1)
451 goto too_short;
452
453 if (*data != '=')
454 goto not_cookie;
455
456 data++;
457 bleft--;
458 }
459
460 /* data points to cookie value */
461 smp->data.str.str = (char *)data;
462 smp->data.str.len = 0;
463
464 while (bleft > 0 && *data != '\r') {
465 data++;
466 bleft--;
467 }
468
469 if (bleft < 2)
470 goto too_short;
471
472 if (data[0] != '\r' || data[1] != '\n')
473 goto not_cookie;
474
475 smp->data.str.len = (char *)data - smp->data.str.str;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100476 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100477 return 1;
478
479 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100480 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100481 not_cookie:
482 return 0;
483}
484
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200485/* Fetch the request RDP cookie identified in the args, or any cookie if no arg
486 * is passed. It is usable both for ACL and for samples. Note: this decoder
487 * only works with non-wrapping data. Accepts either 0 or 1 argument. Argument
Willy Tarreaub169eba2013-12-16 15:14:43 +0100488 * is a string (cookie name), other types will lead to undefined behaviour. The
489 * returned sample has type SMP_T_CSTR.
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200490 */
491int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200492smp_fetch_rdp_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200493{
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200494 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 +0200495}
496
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100497/* returns either 1 or 0 depending on whether an RDP cookie is found or not */
498static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200499smp_fetch_rdp_cookie_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100500{
501 int ret;
502
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200503 ret = smp_fetch_rdp_cookie(args, smp, kw, private);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100504
505 if (smp->flags & SMP_F_MAY_CHANGE)
506 return 0;
507
508 smp->flags = SMP_F_VOLATILE;
509 smp->type = SMP_T_UINT;
510 smp->data.uint = ret;
511 return 1;
512}
513
514/* extracts part of a payload with offset and length at a given position */
515static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200516smp_fetch_payload_lv(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100517{
518 unsigned int len_offset = arg_p[0].data.uint;
519 unsigned int len_size = arg_p[1].data.uint;
520 unsigned int buf_offset;
521 unsigned int buf_size = 0;
522 struct channel *chn;
523 int i;
524
525 /* Format is (len offset, len size, buf offset) or (len offset, len size) */
526 /* by default buf offset == len offset + len size */
527 /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
528
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200529 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +0100530 if (!chn->buf)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100531 return 0;
532
533 if (len_offset + len_size > chn->buf->i)
534 goto too_short;
535
536 for (i = 0; i < len_size; i++) {
537 buf_size = (buf_size << 8) + ((unsigned char *)chn->buf->p)[i + len_offset];
538 }
539
540 /* buf offset may be implicit, absolute or relative */
541 buf_offset = len_offset + len_size;
542 if (arg_p[2].type == ARGT_UINT)
543 buf_offset = arg_p[2].data.uint;
544 else if (arg_p[2].type == ARGT_SINT)
545 buf_offset += arg_p[2].data.sint;
546
547 if (!buf_size || buf_size > chn->buf->size || buf_offset + buf_size > chn->buf->size) {
548 /* will never match */
549 smp->flags = 0;
550 return 0;
551 }
552
553 if (buf_offset + buf_size > chn->buf->i)
554 goto too_short;
555
556 /* init chunk as read only */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100557 smp->type = SMP_T_BIN;
558 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100559 chunk_initlen(&smp->data.str, chn->buf->p + buf_offset, 0, buf_size);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100560 return 1;
561
562 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100563 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100564 return 0;
565}
566
567/* extracts some payload at a fixed position and length */
568static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200569smp_fetch_payload(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100570{
571 unsigned int buf_offset = arg_p[0].data.uint;
572 unsigned int buf_size = arg_p[1].data.uint;
573 struct channel *chn;
574
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200575 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +0100576 if (!chn->buf)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100577 return 0;
578
Willy Tarreau00f00842013-08-02 11:07:32 +0200579 if (buf_size > chn->buf->size || buf_offset + buf_size > chn->buf->size) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100580 /* will never match */
581 smp->flags = 0;
582 return 0;
583 }
584
585 if (buf_offset + buf_size > chn->buf->i)
586 goto too_short;
587
588 /* init chunk as read only */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100589 smp->type = SMP_T_BIN;
590 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreau00f00842013-08-02 11:07:32 +0200591 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 +0100592 if (!buf_size && channel_may_recv(chn) && !channel_input_closed(chn))
Willy Tarreau00f00842013-08-02 11:07:32 +0200593 smp->flags |= SMP_F_MAY_CHANGE;
594
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100595 return 1;
596
597 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100598 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100599 return 0;
600}
601
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100602/* This function is used to validate the arguments passed to a "payload_lv" fetch
603 * keyword. This keyword allows two positive integers and an optional signed one,
604 * with the second one being strictly positive and the third one being greater than
605 * the opposite of the two others if negative. It is assumed that the types are
606 * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> is
607 * not NULL, it will be filled with a pointer to an error message in case of
608 * error, that the caller is responsible for freeing. The initial location must
609 * either be freeable or NULL.
610 */
Thierry FOURNIER49f45af2014-12-08 19:50:43 +0100611int val_payload_lv(struct arg *arg, char **err_msg)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100612{
613 if (!arg[1].data.uint) {
614 memprintf(err_msg, "payload length must be > 0");
615 return 0;
616 }
617
618 if (arg[2].type == ARGT_SINT &&
619 (int)(arg[0].data.uint + arg[1].data.uint + arg[2].data.sint) < 0) {
620 memprintf(err_msg, "payload offset too negative");
621 return 0;
622 }
623 return 1;
624}
625
626/************************************************************************/
627/* All supported sample and ACL keywords must be declared here. */
628/************************************************************************/
629
630/* Note: must not be declared <const> as its list will be overwritten.
631 * Note: fetches that may return multiple types must be declared as the lowest
632 * common denominator, the type that can be casted into all other ones. For
633 * instance IPv4/IPv6 must be declared IPv4.
634 */
Willy Tarreaudc13c112013-06-21 23:16:39 +0200635static struct sample_fetch_kw_list smp_kws = {ILH, {
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100636 { "payload", smp_fetch_payload, ARG2(2,UINT,UINT), NULL, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
637 { "payload_lv", smp_fetch_payload_lv, ARG3(2,UINT,UINT,SINT), val_payload_lv, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
638 { "rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100639 { "rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_L6REQ },
640 { "rep_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_UINT, SMP_USE_L6RES },
Willy Tarreau47e8eba2013-09-11 23:28:46 +0200641 { "req_len", smp_fetch_len, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100642 { "req_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100643 { "req_ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100644 { "req_ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +0100645
Willy Tarreau47e8eba2013-09-11 23:28:46 +0200646 { "req.len", smp_fetch_len, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100647 { "req.payload", smp_fetch_payload, ARG2(2,UINT,UINT), NULL, SMP_T_BIN, SMP_USE_L6REQ },
648 { "req.payload_lv", smp_fetch_payload_lv, ARG3(2,UINT,UINT,SINT), val_payload_lv, SMP_T_BIN, SMP_USE_L6REQ },
649 { "req.rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +0100650 { "req.rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_L6REQ },
651 { "req.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100652 { "req.ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +0100653 { "req.ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_UINT, SMP_USE_L6REQ },
Willy Tarreau47e8eba2013-09-11 23:28:46 +0200654 { "res.len", smp_fetch_len, 0, NULL, SMP_T_UINT, SMP_USE_L6RES },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100655 { "res.payload", smp_fetch_payload, ARG2(2,UINT,UINT), NULL, SMP_T_BIN, SMP_USE_L6RES },
656 { "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 +0100657 { "res.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_UINT, SMP_USE_L6RES },
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100658 { "wait_end", smp_fetch_wait_end, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
659 { /* END */ },
660}};
661
662
663/* Note: must not be declared <const> as its list will be overwritten.
664 * Please take care of keeping this list alphabetically sorted.
665 */
Willy Tarreaudc13c112013-06-21 23:16:39 +0200666static struct acl_kw_list acl_kws = {ILH, {
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +0100667 { "payload", "req.payload", PAT_MATCH_BIN },
668 { "payload_lv", "req.payload_lv", PAT_MATCH_BIN },
669 { "req_rdp_cookie", "req.rdp_cookie", PAT_MATCH_STR },
670 { "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", PAT_MATCH_INT },
671 { "req_ssl_sni", "req.ssl_sni", PAT_MATCH_STR },
672 { "req_ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
673 { "req.ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100674 { /* END */ },
675}};
676
677
678__attribute__((constructor))
679static void __payload_init(void)
680{
681 sample_register_fetches(&smp_kws);
682 acl_register_keywords(&acl_kws);
683}
684
685/*
686 * Local variables:
687 * c-indent-level: 8
688 * c-basic-offset: 8
689 * End:
690 */