blob: 52be7848a3a12512e19c5ddbab2035ff90c75ecb [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 Tarreaudcc048a2020-06-04 19:11:43 +020016#include <haproxy/acl.h>
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020017#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020018#include <haproxy/arg.h>
Willy Tarreauf1d32c42020-06-04 21:07:02 +020019#include <haproxy/channel.h>
Willy Tarreau7ea393d2020-06-04 18:02:10 +020020#include <haproxy/connection.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020021#include <haproxy/htx.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020022#include <haproxy/net_helper.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +020023#include <haproxy/pattern.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020024#include <haproxy/payload.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020025#include <haproxy/sample.h>
Willy Tarreaud4c33c82013-01-07 21:59:07 +010026
27
28/************************************************************************/
29/* All supported sample fetch functions must be declared here */
30/************************************************************************/
31
32/* wait for more data as long as possible, then return TRUE. This should be
33 * used with content inspection.
34 */
35static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020036smp_fetch_wait_end(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010037{
Thierry FOURNIER0786d052015-05-11 15:42:45 +020038 if (!(smp->opt & SMP_OPT_FINAL)) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +010039 smp->flags |= SMP_F_MAY_CHANGE;
40 return 0;
41 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020042 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020043 smp->data.u.sint = 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +010044 return 1;
45}
46
47/* return the number of bytes in the request buffer */
48static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020049smp_fetch_len(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010050{
Christopher Faulet78f371e2020-04-30 09:38:08 +020051 if (smp->strm) {
52 struct channel *chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
53 if (IS_HTX_STRM(smp->strm)) {
54 struct htx *htx = htxbuf(&chn->buf);
55 smp->data.u.sint = htx->data - co_data(chn);
56 }
57 else
58 smp->data.u.sint = ci_data(chn);
59 }
Christopher Fauletf98e6262020-05-06 09:42:04 +020060 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Faulet78f371e2020-04-30 09:38:08 +020061 struct check *check = __objt_check(smp->sess->origin);
62 smp->data.u.sint = ((check->cs && IS_HTX_CS(check->cs)) ? (htxbuf(&check->bi))->data: b_data(&check->bi));
63 }
64 else
Willy Tarreaube508f12016-03-10 11:47:01 +010065 return 0;
66
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020067 smp->data.type = SMP_T_SINT;
Willy Tarreaud4c33c82013-01-07 21:59:07 +010068 smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
69 return 1;
70}
71
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053072/* Returns 0 if the client didn't send a SessionTicket Extension
73 * Returns 1 if the client sent SessionTicket Extension
74 * Returns 2 if the client also sent non-zero length SessionTicket
75 * Returns SMP_T_SINT data type
76 */
77static int
78smp_fetch_req_ssl_st_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
79{
80 int hs_len, ext_len, bleft;
81 struct channel *chn;
82 unsigned char *data;
83
Willy Tarreaube508f12016-03-10 11:47:01 +010084 if (!smp->strm)
85 goto not_ssl_hello;
86
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053087 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +020088 bleft = ci_data(chn);
89 data = (unsigned char *)ci_head(chn);
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053090
91 /* Check for SSL/TLS Handshake */
92 if (!bleft)
93 goto too_short;
94 if (*data != 0x16)
95 goto not_ssl_hello;
96
97 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
98 if (bleft < 3)
99 goto too_short;
100 if (data[1] < 0x03)
101 goto not_ssl_hello;
102
103 if (bleft < 5)
104 goto too_short;
105 hs_len = (data[3] << 8) + data[4];
106 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
107 goto not_ssl_hello; /* too short to have an extension */
108
109 data += 5; /* enter TLS handshake */
110 bleft -= 5;
111
112 /* Check for a complete client hello starting at <data> */
113 if (bleft < 1)
114 goto too_short;
115 if (data[0] != 0x01) /* msg_type = Client Hello */
116 goto not_ssl_hello;
117
118 /* Check the Hello's length */
119 if (bleft < 4)
120 goto too_short;
121 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
122 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
123 goto not_ssl_hello; /* too short to have an extension */
124
125 /* We want the full handshake here */
126 if (bleft < hs_len)
127 goto too_short;
128
129 data += 4;
130 /* Start of the ClientHello message */
131 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
132 goto not_ssl_hello;
133
134 ext_len = data[34]; /* session_id_len */
135 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
136 goto not_ssl_hello;
137
138 /* Jump to cipher suite */
139 hs_len -= 35 + ext_len;
140 data += 35 + ext_len;
141
142 if (hs_len < 4 || /* minimum one cipher */
143 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
144 ext_len > hs_len)
145 goto not_ssl_hello;
146
147 /* Jump to the compression methods */
148 hs_len -= 2 + ext_len;
149 data += 2 + ext_len;
150
151 if (hs_len < 2 || /* minimum one compression method */
152 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
153 goto not_ssl_hello;
154
155 /* Jump to the extensions */
156 hs_len -= 1 + data[0];
157 data += 1 + data[0];
158
159 if (hs_len < 2 || /* minimum one extension list length */
160 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
161 goto not_ssl_hello;
162
163 hs_len = ext_len; /* limit ourselves to the extension length */
164 data += 2;
165
166 while (hs_len >= 4) {
167 int ext_type, ext_len;
168
169 ext_type = (data[0] << 8) + data[1];
170 ext_len = (data[2] << 8) + data[3];
171
172 if (ext_len > hs_len - 4) /* Extension too long */
173 goto not_ssl_hello;
174
175 /* SesstionTicket extension */
176 if (ext_type == 35) {
177 smp->data.type = SMP_T_SINT;
178 /* SessionTicket also present */
179 if (ext_len > 0)
180 smp->data.u.sint = 2;
181 /* SessionTicket absent */
182 else
183 smp->data.u.sint = 1;
184 smp->flags = SMP_F_VOLATILE;
185 return 1;
186 }
187
188 hs_len -= 4 + ext_len;
189 data += 4 + ext_len;
190 }
191 /* SessionTicket Extension not found */
192 smp->data.type = SMP_T_SINT;
193 smp->data.u.sint = 0;
194 smp->flags = SMP_F_VOLATILE;
195 return 1;
196
Pradeep Jindalbb2acf52015-09-29 10:12:57 +0530197 too_short:
198 smp->flags = SMP_F_MAY_CHANGE;
199
200 not_ssl_hello:
201 return 0;
202}
203
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200204/* Returns TRUE if the client sent Supported Elliptic Curves Extension (0x000a)
205 * Mainly used to detect if client supports ECC cipher suites.
206 */
207static int
208smp_fetch_req_ssl_ec_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
209{
210 int hs_len, ext_len, bleft;
211 struct channel *chn;
212 unsigned char *data;
213
Willy Tarreaube508f12016-03-10 11:47:01 +0100214 if (!smp->strm)
215 goto not_ssl_hello;
216
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200217 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200218 bleft = ci_data(chn);
219 data = (unsigned char *)ci_head(chn);
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200220
221 /* Check for SSL/TLS Handshake */
222 if (!bleft)
223 goto too_short;
224 if (*data != 0x16)
225 goto not_ssl_hello;
226
227 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
228 if (bleft < 3)
229 goto too_short;
230 if (data[1] < 0x03)
231 goto not_ssl_hello;
232
233 if (bleft < 5)
234 goto too_short;
235 hs_len = (data[3] << 8) + data[4];
236 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
237 goto not_ssl_hello; /* too short to have an extension */
238
239 data += 5; /* enter TLS handshake */
240 bleft -= 5;
241
242 /* Check for a complete client hello starting at <data> */
243 if (bleft < 1)
244 goto too_short;
245 if (data[0] != 0x01) /* msg_type = Client Hello */
246 goto not_ssl_hello;
247
248 /* Check the Hello's length */
249 if (bleft < 4)
250 goto too_short;
251 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
252 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
253 goto not_ssl_hello; /* too short to have an extension */
254
255 /* We want the full handshake here */
256 if (bleft < hs_len)
257 goto too_short;
258
259 data += 4;
260 /* Start of the ClientHello message */
261 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
262 goto not_ssl_hello;
263
264 ext_len = data[34]; /* session_id_len */
265 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
266 goto not_ssl_hello;
267
268 /* Jump to cipher suite */
269 hs_len -= 35 + ext_len;
270 data += 35 + ext_len;
271
272 if (hs_len < 4 || /* minimum one cipher */
273 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
274 ext_len > hs_len)
275 goto not_ssl_hello;
276
277 /* Jump to the compression methods */
278 hs_len -= 2 + ext_len;
279 data += 2 + ext_len;
280
281 if (hs_len < 2 || /* minimum one compression method */
282 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
283 goto not_ssl_hello;
284
285 /* Jump to the extensions */
286 hs_len -= 1 + data[0];
287 data += 1 + data[0];
288
289 if (hs_len < 2 || /* minimum one extension list length */
290 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
291 goto not_ssl_hello;
292
293 hs_len = ext_len; /* limit ourselves to the extension length */
294 data += 2;
295
296 while (hs_len >= 4) {
297 int ext_type, ext_len;
298
299 ext_type = (data[0] << 8) + data[1];
300 ext_len = (data[2] << 8) + data[3];
301
302 if (ext_len > hs_len - 4) /* Extension too long */
303 goto not_ssl_hello;
304
305 /* Elliptic curves extension */
306 if (ext_type == 10) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200307 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200308 smp->data.u.sint = 1;
Nenad Merdanovic8a39a1f2015-07-15 12:51:11 +0200309 smp->flags = SMP_F_VOLATILE;
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200310 return 1;
311 }
312
313 hs_len -= 4 + ext_len;
314 data += 4 + ext_len;
315 }
316 /* server name not found */
317 goto not_ssl_hello;
318
319 too_short:
320 smp->flags = SMP_F_MAY_CHANGE;
321
322 not_ssl_hello:
323
324 return 0;
325}
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100326/* returns the type of SSL hello message (mainly used to detect an SSL hello) */
327static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200328smp_fetch_ssl_hello_type(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100329{
330 int hs_len;
331 int hs_type, bleft;
332 struct channel *chn;
333 const unsigned char *data;
334
Willy Tarreaube508f12016-03-10 11:47:01 +0100335 if (!smp->strm)
336 goto not_ssl_hello;
337
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200338 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200339 bleft = ci_data(chn);
340 data = (const unsigned char *)ci_head(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100341
342 if (!bleft)
343 goto too_short;
344
345 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
346 /* SSLv3 header format */
347 if (bleft < 9)
348 goto too_short;
349
350 /* ssl version 3 */
351 if ((data[1] << 16) + data[2] < 0x00030000)
352 goto not_ssl_hello;
353
354 /* ssl message len must present handshake type and len */
355 if ((data[3] << 8) + data[4] < 4)
356 goto not_ssl_hello;
357
358 /* format introduced with SSLv3 */
359
360 hs_type = (int)data[5];
361 hs_len = ( data[6] << 16 ) + ( data[7] << 8 ) + data[8];
362
363 /* not a full handshake */
364 if (bleft < (9 + hs_len))
365 goto too_short;
366
367 }
368 else {
369 goto not_ssl_hello;
370 }
371
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200372 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200373 smp->data.u.sint = hs_type;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100374 smp->flags = SMP_F_VOLATILE;
375
376 return 1;
377
378 too_short:
379 smp->flags = SMP_F_MAY_CHANGE;
380
381 not_ssl_hello:
382
383 return 0;
384}
385
386/* Return the version of the SSL protocol in the request. It supports both
387 * SSLv3 (TLSv1) header format for any message, and SSLv2 header format for
388 * the hello message. The SSLv3 format is described in RFC 2246 p49, and the
389 * SSLv2 format is described here, and completed p67 of RFC 2246 :
390 * http://wp.netscape.com/eng/security/SSL_2.html
391 *
392 * Note: this decoder only works with non-wrapping data.
393 */
394static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200395smp_fetch_req_ssl_ver(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100396{
397 int version, bleft, msg_len;
398 const unsigned char *data;
Willy Tarreaube508f12016-03-10 11:47:01 +0100399 struct channel *req;
400
401 if (!smp->strm)
402 return 0;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100403
Willy Tarreaube508f12016-03-10 11:47:01 +0100404 req = &smp->strm->req;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100405 msg_len = 0;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200406 bleft = ci_data(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100407 if (!bleft)
408 goto too_short;
409
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200410 data = (const unsigned char *)ci_head(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100411 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
412 /* SSLv3 header format */
Lukas Tribusc93242c2015-11-05 13:59:30 +0100413 if (bleft < 11)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100414 goto too_short;
415
Lukas Tribusc93242c2015-11-05 13:59:30 +0100416 version = (data[1] << 16) + data[2]; /* record layer version: major, minor */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100417 msg_len = (data[3] << 8) + data[4]; /* record length */
418
419 /* format introduced with SSLv3 */
420 if (version < 0x00030000)
421 goto not_ssl;
422
Lukas Tribusc93242c2015-11-05 13:59:30 +0100423 /* message length between 6 and 2^14 + 2048 */
424 if (msg_len < 6 || msg_len > ((1<<14) + 2048))
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100425 goto not_ssl;
426
427 bleft -= 5; data += 5;
Lukas Tribusc93242c2015-11-05 13:59:30 +0100428
429 /* return the client hello client version, not the record layer version */
430 version = (data[4] << 16) + data[5]; /* client hello version: major, minor */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100431 } else {
432 /* SSLv2 header format, only supported for hello (msg type 1) */
433 int rlen, plen, cilen, silen, chlen;
434
435 if (*data & 0x80) {
436 if (bleft < 3)
437 goto too_short;
438 /* short header format : 15 bits for length */
439 rlen = ((data[0] & 0x7F) << 8) | data[1];
440 plen = 0;
441 bleft -= 2; data += 2;
442 } else {
443 if (bleft < 4)
444 goto too_short;
445 /* long header format : 14 bits for length + pad length */
446 rlen = ((data[0] & 0x3F) << 8) | data[1];
447 plen = data[2];
Willy Tarreau74967f62016-08-30 14:39:46 +0200448 bleft -= 3; data += 3;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100449 }
450
451 if (*data != 0x01)
452 goto not_ssl;
453 bleft--; data++;
454
455 if (bleft < 8)
456 goto too_short;
457 version = (data[0] << 16) + data[1]; /* version: major, minor */
458 cilen = (data[2] << 8) + data[3]; /* cipher len, multiple of 3 */
459 silen = (data[4] << 8) + data[5]; /* session_id_len: 0 or 16 */
460 chlen = (data[6] << 8) + data[7]; /* 16<=challenge length<=32 */
461
462 bleft -= 8; data += 8;
463 if (cilen % 3 != 0)
464 goto not_ssl;
465 if (silen && silen != 16)
466 goto not_ssl;
467 if (chlen < 16 || chlen > 32)
468 goto not_ssl;
469 if (rlen != 9 + cilen + silen + chlen)
470 goto not_ssl;
471
472 /* focus on the remaining data length */
473 msg_len = cilen + silen + chlen + plen;
474 }
475 /* We could recursively check that the buffer ends exactly on an SSL
476 * fragment boundary and that a possible next segment is still SSL,
477 * but that's a bit pointless. However, we could still check that
478 * all the part of the request which fits in a buffer is already
479 * there.
480 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200481 if (msg_len > channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req))
482 msg_len = channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100483
484 if (bleft < msg_len)
485 goto too_short;
486
487 /* OK that's enough. We have at least the whole message, and we have
488 * the protocol version.
489 */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200490 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200491 smp->data.u.sint = version;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100492 smp->flags = SMP_F_VOLATILE;
493 return 1;
494
495 too_short:
496 smp->flags = SMP_F_MAY_CHANGE;
497 not_ssl:
498 return 0;
499}
500
501/* Try to extract the Server Name Indication that may be presented in a TLS
502 * client hello handshake message. The format of the message is the following
503 * (cf RFC5246 + RFC6066) :
504 * TLS frame :
505 * - uint8 type = 0x16 (Handshake)
506 * - uint16 version >= 0x0301 (TLSv1)
507 * - uint16 length (frame length)
508 * - TLS handshake :
509 * - uint8 msg_type = 0x01 (ClientHello)
510 * - uint24 length (handshake message length)
511 * - ClientHello :
512 * - uint16 client_version >= 0x0301 (TLSv1)
513 * - uint8 Random[32] (4 first ones are timestamp)
514 * - SessionID :
515 * - uint8 session_id_len (0..32) (SessionID len in bytes)
516 * - uint8 session_id[session_id_len]
517 * - CipherSuite :
518 * - uint16 cipher_len >= 2 (Cipher length in bytes)
519 * - uint16 ciphers[cipher_len/2]
520 * - CompressionMethod :
521 * - uint8 compression_len >= 1 (# of supported methods)
522 * - uint8 compression_methods[compression_len]
523 * - optional client_extension_len (in bytes)
524 * - optional sequence of ClientHelloExtensions (as many bytes as above):
525 * - uint16 extension_type = 0 for server_name
526 * - uint16 extension_len
527 * - opaque extension_data[extension_len]
528 * - uint16 server_name_list_len (# of bytes here)
529 * - opaque server_names[server_name_list_len bytes]
530 * - uint8 name_type = 0 for host_name
531 * - uint16 name_len
532 * - opaque hostname[name_len bytes]
533 */
534static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200535smp_fetch_ssl_hello_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100536{
537 int hs_len, ext_len, bleft;
538 struct channel *chn;
539 unsigned char *data;
540
Willy Tarreaube508f12016-03-10 11:47:01 +0100541 if (!smp->strm)
542 goto not_ssl_hello;
543
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200544 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200545 bleft = ci_data(chn);
546 data = (unsigned char *)ci_head(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100547
548 /* Check for SSL/TLS Handshake */
549 if (!bleft)
550 goto too_short;
551 if (*data != 0x16)
552 goto not_ssl_hello;
553
Lukas Tribus57d22972014-04-10 21:36:22 +0200554 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100555 if (bleft < 3)
556 goto too_short;
Lukas Tribus57d22972014-04-10 21:36:22 +0200557 if (data[1] < 0x03)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100558 goto not_ssl_hello;
559
560 if (bleft < 5)
561 goto too_short;
562 hs_len = (data[3] << 8) + data[4];
563 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
564 goto not_ssl_hello; /* too short to have an extension */
565
566 data += 5; /* enter TLS handshake */
567 bleft -= 5;
568
569 /* Check for a complete client hello starting at <data> */
570 if (bleft < 1)
571 goto too_short;
572 if (data[0] != 0x01) /* msg_type = Client Hello */
573 goto not_ssl_hello;
574
575 /* Check the Hello's length */
576 if (bleft < 4)
577 goto too_short;
578 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
579 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
580 goto not_ssl_hello; /* too short to have an extension */
581
582 /* We want the full handshake here */
583 if (bleft < hs_len)
584 goto too_short;
585
586 data += 4;
587 /* Start of the ClientHello message */
588 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
589 goto not_ssl_hello;
590
591 ext_len = data[34]; /* session_id_len */
592 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
593 goto not_ssl_hello;
594
595 /* Jump to cipher suite */
596 hs_len -= 35 + ext_len;
597 data += 35 + ext_len;
598
599 if (hs_len < 4 || /* minimum one cipher */
600 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
601 ext_len > hs_len)
602 goto not_ssl_hello;
603
604 /* Jump to the compression methods */
605 hs_len -= 2 + ext_len;
606 data += 2 + ext_len;
607
608 if (hs_len < 2 || /* minimum one compression method */
609 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
610 goto not_ssl_hello;
611
612 /* Jump to the extensions */
613 hs_len -= 1 + data[0];
614 data += 1 + data[0];
615
616 if (hs_len < 2 || /* minimum one extension list length */
617 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
618 goto not_ssl_hello;
619
620 hs_len = ext_len; /* limit ourselves to the extension length */
621 data += 2;
622
623 while (hs_len >= 4) {
624 int ext_type, name_type, srv_len, name_len;
625
626 ext_type = (data[0] << 8) + data[1];
627 ext_len = (data[2] << 8) + data[3];
628
629 if (ext_len > hs_len - 4) /* Extension too long */
630 goto not_ssl_hello;
631
632 if (ext_type == 0) { /* Server name */
633 if (ext_len < 2) /* need one list length */
634 goto not_ssl_hello;
635
636 srv_len = (data[4] << 8) + data[5];
637 if (srv_len < 4 || srv_len > hs_len - 6)
638 goto not_ssl_hello; /* at least 4 bytes per server name */
639
640 name_type = data[6];
641 name_len = (data[7] << 8) + data[8];
642
643 if (name_type == 0) { /* hostname */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200644 smp->data.type = SMP_T_STR;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200645 smp->data.u.str.area = (char *)data + 9;
646 smp->data.u.str.data = name_len;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100647 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100648 return 1;
649 }
650 }
651
652 hs_len -= 4 + ext_len;
653 data += 4 + ext_len;
654 }
655 /* server name not found */
656 goto not_ssl_hello;
657
658 too_short:
659 smp->flags = SMP_F_MAY_CHANGE;
660
661 not_ssl_hello:
662
663 return 0;
664}
665
Alex Zorin4afdd132018-12-30 13:56:28 +1100666/* Try to extract the Application-Layer Protocol Negotiation (ALPN) protocol
667 * names that may be presented in a TLS client hello handshake message. As the
668 * message presents a list of protocol names in descending order of preference,
669 * it may return iteratively. The format of the message is the following
670 * (cf RFC5246 + RFC7301) :
671 * TLS frame :
672 * - uint8 type = 0x16 (Handshake)
673 * - uint16 version >= 0x0301 (TLSv1)
674 * - uint16 length (frame length)
675 * - TLS handshake :
676 * - uint8 msg_type = 0x01 (ClientHello)
677 * - uint24 length (handshake message length)
678 * - ClientHello :
679 * - uint16 client_version >= 0x0301 (TLSv1)
680 * - uint8 Random[32] (4 first ones are timestamp)
681 * - SessionID :
682 * - uint8 session_id_len (0..32) (SessionID len in bytes)
683 * - uint8 session_id[session_id_len]
684 * - CipherSuite :
685 * - uint16 cipher_len >= 2 (Cipher length in bytes)
686 * - uint16 ciphers[cipher_len/2]
687 * - CompressionMethod :
688 * - uint8 compression_len >= 1 (# of supported methods)
689 * - uint8 compression_methods[compression_len]
690 * - optional client_extension_len (in bytes)
691 * - optional sequence of ClientHelloExtensions (as many bytes as above):
692 * - uint16 extension_type = 16 for application_layer_protocol_negotiation
693 * - uint16 extension_len
694 * - opaque extension_data[extension_len]
695 * - uint16 protocol_names_len (# of bytes here)
696 * - opaque protocol_names[protocol_names_len bytes]
697 * - uint8 name_len
698 * - opaque protocol_name[name_len bytes]
699 */
700static int
701smp_fetch_ssl_hello_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
702{
703 int hs_len, ext_len, bleft;
704 struct channel *chn;
705 unsigned char *data;
706
707 if (!smp->strm)
708 goto not_ssl_hello;
709
710 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
711 bleft = ci_data(chn);
712 data = (unsigned char *)ci_head(chn);
713
714 /* Check for SSL/TLS Handshake */
715 if (!bleft)
716 goto too_short;
717 if (*data != 0x16)
718 goto not_ssl_hello;
719
720 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
721 if (bleft < 3)
722 goto too_short;
723 if (data[1] < 0x03)
724 goto not_ssl_hello;
725
726 if (bleft < 5)
727 goto too_short;
728 hs_len = (data[3] << 8) + data[4];
729 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
730 goto not_ssl_hello; /* too short to have an extension */
731
732 data += 5; /* enter TLS handshake */
733 bleft -= 5;
734
735 /* Check for a complete client hello starting at <data> */
736 if (bleft < 1)
737 goto too_short;
738 if (data[0] != 0x01) /* msg_type = Client Hello */
739 goto not_ssl_hello;
740
741 /* Check the Hello's length */
742 if (bleft < 4)
743 goto too_short;
744 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
745 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
746 goto not_ssl_hello; /* too short to have an extension */
747
748 /* We want the full handshake here */
749 if (bleft < hs_len)
750 goto too_short;
751
752 data += 4;
753 /* Start of the ClientHello message */
754 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
755 goto not_ssl_hello;
756
757 ext_len = data[34]; /* session_id_len */
758 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
759 goto not_ssl_hello;
760
761 /* Jump to cipher suite */
762 hs_len -= 35 + ext_len;
763 data += 35 + ext_len;
764
765 if (hs_len < 4 || /* minimum one cipher */
766 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
767 ext_len > hs_len)
768 goto not_ssl_hello;
769
770 /* Jump to the compression methods */
771 hs_len -= 2 + ext_len;
772 data += 2 + ext_len;
773
774 if (hs_len < 2 || /* minimum one compression method */
775 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
776 goto not_ssl_hello;
777
778 /* Jump to the extensions */
779 hs_len -= 1 + data[0];
780 data += 1 + data[0];
781
782 if (hs_len < 2 || /* minimum one extension list length */
783 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
784 goto not_ssl_hello;
785
786 hs_len = ext_len; /* limit ourselves to the extension length */
787 data += 2;
788
789 while (hs_len >= 4) {
790 int ext_type, name_len, name_offset;
791
792 ext_type = (data[0] << 8) + data[1];
793 ext_len = (data[2] << 8) + data[3];
794
795 if (ext_len > hs_len - 4) /* Extension too long */
796 goto not_ssl_hello;
797
798 if (ext_type == 16) { /* ALPN */
799 if (ext_len < 3) /* one list length [uint16] + at least one name length [uint8] */
800 goto not_ssl_hello;
801
802 /* Name cursor in ctx, must begin after protocol_names_len */
803 name_offset = smp->ctx.i < 6 ? 6 : smp->ctx.i;
804 name_len = data[name_offset];
805
806 if (name_len + name_offset - 3 > ext_len)
807 goto not_ssl_hello;
808
809 smp->data.type = SMP_T_STR;
810 smp->data.u.str.area = (char *)data + name_offset + 1; /* +1 to skip name_len */
811 smp->data.u.str.data = name_len;
812 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
813
814 /* May have more protocol names remaining */
815 if (name_len + name_offset - 3 < ext_len) {
816 smp->ctx.i = name_offset + name_len + 1;
817 smp->flags |= SMP_F_NOT_LAST;
818 }
819
820 return 1;
821 }
822
823 hs_len -= 4 + ext_len;
824 data += 4 + ext_len;
825 }
826 /* alpn not found */
827 goto not_ssl_hello;
828
829 too_short:
830 smp->flags = SMP_F_MAY_CHANGE;
831
832 not_ssl_hello:
833
834 return 0;
835}
836
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200837/* Fetch the request RDP cookie identified in <cname>:<clen>, or any cookie if
Willy Tarreaub169eba2013-12-16 15:14:43 +0100838 * <clen> is empty (cname is then ignored). It returns the data into sample <smp>
839 * of type SMP_T_CSTR. Note: this decoder only works with non-wrapping data.
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100840 */
841int
Willy Tarreau87b09662015-04-03 00:22:06 +0200842fetch_rdp_cookie_name(struct stream *s, struct sample *smp, const char *cname, int clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100843{
844 int bleft;
845 const unsigned char *data;
846
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100847 smp->flags = SMP_F_CONST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200848 smp->data.type = SMP_T_STR;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100849
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200850 bleft = ci_data(&s->req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100851 if (bleft <= 11)
852 goto too_short;
853
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200854 data = (const unsigned char *)ci_head(&s->req) + 11;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100855 bleft -= 11;
856
857 if (bleft <= 7)
858 goto too_short;
859
860 if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
861 goto not_cookie;
862
863 data += 7;
864 bleft -= 7;
865
866 while (bleft > 0 && *data == ' ') {
867 data++;
868 bleft--;
869 }
870
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200871 if (clen) {
872 if (bleft <= clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100873 goto too_short;
874
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200875 if ((data[clen] != '=') ||
876 strncasecmp(cname, (const char *)data, clen) != 0)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100877 goto not_cookie;
878
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200879 data += clen + 1;
880 bleft -= clen + 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100881 } else {
882 while (bleft > 0 && *data != '=') {
883 if (*data == '\r' || *data == '\n')
884 goto not_cookie;
885 data++;
886 bleft--;
887 }
888
889 if (bleft < 1)
890 goto too_short;
891
892 if (*data != '=')
893 goto not_cookie;
894
895 data++;
896 bleft--;
897 }
898
899 /* data points to cookie value */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200900 smp->data.u.str.area = (char *)data;
901 smp->data.u.str.data = 0;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100902
903 while (bleft > 0 && *data != '\r') {
904 data++;
905 bleft--;
906 }
907
908 if (bleft < 2)
909 goto too_short;
910
911 if (data[0] != '\r' || data[1] != '\n')
912 goto not_cookie;
913
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200914 smp->data.u.str.data = (char *)data - smp->data.u.str.area;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100915 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100916 return 1;
917
918 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100919 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100920 not_cookie:
921 return 0;
922}
923
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200924/* Fetch the request RDP cookie identified in the args, or any cookie if no arg
925 * is passed. It is usable both for ACL and for samples. Note: this decoder
926 * only works with non-wrapping data. Accepts either 0 or 1 argument. Argument
Willy Tarreaub169eba2013-12-16 15:14:43 +0100927 * is a string (cookie name), other types will lead to undefined behaviour. The
928 * returned sample has type SMP_T_CSTR.
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200929 */
930int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200931smp_fetch_rdp_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200932{
Willy Tarreaube508f12016-03-10 11:47:01 +0100933 if (!smp->strm)
934 return 0;
935
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200936 return fetch_rdp_cookie_name(smp->strm, smp,
937 args ? args->data.str.area : NULL,
938 args ? args->data.str.data : 0);
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200939}
940
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100941/* returns either 1 or 0 depending on whether an RDP cookie is found or not */
942static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200943smp_fetch_rdp_cookie_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100944{
945 int ret;
946
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200947 ret = smp_fetch_rdp_cookie(args, smp, kw, private);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100948
949 if (smp->flags & SMP_F_MAY_CHANGE)
950 return 0;
951
952 smp->flags = SMP_F_VOLATILE;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200953 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200954 smp->data.u.sint = ret;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100955 return 1;
956}
957
958/* extracts part of a payload with offset and length at a given position */
959static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200960smp_fetch_payload_lv(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100961{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200962 unsigned int len_offset = arg_p[0].data.sint;
963 unsigned int len_size = arg_p[1].data.sint;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100964 unsigned int buf_offset;
965 unsigned int buf_size = 0;
Christopher Faulet78f371e2020-04-30 09:38:08 +0200966 struct channel *chn = NULL;
967 char *head = NULL;
968 size_t max, data;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100969 int i;
970
971 /* Format is (len offset, len size, buf offset) or (len offset, len size) */
972 /* by default buf offset == len offset + len size */
973 /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
974
Christopher Faulet78f371e2020-04-30 09:38:08 +0200975 if (smp->strm) {
976 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
977 head = ci_head(chn);
978 data = ci_data(chn);
979 max = global.tune.bufsize;
980 }
Christopher Fauletf98e6262020-05-06 09:42:04 +0200981 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Faulet78f371e2020-04-30 09:38:08 +0200982 struct buffer *buf = &(__objt_check(smp->sess->origin)->bi);
983 head = b_head(buf);
984 data = b_data(buf);
985 max = global.tune.chksize;
986 }
987 if (!head)
Willy Tarreaube508f12016-03-10 11:47:01 +0100988 return 0;
989
Christopher Faulet78f371e2020-04-30 09:38:08 +0200990 if (len_offset + len_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100991 goto too_short;
992
993 for (i = 0; i < len_size; i++) {
Christopher Faulet78f371e2020-04-30 09:38:08 +0200994 buf_size = (buf_size << 8) + ((unsigned char *)head)[i + len_offset];
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100995 }
996
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200997 /* buf offset may be implicit, absolute or relative. If the LSB
998 * is set, then the offset is relative otherwise it is absolute.
999 */
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001000 buf_offset = len_offset + len_size;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001001 if (arg_p[2].type == ARGT_SINT) {
1002 if (arg_p[2].data.sint & 1)
1003 buf_offset += arg_p[2].data.sint >> 1;
1004 else
1005 buf_offset = arg_p[2].data.sint >> 1;
1006 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001007
Christopher Faulet78f371e2020-04-30 09:38:08 +02001008 if (!buf_size || buf_size > max || buf_offset + buf_size > max) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001009 /* will never match */
1010 smp->flags = 0;
1011 return 0;
1012 }
1013
Christopher Faulet78f371e2020-04-30 09:38:08 +02001014 if (buf_offset + buf_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001015 goto too_short;
1016
1017 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001018 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001019 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001020 chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001021 return 1;
1022
1023 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001024 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001025 return 0;
1026}
1027
1028/* extracts some payload at a fixed position and length */
1029static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +02001030smp_fetch_payload(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001031{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001032 unsigned int buf_offset = arg_p[0].data.sint;
1033 unsigned int buf_size = arg_p[1].data.sint;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001034 struct channel *chn = NULL;
1035 char *head = NULL;
1036 size_t max, data;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001037
Christopher Faulet78f371e2020-04-30 09:38:08 +02001038 if (smp->strm) {
1039 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1040 head = ci_head(chn);
1041 data = ci_data(chn);
1042 max = global.tune.bufsize;
1043 }
Christopher Fauletf98e6262020-05-06 09:42:04 +02001044 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Faulet78f371e2020-04-30 09:38:08 +02001045 struct buffer *buf = &(__objt_check(smp->sess->origin)->bi);
1046 head = b_head(buf);
1047 data = b_data(buf);
1048 max = global.tune.chksize;
1049 }
1050 if (!head)
Willy Tarreaube508f12016-03-10 11:47:01 +01001051 return 0;
1052
Christopher Faulet78f371e2020-04-30 09:38:08 +02001053 if (buf_size > max || buf_offset + buf_size > max) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001054 /* will never match */
1055 smp->flags = 0;
1056 return 0;
1057 }
Christopher Faulet78f371e2020-04-30 09:38:08 +02001058 if (buf_offset + buf_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001059 goto too_short;
1060
1061 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001062 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001063 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001064 chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size ? buf_size : (data - buf_offset));
1065
1066 if (!buf_size && chn && channel_may_recv(chn) && !channel_input_closed(chn))
Willy Tarreau00f00842013-08-02 11:07:32 +02001067 smp->flags |= SMP_F_MAY_CHANGE;
1068
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001069 return 1;
1070
Christopher Faulet78f371e2020-04-30 09:38:08 +02001071 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001072 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001073 return 0;
1074}
1075
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001076/* This function is used to validate the arguments passed to a "payload_lv" fetch
1077 * keyword. This keyword allows two positive integers and an optional signed one,
1078 * with the second one being strictly positive and the third one being greater than
1079 * the opposite of the two others if negative. It is assumed that the types are
1080 * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> is
1081 * not NULL, it will be filled with a pointer to an error message in case of
1082 * error, that the caller is responsible for freeing. The initial location must
1083 * either be freeable or NULL.
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001084 *
1085 * Note that offset2 is stored with SINT type, but its not directly usable as is.
1086 * The value is contained in the 63 MSB and the LSB is used as a flag for marking
1087 * the "relative" property of the value.
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001088 */
Thierry FOURNIER49f45af2014-12-08 19:50:43 +01001089int val_payload_lv(struct arg *arg, char **err_msg)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001090{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001091 int relative = 0;
1092 const char *str;
1093
1094 if (arg[0].data.sint < 0) {
1095 memprintf(err_msg, "payload offset1 must be positive");
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001096 return 0;
1097 }
1098
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001099 if (!arg[1].data.sint) {
1100 memprintf(err_msg, "payload length must be > 0");
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001101 return 0;
1102 }
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001103
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001104 if (arg[2].type == ARGT_STR && arg[2].data.str.data > 0) {
Christopher Faulet95917132020-08-05 23:07:07 +02001105 long long int i;
1106
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001107 if (arg[2].data.str.area[0] == '+' || arg[2].data.str.area[0] == '-')
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001108 relative = 1;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001109 str = arg[2].data.str.area;
Christopher Faulet95917132020-08-05 23:07:07 +02001110 i = read_int64(&str, str + arg[2].data.str.data);
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001111 if (*str != '\0') {
1112 memprintf(err_msg, "payload offset2 is not a number");
1113 return 0;
1114 }
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001115 chunk_destroy(&arg[2].data.str);
Christopher Faulet95917132020-08-05 23:07:07 +02001116 arg[2].type = ARGT_SINT;
1117 arg[2].data.sint = i;
1118
1119 if (arg[0].data.sint + arg[1].data.sint + arg[2].data.sint < 0) {
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001120 memprintf(err_msg, "payload offset2 too negative");
1121 return 0;
1122 }
1123 if (relative)
1124 arg[2].data.sint = ( arg[2].data.sint << 1 ) + 1;
1125 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001126 return 1;
1127}
1128
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001129/* extracts the parameter value of a distcc token */
1130static int
1131smp_fetch_distcc_param(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
1132{
1133 unsigned int match_tok = arg_p[0].data.sint;
1134 unsigned int match_occ = arg_p[1].data.sint;
1135 unsigned int token;
1136 unsigned int param;
1137 unsigned int body;
1138 unsigned int ofs;
1139 unsigned int occ;
1140 struct channel *chn;
1141 int i;
1142
1143 /* Format is (token[,occ]). occ starts at 1. */
1144
1145 if (!smp->strm)
1146 return 0;
1147
1148 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1149
1150 ofs = 0; occ = 0;
1151 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001152 if (ofs + 12 > ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001153 /* not there yet but could it at least fit ? */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001154 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001155 goto too_short;
1156
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001157 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001158 goto too_short;
1159
1160 goto no_match;
1161 }
1162
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001163 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001164 ofs += 4;
1165
1166 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001167 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001168
1169 if (c < 0)
1170 goto no_match;
1171 param = (param << 4) + c;
1172 }
1173 ofs += 8;
1174
1175 /* these tokens don't have a body */
1176 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1177 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1178 token != 0x444F4E45 /* DONE */)
1179 body = param;
1180 else
1181 body = 0;
1182
1183 if (token == match_tok) {
1184 occ++;
1185 if (!match_occ || match_occ == occ) {
1186 /* found */
1187 smp->data.type = SMP_T_SINT;
1188 smp->data.u.sint = param;
1189 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1190 return 1;
1191 }
1192 }
1193 ofs += body;
1194 }
1195
1196 too_short:
1197 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1198 return 0;
1199 no_match:
1200 /* will never match (end of buffer, or bad contents) */
1201 smp->flags = 0;
1202 return 0;
1203
1204}
1205
1206/* extracts the (possibly truncated) body of a distcc token */
1207static int
1208smp_fetch_distcc_body(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
1209{
1210 unsigned int match_tok = arg_p[0].data.sint;
1211 unsigned int match_occ = arg_p[1].data.sint;
1212 unsigned int token;
1213 unsigned int param;
1214 unsigned int ofs;
1215 unsigned int occ;
1216 unsigned int body;
1217 struct channel *chn;
1218 int i;
1219
1220 /* Format is (token[,occ]). occ starts at 1. */
1221
1222 if (!smp->strm)
1223 return 0;
1224
1225 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1226
1227 ofs = 0; occ = 0;
1228 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001229 if (ofs + 12 > ci_data(chn)) {
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001230 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001231 goto too_short;
1232
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001233 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001234 goto too_short;
1235
1236 goto no_match;
1237 }
1238
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001239 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001240 ofs += 4;
1241
1242 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001243 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001244
1245 if (c < 0)
1246 goto no_match;
1247 param = (param << 4) + c;
1248 }
1249 ofs += 8;
1250
1251 /* these tokens don't have a body */
1252 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1253 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1254 token != 0x444F4E45 /* DONE */)
1255 body = param;
1256 else
1257 body = 0;
1258
1259 if (token == match_tok) {
1260 occ++;
1261 if (!match_occ || match_occ == occ) {
1262 /* found */
1263
1264 smp->data.type = SMP_T_BIN;
1265 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1266
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001267 if (ofs + body > ci_head(chn) - b_orig(&chn->buf) + ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001268 /* incomplete body */
1269
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001270 if (ofs + body > channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001271 /* truncate it to whatever will fit */
1272 smp->flags |= SMP_F_MAY_CHANGE;
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001273 body = channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn) - ofs;
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001274 }
1275 }
1276
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001277 chunk_initlen(&smp->data.u.str, ci_head(chn) + ofs, 0, body);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001278 return 1;
1279 }
1280 }
1281 ofs += body;
1282 }
1283
1284 too_short:
1285 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1286 return 0;
1287 no_match:
1288 /* will never match (end of buffer, or bad contents) */
1289 smp->flags = 0;
1290 return 0;
1291
1292}
1293
1294/* This function is used to validate the arguments passed to a "distcc_param" or
1295 * "distcc_body" sample fetch keyword. They take a mandatory token name of exactly
1296 * 4 characters, followed by an optional occurrence number starting at 1. It is
1297 * assumed that the types are already the correct ones. Returns 0 on error, non-
1298 * zero if OK. If <err_msg> is not NULL, it will be filled with a pointer to an
1299 * error message in case of error, that the caller is responsible for freeing.
1300 * The initial location must either be freeable or NULL.
1301 */
1302int val_distcc(struct arg *arg, char **err_msg)
1303{
1304 unsigned int token;
1305
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001306 if (arg[0].data.str.data != 4) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001307 memprintf(err_msg, "token name must be exactly 4 characters");
1308 return 0;
1309 }
1310
1311 /* convert the token name to an unsigned int (one byte per character,
1312 * big endian format).
1313 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001314 token = (arg[0].data.str.area[0] << 24) + (arg[0].data.str.area[1] << 16) +
1315 (arg[0].data.str.area[2] << 8) + (arg[0].data.str.area[3] << 0);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001316
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001317 chunk_destroy(&arg[0].data.str);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001318 arg[0].type = ARGT_SINT;
1319 arg[0].data.sint = token;
1320
1321 if (arg[1].type != ARGT_SINT) {
1322 arg[1].type = ARGT_SINT;
1323 arg[1].data.sint = 0;
1324 }
1325 return 1;
1326}
1327
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001328/************************************************************************/
1329/* All supported sample and ACL keywords must be declared here. */
1330/************************************************************************/
1331
1332/* Note: must not be declared <const> as its list will be overwritten.
1333 * Note: fetches that may return multiple types must be declared as the lowest
1334 * common denominator, the type that can be casted into all other ones. For
1335 * instance IPv4/IPv6 must be declared IPv4.
1336 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001337static struct sample_fetch_kw_list smp_kws = {ILH, {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001338 { "distcc_body", smp_fetch_distcc_body, ARG2(1,STR,SINT), val_distcc, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1339 { "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 +02001340 { "payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1341 { "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 +01001342 { "rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001343 { "rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L6REQ },
1344 { "rep_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
1345 { "req_len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1346 { "req_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001347 { "req_ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001348 { "req_ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +01001349
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001350 { "req.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001351 { "req.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ },
1352 { "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 +01001353 { "req.rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001354 { "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 +02001355 { "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 +05301356 { "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 +02001357 { "req.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001358 { "req.ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Alex Zorin4afdd132018-12-30 13:56:28 +11001359 { "req.ssl_alpn", smp_fetch_ssl_hello_alpn, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001360 { "req.ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1361 { "res.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001362 { "res.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6RES },
1363 { "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 +02001364 { "res.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001365 { "wait_end", smp_fetch_wait_end, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
1366 { /* END */ },
1367}};
1368
Willy Tarreau0108d902018-11-25 19:14:37 +01001369INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001370
1371/* Note: must not be declared <const> as its list will be overwritten.
1372 * Please take care of keeping this list alphabetically sorted.
1373 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001374static struct acl_kw_list acl_kws = {ILH, {
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +01001375 { "payload", "req.payload", PAT_MATCH_BIN },
1376 { "payload_lv", "req.payload_lv", PAT_MATCH_BIN },
1377 { "req_rdp_cookie", "req.rdp_cookie", PAT_MATCH_STR },
1378 { "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", PAT_MATCH_INT },
1379 { "req_ssl_sni", "req.ssl_sni", PAT_MATCH_STR },
1380 { "req_ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
1381 { "req.ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001382 { /* END */ },
1383}};
1384
Willy Tarreau0108d902018-11-25 19:14:37 +01001385INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001386
1387/*
1388 * Local variables:
1389 * c-indent-level: 8
1390 * c-basic-offset: 8
1391 * End:
1392 */