blob: f867541bc563b177adcda0d63e148527b8acfcfd [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);
Christopher Faulet78f371e2020-04-30 09:38:08 +0200979 }
Christopher Fauletf98e6262020-05-06 09:42:04 +0200980 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Faulet78f371e2020-04-30 09:38:08 +0200981 struct buffer *buf = &(__objt_check(smp->sess->origin)->bi);
982 head = b_head(buf);
983 data = b_data(buf);
Christopher Faulet78f371e2020-04-30 09:38:08 +0200984 }
Christopher Fauletbb9fb8b2020-11-25 17:20:57 +0100985 max = global.tune.bufsize;
Christopher Faulet78f371e2020-04-30 09:38:08 +0200986 if (!head)
Willy Tarreaube508f12016-03-10 11:47:01 +0100987 return 0;
988
Christopher Faulet78f371e2020-04-30 09:38:08 +0200989 if (len_offset + len_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100990 goto too_short;
991
992 for (i = 0; i < len_size; i++) {
Christopher Faulet78f371e2020-04-30 09:38:08 +0200993 buf_size = (buf_size << 8) + ((unsigned char *)head)[i + len_offset];
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100994 }
995
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200996 /* buf offset may be implicit, absolute or relative. If the LSB
997 * is set, then the offset is relative otherwise it is absolute.
998 */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100999 buf_offset = len_offset + len_size;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001000 if (arg_p[2].type == ARGT_SINT) {
1001 if (arg_p[2].data.sint & 1)
1002 buf_offset += arg_p[2].data.sint >> 1;
1003 else
1004 buf_offset = arg_p[2].data.sint >> 1;
1005 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001006
Christopher Faulet78f371e2020-04-30 09:38:08 +02001007 if (!buf_size || buf_size > max || buf_offset + buf_size > max) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001008 /* will never match */
1009 smp->flags = 0;
1010 return 0;
1011 }
1012
Christopher Faulet78f371e2020-04-30 09:38:08 +02001013 if (buf_offset + buf_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001014 goto too_short;
1015
1016 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001017 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001018 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001019 chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001020 return 1;
1021
1022 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001023 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001024 return 0;
1025}
1026
1027/* extracts some payload at a fixed position and length */
1028static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +02001029smp_fetch_payload(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001030{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001031 unsigned int buf_offset = arg_p[0].data.sint;
1032 unsigned int buf_size = arg_p[1].data.sint;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001033 struct channel *chn = NULL;
1034 char *head = NULL;
1035 size_t max, data;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001036
Christopher Faulet78f371e2020-04-30 09:38:08 +02001037 if (smp->strm) {
1038 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1039 head = ci_head(chn);
1040 data = ci_data(chn);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001041 }
Christopher Fauletf98e6262020-05-06 09:42:04 +02001042 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Faulet78f371e2020-04-30 09:38:08 +02001043 struct buffer *buf = &(__objt_check(smp->sess->origin)->bi);
1044 head = b_head(buf);
1045 data = b_data(buf);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001046 }
Christopher Fauletbb9fb8b2020-11-25 17:20:57 +01001047 max = global.tune.bufsize;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001048 if (!head)
Willy Tarreaube508f12016-03-10 11:47:01 +01001049 return 0;
1050
Christopher Faulet78f371e2020-04-30 09:38:08 +02001051 if (buf_size > max || buf_offset + buf_size > max) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001052 /* will never match */
1053 smp->flags = 0;
1054 return 0;
1055 }
Christopher Faulet78f371e2020-04-30 09:38:08 +02001056 if (buf_offset + buf_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001057 goto too_short;
1058
1059 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001060 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001061 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001062 chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size ? buf_size : (data - buf_offset));
1063
1064 if (!buf_size && chn && channel_may_recv(chn) && !channel_input_closed(chn))
Willy Tarreau00f00842013-08-02 11:07:32 +02001065 smp->flags |= SMP_F_MAY_CHANGE;
1066
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001067 return 1;
1068
Christopher Faulet78f371e2020-04-30 09:38:08 +02001069 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001070 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001071 return 0;
1072}
1073
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001074/* This function is used to validate the arguments passed to a "payload_lv" fetch
1075 * keyword. This keyword allows two positive integers and an optional signed one,
1076 * with the second one being strictly positive and the third one being greater than
1077 * the opposite of the two others if negative. It is assumed that the types are
1078 * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> is
1079 * not NULL, it will be filled with a pointer to an error message in case of
1080 * error, that the caller is responsible for freeing. The initial location must
1081 * either be freeable or NULL.
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001082 *
1083 * Note that offset2 is stored with SINT type, but its not directly usable as is.
1084 * The value is contained in the 63 MSB and the LSB is used as a flag for marking
1085 * the "relative" property of the value.
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001086 */
Thierry FOURNIER49f45af2014-12-08 19:50:43 +01001087int val_payload_lv(struct arg *arg, char **err_msg)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001088{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001089 int relative = 0;
1090 const char *str;
1091
1092 if (arg[0].data.sint < 0) {
1093 memprintf(err_msg, "payload offset1 must be positive");
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001094 return 0;
1095 }
1096
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001097 if (!arg[1].data.sint) {
1098 memprintf(err_msg, "payload length must be > 0");
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001099 return 0;
1100 }
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001101
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001102 if (arg[2].type == ARGT_STR && arg[2].data.str.data > 0) {
Christopher Faulet95917132020-08-05 23:07:07 +02001103 long long int i;
1104
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001105 if (arg[2].data.str.area[0] == '+' || arg[2].data.str.area[0] == '-')
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001106 relative = 1;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001107 str = arg[2].data.str.area;
Christopher Faulet95917132020-08-05 23:07:07 +02001108 i = read_int64(&str, str + arg[2].data.str.data);
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001109 if (*str != '\0') {
1110 memprintf(err_msg, "payload offset2 is not a number");
1111 return 0;
1112 }
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001113 chunk_destroy(&arg[2].data.str);
Christopher Faulet95917132020-08-05 23:07:07 +02001114 arg[2].type = ARGT_SINT;
1115 arg[2].data.sint = i;
1116
1117 if (arg[0].data.sint + arg[1].data.sint + arg[2].data.sint < 0) {
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001118 memprintf(err_msg, "payload offset2 too negative");
1119 return 0;
1120 }
1121 if (relative)
1122 arg[2].data.sint = ( arg[2].data.sint << 1 ) + 1;
1123 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001124 return 1;
1125}
1126
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001127/* extracts the parameter value of a distcc token */
1128static int
1129smp_fetch_distcc_param(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
1130{
1131 unsigned int match_tok = arg_p[0].data.sint;
1132 unsigned int match_occ = arg_p[1].data.sint;
1133 unsigned int token;
1134 unsigned int param;
1135 unsigned int body;
1136 unsigned int ofs;
1137 unsigned int occ;
1138 struct channel *chn;
1139 int i;
1140
1141 /* Format is (token[,occ]). occ starts at 1. */
1142
1143 if (!smp->strm)
1144 return 0;
1145
1146 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1147
1148 ofs = 0; occ = 0;
1149 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001150 if (ofs + 12 > ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001151 /* not there yet but could it at least fit ? */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001152 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001153 goto too_short;
1154
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001155 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001156 goto too_short;
1157
1158 goto no_match;
1159 }
1160
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001161 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001162 ofs += 4;
1163
1164 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001165 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001166
1167 if (c < 0)
1168 goto no_match;
1169 param = (param << 4) + c;
1170 }
1171 ofs += 8;
1172
1173 /* these tokens don't have a body */
1174 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1175 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1176 token != 0x444F4E45 /* DONE */)
1177 body = param;
1178 else
1179 body = 0;
1180
1181 if (token == match_tok) {
1182 occ++;
1183 if (!match_occ || match_occ == occ) {
1184 /* found */
1185 smp->data.type = SMP_T_SINT;
1186 smp->data.u.sint = param;
1187 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1188 return 1;
1189 }
1190 }
1191 ofs += body;
1192 }
1193
1194 too_short:
1195 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1196 return 0;
1197 no_match:
1198 /* will never match (end of buffer, or bad contents) */
1199 smp->flags = 0;
1200 return 0;
1201
1202}
1203
1204/* extracts the (possibly truncated) body of a distcc token */
1205static int
1206smp_fetch_distcc_body(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
1207{
1208 unsigned int match_tok = arg_p[0].data.sint;
1209 unsigned int match_occ = arg_p[1].data.sint;
1210 unsigned int token;
1211 unsigned int param;
1212 unsigned int ofs;
1213 unsigned int occ;
1214 unsigned int body;
1215 struct channel *chn;
1216 int i;
1217
1218 /* Format is (token[,occ]). occ starts at 1. */
1219
1220 if (!smp->strm)
1221 return 0;
1222
1223 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1224
1225 ofs = 0; occ = 0;
1226 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001227 if (ofs + 12 > ci_data(chn)) {
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001228 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001229 goto too_short;
1230
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001231 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001232 goto too_short;
1233
1234 goto no_match;
1235 }
1236
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001237 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001238 ofs += 4;
1239
1240 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001241 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001242
1243 if (c < 0)
1244 goto no_match;
1245 param = (param << 4) + c;
1246 }
1247 ofs += 8;
1248
1249 /* these tokens don't have a body */
1250 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1251 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1252 token != 0x444F4E45 /* DONE */)
1253 body = param;
1254 else
1255 body = 0;
1256
1257 if (token == match_tok) {
1258 occ++;
1259 if (!match_occ || match_occ == occ) {
1260 /* found */
1261
1262 smp->data.type = SMP_T_BIN;
1263 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1264
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001265 if (ofs + body > ci_head(chn) - b_orig(&chn->buf) + ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001266 /* incomplete body */
1267
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001268 if (ofs + body > channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001269 /* truncate it to whatever will fit */
1270 smp->flags |= SMP_F_MAY_CHANGE;
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001271 body = channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn) - ofs;
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001272 }
1273 }
1274
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001275 chunk_initlen(&smp->data.u.str, ci_head(chn) + ofs, 0, body);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001276 return 1;
1277 }
1278 }
1279 ofs += body;
1280 }
1281
1282 too_short:
1283 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1284 return 0;
1285 no_match:
1286 /* will never match (end of buffer, or bad contents) */
1287 smp->flags = 0;
1288 return 0;
1289
1290}
1291
1292/* This function is used to validate the arguments passed to a "distcc_param" or
1293 * "distcc_body" sample fetch keyword. They take a mandatory token name of exactly
1294 * 4 characters, followed by an optional occurrence number starting at 1. It is
1295 * assumed that the types are already the correct ones. Returns 0 on error, non-
1296 * zero if OK. If <err_msg> is not NULL, it will be filled with a pointer to an
1297 * error message in case of error, that the caller is responsible for freeing.
1298 * The initial location must either be freeable or NULL.
1299 */
1300int val_distcc(struct arg *arg, char **err_msg)
1301{
1302 unsigned int token;
1303
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001304 if (arg[0].data.str.data != 4) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001305 memprintf(err_msg, "token name must be exactly 4 characters");
1306 return 0;
1307 }
1308
1309 /* convert the token name to an unsigned int (one byte per character,
1310 * big endian format).
1311 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001312 token = (arg[0].data.str.area[0] << 24) + (arg[0].data.str.area[1] << 16) +
1313 (arg[0].data.str.area[2] << 8) + (arg[0].data.str.area[3] << 0);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001314
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001315 chunk_destroy(&arg[0].data.str);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001316 arg[0].type = ARGT_SINT;
1317 arg[0].data.sint = token;
1318
1319 if (arg[1].type != ARGT_SINT) {
1320 arg[1].type = ARGT_SINT;
1321 arg[1].data.sint = 0;
1322 }
1323 return 1;
1324}
1325
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001326/************************************************************************/
1327/* All supported sample and ACL keywords must be declared here. */
1328/************************************************************************/
1329
1330/* Note: must not be declared <const> as its list will be overwritten.
1331 * Note: fetches that may return multiple types must be declared as the lowest
1332 * common denominator, the type that can be casted into all other ones. For
1333 * instance IPv4/IPv6 must be declared IPv4.
1334 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001335static struct sample_fetch_kw_list smp_kws = {ILH, {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001336 { "distcc_body", smp_fetch_distcc_body, ARG2(1,STR,SINT), val_distcc, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1337 { "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 +02001338 { "payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1339 { "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 +01001340 { "rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001341 { "rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L6REQ },
1342 { "rep_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
1343 { "req_len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1344 { "req_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001345 { "req_ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001346 { "req_ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +01001347
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001348 { "req.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001349 { "req.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ },
1350 { "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 +01001351 { "req.rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001352 { "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 +02001353 { "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 +05301354 { "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 +02001355 { "req.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001356 { "req.ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Alex Zorin4afdd132018-12-30 13:56:28 +11001357 { "req.ssl_alpn", smp_fetch_ssl_hello_alpn, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001358 { "req.ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1359 { "res.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001360 { "res.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6RES },
1361 { "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 +02001362 { "res.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001363 { "wait_end", smp_fetch_wait_end, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
1364 { /* END */ },
1365}};
1366
Willy Tarreau0108d902018-11-25 19:14:37 +01001367INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001368
1369/* Note: must not be declared <const> as its list will be overwritten.
1370 * Please take care of keeping this list alphabetically sorted.
1371 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001372static struct acl_kw_list acl_kws = {ILH, {
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +01001373 { "payload", "req.payload", PAT_MATCH_BIN },
1374 { "payload_lv", "req.payload_lv", PAT_MATCH_BIN },
1375 { "req_rdp_cookie", "req.rdp_cookie", PAT_MATCH_STR },
1376 { "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", PAT_MATCH_INT },
1377 { "req_ssl_sni", "req.ssl_sni", PAT_MATCH_STR },
1378 { "req_ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
1379 { "req.ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001380 { /* END */ },
1381}};
1382
Willy Tarreau0108d902018-11-25 19:14:37 +01001383INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001384
1385/*
1386 * Local variables:
1387 * c-indent-level: 8
1388 * c-basic-offset: 8
1389 * End:
1390 */