blob: 653f9d2645f3c37ce79614d6b509fee787c8f559 [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 Faulet1339d742016-05-11 16:48:33 +020029#include <proto/hdr_idx.h>
Christopher Faulete0aa6f72018-11-30 22:23:32 +010030#include <proto/http_htx.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020031#include <proto/log.h>
Christopher Faulete0aa6f72018-11-30 22:23:32 +010032#include <proto/proto_http.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020033#include <proto/stream.h>
34
Christopher Fauletf4a4ef72018-12-07 17:39:53 +010035const char *trace_flt_id = "trace filter";
36
Christopher Faulete6c3b692015-09-02 17:15:16 +020037struct flt_ops trace_ops;
38
39struct trace_config {
40 struct proxy *proxy;
41 char *name;
42 int rand_parsing;
43 int rand_forwarding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010044 int hexdump;
Christopher Faulete6c3b692015-09-02 17:15:16 +020045};
46
47#define TRACE(conf, fmt, ...) \
48 fprintf(stderr, "%d.%06d [%-20s] " fmt "\n", \
49 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
50 ##__VA_ARGS__)
51
Christopher Fauletfcd99f82016-10-31 11:27:21 +010052#define STRM_TRACE(conf, strm, fmt, ...) \
53 fprintf(stderr, "%d.%06d [%-20s] [strm %p(%x) 0x%08x 0x%08x] " fmt "\n", \
54 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
55 strm, (strm ? ((struct stream *)strm)->uniq_id : ~0U), \
56 (strm ? strm->req.analysers : 0), (strm ? strm->res.analysers : 0), \
Christopher Faulete6c3b692015-09-02 17:15:16 +020057 ##__VA_ARGS__)
58
59
60static const char *
61channel_label(const struct channel *chn)
62{
63 return (chn->flags & CF_ISRESP) ? "RESPONSE" : "REQUEST";
64}
65
66static const char *
67proxy_mode(const struct stream *s)
68{
69 struct proxy *px = (s->flags & SF_BE_ASSIGNED ? s->be : strm_fe(s));
70
Christopher Faulet386a0cd2019-07-15 21:22:44 +020071 return ((px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
Christopher Faulete6c3b692015-09-02 17:15:16 +020072}
73
74static const char *
75stream_pos(const struct stream *s)
76{
77 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
78}
79
Christopher Faulet31ed32d2016-06-21 11:42:37 +020080static const char *
81filter_type(const struct filter *f)
82{
83 return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
84}
85
Christopher Fauletfcd99f82016-10-31 11:27:21 +010086static void
Christopher Faulete0aa6f72018-11-30 22:23:32 +010087trace_hexdump(struct ist ist)
Christopher Fauletfcd99f82016-10-31 11:27:21 +010088{
Christopher Faulete0aa6f72018-11-30 22:23:32 +010089 int i, j, padding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010090
Christopher Faulete0aa6f72018-11-30 22:23:32 +010091 padding = ((ist.len % 16) ? (16 - ist.len % 16) : 0);
92 for (i = 0; i < ist.len + padding; i++) {
Christopher Fauletfcd99f82016-10-31 11:27:21 +010093 if (!(i % 16))
94 fprintf(stderr, "\t0x%06x: ", i);
95 else if (!(i % 8))
96 fprintf(stderr, " ");
97
Christopher Faulete0aa6f72018-11-30 22:23:32 +010098 if (i < ist.len)
99 fprintf(stderr, "%02x ", (unsigned char)*(ist.ptr+i));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100100 else
101 fprintf(stderr, " ");
102
103 /* print ASCII dump */
104 if (i % 16 == 15) {
105 fprintf(stderr, " |");
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100106 for(j = i - 15; j <= i && j < ist.len; j++)
107 fprintf(stderr, "%c", (isprint(*(ist.ptr+j)) ? *(ist.ptr+j) : '.'));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100108 fprintf(stderr, "|\n");
109 }
110 }
111}
112
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100113static void
114trace_raw_hexdump(struct buffer *buf, int len, int out)
115{
116 unsigned char p[len];
117 int block1, block2;
118
119 block1 = len;
120 if (block1 > b_contig_data(buf, out))
121 block1 = b_contig_data(buf, out);
122 block2 = len - block1;
123
124 memcpy(p, b_head(buf), block1);
125 memcpy(p+block1, b_orig(buf), block2);
126 trace_hexdump(ist2(p, len));
127}
128
129static void
130trace_htx_hexdump(struct htx *htx, unsigned int offset, unsigned int len)
131{
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100132 struct htx_blk *blk;
133
Christopher Fauletee847d42019-05-23 11:55:33 +0200134 for (blk = htx_get_first_blk(htx); blk && len; blk = htx_get_next_blk(htx, blk)) {
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100135 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Fauletee847d42019-05-23 11:55:33 +0200136 uint32_t sz = htx_get_blksz(blk);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100137 struct ist v;
138
Christopher Fauletee847d42019-05-23 11:55:33 +0200139 if (offset >= sz) {
140 offset -= sz;
141 continue;
142 }
143
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100144 v = htx_get_blk_value(htx, blk);
145 v.ptr += offset;
146 v.len -= offset;
147 offset = 0;
148
149 if (v.len > len)
150 v.len = len;
151 len -= v.len;
Christopher Faulet2d7c5392019-06-03 10:41:26 +0200152 if (type == HTX_BLK_DATA)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100153 trace_hexdump(v);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100154 }
155}
156
Christopher Faulete6c3b692015-09-02 17:15:16 +0200157/***************************************************************************
158 * Hooks that manage the filter lifecycle (init/check/deinit)
159 **************************************************************************/
160/* Initialize the filter. Returns -1 on error, else 0. */
161static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100162trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200163{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100164 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200165
166 if (conf->name)
167 memprintf(&conf->name, "%s/%s", conf->name, px->id);
168 else
169 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100170
Christopher Faulet6e540952018-12-03 22:43:41 +0100171 fconf->flags |= FLT_CFG_FL_HTX;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100172 fconf->conf = conf;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100173
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100174 TRACE(conf, "filter initialized [read random=%s - fwd random=%s - hexdump=%s]",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200175 (conf->rand_parsing ? "true" : "false"),
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100176 (conf->rand_forwarding ? "true" : "false"),
177 (conf->hexdump ? "true" : "false"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200178 return 0;
179}
180
181/* Free ressources allocated by the trace filter. */
182static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100183trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200184{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100185 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200186
187 if (conf) {
188 TRACE(conf, "filter deinitialized");
189 free(conf->name);
190 free(conf);
191 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100192 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200193}
194
195/* Check configuration of a trace filter for a specified proxy.
196 * Return 1 on error, else 0. */
197static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100198trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200199{
200 return 0;
201}
202
Christopher Fauletf2273722017-07-27 16:58:42 +0200203/* Initialize the filter for each thread. Return -1 on error, else 0. */
204static int
205trace_init_per_thread(struct proxy *px, struct flt_conf *fconf)
206{
207 struct trace_config *conf = fconf->conf;
208
209 TRACE(conf, "filter initialized for thread tid %u", tid);
210 return 0;
211}
212
213/* Free ressources allocate by the trace filter for each thread. */
214static void
215trace_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
216{
217 struct trace_config *conf = fconf->conf;
218
219 if (conf)
220 TRACE(conf, "filter deinitialized for thread tid %u", tid);
221}
222
Christopher Faulete6c3b692015-09-02 17:15:16 +0200223/**************************************************************************
224 * Hooks to handle start/stop of streams
225 *************************************************************************/
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200226/* Called when a filter instance is created and attach to a stream */
227static int
228trace_attach(struct stream *s, struct filter *filter)
229{
230 struct trace_config *conf = FLT_CONF(filter);
231
232 STRM_TRACE(conf, s, "%-25s: filter-type=%s",
233 __FUNCTION__, filter_type(filter));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100234
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200235 return 1;
236}
237
238/* Called when a filter instance is detach from a stream, just before its
239 * destruction */
240static void
241trace_detach(struct stream *s, struct filter *filter)
242{
243 struct trace_config *conf = FLT_CONF(filter);
244
245 STRM_TRACE(conf, s, "%-25s: filter-type=%s",
246 __FUNCTION__, filter_type(filter));
247}
248
Christopher Faulete6c3b692015-09-02 17:15:16 +0200249/* Called when a stream is created */
250static int
251trace_stream_start(struct stream *s, struct filter *filter)
252{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100253 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200254
255 STRM_TRACE(conf, s, "%-25s",
256 __FUNCTION__);
257 return 0;
258}
259
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200260
261/* Called when a backend is set for a stream */
262static int
263trace_stream_set_backend(struct stream *s, struct filter *filter,
264 struct proxy *be)
265{
266 struct trace_config *conf = FLT_CONF(filter);
267
268 STRM_TRACE(conf, s, "%-25s: backend=%s",
269 __FUNCTION__, be->id);
270 return 0;
271}
272
Christopher Faulete6c3b692015-09-02 17:15:16 +0200273/* Called when a stream is destroyed */
274static void
275trace_stream_stop(struct stream *s, struct filter *filter)
276{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100277 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200278
279 STRM_TRACE(conf, s, "%-25s",
280 __FUNCTION__);
281}
282
Christopher Fauleta00d8172016-11-10 14:58:05 +0100283/* Called when the stream is woken up because of an expired timer */
284static void
285trace_check_timeouts(struct stream *s, struct filter *filter)
286{
287 struct trace_config *conf = FLT_CONF(filter);
288
289 STRM_TRACE(conf, s, "%-25s",
290 __FUNCTION__);
291}
292
Christopher Faulete6c3b692015-09-02 17:15:16 +0200293/**************************************************************************
294 * Hooks to handle channels activity
295 *************************************************************************/
296/* Called when analyze starts for a given channel */
297static int
298trace_chn_start_analyze(struct stream *s, struct filter *filter,
299 struct channel *chn)
300{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100301 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200302
303 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
304 __FUNCTION__,
305 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200306 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
307 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100308 register_data_filter(s, chn, filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200309 return 1;
310}
311
312/* Called before a processing happens on a given channel */
313static int
314trace_chn_analyze(struct stream *s, struct filter *filter,
315 struct channel *chn, unsigned an_bit)
316{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100317 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200318 char *ana;
319
320 switch (an_bit) {
321 case AN_REQ_INSPECT_FE:
322 ana = "AN_REQ_INSPECT_FE";
323 break;
324 case AN_REQ_WAIT_HTTP:
325 ana = "AN_REQ_WAIT_HTTP";
326 break;
327 case AN_REQ_HTTP_BODY:
328 ana = "AN_REQ_HTTP_BODY";
329 break;
330 case AN_REQ_HTTP_PROCESS_FE:
331 ana = "AN_REQ_HTTP_PROCESS_FE";
332 break;
333 case AN_REQ_SWITCHING_RULES:
334 ana = "AN_REQ_SWITCHING_RULES";
335 break;
336 case AN_REQ_INSPECT_BE:
337 ana = "AN_REQ_INSPECT_BE";
338 break;
339 case AN_REQ_HTTP_PROCESS_BE:
340 ana = "AN_REQ_HTTP_PROCESS_BE";
341 break;
342 case AN_REQ_SRV_RULES:
343 ana = "AN_REQ_SRV_RULES";
344 break;
345 case AN_REQ_HTTP_INNER:
346 ana = "AN_REQ_HTTP_INNER";
347 break;
348 case AN_REQ_HTTP_TARPIT:
349 ana = "AN_REQ_HTTP_TARPIT";
350 break;
351 case AN_REQ_STICKING_RULES:
352 ana = "AN_REQ_STICKING_RULES";
353 break;
354 case AN_REQ_PRST_RDP_COOKIE:
355 ana = "AN_REQ_PRST_RDP_COOKIE";
356 break;
357 case AN_REQ_HTTP_XFER_BODY:
358 ana = "AN_REQ_HTTP_XFER_BODY";
359 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200360 case AN_RES_INSPECT:
361 ana = "AN_RES_INSPECT";
362 break;
363 case AN_RES_WAIT_HTTP:
364 ana = "AN_RES_WAIT_HTTP";
365 break;
366 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
367 ana = "AN_RES_HTTP_PROCESS_FE/BE";
368 break;
369 case AN_RES_STORE_RULES:
370 ana = "AN_RES_STORE_RULES";
371 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200372 case AN_RES_HTTP_XFER_BODY:
373 ana = "AN_RES_HTTP_XFER_BODY";
374 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200375 default:
376 ana = "unknown";
377 }
378
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200379 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
380 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200381 __FUNCTION__,
382 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200383 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200384 return 1;
385}
386
387/* Called when analyze ends for a given channel */
388static int
389trace_chn_end_analyze(struct stream *s, struct filter *filter,
390 struct channel *chn)
391{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100392 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200393
394 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
395 __FUNCTION__,
396 channel_label(chn), proxy_mode(s), stream_pos(s));
397 return 1;
398}
399
400/**************************************************************************
401 * Hooks to filter HTTP messages
402 *************************************************************************/
403static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200404trace_http_headers(struct stream *s, struct filter *filter,
405 struct http_msg *msg)
406{
407 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200408 struct htx *htx = htxbuf(&msg->chn->buf);
409 struct htx_sl *sl = http_get_stline(htx);
410 int32_t pos;
Christopher Faulet1339d742016-05-11 16:48:33 +0200411
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200412 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)\t%.*s %.*s %.*s",
Christopher Faulet1339d742016-05-11 16:48:33 +0200413 __FUNCTION__,
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200414 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
415 HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl),
416 HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
417 HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100418
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200419 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
420 struct htx_blk *blk = htx_get_blk(htx, pos);
421 enum htx_blk_type type = htx_get_blk_type(blk);
422 struct ist n, v;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100423
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200424 if (type == HTX_BLK_EOH)
425 break;
426 if (type != HTX_BLK_HDR)
427 continue;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100428
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200429 n = htx_get_blk_name(htx, blk);
430 v = htx_get_blk_value(htx, blk);
431 STRM_TRACE(conf, s, "\t%.*s: %.*s",
432 (int)n.len, n.ptr, (int)v.len, v.ptr);
Christopher Faulet1339d742016-05-11 16:48:33 +0200433 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200434 return 1;
435}
436
437static int
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100438trace_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
439 unsigned int offset, unsigned int len)
440{
441 struct trace_config *conf = FLT_CONF(filter);
442 int ret = len;
443
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200444 if (ret && conf->rand_forwarding) {
445 struct htx *htx = htxbuf(&msg->chn->buf);
446 struct htx_blk *blk;
447 uint32_t sz, data = 0;
Christopher Faulet50fe9fb2019-06-11 10:20:57 +0200448 unsigned int off = offset;
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200449
450 for (blk = htx_get_first_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) {
451 if (htx_get_blk_type(blk) != HTX_BLK_DATA)
452 break;
453
454 sz = htx_get_blksz(blk);
Christopher Faulet50fe9fb2019-06-11 10:20:57 +0200455 if (off >= sz) {
456 off -= sz;
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200457 continue;
458 }
Christopher Faulet50fe9fb2019-06-11 10:20:57 +0200459 data += sz - off;
460 off = 0;
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200461 if (data > len) {
462 data = len;
463 break;
464 }
465 }
Christopher Faulet647fe1d2019-06-12 16:07:48 +0200466 if (data) {
467 ret = random() % (ret+1);
468 if (!ret || ret >= data)
469 ret = len;
470 }
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200471 }
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100472
473 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
474 "offset=%u - len=%u - forward=%d",
475 __FUNCTION__,
476 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
477 offset, len, ret);
478
479 if (conf->hexdump)
Christopher Faulet27ba2dc2018-12-05 11:53:24 +0100480 trace_htx_hexdump(htxbuf(&msg->chn->buf), offset, len);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100481
482 if (ret != len)
483 task_wakeup(s->task, TASK_WOKEN_MSG);
484 return ret;
485}
486
487static int
Christopher Faulete6c3b692015-09-02 17:15:16 +0200488trace_http_end(struct stream *s, struct filter *filter,
489 struct http_msg *msg)
490{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100491 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200492
493 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
494 __FUNCTION__,
495 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
496 return 1;
497}
498
499static void
500trace_http_reset(struct stream *s, struct filter *filter,
501 struct http_msg *msg)
502{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100503 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200504
505 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
506 __FUNCTION__,
507 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
508}
509
510static void
511trace_http_reply(struct stream *s, struct filter *filter, short status,
Willy Tarreau83061a82018-07-13 11:56:34 +0200512 const struct buffer *msg)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200513{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100514 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200515
516 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
517 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
518}
519
Christopher Faulete6c3b692015-09-02 17:15:16 +0200520/**************************************************************************
521 * Hooks to filter TCP data
522 *************************************************************************/
523static int
524trace_tcp_data(struct stream *s, struct filter *filter, struct channel *chn)
525{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100526 struct trace_config *conf = FLT_CONF(filter);
Willy Tarreauf1589372018-06-19 07:22:43 +0200527 int avail = ci_data(chn) - FLT_NXT(filter, chn);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200528 int ret = avail;
529
530 if (ret && conf->rand_parsing)
531 ret = random() % (ret+1);
532
533 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - next=%u - avail=%u - consume=%d",
534 __FUNCTION__,
535 channel_label(chn), proxy_mode(s), stream_pos(s),
536 FLT_NXT(filter, chn), avail, ret);
537
538 if (ret != avail)
539 task_wakeup(s->task, TASK_WOKEN_MSG);
540 return ret;
541}
542
543static int
544trace_tcp_forward_data(struct stream *s, struct filter *filter, struct channel *chn,
545 unsigned int len)
546{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100547 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200548 int ret = len;
549
550 if (ret && conf->rand_forwarding)
551 ret = random() % (ret+1);
552
553 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - len=%u - fwd=%u - forward=%d",
554 __FUNCTION__,
555 channel_label(chn), proxy_mode(s), stream_pos(s), len,
556 FLT_FWD(filter, chn), ret);
557
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100558 if (conf->hexdump) {
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200559 c_adv(chn, FLT_FWD(filter, chn));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100560 trace_raw_hexdump(&chn->buf, ret, co_data(chn));
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200561 c_rew(chn, FLT_FWD(filter, chn));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100562 }
563
Christopher Faulete6c3b692015-09-02 17:15:16 +0200564 if (ret != len)
565 task_wakeup(s->task, TASK_WOKEN_MSG);
566 return ret;
567}
568
569/********************************************************************
570 * Functions that manage the filter initialization
571 ********************************************************************/
572struct flt_ops trace_ops = {
573 /* Manage trace filter, called for each filter declaration */
Christopher Fauletf2273722017-07-27 16:58:42 +0200574 .init = trace_init,
575 .deinit = trace_deinit,
576 .check = trace_check,
577 .init_per_thread = trace_init_per_thread,
578 .deinit_per_thread = trace_deinit_per_thread,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200579
580 /* Handle start/stop of streams */
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200581 .attach = trace_attach,
582 .detach = trace_detach,
583 .stream_start = trace_stream_start,
584 .stream_set_backend = trace_stream_set_backend,
585 .stream_stop = trace_stream_stop,
Christopher Fauleta00d8172016-11-10 14:58:05 +0100586 .check_timeouts = trace_check_timeouts,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200587
588 /* Handle channels activity */
589 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200590 .channel_pre_analyze = trace_chn_analyze,
591 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200592 .channel_end_analyze = trace_chn_end_analyze,
593
594 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200595 .http_headers = trace_http_headers,
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100596 .http_payload = trace_http_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200597 .http_end = trace_http_end,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200598 .http_reset = trace_http_reset,
599 .http_reply = trace_http_reply,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200600
601 /* Filter TCP data */
602 .tcp_data = trace_tcp_data,
603 .tcp_forward_data = trace_tcp_forward_data,
604};
605
606/* Return -1 on error, else 0 */
607static int
608parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200609 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200610{
611 struct trace_config *conf;
612 int pos = *cur_arg;
613
614 conf = calloc(1, sizeof(*conf));
615 if (!conf) {
616 memprintf(err, "%s: out of memory", args[*cur_arg]);
617 return -1;
618 }
619 conf->proxy = px;
620
621 if (!strcmp(args[pos], "trace")) {
622 pos++;
623
624 while (*args[pos]) {
625 if (!strcmp(args[pos], "name")) {
626 if (!*args[pos + 1]) {
627 memprintf(err, "'%s' : '%s' option without value",
628 args[*cur_arg], args[pos]);
629 goto error;
630 }
631 conf->name = strdup(args[pos + 1]);
632 if (!conf->name) {
633 memprintf(err, "%s: out of memory", args[*cur_arg]);
634 goto error;
635 }
636 pos++;
637 }
638 else if (!strcmp(args[pos], "random-parsing"))
639 conf->rand_parsing = 1;
640 else if (!strcmp(args[pos], "random-forwarding"))
641 conf->rand_forwarding = 1;
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100642 else if (!strcmp(args[pos], "hexdump"))
643 conf->hexdump = 1;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200644 else
645 break;
646 pos++;
647 }
648 *cur_arg = pos;
Christopher Fauletf4a4ef72018-12-07 17:39:53 +0100649 fconf->id = trace_flt_id;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100650 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200651 }
652
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100653 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200654 return 0;
655
656 error:
657 if (conf->name)
658 free(conf->name);
659 free(conf);
660 return -1;
661}
662
663/* Declare the filter parser for "trace" keyword */
664static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200665 { "trace", parse_trace_flt, NULL },
666 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200667 }
668};
669
Willy Tarreau0108d902018-11-25 19:14:37 +0100670INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);