blob: 7e66f04084407a9d1657fa8449aaabd3df090a6f [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>
Christopher Faulet1329f2a2021-12-16 17:32:56 +010021#include <haproxy/conn_stream.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020022#include <haproxy/htx.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020023#include <haproxy/net_helper.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +020024#include <haproxy/pattern.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020025#include <haproxy/payload.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020026#include <haproxy/sample.h>
Willy Tarreau485261b2021-05-08 13:55:40 +020027#include <haproxy/tools.h>
Willy Tarreaud4c33c82013-01-07 21:59:07 +010028
29
30/************************************************************************/
31/* All supported sample fetch functions must be declared here */
32/************************************************************************/
33
34/* wait for more data as long as possible, then return TRUE. This should be
35 * used with content inspection.
36 */
37static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020038smp_fetch_wait_end(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010039{
Thierry FOURNIER0786d052015-05-11 15:42:45 +020040 if (!(smp->opt & SMP_OPT_FINAL)) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +010041 smp->flags |= SMP_F_MAY_CHANGE;
42 return 0;
43 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020044 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020045 smp->data.u.sint = 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +010046 return 1;
47}
48
49/* return the number of bytes in the request buffer */
50static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020051smp_fetch_len(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010052{
Christopher Faulet78f371e2020-04-30 09:38:08 +020053 if (smp->strm) {
54 struct channel *chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Christopher Fauleta434a002021-03-25 11:58:51 +010055
56 /* Not accurate but kept for backward compatibility purpose */
Christopher Faulet78f371e2020-04-30 09:38:08 +020057 if (IS_HTX_STRM(smp->strm)) {
58 struct htx *htx = htxbuf(&chn->buf);
59 smp->data.u.sint = htx->data - co_data(chn);
60 }
61 else
62 smp->data.u.sint = ci_data(chn);
63 }
Christopher Fauletf98e6262020-05-06 09:42:04 +020064 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Faulet78f371e2020-04-30 09:38:08 +020065 struct check *check = __objt_check(smp->sess->origin);
Christopher Fauleta434a002021-03-25 11:58:51 +010066
67 /* Not accurate but kept for backward compatibility purpose */
Christopher Faulet78f371e2020-04-30 09:38:08 +020068 smp->data.u.sint = ((check->cs && IS_HTX_CS(check->cs)) ? (htxbuf(&check->bi))->data: b_data(&check->bi));
69 }
70 else
Willy Tarreaube508f12016-03-10 11:47:01 +010071 return 0;
72
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020073 smp->data.type = SMP_T_SINT;
Willy Tarreaud4c33c82013-01-07 21:59:07 +010074 smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
75 return 1;
76}
77
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053078/* Returns 0 if the client didn't send a SessionTicket Extension
79 * Returns 1 if the client sent SessionTicket Extension
80 * Returns 2 if the client also sent non-zero length SessionTicket
81 * Returns SMP_T_SINT data type
82 */
83static int
84smp_fetch_req_ssl_st_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
85{
86 int hs_len, ext_len, bleft;
87 struct channel *chn;
88 unsigned char *data;
89
Willy Tarreaube508f12016-03-10 11:47:01 +010090 if (!smp->strm)
91 goto not_ssl_hello;
92
Christopher Fauleta434a002021-03-25 11:58:51 +010093 /* meaningless for HTX buffers */
94 if (IS_HTX_STRM(smp->strm))
95 goto not_ssl_hello;
96
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053097 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Christopher Fauleta434a002021-03-25 11:58:51 +010098
99
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200100 bleft = ci_data(chn);
101 data = (unsigned char *)ci_head(chn);
Pradeep Jindalbb2acf52015-09-29 10:12:57 +0530102
103 /* Check for SSL/TLS Handshake */
104 if (!bleft)
105 goto too_short;
106 if (*data != 0x16)
107 goto not_ssl_hello;
108
109 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
110 if (bleft < 3)
111 goto too_short;
112 if (data[1] < 0x03)
113 goto not_ssl_hello;
114
115 if (bleft < 5)
116 goto too_short;
117 hs_len = (data[3] << 8) + data[4];
118 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
119 goto not_ssl_hello; /* too short to have an extension */
120
121 data += 5; /* enter TLS handshake */
122 bleft -= 5;
123
124 /* Check for a complete client hello starting at <data> */
125 if (bleft < 1)
126 goto too_short;
127 if (data[0] != 0x01) /* msg_type = Client Hello */
128 goto not_ssl_hello;
129
130 /* Check the Hello's length */
131 if (bleft < 4)
132 goto too_short;
133 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
134 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
135 goto not_ssl_hello; /* too short to have an extension */
136
137 /* We want the full handshake here */
138 if (bleft < hs_len)
139 goto too_short;
140
141 data += 4;
142 /* Start of the ClientHello message */
143 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
144 goto not_ssl_hello;
145
146 ext_len = data[34]; /* session_id_len */
147 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
148 goto not_ssl_hello;
149
150 /* Jump to cipher suite */
151 hs_len -= 35 + ext_len;
152 data += 35 + ext_len;
153
154 if (hs_len < 4 || /* minimum one cipher */
155 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
156 ext_len > hs_len)
157 goto not_ssl_hello;
158
159 /* Jump to the compression methods */
160 hs_len -= 2 + ext_len;
161 data += 2 + ext_len;
162
163 if (hs_len < 2 || /* minimum one compression method */
164 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
165 goto not_ssl_hello;
166
167 /* Jump to the extensions */
168 hs_len -= 1 + data[0];
169 data += 1 + data[0];
170
171 if (hs_len < 2 || /* minimum one extension list length */
172 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
173 goto not_ssl_hello;
174
175 hs_len = ext_len; /* limit ourselves to the extension length */
176 data += 2;
177
178 while (hs_len >= 4) {
179 int ext_type, ext_len;
180
181 ext_type = (data[0] << 8) + data[1];
182 ext_len = (data[2] << 8) + data[3];
183
184 if (ext_len > hs_len - 4) /* Extension too long */
185 goto not_ssl_hello;
186
187 /* SesstionTicket extension */
188 if (ext_type == 35) {
189 smp->data.type = SMP_T_SINT;
190 /* SessionTicket also present */
191 if (ext_len > 0)
192 smp->data.u.sint = 2;
193 /* SessionTicket absent */
194 else
195 smp->data.u.sint = 1;
196 smp->flags = SMP_F_VOLATILE;
197 return 1;
198 }
199
200 hs_len -= 4 + ext_len;
201 data += 4 + ext_len;
202 }
203 /* SessionTicket Extension not found */
204 smp->data.type = SMP_T_SINT;
205 smp->data.u.sint = 0;
206 smp->flags = SMP_F_VOLATILE;
207 return 1;
208
Pradeep Jindalbb2acf52015-09-29 10:12:57 +0530209 too_short:
210 smp->flags = SMP_F_MAY_CHANGE;
211
212 not_ssl_hello:
213 return 0;
214}
215
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200216/* Returns TRUE if the client sent Supported Elliptic Curves Extension (0x000a)
217 * Mainly used to detect if client supports ECC cipher suites.
218 */
219static int
220smp_fetch_req_ssl_ec_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
221{
222 int hs_len, ext_len, bleft;
223 struct channel *chn;
224 unsigned char *data;
225
Willy Tarreaube508f12016-03-10 11:47:01 +0100226 if (!smp->strm)
227 goto not_ssl_hello;
228
Christopher Fauleta434a002021-03-25 11:58:51 +0100229 /* meaningless for HTX buffers */
230 if (IS_HTX_STRM(smp->strm))
231 goto not_ssl_hello;
232
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200233 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200234 bleft = ci_data(chn);
235 data = (unsigned char *)ci_head(chn);
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200236
237 /* Check for SSL/TLS Handshake */
238 if (!bleft)
239 goto too_short;
240 if (*data != 0x16)
241 goto not_ssl_hello;
242
243 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
244 if (bleft < 3)
245 goto too_short;
246 if (data[1] < 0x03)
247 goto not_ssl_hello;
248
249 if (bleft < 5)
250 goto too_short;
251 hs_len = (data[3] << 8) + data[4];
252 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
253 goto not_ssl_hello; /* too short to have an extension */
254
255 data += 5; /* enter TLS handshake */
256 bleft -= 5;
257
258 /* Check for a complete client hello starting at <data> */
259 if (bleft < 1)
260 goto too_short;
261 if (data[0] != 0x01) /* msg_type = Client Hello */
262 goto not_ssl_hello;
263
264 /* Check the Hello's length */
265 if (bleft < 4)
266 goto too_short;
267 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
268 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
269 goto not_ssl_hello; /* too short to have an extension */
270
271 /* We want the full handshake here */
272 if (bleft < hs_len)
273 goto too_short;
274
275 data += 4;
276 /* Start of the ClientHello message */
277 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
278 goto not_ssl_hello;
279
280 ext_len = data[34]; /* session_id_len */
281 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
282 goto not_ssl_hello;
283
284 /* Jump to cipher suite */
285 hs_len -= 35 + ext_len;
286 data += 35 + ext_len;
287
288 if (hs_len < 4 || /* minimum one cipher */
289 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
290 ext_len > hs_len)
291 goto not_ssl_hello;
292
293 /* Jump to the compression methods */
294 hs_len -= 2 + ext_len;
295 data += 2 + ext_len;
296
297 if (hs_len < 2 || /* minimum one compression method */
298 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
299 goto not_ssl_hello;
300
301 /* Jump to the extensions */
302 hs_len -= 1 + data[0];
303 data += 1 + data[0];
304
305 if (hs_len < 2 || /* minimum one extension list length */
306 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
307 goto not_ssl_hello;
308
309 hs_len = ext_len; /* limit ourselves to the extension length */
310 data += 2;
311
312 while (hs_len >= 4) {
313 int ext_type, ext_len;
314
315 ext_type = (data[0] << 8) + data[1];
316 ext_len = (data[2] << 8) + data[3];
317
318 if (ext_len > hs_len - 4) /* Extension too long */
319 goto not_ssl_hello;
320
321 /* Elliptic curves extension */
322 if (ext_type == 10) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200323 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200324 smp->data.u.sint = 1;
Nenad Merdanovic8a39a1f2015-07-15 12:51:11 +0200325 smp->flags = SMP_F_VOLATILE;
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200326 return 1;
327 }
328
329 hs_len -= 4 + ext_len;
330 data += 4 + ext_len;
331 }
332 /* server name not found */
333 goto not_ssl_hello;
334
335 too_short:
336 smp->flags = SMP_F_MAY_CHANGE;
337
338 not_ssl_hello:
339
340 return 0;
341}
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100342/* returns the type of SSL hello message (mainly used to detect an SSL hello) */
343static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200344smp_fetch_ssl_hello_type(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100345{
346 int hs_len;
347 int hs_type, bleft;
348 struct channel *chn;
349 const unsigned char *data;
350
Willy Tarreaube508f12016-03-10 11:47:01 +0100351 if (!smp->strm)
352 goto not_ssl_hello;
353
Christopher Fauleta434a002021-03-25 11:58:51 +0100354 /* meaningless for HTX buffers */
355 if (IS_HTX_STRM(smp->strm))
356 goto not_ssl_hello;
357
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200358 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200359 bleft = ci_data(chn);
360 data = (const unsigned char *)ci_head(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100361
362 if (!bleft)
363 goto too_short;
364
365 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
366 /* SSLv3 header format */
367 if (bleft < 9)
368 goto too_short;
369
370 /* ssl version 3 */
371 if ((data[1] << 16) + data[2] < 0x00030000)
372 goto not_ssl_hello;
373
374 /* ssl message len must present handshake type and len */
375 if ((data[3] << 8) + data[4] < 4)
376 goto not_ssl_hello;
377
378 /* format introduced with SSLv3 */
379
380 hs_type = (int)data[5];
381 hs_len = ( data[6] << 16 ) + ( data[7] << 8 ) + data[8];
382
383 /* not a full handshake */
384 if (bleft < (9 + hs_len))
385 goto too_short;
386
387 }
388 else {
389 goto not_ssl_hello;
390 }
391
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200392 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200393 smp->data.u.sint = hs_type;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100394 smp->flags = SMP_F_VOLATILE;
395
396 return 1;
397
398 too_short:
399 smp->flags = SMP_F_MAY_CHANGE;
400
401 not_ssl_hello:
402
403 return 0;
404}
405
406/* Return the version of the SSL protocol in the request. It supports both
407 * SSLv3 (TLSv1) header format for any message, and SSLv2 header format for
408 * the hello message. The SSLv3 format is described in RFC 2246 p49, and the
409 * SSLv2 format is described here, and completed p67 of RFC 2246 :
410 * http://wp.netscape.com/eng/security/SSL_2.html
411 *
412 * Note: this decoder only works with non-wrapping data.
413 */
414static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200415smp_fetch_req_ssl_ver(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100416{
417 int version, bleft, msg_len;
418 const unsigned char *data;
Willy Tarreaube508f12016-03-10 11:47:01 +0100419 struct channel *req;
420
421 if (!smp->strm)
Christopher Fauleta434a002021-03-25 11:58:51 +0100422 goto not_ssl;
423
424 /* meaningless for HTX buffers */
425 if (IS_HTX_STRM(smp->strm))
426 goto not_ssl;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100427
Willy Tarreaube508f12016-03-10 11:47:01 +0100428 req = &smp->strm->req;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100429 msg_len = 0;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200430 bleft = ci_data(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100431 if (!bleft)
432 goto too_short;
433
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200434 data = (const unsigned char *)ci_head(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100435 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
436 /* SSLv3 header format */
Lukas Tribusc93242c2015-11-05 13:59:30 +0100437 if (bleft < 11)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100438 goto too_short;
439
Lukas Tribusc93242c2015-11-05 13:59:30 +0100440 version = (data[1] << 16) + data[2]; /* record layer version: major, minor */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100441 msg_len = (data[3] << 8) + data[4]; /* record length */
442
443 /* format introduced with SSLv3 */
444 if (version < 0x00030000)
445 goto not_ssl;
446
Lukas Tribusc93242c2015-11-05 13:59:30 +0100447 /* message length between 6 and 2^14 + 2048 */
448 if (msg_len < 6 || msg_len > ((1<<14) + 2048))
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100449 goto not_ssl;
450
451 bleft -= 5; data += 5;
Lukas Tribusc93242c2015-11-05 13:59:30 +0100452
453 /* return the client hello client version, not the record layer version */
454 version = (data[4] << 16) + data[5]; /* client hello version: major, minor */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100455 } else {
456 /* SSLv2 header format, only supported for hello (msg type 1) */
457 int rlen, plen, cilen, silen, chlen;
458
459 if (*data & 0x80) {
460 if (bleft < 3)
461 goto too_short;
462 /* short header format : 15 bits for length */
463 rlen = ((data[0] & 0x7F) << 8) | data[1];
464 plen = 0;
465 bleft -= 2; data += 2;
466 } else {
467 if (bleft < 4)
468 goto too_short;
469 /* long header format : 14 bits for length + pad length */
470 rlen = ((data[0] & 0x3F) << 8) | data[1];
471 plen = data[2];
Willy Tarreau74967f62016-08-30 14:39:46 +0200472 bleft -= 3; data += 3;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100473 }
474
475 if (*data != 0x01)
476 goto not_ssl;
477 bleft--; data++;
478
479 if (bleft < 8)
480 goto too_short;
481 version = (data[0] << 16) + data[1]; /* version: major, minor */
482 cilen = (data[2] << 8) + data[3]; /* cipher len, multiple of 3 */
483 silen = (data[4] << 8) + data[5]; /* session_id_len: 0 or 16 */
484 chlen = (data[6] << 8) + data[7]; /* 16<=challenge length<=32 */
485
486 bleft -= 8; data += 8;
487 if (cilen % 3 != 0)
488 goto not_ssl;
489 if (silen && silen != 16)
490 goto not_ssl;
491 if (chlen < 16 || chlen > 32)
492 goto not_ssl;
493 if (rlen != 9 + cilen + silen + chlen)
494 goto not_ssl;
495
496 /* focus on the remaining data length */
497 msg_len = cilen + silen + chlen + plen;
498 }
499 /* We could recursively check that the buffer ends exactly on an SSL
500 * fragment boundary and that a possible next segment is still SSL,
501 * but that's a bit pointless. However, we could still check that
502 * all the part of the request which fits in a buffer is already
503 * there.
504 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200505 if (msg_len > channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req))
506 msg_len = channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100507
508 if (bleft < msg_len)
509 goto too_short;
510
511 /* OK that's enough. We have at least the whole message, and we have
512 * the protocol version.
513 */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200514 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200515 smp->data.u.sint = version;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100516 smp->flags = SMP_F_VOLATILE;
517 return 1;
518
519 too_short:
520 smp->flags = SMP_F_MAY_CHANGE;
521 not_ssl:
522 return 0;
523}
524
525/* Try to extract the Server Name Indication that may be presented in a TLS
526 * client hello handshake message. The format of the message is the following
527 * (cf RFC5246 + RFC6066) :
528 * TLS frame :
529 * - uint8 type = 0x16 (Handshake)
530 * - uint16 version >= 0x0301 (TLSv1)
531 * - uint16 length (frame length)
532 * - TLS handshake :
533 * - uint8 msg_type = 0x01 (ClientHello)
534 * - uint24 length (handshake message length)
535 * - ClientHello :
536 * - uint16 client_version >= 0x0301 (TLSv1)
537 * - uint8 Random[32] (4 first ones are timestamp)
538 * - SessionID :
539 * - uint8 session_id_len (0..32) (SessionID len in bytes)
540 * - uint8 session_id[session_id_len]
541 * - CipherSuite :
542 * - uint16 cipher_len >= 2 (Cipher length in bytes)
543 * - uint16 ciphers[cipher_len/2]
544 * - CompressionMethod :
545 * - uint8 compression_len >= 1 (# of supported methods)
546 * - uint8 compression_methods[compression_len]
547 * - optional client_extension_len (in bytes)
548 * - optional sequence of ClientHelloExtensions (as many bytes as above):
549 * - uint16 extension_type = 0 for server_name
550 * - uint16 extension_len
551 * - opaque extension_data[extension_len]
552 * - uint16 server_name_list_len (# of bytes here)
553 * - opaque server_names[server_name_list_len bytes]
554 * - uint8 name_type = 0 for host_name
555 * - uint16 name_len
556 * - opaque hostname[name_len bytes]
557 */
558static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200559smp_fetch_ssl_hello_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100560{
561 int hs_len, ext_len, bleft;
562 struct channel *chn;
563 unsigned char *data;
564
Willy Tarreaube508f12016-03-10 11:47:01 +0100565 if (!smp->strm)
566 goto not_ssl_hello;
567
Christopher Fauleta434a002021-03-25 11:58:51 +0100568 /* meaningless for HTX buffers */
569 if (IS_HTX_STRM(smp->strm))
570 goto not_ssl_hello;
571
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200572 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200573 bleft = ci_data(chn);
574 data = (unsigned char *)ci_head(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100575
576 /* Check for SSL/TLS Handshake */
577 if (!bleft)
578 goto too_short;
579 if (*data != 0x16)
580 goto not_ssl_hello;
581
Lukas Tribus57d22972014-04-10 21:36:22 +0200582 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100583 if (bleft < 3)
584 goto too_short;
Lukas Tribus57d22972014-04-10 21:36:22 +0200585 if (data[1] < 0x03)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100586 goto not_ssl_hello;
587
588 if (bleft < 5)
589 goto too_short;
590 hs_len = (data[3] << 8) + data[4];
591 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
592 goto not_ssl_hello; /* too short to have an extension */
593
594 data += 5; /* enter TLS handshake */
595 bleft -= 5;
596
597 /* Check for a complete client hello starting at <data> */
598 if (bleft < 1)
599 goto too_short;
600 if (data[0] != 0x01) /* msg_type = Client Hello */
601 goto not_ssl_hello;
602
603 /* Check the Hello's length */
604 if (bleft < 4)
605 goto too_short;
606 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
607 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
608 goto not_ssl_hello; /* too short to have an extension */
609
610 /* We want the full handshake here */
611 if (bleft < hs_len)
612 goto too_short;
613
614 data += 4;
615 /* Start of the ClientHello message */
616 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
617 goto not_ssl_hello;
618
619 ext_len = data[34]; /* session_id_len */
620 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
621 goto not_ssl_hello;
622
623 /* Jump to cipher suite */
624 hs_len -= 35 + ext_len;
625 data += 35 + ext_len;
626
627 if (hs_len < 4 || /* minimum one cipher */
628 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
629 ext_len > hs_len)
630 goto not_ssl_hello;
631
632 /* Jump to the compression methods */
633 hs_len -= 2 + ext_len;
634 data += 2 + ext_len;
635
636 if (hs_len < 2 || /* minimum one compression method */
637 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
638 goto not_ssl_hello;
639
640 /* Jump to the extensions */
641 hs_len -= 1 + data[0];
642 data += 1 + data[0];
643
644 if (hs_len < 2 || /* minimum one extension list length */
645 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
646 goto not_ssl_hello;
647
648 hs_len = ext_len; /* limit ourselves to the extension length */
649 data += 2;
650
651 while (hs_len >= 4) {
652 int ext_type, name_type, srv_len, name_len;
653
654 ext_type = (data[0] << 8) + data[1];
655 ext_len = (data[2] << 8) + data[3];
656
657 if (ext_len > hs_len - 4) /* Extension too long */
658 goto not_ssl_hello;
659
660 if (ext_type == 0) { /* Server name */
661 if (ext_len < 2) /* need one list length */
662 goto not_ssl_hello;
663
664 srv_len = (data[4] << 8) + data[5];
665 if (srv_len < 4 || srv_len > hs_len - 6)
666 goto not_ssl_hello; /* at least 4 bytes per server name */
667
668 name_type = data[6];
669 name_len = (data[7] << 8) + data[8];
670
671 if (name_type == 0) { /* hostname */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200672 smp->data.type = SMP_T_STR;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200673 smp->data.u.str.area = (char *)data + 9;
674 smp->data.u.str.data = name_len;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100675 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100676 return 1;
677 }
678 }
679
680 hs_len -= 4 + ext_len;
681 data += 4 + ext_len;
682 }
683 /* server name not found */
684 goto not_ssl_hello;
685
686 too_short:
687 smp->flags = SMP_F_MAY_CHANGE;
688
689 not_ssl_hello:
690
691 return 0;
692}
693
Alex Zorin4afdd132018-12-30 13:56:28 +1100694/* Try to extract the Application-Layer Protocol Negotiation (ALPN) protocol
695 * names that may be presented in a TLS client hello handshake message. As the
696 * message presents a list of protocol names in descending order of preference,
697 * it may return iteratively. The format of the message is the following
698 * (cf RFC5246 + RFC7301) :
699 * TLS frame :
700 * - uint8 type = 0x16 (Handshake)
701 * - uint16 version >= 0x0301 (TLSv1)
702 * - uint16 length (frame length)
703 * - TLS handshake :
704 * - uint8 msg_type = 0x01 (ClientHello)
705 * - uint24 length (handshake message length)
706 * - ClientHello :
707 * - uint16 client_version >= 0x0301 (TLSv1)
708 * - uint8 Random[32] (4 first ones are timestamp)
709 * - SessionID :
710 * - uint8 session_id_len (0..32) (SessionID len in bytes)
711 * - uint8 session_id[session_id_len]
712 * - CipherSuite :
713 * - uint16 cipher_len >= 2 (Cipher length in bytes)
714 * - uint16 ciphers[cipher_len/2]
715 * - CompressionMethod :
716 * - uint8 compression_len >= 1 (# of supported methods)
717 * - uint8 compression_methods[compression_len]
718 * - optional client_extension_len (in bytes)
719 * - optional sequence of ClientHelloExtensions (as many bytes as above):
720 * - uint16 extension_type = 16 for application_layer_protocol_negotiation
721 * - uint16 extension_len
722 * - opaque extension_data[extension_len]
723 * - uint16 protocol_names_len (# of bytes here)
724 * - opaque protocol_names[protocol_names_len bytes]
725 * - uint8 name_len
726 * - opaque protocol_name[name_len bytes]
727 */
728static int
729smp_fetch_ssl_hello_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
730{
731 int hs_len, ext_len, bleft;
732 struct channel *chn;
733 unsigned char *data;
734
735 if (!smp->strm)
736 goto not_ssl_hello;
737
Christopher Fauleta434a002021-03-25 11:58:51 +0100738 /* meaningless for HTX buffers */
739 if (IS_HTX_STRM(smp->strm))
740 goto not_ssl_hello;
741
Alex Zorin4afdd132018-12-30 13:56:28 +1100742 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
743 bleft = ci_data(chn);
744 data = (unsigned char *)ci_head(chn);
745
746 /* Check for SSL/TLS Handshake */
747 if (!bleft)
748 goto too_short;
749 if (*data != 0x16)
750 goto not_ssl_hello;
751
752 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
753 if (bleft < 3)
754 goto too_short;
755 if (data[1] < 0x03)
756 goto not_ssl_hello;
757
758 if (bleft < 5)
759 goto too_short;
760 hs_len = (data[3] << 8) + data[4];
761 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
762 goto not_ssl_hello; /* too short to have an extension */
763
764 data += 5; /* enter TLS handshake */
765 bleft -= 5;
766
767 /* Check for a complete client hello starting at <data> */
768 if (bleft < 1)
769 goto too_short;
770 if (data[0] != 0x01) /* msg_type = Client Hello */
771 goto not_ssl_hello;
772
773 /* Check the Hello's length */
774 if (bleft < 4)
775 goto too_short;
776 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
777 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
778 goto not_ssl_hello; /* too short to have an extension */
779
780 /* We want the full handshake here */
781 if (bleft < hs_len)
782 goto too_short;
783
784 data += 4;
785 /* Start of the ClientHello message */
786 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
787 goto not_ssl_hello;
788
789 ext_len = data[34]; /* session_id_len */
790 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
791 goto not_ssl_hello;
792
793 /* Jump to cipher suite */
794 hs_len -= 35 + ext_len;
795 data += 35 + ext_len;
796
797 if (hs_len < 4 || /* minimum one cipher */
798 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
799 ext_len > hs_len)
800 goto not_ssl_hello;
801
802 /* Jump to the compression methods */
803 hs_len -= 2 + ext_len;
804 data += 2 + ext_len;
805
806 if (hs_len < 2 || /* minimum one compression method */
807 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
808 goto not_ssl_hello;
809
810 /* Jump to the extensions */
811 hs_len -= 1 + data[0];
812 data += 1 + data[0];
813
814 if (hs_len < 2 || /* minimum one extension list length */
815 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
816 goto not_ssl_hello;
817
818 hs_len = ext_len; /* limit ourselves to the extension length */
819 data += 2;
820
821 while (hs_len >= 4) {
822 int ext_type, name_len, name_offset;
823
824 ext_type = (data[0] << 8) + data[1];
825 ext_len = (data[2] << 8) + data[3];
826
827 if (ext_len > hs_len - 4) /* Extension too long */
828 goto not_ssl_hello;
829
830 if (ext_type == 16) { /* ALPN */
831 if (ext_len < 3) /* one list length [uint16] + at least one name length [uint8] */
832 goto not_ssl_hello;
833
834 /* Name cursor in ctx, must begin after protocol_names_len */
835 name_offset = smp->ctx.i < 6 ? 6 : smp->ctx.i;
836 name_len = data[name_offset];
837
838 if (name_len + name_offset - 3 > ext_len)
839 goto not_ssl_hello;
840
841 smp->data.type = SMP_T_STR;
842 smp->data.u.str.area = (char *)data + name_offset + 1; /* +1 to skip name_len */
843 smp->data.u.str.data = name_len;
844 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
845
846 /* May have more protocol names remaining */
847 if (name_len + name_offset - 3 < ext_len) {
848 smp->ctx.i = name_offset + name_len + 1;
849 smp->flags |= SMP_F_NOT_LAST;
850 }
851
852 return 1;
853 }
854
855 hs_len -= 4 + ext_len;
856 data += 4 + ext_len;
857 }
858 /* alpn not found */
859 goto not_ssl_hello;
860
861 too_short:
862 smp->flags = SMP_F_MAY_CHANGE;
863
864 not_ssl_hello:
865
866 return 0;
867}
868
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200869/* Fetch the request RDP cookie identified in <cname>:<clen>, or any cookie if
Willy Tarreaub169eba2013-12-16 15:14:43 +0100870 * <clen> is empty (cname is then ignored). It returns the data into sample <smp>
871 * of type SMP_T_CSTR. Note: this decoder only works with non-wrapping data.
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100872 */
873int
Willy Tarreau87b09662015-04-03 00:22:06 +0200874fetch_rdp_cookie_name(struct stream *s, struct sample *smp, const char *cname, int clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100875{
876 int bleft;
877 const unsigned char *data;
878
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100879 smp->flags = SMP_F_CONST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200880 smp->data.type = SMP_T_STR;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100881
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200882 bleft = ci_data(&s->req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100883 if (bleft <= 11)
884 goto too_short;
885
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200886 data = (const unsigned char *)ci_head(&s->req) + 11;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100887 bleft -= 11;
888
889 if (bleft <= 7)
890 goto too_short;
891
892 if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
893 goto not_cookie;
894
895 data += 7;
896 bleft -= 7;
897
898 while (bleft > 0 && *data == ' ') {
899 data++;
900 bleft--;
901 }
902
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200903 if (clen) {
904 if (bleft <= clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100905 goto too_short;
906
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200907 if ((data[clen] != '=') ||
908 strncasecmp(cname, (const char *)data, clen) != 0)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100909 goto not_cookie;
910
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200911 data += clen + 1;
912 bleft -= clen + 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100913 } else {
914 while (bleft > 0 && *data != '=') {
915 if (*data == '\r' || *data == '\n')
916 goto not_cookie;
917 data++;
918 bleft--;
919 }
920
921 if (bleft < 1)
922 goto too_short;
923
924 if (*data != '=')
925 goto not_cookie;
926
927 data++;
928 bleft--;
929 }
930
931 /* data points to cookie value */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200932 smp->data.u.str.area = (char *)data;
933 smp->data.u.str.data = 0;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100934
935 while (bleft > 0 && *data != '\r') {
936 data++;
937 bleft--;
938 }
939
940 if (bleft < 2)
941 goto too_short;
942
943 if (data[0] != '\r' || data[1] != '\n')
944 goto not_cookie;
945
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200946 smp->data.u.str.data = (char *)data - smp->data.u.str.area;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100947 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100948 return 1;
949
950 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100951 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100952 not_cookie:
953 return 0;
954}
955
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200956/* Fetch the request RDP cookie identified in the args, or any cookie if no arg
957 * is passed. It is usable both for ACL and for samples. Note: this decoder
958 * only works with non-wrapping data. Accepts either 0 or 1 argument. Argument
Willy Tarreaub169eba2013-12-16 15:14:43 +0100959 * is a string (cookie name), other types will lead to undefined behaviour. The
960 * returned sample has type SMP_T_CSTR.
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200961 */
962int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200963smp_fetch_rdp_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200964{
Willy Tarreaube508f12016-03-10 11:47:01 +0100965 if (!smp->strm)
966 return 0;
967
Christopher Fauleta434a002021-03-25 11:58:51 +0100968 /* meaningless for HTX buffers */
969 if (IS_HTX_STRM(smp->strm))
970 return 0;
971
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200972 return fetch_rdp_cookie_name(smp->strm, smp,
973 args ? args->data.str.area : NULL,
974 args ? args->data.str.data : 0);
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200975}
976
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100977/* returns either 1 or 0 depending on whether an RDP cookie is found or not */
978static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200979smp_fetch_rdp_cookie_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100980{
981 int ret;
982
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200983 ret = smp_fetch_rdp_cookie(args, smp, kw, private);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100984
985 if (smp->flags & SMP_F_MAY_CHANGE)
986 return 0;
987
988 smp->flags = SMP_F_VOLATILE;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200989 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200990 smp->data.u.sint = ret;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100991 return 1;
992}
993
994/* extracts part of a payload with offset and length at a given position */
995static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200996smp_fetch_payload_lv(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100997{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200998 unsigned int len_offset = arg_p[0].data.sint;
999 unsigned int len_size = arg_p[1].data.sint;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001000 unsigned int buf_offset;
1001 unsigned int buf_size = 0;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001002 struct channel *chn = NULL;
1003 char *head = NULL;
1004 size_t max, data;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001005 int i;
1006
1007 /* Format is (len offset, len size, buf offset) or (len offset, len size) */
1008 /* by default buf offset == len offset + len size */
1009 /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
1010
Christopher Faulet78f371e2020-04-30 09:38:08 +02001011 if (smp->strm) {
Christopher Fauleta434a002021-03-25 11:58:51 +01001012 /* meaningless for HTX buffers */
1013 if (IS_HTX_STRM(smp->strm))
1014 return 0;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001015 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1016 head = ci_head(chn);
1017 data = ci_data(chn);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001018 }
Christopher Fauletf98e6262020-05-06 09:42:04 +02001019 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Fauleta434a002021-03-25 11:58:51 +01001020 struct check *check = __objt_check(smp->sess->origin);
1021
1022 /* meaningless for HTX buffers */
1023 if (check->cs && IS_HTX_CS(check->cs))
1024 return 0;
1025 head = b_head(&check->bi);
1026 data = b_data(&check->bi);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001027 }
Christopher Fauletbb9fb8b2020-11-25 17:20:57 +01001028 max = global.tune.bufsize;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001029 if (!head)
Christopher Faulet50623022021-03-29 11:09:45 +02001030 goto too_short;
Willy Tarreaube508f12016-03-10 11:47:01 +01001031
Christopher Faulet78f371e2020-04-30 09:38:08 +02001032 if (len_offset + len_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001033 goto too_short;
1034
1035 for (i = 0; i < len_size; i++) {
Christopher Faulet78f371e2020-04-30 09:38:08 +02001036 buf_size = (buf_size << 8) + ((unsigned char *)head)[i + len_offset];
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001037 }
1038
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001039 /* buf offset may be implicit, absolute or relative. If the LSB
1040 * is set, then the offset is relative otherwise it is absolute.
1041 */
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001042 buf_offset = len_offset + len_size;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001043 if (arg_p[2].type == ARGT_SINT) {
1044 if (arg_p[2].data.sint & 1)
1045 buf_offset += arg_p[2].data.sint >> 1;
1046 else
1047 buf_offset = arg_p[2].data.sint >> 1;
1048 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001049
Christopher Faulet78f371e2020-04-30 09:38:08 +02001050 if (!buf_size || buf_size > max || buf_offset + buf_size > max) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001051 /* will never match */
1052 smp->flags = 0;
1053 return 0;
1054 }
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);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001063 return 1;
1064
1065 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001066 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001067 return 0;
1068}
1069
1070/* extracts some payload at a fixed position and length */
1071static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +02001072smp_fetch_payload(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001073{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001074 unsigned int buf_offset = arg_p[0].data.sint;
1075 unsigned int buf_size = arg_p[1].data.sint;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001076 struct channel *chn = NULL;
1077 char *head = NULL;
1078 size_t max, data;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001079
Christopher Faulet78f371e2020-04-30 09:38:08 +02001080 if (smp->strm) {
Christopher Fauleta434a002021-03-25 11:58:51 +01001081 /* meaningless for HTX buffers */
1082 if (IS_HTX_STRM(smp->strm))
1083 return 0;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001084 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1085 head = ci_head(chn);
1086 data = ci_data(chn);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001087 }
Christopher Fauletf98e6262020-05-06 09:42:04 +02001088 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Fauleta434a002021-03-25 11:58:51 +01001089 struct check *check = __objt_check(smp->sess->origin);
1090
1091 /* meaningless for HTX buffers */
1092 if (check->cs && IS_HTX_CS(check->cs))
1093 return 0;
1094 head = b_head(&check->bi);
1095 data = b_data(&check->bi);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001096 }
Christopher Fauletbb9fb8b2020-11-25 17:20:57 +01001097 max = global.tune.bufsize;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001098 if (!head)
Christopher Faulet50623022021-03-29 11:09:45 +02001099 goto too_short;
Willy Tarreaube508f12016-03-10 11:47:01 +01001100
Christopher Faulet78f371e2020-04-30 09:38:08 +02001101 if (buf_size > max || buf_offset + buf_size > max) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001102 /* will never match */
1103 smp->flags = 0;
1104 return 0;
1105 }
Christopher Faulet78f371e2020-04-30 09:38:08 +02001106 if (buf_offset + buf_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001107 goto too_short;
1108
1109 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001110 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001111 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001112 chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size ? buf_size : (data - buf_offset));
1113
1114 if (!buf_size && chn && channel_may_recv(chn) && !channel_input_closed(chn))
Willy Tarreau00f00842013-08-02 11:07:32 +02001115 smp->flags |= SMP_F_MAY_CHANGE;
1116
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001117 return 1;
1118
Christopher Faulet78f371e2020-04-30 09:38:08 +02001119 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001120 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001121 return 0;
1122}
1123
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001124/* This function is used to validate the arguments passed to a "payload_lv" fetch
1125 * keyword. This keyword allows two positive integers and an optional signed one,
1126 * with the second one being strictly positive and the third one being greater than
1127 * the opposite of the two others if negative. It is assumed that the types are
1128 * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> is
1129 * not NULL, it will be filled with a pointer to an error message in case of
1130 * error, that the caller is responsible for freeing. The initial location must
1131 * either be freeable or NULL.
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001132 *
1133 * Note that offset2 is stored with SINT type, but its not directly usable as is.
1134 * The value is contained in the 63 MSB and the LSB is used as a flag for marking
1135 * the "relative" property of the value.
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001136 */
Thierry FOURNIER49f45af2014-12-08 19:50:43 +01001137int val_payload_lv(struct arg *arg, char **err_msg)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001138{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001139 int relative = 0;
1140 const char *str;
1141
1142 if (arg[0].data.sint < 0) {
1143 memprintf(err_msg, "payload offset1 must be positive");
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001144 return 0;
1145 }
1146
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001147 if (!arg[1].data.sint) {
1148 memprintf(err_msg, "payload length must be > 0");
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001149 return 0;
1150 }
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001151
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001152 if (arg[2].type == ARGT_STR && arg[2].data.str.data > 0) {
Christopher Faulet95917132020-08-05 23:07:07 +02001153 long long int i;
1154
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001155 if (arg[2].data.str.area[0] == '+' || arg[2].data.str.area[0] == '-')
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001156 relative = 1;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001157 str = arg[2].data.str.area;
Christopher Faulet95917132020-08-05 23:07:07 +02001158 i = read_int64(&str, str + arg[2].data.str.data);
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001159 if (*str != '\0') {
1160 memprintf(err_msg, "payload offset2 is not a number");
1161 return 0;
1162 }
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001163 chunk_destroy(&arg[2].data.str);
Christopher Faulet95917132020-08-05 23:07:07 +02001164 arg[2].type = ARGT_SINT;
1165 arg[2].data.sint = i;
1166
1167 if (arg[0].data.sint + arg[1].data.sint + arg[2].data.sint < 0) {
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001168 memprintf(err_msg, "payload offset2 too negative");
1169 return 0;
1170 }
1171 if (relative)
1172 arg[2].data.sint = ( arg[2].data.sint << 1 ) + 1;
1173 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001174 return 1;
1175}
1176
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001177/* extracts the parameter value of a distcc token */
1178static int
1179smp_fetch_distcc_param(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
1180{
1181 unsigned int match_tok = arg_p[0].data.sint;
1182 unsigned int match_occ = arg_p[1].data.sint;
1183 unsigned int token;
1184 unsigned int param;
1185 unsigned int body;
1186 unsigned int ofs;
1187 unsigned int occ;
1188 struct channel *chn;
1189 int i;
1190
1191 /* Format is (token[,occ]). occ starts at 1. */
1192
1193 if (!smp->strm)
1194 return 0;
1195
Christopher Fauleta434a002021-03-25 11:58:51 +01001196 /* meaningless for HTX buffers */
1197 if (IS_HTX_STRM(smp->strm))
1198 return 0;
1199
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001200 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1201
1202 ofs = 0; occ = 0;
1203 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001204 if (ofs + 12 > ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001205 /* not there yet but could it at least fit ? */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001206 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001207 goto too_short;
1208
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001209 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001210 goto too_short;
1211
1212 goto no_match;
1213 }
1214
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001215 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001216 ofs += 4;
1217
1218 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001219 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001220
1221 if (c < 0)
1222 goto no_match;
1223 param = (param << 4) + c;
1224 }
1225 ofs += 8;
1226
1227 /* these tokens don't have a body */
1228 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1229 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1230 token != 0x444F4E45 /* DONE */)
1231 body = param;
1232 else
1233 body = 0;
1234
1235 if (token == match_tok) {
1236 occ++;
1237 if (!match_occ || match_occ == occ) {
1238 /* found */
1239 smp->data.type = SMP_T_SINT;
1240 smp->data.u.sint = param;
1241 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1242 return 1;
1243 }
1244 }
1245 ofs += body;
1246 }
1247
1248 too_short:
1249 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1250 return 0;
1251 no_match:
1252 /* will never match (end of buffer, or bad contents) */
1253 smp->flags = 0;
1254 return 0;
1255
1256}
1257
1258/* extracts the (possibly truncated) body of a distcc token */
1259static int
1260smp_fetch_distcc_body(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
1261{
1262 unsigned int match_tok = arg_p[0].data.sint;
1263 unsigned int match_occ = arg_p[1].data.sint;
1264 unsigned int token;
1265 unsigned int param;
1266 unsigned int ofs;
1267 unsigned int occ;
1268 unsigned int body;
1269 struct channel *chn;
1270 int i;
1271
1272 /* Format is (token[,occ]). occ starts at 1. */
1273
1274 if (!smp->strm)
1275 return 0;
1276
Christopher Fauleta434a002021-03-25 11:58:51 +01001277 /* meaningless for HTX buffers */
1278 if (IS_HTX_STRM(smp->strm))
1279 return 0;
1280
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001281 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1282
1283 ofs = 0; occ = 0;
1284 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001285 if (ofs + 12 > ci_data(chn)) {
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001286 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001287 goto too_short;
1288
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001289 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001290 goto too_short;
1291
1292 goto no_match;
1293 }
1294
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001295 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001296 ofs += 4;
1297
1298 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001299 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001300
1301 if (c < 0)
1302 goto no_match;
1303 param = (param << 4) + c;
1304 }
1305 ofs += 8;
1306
1307 /* these tokens don't have a body */
1308 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1309 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1310 token != 0x444F4E45 /* DONE */)
1311 body = param;
1312 else
1313 body = 0;
1314
1315 if (token == match_tok) {
1316 occ++;
1317 if (!match_occ || match_occ == occ) {
1318 /* found */
1319
1320 smp->data.type = SMP_T_BIN;
1321 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1322
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001323 if (ofs + body > ci_head(chn) - b_orig(&chn->buf) + ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001324 /* incomplete body */
1325
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001326 if (ofs + body > channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001327 /* truncate it to whatever will fit */
1328 smp->flags |= SMP_F_MAY_CHANGE;
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001329 body = channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn) - ofs;
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001330 }
1331 }
1332
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001333 chunk_initlen(&smp->data.u.str, ci_head(chn) + ofs, 0, body);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001334 return 1;
1335 }
1336 }
1337 ofs += body;
1338 }
1339
1340 too_short:
1341 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1342 return 0;
1343 no_match:
1344 /* will never match (end of buffer, or bad contents) */
1345 smp->flags = 0;
1346 return 0;
1347
1348}
1349
1350/* This function is used to validate the arguments passed to a "distcc_param" or
1351 * "distcc_body" sample fetch keyword. They take a mandatory token name of exactly
1352 * 4 characters, followed by an optional occurrence number starting at 1. It is
1353 * assumed that the types are already the correct ones. Returns 0 on error, non-
1354 * zero if OK. If <err_msg> is not NULL, it will be filled with a pointer to an
1355 * error message in case of error, that the caller is responsible for freeing.
1356 * The initial location must either be freeable or NULL.
1357 */
1358int val_distcc(struct arg *arg, char **err_msg)
1359{
1360 unsigned int token;
1361
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001362 if (arg[0].data.str.data != 4) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001363 memprintf(err_msg, "token name must be exactly 4 characters");
1364 return 0;
1365 }
1366
1367 /* convert the token name to an unsigned int (one byte per character,
1368 * big endian format).
1369 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001370 token = (arg[0].data.str.area[0] << 24) + (arg[0].data.str.area[1] << 16) +
1371 (arg[0].data.str.area[2] << 8) + (arg[0].data.str.area[3] << 0);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001372
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001373 chunk_destroy(&arg[0].data.str);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001374 arg[0].type = ARGT_SINT;
1375 arg[0].data.sint = token;
1376
1377 if (arg[1].type != ARGT_SINT) {
1378 arg[1].type = ARGT_SINT;
1379 arg[1].data.sint = 0;
1380 }
1381 return 1;
1382}
1383
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001384/************************************************************************/
1385/* All supported sample and ACL keywords must be declared here. */
1386/************************************************************************/
1387
1388/* Note: must not be declared <const> as its list will be overwritten.
1389 * Note: fetches that may return multiple types must be declared as the lowest
1390 * common denominator, the type that can be casted into all other ones. For
1391 * instance IPv4/IPv6 must be declared IPv4.
1392 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001393static struct sample_fetch_kw_list smp_kws = {ILH, {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001394 { "distcc_body", smp_fetch_distcc_body, ARG2(1,STR,SINT), val_distcc, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1395 { "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 +02001396 { "payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1397 { "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 +01001398 { "rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001399 { "rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L6REQ },
1400 { "rep_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
1401 { "req_len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1402 { "req_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001403 { "req_ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001404 { "req_ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +01001405
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001406 { "req.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001407 { "req.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ },
1408 { "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 +01001409 { "req.rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001410 { "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 +02001411 { "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 +05301412 { "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 +02001413 { "req.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001414 { "req.ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Alex Zorin4afdd132018-12-30 13:56:28 +11001415 { "req.ssl_alpn", smp_fetch_ssl_hello_alpn, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001416 { "req.ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1417 { "res.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001418 { "res.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6RES },
1419 { "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 +02001420 { "res.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001421 { "wait_end", smp_fetch_wait_end, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
1422 { /* END */ },
1423}};
1424
Willy Tarreau0108d902018-11-25 19:14:37 +01001425INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001426
1427/* Note: must not be declared <const> as its list will be overwritten.
1428 * Please take care of keeping this list alphabetically sorted.
1429 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001430static struct acl_kw_list acl_kws = {ILH, {
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +01001431 { "payload", "req.payload", PAT_MATCH_BIN },
1432 { "payload_lv", "req.payload_lv", PAT_MATCH_BIN },
1433 { "req_rdp_cookie", "req.rdp_cookie", PAT_MATCH_STR },
1434 { "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", PAT_MATCH_INT },
1435 { "req_ssl_sni", "req.ssl_sni", PAT_MATCH_STR },
1436 { "req_ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
1437 { "req.ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001438 { /* END */ },
1439}};
1440
Willy Tarreau0108d902018-11-25 19:14:37 +01001441INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001442
1443/*
1444 * Local variables:
1445 * c-indent-level: 8
1446 * c-basic-offset: 8
1447 * End:
1448 */