blob: eaf8f06e51db2c612d0fdcf38aa744252ee7c904 [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
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020016#include <haproxy/api.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020017#include <haproxy/net_helper.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +020018#include <haproxy/pattern.h>
Willy Tarreau16f958c2020-06-03 08:44:35 +020019#include <haproxy/htx.h>
Willy Tarreaud4c33c82013-01-07 21:59:07 +010020#include <proto/acl.h>
Willy Tarreauaa74c4e2020-06-04 10:19:23 +020021#include <haproxy/arg.h>
Willy Tarreaud4c33c82013-01-07 21:59:07 +010022#include <proto/channel.h>
Christopher Faulet78f371e2020-04-30 09:38:08 +020023#include <proto/connection.h>
Willy Tarreaud4c33c82013-01-07 21:59:07 +010024#include <proto/payload.h>
25#include <proto/sample.h>
Christopher Fauletfc9cfe42019-07-16 14:54:53 +020026#include <proto/http_ana.h>
Willy Tarreaud4c33c82013-01-07 21:59:07 +010027
28
29/************************************************************************/
30/* All supported sample fetch functions must be declared here */
31/************************************************************************/
32
33/* wait for more data as long as possible, then return TRUE. This should be
34 * used with content inspection.
35 */
36static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020037smp_fetch_wait_end(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010038{
Thierry FOURNIER0786d052015-05-11 15:42:45 +020039 if (!(smp->opt & SMP_OPT_FINAL)) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +010040 smp->flags |= SMP_F_MAY_CHANGE;
41 return 0;
42 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020043 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020044 smp->data.u.sint = 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +010045 return 1;
46}
47
48/* return the number of bytes in the request buffer */
49static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020050smp_fetch_len(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010051{
Christopher Faulet78f371e2020-04-30 09:38:08 +020052 if (smp->strm) {
53 struct channel *chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
54 if (IS_HTX_STRM(smp->strm)) {
55 struct htx *htx = htxbuf(&chn->buf);
56 smp->data.u.sint = htx->data - co_data(chn);
57 }
58 else
59 smp->data.u.sint = ci_data(chn);
60 }
Christopher Fauletf98e6262020-05-06 09:42:04 +020061 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Faulet78f371e2020-04-30 09:38:08 +020062 struct check *check = __objt_check(smp->sess->origin);
63 smp->data.u.sint = ((check->cs && IS_HTX_CS(check->cs)) ? (htxbuf(&check->bi))->data: b_data(&check->bi));
64 }
65 else
Willy Tarreaube508f12016-03-10 11:47:01 +010066 return 0;
67
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020068 smp->data.type = SMP_T_SINT;
Willy Tarreaud4c33c82013-01-07 21:59:07 +010069 smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
70 return 1;
71}
72
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053073/* Returns 0 if the client didn't send a SessionTicket Extension
74 * Returns 1 if the client sent SessionTicket Extension
75 * Returns 2 if the client also sent non-zero length SessionTicket
76 * Returns SMP_T_SINT data type
77 */
78static int
79smp_fetch_req_ssl_st_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
80{
81 int hs_len, ext_len, bleft;
82 struct channel *chn;
83 unsigned char *data;
84
Willy Tarreaube508f12016-03-10 11:47:01 +010085 if (!smp->strm)
86 goto not_ssl_hello;
87
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053088 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +020089 bleft = ci_data(chn);
90 data = (unsigned char *)ci_head(chn);
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053091
92 /* Check for SSL/TLS Handshake */
93 if (!bleft)
94 goto too_short;
95 if (*data != 0x16)
96 goto not_ssl_hello;
97
98 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
99 if (bleft < 3)
100 goto too_short;
101 if (data[1] < 0x03)
102 goto not_ssl_hello;
103
104 if (bleft < 5)
105 goto too_short;
106 hs_len = (data[3] << 8) + data[4];
107 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
108 goto not_ssl_hello; /* too short to have an extension */
109
110 data += 5; /* enter TLS handshake */
111 bleft -= 5;
112
113 /* Check for a complete client hello starting at <data> */
114 if (bleft < 1)
115 goto too_short;
116 if (data[0] != 0x01) /* msg_type = Client Hello */
117 goto not_ssl_hello;
118
119 /* Check the Hello's length */
120 if (bleft < 4)
121 goto too_short;
122 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
123 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
124 goto not_ssl_hello; /* too short to have an extension */
125
126 /* We want the full handshake here */
127 if (bleft < hs_len)
128 goto too_short;
129
130 data += 4;
131 /* Start of the ClientHello message */
132 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
133 goto not_ssl_hello;
134
135 ext_len = data[34]; /* session_id_len */
136 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
137 goto not_ssl_hello;
138
139 /* Jump to cipher suite */
140 hs_len -= 35 + ext_len;
141 data += 35 + ext_len;
142
143 if (hs_len < 4 || /* minimum one cipher */
144 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
145 ext_len > hs_len)
146 goto not_ssl_hello;
147
148 /* Jump to the compression methods */
149 hs_len -= 2 + ext_len;
150 data += 2 + ext_len;
151
152 if (hs_len < 2 || /* minimum one compression method */
153 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
154 goto not_ssl_hello;
155
156 /* Jump to the extensions */
157 hs_len -= 1 + data[0];
158 data += 1 + data[0];
159
160 if (hs_len < 2 || /* minimum one extension list length */
161 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
162 goto not_ssl_hello;
163
164 hs_len = ext_len; /* limit ourselves to the extension length */
165 data += 2;
166
167 while (hs_len >= 4) {
168 int ext_type, ext_len;
169
170 ext_type = (data[0] << 8) + data[1];
171 ext_len = (data[2] << 8) + data[3];
172
173 if (ext_len > hs_len - 4) /* Extension too long */
174 goto not_ssl_hello;
175
176 /* SesstionTicket extension */
177 if (ext_type == 35) {
178 smp->data.type = SMP_T_SINT;
179 /* SessionTicket also present */
180 if (ext_len > 0)
181 smp->data.u.sint = 2;
182 /* SessionTicket absent */
183 else
184 smp->data.u.sint = 1;
185 smp->flags = SMP_F_VOLATILE;
186 return 1;
187 }
188
189 hs_len -= 4 + ext_len;
190 data += 4 + ext_len;
191 }
192 /* SessionTicket Extension not found */
193 smp->data.type = SMP_T_SINT;
194 smp->data.u.sint = 0;
195 smp->flags = SMP_F_VOLATILE;
196 return 1;
197
Pradeep Jindalbb2acf52015-09-29 10:12:57 +0530198 too_short:
199 smp->flags = SMP_F_MAY_CHANGE;
200
201 not_ssl_hello:
202 return 0;
203}
204
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200205/* Returns TRUE if the client sent Supported Elliptic Curves Extension (0x000a)
206 * Mainly used to detect if client supports ECC cipher suites.
207 */
208static int
209smp_fetch_req_ssl_ec_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
210{
211 int hs_len, ext_len, bleft;
212 struct channel *chn;
213 unsigned char *data;
214
Willy Tarreaube508f12016-03-10 11:47:01 +0100215 if (!smp->strm)
216 goto not_ssl_hello;
217
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200218 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200219 bleft = ci_data(chn);
220 data = (unsigned char *)ci_head(chn);
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200221
222 /* Check for SSL/TLS Handshake */
223 if (!bleft)
224 goto too_short;
225 if (*data != 0x16)
226 goto not_ssl_hello;
227
228 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
229 if (bleft < 3)
230 goto too_short;
231 if (data[1] < 0x03)
232 goto not_ssl_hello;
233
234 if (bleft < 5)
235 goto too_short;
236 hs_len = (data[3] << 8) + data[4];
237 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
238 goto not_ssl_hello; /* too short to have an extension */
239
240 data += 5; /* enter TLS handshake */
241 bleft -= 5;
242
243 /* Check for a complete client hello starting at <data> */
244 if (bleft < 1)
245 goto too_short;
246 if (data[0] != 0x01) /* msg_type = Client Hello */
247 goto not_ssl_hello;
248
249 /* Check the Hello's length */
250 if (bleft < 4)
251 goto too_short;
252 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
253 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
254 goto not_ssl_hello; /* too short to have an extension */
255
256 /* We want the full handshake here */
257 if (bleft < hs_len)
258 goto too_short;
259
260 data += 4;
261 /* Start of the ClientHello message */
262 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
263 goto not_ssl_hello;
264
265 ext_len = data[34]; /* session_id_len */
266 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
267 goto not_ssl_hello;
268
269 /* Jump to cipher suite */
270 hs_len -= 35 + ext_len;
271 data += 35 + ext_len;
272
273 if (hs_len < 4 || /* minimum one cipher */
274 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
275 ext_len > hs_len)
276 goto not_ssl_hello;
277
278 /* Jump to the compression methods */
279 hs_len -= 2 + ext_len;
280 data += 2 + ext_len;
281
282 if (hs_len < 2 || /* minimum one compression method */
283 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
284 goto not_ssl_hello;
285
286 /* Jump to the extensions */
287 hs_len -= 1 + data[0];
288 data += 1 + data[0];
289
290 if (hs_len < 2 || /* minimum one extension list length */
291 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
292 goto not_ssl_hello;
293
294 hs_len = ext_len; /* limit ourselves to the extension length */
295 data += 2;
296
297 while (hs_len >= 4) {
298 int ext_type, ext_len;
299
300 ext_type = (data[0] << 8) + data[1];
301 ext_len = (data[2] << 8) + data[3];
302
303 if (ext_len > hs_len - 4) /* Extension too long */
304 goto not_ssl_hello;
305
306 /* Elliptic curves extension */
307 if (ext_type == 10) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200308 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200309 smp->data.u.sint = 1;
Nenad Merdanovic8a39a1f2015-07-15 12:51:11 +0200310 smp->flags = SMP_F_VOLATILE;
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200311 return 1;
312 }
313
314 hs_len -= 4 + ext_len;
315 data += 4 + ext_len;
316 }
317 /* server name not found */
318 goto not_ssl_hello;
319
320 too_short:
321 smp->flags = SMP_F_MAY_CHANGE;
322
323 not_ssl_hello:
324
325 return 0;
326}
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100327/* returns the type of SSL hello message (mainly used to detect an SSL hello) */
328static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200329smp_fetch_ssl_hello_type(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100330{
331 int hs_len;
332 int hs_type, bleft;
333 struct channel *chn;
334 const unsigned char *data;
335
Willy Tarreaube508f12016-03-10 11:47:01 +0100336 if (!smp->strm)
337 goto not_ssl_hello;
338
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200339 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200340 bleft = ci_data(chn);
341 data = (const unsigned char *)ci_head(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100342
343 if (!bleft)
344 goto too_short;
345
346 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
347 /* SSLv3 header format */
348 if (bleft < 9)
349 goto too_short;
350
351 /* ssl version 3 */
352 if ((data[1] << 16) + data[2] < 0x00030000)
353 goto not_ssl_hello;
354
355 /* ssl message len must present handshake type and len */
356 if ((data[3] << 8) + data[4] < 4)
357 goto not_ssl_hello;
358
359 /* format introduced with SSLv3 */
360
361 hs_type = (int)data[5];
362 hs_len = ( data[6] << 16 ) + ( data[7] << 8 ) + data[8];
363
364 /* not a full handshake */
365 if (bleft < (9 + hs_len))
366 goto too_short;
367
368 }
369 else {
370 goto not_ssl_hello;
371 }
372
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200373 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200374 smp->data.u.sint = hs_type;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100375 smp->flags = SMP_F_VOLATILE;
376
377 return 1;
378
379 too_short:
380 smp->flags = SMP_F_MAY_CHANGE;
381
382 not_ssl_hello:
383
384 return 0;
385}
386
387/* Return the version of the SSL protocol in the request. It supports both
388 * SSLv3 (TLSv1) header format for any message, and SSLv2 header format for
389 * the hello message. The SSLv3 format is described in RFC 2246 p49, and the
390 * SSLv2 format is described here, and completed p67 of RFC 2246 :
391 * http://wp.netscape.com/eng/security/SSL_2.html
392 *
393 * Note: this decoder only works with non-wrapping data.
394 */
395static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200396smp_fetch_req_ssl_ver(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100397{
398 int version, bleft, msg_len;
399 const unsigned char *data;
Willy Tarreaube508f12016-03-10 11:47:01 +0100400 struct channel *req;
401
402 if (!smp->strm)
403 return 0;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100404
Willy Tarreaube508f12016-03-10 11:47:01 +0100405 req = &smp->strm->req;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100406 msg_len = 0;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200407 bleft = ci_data(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100408 if (!bleft)
409 goto too_short;
410
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200411 data = (const unsigned char *)ci_head(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100412 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
413 /* SSLv3 header format */
Lukas Tribusc93242c2015-11-05 13:59:30 +0100414 if (bleft < 11)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100415 goto too_short;
416
Lukas Tribusc93242c2015-11-05 13:59:30 +0100417 version = (data[1] << 16) + data[2]; /* record layer version: major, minor */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100418 msg_len = (data[3] << 8) + data[4]; /* record length */
419
420 /* format introduced with SSLv3 */
421 if (version < 0x00030000)
422 goto not_ssl;
423
Lukas Tribusc93242c2015-11-05 13:59:30 +0100424 /* message length between 6 and 2^14 + 2048 */
425 if (msg_len < 6 || msg_len > ((1<<14) + 2048))
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100426 goto not_ssl;
427
428 bleft -= 5; data += 5;
Lukas Tribusc93242c2015-11-05 13:59:30 +0100429
430 /* return the client hello client version, not the record layer version */
431 version = (data[4] << 16) + data[5]; /* client hello version: major, minor */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100432 } else {
433 /* SSLv2 header format, only supported for hello (msg type 1) */
434 int rlen, plen, cilen, silen, chlen;
435
436 if (*data & 0x80) {
437 if (bleft < 3)
438 goto too_short;
439 /* short header format : 15 bits for length */
440 rlen = ((data[0] & 0x7F) << 8) | data[1];
441 plen = 0;
442 bleft -= 2; data += 2;
443 } else {
444 if (bleft < 4)
445 goto too_short;
446 /* long header format : 14 bits for length + pad length */
447 rlen = ((data[0] & 0x3F) << 8) | data[1];
448 plen = data[2];
Willy Tarreau74967f62016-08-30 14:39:46 +0200449 bleft -= 3; data += 3;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100450 }
451
452 if (*data != 0x01)
453 goto not_ssl;
454 bleft--; data++;
455
456 if (bleft < 8)
457 goto too_short;
458 version = (data[0] << 16) + data[1]; /* version: major, minor */
459 cilen = (data[2] << 8) + data[3]; /* cipher len, multiple of 3 */
460 silen = (data[4] << 8) + data[5]; /* session_id_len: 0 or 16 */
461 chlen = (data[6] << 8) + data[7]; /* 16<=challenge length<=32 */
462
463 bleft -= 8; data += 8;
464 if (cilen % 3 != 0)
465 goto not_ssl;
466 if (silen && silen != 16)
467 goto not_ssl;
468 if (chlen < 16 || chlen > 32)
469 goto not_ssl;
470 if (rlen != 9 + cilen + silen + chlen)
471 goto not_ssl;
472
473 /* focus on the remaining data length */
474 msg_len = cilen + silen + chlen + plen;
475 }
476 /* We could recursively check that the buffer ends exactly on an SSL
477 * fragment boundary and that a possible next segment is still SSL,
478 * but that's a bit pointless. However, we could still check that
479 * all the part of the request which fits in a buffer is already
480 * there.
481 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200482 if (msg_len > channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req))
483 msg_len = channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100484
485 if (bleft < msg_len)
486 goto too_short;
487
488 /* OK that's enough. We have at least the whole message, and we have
489 * the protocol version.
490 */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200491 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200492 smp->data.u.sint = version;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100493 smp->flags = SMP_F_VOLATILE;
494 return 1;
495
496 too_short:
497 smp->flags = SMP_F_MAY_CHANGE;
498 not_ssl:
499 return 0;
500}
501
502/* Try to extract the Server Name Indication that may be presented in a TLS
503 * client hello handshake message. The format of the message is the following
504 * (cf RFC5246 + RFC6066) :
505 * TLS frame :
506 * - uint8 type = 0x16 (Handshake)
507 * - uint16 version >= 0x0301 (TLSv1)
508 * - uint16 length (frame length)
509 * - TLS handshake :
510 * - uint8 msg_type = 0x01 (ClientHello)
511 * - uint24 length (handshake message length)
512 * - ClientHello :
513 * - uint16 client_version >= 0x0301 (TLSv1)
514 * - uint8 Random[32] (4 first ones are timestamp)
515 * - SessionID :
516 * - uint8 session_id_len (0..32) (SessionID len in bytes)
517 * - uint8 session_id[session_id_len]
518 * - CipherSuite :
519 * - uint16 cipher_len >= 2 (Cipher length in bytes)
520 * - uint16 ciphers[cipher_len/2]
521 * - CompressionMethod :
522 * - uint8 compression_len >= 1 (# of supported methods)
523 * - uint8 compression_methods[compression_len]
524 * - optional client_extension_len (in bytes)
525 * - optional sequence of ClientHelloExtensions (as many bytes as above):
526 * - uint16 extension_type = 0 for server_name
527 * - uint16 extension_len
528 * - opaque extension_data[extension_len]
529 * - uint16 server_name_list_len (# of bytes here)
530 * - opaque server_names[server_name_list_len bytes]
531 * - uint8 name_type = 0 for host_name
532 * - uint16 name_len
533 * - opaque hostname[name_len bytes]
534 */
535static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200536smp_fetch_ssl_hello_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100537{
538 int hs_len, ext_len, bleft;
539 struct channel *chn;
540 unsigned char *data;
541
Willy Tarreaube508f12016-03-10 11:47:01 +0100542 if (!smp->strm)
543 goto not_ssl_hello;
544
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200545 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200546 bleft = ci_data(chn);
547 data = (unsigned char *)ci_head(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100548
549 /* Check for SSL/TLS Handshake */
550 if (!bleft)
551 goto too_short;
552 if (*data != 0x16)
553 goto not_ssl_hello;
554
Lukas Tribus57d22972014-04-10 21:36:22 +0200555 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100556 if (bleft < 3)
557 goto too_short;
Lukas Tribus57d22972014-04-10 21:36:22 +0200558 if (data[1] < 0x03)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100559 goto not_ssl_hello;
560
561 if (bleft < 5)
562 goto too_short;
563 hs_len = (data[3] << 8) + data[4];
564 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
565 goto not_ssl_hello; /* too short to have an extension */
566
567 data += 5; /* enter TLS handshake */
568 bleft -= 5;
569
570 /* Check for a complete client hello starting at <data> */
571 if (bleft < 1)
572 goto too_short;
573 if (data[0] != 0x01) /* msg_type = Client Hello */
574 goto not_ssl_hello;
575
576 /* Check the Hello's length */
577 if (bleft < 4)
578 goto too_short;
579 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
580 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
581 goto not_ssl_hello; /* too short to have an extension */
582
583 /* We want the full handshake here */
584 if (bleft < hs_len)
585 goto too_short;
586
587 data += 4;
588 /* Start of the ClientHello message */
589 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
590 goto not_ssl_hello;
591
592 ext_len = data[34]; /* session_id_len */
593 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
594 goto not_ssl_hello;
595
596 /* Jump to cipher suite */
597 hs_len -= 35 + ext_len;
598 data += 35 + ext_len;
599
600 if (hs_len < 4 || /* minimum one cipher */
601 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
602 ext_len > hs_len)
603 goto not_ssl_hello;
604
605 /* Jump to the compression methods */
606 hs_len -= 2 + ext_len;
607 data += 2 + ext_len;
608
609 if (hs_len < 2 || /* minimum one compression method */
610 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
611 goto not_ssl_hello;
612
613 /* Jump to the extensions */
614 hs_len -= 1 + data[0];
615 data += 1 + data[0];
616
617 if (hs_len < 2 || /* minimum one extension list length */
618 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
619 goto not_ssl_hello;
620
621 hs_len = ext_len; /* limit ourselves to the extension length */
622 data += 2;
623
624 while (hs_len >= 4) {
625 int ext_type, name_type, srv_len, name_len;
626
627 ext_type = (data[0] << 8) + data[1];
628 ext_len = (data[2] << 8) + data[3];
629
630 if (ext_len > hs_len - 4) /* Extension too long */
631 goto not_ssl_hello;
632
633 if (ext_type == 0) { /* Server name */
634 if (ext_len < 2) /* need one list length */
635 goto not_ssl_hello;
636
637 srv_len = (data[4] << 8) + data[5];
638 if (srv_len < 4 || srv_len > hs_len - 6)
639 goto not_ssl_hello; /* at least 4 bytes per server name */
640
641 name_type = data[6];
642 name_len = (data[7] << 8) + data[8];
643
644 if (name_type == 0) { /* hostname */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200645 smp->data.type = SMP_T_STR;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200646 smp->data.u.str.area = (char *)data + 9;
647 smp->data.u.str.data = name_len;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100648 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100649 return 1;
650 }
651 }
652
653 hs_len -= 4 + ext_len;
654 data += 4 + ext_len;
655 }
656 /* server name not found */
657 goto not_ssl_hello;
658
659 too_short:
660 smp->flags = SMP_F_MAY_CHANGE;
661
662 not_ssl_hello:
663
664 return 0;
665}
666
Alex Zorin4afdd132018-12-30 13:56:28 +1100667/* Try to extract the Application-Layer Protocol Negotiation (ALPN) protocol
668 * names that may be presented in a TLS client hello handshake message. As the
669 * message presents a list of protocol names in descending order of preference,
670 * it may return iteratively. The format of the message is the following
671 * (cf RFC5246 + RFC7301) :
672 * TLS frame :
673 * - uint8 type = 0x16 (Handshake)
674 * - uint16 version >= 0x0301 (TLSv1)
675 * - uint16 length (frame length)
676 * - TLS handshake :
677 * - uint8 msg_type = 0x01 (ClientHello)
678 * - uint24 length (handshake message length)
679 * - ClientHello :
680 * - uint16 client_version >= 0x0301 (TLSv1)
681 * - uint8 Random[32] (4 first ones are timestamp)
682 * - SessionID :
683 * - uint8 session_id_len (0..32) (SessionID len in bytes)
684 * - uint8 session_id[session_id_len]
685 * - CipherSuite :
686 * - uint16 cipher_len >= 2 (Cipher length in bytes)
687 * - uint16 ciphers[cipher_len/2]
688 * - CompressionMethod :
689 * - uint8 compression_len >= 1 (# of supported methods)
690 * - uint8 compression_methods[compression_len]
691 * - optional client_extension_len (in bytes)
692 * - optional sequence of ClientHelloExtensions (as many bytes as above):
693 * - uint16 extension_type = 16 for application_layer_protocol_negotiation
694 * - uint16 extension_len
695 * - opaque extension_data[extension_len]
696 * - uint16 protocol_names_len (# of bytes here)
697 * - opaque protocol_names[protocol_names_len bytes]
698 * - uint8 name_len
699 * - opaque protocol_name[name_len bytes]
700 */
701static int
702smp_fetch_ssl_hello_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
703{
704 int hs_len, ext_len, bleft;
705 struct channel *chn;
706 unsigned char *data;
707
708 if (!smp->strm)
709 goto not_ssl_hello;
710
711 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
712 bleft = ci_data(chn);
713 data = (unsigned char *)ci_head(chn);
714
715 /* Check for SSL/TLS Handshake */
716 if (!bleft)
717 goto too_short;
718 if (*data != 0x16)
719 goto not_ssl_hello;
720
721 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
722 if (bleft < 3)
723 goto too_short;
724 if (data[1] < 0x03)
725 goto not_ssl_hello;
726
727 if (bleft < 5)
728 goto too_short;
729 hs_len = (data[3] << 8) + data[4];
730 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
731 goto not_ssl_hello; /* too short to have an extension */
732
733 data += 5; /* enter TLS handshake */
734 bleft -= 5;
735
736 /* Check for a complete client hello starting at <data> */
737 if (bleft < 1)
738 goto too_short;
739 if (data[0] != 0x01) /* msg_type = Client Hello */
740 goto not_ssl_hello;
741
742 /* Check the Hello's length */
743 if (bleft < 4)
744 goto too_short;
745 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
746 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
747 goto not_ssl_hello; /* too short to have an extension */
748
749 /* We want the full handshake here */
750 if (bleft < hs_len)
751 goto too_short;
752
753 data += 4;
754 /* Start of the ClientHello message */
755 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
756 goto not_ssl_hello;
757
758 ext_len = data[34]; /* session_id_len */
759 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
760 goto not_ssl_hello;
761
762 /* Jump to cipher suite */
763 hs_len -= 35 + ext_len;
764 data += 35 + ext_len;
765
766 if (hs_len < 4 || /* minimum one cipher */
767 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
768 ext_len > hs_len)
769 goto not_ssl_hello;
770
771 /* Jump to the compression methods */
772 hs_len -= 2 + ext_len;
773 data += 2 + ext_len;
774
775 if (hs_len < 2 || /* minimum one compression method */
776 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
777 goto not_ssl_hello;
778
779 /* Jump to the extensions */
780 hs_len -= 1 + data[0];
781 data += 1 + data[0];
782
783 if (hs_len < 2 || /* minimum one extension list length */
784 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
785 goto not_ssl_hello;
786
787 hs_len = ext_len; /* limit ourselves to the extension length */
788 data += 2;
789
790 while (hs_len >= 4) {
791 int ext_type, name_len, name_offset;
792
793 ext_type = (data[0] << 8) + data[1];
794 ext_len = (data[2] << 8) + data[3];
795
796 if (ext_len > hs_len - 4) /* Extension too long */
797 goto not_ssl_hello;
798
799 if (ext_type == 16) { /* ALPN */
800 if (ext_len < 3) /* one list length [uint16] + at least one name length [uint8] */
801 goto not_ssl_hello;
802
803 /* Name cursor in ctx, must begin after protocol_names_len */
804 name_offset = smp->ctx.i < 6 ? 6 : smp->ctx.i;
805 name_len = data[name_offset];
806
807 if (name_len + name_offset - 3 > ext_len)
808 goto not_ssl_hello;
809
810 smp->data.type = SMP_T_STR;
811 smp->data.u.str.area = (char *)data + name_offset + 1; /* +1 to skip name_len */
812 smp->data.u.str.data = name_len;
813 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
814
815 /* May have more protocol names remaining */
816 if (name_len + name_offset - 3 < ext_len) {
817 smp->ctx.i = name_offset + name_len + 1;
818 smp->flags |= SMP_F_NOT_LAST;
819 }
820
821 return 1;
822 }
823
824 hs_len -= 4 + ext_len;
825 data += 4 + ext_len;
826 }
827 /* alpn not found */
828 goto not_ssl_hello;
829
830 too_short:
831 smp->flags = SMP_F_MAY_CHANGE;
832
833 not_ssl_hello:
834
835 return 0;
836}
837
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200838/* Fetch the request RDP cookie identified in <cname>:<clen>, or any cookie if
Willy Tarreaub169eba2013-12-16 15:14:43 +0100839 * <clen> is empty (cname is then ignored). It returns the data into sample <smp>
840 * of type SMP_T_CSTR. Note: this decoder only works with non-wrapping data.
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100841 */
842int
Willy Tarreau87b09662015-04-03 00:22:06 +0200843fetch_rdp_cookie_name(struct stream *s, struct sample *smp, const char *cname, int clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100844{
845 int bleft;
846 const unsigned char *data;
847
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100848 smp->flags = SMP_F_CONST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200849 smp->data.type = SMP_T_STR;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100850
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200851 bleft = ci_data(&s->req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100852 if (bleft <= 11)
853 goto too_short;
854
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200855 data = (const unsigned char *)ci_head(&s->req) + 11;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100856 bleft -= 11;
857
858 if (bleft <= 7)
859 goto too_short;
860
861 if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
862 goto not_cookie;
863
864 data += 7;
865 bleft -= 7;
866
867 while (bleft > 0 && *data == ' ') {
868 data++;
869 bleft--;
870 }
871
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200872 if (clen) {
873 if (bleft <= clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100874 goto too_short;
875
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200876 if ((data[clen] != '=') ||
877 strncasecmp(cname, (const char *)data, clen) != 0)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100878 goto not_cookie;
879
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200880 data += clen + 1;
881 bleft -= clen + 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100882 } else {
883 while (bleft > 0 && *data != '=') {
884 if (*data == '\r' || *data == '\n')
885 goto not_cookie;
886 data++;
887 bleft--;
888 }
889
890 if (bleft < 1)
891 goto too_short;
892
893 if (*data != '=')
894 goto not_cookie;
895
896 data++;
897 bleft--;
898 }
899
900 /* data points to cookie value */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200901 smp->data.u.str.area = (char *)data;
902 smp->data.u.str.data = 0;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100903
904 while (bleft > 0 && *data != '\r') {
905 data++;
906 bleft--;
907 }
908
909 if (bleft < 2)
910 goto too_short;
911
912 if (data[0] != '\r' || data[1] != '\n')
913 goto not_cookie;
914
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200915 smp->data.u.str.data = (char *)data - smp->data.u.str.area;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100916 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100917 return 1;
918
919 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100920 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100921 not_cookie:
922 return 0;
923}
924
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200925/* Fetch the request RDP cookie identified in the args, or any cookie if no arg
926 * is passed. It is usable both for ACL and for samples. Note: this decoder
927 * only works with non-wrapping data. Accepts either 0 or 1 argument. Argument
Willy Tarreaub169eba2013-12-16 15:14:43 +0100928 * is a string (cookie name), other types will lead to undefined behaviour. The
929 * returned sample has type SMP_T_CSTR.
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200930 */
931int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200932smp_fetch_rdp_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200933{
Willy Tarreaube508f12016-03-10 11:47:01 +0100934 if (!smp->strm)
935 return 0;
936
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200937 return fetch_rdp_cookie_name(smp->strm, smp,
938 args ? args->data.str.area : NULL,
939 args ? args->data.str.data : 0);
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200940}
941
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100942/* returns either 1 or 0 depending on whether an RDP cookie is found or not */
943static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200944smp_fetch_rdp_cookie_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100945{
946 int ret;
947
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200948 ret = smp_fetch_rdp_cookie(args, smp, kw, private);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100949
950 if (smp->flags & SMP_F_MAY_CHANGE)
951 return 0;
952
953 smp->flags = SMP_F_VOLATILE;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200954 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200955 smp->data.u.sint = ret;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100956 return 1;
957}
958
959/* extracts part of a payload with offset and length at a given position */
960static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200961smp_fetch_payload_lv(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100962{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200963 unsigned int len_offset = arg_p[0].data.sint;
964 unsigned int len_size = arg_p[1].data.sint;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100965 unsigned int buf_offset;
966 unsigned int buf_size = 0;
Christopher Faulet78f371e2020-04-30 09:38:08 +0200967 struct channel *chn = NULL;
968 char *head = NULL;
969 size_t max, data;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100970 int i;
971
972 /* Format is (len offset, len size, buf offset) or (len offset, len size) */
973 /* by default buf offset == len offset + len size */
974 /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
975
Christopher Faulet78f371e2020-04-30 09:38:08 +0200976 if (smp->strm) {
977 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
978 head = ci_head(chn);
979 data = ci_data(chn);
980 max = global.tune.bufsize;
981 }
Christopher Fauletf98e6262020-05-06 09:42:04 +0200982 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Faulet78f371e2020-04-30 09:38:08 +0200983 struct buffer *buf = &(__objt_check(smp->sess->origin)->bi);
984 head = b_head(buf);
985 data = b_data(buf);
986 max = global.tune.chksize;
987 }
988 if (!head)
Willy Tarreaube508f12016-03-10 11:47:01 +0100989 return 0;
990
Christopher Faulet78f371e2020-04-30 09:38:08 +0200991 if (len_offset + len_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100992 goto too_short;
993
994 for (i = 0; i < len_size; i++) {
Christopher Faulet78f371e2020-04-30 09:38:08 +0200995 buf_size = (buf_size << 8) + ((unsigned char *)head)[i + len_offset];
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100996 }
997
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200998 /* buf offset may be implicit, absolute or relative. If the LSB
999 * is set, then the offset is relative otherwise it is absolute.
1000 */
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001001 buf_offset = len_offset + len_size;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001002 if (arg_p[2].type == ARGT_SINT) {
1003 if (arg_p[2].data.sint & 1)
1004 buf_offset += arg_p[2].data.sint >> 1;
1005 else
1006 buf_offset = arg_p[2].data.sint >> 1;
1007 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001008
Christopher Faulet78f371e2020-04-30 09:38:08 +02001009 if (!buf_size || buf_size > max || buf_offset + buf_size > max) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001010 /* will never match */
1011 smp->flags = 0;
1012 return 0;
1013 }
1014
Christopher Faulet78f371e2020-04-30 09:38:08 +02001015 if (buf_offset + buf_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001016 goto too_short;
1017
1018 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001019 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001020 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001021 chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001022 return 1;
1023
1024 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001025 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001026 return 0;
1027}
1028
1029/* extracts some payload at a fixed position and length */
1030static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +02001031smp_fetch_payload(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001032{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001033 unsigned int buf_offset = arg_p[0].data.sint;
1034 unsigned int buf_size = arg_p[1].data.sint;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001035 struct channel *chn = NULL;
1036 char *head = NULL;
1037 size_t max, data;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001038
Christopher Faulet78f371e2020-04-30 09:38:08 +02001039 if (smp->strm) {
1040 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1041 head = ci_head(chn);
1042 data = ci_data(chn);
1043 max = global.tune.bufsize;
1044 }
Christopher Fauletf98e6262020-05-06 09:42:04 +02001045 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Faulet78f371e2020-04-30 09:38:08 +02001046 struct buffer *buf = &(__objt_check(smp->sess->origin)->bi);
1047 head = b_head(buf);
1048 data = b_data(buf);
1049 max = global.tune.chksize;
1050 }
1051 if (!head)
Willy Tarreaube508f12016-03-10 11:47:01 +01001052 return 0;
1053
Christopher Faulet78f371e2020-04-30 09:38:08 +02001054 if (buf_size > max || buf_offset + buf_size > max) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001055 /* will never match */
1056 smp->flags = 0;
1057 return 0;
1058 }
Christopher Faulet78f371e2020-04-30 09:38:08 +02001059 if (buf_offset + buf_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001060 goto too_short;
1061
1062 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001063 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001064 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001065 chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size ? buf_size : (data - buf_offset));
1066
1067 if (!buf_size && chn && channel_may_recv(chn) && !channel_input_closed(chn))
Willy Tarreau00f00842013-08-02 11:07:32 +02001068 smp->flags |= SMP_F_MAY_CHANGE;
1069
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001070 return 1;
1071
Christopher Faulet78f371e2020-04-30 09:38:08 +02001072 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001073 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001074 return 0;
1075}
1076
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001077/* This function is used to validate the arguments passed to a "payload_lv" fetch
1078 * keyword. This keyword allows two positive integers and an optional signed one,
1079 * with the second one being strictly positive and the third one being greater than
1080 * the opposite of the two others if negative. It is assumed that the types are
1081 * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> is
1082 * not NULL, it will be filled with a pointer to an error message in case of
1083 * error, that the caller is responsible for freeing. The initial location must
1084 * either be freeable or NULL.
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001085 *
1086 * Note that offset2 is stored with SINT type, but its not directly usable as is.
1087 * The value is contained in the 63 MSB and the LSB is used as a flag for marking
1088 * the "relative" property of the value.
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001089 */
Thierry FOURNIER49f45af2014-12-08 19:50:43 +01001090int val_payload_lv(struct arg *arg, char **err_msg)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001091{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001092 int relative = 0;
1093 const char *str;
1094
1095 if (arg[0].data.sint < 0) {
1096 memprintf(err_msg, "payload offset1 must be positive");
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001097 return 0;
1098 }
1099
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001100 if (!arg[1].data.sint) {
1101 memprintf(err_msg, "payload length must be > 0");
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001102 return 0;
1103 }
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001104
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001105 if (arg[2].type == ARGT_STR && arg[2].data.str.data > 0) {
1106 if (arg[2].data.str.area[0] == '+' || arg[2].data.str.area[0] == '-')
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001107 relative = 1;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001108 str = arg[2].data.str.area;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001109 arg[2].type = ARGT_SINT;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001110 arg[2].data.sint = read_int64(&str,
1111 str + arg[2].data.str.data);
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001112 if (*str != '\0') {
1113 memprintf(err_msg, "payload offset2 is not a number");
1114 return 0;
1115 }
1116 if (arg[0].data.sint + arg[1].data.sint + arg[2].data.sint < 0) {
1117 memprintf(err_msg, "payload offset2 too negative");
1118 return 0;
1119 }
1120 if (relative)
1121 arg[2].data.sint = ( arg[2].data.sint << 1 ) + 1;
1122 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001123 return 1;
1124}
1125
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001126/* extracts the parameter value of a distcc token */
1127static int
1128smp_fetch_distcc_param(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
1129{
1130 unsigned int match_tok = arg_p[0].data.sint;
1131 unsigned int match_occ = arg_p[1].data.sint;
1132 unsigned int token;
1133 unsigned int param;
1134 unsigned int body;
1135 unsigned int ofs;
1136 unsigned int occ;
1137 struct channel *chn;
1138 int i;
1139
1140 /* Format is (token[,occ]). occ starts at 1. */
1141
1142 if (!smp->strm)
1143 return 0;
1144
1145 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1146
1147 ofs = 0; occ = 0;
1148 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001149 if (ofs + 12 > ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001150 /* not there yet but could it at least fit ? */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001151 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001152 goto too_short;
1153
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001154 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001155 goto too_short;
1156
1157 goto no_match;
1158 }
1159
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001160 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001161 ofs += 4;
1162
1163 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001164 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001165
1166 if (c < 0)
1167 goto no_match;
1168 param = (param << 4) + c;
1169 }
1170 ofs += 8;
1171
1172 /* these tokens don't have a body */
1173 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1174 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1175 token != 0x444F4E45 /* DONE */)
1176 body = param;
1177 else
1178 body = 0;
1179
1180 if (token == match_tok) {
1181 occ++;
1182 if (!match_occ || match_occ == occ) {
1183 /* found */
1184 smp->data.type = SMP_T_SINT;
1185 smp->data.u.sint = param;
1186 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1187 return 1;
1188 }
1189 }
1190 ofs += body;
1191 }
1192
1193 too_short:
1194 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1195 return 0;
1196 no_match:
1197 /* will never match (end of buffer, or bad contents) */
1198 smp->flags = 0;
1199 return 0;
1200
1201}
1202
1203/* extracts the (possibly truncated) body of a distcc token */
1204static int
1205smp_fetch_distcc_body(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
1206{
1207 unsigned int match_tok = arg_p[0].data.sint;
1208 unsigned int match_occ = arg_p[1].data.sint;
1209 unsigned int token;
1210 unsigned int param;
1211 unsigned int ofs;
1212 unsigned int occ;
1213 unsigned int body;
1214 struct channel *chn;
1215 int i;
1216
1217 /* Format is (token[,occ]). occ starts at 1. */
1218
1219 if (!smp->strm)
1220 return 0;
1221
1222 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1223
1224 ofs = 0; occ = 0;
1225 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001226 if (ofs + 12 > ci_data(chn)) {
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001227 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001228 goto too_short;
1229
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001230 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001231 goto too_short;
1232
1233 goto no_match;
1234 }
1235
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001236 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001237 ofs += 4;
1238
1239 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001240 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001241
1242 if (c < 0)
1243 goto no_match;
1244 param = (param << 4) + c;
1245 }
1246 ofs += 8;
1247
1248 /* these tokens don't have a body */
1249 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1250 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1251 token != 0x444F4E45 /* DONE */)
1252 body = param;
1253 else
1254 body = 0;
1255
1256 if (token == match_tok) {
1257 occ++;
1258 if (!match_occ || match_occ == occ) {
1259 /* found */
1260
1261 smp->data.type = SMP_T_BIN;
1262 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1263
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001264 if (ofs + body > ci_head(chn) - b_orig(&chn->buf) + ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001265 /* incomplete body */
1266
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001267 if (ofs + body > channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001268 /* truncate it to whatever will fit */
1269 smp->flags |= SMP_F_MAY_CHANGE;
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001270 body = channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn) - ofs;
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001271 }
1272 }
1273
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001274 chunk_initlen(&smp->data.u.str, ci_head(chn) + ofs, 0, body);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001275 return 1;
1276 }
1277 }
1278 ofs += body;
1279 }
1280
1281 too_short:
1282 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1283 return 0;
1284 no_match:
1285 /* will never match (end of buffer, or bad contents) */
1286 smp->flags = 0;
1287 return 0;
1288
1289}
1290
1291/* This function is used to validate the arguments passed to a "distcc_param" or
1292 * "distcc_body" sample fetch keyword. They take a mandatory token name of exactly
1293 * 4 characters, followed by an optional occurrence number starting at 1. It is
1294 * assumed that the types are already the correct ones. Returns 0 on error, non-
1295 * zero if OK. If <err_msg> is not NULL, it will be filled with a pointer to an
1296 * error message in case of error, that the caller is responsible for freeing.
1297 * The initial location must either be freeable or NULL.
1298 */
1299int val_distcc(struct arg *arg, char **err_msg)
1300{
1301 unsigned int token;
1302
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001303 if (arg[0].data.str.data != 4) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001304 memprintf(err_msg, "token name must be exactly 4 characters");
1305 return 0;
1306 }
1307
1308 /* convert the token name to an unsigned int (one byte per character,
1309 * big endian format).
1310 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001311 token = (arg[0].data.str.area[0] << 24) + (arg[0].data.str.area[1] << 16) +
1312 (arg[0].data.str.area[2] << 8) + (arg[0].data.str.area[3] << 0);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001313
1314 arg[0].type = ARGT_SINT;
1315 arg[0].data.sint = token;
1316
1317 if (arg[1].type != ARGT_SINT) {
1318 arg[1].type = ARGT_SINT;
1319 arg[1].data.sint = 0;
1320 }
1321 return 1;
1322}
1323
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001324/************************************************************************/
1325/* All supported sample and ACL keywords must be declared here. */
1326/************************************************************************/
1327
1328/* Note: must not be declared <const> as its list will be overwritten.
1329 * Note: fetches that may return multiple types must be declared as the lowest
1330 * common denominator, the type that can be casted into all other ones. For
1331 * instance IPv4/IPv6 must be declared IPv4.
1332 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001333static struct sample_fetch_kw_list smp_kws = {ILH, {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001334 { "distcc_body", smp_fetch_distcc_body, ARG2(1,STR,SINT), val_distcc, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1335 { "distcc_param", smp_fetch_distcc_param, ARG2(1,STR,SINT), val_distcc, SMP_T_SINT, SMP_USE_L6REQ|SMP_USE_L6RES },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001336 { "payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1337 { "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 +01001338 { "rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001339 { "rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L6REQ },
1340 { "rep_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
1341 { "req_len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1342 { "req_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001343 { "req_ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001344 { "req_ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +01001345
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001346 { "req.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001347 { "req.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ },
1348 { "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 +01001349 { "req.rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001350 { "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 +02001351 { "req.ssl_ec_ext", smp_fetch_req_ssl_ec_ext, 0, NULL, SMP_T_BOOL, SMP_USE_L6REQ },
Pradeep Jindalbb2acf52015-09-29 10:12:57 +05301352 { "req.ssl_st_ext", smp_fetch_req_ssl_st_ext, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001353 { "req.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001354 { "req.ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Alex Zorin4afdd132018-12-30 13:56:28 +11001355 { "req.ssl_alpn", smp_fetch_ssl_hello_alpn, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001356 { "req.ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1357 { "res.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001358 { "res.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6RES },
1359 { "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 +02001360 { "res.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001361 { "wait_end", smp_fetch_wait_end, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
1362 { /* END */ },
1363}};
1364
Willy Tarreau0108d902018-11-25 19:14:37 +01001365INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001366
1367/* Note: must not be declared <const> as its list will be overwritten.
1368 * Please take care of keeping this list alphabetically sorted.
1369 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001370static struct acl_kw_list acl_kws = {ILH, {
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +01001371 { "payload", "req.payload", PAT_MATCH_BIN },
1372 { "payload_lv", "req.payload_lv", PAT_MATCH_BIN },
1373 { "req_rdp_cookie", "req.rdp_cookie", PAT_MATCH_STR },
1374 { "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", PAT_MATCH_INT },
1375 { "req_ssl_sni", "req.ssl_sni", PAT_MATCH_STR },
1376 { "req_ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
1377 { "req.ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001378 { /* END */ },
1379}};
1380
Willy Tarreau0108d902018-11-25 19:14:37 +01001381INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001382
1383/*
1384 * Local variables:
1385 * c-indent-level: 8
1386 * c-basic-offset: 8
1387 * End:
1388 */