blob: 910f5c486165a052cbbbfeca733f345b12d28e69 [file] [log] [blame]
Christopher Faulete6c3b692015-09-02 17:15:16 +02001/*
2 * Stream filters related variables and functions.
3 *
4 * Copyright (C) 2015 Qualys Inc., Christopher Faulet <cfaulet@qualys.com>
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
Christopher Fauletfcd99f82016-10-31 11:27:21 +010013#include <ctype.h>
14
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020015#include <haproxy/api.h>
Willy Tarreauf1d32c42020-06-04 21:07:02 +020016#include <haproxy/channel-t.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020017#include <haproxy/errors.h>
Willy Tarreauc7babd82020-06-04 21:29:29 +020018#include <haproxy/filters.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020019#include <haproxy/global.h>
Willy Tarreauc2b1ff02020-06-04 21:21:03 +020020#include <haproxy/http_ana-t.h>
Willy Tarreau87735332020-06-04 09:08:41 +020021#include <haproxy/http_htx.h>
Willy Tarreau16f958c2020-06-03 08:44:35 +020022#include <haproxy/htx.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020023#include <haproxy/proxy-t.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020024#include <haproxy/stream.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020025#include <haproxy/tools.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020026#include <haproxy/time.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020027
Christopher Fauletf4a4ef72018-12-07 17:39:53 +010028const char *trace_flt_id = "trace filter";
29
Christopher Faulete6c3b692015-09-02 17:15:16 +020030struct flt_ops trace_ops;
31
32struct trace_config {
33 struct proxy *proxy;
34 char *name;
35 int rand_parsing;
36 int rand_forwarding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010037 int hexdump;
Christopher Faulete6c3b692015-09-02 17:15:16 +020038};
39
Christopher Fauleta3ed2712019-11-04 11:35:42 +010040#define FLT_TRACE(conf, fmt, ...) \
Christopher Faulete6c3b692015-09-02 17:15:16 +020041 fprintf(stderr, "%d.%06d [%-20s] " fmt "\n", \
42 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
43 ##__VA_ARGS__)
44
Christopher Fauleta3ed2712019-11-04 11:35:42 +010045#define FLT_STRM_TRACE(conf, strm, fmt, ...) \
Christopher Fauletfcd99f82016-10-31 11:27:21 +010046 fprintf(stderr, "%d.%06d [%-20s] [strm %p(%x) 0x%08x 0x%08x] " fmt "\n", \
47 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
48 strm, (strm ? ((struct stream *)strm)->uniq_id : ~0U), \
49 (strm ? strm->req.analysers : 0), (strm ? strm->res.analysers : 0), \
Christopher Faulete6c3b692015-09-02 17:15:16 +020050 ##__VA_ARGS__)
51
52
53static const char *
54channel_label(const struct channel *chn)
55{
56 return (chn->flags & CF_ISRESP) ? "RESPONSE" : "REQUEST";
57}
58
59static const char *
60proxy_mode(const struct stream *s)
61{
62 struct proxy *px = (s->flags & SF_BE_ASSIGNED ? s->be : strm_fe(s));
63
Christopher Faulet386a0cd2019-07-15 21:22:44 +020064 return ((px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
Christopher Faulete6c3b692015-09-02 17:15:16 +020065}
66
67static const char *
68stream_pos(const struct stream *s)
69{
70 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
71}
72
Christopher Faulet31ed32d2016-06-21 11:42:37 +020073static const char *
74filter_type(const struct filter *f)
75{
76 return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
77}
78
Christopher Fauletfcd99f82016-10-31 11:27:21 +010079static void
Christopher Faulete0aa6f72018-11-30 22:23:32 +010080trace_hexdump(struct ist ist)
Christopher Fauletfcd99f82016-10-31 11:27:21 +010081{
Christopher Faulete0aa6f72018-11-30 22:23:32 +010082 int i, j, padding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010083
Christopher Faulete0aa6f72018-11-30 22:23:32 +010084 padding = ((ist.len % 16) ? (16 - ist.len % 16) : 0);
85 for (i = 0; i < ist.len + padding; i++) {
Christopher Fauletfcd99f82016-10-31 11:27:21 +010086 if (!(i % 16))
87 fprintf(stderr, "\t0x%06x: ", i);
88 else if (!(i % 8))
89 fprintf(stderr, " ");
90
Christopher Faulete0aa6f72018-11-30 22:23:32 +010091 if (i < ist.len)
92 fprintf(stderr, "%02x ", (unsigned char)*(ist.ptr+i));
Christopher Fauletfcd99f82016-10-31 11:27:21 +010093 else
94 fprintf(stderr, " ");
95
96 /* print ASCII dump */
97 if (i % 16 == 15) {
98 fprintf(stderr, " |");
Christopher Faulete0aa6f72018-11-30 22:23:32 +010099 for(j = i - 15; j <= i && j < ist.len; j++)
Willy Tarreau90807112020-02-25 08:16:33 +0100100 fprintf(stderr, "%c", (isprint((unsigned char)*(ist.ptr+j)) ? *(ist.ptr+j) : '.'));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100101 fprintf(stderr, "|\n");
102 }
103 }
104}
105
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100106static void
Christopher Fauletb2e58492019-11-12 11:13:01 +0100107trace_raw_hexdump(struct buffer *buf, unsigned int offset, unsigned int len)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100108{
109 unsigned char p[len];
110 int block1, block2;
111
112 block1 = len;
Christopher Fauletb2e58492019-11-12 11:13:01 +0100113 if (block1 > b_contig_data(buf, offset))
114 block1 = b_contig_data(buf, offset);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100115 block2 = len - block1;
116
Christopher Fauletb2e58492019-11-12 11:13:01 +0100117 memcpy(p, b_peek(buf, offset), block1);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100118 memcpy(p+block1, b_orig(buf), block2);
119 trace_hexdump(ist2(p, len));
120}
121
122static void
123trace_htx_hexdump(struct htx *htx, unsigned int offset, unsigned int len)
124{
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100125 struct htx_blk *blk;
126
Christopher Fauletee847d42019-05-23 11:55:33 +0200127 for (blk = htx_get_first_blk(htx); blk && len; blk = htx_get_next_blk(htx, blk)) {
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100128 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Fauletee847d42019-05-23 11:55:33 +0200129 uint32_t sz = htx_get_blksz(blk);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100130 struct ist v;
131
Christopher Fauletee847d42019-05-23 11:55:33 +0200132 if (offset >= sz) {
133 offset -= sz;
134 continue;
135 }
136
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100137 v = htx_get_blk_value(htx, blk);
138 v.ptr += offset;
139 v.len -= offset;
140 offset = 0;
141
142 if (v.len > len)
143 v.len = len;
144 len -= v.len;
Christopher Faulet2d7c5392019-06-03 10:41:26 +0200145 if (type == HTX_BLK_DATA)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100146 trace_hexdump(v);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100147 }
148}
149
Christopher Fauletb2e58492019-11-12 11:13:01 +0100150static unsigned int
151trace_get_htx_datalen(struct htx *htx, unsigned int offset, unsigned int len)
152{
153 struct htx_blk *blk;
Christopher Faulet24598a42020-02-26 22:06:11 +0100154 struct htx_ret htxret = htx_find_offset(htx, offset);
155 uint32_t data = 0;
Christopher Fauletb2e58492019-11-12 11:13:01 +0100156
Christopher Faulet24598a42020-02-26 22:06:11 +0100157 blk = htxret.blk;
158 if (blk && htxret.ret && htx_get_blk_type(blk) == HTX_BLK_DATA) {
159 data += htxret.ret;
160 blk = htx_get_next_blk(htx, blk);
161 }
162 while (blk) {
163 if (htx_get_blk_type(blk) == HTX_BLK_UNUSED)
164 goto next;
165 else if (htx_get_blk_type(blk) != HTX_BLK_DATA)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100166 break;
Christopher Faulet24598a42020-02-26 22:06:11 +0100167 data += htx_get_blksz(blk);
168 next:
169 blk = htx_get_next_blk(htx, blk);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100170 }
171 return data;
172}
173
Christopher Faulete6c3b692015-09-02 17:15:16 +0200174/***************************************************************************
175 * Hooks that manage the filter lifecycle (init/check/deinit)
176 **************************************************************************/
177/* Initialize the filter. Returns -1 on error, else 0. */
178static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100179trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200180{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100181 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200182
183 if (conf->name)
184 memprintf(&conf->name, "%s/%s", conf->name, px->id);
185 else
186 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100187
Christopher Faulet6e540952018-12-03 22:43:41 +0100188 fconf->flags |= FLT_CFG_FL_HTX;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100189 fconf->conf = conf;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100190
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100191 FLT_TRACE(conf, "filter initialized [read random=%s - fwd random=%s - hexdump=%s]",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200192 (conf->rand_parsing ? "true" : "false"),
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100193 (conf->rand_forwarding ? "true" : "false"),
194 (conf->hexdump ? "true" : "false"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200195 return 0;
196}
197
198/* Free ressources allocated by the trace filter. */
199static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100200trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200201{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100202 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200203
204 if (conf) {
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100205 FLT_TRACE(conf, "filter deinitialized");
Christopher Faulete6c3b692015-09-02 17:15:16 +0200206 free(conf->name);
207 free(conf);
208 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100209 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200210}
211
212/* Check configuration of a trace filter for a specified proxy.
213 * Return 1 on error, else 0. */
214static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100215trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200216{
217 return 0;
218}
219
Christopher Fauletf2273722017-07-27 16:58:42 +0200220/* Initialize the filter for each thread. Return -1 on error, else 0. */
221static int
222trace_init_per_thread(struct proxy *px, struct flt_conf *fconf)
223{
224 struct trace_config *conf = fconf->conf;
225
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100226 FLT_TRACE(conf, "filter initialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200227 return 0;
228}
229
230/* Free ressources allocate by the trace filter for each thread. */
231static void
232trace_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
233{
234 struct trace_config *conf = fconf->conf;
235
236 if (conf)
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100237 FLT_TRACE(conf, "filter deinitialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200238}
239
Christopher Faulete6c3b692015-09-02 17:15:16 +0200240/**************************************************************************
241 * Hooks to handle start/stop of streams
242 *************************************************************************/
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200243/* Called when a filter instance is created and attach to a stream */
244static int
245trace_attach(struct stream *s, struct filter *filter)
246{
247 struct trace_config *conf = FLT_CONF(filter);
248
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100249 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200250 __FUNCTION__, filter_type(filter));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100251
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200252 return 1;
253}
254
255/* Called when a filter instance is detach from a stream, just before its
256 * destruction */
257static void
258trace_detach(struct stream *s, struct filter *filter)
259{
260 struct trace_config *conf = FLT_CONF(filter);
261
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100262 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200263 __FUNCTION__, filter_type(filter));
264}
265
Christopher Faulete6c3b692015-09-02 17:15:16 +0200266/* Called when a stream is created */
267static int
268trace_stream_start(struct stream *s, struct filter *filter)
269{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100270 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200271
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100272 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200273 __FUNCTION__);
274 return 0;
275}
276
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200277
278/* Called when a backend is set for a stream */
279static int
280trace_stream_set_backend(struct stream *s, struct filter *filter,
281 struct proxy *be)
282{
283 struct trace_config *conf = FLT_CONF(filter);
284
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100285 FLT_STRM_TRACE(conf, s, "%-25s: backend=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200286 __FUNCTION__, be->id);
287 return 0;
288}
289
Christopher Faulete6c3b692015-09-02 17:15:16 +0200290/* Called when a stream is destroyed */
291static void
292trace_stream_stop(struct stream *s, struct filter *filter)
293{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100294 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200295
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100296 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200297 __FUNCTION__);
298}
299
Christopher Fauleta00d8172016-11-10 14:58:05 +0100300/* Called when the stream is woken up because of an expired timer */
301static void
302trace_check_timeouts(struct stream *s, struct filter *filter)
303{
304 struct trace_config *conf = FLT_CONF(filter);
305
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100306 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Fauleta00d8172016-11-10 14:58:05 +0100307 __FUNCTION__);
308}
309
Christopher Faulete6c3b692015-09-02 17:15:16 +0200310/**************************************************************************
311 * Hooks to handle channels activity
312 *************************************************************************/
313/* Called when analyze starts for a given channel */
314static int
315trace_chn_start_analyze(struct stream *s, struct filter *filter,
316 struct channel *chn)
317{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100318 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200319
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100320 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200321 __FUNCTION__,
322 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200323 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
324 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100325 register_data_filter(s, chn, filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200326 return 1;
327}
328
329/* Called before a processing happens on a given channel */
330static int
331trace_chn_analyze(struct stream *s, struct filter *filter,
332 struct channel *chn, unsigned an_bit)
333{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100334 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200335 char *ana;
336
337 switch (an_bit) {
338 case AN_REQ_INSPECT_FE:
339 ana = "AN_REQ_INSPECT_FE";
340 break;
341 case AN_REQ_WAIT_HTTP:
342 ana = "AN_REQ_WAIT_HTTP";
343 break;
344 case AN_REQ_HTTP_BODY:
345 ana = "AN_REQ_HTTP_BODY";
346 break;
347 case AN_REQ_HTTP_PROCESS_FE:
348 ana = "AN_REQ_HTTP_PROCESS_FE";
349 break;
350 case AN_REQ_SWITCHING_RULES:
351 ana = "AN_REQ_SWITCHING_RULES";
352 break;
353 case AN_REQ_INSPECT_BE:
354 ana = "AN_REQ_INSPECT_BE";
355 break;
356 case AN_REQ_HTTP_PROCESS_BE:
357 ana = "AN_REQ_HTTP_PROCESS_BE";
358 break;
359 case AN_REQ_SRV_RULES:
360 ana = "AN_REQ_SRV_RULES";
361 break;
362 case AN_REQ_HTTP_INNER:
363 ana = "AN_REQ_HTTP_INNER";
364 break;
365 case AN_REQ_HTTP_TARPIT:
366 ana = "AN_REQ_HTTP_TARPIT";
367 break;
368 case AN_REQ_STICKING_RULES:
369 ana = "AN_REQ_STICKING_RULES";
370 break;
371 case AN_REQ_PRST_RDP_COOKIE:
372 ana = "AN_REQ_PRST_RDP_COOKIE";
373 break;
374 case AN_REQ_HTTP_XFER_BODY:
375 ana = "AN_REQ_HTTP_XFER_BODY";
376 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200377 case AN_RES_INSPECT:
378 ana = "AN_RES_INSPECT";
379 break;
380 case AN_RES_WAIT_HTTP:
381 ana = "AN_RES_WAIT_HTTP";
382 break;
383 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
384 ana = "AN_RES_HTTP_PROCESS_FE/BE";
385 break;
386 case AN_RES_STORE_RULES:
387 ana = "AN_RES_STORE_RULES";
388 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200389 case AN_RES_HTTP_XFER_BODY:
390 ana = "AN_RES_HTTP_XFER_BODY";
391 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200392 default:
393 ana = "unknown";
394 }
395
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100396 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200397 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200398 __FUNCTION__,
399 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200400 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200401 return 1;
402}
403
404/* Called when analyze ends for a given channel */
405static int
406trace_chn_end_analyze(struct stream *s, struct filter *filter,
407 struct channel *chn)
408{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100409 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200410
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100411 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200412 __FUNCTION__,
413 channel_label(chn), proxy_mode(s), stream_pos(s));
414 return 1;
415}
416
417/**************************************************************************
418 * Hooks to filter HTTP messages
419 *************************************************************************/
420static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200421trace_http_headers(struct stream *s, struct filter *filter,
422 struct http_msg *msg)
423{
424 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200425 struct htx *htx = htxbuf(&msg->chn->buf);
426 struct htx_sl *sl = http_get_stline(htx);
427 int32_t pos;
Christopher Faulet1339d742016-05-11 16:48:33 +0200428
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100429 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)\t%.*s %.*s %.*s",
Christopher Faulet1339d742016-05-11 16:48:33 +0200430 __FUNCTION__,
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200431 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
432 HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl),
433 HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
434 HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100435
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200436 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
437 struct htx_blk *blk = htx_get_blk(htx, pos);
438 enum htx_blk_type type = htx_get_blk_type(blk);
439 struct ist n, v;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100440
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200441 if (type == HTX_BLK_EOH)
442 break;
443 if (type != HTX_BLK_HDR)
444 continue;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100445
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200446 n = htx_get_blk_name(htx, blk);
447 v = htx_get_blk_value(htx, blk);
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100448 FLT_STRM_TRACE(conf, s, "\t%.*s: %.*s",
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200449 (int)n.len, n.ptr, (int)v.len, v.ptr);
Christopher Faulet1339d742016-05-11 16:48:33 +0200450 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200451 return 1;
452}
453
454static int
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100455trace_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
456 unsigned int offset, unsigned int len)
457{
458 struct trace_config *conf = FLT_CONF(filter);
459 int ret = len;
460
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200461 if (ret && conf->rand_forwarding) {
Christopher Fauletb2e58492019-11-12 11:13:01 +0100462 unsigned int data = trace_get_htx_datalen(htxbuf(&msg->chn->buf), offset, len);
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200463
Christopher Fauletb2e58492019-11-12 11:13:01 +0100464 if (data) {
Willy Tarreau52bf8392020-03-08 00:42:37 +0100465 ret = ha_random() % (ret+1);
Christopher Faulet647fe1d2019-06-12 16:07:48 +0200466 if (!ret || ret >= data)
467 ret = len;
468 }
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200469 }
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100470
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100471 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100472 "offset=%u - len=%u - forward=%d",
473 __FUNCTION__,
474 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
475 offset, len, ret);
476
477 if (conf->hexdump)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100478 trace_htx_hexdump(htxbuf(&msg->chn->buf), offset, ret);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100479
480 if (ret != len)
481 task_wakeup(s->task, TASK_WOKEN_MSG);
482 return ret;
483}
484
485static int
Christopher Faulete6c3b692015-09-02 17:15:16 +0200486trace_http_end(struct stream *s, struct filter *filter,
487 struct http_msg *msg)
488{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100489 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200490
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100491 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200492 __FUNCTION__,
493 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
494 return 1;
495}
496
497static void
498trace_http_reset(struct stream *s, struct filter *filter,
499 struct http_msg *msg)
500{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100501 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200502
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100503 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200504 __FUNCTION__,
505 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
506}
507
508static void
509trace_http_reply(struct stream *s, struct filter *filter, short status,
Willy Tarreau83061a82018-07-13 11:56:34 +0200510 const struct buffer *msg)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200511{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100512 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200513
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100514 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200515 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
516}
517
Christopher Faulete6c3b692015-09-02 17:15:16 +0200518/**************************************************************************
519 * Hooks to filter TCP data
520 *************************************************************************/
521static int
Christopher Fauletb2e58492019-11-12 11:13:01 +0100522trace_tcp_payload(struct stream *s, struct filter *filter, struct channel *chn,
523 unsigned int offset, unsigned int len)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200524{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100525 struct trace_config *conf = FLT_CONF(filter);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100526 int ret = len;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200527
Christopher Fauletb2e58492019-11-12 11:13:01 +0100528 if (s->flags & SF_HTX) {
529 if (ret && conf->rand_forwarding) {
530 unsigned int data = trace_get_htx_datalen(htxbuf(&chn->buf), offset, len);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200531
Christopher Fauletb2e58492019-11-12 11:13:01 +0100532 if (data) {
Willy Tarreau52bf8392020-03-08 00:42:37 +0100533 ret = ha_random() % (ret+1);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100534 if (!ret || ret >= data)
535 ret = len;
536 }
537 }
Christopher Faulete6c3b692015-09-02 17:15:16 +0200538
Christopher Fauletb2e58492019-11-12 11:13:01 +0100539 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
540 "offset=%u - len=%u - forward=%d",
541 __FUNCTION__,
542 channel_label(chn), proxy_mode(s), stream_pos(s),
543 offset, len, ret);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200544
Christopher Fauletb2e58492019-11-12 11:13:01 +0100545 if (conf->hexdump)
546 trace_htx_hexdump(htxbuf(&chn->buf), offset, ret);
547 }
548 else {
Christopher Faulete6c3b692015-09-02 17:15:16 +0200549
Christopher Fauletb2e58492019-11-12 11:13:01 +0100550 if (ret && conf->rand_forwarding)
Willy Tarreau52bf8392020-03-08 00:42:37 +0100551 ret = ha_random() % (ret+1);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200552
Christopher Fauletb2e58492019-11-12 11:13:01 +0100553 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
554 "offset=%u - len=%u - forward=%d",
555 __FUNCTION__,
556 channel_label(chn), proxy_mode(s), stream_pos(s),
557 offset, len, ret);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200558
Christopher Fauletb2e58492019-11-12 11:13:01 +0100559 if (conf->hexdump)
560 trace_raw_hexdump(&chn->buf, offset, ret);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100561 }
562
Christopher Fauletb2e58492019-11-12 11:13:01 +0100563 if (ret != len)
564 task_wakeup(s->task, TASK_WOKEN_MSG);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200565 return ret;
566}
Christopher Faulete6c3b692015-09-02 17:15:16 +0200567/********************************************************************
568 * Functions that manage the filter initialization
569 ********************************************************************/
570struct flt_ops trace_ops = {
571 /* Manage trace filter, called for each filter declaration */
Christopher Fauletf2273722017-07-27 16:58:42 +0200572 .init = trace_init,
573 .deinit = trace_deinit,
574 .check = trace_check,
575 .init_per_thread = trace_init_per_thread,
576 .deinit_per_thread = trace_deinit_per_thread,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200577
578 /* Handle start/stop of streams */
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200579 .attach = trace_attach,
580 .detach = trace_detach,
581 .stream_start = trace_stream_start,
582 .stream_set_backend = trace_stream_set_backend,
583 .stream_stop = trace_stream_stop,
Christopher Fauleta00d8172016-11-10 14:58:05 +0100584 .check_timeouts = trace_check_timeouts,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200585
586 /* Handle channels activity */
587 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200588 .channel_pre_analyze = trace_chn_analyze,
589 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200590 .channel_end_analyze = trace_chn_end_analyze,
591
592 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200593 .http_headers = trace_http_headers,
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100594 .http_payload = trace_http_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200595 .http_end = trace_http_end,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200596 .http_reset = trace_http_reset,
597 .http_reply = trace_http_reply,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200598
599 /* Filter TCP data */
Christopher Fauletb2e58492019-11-12 11:13:01 +0100600 .tcp_payload = trace_tcp_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200601};
602
603/* Return -1 on error, else 0 */
604static int
605parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200606 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200607{
608 struct trace_config *conf;
609 int pos = *cur_arg;
610
611 conf = calloc(1, sizeof(*conf));
612 if (!conf) {
613 memprintf(err, "%s: out of memory", args[*cur_arg]);
614 return -1;
615 }
616 conf->proxy = px;
617
618 if (!strcmp(args[pos], "trace")) {
619 pos++;
620
621 while (*args[pos]) {
622 if (!strcmp(args[pos], "name")) {
623 if (!*args[pos + 1]) {
624 memprintf(err, "'%s' : '%s' option without value",
625 args[*cur_arg], args[pos]);
626 goto error;
627 }
628 conf->name = strdup(args[pos + 1]);
629 if (!conf->name) {
630 memprintf(err, "%s: out of memory", args[*cur_arg]);
631 goto error;
632 }
633 pos++;
634 }
635 else if (!strcmp(args[pos], "random-parsing"))
636 conf->rand_parsing = 1;
637 else if (!strcmp(args[pos], "random-forwarding"))
638 conf->rand_forwarding = 1;
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100639 else if (!strcmp(args[pos], "hexdump"))
640 conf->hexdump = 1;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200641 else
642 break;
643 pos++;
644 }
645 *cur_arg = pos;
Christopher Fauletf4a4ef72018-12-07 17:39:53 +0100646 fconf->id = trace_flt_id;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100647 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200648 }
649
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100650 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200651 return 0;
652
653 error:
654 if (conf->name)
655 free(conf->name);
656 free(conf);
657 return -1;
658}
659
660/* Declare the filter parser for "trace" keyword */
661static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200662 { "trace", parse_trace_flt, NULL },
663 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200664 }
665};
666
Willy Tarreau0108d902018-11-25 19:14:37 +0100667INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);