blob: 5ed515802c2cfca3bbb009c7a2d156315b5b1631 [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 Tarreau0108d902018-11-25 19:14:37 +010015#include <common/hathreads.h>
Willy Tarreaub96b77e2018-12-11 10:22:41 +010016#include <common/htx.h>
Willy Tarreau0108d902018-11-25 19:14:37 +010017#include <common/initcall.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020018#include <common/standard.h>
19#include <common/time.h>
20#include <common/tools.h>
21
22#include <types/channel.h>
23#include <types/filters.h>
24#include <types/global.h>
25#include <types/proxy.h>
26#include <types/stream.h>
27
28#include <proto/filters.h>
Christopher Faulete0aa6f72018-11-30 22:23:32 +010029#include <proto/http_htx.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020030#include <proto/log.h>
Christopher Fauletfc9cfe42019-07-16 14:54:53 +020031#include <proto/http_ana.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020032#include <proto/stream.h>
33
Christopher Fauletf4a4ef72018-12-07 17:39:53 +010034const char *trace_flt_id = "trace filter";
35
Christopher Faulete6c3b692015-09-02 17:15:16 +020036struct flt_ops trace_ops;
37
38struct trace_config {
39 struct proxy *proxy;
40 char *name;
41 int rand_parsing;
42 int rand_forwarding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010043 int hexdump;
Christopher Faulete6c3b692015-09-02 17:15:16 +020044};
45
Christopher Fauleta3ed2712019-11-04 11:35:42 +010046#define FLT_TRACE(conf, fmt, ...) \
Christopher Faulete6c3b692015-09-02 17:15:16 +020047 fprintf(stderr, "%d.%06d [%-20s] " fmt "\n", \
48 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
49 ##__VA_ARGS__)
50
Christopher Fauleta3ed2712019-11-04 11:35:42 +010051#define FLT_STRM_TRACE(conf, strm, fmt, ...) \
Christopher Fauletfcd99f82016-10-31 11:27:21 +010052 fprintf(stderr, "%d.%06d [%-20s] [strm %p(%x) 0x%08x 0x%08x] " fmt "\n", \
53 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
54 strm, (strm ? ((struct stream *)strm)->uniq_id : ~0U), \
55 (strm ? strm->req.analysers : 0), (strm ? strm->res.analysers : 0), \
Christopher Faulete6c3b692015-09-02 17:15:16 +020056 ##__VA_ARGS__)
57
58
59static const char *
60channel_label(const struct channel *chn)
61{
62 return (chn->flags & CF_ISRESP) ? "RESPONSE" : "REQUEST";
63}
64
65static const char *
66proxy_mode(const struct stream *s)
67{
68 struct proxy *px = (s->flags & SF_BE_ASSIGNED ? s->be : strm_fe(s));
69
Christopher Faulet386a0cd2019-07-15 21:22:44 +020070 return ((px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
Christopher Faulete6c3b692015-09-02 17:15:16 +020071}
72
73static const char *
74stream_pos(const struct stream *s)
75{
76 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
77}
78
Christopher Faulet31ed32d2016-06-21 11:42:37 +020079static const char *
80filter_type(const struct filter *f)
81{
82 return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
83}
84
Christopher Fauletfcd99f82016-10-31 11:27:21 +010085static void
Christopher Faulete0aa6f72018-11-30 22:23:32 +010086trace_hexdump(struct ist ist)
Christopher Fauletfcd99f82016-10-31 11:27:21 +010087{
Christopher Faulete0aa6f72018-11-30 22:23:32 +010088 int i, j, padding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010089
Christopher Faulete0aa6f72018-11-30 22:23:32 +010090 padding = ((ist.len % 16) ? (16 - ist.len % 16) : 0);
91 for (i = 0; i < ist.len + padding; i++) {
Christopher Fauletfcd99f82016-10-31 11:27:21 +010092 if (!(i % 16))
93 fprintf(stderr, "\t0x%06x: ", i);
94 else if (!(i % 8))
95 fprintf(stderr, " ");
96
Christopher Faulete0aa6f72018-11-30 22:23:32 +010097 if (i < ist.len)
98 fprintf(stderr, "%02x ", (unsigned char)*(ist.ptr+i));
Christopher Fauletfcd99f82016-10-31 11:27:21 +010099 else
100 fprintf(stderr, " ");
101
102 /* print ASCII dump */
103 if (i % 16 == 15) {
104 fprintf(stderr, " |");
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100105 for(j = i - 15; j <= i && j < ist.len; j++)
106 fprintf(stderr, "%c", (isprint(*(ist.ptr+j)) ? *(ist.ptr+j) : '.'));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100107 fprintf(stderr, "|\n");
108 }
109 }
110}
111
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100112static void
113trace_raw_hexdump(struct buffer *buf, int len, int out)
114{
115 unsigned char p[len];
116 int block1, block2;
117
118 block1 = len;
119 if (block1 > b_contig_data(buf, out))
120 block1 = b_contig_data(buf, out);
121 block2 = len - block1;
122
123 memcpy(p, b_head(buf), block1);
124 memcpy(p+block1, b_orig(buf), block2);
125 trace_hexdump(ist2(p, len));
126}
127
128static void
129trace_htx_hexdump(struct htx *htx, unsigned int offset, unsigned int len)
130{
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100131 struct htx_blk *blk;
132
Christopher Fauletee847d42019-05-23 11:55:33 +0200133 for (blk = htx_get_first_blk(htx); blk && len; blk = htx_get_next_blk(htx, blk)) {
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100134 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Fauletee847d42019-05-23 11:55:33 +0200135 uint32_t sz = htx_get_blksz(blk);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100136 struct ist v;
137
Christopher Fauletee847d42019-05-23 11:55:33 +0200138 if (offset >= sz) {
139 offset -= sz;
140 continue;
141 }
142
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100143 v = htx_get_blk_value(htx, blk);
144 v.ptr += offset;
145 v.len -= offset;
146 offset = 0;
147
148 if (v.len > len)
149 v.len = len;
150 len -= v.len;
Christopher Faulet2d7c5392019-06-03 10:41:26 +0200151 if (type == HTX_BLK_DATA)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100152 trace_hexdump(v);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100153 }
154}
155
Christopher Faulete6c3b692015-09-02 17:15:16 +0200156/***************************************************************************
157 * Hooks that manage the filter lifecycle (init/check/deinit)
158 **************************************************************************/
159/* Initialize the filter. Returns -1 on error, else 0. */
160static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100161trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200162{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100163 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200164
165 if (conf->name)
166 memprintf(&conf->name, "%s/%s", conf->name, px->id);
167 else
168 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100169
Christopher Faulet6e540952018-12-03 22:43:41 +0100170 fconf->flags |= FLT_CFG_FL_HTX;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100171 fconf->conf = conf;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100172
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100173 FLT_TRACE(conf, "filter initialized [read random=%s - fwd random=%s - hexdump=%s]",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200174 (conf->rand_parsing ? "true" : "false"),
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100175 (conf->rand_forwarding ? "true" : "false"),
176 (conf->hexdump ? "true" : "false"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200177 return 0;
178}
179
180/* Free ressources allocated by the trace filter. */
181static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100182trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200183{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100184 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200185
186 if (conf) {
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100187 FLT_TRACE(conf, "filter deinitialized");
Christopher Faulete6c3b692015-09-02 17:15:16 +0200188 free(conf->name);
189 free(conf);
190 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100191 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200192}
193
194/* Check configuration of a trace filter for a specified proxy.
195 * Return 1 on error, else 0. */
196static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100197trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200198{
199 return 0;
200}
201
Christopher Fauletf2273722017-07-27 16:58:42 +0200202/* Initialize the filter for each thread. Return -1 on error, else 0. */
203static int
204trace_init_per_thread(struct proxy *px, struct flt_conf *fconf)
205{
206 struct trace_config *conf = fconf->conf;
207
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100208 FLT_TRACE(conf, "filter initialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200209 return 0;
210}
211
212/* Free ressources allocate by the trace filter for each thread. */
213static void
214trace_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
215{
216 struct trace_config *conf = fconf->conf;
217
218 if (conf)
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100219 FLT_TRACE(conf, "filter deinitialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200220}
221
Christopher Faulete6c3b692015-09-02 17:15:16 +0200222/**************************************************************************
223 * Hooks to handle start/stop of streams
224 *************************************************************************/
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200225/* Called when a filter instance is created and attach to a stream */
226static int
227trace_attach(struct stream *s, struct filter *filter)
228{
229 struct trace_config *conf = FLT_CONF(filter);
230
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100231 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200232 __FUNCTION__, filter_type(filter));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100233
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200234 return 1;
235}
236
237/* Called when a filter instance is detach from a stream, just before its
238 * destruction */
239static void
240trace_detach(struct stream *s, struct filter *filter)
241{
242 struct trace_config *conf = FLT_CONF(filter);
243
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100244 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200245 __FUNCTION__, filter_type(filter));
246}
247
Christopher Faulete6c3b692015-09-02 17:15:16 +0200248/* Called when a stream is created */
249static int
250trace_stream_start(struct stream *s, struct filter *filter)
251{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100252 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200253
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100254 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200255 __FUNCTION__);
256 return 0;
257}
258
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200259
260/* Called when a backend is set for a stream */
261static int
262trace_stream_set_backend(struct stream *s, struct filter *filter,
263 struct proxy *be)
264{
265 struct trace_config *conf = FLT_CONF(filter);
266
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100267 FLT_STRM_TRACE(conf, s, "%-25s: backend=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200268 __FUNCTION__, be->id);
269 return 0;
270}
271
Christopher Faulete6c3b692015-09-02 17:15:16 +0200272/* Called when a stream is destroyed */
273static void
274trace_stream_stop(struct stream *s, struct filter *filter)
275{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100276 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200277
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100278 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200279 __FUNCTION__);
280}
281
Christopher Fauleta00d8172016-11-10 14:58:05 +0100282/* Called when the stream is woken up because of an expired timer */
283static void
284trace_check_timeouts(struct stream *s, struct filter *filter)
285{
286 struct trace_config *conf = FLT_CONF(filter);
287
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100288 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Fauleta00d8172016-11-10 14:58:05 +0100289 __FUNCTION__);
290}
291
Christopher Faulete6c3b692015-09-02 17:15:16 +0200292/**************************************************************************
293 * Hooks to handle channels activity
294 *************************************************************************/
295/* Called when analyze starts for a given channel */
296static int
297trace_chn_start_analyze(struct stream *s, struct filter *filter,
298 struct channel *chn)
299{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100300 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200301
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100302 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200303 __FUNCTION__,
304 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200305 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
306 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100307 register_data_filter(s, chn, filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200308 return 1;
309}
310
311/* Called before a processing happens on a given channel */
312static int
313trace_chn_analyze(struct stream *s, struct filter *filter,
314 struct channel *chn, unsigned an_bit)
315{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100316 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200317 char *ana;
318
319 switch (an_bit) {
320 case AN_REQ_INSPECT_FE:
321 ana = "AN_REQ_INSPECT_FE";
322 break;
323 case AN_REQ_WAIT_HTTP:
324 ana = "AN_REQ_WAIT_HTTP";
325 break;
326 case AN_REQ_HTTP_BODY:
327 ana = "AN_REQ_HTTP_BODY";
328 break;
329 case AN_REQ_HTTP_PROCESS_FE:
330 ana = "AN_REQ_HTTP_PROCESS_FE";
331 break;
332 case AN_REQ_SWITCHING_RULES:
333 ana = "AN_REQ_SWITCHING_RULES";
334 break;
335 case AN_REQ_INSPECT_BE:
336 ana = "AN_REQ_INSPECT_BE";
337 break;
338 case AN_REQ_HTTP_PROCESS_BE:
339 ana = "AN_REQ_HTTP_PROCESS_BE";
340 break;
341 case AN_REQ_SRV_RULES:
342 ana = "AN_REQ_SRV_RULES";
343 break;
344 case AN_REQ_HTTP_INNER:
345 ana = "AN_REQ_HTTP_INNER";
346 break;
347 case AN_REQ_HTTP_TARPIT:
348 ana = "AN_REQ_HTTP_TARPIT";
349 break;
350 case AN_REQ_STICKING_RULES:
351 ana = "AN_REQ_STICKING_RULES";
352 break;
353 case AN_REQ_PRST_RDP_COOKIE:
354 ana = "AN_REQ_PRST_RDP_COOKIE";
355 break;
356 case AN_REQ_HTTP_XFER_BODY:
357 ana = "AN_REQ_HTTP_XFER_BODY";
358 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200359 case AN_RES_INSPECT:
360 ana = "AN_RES_INSPECT";
361 break;
362 case AN_RES_WAIT_HTTP:
363 ana = "AN_RES_WAIT_HTTP";
364 break;
365 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
366 ana = "AN_RES_HTTP_PROCESS_FE/BE";
367 break;
368 case AN_RES_STORE_RULES:
369 ana = "AN_RES_STORE_RULES";
370 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200371 case AN_RES_HTTP_XFER_BODY:
372 ana = "AN_RES_HTTP_XFER_BODY";
373 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200374 default:
375 ana = "unknown";
376 }
377
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100378 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200379 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200380 __FUNCTION__,
381 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200382 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200383 return 1;
384}
385
386/* Called when analyze ends for a given channel */
387static int
388trace_chn_end_analyze(struct stream *s, struct filter *filter,
389 struct channel *chn)
390{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100391 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200392
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100393 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200394 __FUNCTION__,
395 channel_label(chn), proxy_mode(s), stream_pos(s));
396 return 1;
397}
398
399/**************************************************************************
400 * Hooks to filter HTTP messages
401 *************************************************************************/
402static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200403trace_http_headers(struct stream *s, struct filter *filter,
404 struct http_msg *msg)
405{
406 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200407 struct htx *htx = htxbuf(&msg->chn->buf);
408 struct htx_sl *sl = http_get_stline(htx);
409 int32_t pos;
Christopher Faulet1339d742016-05-11 16:48:33 +0200410
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100411 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)\t%.*s %.*s %.*s",
Christopher Faulet1339d742016-05-11 16:48:33 +0200412 __FUNCTION__,
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200413 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
414 HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl),
415 HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
416 HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100417
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200418 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
419 struct htx_blk *blk = htx_get_blk(htx, pos);
420 enum htx_blk_type type = htx_get_blk_type(blk);
421 struct ist n, v;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100422
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200423 if (type == HTX_BLK_EOH)
424 break;
425 if (type != HTX_BLK_HDR)
426 continue;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100427
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200428 n = htx_get_blk_name(htx, blk);
429 v = htx_get_blk_value(htx, blk);
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100430 FLT_STRM_TRACE(conf, s, "\t%.*s: %.*s",
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200431 (int)n.len, n.ptr, (int)v.len, v.ptr);
Christopher Faulet1339d742016-05-11 16:48:33 +0200432 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200433 return 1;
434}
435
436static int
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100437trace_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
438 unsigned int offset, unsigned int len)
439{
440 struct trace_config *conf = FLT_CONF(filter);
441 int ret = len;
442
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200443 if (ret && conf->rand_forwarding) {
444 struct htx *htx = htxbuf(&msg->chn->buf);
445 struct htx_blk *blk;
446 uint32_t sz, data = 0;
Christopher Faulet50fe9fb2019-06-11 10:20:57 +0200447 unsigned int off = offset;
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200448
449 for (blk = htx_get_first_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) {
450 if (htx_get_blk_type(blk) != HTX_BLK_DATA)
451 break;
452
453 sz = htx_get_blksz(blk);
Christopher Faulet50fe9fb2019-06-11 10:20:57 +0200454 if (off >= sz) {
455 off -= sz;
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200456 continue;
457 }
Christopher Faulet50fe9fb2019-06-11 10:20:57 +0200458 data += sz - off;
459 off = 0;
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200460 if (data > len) {
461 data = len;
462 break;
463 }
464 }
Christopher Faulet647fe1d2019-06-12 16:07:48 +0200465 if (data) {
466 ret = random() % (ret+1);
467 if (!ret || ret >= data)
468 ret = len;
469 }
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200470 }
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100471
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100472 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100473 "offset=%u - len=%u - forward=%d",
474 __FUNCTION__,
475 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
476 offset, len, ret);
477
478 if (conf->hexdump)
Christopher Faulet27ba2dc2018-12-05 11:53:24 +0100479 trace_htx_hexdump(htxbuf(&msg->chn->buf), offset, len);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100480
481 if (ret != len)
482 task_wakeup(s->task, TASK_WOKEN_MSG);
483 return ret;
484}
485
486static int
Christopher Faulete6c3b692015-09-02 17:15:16 +0200487trace_http_end(struct stream *s, struct filter *filter,
488 struct http_msg *msg)
489{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100490 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200491
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100492 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200493 __FUNCTION__,
494 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
495 return 1;
496}
497
498static void
499trace_http_reset(struct stream *s, struct filter *filter,
500 struct http_msg *msg)
501{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100502 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200503
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100504 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200505 __FUNCTION__,
506 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
507}
508
509static void
510trace_http_reply(struct stream *s, struct filter *filter, short status,
Willy Tarreau83061a82018-07-13 11:56:34 +0200511 const struct buffer *msg)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200512{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100513 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200514
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100515 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200516 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
517}
518
Christopher Faulete6c3b692015-09-02 17:15:16 +0200519/**************************************************************************
520 * Hooks to filter TCP data
521 *************************************************************************/
522static int
523trace_tcp_data(struct stream *s, struct filter *filter, struct channel *chn)
524{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100525 struct trace_config *conf = FLT_CONF(filter);
Willy Tarreauf1589372018-06-19 07:22:43 +0200526 int avail = ci_data(chn) - FLT_NXT(filter, chn);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200527 int ret = avail;
528
529 if (ret && conf->rand_parsing)
530 ret = random() % (ret+1);
531
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100532 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - next=%u - avail=%u - consume=%d",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200533 __FUNCTION__,
534 channel_label(chn), proxy_mode(s), stream_pos(s),
535 FLT_NXT(filter, chn), avail, ret);
536
537 if (ret != avail)
538 task_wakeup(s->task, TASK_WOKEN_MSG);
539 return ret;
540}
541
542static int
543trace_tcp_forward_data(struct stream *s, struct filter *filter, struct channel *chn,
544 unsigned int len)
545{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100546 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200547 int ret = len;
548
549 if (ret && conf->rand_forwarding)
550 ret = random() % (ret+1);
551
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100552 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - len=%u - fwd=%u - forward=%d",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200553 __FUNCTION__,
554 channel_label(chn), proxy_mode(s), stream_pos(s), len,
555 FLT_FWD(filter, chn), ret);
556
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100557 if (conf->hexdump) {
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200558 c_adv(chn, FLT_FWD(filter, chn));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100559 trace_raw_hexdump(&chn->buf, ret, co_data(chn));
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200560 c_rew(chn, FLT_FWD(filter, chn));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100561 }
562
Christopher Faulete6c3b692015-09-02 17:15:16 +0200563 if (ret != len)
564 task_wakeup(s->task, TASK_WOKEN_MSG);
565 return ret;
566}
567
568/********************************************************************
569 * Functions that manage the filter initialization
570 ********************************************************************/
571struct flt_ops trace_ops = {
572 /* Manage trace filter, called for each filter declaration */
Christopher Fauletf2273722017-07-27 16:58:42 +0200573 .init = trace_init,
574 .deinit = trace_deinit,
575 .check = trace_check,
576 .init_per_thread = trace_init_per_thread,
577 .deinit_per_thread = trace_deinit_per_thread,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200578
579 /* Handle start/stop of streams */
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200580 .attach = trace_attach,
581 .detach = trace_detach,
582 .stream_start = trace_stream_start,
583 .stream_set_backend = trace_stream_set_backend,
584 .stream_stop = trace_stream_stop,
Christopher Fauleta00d8172016-11-10 14:58:05 +0100585 .check_timeouts = trace_check_timeouts,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200586
587 /* Handle channels activity */
588 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200589 .channel_pre_analyze = trace_chn_analyze,
590 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200591 .channel_end_analyze = trace_chn_end_analyze,
592
593 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200594 .http_headers = trace_http_headers,
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100595 .http_payload = trace_http_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200596 .http_end = trace_http_end,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200597 .http_reset = trace_http_reset,
598 .http_reply = trace_http_reply,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200599
600 /* Filter TCP data */
601 .tcp_data = trace_tcp_data,
602 .tcp_forward_data = trace_tcp_forward_data,
603};
604
605/* Return -1 on error, else 0 */
606static int
607parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200608 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200609{
610 struct trace_config *conf;
611 int pos = *cur_arg;
612
613 conf = calloc(1, sizeof(*conf));
614 if (!conf) {
615 memprintf(err, "%s: out of memory", args[*cur_arg]);
616 return -1;
617 }
618 conf->proxy = px;
619
620 if (!strcmp(args[pos], "trace")) {
621 pos++;
622
623 while (*args[pos]) {
624 if (!strcmp(args[pos], "name")) {
625 if (!*args[pos + 1]) {
626 memprintf(err, "'%s' : '%s' option without value",
627 args[*cur_arg], args[pos]);
628 goto error;
629 }
630 conf->name = strdup(args[pos + 1]);
631 if (!conf->name) {
632 memprintf(err, "%s: out of memory", args[*cur_arg]);
633 goto error;
634 }
635 pos++;
636 }
637 else if (!strcmp(args[pos], "random-parsing"))
638 conf->rand_parsing = 1;
639 else if (!strcmp(args[pos], "random-forwarding"))
640 conf->rand_forwarding = 1;
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100641 else if (!strcmp(args[pos], "hexdump"))
642 conf->hexdump = 1;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200643 else
644 break;
645 pos++;
646 }
647 *cur_arg = pos;
Christopher Fauletf4a4ef72018-12-07 17:39:53 +0100648 fconf->id = trace_flt_id;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100649 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200650 }
651
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100652 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200653 return 0;
654
655 error:
656 if (conf->name)
657 free(conf->name);
658 free(conf);
659 return -1;
660}
661
662/* Declare the filter parser for "trace" keyword */
663static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200664 { "trace", parse_trace_flt, NULL },
665 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200666 }
667};
668
Willy Tarreau0108d902018-11-25 19:14:37 +0100669INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);