blob: 7dd08c814e83b9faa23592f5510055e0b55f0bc9 [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 Tarreau485261b2021-05-08 13:55:40 +020026#include <haproxy/tools.h>
Willy Tarreaud4c33c82013-01-07 21:59:07 +010027
28
29/************************************************************************/
30/* All supported sample fetch functions must be declared here */
31/************************************************************************/
32
33/* wait for more data as long as possible, then return TRUE. This should be
34 * used with content inspection.
35 */
36static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020037smp_fetch_wait_end(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010038{
Thierry FOURNIER0786d052015-05-11 15:42:45 +020039 if (!(smp->opt & SMP_OPT_FINAL)) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +010040 smp->flags |= SMP_F_MAY_CHANGE;
41 return 0;
42 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020043 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020044 smp->data.u.sint = 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +010045 return 1;
46}
47
48/* return the number of bytes in the request buffer */
49static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020050smp_fetch_len(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010051{
Christopher Faulet78f371e2020-04-30 09:38:08 +020052 if (smp->strm) {
53 struct channel *chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Christopher Fauleta434a002021-03-25 11:58:51 +010054
55 /* Not accurate but kept for backward compatibility purpose */
Christopher Faulet78f371e2020-04-30 09:38:08 +020056 if (IS_HTX_STRM(smp->strm)) {
57 struct htx *htx = htxbuf(&chn->buf);
58 smp->data.u.sint = htx->data - co_data(chn);
59 }
60 else
61 smp->data.u.sint = ci_data(chn);
62 }
Christopher Fauletf98e6262020-05-06 09:42:04 +020063 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Faulet78f371e2020-04-30 09:38:08 +020064 struct check *check = __objt_check(smp->sess->origin);
Christopher Fauleta434a002021-03-25 11:58:51 +010065
66 /* Not accurate but kept for backward compatibility purpose */
Christopher Faulet78f371e2020-04-30 09:38:08 +020067 smp->data.u.sint = ((check->cs && IS_HTX_CS(check->cs)) ? (htxbuf(&check->bi))->data: b_data(&check->bi));
68 }
69 else
Willy Tarreaube508f12016-03-10 11:47:01 +010070 return 0;
71
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020072 smp->data.type = SMP_T_SINT;
Willy Tarreaud4c33c82013-01-07 21:59:07 +010073 smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
74 return 1;
75}
76
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053077/* Returns 0 if the client didn't send a SessionTicket Extension
78 * Returns 1 if the client sent SessionTicket Extension
79 * Returns 2 if the client also sent non-zero length SessionTicket
80 * Returns SMP_T_SINT data type
81 */
82static int
83smp_fetch_req_ssl_st_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
84{
85 int hs_len, ext_len, bleft;
86 struct channel *chn;
87 unsigned char *data;
88
Willy Tarreaube508f12016-03-10 11:47:01 +010089 if (!smp->strm)
90 goto not_ssl_hello;
91
Christopher Fauleta434a002021-03-25 11:58:51 +010092 /* meaningless for HTX buffers */
93 if (IS_HTX_STRM(smp->strm))
94 goto not_ssl_hello;
95
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053096 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Christopher Fauleta434a002021-03-25 11:58:51 +010097
98
Willy Tarreaufc0785d2018-06-19 07:19:56 +020099 bleft = ci_data(chn);
100 data = (unsigned char *)ci_head(chn);
Pradeep Jindalbb2acf52015-09-29 10:12:57 +0530101
102 /* Check for SSL/TLS Handshake */
103 if (!bleft)
104 goto too_short;
105 if (*data != 0x16)
106 goto not_ssl_hello;
107
108 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
109 if (bleft < 3)
110 goto too_short;
111 if (data[1] < 0x03)
112 goto not_ssl_hello;
113
114 if (bleft < 5)
115 goto too_short;
116 hs_len = (data[3] << 8) + data[4];
117 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
118 goto not_ssl_hello; /* too short to have an extension */
119
120 data += 5; /* enter TLS handshake */
121 bleft -= 5;
122
123 /* Check for a complete client hello starting at <data> */
124 if (bleft < 1)
125 goto too_short;
126 if (data[0] != 0x01) /* msg_type = Client Hello */
127 goto not_ssl_hello;
128
129 /* Check the Hello's length */
130 if (bleft < 4)
131 goto too_short;
132 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
133 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
134 goto not_ssl_hello; /* too short to have an extension */
135
136 /* We want the full handshake here */
137 if (bleft < hs_len)
138 goto too_short;
139
140 data += 4;
141 /* Start of the ClientHello message */
142 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
143 goto not_ssl_hello;
144
145 ext_len = data[34]; /* session_id_len */
146 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
147 goto not_ssl_hello;
148
149 /* Jump to cipher suite */
150 hs_len -= 35 + ext_len;
151 data += 35 + ext_len;
152
153 if (hs_len < 4 || /* minimum one cipher */
154 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
155 ext_len > hs_len)
156 goto not_ssl_hello;
157
158 /* Jump to the compression methods */
159 hs_len -= 2 + ext_len;
160 data += 2 + ext_len;
161
162 if (hs_len < 2 || /* minimum one compression method */
163 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
164 goto not_ssl_hello;
165
166 /* Jump to the extensions */
167 hs_len -= 1 + data[0];
168 data += 1 + data[0];
169
170 if (hs_len < 2 || /* minimum one extension list length */
171 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
172 goto not_ssl_hello;
173
174 hs_len = ext_len; /* limit ourselves to the extension length */
175 data += 2;
176
177 while (hs_len >= 4) {
178 int ext_type, ext_len;
179
180 ext_type = (data[0] << 8) + data[1];
181 ext_len = (data[2] << 8) + data[3];
182
183 if (ext_len > hs_len - 4) /* Extension too long */
184 goto not_ssl_hello;
185
186 /* SesstionTicket extension */
187 if (ext_type == 35) {
188 smp->data.type = SMP_T_SINT;
189 /* SessionTicket also present */
190 if (ext_len > 0)
191 smp->data.u.sint = 2;
192 /* SessionTicket absent */
193 else
194 smp->data.u.sint = 1;
195 smp->flags = SMP_F_VOLATILE;
196 return 1;
197 }
198
199 hs_len -= 4 + ext_len;
200 data += 4 + ext_len;
201 }
202 /* SessionTicket Extension not found */
203 smp->data.type = SMP_T_SINT;
204 smp->data.u.sint = 0;
205 smp->flags = SMP_F_VOLATILE;
206 return 1;
207
Pradeep Jindalbb2acf52015-09-29 10:12:57 +0530208 too_short:
209 smp->flags = SMP_F_MAY_CHANGE;
210
211 not_ssl_hello:
212 return 0;
213}
214
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200215/* Returns TRUE if the client sent Supported Elliptic Curves Extension (0x000a)
216 * Mainly used to detect if client supports ECC cipher suites.
217 */
218static int
219smp_fetch_req_ssl_ec_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
220{
221 int hs_len, ext_len, bleft;
222 struct channel *chn;
223 unsigned char *data;
224
Willy Tarreaube508f12016-03-10 11:47:01 +0100225 if (!smp->strm)
226 goto not_ssl_hello;
227
Christopher Fauleta434a002021-03-25 11:58:51 +0100228 /* meaningless for HTX buffers */
229 if (IS_HTX_STRM(smp->strm))
230 goto not_ssl_hello;
231
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200232 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200233 bleft = ci_data(chn);
234 data = (unsigned char *)ci_head(chn);
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200235
236 /* Check for SSL/TLS Handshake */
237 if (!bleft)
238 goto too_short;
239 if (*data != 0x16)
240 goto not_ssl_hello;
241
242 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
243 if (bleft < 3)
244 goto too_short;
245 if (data[1] < 0x03)
246 goto not_ssl_hello;
247
248 if (bleft < 5)
249 goto too_short;
250 hs_len = (data[3] << 8) + data[4];
251 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
252 goto not_ssl_hello; /* too short to have an extension */
253
254 data += 5; /* enter TLS handshake */
255 bleft -= 5;
256
257 /* Check for a complete client hello starting at <data> */
258 if (bleft < 1)
259 goto too_short;
260 if (data[0] != 0x01) /* msg_type = Client Hello */
261 goto not_ssl_hello;
262
263 /* Check the Hello's length */
264 if (bleft < 4)
265 goto too_short;
266 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
267 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
268 goto not_ssl_hello; /* too short to have an extension */
269
270 /* We want the full handshake here */
271 if (bleft < hs_len)
272 goto too_short;
273
274 data += 4;
275 /* Start of the ClientHello message */
276 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
277 goto not_ssl_hello;
278
279 ext_len = data[34]; /* session_id_len */
280 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
281 goto not_ssl_hello;
282
283 /* Jump to cipher suite */
284 hs_len -= 35 + ext_len;
285 data += 35 + ext_len;
286
287 if (hs_len < 4 || /* minimum one cipher */
288 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
289 ext_len > hs_len)
290 goto not_ssl_hello;
291
292 /* Jump to the compression methods */
293 hs_len -= 2 + ext_len;
294 data += 2 + ext_len;
295
296 if (hs_len < 2 || /* minimum one compression method */
297 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
298 goto not_ssl_hello;
299
300 /* Jump to the extensions */
301 hs_len -= 1 + data[0];
302 data += 1 + data[0];
303
304 if (hs_len < 2 || /* minimum one extension list length */
305 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
306 goto not_ssl_hello;
307
308 hs_len = ext_len; /* limit ourselves to the extension length */
309 data += 2;
310
311 while (hs_len >= 4) {
312 int ext_type, ext_len;
313
314 ext_type = (data[0] << 8) + data[1];
315 ext_len = (data[2] << 8) + data[3];
316
317 if (ext_len > hs_len - 4) /* Extension too long */
318 goto not_ssl_hello;
319
320 /* Elliptic curves extension */
321 if (ext_type == 10) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200322 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200323 smp->data.u.sint = 1;
Nenad Merdanovic8a39a1f2015-07-15 12:51:11 +0200324 smp->flags = SMP_F_VOLATILE;
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200325 return 1;
326 }
327
328 hs_len -= 4 + ext_len;
329 data += 4 + ext_len;
330 }
331 /* server name not found */
332 goto not_ssl_hello;
333
334 too_short:
335 smp->flags = SMP_F_MAY_CHANGE;
336
337 not_ssl_hello:
338
339 return 0;
340}
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100341/* returns the type of SSL hello message (mainly used to detect an SSL hello) */
342static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200343smp_fetch_ssl_hello_type(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100344{
345 int hs_len;
346 int hs_type, bleft;
347 struct channel *chn;
348 const unsigned char *data;
349
Willy Tarreaube508f12016-03-10 11:47:01 +0100350 if (!smp->strm)
351 goto not_ssl_hello;
352
Christopher Fauleta434a002021-03-25 11:58:51 +0100353 /* meaningless for HTX buffers */
354 if (IS_HTX_STRM(smp->strm))
355 goto not_ssl_hello;
356
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200357 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200358 bleft = ci_data(chn);
359 data = (const unsigned char *)ci_head(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100360
361 if (!bleft)
362 goto too_short;
363
364 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
365 /* SSLv3 header format */
366 if (bleft < 9)
367 goto too_short;
368
369 /* ssl version 3 */
370 if ((data[1] << 16) + data[2] < 0x00030000)
371 goto not_ssl_hello;
372
373 /* ssl message len must present handshake type and len */
374 if ((data[3] << 8) + data[4] < 4)
375 goto not_ssl_hello;
376
377 /* format introduced with SSLv3 */
378
379 hs_type = (int)data[5];
380 hs_len = ( data[6] << 16 ) + ( data[7] << 8 ) + data[8];
381
382 /* not a full handshake */
383 if (bleft < (9 + hs_len))
384 goto too_short;
385
386 }
387 else {
388 goto not_ssl_hello;
389 }
390
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200391 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200392 smp->data.u.sint = hs_type;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100393 smp->flags = SMP_F_VOLATILE;
394
395 return 1;
396
397 too_short:
398 smp->flags = SMP_F_MAY_CHANGE;
399
400 not_ssl_hello:
401
402 return 0;
403}
404
405/* Return the version of the SSL protocol in the request. It supports both
406 * SSLv3 (TLSv1) header format for any message, and SSLv2 header format for
407 * the hello message. The SSLv3 format is described in RFC 2246 p49, and the
408 * SSLv2 format is described here, and completed p67 of RFC 2246 :
409 * http://wp.netscape.com/eng/security/SSL_2.html
410 *
411 * Note: this decoder only works with non-wrapping data.
412 */
413static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200414smp_fetch_req_ssl_ver(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100415{
416 int version, bleft, msg_len;
417 const unsigned char *data;
Willy Tarreaube508f12016-03-10 11:47:01 +0100418 struct channel *req;
419
420 if (!smp->strm)
Christopher Fauleta434a002021-03-25 11:58:51 +0100421 goto not_ssl;
422
423 /* meaningless for HTX buffers */
424 if (IS_HTX_STRM(smp->strm))
425 goto not_ssl;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100426
Willy Tarreaube508f12016-03-10 11:47:01 +0100427 req = &smp->strm->req;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100428 msg_len = 0;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200429 bleft = ci_data(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100430 if (!bleft)
431 goto too_short;
432
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200433 data = (const unsigned char *)ci_head(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100434 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
435 /* SSLv3 header format */
Lukas Tribusc93242c2015-11-05 13:59:30 +0100436 if (bleft < 11)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100437 goto too_short;
438
Lukas Tribusc93242c2015-11-05 13:59:30 +0100439 version = (data[1] << 16) + data[2]; /* record layer version: major, minor */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100440 msg_len = (data[3] << 8) + data[4]; /* record length */
441
442 /* format introduced with SSLv3 */
443 if (version < 0x00030000)
444 goto not_ssl;
445
Lukas Tribusc93242c2015-11-05 13:59:30 +0100446 /* message length between 6 and 2^14 + 2048 */
447 if (msg_len < 6 || msg_len > ((1<<14) + 2048))
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100448 goto not_ssl;
449
450 bleft -= 5; data += 5;
Lukas Tribusc93242c2015-11-05 13:59:30 +0100451
452 /* return the client hello client version, not the record layer version */
453 version = (data[4] << 16) + data[5]; /* client hello version: major, minor */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100454 } else {
455 /* SSLv2 header format, only supported for hello (msg type 1) */
456 int rlen, plen, cilen, silen, chlen;
457
458 if (*data & 0x80) {
459 if (bleft < 3)
460 goto too_short;
461 /* short header format : 15 bits for length */
462 rlen = ((data[0] & 0x7F) << 8) | data[1];
463 plen = 0;
464 bleft -= 2; data += 2;
465 } else {
466 if (bleft < 4)
467 goto too_short;
468 /* long header format : 14 bits for length + pad length */
469 rlen = ((data[0] & 0x3F) << 8) | data[1];
470 plen = data[2];
Willy Tarreau74967f62016-08-30 14:39:46 +0200471 bleft -= 3; data += 3;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100472 }
473
474 if (*data != 0x01)
475 goto not_ssl;
476 bleft--; data++;
477
478 if (bleft < 8)
479 goto too_short;
480 version = (data[0] << 16) + data[1]; /* version: major, minor */
481 cilen = (data[2] << 8) + data[3]; /* cipher len, multiple of 3 */
482 silen = (data[4] << 8) + data[5]; /* session_id_len: 0 or 16 */
483 chlen = (data[6] << 8) + data[7]; /* 16<=challenge length<=32 */
484
485 bleft -= 8; data += 8;
486 if (cilen % 3 != 0)
487 goto not_ssl;
488 if (silen && silen != 16)
489 goto not_ssl;
490 if (chlen < 16 || chlen > 32)
491 goto not_ssl;
492 if (rlen != 9 + cilen + silen + chlen)
493 goto not_ssl;
494
495 /* focus on the remaining data length */
496 msg_len = cilen + silen + chlen + plen;
497 }
498 /* We could recursively check that the buffer ends exactly on an SSL
499 * fragment boundary and that a possible next segment is still SSL,
500 * but that's a bit pointless. However, we could still check that
501 * all the part of the request which fits in a buffer is already
502 * there.
503 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200504 if (msg_len > channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req))
505 msg_len = channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100506
507 if (bleft < msg_len)
508 goto too_short;
509
510 /* OK that's enough. We have at least the whole message, and we have
511 * the protocol version.
512 */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200513 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200514 smp->data.u.sint = version;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100515 smp->flags = SMP_F_VOLATILE;
516 return 1;
517
518 too_short:
519 smp->flags = SMP_F_MAY_CHANGE;
520 not_ssl:
521 return 0;
522}
523
524/* Try to extract the Server Name Indication that may be presented in a TLS
525 * client hello handshake message. The format of the message is the following
526 * (cf RFC5246 + RFC6066) :
527 * TLS frame :
528 * - uint8 type = 0x16 (Handshake)
529 * - uint16 version >= 0x0301 (TLSv1)
530 * - uint16 length (frame length)
531 * - TLS handshake :
532 * - uint8 msg_type = 0x01 (ClientHello)
533 * - uint24 length (handshake message length)
534 * - ClientHello :
535 * - uint16 client_version >= 0x0301 (TLSv1)
536 * - uint8 Random[32] (4 first ones are timestamp)
537 * - SessionID :
538 * - uint8 session_id_len (0..32) (SessionID len in bytes)
539 * - uint8 session_id[session_id_len]
540 * - CipherSuite :
541 * - uint16 cipher_len >= 2 (Cipher length in bytes)
542 * - uint16 ciphers[cipher_len/2]
543 * - CompressionMethod :
544 * - uint8 compression_len >= 1 (# of supported methods)
545 * - uint8 compression_methods[compression_len]
546 * - optional client_extension_len (in bytes)
547 * - optional sequence of ClientHelloExtensions (as many bytes as above):
548 * - uint16 extension_type = 0 for server_name
549 * - uint16 extension_len
550 * - opaque extension_data[extension_len]
551 * - uint16 server_name_list_len (# of bytes here)
552 * - opaque server_names[server_name_list_len bytes]
553 * - uint8 name_type = 0 for host_name
554 * - uint16 name_len
555 * - opaque hostname[name_len bytes]
556 */
557static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200558smp_fetch_ssl_hello_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100559{
560 int hs_len, ext_len, bleft;
561 struct channel *chn;
562 unsigned char *data;
563
Willy Tarreaube508f12016-03-10 11:47:01 +0100564 if (!smp->strm)
565 goto not_ssl_hello;
566
Christopher Fauleta434a002021-03-25 11:58:51 +0100567 /* meaningless for HTX buffers */
568 if (IS_HTX_STRM(smp->strm))
569 goto not_ssl_hello;
570
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200571 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200572 bleft = ci_data(chn);
573 data = (unsigned char *)ci_head(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100574
575 /* Check for SSL/TLS Handshake */
576 if (!bleft)
577 goto too_short;
578 if (*data != 0x16)
579 goto not_ssl_hello;
580
Lukas Tribus57d22972014-04-10 21:36:22 +0200581 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100582 if (bleft < 3)
583 goto too_short;
Lukas Tribus57d22972014-04-10 21:36:22 +0200584 if (data[1] < 0x03)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100585 goto not_ssl_hello;
586
587 if (bleft < 5)
588 goto too_short;
589 hs_len = (data[3] << 8) + data[4];
590 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
591 goto not_ssl_hello; /* too short to have an extension */
592
593 data += 5; /* enter TLS handshake */
594 bleft -= 5;
595
596 /* Check for a complete client hello starting at <data> */
597 if (bleft < 1)
598 goto too_short;
599 if (data[0] != 0x01) /* msg_type = Client Hello */
600 goto not_ssl_hello;
601
602 /* Check the Hello's length */
603 if (bleft < 4)
604 goto too_short;
605 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
606 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
607 goto not_ssl_hello; /* too short to have an extension */
608
609 /* We want the full handshake here */
610 if (bleft < hs_len)
611 goto too_short;
612
613 data += 4;
614 /* Start of the ClientHello message */
615 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
616 goto not_ssl_hello;
617
618 ext_len = data[34]; /* session_id_len */
619 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
620 goto not_ssl_hello;
621
622 /* Jump to cipher suite */
623 hs_len -= 35 + ext_len;
624 data += 35 + ext_len;
625
626 if (hs_len < 4 || /* minimum one cipher */
627 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
628 ext_len > hs_len)
629 goto not_ssl_hello;
630
631 /* Jump to the compression methods */
632 hs_len -= 2 + ext_len;
633 data += 2 + ext_len;
634
635 if (hs_len < 2 || /* minimum one compression method */
636 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
637 goto not_ssl_hello;
638
639 /* Jump to the extensions */
640 hs_len -= 1 + data[0];
641 data += 1 + data[0];
642
643 if (hs_len < 2 || /* minimum one extension list length */
644 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
645 goto not_ssl_hello;
646
647 hs_len = ext_len; /* limit ourselves to the extension length */
648 data += 2;
649
650 while (hs_len >= 4) {
651 int ext_type, name_type, srv_len, name_len;
652
653 ext_type = (data[0] << 8) + data[1];
654 ext_len = (data[2] << 8) + data[3];
655
656 if (ext_len > hs_len - 4) /* Extension too long */
657 goto not_ssl_hello;
658
659 if (ext_type == 0) { /* Server name */
660 if (ext_len < 2) /* need one list length */
661 goto not_ssl_hello;
662
663 srv_len = (data[4] << 8) + data[5];
664 if (srv_len < 4 || srv_len > hs_len - 6)
665 goto not_ssl_hello; /* at least 4 bytes per server name */
666
667 name_type = data[6];
668 name_len = (data[7] << 8) + data[8];
669
670 if (name_type == 0) { /* hostname */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200671 smp->data.type = SMP_T_STR;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200672 smp->data.u.str.area = (char *)data + 9;
673 smp->data.u.str.data = name_len;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100674 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100675 return 1;
676 }
677 }
678
679 hs_len -= 4 + ext_len;
680 data += 4 + ext_len;
681 }
682 /* server name not found */
683 goto not_ssl_hello;
684
685 too_short:
686 smp->flags = SMP_F_MAY_CHANGE;
687
688 not_ssl_hello:
689
690 return 0;
691}
692
Alex Zorin4afdd132018-12-30 13:56:28 +1100693/* Try to extract the Application-Layer Protocol Negotiation (ALPN) protocol
694 * names that may be presented in a TLS client hello handshake message. As the
695 * message presents a list of protocol names in descending order of preference,
696 * it may return iteratively. The format of the message is the following
697 * (cf RFC5246 + RFC7301) :
698 * TLS frame :
699 * - uint8 type = 0x16 (Handshake)
700 * - uint16 version >= 0x0301 (TLSv1)
701 * - uint16 length (frame length)
702 * - TLS handshake :
703 * - uint8 msg_type = 0x01 (ClientHello)
704 * - uint24 length (handshake message length)
705 * - ClientHello :
706 * - uint16 client_version >= 0x0301 (TLSv1)
707 * - uint8 Random[32] (4 first ones are timestamp)
708 * - SessionID :
709 * - uint8 session_id_len (0..32) (SessionID len in bytes)
710 * - uint8 session_id[session_id_len]
711 * - CipherSuite :
712 * - uint16 cipher_len >= 2 (Cipher length in bytes)
713 * - uint16 ciphers[cipher_len/2]
714 * - CompressionMethod :
715 * - uint8 compression_len >= 1 (# of supported methods)
716 * - uint8 compression_methods[compression_len]
717 * - optional client_extension_len (in bytes)
718 * - optional sequence of ClientHelloExtensions (as many bytes as above):
719 * - uint16 extension_type = 16 for application_layer_protocol_negotiation
720 * - uint16 extension_len
721 * - opaque extension_data[extension_len]
722 * - uint16 protocol_names_len (# of bytes here)
723 * - opaque protocol_names[protocol_names_len bytes]
724 * - uint8 name_len
725 * - opaque protocol_name[name_len bytes]
726 */
727static int
728smp_fetch_ssl_hello_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
729{
730 int hs_len, ext_len, bleft;
731 struct channel *chn;
732 unsigned char *data;
733
734 if (!smp->strm)
735 goto not_ssl_hello;
736
Christopher Fauleta434a002021-03-25 11:58:51 +0100737 /* meaningless for HTX buffers */
738 if (IS_HTX_STRM(smp->strm))
739 goto not_ssl_hello;
740
Alex Zorin4afdd132018-12-30 13:56:28 +1100741 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
742 bleft = ci_data(chn);
743 data = (unsigned char *)ci_head(chn);
744
745 /* Check for SSL/TLS Handshake */
746 if (!bleft)
747 goto too_short;
748 if (*data != 0x16)
749 goto not_ssl_hello;
750
751 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
752 if (bleft < 3)
753 goto too_short;
754 if (data[1] < 0x03)
755 goto not_ssl_hello;
756
757 if (bleft < 5)
758 goto too_short;
759 hs_len = (data[3] << 8) + data[4];
760 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
761 goto not_ssl_hello; /* too short to have an extension */
762
763 data += 5; /* enter TLS handshake */
764 bleft -= 5;
765
766 /* Check for a complete client hello starting at <data> */
767 if (bleft < 1)
768 goto too_short;
769 if (data[0] != 0x01) /* msg_type = Client Hello */
770 goto not_ssl_hello;
771
772 /* Check the Hello's length */
773 if (bleft < 4)
774 goto too_short;
775 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
776 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
777 goto not_ssl_hello; /* too short to have an extension */
778
779 /* We want the full handshake here */
780 if (bleft < hs_len)
781 goto too_short;
782
783 data += 4;
784 /* Start of the ClientHello message */
785 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
786 goto not_ssl_hello;
787
788 ext_len = data[34]; /* session_id_len */
789 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
790 goto not_ssl_hello;
791
792 /* Jump to cipher suite */
793 hs_len -= 35 + ext_len;
794 data += 35 + ext_len;
795
796 if (hs_len < 4 || /* minimum one cipher */
797 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
798 ext_len > hs_len)
799 goto not_ssl_hello;
800
801 /* Jump to the compression methods */
802 hs_len -= 2 + ext_len;
803 data += 2 + ext_len;
804
805 if (hs_len < 2 || /* minimum one compression method */
806 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
807 goto not_ssl_hello;
808
809 /* Jump to the extensions */
810 hs_len -= 1 + data[0];
811 data += 1 + data[0];
812
813 if (hs_len < 2 || /* minimum one extension list length */
814 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
815 goto not_ssl_hello;
816
817 hs_len = ext_len; /* limit ourselves to the extension length */
818 data += 2;
819
820 while (hs_len >= 4) {
821 int ext_type, name_len, name_offset;
822
823 ext_type = (data[0] << 8) + data[1];
824 ext_len = (data[2] << 8) + data[3];
825
826 if (ext_len > hs_len - 4) /* Extension too long */
827 goto not_ssl_hello;
828
829 if (ext_type == 16) { /* ALPN */
830 if (ext_len < 3) /* one list length [uint16] + at least one name length [uint8] */
831 goto not_ssl_hello;
832
833 /* Name cursor in ctx, must begin after protocol_names_len */
834 name_offset = smp->ctx.i < 6 ? 6 : smp->ctx.i;
835 name_len = data[name_offset];
836
837 if (name_len + name_offset - 3 > ext_len)
838 goto not_ssl_hello;
839
840 smp->data.type = SMP_T_STR;
841 smp->data.u.str.area = (char *)data + name_offset + 1; /* +1 to skip name_len */
842 smp->data.u.str.data = name_len;
843 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
844
845 /* May have more protocol names remaining */
846 if (name_len + name_offset - 3 < ext_len) {
847 smp->ctx.i = name_offset + name_len + 1;
848 smp->flags |= SMP_F_NOT_LAST;
849 }
850
851 return 1;
852 }
853
854 hs_len -= 4 + ext_len;
855 data += 4 + ext_len;
856 }
857 /* alpn not found */
858 goto not_ssl_hello;
859
860 too_short:
861 smp->flags = SMP_F_MAY_CHANGE;
862
863 not_ssl_hello:
864
865 return 0;
866}
867
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200868/* Fetch the request RDP cookie identified in <cname>:<clen>, or any cookie if
Willy Tarreaub169eba2013-12-16 15:14:43 +0100869 * <clen> is empty (cname is then ignored). It returns the data into sample <smp>
870 * of type SMP_T_CSTR. Note: this decoder only works with non-wrapping data.
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100871 */
872int
Willy Tarreau87b09662015-04-03 00:22:06 +0200873fetch_rdp_cookie_name(struct stream *s, struct sample *smp, const char *cname, int clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100874{
875 int bleft;
876 const unsigned char *data;
877
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100878 smp->flags = SMP_F_CONST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200879 smp->data.type = SMP_T_STR;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100880
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200881 bleft = ci_data(&s->req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100882 if (bleft <= 11)
883 goto too_short;
884
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200885 data = (const unsigned char *)ci_head(&s->req) + 11;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100886 bleft -= 11;
887
888 if (bleft <= 7)
889 goto too_short;
890
891 if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
892 goto not_cookie;
893
894 data += 7;
895 bleft -= 7;
896
897 while (bleft > 0 && *data == ' ') {
898 data++;
899 bleft--;
900 }
901
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200902 if (clen) {
903 if (bleft <= clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100904 goto too_short;
905
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200906 if ((data[clen] != '=') ||
907 strncasecmp(cname, (const char *)data, clen) != 0)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100908 goto not_cookie;
909
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200910 data += clen + 1;
911 bleft -= clen + 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100912 } else {
913 while (bleft > 0 && *data != '=') {
914 if (*data == '\r' || *data == '\n')
915 goto not_cookie;
916 data++;
917 bleft--;
918 }
919
920 if (bleft < 1)
921 goto too_short;
922
923 if (*data != '=')
924 goto not_cookie;
925
926 data++;
927 bleft--;
928 }
929
930 /* data points to cookie value */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200931 smp->data.u.str.area = (char *)data;
932 smp->data.u.str.data = 0;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100933
934 while (bleft > 0 && *data != '\r') {
935 data++;
936 bleft--;
937 }
938
939 if (bleft < 2)
940 goto too_short;
941
942 if (data[0] != '\r' || data[1] != '\n')
943 goto not_cookie;
944
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200945 smp->data.u.str.data = (char *)data - smp->data.u.str.area;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100946 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100947 return 1;
948
949 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100950 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100951 not_cookie:
952 return 0;
953}
954
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200955/* Fetch the request RDP cookie identified in the args, or any cookie if no arg
956 * is passed. It is usable both for ACL and for samples. Note: this decoder
957 * only works with non-wrapping data. Accepts either 0 or 1 argument. Argument
Willy Tarreaub169eba2013-12-16 15:14:43 +0100958 * is a string (cookie name), other types will lead to undefined behaviour. The
959 * returned sample has type SMP_T_CSTR.
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200960 */
961int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200962smp_fetch_rdp_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200963{
Willy Tarreaube508f12016-03-10 11:47:01 +0100964 if (!smp->strm)
965 return 0;
966
Christopher Fauleta434a002021-03-25 11:58:51 +0100967 /* meaningless for HTX buffers */
968 if (IS_HTX_STRM(smp->strm))
969 return 0;
970
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200971 return fetch_rdp_cookie_name(smp->strm, smp,
972 args ? args->data.str.area : NULL,
973 args ? args->data.str.data : 0);
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200974}
975
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100976/* returns either 1 or 0 depending on whether an RDP cookie is found or not */
977static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200978smp_fetch_rdp_cookie_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100979{
980 int ret;
981
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200982 ret = smp_fetch_rdp_cookie(args, smp, kw, private);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100983
984 if (smp->flags & SMP_F_MAY_CHANGE)
985 return 0;
986
987 smp->flags = SMP_F_VOLATILE;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200988 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200989 smp->data.u.sint = ret;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100990 return 1;
991}
992
993/* extracts part of a payload with offset and length at a given position */
994static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200995smp_fetch_payload_lv(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100996{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200997 unsigned int len_offset = arg_p[0].data.sint;
998 unsigned int len_size = arg_p[1].data.sint;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100999 unsigned int buf_offset;
1000 unsigned int buf_size = 0;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001001 struct channel *chn = NULL;
1002 char *head = NULL;
1003 size_t max, data;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001004 int i;
1005
1006 /* Format is (len offset, len size, buf offset) or (len offset, len size) */
1007 /* by default buf offset == len offset + len size */
1008 /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
1009
Christopher Faulet78f371e2020-04-30 09:38:08 +02001010 if (smp->strm) {
Christopher Fauleta434a002021-03-25 11:58:51 +01001011 /* meaningless for HTX buffers */
1012 if (IS_HTX_STRM(smp->strm))
1013 return 0;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001014 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1015 head = ci_head(chn);
1016 data = ci_data(chn);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001017 }
Christopher Fauletf98e6262020-05-06 09:42:04 +02001018 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Fauleta434a002021-03-25 11:58:51 +01001019 struct check *check = __objt_check(smp->sess->origin);
1020
1021 /* meaningless for HTX buffers */
1022 if (check->cs && IS_HTX_CS(check->cs))
1023 return 0;
1024 head = b_head(&check->bi);
1025 data = b_data(&check->bi);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001026 }
Christopher Fauletbb9fb8b2020-11-25 17:20:57 +01001027 max = global.tune.bufsize;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001028 if (!head)
Christopher Faulet50623022021-03-29 11:09:45 +02001029 goto too_short;
Willy Tarreaube508f12016-03-10 11:47:01 +01001030
Christopher Faulet78f371e2020-04-30 09:38:08 +02001031 if (len_offset + len_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001032 goto too_short;
1033
1034 for (i = 0; i < len_size; i++) {
Christopher Faulet78f371e2020-04-30 09:38:08 +02001035 buf_size = (buf_size << 8) + ((unsigned char *)head)[i + len_offset];
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001036 }
1037
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001038 /* buf offset may be implicit, absolute or relative. If the LSB
1039 * is set, then the offset is relative otherwise it is absolute.
1040 */
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001041 buf_offset = len_offset + len_size;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001042 if (arg_p[2].type == ARGT_SINT) {
1043 if (arg_p[2].data.sint & 1)
1044 buf_offset += arg_p[2].data.sint >> 1;
1045 else
1046 buf_offset = arg_p[2].data.sint >> 1;
1047 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001048
Christopher Faulet78f371e2020-04-30 09:38:08 +02001049 if (!buf_size || buf_size > max || buf_offset + buf_size > max) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001050 /* will never match */
1051 smp->flags = 0;
1052 return 0;
1053 }
1054
Christopher Faulet78f371e2020-04-30 09:38:08 +02001055 if (buf_offset + buf_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001056 goto too_short;
1057
1058 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001059 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001060 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001061 chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001062 return 1;
1063
1064 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001065 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001066 return 0;
1067}
1068
1069/* extracts some payload at a fixed position and length */
1070static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +02001071smp_fetch_payload(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001072{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001073 unsigned int buf_offset = arg_p[0].data.sint;
1074 unsigned int buf_size = arg_p[1].data.sint;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001075 struct channel *chn = NULL;
1076 char *head = NULL;
1077 size_t max, data;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001078
Christopher Faulet78f371e2020-04-30 09:38:08 +02001079 if (smp->strm) {
Christopher Fauleta434a002021-03-25 11:58:51 +01001080 /* meaningless for HTX buffers */
1081 if (IS_HTX_STRM(smp->strm))
1082 return 0;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001083 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1084 head = ci_head(chn);
1085 data = ci_data(chn);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001086 }
Christopher Fauletf98e6262020-05-06 09:42:04 +02001087 else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) {
Christopher Fauleta434a002021-03-25 11:58:51 +01001088 struct check *check = __objt_check(smp->sess->origin);
1089
1090 /* meaningless for HTX buffers */
1091 if (check->cs && IS_HTX_CS(check->cs))
1092 return 0;
1093 head = b_head(&check->bi);
1094 data = b_data(&check->bi);
Christopher Faulet78f371e2020-04-30 09:38:08 +02001095 }
Christopher Fauletbb9fb8b2020-11-25 17:20:57 +01001096 max = global.tune.bufsize;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001097 if (!head)
Christopher Faulet50623022021-03-29 11:09:45 +02001098 goto too_short;
Willy Tarreaube508f12016-03-10 11:47:01 +01001099
Christopher Faulet78f371e2020-04-30 09:38:08 +02001100 if (buf_size > max || buf_offset + buf_size > max) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001101 /* will never match */
1102 smp->flags = 0;
1103 return 0;
1104 }
Christopher Faulet78f371e2020-04-30 09:38:08 +02001105 if (buf_offset + buf_size > data)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001106 goto too_short;
1107
1108 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001109 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001110 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Christopher Faulet78f371e2020-04-30 09:38:08 +02001111 chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size ? buf_size : (data - buf_offset));
1112
1113 if (!buf_size && chn && channel_may_recv(chn) && !channel_input_closed(chn))
Willy Tarreau00f00842013-08-02 11:07:32 +02001114 smp->flags |= SMP_F_MAY_CHANGE;
1115
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001116 return 1;
1117
Christopher Faulet78f371e2020-04-30 09:38:08 +02001118 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001119 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001120 return 0;
1121}
1122
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001123/* This function is used to validate the arguments passed to a "payload_lv" fetch
1124 * keyword. This keyword allows two positive integers and an optional signed one,
1125 * with the second one being strictly positive and the third one being greater than
1126 * the opposite of the two others if negative. It is assumed that the types are
1127 * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> is
1128 * not NULL, it will be filled with a pointer to an error message in case of
1129 * error, that the caller is responsible for freeing. The initial location must
1130 * either be freeable or NULL.
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001131 *
1132 * Note that offset2 is stored with SINT type, but its not directly usable as is.
1133 * The value is contained in the 63 MSB and the LSB is used as a flag for marking
1134 * the "relative" property of the value.
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001135 */
Thierry FOURNIER49f45af2014-12-08 19:50:43 +01001136int val_payload_lv(struct arg *arg, char **err_msg)
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001137{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001138 int relative = 0;
1139 const char *str;
1140
1141 if (arg[0].data.sint < 0) {
1142 memprintf(err_msg, "payload offset1 must be positive");
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001143 return 0;
1144 }
1145
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001146 if (!arg[1].data.sint) {
1147 memprintf(err_msg, "payload length must be > 0");
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001148 return 0;
1149 }
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001150
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001151 if (arg[2].type == ARGT_STR && arg[2].data.str.data > 0) {
Christopher Faulet95917132020-08-05 23:07:07 +02001152 long long int i;
1153
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001154 if (arg[2].data.str.area[0] == '+' || arg[2].data.str.area[0] == '-')
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001155 relative = 1;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001156 str = arg[2].data.str.area;
Christopher Faulet95917132020-08-05 23:07:07 +02001157 i = read_int64(&str, str + arg[2].data.str.data);
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001158 if (*str != '\0') {
1159 memprintf(err_msg, "payload offset2 is not a number");
1160 return 0;
1161 }
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001162 chunk_destroy(&arg[2].data.str);
Christopher Faulet95917132020-08-05 23:07:07 +02001163 arg[2].type = ARGT_SINT;
1164 arg[2].data.sint = i;
1165
1166 if (arg[0].data.sint + arg[1].data.sint + arg[2].data.sint < 0) {
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001167 memprintf(err_msg, "payload offset2 too negative");
1168 return 0;
1169 }
1170 if (relative)
1171 arg[2].data.sint = ( arg[2].data.sint << 1 ) + 1;
1172 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001173 return 1;
1174}
1175
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001176/* extracts the parameter value of a distcc token */
1177static int
1178smp_fetch_distcc_param(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
1179{
1180 unsigned int match_tok = arg_p[0].data.sint;
1181 unsigned int match_occ = arg_p[1].data.sint;
1182 unsigned int token;
1183 unsigned int param;
1184 unsigned int body;
1185 unsigned int ofs;
1186 unsigned int occ;
1187 struct channel *chn;
1188 int i;
1189
1190 /* Format is (token[,occ]). occ starts at 1. */
1191
1192 if (!smp->strm)
1193 return 0;
1194
Christopher Fauleta434a002021-03-25 11:58:51 +01001195 /* meaningless for HTX buffers */
1196 if (IS_HTX_STRM(smp->strm))
1197 return 0;
1198
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001199 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1200
1201 ofs = 0; occ = 0;
1202 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001203 if (ofs + 12 > ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001204 /* not there yet but could it at least fit ? */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001205 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001206 goto too_short;
1207
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001208 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001209 goto too_short;
1210
1211 goto no_match;
1212 }
1213
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001214 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001215 ofs += 4;
1216
1217 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001218 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001219
1220 if (c < 0)
1221 goto no_match;
1222 param = (param << 4) + c;
1223 }
1224 ofs += 8;
1225
1226 /* these tokens don't have a body */
1227 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1228 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1229 token != 0x444F4E45 /* DONE */)
1230 body = param;
1231 else
1232 body = 0;
1233
1234 if (token == match_tok) {
1235 occ++;
1236 if (!match_occ || match_occ == occ) {
1237 /* found */
1238 smp->data.type = SMP_T_SINT;
1239 smp->data.u.sint = param;
1240 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1241 return 1;
1242 }
1243 }
1244 ofs += body;
1245 }
1246
1247 too_short:
1248 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1249 return 0;
1250 no_match:
1251 /* will never match (end of buffer, or bad contents) */
1252 smp->flags = 0;
1253 return 0;
1254
1255}
1256
1257/* extracts the (possibly truncated) body of a distcc token */
1258static int
1259smp_fetch_distcc_body(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
1260{
1261 unsigned int match_tok = arg_p[0].data.sint;
1262 unsigned int match_occ = arg_p[1].data.sint;
1263 unsigned int token;
1264 unsigned int param;
1265 unsigned int ofs;
1266 unsigned int occ;
1267 unsigned int body;
1268 struct channel *chn;
1269 int i;
1270
1271 /* Format is (token[,occ]). occ starts at 1. */
1272
1273 if (!smp->strm)
1274 return 0;
1275
Christopher Fauleta434a002021-03-25 11:58:51 +01001276 /* meaningless for HTX buffers */
1277 if (IS_HTX_STRM(smp->strm))
1278 return 0;
1279
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001280 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1281
1282 ofs = 0; occ = 0;
1283 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001284 if (ofs + 12 > ci_data(chn)) {
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001285 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001286 goto too_short;
1287
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001288 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001289 goto too_short;
1290
1291 goto no_match;
1292 }
1293
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001294 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001295 ofs += 4;
1296
1297 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001298 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001299
1300 if (c < 0)
1301 goto no_match;
1302 param = (param << 4) + c;
1303 }
1304 ofs += 8;
1305
1306 /* these tokens don't have a body */
1307 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1308 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1309 token != 0x444F4E45 /* DONE */)
1310 body = param;
1311 else
1312 body = 0;
1313
1314 if (token == match_tok) {
1315 occ++;
1316 if (!match_occ || match_occ == occ) {
1317 /* found */
1318
1319 smp->data.type = SMP_T_BIN;
1320 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1321
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001322 if (ofs + body > ci_head(chn) - b_orig(&chn->buf) + ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001323 /* incomplete body */
1324
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001325 if (ofs + body > channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001326 /* truncate it to whatever will fit */
1327 smp->flags |= SMP_F_MAY_CHANGE;
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001328 body = channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn) - ofs;
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001329 }
1330 }
1331
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001332 chunk_initlen(&smp->data.u.str, ci_head(chn) + ofs, 0, body);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001333 return 1;
1334 }
1335 }
1336 ofs += body;
1337 }
1338
1339 too_short:
1340 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1341 return 0;
1342 no_match:
1343 /* will never match (end of buffer, or bad contents) */
1344 smp->flags = 0;
1345 return 0;
1346
1347}
1348
1349/* This function is used to validate the arguments passed to a "distcc_param" or
1350 * "distcc_body" sample fetch keyword. They take a mandatory token name of exactly
1351 * 4 characters, followed by an optional occurrence number starting at 1. It is
1352 * assumed that the types are already the correct ones. Returns 0 on error, non-
1353 * zero if OK. If <err_msg> is not NULL, it will be filled with a pointer to an
1354 * error message in case of error, that the caller is responsible for freeing.
1355 * The initial location must either be freeable or NULL.
1356 */
1357int val_distcc(struct arg *arg, char **err_msg)
1358{
1359 unsigned int token;
1360
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001361 if (arg[0].data.str.data != 4) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001362 memprintf(err_msg, "token name must be exactly 4 characters");
1363 return 0;
1364 }
1365
1366 /* convert the token name to an unsigned int (one byte per character,
1367 * big endian format).
1368 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001369 token = (arg[0].data.str.area[0] << 24) + (arg[0].data.str.area[1] << 16) +
1370 (arg[0].data.str.area[2] << 8) + (arg[0].data.str.area[3] << 0);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001371
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001372 chunk_destroy(&arg[0].data.str);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001373 arg[0].type = ARGT_SINT;
1374 arg[0].data.sint = token;
1375
1376 if (arg[1].type != ARGT_SINT) {
1377 arg[1].type = ARGT_SINT;
1378 arg[1].data.sint = 0;
1379 }
1380 return 1;
1381}
1382
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001383/************************************************************************/
1384/* All supported sample and ACL keywords must be declared here. */
1385/************************************************************************/
1386
1387/* Note: must not be declared <const> as its list will be overwritten.
1388 * Note: fetches that may return multiple types must be declared as the lowest
1389 * common denominator, the type that can be casted into all other ones. For
1390 * instance IPv4/IPv6 must be declared IPv4.
1391 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001392static struct sample_fetch_kw_list smp_kws = {ILH, {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001393 { "distcc_body", smp_fetch_distcc_body, ARG2(1,STR,SINT), val_distcc, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1394 { "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 +02001395 { "payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1396 { "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 +01001397 { "rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001398 { "rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L6REQ },
1399 { "rep_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
1400 { "req_len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1401 { "req_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001402 { "req_ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001403 { "req_ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +01001404
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001405 { "req.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001406 { "req.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ },
1407 { "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 +01001408 { "req.rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001409 { "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 +02001410 { "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 +05301411 { "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 +02001412 { "req.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001413 { "req.ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Alex Zorin4afdd132018-12-30 13:56:28 +11001414 { "req.ssl_alpn", smp_fetch_ssl_hello_alpn, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001415 { "req.ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1416 { "res.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001417 { "res.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6RES },
1418 { "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 +02001419 { "res.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001420 { "wait_end", smp_fetch_wait_end, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
1421 { /* END */ },
1422}};
1423
Willy Tarreau0108d902018-11-25 19:14:37 +01001424INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001425
1426/* Note: must not be declared <const> as its list will be overwritten.
1427 * Please take care of keeping this list alphabetically sorted.
1428 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001429static struct acl_kw_list acl_kws = {ILH, {
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +01001430 { "payload", "req.payload", PAT_MATCH_BIN },
1431 { "payload_lv", "req.payload_lv", PAT_MATCH_BIN },
1432 { "req_rdp_cookie", "req.rdp_cookie", PAT_MATCH_STR },
1433 { "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", PAT_MATCH_INT },
1434 { "req_ssl_sni", "req.ssl_sni", PAT_MATCH_STR },
1435 { "req_ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
1436 { "req.ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001437 { /* END */ },
1438}};
1439
Willy Tarreau0108d902018-11-25 19:14:37 +01001440INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001441
1442/*
1443 * Local variables:
1444 * c-indent-level: 8
1445 * c-basic-offset: 8
1446 * End:
1447 */