blob: 14191a7e20e0a758715904dec227e1c90040cae6 [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 Tarreau0108d902018-11-25 19:14:37 +010016#include <common/initcall.h>
Willy Tarreaud716f9b2017-10-13 11:03:15 +020017#include <common/net_helper.h>
Willy Tarreaud4c33c82013-01-07 21:59:07 +010018#include <proto/acl.h>
19#include <proto/arg.h>
20#include <proto/channel.h>
Thierry FOURNIERed66c292013-11-28 11:05:19 +010021#include <proto/pattern.h>
Willy Tarreaud4c33c82013-01-07 21:59:07 +010022#include <proto/payload.h>
23#include <proto/sample.h>
24
25
26/************************************************************************/
27/* All supported sample fetch functions must be declared here */
28/************************************************************************/
29
30/* wait for more data as long as possible, then return TRUE. This should be
31 * used with content inspection.
32 */
33static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020034smp_fetch_wait_end(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010035{
Thierry FOURNIER0786d052015-05-11 15:42:45 +020036 if (!(smp->opt & SMP_OPT_FINAL)) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +010037 smp->flags |= SMP_F_MAY_CHANGE;
38 return 0;
39 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020040 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020041 smp->data.u.sint = 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +010042 return 1;
43}
44
45/* return the number of bytes in the request buffer */
46static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +020047smp_fetch_len(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +010048{
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010049 struct channel *chn;
50
Willy Tarreaube508f12016-03-10 11:47:01 +010051 if (!smp->strm)
52 return 0;
53
Thierry FOURNIER0786d052015-05-11 15:42:45 +020054 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +020055 smp->data.type = SMP_T_SINT;
Willy Tarreaufc0785d2018-06-19 07:19:56 +020056 smp->data.u.sint = ci_data(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +010057 smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
58 return 1;
59}
60
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053061/* Returns 0 if the client didn't send a SessionTicket Extension
62 * Returns 1 if the client sent SessionTicket Extension
63 * Returns 2 if the client also sent non-zero length SessionTicket
64 * Returns SMP_T_SINT data type
65 */
66static int
67smp_fetch_req_ssl_st_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
68{
69 int hs_len, ext_len, bleft;
70 struct channel *chn;
71 unsigned char *data;
72
Willy Tarreaube508f12016-03-10 11:47:01 +010073 if (!smp->strm)
74 goto not_ssl_hello;
75
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053076 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +020077 bleft = ci_data(chn);
78 data = (unsigned char *)ci_head(chn);
Pradeep Jindalbb2acf52015-09-29 10:12:57 +053079
80 /* Check for SSL/TLS Handshake */
81 if (!bleft)
82 goto too_short;
83 if (*data != 0x16)
84 goto not_ssl_hello;
85
86 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
87 if (bleft < 3)
88 goto too_short;
89 if (data[1] < 0x03)
90 goto not_ssl_hello;
91
92 if (bleft < 5)
93 goto too_short;
94 hs_len = (data[3] << 8) + data[4];
95 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
96 goto not_ssl_hello; /* too short to have an extension */
97
98 data += 5; /* enter TLS handshake */
99 bleft -= 5;
100
101 /* Check for a complete client hello starting at <data> */
102 if (bleft < 1)
103 goto too_short;
104 if (data[0] != 0x01) /* msg_type = Client Hello */
105 goto not_ssl_hello;
106
107 /* Check the Hello's length */
108 if (bleft < 4)
109 goto too_short;
110 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
111 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
112 goto not_ssl_hello; /* too short to have an extension */
113
114 /* We want the full handshake here */
115 if (bleft < hs_len)
116 goto too_short;
117
118 data += 4;
119 /* Start of the ClientHello message */
120 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
121 goto not_ssl_hello;
122
123 ext_len = data[34]; /* session_id_len */
124 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
125 goto not_ssl_hello;
126
127 /* Jump to cipher suite */
128 hs_len -= 35 + ext_len;
129 data += 35 + ext_len;
130
131 if (hs_len < 4 || /* minimum one cipher */
132 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
133 ext_len > hs_len)
134 goto not_ssl_hello;
135
136 /* Jump to the compression methods */
137 hs_len -= 2 + ext_len;
138 data += 2 + ext_len;
139
140 if (hs_len < 2 || /* minimum one compression method */
141 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
142 goto not_ssl_hello;
143
144 /* Jump to the extensions */
145 hs_len -= 1 + data[0];
146 data += 1 + data[0];
147
148 if (hs_len < 2 || /* minimum one extension list length */
149 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
150 goto not_ssl_hello;
151
152 hs_len = ext_len; /* limit ourselves to the extension length */
153 data += 2;
154
155 while (hs_len >= 4) {
156 int ext_type, ext_len;
157
158 ext_type = (data[0] << 8) + data[1];
159 ext_len = (data[2] << 8) + data[3];
160
161 if (ext_len > hs_len - 4) /* Extension too long */
162 goto not_ssl_hello;
163
164 /* SesstionTicket extension */
165 if (ext_type == 35) {
166 smp->data.type = SMP_T_SINT;
167 /* SessionTicket also present */
168 if (ext_len > 0)
169 smp->data.u.sint = 2;
170 /* SessionTicket absent */
171 else
172 smp->data.u.sint = 1;
173 smp->flags = SMP_F_VOLATILE;
174 return 1;
175 }
176
177 hs_len -= 4 + ext_len;
178 data += 4 + ext_len;
179 }
180 /* SessionTicket Extension not found */
181 smp->data.type = SMP_T_SINT;
182 smp->data.u.sint = 0;
183 smp->flags = SMP_F_VOLATILE;
184 return 1;
185
Pradeep Jindalbb2acf52015-09-29 10:12:57 +0530186 too_short:
187 smp->flags = SMP_F_MAY_CHANGE;
188
189 not_ssl_hello:
190 return 0;
191}
192
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200193/* Returns TRUE if the client sent Supported Elliptic Curves Extension (0x000a)
194 * Mainly used to detect if client supports ECC cipher suites.
195 */
196static int
197smp_fetch_req_ssl_ec_ext(const struct arg *args, struct sample *smp, const char *kw, void *private)
198{
199 int hs_len, ext_len, bleft;
200 struct channel *chn;
201 unsigned char *data;
202
Willy Tarreaube508f12016-03-10 11:47:01 +0100203 if (!smp->strm)
204 goto not_ssl_hello;
205
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200206 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200207 bleft = ci_data(chn);
208 data = (unsigned char *)ci_head(chn);
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200209
210 /* Check for SSL/TLS Handshake */
211 if (!bleft)
212 goto too_short;
213 if (*data != 0x16)
214 goto not_ssl_hello;
215
216 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
217 if (bleft < 3)
218 goto too_short;
219 if (data[1] < 0x03)
220 goto not_ssl_hello;
221
222 if (bleft < 5)
223 goto too_short;
224 hs_len = (data[3] << 8) + data[4];
225 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
226 goto not_ssl_hello; /* too short to have an extension */
227
228 data += 5; /* enter TLS handshake */
229 bleft -= 5;
230
231 /* Check for a complete client hello starting at <data> */
232 if (bleft < 1)
233 goto too_short;
234 if (data[0] != 0x01) /* msg_type = Client Hello */
235 goto not_ssl_hello;
236
237 /* Check the Hello's length */
238 if (bleft < 4)
239 goto too_short;
240 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
241 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
242 goto not_ssl_hello; /* too short to have an extension */
243
244 /* We want the full handshake here */
245 if (bleft < hs_len)
246 goto too_short;
247
248 data += 4;
249 /* Start of the ClientHello message */
250 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
251 goto not_ssl_hello;
252
253 ext_len = data[34]; /* session_id_len */
254 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
255 goto not_ssl_hello;
256
257 /* Jump to cipher suite */
258 hs_len -= 35 + ext_len;
259 data += 35 + ext_len;
260
261 if (hs_len < 4 || /* minimum one cipher */
262 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
263 ext_len > hs_len)
264 goto not_ssl_hello;
265
266 /* Jump to the compression methods */
267 hs_len -= 2 + ext_len;
268 data += 2 + ext_len;
269
270 if (hs_len < 2 || /* minimum one compression method */
271 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
272 goto not_ssl_hello;
273
274 /* Jump to the extensions */
275 hs_len -= 1 + data[0];
276 data += 1 + data[0];
277
278 if (hs_len < 2 || /* minimum one extension list length */
279 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
280 goto not_ssl_hello;
281
282 hs_len = ext_len; /* limit ourselves to the extension length */
283 data += 2;
284
285 while (hs_len >= 4) {
286 int ext_type, ext_len;
287
288 ext_type = (data[0] << 8) + data[1];
289 ext_len = (data[2] << 8) + data[3];
290
291 if (ext_len > hs_len - 4) /* Extension too long */
292 goto not_ssl_hello;
293
294 /* Elliptic curves extension */
295 if (ext_type == 10) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200296 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200297 smp->data.u.sint = 1;
Nenad Merdanovic8a39a1f2015-07-15 12:51:11 +0200298 smp->flags = SMP_F_VOLATILE;
Nenad Merdanovic5fc7d7e2015-07-07 22:00:17 +0200299 return 1;
300 }
301
302 hs_len -= 4 + ext_len;
303 data += 4 + ext_len;
304 }
305 /* server name not found */
306 goto not_ssl_hello;
307
308 too_short:
309 smp->flags = SMP_F_MAY_CHANGE;
310
311 not_ssl_hello:
312
313 return 0;
314}
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100315/* returns the type of SSL hello message (mainly used to detect an SSL hello) */
316static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200317smp_fetch_ssl_hello_type(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100318{
319 int hs_len;
320 int hs_type, bleft;
321 struct channel *chn;
322 const unsigned char *data;
323
Willy Tarreaube508f12016-03-10 11:47:01 +0100324 if (!smp->strm)
325 goto not_ssl_hello;
326
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200327 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200328 bleft = ci_data(chn);
329 data = (const unsigned char *)ci_head(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100330
331 if (!bleft)
332 goto too_short;
333
334 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
335 /* SSLv3 header format */
336 if (bleft < 9)
337 goto too_short;
338
339 /* ssl version 3 */
340 if ((data[1] << 16) + data[2] < 0x00030000)
341 goto not_ssl_hello;
342
343 /* ssl message len must present handshake type and len */
344 if ((data[3] << 8) + data[4] < 4)
345 goto not_ssl_hello;
346
347 /* format introduced with SSLv3 */
348
349 hs_type = (int)data[5];
350 hs_len = ( data[6] << 16 ) + ( data[7] << 8 ) + data[8];
351
352 /* not a full handshake */
353 if (bleft < (9 + hs_len))
354 goto too_short;
355
356 }
357 else {
358 goto not_ssl_hello;
359 }
360
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200361 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200362 smp->data.u.sint = hs_type;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100363 smp->flags = SMP_F_VOLATILE;
364
365 return 1;
366
367 too_short:
368 smp->flags = SMP_F_MAY_CHANGE;
369
370 not_ssl_hello:
371
372 return 0;
373}
374
375/* Return the version of the SSL protocol in the request. It supports both
376 * SSLv3 (TLSv1) header format for any message, and SSLv2 header format for
377 * the hello message. The SSLv3 format is described in RFC 2246 p49, and the
378 * SSLv2 format is described here, and completed p67 of RFC 2246 :
379 * http://wp.netscape.com/eng/security/SSL_2.html
380 *
381 * Note: this decoder only works with non-wrapping data.
382 */
383static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200384smp_fetch_req_ssl_ver(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100385{
386 int version, bleft, msg_len;
387 const unsigned char *data;
Willy Tarreaube508f12016-03-10 11:47:01 +0100388 struct channel *req;
389
390 if (!smp->strm)
391 return 0;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100392
Willy Tarreaube508f12016-03-10 11:47:01 +0100393 req = &smp->strm->req;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100394 msg_len = 0;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200395 bleft = ci_data(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100396 if (!bleft)
397 goto too_short;
398
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200399 data = (const unsigned char *)ci_head(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100400 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
401 /* SSLv3 header format */
Lukas Tribusc93242c2015-11-05 13:59:30 +0100402 if (bleft < 11)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100403 goto too_short;
404
Lukas Tribusc93242c2015-11-05 13:59:30 +0100405 version = (data[1] << 16) + data[2]; /* record layer version: major, minor */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100406 msg_len = (data[3] << 8) + data[4]; /* record length */
407
408 /* format introduced with SSLv3 */
409 if (version < 0x00030000)
410 goto not_ssl;
411
Lukas Tribusc93242c2015-11-05 13:59:30 +0100412 /* message length between 6 and 2^14 + 2048 */
413 if (msg_len < 6 || msg_len > ((1<<14) + 2048))
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100414 goto not_ssl;
415
416 bleft -= 5; data += 5;
Lukas Tribusc93242c2015-11-05 13:59:30 +0100417
418 /* return the client hello client version, not the record layer version */
419 version = (data[4] << 16) + data[5]; /* client hello version: major, minor */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100420 } else {
421 /* SSLv2 header format, only supported for hello (msg type 1) */
422 int rlen, plen, cilen, silen, chlen;
423
424 if (*data & 0x80) {
425 if (bleft < 3)
426 goto too_short;
427 /* short header format : 15 bits for length */
428 rlen = ((data[0] & 0x7F) << 8) | data[1];
429 plen = 0;
430 bleft -= 2; data += 2;
431 } else {
432 if (bleft < 4)
433 goto too_short;
434 /* long header format : 14 bits for length + pad length */
435 rlen = ((data[0] & 0x3F) << 8) | data[1];
436 plen = data[2];
Willy Tarreau74967f62016-08-30 14:39:46 +0200437 bleft -= 3; data += 3;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100438 }
439
440 if (*data != 0x01)
441 goto not_ssl;
442 bleft--; data++;
443
444 if (bleft < 8)
445 goto too_short;
446 version = (data[0] << 16) + data[1]; /* version: major, minor */
447 cilen = (data[2] << 8) + data[3]; /* cipher len, multiple of 3 */
448 silen = (data[4] << 8) + data[5]; /* session_id_len: 0 or 16 */
449 chlen = (data[6] << 8) + data[7]; /* 16<=challenge length<=32 */
450
451 bleft -= 8; data += 8;
452 if (cilen % 3 != 0)
453 goto not_ssl;
454 if (silen && silen != 16)
455 goto not_ssl;
456 if (chlen < 16 || chlen > 32)
457 goto not_ssl;
458 if (rlen != 9 + cilen + silen + chlen)
459 goto not_ssl;
460
461 /* focus on the remaining data length */
462 msg_len = cilen + silen + chlen + plen;
463 }
464 /* We could recursively check that the buffer ends exactly on an SSL
465 * fragment boundary and that a possible next segment is still SSL,
466 * but that's a bit pointless. However, we could still check that
467 * all the part of the request which fits in a buffer is already
468 * there.
469 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200470 if (msg_len > channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req))
471 msg_len = channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100472
473 if (bleft < msg_len)
474 goto too_short;
475
476 /* OK that's enough. We have at least the whole message, and we have
477 * the protocol version.
478 */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200479 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200480 smp->data.u.sint = version;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100481 smp->flags = SMP_F_VOLATILE;
482 return 1;
483
484 too_short:
485 smp->flags = SMP_F_MAY_CHANGE;
486 not_ssl:
487 return 0;
488}
489
490/* Try to extract the Server Name Indication that may be presented in a TLS
491 * client hello handshake message. The format of the message is the following
492 * (cf RFC5246 + RFC6066) :
493 * TLS frame :
494 * - uint8 type = 0x16 (Handshake)
495 * - uint16 version >= 0x0301 (TLSv1)
496 * - uint16 length (frame length)
497 * - TLS handshake :
498 * - uint8 msg_type = 0x01 (ClientHello)
499 * - uint24 length (handshake message length)
500 * - ClientHello :
501 * - uint16 client_version >= 0x0301 (TLSv1)
502 * - uint8 Random[32] (4 first ones are timestamp)
503 * - SessionID :
504 * - uint8 session_id_len (0..32) (SessionID len in bytes)
505 * - uint8 session_id[session_id_len]
506 * - CipherSuite :
507 * - uint16 cipher_len >= 2 (Cipher length in bytes)
508 * - uint16 ciphers[cipher_len/2]
509 * - CompressionMethod :
510 * - uint8 compression_len >= 1 (# of supported methods)
511 * - uint8 compression_methods[compression_len]
512 * - optional client_extension_len (in bytes)
513 * - optional sequence of ClientHelloExtensions (as many bytes as above):
514 * - uint16 extension_type = 0 for server_name
515 * - uint16 extension_len
516 * - opaque extension_data[extension_len]
517 * - uint16 server_name_list_len (# of bytes here)
518 * - opaque server_names[server_name_list_len bytes]
519 * - uint8 name_type = 0 for host_name
520 * - uint16 name_len
521 * - opaque hostname[name_len bytes]
522 */
523static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200524smp_fetch_ssl_hello_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100525{
526 int hs_len, ext_len, bleft;
527 struct channel *chn;
528 unsigned char *data;
529
Willy Tarreaube508f12016-03-10 11:47:01 +0100530 if (!smp->strm)
531 goto not_ssl_hello;
532
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200533 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200534 bleft = ci_data(chn);
535 data = (unsigned char *)ci_head(chn);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100536
537 /* Check for SSL/TLS Handshake */
538 if (!bleft)
539 goto too_short;
540 if (*data != 0x16)
541 goto not_ssl_hello;
542
Lukas Tribus57d22972014-04-10 21:36:22 +0200543 /* Check for SSLv3 or later (SSL version >= 3.0) in the record layer*/
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100544 if (bleft < 3)
545 goto too_short;
Lukas Tribus57d22972014-04-10 21:36:22 +0200546 if (data[1] < 0x03)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100547 goto not_ssl_hello;
548
549 if (bleft < 5)
550 goto too_short;
551 hs_len = (data[3] << 8) + data[4];
552 if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
553 goto not_ssl_hello; /* too short to have an extension */
554
555 data += 5; /* enter TLS handshake */
556 bleft -= 5;
557
558 /* Check for a complete client hello starting at <data> */
559 if (bleft < 1)
560 goto too_short;
561 if (data[0] != 0x01) /* msg_type = Client Hello */
562 goto not_ssl_hello;
563
564 /* Check the Hello's length */
565 if (bleft < 4)
566 goto too_short;
567 hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
568 if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
569 goto not_ssl_hello; /* too short to have an extension */
570
571 /* We want the full handshake here */
572 if (bleft < hs_len)
573 goto too_short;
574
575 data += 4;
576 /* Start of the ClientHello message */
577 if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
578 goto not_ssl_hello;
579
580 ext_len = data[34]; /* session_id_len */
581 if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
582 goto not_ssl_hello;
583
584 /* Jump to cipher suite */
585 hs_len -= 35 + ext_len;
586 data += 35 + ext_len;
587
588 if (hs_len < 4 || /* minimum one cipher */
589 (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
590 ext_len > hs_len)
591 goto not_ssl_hello;
592
593 /* Jump to the compression methods */
594 hs_len -= 2 + ext_len;
595 data += 2 + ext_len;
596
597 if (hs_len < 2 || /* minimum one compression method */
598 data[0] < 1 || data[0] > hs_len) /* minimum 1 bytes for a method */
599 goto not_ssl_hello;
600
601 /* Jump to the extensions */
602 hs_len -= 1 + data[0];
603 data += 1 + data[0];
604
605 if (hs_len < 2 || /* minimum one extension list length */
606 (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
607 goto not_ssl_hello;
608
609 hs_len = ext_len; /* limit ourselves to the extension length */
610 data += 2;
611
612 while (hs_len >= 4) {
613 int ext_type, name_type, srv_len, name_len;
614
615 ext_type = (data[0] << 8) + data[1];
616 ext_len = (data[2] << 8) + data[3];
617
618 if (ext_len > hs_len - 4) /* Extension too long */
619 goto not_ssl_hello;
620
621 if (ext_type == 0) { /* Server name */
622 if (ext_len < 2) /* need one list length */
623 goto not_ssl_hello;
624
625 srv_len = (data[4] << 8) + data[5];
626 if (srv_len < 4 || srv_len > hs_len - 6)
627 goto not_ssl_hello; /* at least 4 bytes per server name */
628
629 name_type = data[6];
630 name_len = (data[7] << 8) + data[8];
631
632 if (name_type == 0) { /* hostname */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200633 smp->data.type = SMP_T_STR;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200634 smp->data.u.str.area = (char *)data + 9;
635 smp->data.u.str.data = name_len;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100636 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100637 return 1;
638 }
639 }
640
641 hs_len -= 4 + ext_len;
642 data += 4 + ext_len;
643 }
644 /* server name not found */
645 goto not_ssl_hello;
646
647 too_short:
648 smp->flags = SMP_F_MAY_CHANGE;
649
650 not_ssl_hello:
651
652 return 0;
653}
654
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200655/* Fetch the request RDP cookie identified in <cname>:<clen>, or any cookie if
Willy Tarreaub169eba2013-12-16 15:14:43 +0100656 * <clen> is empty (cname is then ignored). It returns the data into sample <smp>
657 * of type SMP_T_CSTR. Note: this decoder only works with non-wrapping data.
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100658 */
659int
Willy Tarreau87b09662015-04-03 00:22:06 +0200660fetch_rdp_cookie_name(struct stream *s, struct sample *smp, const char *cname, int clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100661{
662 int bleft;
663 const unsigned char *data;
664
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100665 smp->flags = SMP_F_CONST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200666 smp->data.type = SMP_T_STR;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100667
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200668 bleft = ci_data(&s->req);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100669 if (bleft <= 11)
670 goto too_short;
671
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200672 data = (const unsigned char *)ci_head(&s->req) + 11;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100673 bleft -= 11;
674
675 if (bleft <= 7)
676 goto too_short;
677
678 if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
679 goto not_cookie;
680
681 data += 7;
682 bleft -= 7;
683
684 while (bleft > 0 && *data == ' ') {
685 data++;
686 bleft--;
687 }
688
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200689 if (clen) {
690 if (bleft <= clen)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100691 goto too_short;
692
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200693 if ((data[clen] != '=') ||
694 strncasecmp(cname, (const char *)data, clen) != 0)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100695 goto not_cookie;
696
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200697 data += clen + 1;
698 bleft -= clen + 1;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100699 } else {
700 while (bleft > 0 && *data != '=') {
701 if (*data == '\r' || *data == '\n')
702 goto not_cookie;
703 data++;
704 bleft--;
705 }
706
707 if (bleft < 1)
708 goto too_short;
709
710 if (*data != '=')
711 goto not_cookie;
712
713 data++;
714 bleft--;
715 }
716
717 /* data points to cookie value */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200718 smp->data.u.str.area = (char *)data;
719 smp->data.u.str.data = 0;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100720
721 while (bleft > 0 && *data != '\r') {
722 data++;
723 bleft--;
724 }
725
726 if (bleft < 2)
727 goto too_short;
728
729 if (data[0] != '\r' || data[1] != '\n')
730 goto not_cookie;
731
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200732 smp->data.u.str.data = (char *)data - smp->data.u.str.area;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100733 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100734 return 1;
735
736 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100737 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100738 not_cookie:
739 return 0;
740}
741
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200742/* Fetch the request RDP cookie identified in the args, or any cookie if no arg
743 * is passed. It is usable both for ACL and for samples. Note: this decoder
744 * only works with non-wrapping data. Accepts either 0 or 1 argument. Argument
Willy Tarreaub169eba2013-12-16 15:14:43 +0100745 * is a string (cookie name), other types will lead to undefined behaviour. The
746 * returned sample has type SMP_T_CSTR.
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200747 */
748int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200749smp_fetch_rdp_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200750{
Willy Tarreaube508f12016-03-10 11:47:01 +0100751 if (!smp->strm)
752 return 0;
753
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200754 return fetch_rdp_cookie_name(smp->strm, smp,
755 args ? args->data.str.area : NULL,
756 args ? args->data.str.data : 0);
Willy Tarreaucadd8c92013-07-22 18:09:52 +0200757}
758
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100759/* returns either 1 or 0 depending on whether an RDP cookie is found or not */
760static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200761smp_fetch_rdp_cookie_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100762{
763 int ret;
764
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200765 ret = smp_fetch_rdp_cookie(args, smp, kw, private);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100766
767 if (smp->flags & SMP_F_MAY_CHANGE)
768 return 0;
769
770 smp->flags = SMP_F_VOLATILE;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200771 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200772 smp->data.u.sint = ret;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100773 return 1;
774}
775
776/* extracts part of a payload with offset and length at a given position */
777static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200778smp_fetch_payload_lv(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100779{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200780 unsigned int len_offset = arg_p[0].data.sint;
781 unsigned int len_size = arg_p[1].data.sint;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100782 unsigned int buf_offset;
783 unsigned int buf_size = 0;
784 struct channel *chn;
785 int i;
786
787 /* Format is (len offset, len size, buf offset) or (len offset, len size) */
788 /* by default buf offset == len offset + len size */
789 /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
790
Willy Tarreaube508f12016-03-10 11:47:01 +0100791 if (!smp->strm)
792 return 0;
793
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200794 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200795 if (len_offset + len_size > ci_data(chn))
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100796 goto too_short;
797
798 for (i = 0; i < len_size; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200799 buf_size = (buf_size << 8) + ((unsigned char *)ci_head(chn))[i + len_offset];
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100800 }
801
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200802 /* buf offset may be implicit, absolute or relative. If the LSB
803 * is set, then the offset is relative otherwise it is absolute.
804 */
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100805 buf_offset = len_offset + len_size;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200806 if (arg_p[2].type == ARGT_SINT) {
807 if (arg_p[2].data.sint & 1)
808 buf_offset += arg_p[2].data.sint >> 1;
809 else
810 buf_offset = arg_p[2].data.sint >> 1;
811 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100812
Willy Tarreaud7bdcb82015-09-24 16:33:10 +0200813 if (!buf_size || buf_size > global.tune.bufsize || buf_offset + buf_size > global.tune.bufsize) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100814 /* will never match */
815 smp->flags = 0;
816 return 0;
817 }
818
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200819 if (buf_offset + buf_size > ci_data(chn))
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100820 goto too_short;
821
822 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200823 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100824 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200825 chunk_initlen(&smp->data.u.str, ci_head(chn) + buf_offset, 0, buf_size);
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100826 return 1;
827
828 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100829 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100830 return 0;
831}
832
833/* extracts some payload at a fixed position and length */
834static int
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200835smp_fetch_payload(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100836{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200837 unsigned int buf_offset = arg_p[0].data.sint;
838 unsigned int buf_size = arg_p[1].data.sint;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100839 struct channel *chn;
840
Willy Tarreaube508f12016-03-10 11:47:01 +0100841 if (!smp->strm)
842 return 0;
843
Thierry FOURNIER0786d052015-05-11 15:42:45 +0200844 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
Felipe Guerreiro Barbosa Ruiz00f55522017-03-16 17:01:41 -0300845 if (buf_size > global.tune.bufsize || buf_offset + buf_size > global.tune.bufsize) {
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100846 /* will never match */
847 smp->flags = 0;
848 return 0;
849 }
850
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200851 if (buf_offset + buf_size > ci_data(chn))
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100852 goto too_short;
853
854 /* init chunk as read only */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200855 smp->data.type = SMP_T_BIN;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100856 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200857 chunk_initlen(&smp->data.u.str, ci_head(chn) + buf_offset, 0, buf_size ? buf_size : (ci_data(chn) - buf_offset));
Willy Tarreau3889fff2015-01-13 20:20:10 +0100858 if (!buf_size && channel_may_recv(chn) && !channel_input_closed(chn))
Willy Tarreau00f00842013-08-02 11:07:32 +0200859 smp->flags |= SMP_F_MAY_CHANGE;
860
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100861 return 1;
862
863 too_short:
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100864 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100865 return 0;
866}
867
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100868/* This function is used to validate the arguments passed to a "payload_lv" fetch
869 * keyword. This keyword allows two positive integers and an optional signed one,
870 * with the second one being strictly positive and the third one being greater than
871 * the opposite of the two others if negative. It is assumed that the types are
872 * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> is
873 * not NULL, it will be filled with a pointer to an error message in case of
874 * error, that the caller is responsible for freeing. The initial location must
875 * either be freeable or NULL.
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200876 *
877 * Note that offset2 is stored with SINT type, but its not directly usable as is.
878 * The value is contained in the 63 MSB and the LSB is used as a flag for marking
879 * the "relative" property of the value.
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100880 */
Thierry FOURNIER49f45af2014-12-08 19:50:43 +0100881int val_payload_lv(struct arg *arg, char **err_msg)
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100882{
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200883 int relative = 0;
884 const char *str;
885
886 if (arg[0].data.sint < 0) {
887 memprintf(err_msg, "payload offset1 must be positive");
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100888 return 0;
889 }
890
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200891 if (!arg[1].data.sint) {
892 memprintf(err_msg, "payload length must be > 0");
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100893 return 0;
894 }
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200895
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200896 if (arg[2].type == ARGT_STR && arg[2].data.str.data > 0) {
897 if (arg[2].data.str.area[0] == '+' || arg[2].data.str.area[0] == '-')
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200898 relative = 1;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200899 str = arg[2].data.str.area;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200900 arg[2].type = ARGT_SINT;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200901 arg[2].data.sint = read_int64(&str,
902 str + arg[2].data.str.data);
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200903 if (*str != '\0') {
904 memprintf(err_msg, "payload offset2 is not a number");
905 return 0;
906 }
907 if (arg[0].data.sint + arg[1].data.sint + arg[2].data.sint < 0) {
908 memprintf(err_msg, "payload offset2 too negative");
909 return 0;
910 }
911 if (relative)
912 arg[2].data.sint = ( arg[2].data.sint << 1 ) + 1;
913 }
Willy Tarreaud4c33c82013-01-07 21:59:07 +0100914 return 1;
915}
916
Willy Tarreaud716f9b2017-10-13 11:03:15 +0200917/* extracts the parameter value of a distcc token */
918static int
919smp_fetch_distcc_param(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
920{
921 unsigned int match_tok = arg_p[0].data.sint;
922 unsigned int match_occ = arg_p[1].data.sint;
923 unsigned int token;
924 unsigned int param;
925 unsigned int body;
926 unsigned int ofs;
927 unsigned int occ;
928 struct channel *chn;
929 int i;
930
931 /* Format is (token[,occ]). occ starts at 1. */
932
933 if (!smp->strm)
934 return 0;
935
936 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
937
938 ofs = 0; occ = 0;
939 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200940 if (ofs + 12 > ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +0200941 /* not there yet but could it at least fit ? */
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200942 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +0200943 goto too_short;
944
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200945 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +0200946 goto too_short;
947
948 goto no_match;
949 }
950
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200951 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +0200952 ofs += 4;
953
954 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +0200955 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +0200956
957 if (c < 0)
958 goto no_match;
959 param = (param << 4) + c;
960 }
961 ofs += 8;
962
963 /* these tokens don't have a body */
964 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
965 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
966 token != 0x444F4E45 /* DONE */)
967 body = param;
968 else
969 body = 0;
970
971 if (token == match_tok) {
972 occ++;
973 if (!match_occ || match_occ == occ) {
974 /* found */
975 smp->data.type = SMP_T_SINT;
976 smp->data.u.sint = param;
977 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
978 return 1;
979 }
980 }
981 ofs += body;
982 }
983
984 too_short:
985 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
986 return 0;
987 no_match:
988 /* will never match (end of buffer, or bad contents) */
989 smp->flags = 0;
990 return 0;
991
992}
993
994/* extracts the (possibly truncated) body of a distcc token */
995static int
996smp_fetch_distcc_body(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
997{
998 unsigned int match_tok = arg_p[0].data.sint;
999 unsigned int match_occ = arg_p[1].data.sint;
1000 unsigned int token;
1001 unsigned int param;
1002 unsigned int ofs;
1003 unsigned int occ;
1004 unsigned int body;
1005 struct channel *chn;
1006 int i;
1007
1008 /* Format is (token[,occ]). occ starts at 1. */
1009
1010 if (!smp->strm)
1011 return 0;
1012
1013 chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
1014
1015 ofs = 0; occ = 0;
1016 while (1) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001017 if (ofs + 12 > ci_data(chn)) {
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001018 if (!chn->buf.size)
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001019 goto too_short;
1020
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001021 if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001022 goto too_short;
1023
1024 goto no_match;
1025 }
1026
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001027 token = read_n32(ci_head(chn) + ofs);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001028 ofs += 4;
1029
1030 for (i = param = 0; i < 8; i++) {
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001031 int c = hex2i(ci_head(chn)[ofs + i]);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001032
1033 if (c < 0)
1034 goto no_match;
1035 param = (param << 4) + c;
1036 }
1037 ofs += 8;
1038
1039 /* these tokens don't have a body */
1040 if (token != 0x41524743 /* ARGC */ && token != 0x44495354 /* DIST */ &&
1041 token != 0x4E46494C /* NFIL */ && token != 0x53544154 /* STAT */ &&
1042 token != 0x444F4E45 /* DONE */)
1043 body = param;
1044 else
1045 body = 0;
1046
1047 if (token == match_tok) {
1048 occ++;
1049 if (!match_occ || match_occ == occ) {
1050 /* found */
1051
1052 smp->data.type = SMP_T_BIN;
1053 smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
1054
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001055 if (ofs + body > ci_head(chn) - b_orig(&chn->buf) + ci_data(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001056 /* incomplete body */
1057
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001058 if (ofs + body > channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn)) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001059 /* truncate it to whatever will fit */
1060 smp->flags |= SMP_F_MAY_CHANGE;
Willy Tarreauc9fa0482018-07-10 17:43:27 +02001061 body = channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn) - ofs;
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001062 }
1063 }
1064
Willy Tarreaufc0785d2018-06-19 07:19:56 +02001065 chunk_initlen(&smp->data.u.str, ci_head(chn) + ofs, 0, body);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001066 return 1;
1067 }
1068 }
1069 ofs += body;
1070 }
1071
1072 too_short:
1073 smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST;
1074 return 0;
1075 no_match:
1076 /* will never match (end of buffer, or bad contents) */
1077 smp->flags = 0;
1078 return 0;
1079
1080}
1081
1082/* This function is used to validate the arguments passed to a "distcc_param" or
1083 * "distcc_body" sample fetch keyword. They take a mandatory token name of exactly
1084 * 4 characters, followed by an optional occurrence number starting at 1. It is
1085 * assumed that the types are already the correct ones. Returns 0 on error, non-
1086 * zero if OK. If <err_msg> is not NULL, it will be filled with a pointer to an
1087 * error message in case of error, that the caller is responsible for freeing.
1088 * The initial location must either be freeable or NULL.
1089 */
1090int val_distcc(struct arg *arg, char **err_msg)
1091{
1092 unsigned int token;
1093
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001094 if (arg[0].data.str.data != 4) {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001095 memprintf(err_msg, "token name must be exactly 4 characters");
1096 return 0;
1097 }
1098
1099 /* convert the token name to an unsigned int (one byte per character,
1100 * big endian format).
1101 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001102 token = (arg[0].data.str.area[0] << 24) + (arg[0].data.str.area[1] << 16) +
1103 (arg[0].data.str.area[2] << 8) + (arg[0].data.str.area[3] << 0);
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001104
1105 arg[0].type = ARGT_SINT;
1106 arg[0].data.sint = token;
1107
1108 if (arg[1].type != ARGT_SINT) {
1109 arg[1].type = ARGT_SINT;
1110 arg[1].data.sint = 0;
1111 }
1112 return 1;
1113}
1114
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001115/************************************************************************/
1116/* All supported sample and ACL keywords must be declared here. */
1117/************************************************************************/
1118
1119/* Note: must not be declared <const> as its list will be overwritten.
1120 * Note: fetches that may return multiple types must be declared as the lowest
1121 * common denominator, the type that can be casted into all other ones. For
1122 * instance IPv4/IPv6 must be declared IPv4.
1123 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001124static struct sample_fetch_kw_list smp_kws = {ILH, {
Willy Tarreaud716f9b2017-10-13 11:03:15 +02001125 { "distcc_body", smp_fetch_distcc_body, ARG2(1,STR,SINT), val_distcc, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1126 { "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 +02001127 { "payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ|SMP_USE_L6RES },
1128 { "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 +01001129 { "rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001130 { "rdp_cookie_cnt", smp_fetch_rdp_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L6REQ },
1131 { "rep_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
1132 { "req_len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1133 { "req_ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001134 { "req_ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001135 { "req_ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Willy Tarreaufa957342013-01-14 16:07:52 +01001136
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001137 { "req.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001138 { "req.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6REQ },
1139 { "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 +01001140 { "req.rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001141 { "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 +02001142 { "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 +05301143 { "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 +02001144 { "req.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01001145 { "req.ssl_sni", smp_fetch_ssl_hello_sni, 0, NULL, SMP_T_STR, SMP_USE_L6REQ },
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001146 { "req.ssl_ver", smp_fetch_req_ssl_ver, 0, NULL, SMP_T_SINT, SMP_USE_L6REQ },
1147 { "res.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +02001148 { "res.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_L6RES },
1149 { "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 +02001150 { "res.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001151 { "wait_end", smp_fetch_wait_end, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
1152 { /* END */ },
1153}};
1154
Willy Tarreau0108d902018-11-25 19:14:37 +01001155INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001156
1157/* Note: must not be declared <const> as its list will be overwritten.
1158 * Please take care of keeping this list alphabetically sorted.
1159 */
Willy Tarreaudc13c112013-06-21 23:16:39 +02001160static struct acl_kw_list acl_kws = {ILH, {
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +01001161 { "payload", "req.payload", PAT_MATCH_BIN },
1162 { "payload_lv", "req.payload_lv", PAT_MATCH_BIN },
1163 { "req_rdp_cookie", "req.rdp_cookie", PAT_MATCH_STR },
1164 { "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", PAT_MATCH_INT },
1165 { "req_ssl_sni", "req.ssl_sni", PAT_MATCH_STR },
1166 { "req_ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
1167 { "req.ssl_ver", "req.ssl_ver", PAT_MATCH_INT, pat_parse_dotted_ver },
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001168 { /* END */ },
1169}};
1170
Willy Tarreau0108d902018-11-25 19:14:37 +01001171INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
Willy Tarreaud4c33c82013-01-07 21:59:07 +01001172
1173/*
1174 * Local variables:
1175 * c-indent-level: 8
1176 * c-basic-offset: 8
1177 * End:
1178 */