blob: 32e5456e62a0f3320c210f4d18ab8607121a0c1b [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;
Christopher Fauleta434a002021-03-25 11:58:51 +010053
54 /* Not accurate but kept for backward compatibility purpose */
Christopher Faulet78f371e2020-04-30 09:38:08 +020055 if (IS_HTX_STRM(smp->strm)) {
56 struct htx *htx = htxbuf(&chn->buf);
57 smp->data.u.sint = htx->data - co_data(chn);
58 }
59 else
60 smp->data.u.sint = ci_data(chn);
61 }
Christopher Fauletf98e6262020-05-06 09:42:04 +020062 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Faulet78f371e2020-04-30 09:38:08 +020063 struct check *check = __objt_check(smp->sess->origin);
Christopher Fauleta434a002021-03-25 11:58:51 +010064
65 /* Not accurate but kept for backward compatibility purpose */
Christopher Faulet78f371e2020-04-30 09:38:08 +020066 smp->data.u.sint = ((check->cs && IS_HTX_CS(check->cs)) ? (htxbuf(&check->bi))->data: b_data(&check->bi));
67 }
68 else
Willy Tarreaube508f12016-03-10 11:47:01 +010069 return 0;
70
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020071 smp->data.type = SMP_T_SINT;
Willy Tarreaud4c33c82013-01-07 21:59:07 +010072 smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
73 return 1;
74}
75
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053076/* Returns 0 if the client didn't send a SessionTicket Extension
77 * Returns 1 if the client sent SessionTicket Extension
78 * Returns 2 if the client also sent non-zero length SessionTicket
79 * Returns SMP_T_SINT data type
80 */
81static int
82smp_fetch_req_ssl_st_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
83{
84 int hs_len, ext_len, bleft;
85 struct channel *chn;
86 unsigned char *data;
87
Willy Tarreaube508f12016-03-10 11:47:01 +010088 if (!smp->strm)
89 goto not_ssl_hello;
90
Christopher Fauleta434a002021-03-25 11:58:51 +010091 /* meaningless for HTX buffers */
92 if (IS_HTX_STRM(smp->strm))
93 goto not_ssl_hello;
94
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053095 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Christopher Fauleta434a002021-03-25 11:58:51 +010096
97
Willy Tarreaufc0785d2018-06-19 07:19:56 +020098 bleft = ci_data(chn);
99 data = (unsigned char *)ci_head(chn);
Pradeep Jindalbb2acf52015-09-29 10:12:57 +0530100
101 /* Check for SSL/TLS Handshake */
102 if (!bleft)
103 goto too_short;
104 if (*data != 0x16)
105 goto not_ssl_hello;
106
107 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
108 if (bleft < 3)
109 goto too_short;
110 if (data[1] < 0x03)
111 goto not_ssl_hello;
112
113 if (bleft < 5)
114 goto too_short;
115 hs_len = (data[3] << 8) + data[4];
116 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
117 goto not_ssl_hello; /* too short to have an extension */
118
119 data += 5; /* enter TLS handshake */
120 bleft -= 5;
121
122 /* Check for a complete client hello starting at <data> */
123 if (bleft < 1)
124 goto too_short;
125 if (data[0] != 0x01) /* msg_type = Client Hello */
126 goto not_ssl_hello;
127
128 /* Check the Hello's length */
129 if (bleft < 4)
130 goto too_short;
131 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
132 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
133 goto not_ssl_hello; /* too short to have an extension */
134
135 /* We want the full handshake here */
136 if (bleft < hs_len)
137 goto too_short;
138
139 data += 4;
140 /* Start of the ClientHello message */
141 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
142 goto not_ssl_hello;
143
144 ext_len = data[34]; /* session_id_len */
145 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
146 goto not_ssl_hello;
147
148 /* Jump to cipher suite */
149 hs_len -= 35 + ext_len;
150 data += 35 + ext_len;
151
152 if (hs_len < 4 || /* minimum one cipher */
153 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
154 ext_len > hs_len)
155 goto not_ssl_hello;
156
157 /* Jump to the compression methods */
158 hs_len -= 2 + ext_len;
159 data += 2 + ext_len;
160
161 if (hs_len < 2 || /* minimum one compression method */
162 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
163 goto not_ssl_hello;
164
165 /* Jump to the extensions */
166 hs_len -= 1 + data[0];
167 data += 1 + data[0];
168
169 if (hs_len < 2 || /* minimum one extension list length */
170 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
171 goto not_ssl_hello;
172
173 hs_len = ext_len; /* limit ourselves to the extension length */
174 data += 2;
175
176 while (hs_len >= 4) {
177 int ext_type, ext_len;
178
179 ext_type = (data[0] << 8) + data[1];
180 ext_len = (data[2] << 8) + data[3];
181
182 if (ext_len > hs_len - 4) /* Extension too long */
183 goto not_ssl_hello;
184
185 /* SesstionTicket extension */
186 if (ext_type == 35) {
187 smp->data.type = SMP_T_SINT;
188 /* SessionTicket also present */
189 if (ext_len > 0)
190 smp->data.u.sint = 2;
191 /* SessionTicket absent */
192 else
193 smp->data.u.sint = 1;
194 smp->flags = SMP_F_VOLATILE;
195 return 1;
196 }
197
198 hs_len -= 4 + ext_len;
199 data += 4 + ext_len;
200 }
201 /* SessionTicket Extension not found */
202 smp->data.type = SMP_T_SINT;
203 smp->data.u.sint = 0;
204 smp->flags = SMP_F_VOLATILE;
205 return 1;
206
Pradeep Jindalbb2acf52015-09-29 10:12:57 +0530207 too_short:
208 smp->flags = SMP_F_MAY_CHANGE;
209
210 not_ssl_hello:
211 return 0;
212}
213
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200214/* Returns TRUE if the client sent Supported Elliptic Curves Extension (0x000a)
215 * Mainly used to detect if client supports ECC cipher suites.
216 */
217static int
218smp_fetch_req_ssl_ec_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
219{
220 int hs_len, ext_len, bleft;
221 struct channel *chn;
222 unsigned char *data;
223
Willy Tarreaube508f12016-03-10 11:47:01 +0100224 if (!smp->strm)
225 goto not_ssl_hello;
226
Christopher Fauleta434a002021-03-25 11:58:51 +0100227 /* meaningless for HTX buffers */
228 if (IS_HTX_STRM(smp->strm))
229 goto not_ssl_hello;
230
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200231 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200232 bleft = ci_data(chn);
233 data = (unsigned char *)ci_head(chn);
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200234
235 /* Check for SSL/TLS Handshake */
236 if (!bleft)
237 goto too_short;
238 if (*data != 0x16)
239 goto not_ssl_hello;
240
241 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
242 if (bleft < 3)
243 goto too_short;
244 if (data[1] < 0x03)
245 goto not_ssl_hello;
246
247 if (bleft < 5)
248 goto too_short;
249 hs_len = (data[3] << 8) + data[4];
250 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
251 goto not_ssl_hello; /* too short to have an extension */
252
253 data += 5; /* enter TLS handshake */
254 bleft -= 5;
255
256 /* Check for a complete client hello starting at <data> */
257 if (bleft < 1)
258 goto too_short;
259 if (data[0] != 0x01) /* msg_type = Client Hello */
260 goto not_ssl_hello;
261
262 /* Check the Hello's length */
263 if (bleft < 4)
264 goto too_short;
265 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
266 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
267 goto not_ssl_hello; /* too short to have an extension */
268
269 /* We want the full handshake here */
270 if (bleft < hs_len)
271 goto too_short;
272
273 data += 4;
274 /* Start of the ClientHello message */
275 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
276 goto not_ssl_hello;
277
278 ext_len = data[34]; /* session_id_len */
279 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
280 goto not_ssl_hello;
281
282 /* Jump to cipher suite */
283 hs_len -= 35 + ext_len;
284 data += 35 + ext_len;
285
286 if (hs_len < 4 || /* minimum one cipher */
287 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
288 ext_len > hs_len)
289 goto not_ssl_hello;
290
291 /* Jump to the compression methods */
292 hs_len -= 2 + ext_len;
293 data += 2 + ext_len;
294
295 if (hs_len < 2 || /* minimum one compression method */
296 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
297 goto not_ssl_hello;
298
299 /* Jump to the extensions */
300 hs_len -= 1 + data[0];
301 data += 1 + data[0];
302
303 if (hs_len < 2 || /* minimum one extension list length */
304 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
305 goto not_ssl_hello;
306
307 hs_len = ext_len; /* limit ourselves to the extension length */
308 data += 2;
309
310 while (hs_len >= 4) {
311 int ext_type, ext_len;
312
313 ext_type = (data[0] << 8) + data[1];
314 ext_len = (data[2] << 8) + data[3];
315
316 if (ext_len > hs_len - 4) /* Extension too long */
317 goto not_ssl_hello;
318
319 /* Elliptic curves extension */
320 if (ext_type == 10) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200321 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200322 smp->data.u.sint = 1;
Nenad Merdanovic8a39a1f2015-07-15 12:51:11 +0200323 smp->flags = SMP_F_VOLATILE;
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200324 return 1;
325 }
326
327 hs_len -= 4 + ext_len;
328 data += 4 + ext_len;
329 }
330 /* server name not found */
331 goto not_ssl_hello;
332
333 too_short:
334 smp->flags = SMP_F_MAY_CHANGE;
335
336 not_ssl_hello:
337
338 return 0;
339}
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100340/* returns the type of SSL hello message (mainly used to detect an SSL hello) */
341static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200342smp_fetch_ssl_hello_type(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100343{
344 int hs_len;
345 int hs_type, bleft;
346 struct channel *chn;
347 const unsigned char *data;
348
Willy Tarreaube508f12016-03-10 11:47:01 +0100349 if (!smp->strm)
350 goto not_ssl_hello;
351
Christopher Fauleta434a002021-03-25 11:58:51 +0100352 /* meaningless for HTX buffers */
353 if (IS_HTX_STRM(smp->strm))
354 goto not_ssl_hello;
355
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200356 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200357 bleft = ci_data(chn);
358 data = (const unsigned char *)ci_head(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100359
360 if (!bleft)
361 goto too_short;
362
363 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
364 /* SSLv3 header format */
365 if (bleft < 9)
366 goto too_short;
367
368 /* ssl version 3 */
369 if ((data[1] << 16) + data[2] < 0x00030000)
370 goto not_ssl_hello;
371
372 /* ssl message len must present handshake type and len */
373 if ((data[3] << 8) + data[4] < 4)
374 goto not_ssl_hello;
375
376 /* format introduced with SSLv3 */
377
378 hs_type = (int)data[5];
379 hs_len = ( data[6] << 16 ) + ( data[7] << 8 ) + data[8];
380
381 /* not a full handshake */
382 if (bleft < (9 + hs_len))
383 goto too_short;
384
385 }
386 else {
387 goto not_ssl_hello;
388 }
389
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200390 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200391 smp->data.u.sint = hs_type;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100392 smp->flags = SMP_F_VOLATILE;
393
394 return 1;
395
396 too_short:
397 smp->flags = SMP_F_MAY_CHANGE;
398
399 not_ssl_hello:
400
401 return 0;
402}
403
404/* Return the version of the SSL protocol in the request. It supports both
405 * SSLv3 (TLSv1) header format for any message, and SSLv2 header format for
406 * the hello message. The SSLv3 format is described in RFC 2246 p49, and the
407 * SSLv2 format is described here, and completed p67 of RFC 2246 :
408 * http://wp.netscape.com/eng/security/SSL_2.html
409 *
410 * Note: this decoder only works with non-wrapping data.
411 */
412static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200413smp_fetch_req_ssl_ver(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100414{
415 int version, bleft, msg_len;
416 const unsigned char *data;
Willy Tarreaube508f12016-03-10 11:47:01 +0100417 struct channel *req;
418
419 if (!smp->strm)
Christopher Fauleta434a002021-03-25 11:58:51 +0100420 goto not_ssl;
421
422 /* meaningless for HTX buffers */
423 if (IS_HTX_STRM(smp->strm))
424 goto not_ssl;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100425
Willy Tarreaube508f12016-03-10 11:47:01 +0100426 req = &smp->strm->req;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100427 msg_len = 0;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200428 bleft = ci_data(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100429 if (!bleft)
430 goto too_short;
431
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200432 data = (const unsigned char *)ci_head(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100433 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
434 /* SSLv3 header format */
Lukas Tribusc93242c2015-11-05 13:59:30 +0100435 if (bleft < 11)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100436 goto too_short;
437
Lukas Tribusc93242c2015-11-05 13:59:30 +0100438 version = (data[1] << 16) + data[2]; /* record layer version: major, minor */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100439 msg_len = (data[3] << 8) + data[4]; /* record length */
440
441 /* format introduced with SSLv3 */
442 if (version < 0x00030000)
443 goto not_ssl;
444
Lukas Tribusc93242c2015-11-05 13:59:30 +0100445 /* message length between 6 and 2^14 + 2048 */
446 if (msg_len < 6 || msg_len > ((1<<14) + 2048))
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100447 goto not_ssl;
448
449 bleft -= 5; data += 5;
Lukas Tribusc93242c2015-11-05 13:59:30 +0100450
451 /* return the client hello client version, not the record layer version */
452 version = (data[4] << 16) + data[5]; /* client hello version: major, minor */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100453 } else {
454 /* SSLv2 header format, only supported for hello (msg type 1) */
455 int rlen, plen, cilen, silen, chlen;
456
457 if (*data & 0x80) {
458 if (bleft < 3)
459 goto too_short;
460 /* short header format : 15 bits for length */
461 rlen = ((data[0] & 0x7F) << 8) | data[1];
462 plen = 0;
463 bleft -= 2; data += 2;
464 } else {
465 if (bleft < 4)
466 goto too_short;
467 /* long header format : 14 bits for length + pad length */
468 rlen = ((data[0] & 0x3F) << 8) | data[1];
469 plen = data[2];
Willy Tarreau74967f62016-08-30 14:39:46 +0200470 bleft -= 3; data += 3;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100471 }
472
473 if (*data != 0x01)
474 goto not_ssl;
475 bleft--; data++;
476
477 if (bleft < 8)
478 goto too_short;
479 version = (data[0] << 16) + data[1]; /* version: major, minor */
480 cilen = (data[2] << 8) + data[3]; /* cipher len, multiple of 3 */
481 silen = (data[4] << 8) + data[5]; /* session_id_len: 0 or 16 */
482 chlen = (data[6] << 8) + data[7]; /* 16<=challenge length<=32 */
483
484 bleft -= 8; data += 8;
485 if (cilen % 3 != 0)
486 goto not_ssl;
487 if (silen && silen != 16)
488 goto not_ssl;
489 if (chlen < 16 || chlen > 32)
490 goto not_ssl;
491 if (rlen != 9 + cilen + silen + chlen)
492 goto not_ssl;
493
494 /* focus on the remaining data length */
495 msg_len = cilen + silen + chlen + plen;
496 }
497 /* We could recursively check that the buffer ends exactly on an SSL
498 * fragment boundary and that a possible next segment is still SSL,
499 * but that's a bit pointless. However, we could still check that
500 * all the part of the request which fits in a buffer is already
501 * there.
502 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200503 if (msg_len > channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req))
504 msg_len = channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100505
506 if (bleft < msg_len)
507 goto too_short;
508
509 /* OK that's enough. We have at least the whole message, and we have
510 * the protocol version.
511 */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200512 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200513 smp->data.u.sint = version;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100514 smp->flags = SMP_F_VOLATILE;
515 return 1;
516
517 too_short:
518 smp->flags = SMP_F_MAY_CHANGE;
519 not_ssl:
520 return 0;
521}
522
523/* Try to extract the Server Name Indication that may be presented in a TLS
524 * client hello handshake message. The format of the message is the following
525 * (cf RFC5246 + RFC6066) :
526 * TLS frame :
527 * - uint8 type = 0x16 (Handshake)
528 * - uint16 version >= 0x0301 (TLSv1)
529 * - uint16 length (frame length)
530 * - TLS handshake :
531 * - uint8 msg_type = 0x01 (ClientHello)
532 * - uint24 length (handshake message length)
533 * - ClientHello :
534 * - uint16 client_version >= 0x0301 (TLSv1)
535 * - uint8 Random[32] (4 first ones are timestamp)
536 * - SessionID :
537 * - uint8 session_id_len (0..32) (SessionID len in bytes)
538 * - uint8 session_id[session_id_len]
539 * - CipherSuite :
540 * - uint16 cipher_len >= 2 (Cipher length in bytes)
541 * - uint16 ciphers[cipher_len/2]
542 * - CompressionMethod :
543 * - uint8 compression_len >= 1 (# of supported methods)
544 * - uint8 compression_methods[compression_len]
545 * - optional client_extension_len (in bytes)
546 * - optional sequence of ClientHelloExtensions (as many bytes as above):
547 * - uint16 extension_type = 0 for server_name
548 * - uint16 extension_len
549 * - opaque extension_data[extension_len]
550 * - uint16 server_name_list_len (# of bytes here)
551 * - opaque server_names[server_name_list_len bytes]
552 * - uint8 name_type = 0 for host_name
553 * - uint16 name_len
554 * - opaque hostname[name_len bytes]
555 */
556static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200557smp_fetch_ssl_hello_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100558{
559 int hs_len, ext_len, bleft;
560 struct channel *chn;
561 unsigned char *data;
562
Willy Tarreaube508f12016-03-10 11:47:01 +0100563 if (!smp->strm)
564 goto not_ssl_hello;
565
Christopher Fauleta434a002021-03-25 11:58:51 +0100566 /* meaningless for HTX buffers */
567 if (IS_HTX_STRM(smp->strm))
568 goto not_ssl_hello;
569
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200570 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200571 bleft = ci_data(chn);
572 data = (unsigned char *)ci_head(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100573
574 /* Check for SSL/TLS Handshake */
575 if (!bleft)
576 goto too_short;
577 if (*data != 0x16)
578 goto not_ssl_hello;
579
Lukas Tribus57d22972014-04-10 21:36:22 +0200580 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100581 if (bleft < 3)
582 goto too_short;
Lukas Tribus57d22972014-04-10 21:36:22 +0200583 if (data[1] < 0x03)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100584 goto not_ssl_hello;
585
586 if (bleft < 5)
587 goto too_short;
588 hs_len = (data[3] << 8) + data[4];
589 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
590 goto not_ssl_hello; /* too short to have an extension */
591
592 data += 5; /* enter TLS handshake */
593 bleft -= 5;
594
595 /* Check for a complete client hello starting at <data> */
596 if (bleft < 1)
597 goto too_short;
598 if (data[0] != 0x01) /* msg_type = Client Hello */
599 goto not_ssl_hello;
600
601 /* Check the Hello's length */
602 if (bleft < 4)
603 goto too_short;
604 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
605 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
606 goto not_ssl_hello; /* too short to have an extension */
607
608 /* We want the full handshake here */
609 if (bleft < hs_len)
610 goto too_short;
611
612 data += 4;
613 /* Start of the ClientHello message */
614 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
615 goto not_ssl_hello;
616
617 ext_len = data[34]; /* session_id_len */
618 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
619 goto not_ssl_hello;
620
621 /* Jump to cipher suite */
622 hs_len -= 35 + ext_len;
623 data += 35 + ext_len;
624
625 if (hs_len < 4 || /* minimum one cipher */
626 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
627 ext_len > hs_len)
628 goto not_ssl_hello;
629
630 /* Jump to the compression methods */
631 hs_len -= 2 + ext_len;
632 data += 2 + ext_len;
633
634 if (hs_len < 2 || /* minimum one compression method */
635 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
636 goto not_ssl_hello;
637
638 /* Jump to the extensions */
639 hs_len -= 1 + data[0];
640 data += 1 + data[0];
641
642 if (hs_len < 2 || /* minimum one extension list length */
643 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
644 goto not_ssl_hello;
645
646 hs_len = ext_len; /* limit ourselves to the extension length */
647 data += 2;
648
649 while (hs_len >= 4) {
650 int ext_type, name_type, srv_len, name_len;
651
652 ext_type = (data[0] << 8) + data[1];
653 ext_len = (data[2] << 8) + data[3];
654
655 if (ext_len > hs_len - 4) /* Extension too long */
656 goto not_ssl_hello;
657
658 if (ext_type == 0) { /* Server name */
659 if (ext_len < 2) /* need one list length */
660 goto not_ssl_hello;
661
662 srv_len = (data[4] << 8) + data[5];
663 if (srv_len < 4 || srv_len > hs_len - 6)
664 goto not_ssl_hello; /* at least 4 bytes per server name */
665
666 name_type = data[6];
667 name_len = (data[7] << 8) + data[8];
668
669 if (name_type == 0) { /* hostname */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200670 smp->data.type = SMP_T_STR;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200671 smp->data.u.str.area = (char *)data + 9;
672 smp->data.u.str.data = name_len;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100673 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100674 return 1;
675 }
676 }
677
678 hs_len -= 4 + ext_len;
679 data += 4 + ext_len;
680 }
681 /* server name not found */
682 goto not_ssl_hello;
683
684 too_short:
685 smp->flags = SMP_F_MAY_CHANGE;
686
687 not_ssl_hello:
688
689 return 0;
690}
691
Alex Zorin4afdd132018-12-30 13:56:28 +1100692/* Try to extract the Application-Layer Protocol Negotiation (ALPN) protocol
693 * names that may be presented in a TLS client hello handshake message. As the
694 * message presents a list of protocol names in descending order of preference,
695 * it may return iteratively. The format of the message is the following
696 * (cf RFC5246 + RFC7301) :
697 * TLS frame :
698 * - uint8 type = 0x16 (Handshake)
699 * - uint16 version >= 0x0301 (TLSv1)
700 * - uint16 length (frame length)
701 * - TLS handshake :
702 * - uint8 msg_type = 0x01 (ClientHello)
703 * - uint24 length (handshake message length)
704 * - ClientHello :
705 * - uint16 client_version >= 0x0301 (TLSv1)
706 * - uint8 Random[32] (4 first ones are timestamp)
707 * - SessionID :
708 * - uint8 session_id_len (0..32) (SessionID len in bytes)
709 * - uint8 session_id[session_id_len]
710 * - CipherSuite :
711 * - uint16 cipher_len >= 2 (Cipher length in bytes)
712 * - uint16 ciphers[cipher_len/2]
713 * - CompressionMethod :
714 * - uint8 compression_len >= 1 (# of supported methods)
715 * - uint8 compression_methods[compression_len]
716 * - optional client_extension_len (in bytes)
717 * - optional sequence of ClientHelloExtensions (as many bytes as above):
718 * - uint16 extension_type = 16 for application_layer_protocol_negotiation
719 * - uint16 extension_len
720 * - opaque extension_data[extension_len]
721 * - uint16 protocol_names_len (# of bytes here)
722 * - opaque protocol_names[protocol_names_len bytes]
723 * - uint8 name_len
724 * - opaque protocol_name[name_len bytes]
725 */
726static int
727smp_fetch_ssl_hello_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
728{
729 int hs_len, ext_len, bleft;
730 struct channel *chn;
731 unsigned char *data;
732
733 if (!smp->strm)
734 goto not_ssl_hello;
735
Christopher Fauleta434a002021-03-25 11:58:51 +0100736 /* meaningless for HTX buffers */
737 if (IS_HTX_STRM(smp->strm))
738 goto not_ssl_hello;
739
Alex Zorin4afdd132018-12-30 13:56:28 +1100740 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
741 bleft = ci_data(chn);
742 data = (unsigned char *)ci_head(chn);
743
744 /* Check for SSL/TLS Handshake */
745 if (!bleft)
746 goto too_short;
747 if (*data != 0x16)
748 goto not_ssl_hello;
749
750 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
751 if (bleft < 3)
752 goto too_short;
753 if (data[1] < 0x03)
754 goto not_ssl_hello;
755
756 if (bleft < 5)
757 goto too_short;
758 hs_len = (data[3] << 8) + data[4];
759 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
760 goto not_ssl_hello; /* too short to have an extension */
761
762 data += 5; /* enter TLS handshake */
763 bleft -= 5;
764
765 /* Check for a complete client hello starting at <data> */
766 if (bleft < 1)
767 goto too_short;
768 if (data[0] != 0x01) /* msg_type = Client Hello */
769 goto not_ssl_hello;
770
771 /* Check the Hello's length */
772 if (bleft < 4)
773 goto too_short;
774 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
775 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
776 goto not_ssl_hello; /* too short to have an extension */
777
778 /* We want the full handshake here */
779 if (bleft < hs_len)
780 goto too_short;
781
782 data += 4;
783 /* Start of the ClientHello message */
784 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
785 goto not_ssl_hello;
786
787 ext_len = data[34]; /* session_id_len */
788 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
789 goto not_ssl_hello;
790
791 /* Jump to cipher suite */
792 hs_len -= 35 + ext_len;
793 data += 35 + ext_len;
794
795 if (hs_len < 4 || /* minimum one cipher */
796 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
797 ext_len > hs_len)
798 goto not_ssl_hello;
799
800 /* Jump to the compression methods */
801 hs_len -= 2 + ext_len;
802 data += 2 + ext_len;
803
804 if (hs_len < 2 || /* minimum one compression method */
805 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
806 goto not_ssl_hello;
807
808 /* Jump to the extensions */
809 hs_len -= 1 + data[0];
810 data += 1 + data[0];
811
812 if (hs_len < 2 || /* minimum one extension list length */
813 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
814 goto not_ssl_hello;
815
816 hs_len = ext_len; /* limit ourselves to the extension length */
817 data += 2;
818
819 while (hs_len >= 4) {
820 int ext_type, name_len, name_offset;
821
822 ext_type = (data[0] << 8) + data[1];
823 ext_len = (data[2] << 8) + data[3];
824
825 if (ext_len > hs_len - 4) /* Extension too long */
826 goto not_ssl_hello;
827
828 if (ext_type == 16) { /* ALPN */
829 if (ext_len < 3) /* one list length [uint16] + at least one name length [uint8] */
830 goto not_ssl_hello;
831
832 /* Name cursor in ctx, must begin after protocol_names_len */
833 name_offset = smp->ctx.i < 6 ? 6 : smp->ctx.i;
834 name_len = data[name_offset];
835
836 if (name_len + name_offset - 3 > ext_len)
837 goto not_ssl_hello;
838
839 smp->data.type = SMP_T_STR;
840 smp->data.u.str.area = (char *)data + name_offset + 1; /* +1 to skip name_len */
841 smp->data.u.str.data = name_len;
842 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
843
844 /* May have more protocol names remaining */
845 if (name_len + name_offset - 3 < ext_len) {
846 smp->ctx.i = name_offset + name_len + 1;
847 smp->flags |= SMP_F_NOT_LAST;
848 }
849
850 return 1;
851 }
852
853 hs_len -= 4 + ext_len;
854 data += 4 + ext_len;
855 }
856 /* alpn not found */
857 goto not_ssl_hello;
858
859 too_short:
860 smp->flags = SMP_F_MAY_CHANGE;
861
862 not_ssl_hello:
863
864 return 0;
865}
866
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200867/* Fetch the request RDP cookie identified in <cname>:<clen>, or any cookie if
Willy Tarreaub169eba2013-12-16 15:14:43 +0100868 * <clen> is empty (cname is then ignored). It returns the data into sample <smp>
869 * of type SMP_T_CSTR. Note: this decoder only works with non-wrapping data.
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100870 */
871int
Willy Tarreau87b09662015-04-03 00:22:06 +0200872fetch_rdp_cookie_name(struct stream *s, struct sample *smp, const char *cname, int clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100873{
874 int bleft;
875 const unsigned char *data;
876
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100877 smp->flags = SMP_F_CONST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200878 smp->data.type = SMP_T_STR;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100879
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200880 bleft = ci_data(&s->req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100881 if (bleft <= 11)
882 goto too_short;
883
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200884 data = (const unsigned char *)ci_head(&s->req) + 11;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100885 bleft -= 11;
886
887 if (bleft <= 7)
888 goto too_short;
889
890 if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
891 goto not_cookie;
892
893 data += 7;
894 bleft -= 7;
895
896 while (bleft > 0 && *data == ' ') {
897 data++;
898 bleft--;
899 }
900
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200901 if (clen) {
902 if (bleft <= clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100903 goto too_short;
904
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200905 if ((data[clen] != '=') ||
906 strncasecmp(cname, (const char *)data, clen) != 0)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100907 goto not_cookie;
908
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200909 data += clen + 1;
910 bleft -= clen + 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100911 } else {
912 while (bleft > 0 && *data != '=') {
913 if (*data == '\r' || *data == '\n')
914 goto not_cookie;
915 data++;
916 bleft--;
917 }
918
919 if (bleft < 1)
920 goto too_short;
921
922 if (*data != '=')
923 goto not_cookie;
924
925 data++;
926 bleft--;
927 }
928
929 /* data points to cookie value */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200930 smp->data.u.str.area = (char *)data;
931 smp->data.u.str.data = 0;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100932
933 while (bleft > 0 && *data != '\r') {
934 data++;
935 bleft--;
936 }
937
938 if (bleft < 2)
939 goto too_short;
940
941 if (data[0] != '\r' || data[1] != '\n')
942 goto not_cookie;
943
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200944 smp->data.u.str.data = (char *)data - smp->data.u.str.area;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100945 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100946 return 1;
947
948 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100949 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100950 not_cookie:
951 return 0;
952}
953
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200954/* Fetch the request RDP cookie identified in the args, or any cookie if no arg
955 * is passed. It is usable both for ACL and for samples. Note: this decoder
956 * only works with non-wrapping data. Accepts either 0 or 1 argument. Argument
Willy Tarreaub169eba2013-12-16 15:14:43 +0100957 * is a string (cookie name), other types will lead to undefined behaviour. The
958 * returned sample has type SMP_T_CSTR.
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200959 */
960int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200961smp_fetch_rdp_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200962{
Willy Tarreaube508f12016-03-10 11:47:01 +0100963 if (!smp->strm)
964 return 0;
965
Christopher Fauleta434a002021-03-25 11:58:51 +0100966 /* meaningless for HTX buffers */
967 if (IS_HTX_STRM(smp->strm))
968 return 0;
969
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200970 return fetch_rdp_cookie_name(smp->strm, smp,
971 args ? args->data.str.area : NULL,
972 args ? args->data.str.data : 0);
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200973}
974
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100975/* returns either 1 or 0 depending on whether an RDP cookie is found or not */
976static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200977smp_fetch_rdp_cookie_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100978{
979 int ret;
980
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200981 ret = smp_fetch_rdp_cookie(args, smp, kw, private);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100982
983 if (smp->flags & SMP_F_MAY_CHANGE)
984 return 0;
985
986 smp->flags = SMP_F_VOLATILE;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200987 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200988 smp->data.u.sint = ret;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100989 return 1;
990}
991
992/* extracts part of a payload with offset and length at a given position */
993static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200994smp_fetch_payload_lv(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100995{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200996 unsigned int len_offset = arg_p[0].data.sint;
997 unsigned int len_size = arg_p[1].data.sint;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100998 unsigned int buf_offset;
999 unsigned int buf_size = 0;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001000 struct channel *chn = NULL;
1001 char *head = NULL;
1002 size_t max, data;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001003 int i;
1004
1005 /* Format is (len offset, len size, buf offset) or (len offset, len size) */
1006 /* by default buf offset == len offset + len size */
1007 /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
1008
Christopher Faulet78f371e2020-04-30 09:38:08 +02001009 if (smp->strm) {
Christopher Fauleta434a002021-03-25 11:58:51 +01001010 /* meaningless for HTX buffers */
1011 if (IS_HTX_STRM(smp->strm))
1012 return 0;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001013 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1014 head = ci_head(chn);
1015 data = ci_data(chn);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001016 }
Christopher Fauletf98e6262020-05-06 09:42:04 +02001017 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Fauleta434a002021-03-25 11:58:51 +01001018 struct check *check = __objt_check(smp->sess->origin);
1019
1020 /* meaningless for HTX buffers */
1021 if (check->cs && IS_HTX_CS(check->cs))
1022 return 0;
1023 head = b_head(&check->bi);
1024 data = b_data(&check->bi);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001025 }
Christopher Fauletbb9fb8b2020-11-25 17:20:57 +01001026 max = global.tune.bufsize;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001027 if (!head)
Christopher Faulet50623022021-03-29 11:09:45 +02001028 goto too_short;
Willy Tarreaube508f12016-03-10 11:47:01 +01001029
Christopher Faulet78f371e2020-04-30 09:38:08 +02001030 if (len_offset + len_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001031 goto too_short;
1032
1033 for (i = 0; i < len_size; i++) {
Christopher Faulet78f371e2020-04-30 09:38:08 +02001034 buf_size = (buf_size << 8) + ((unsigned char *)head)[i + len_offset];
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001035 }
1036
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001037 /* buf offset may be implicit, absolute or relative. If the LSB
1038 * is set, then the offset is relative otherwise it is absolute.
1039 */
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001040 buf_offset = len_offset + len_size;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001041 if (arg_p[2].type == ARGT_SINT) {
1042 if (arg_p[2].data.sint & 1)
1043 buf_offset += arg_p[2].data.sint >> 1;
1044 else
1045 buf_offset = arg_p[2].data.sint >> 1;
1046 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001047
Christopher Faulet78f371e2020-04-30 09:38:08 +02001048 if (!buf_size || buf_size > max || buf_offset + buf_size > max) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001049 /* will never match */
1050 smp->flags = 0;
1051 return 0;
1052 }
1053
Christopher Faulet78f371e2020-04-30 09:38:08 +02001054 if (buf_offset + buf_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001055 goto too_short;
1056
1057 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001058 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001059 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001060 chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001061 return 1;
1062
1063 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001064 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001065 return 0;
1066}
1067
1068/* extracts some payload at a fixed position and length */
1069static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +02001070smp_fetch_payload(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001071{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001072 unsigned int buf_offset = arg_p[0].data.sint;
1073 unsigned int buf_size = arg_p[1].data.sint;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001074 struct channel *chn = NULL;
1075 char *head = NULL;
1076 size_t max, data;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001077
Christopher Faulet78f371e2020-04-30 09:38:08 +02001078 if (smp->strm) {
Christopher Fauleta434a002021-03-25 11:58:51 +01001079 /* meaningless for HTX buffers */
1080 if (IS_HTX_STRM(smp->strm))
1081 return 0;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001082 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1083 head = ci_head(chn);
1084 data = ci_data(chn);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001085 }
Christopher Fauletf98e6262020-05-06 09:42:04 +02001086 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Fauleta434a002021-03-25 11:58:51 +01001087 struct check *check = __objt_check(smp->sess->origin);
1088
1089 /* meaningless for HTX buffers */
1090 if (check->cs && IS_HTX_CS(check->cs))
1091 return 0;
1092 head = b_head(&check->bi);
1093 data = b_data(&check->bi);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001094 }
Christopher Fauletbb9fb8b2020-11-25 17:20:57 +01001095 max = global.tune.bufsize;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001096 if (!head)
Christopher Faulet50623022021-03-29 11:09:45 +02001097 goto too_short;
Willy Tarreaube508f12016-03-10 11:47:01 +01001098
Christopher Faulet78f371e2020-04-30 09:38:08 +02001099 if (buf_size > max || buf_offset + buf_size > max) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001100 /* will never match */
1101 smp->flags = 0;
1102 return 0;
1103 }
Christopher Faulet78f371e2020-04-30 09:38:08 +02001104 if (buf_offset + buf_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001105 goto too_short;
1106
1107 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001108 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001109 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001110 chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size ? buf_size : (data - buf_offset));
1111
1112 if (!buf_size && chn && channel_may_recv(chn) && !channel_input_closed(chn))
Willy Tarreau00f00842013-08-02 11:07:32 +02001113 smp->flags |= SMP_F_MAY_CHANGE;
1114
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001115 return 1;
1116
Christopher Faulet78f371e2020-04-30 09:38:08 +02001117 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001118 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001119 return 0;
1120}
1121
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001122/* This function is used to validate the arguments passed to a "payload_lv" fetch
1123 * keyword. This keyword allows two positive integers and an optional signed one,
1124 * with the second one being strictly positive and the third one being greater than
1125 * the opposite of the two others if negative. It is assumed that the types are
1126 * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> is
1127 * not NULL, it will be filled with a pointer to an error message in case of
1128 * error, that the caller is responsible for freeing. The initial location must
1129 * either be freeable or NULL.
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001130 *
1131 * Note that offset2 is stored with SINT type, but its not directly usable as is.
1132 * The value is contained in the 63 MSB and the LSB is used as a flag for marking
1133 * the "relative" property of the value.
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001134 */
Thierry FOURNIER49f45af2014-12-08 19:50:43 +01001135int val_payload_lv(struct arg *arg, char **err_msg)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001136{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001137 int relative = 0;
1138 const char *str;
1139
1140 if (arg[0].data.sint < 0) {
1141 memprintf(err_msg, "payload offset1 must be positive");
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001142 return 0;
1143 }
1144
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001145 if (!arg[1].data.sint) {
1146 memprintf(err_msg, "payload length must be > 0");
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001147 return 0;
1148 }
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001149
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001150 if (arg[2].type == ARGT_STR && arg[2].data.str.data > 0) {
Christopher Faulet95917132020-08-05 23:07:07 +02001151 long long int i;
1152
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001153 if (arg[2].data.str.area[0] == '+' || arg[2].data.str.area[0] == '-')
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001154 relative = 1;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001155 str = arg[2].data.str.area;
Christopher Faulet95917132020-08-05 23:07:07 +02001156 i = read_int64(&str, str + arg[2].data.str.data);
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001157 if (*str != '\0') {
1158 memprintf(err_msg, "payload offset2 is not a number");
1159 return 0;
1160 }
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001161 chunk_destroy(&arg[2].data.str);
Christopher Faulet95917132020-08-05 23:07:07 +02001162 arg[2].type = ARGT_SINT;
1163 arg[2].data.sint = i;
1164
1165 if (arg[0].data.sint + arg[1].data.sint + arg[2].data.sint < 0) {
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001166 memprintf(err_msg, "payload offset2 too negative");
1167 return 0;
1168 }
1169 if (relative)
1170 arg[2].data.sint = ( arg[2].data.sint << 1 ) + 1;
1171 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001172 return 1;
1173}
1174
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001175/* extracts the parameter value of a distcc token */
1176static int
1177smp_fetch_distcc_param(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
1178{
1179 unsigned int match_tok = arg_p[0].data.sint;
1180 unsigned int match_occ = arg_p[1].data.sint;
1181 unsigned int token;
1182 unsigned int param;
1183 unsigned int body;
1184 unsigned int ofs;
1185 unsigned int occ;
1186 struct channel *chn;
1187 int i;
1188
1189 /* Format is (token[,occ]). occ starts at 1. */
1190
1191 if (!smp->strm)
1192 return 0;
1193
Christopher Fauleta434a002021-03-25 11:58:51 +01001194 /* meaningless for HTX buffers */
1195 if (IS_HTX_STRM(smp->strm))
1196 return 0;
1197
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001198 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1199
1200 ofs = 0; occ = 0;
1201 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001202 if (ofs + 12 > ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001203 /* not there yet but could it at least fit ? */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001204 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001205 goto too_short;
1206
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001207 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001208 goto too_short;
1209
1210 goto no_match;
1211 }
1212
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001213 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001214 ofs += 4;
1215
1216 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001217 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001218
1219 if (c < 0)
1220 goto no_match;
1221 param = (param << 4) + c;
1222 }
1223 ofs += 8;
1224
1225 /* these tokens don't have a body */
1226 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1227 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1228 token != 0x444F4E45 /* DONE */)
1229 body = param;
1230 else
1231 body = 0;
1232
1233 if (token == match_tok) {
1234 occ++;
1235 if (!match_occ || match_occ == occ) {
1236 /* found */
1237 smp->data.type = SMP_T_SINT;
1238 smp->data.u.sint = param;
1239 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1240 return 1;
1241 }
1242 }
1243 ofs += body;
1244 }
1245
1246 too_short:
1247 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1248 return 0;
1249 no_match:
1250 /* will never match (end of buffer, or bad contents) */
1251 smp->flags = 0;
1252 return 0;
1253
1254}
1255
1256/* extracts the (possibly truncated) body of a distcc token */
1257static int
1258smp_fetch_distcc_body(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
1259{
1260 unsigned int match_tok = arg_p[0].data.sint;
1261 unsigned int match_occ = arg_p[1].data.sint;
1262 unsigned int token;
1263 unsigned int param;
1264 unsigned int ofs;
1265 unsigned int occ;
1266 unsigned int body;
1267 struct channel *chn;
1268 int i;
1269
1270 /* Format is (token[,occ]). occ starts at 1. */
1271
1272 if (!smp->strm)
1273 return 0;
1274
Christopher Fauleta434a002021-03-25 11:58:51 +01001275 /* meaningless for HTX buffers */
1276 if (IS_HTX_STRM(smp->strm))
1277 return 0;
1278
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001279 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1280
1281 ofs = 0; occ = 0;
1282 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001283 if (ofs + 12 > ci_data(chn)) {
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001284 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001285 goto too_short;
1286
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001287 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001288 goto too_short;
1289
1290 goto no_match;
1291 }
1292
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001293 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001294 ofs += 4;
1295
1296 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001297 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001298
1299 if (c < 0)
1300 goto no_match;
1301 param = (param << 4) + c;
1302 }
1303 ofs += 8;
1304
1305 /* these tokens don't have a body */
1306 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1307 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1308 token != 0x444F4E45 /* DONE */)
1309 body = param;
1310 else
1311 body = 0;
1312
1313 if (token == match_tok) {
1314 occ++;
1315 if (!match_occ || match_occ == occ) {
1316 /* found */
1317
1318 smp->data.type = SMP_T_BIN;
1319 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1320
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001321 if (ofs + body > ci_head(chn) - b_orig(&chn->buf) + ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001322 /* incomplete body */
1323
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001324 if (ofs + body > channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001325 /* truncate it to whatever will fit */
1326 smp->flags |= SMP_F_MAY_CHANGE;
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001327 body = channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn) - ofs;
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001328 }
1329 }
1330
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001331 chunk_initlen(&smp->data.u.str, ci_head(chn) + ofs, 0, body);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001332 return 1;
1333 }
1334 }
1335 ofs += body;
1336 }
1337
1338 too_short:
1339 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1340 return 0;
1341 no_match:
1342 /* will never match (end of buffer, or bad contents) */
1343 smp->flags = 0;
1344 return 0;
1345
1346}
1347
1348/* This function is used to validate the arguments passed to a "distcc_param" or
1349 * "distcc_body" sample fetch keyword. They take a mandatory token name of exactly
1350 * 4 characters, followed by an optional occurrence number starting at 1. It is
1351 * assumed that the types are already the correct ones. Returns 0 on error, non-
1352 * zero if OK. If <err_msg> is not NULL, it will be filled with a pointer to an
1353 * error message in case of error, that the caller is responsible for freeing.
1354 * The initial location must either be freeable or NULL.
1355 */
1356int val_distcc(struct arg *arg, char **err_msg)
1357{
1358 unsigned int token;
1359
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001360 if (arg[0].data.str.data != 4) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001361 memprintf(err_msg, "token name must be exactly 4 characters");
1362 return 0;
1363 }
1364
1365 /* convert the token name to an unsigned int (one byte per character,
1366 * big endian format).
1367 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001368 token = (arg[0].data.str.area[0] << 24) + (arg[0].data.str.area[1] << 16) +
1369 (arg[0].data.str.area[2] << 8) + (arg[0].data.str.area[3] << 0);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001370
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001371 chunk_destroy(&arg[0].data.str);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001372 arg[0].type = ARGT_SINT;
1373 arg[0].data.sint = token;
1374
1375 if (arg[1].type != ARGT_SINT) {
1376 arg[1].type = ARGT_SINT;
1377 arg[1].data.sint = 0;
1378 }
1379 return 1;
1380}
1381
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001382/************************************************************************/
1383/* All supported sample and ACL keywords must be declared here. */
1384/************************************************************************/
1385
1386/* Note: must not be declared <const> as its list will be overwritten.
1387 * Note: fetches that may return multiple types must be declared as the lowest
1388 * common denominator, the type that can be casted into all other ones. For
1389 * instance IPv4/IPv6 must be declared IPv4.
1390 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001391static struct sample_fetch_kw_list smp_kws = {ILH, {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001392 { "distcc_body", smp_fetch_distcc_body, ARG2(1,STR,SINT), val_distcc, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1393 { "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 +02001394 { "payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1395 { "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 +01001396 { "rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001397 { "rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L6REQ },
1398 { "rep_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
1399 { "req_len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1400 { "req_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001401 { "req_ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001402 { "req_ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +01001403
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001404 { "req.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001405 { "req.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ },
1406 { "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 +01001407 { "req.rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001408 { "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 +02001409 { "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 +05301410 { "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 +02001411 { "req.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001412 { "req.ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Alex Zorin4afdd132018-12-30 13:56:28 +11001413 { "req.ssl_alpn", smp_fetch_ssl_hello_alpn, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001414 { "req.ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1415 { "res.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001416 { "res.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6RES },
1417 { "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 +02001418 { "res.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001419 { "wait_end", smp_fetch_wait_end, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
1420 { /* END */ },
1421}};
1422
Willy Tarreau0108d902018-11-25 19:14:37 +01001423INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001424
1425/* Note: must not be declared <const> as its list will be overwritten.
1426 * Please take care of keeping this list alphabetically sorted.
1427 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001428static struct acl_kw_list acl_kws = {ILH, {
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +01001429 { "payload", "req.payload", PAT_MATCH_BIN },
1430 { "payload_lv", "req.payload_lv", PAT_MATCH_BIN },
1431 { "req_rdp_cookie", "req.rdp_cookie", PAT_MATCH_STR },
1432 { "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", PAT_MATCH_INT },
1433 { "req_ssl_sni", "req.ssl_sni", PAT_MATCH_STR },
1434 { "req_ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
1435 { "req.ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001436 { /* END */ },
1437}};
1438
Willy Tarreau0108d902018-11-25 19:14:37 +01001439INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001440
1441/*
1442 * Local variables:
1443 * c-indent-level: 8
1444 * c-basic-offset: 8
1445 * End:
1446 */