blob: c0660acab161420fa43ad35bd0426b19d14bd600 [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 Faulete0aa6f72018-11-30 22:23:32 +010071 return ((px->mode == PR_MODE_HTTP)
72 ? (IS_HTX_STRM(s) ? "HTX" : "HTTP")
73 : "TCP");
Christopher Faulete6c3b692015-09-02 17:15:16 +020074}
75
76static const char *
77stream_pos(const struct stream *s)
78{
79 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
80}
81
Christopher Faulet31ed32d2016-06-21 11:42:37 +020082static const char *
83filter_type(const struct filter *f)
84{
85 return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
86}
87
Christopher Fauletfcd99f82016-10-31 11:27:21 +010088static void
Christopher Faulete0aa6f72018-11-30 22:23:32 +010089trace_hexdump(struct ist ist)
Christopher Fauletfcd99f82016-10-31 11:27:21 +010090{
Christopher Faulete0aa6f72018-11-30 22:23:32 +010091 int i, j, padding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010092
Christopher Faulete0aa6f72018-11-30 22:23:32 +010093 padding = ((ist.len % 16) ? (16 - ist.len % 16) : 0);
94 for (i = 0; i < ist.len + padding; i++) {
Christopher Fauletfcd99f82016-10-31 11:27:21 +010095 if (!(i % 16))
96 fprintf(stderr, "\t0x%06x: ", i);
97 else if (!(i % 8))
98 fprintf(stderr, " ");
99
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100100 if (i < ist.len)
101 fprintf(stderr, "%02x ", (unsigned char)*(ist.ptr+i));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100102 else
103 fprintf(stderr, " ");
104
105 /* print ASCII dump */
106 if (i % 16 == 15) {
107 fprintf(stderr, " |");
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100108 for(j = i - 15; j <= i && j < ist.len; j++)
109 fprintf(stderr, "%c", (isprint(*(ist.ptr+j)) ? *(ist.ptr+j) : '.'));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100110 fprintf(stderr, "|\n");
111 }
112 }
113}
114
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100115static void
116trace_raw_hexdump(struct buffer *buf, int len, int out)
117{
118 unsigned char p[len];
119 int block1, block2;
120
121 block1 = len;
122 if (block1 > b_contig_data(buf, out))
123 block1 = b_contig_data(buf, out);
124 block2 = len - block1;
125
126 memcpy(p, b_head(buf), block1);
127 memcpy(p+block1, b_orig(buf), block2);
128 trace_hexdump(ist2(p, len));
129}
130
131static void
132trace_htx_hexdump(struct htx *htx, unsigned int offset, unsigned int len)
133{
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100134 struct htx_blk *blk;
135
Christopher Fauletee847d42019-05-23 11:55:33 +0200136 for (blk = htx_get_first_blk(htx); blk && len; blk = htx_get_next_blk(htx, blk)) {
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100137 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Fauletee847d42019-05-23 11:55:33 +0200138 uint32_t sz = htx_get_blksz(blk);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100139 struct ist v;
140
Christopher Fauletee847d42019-05-23 11:55:33 +0200141 if (offset >= sz) {
142 offset -= sz;
143 continue;
144 }
145
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100146 v = htx_get_blk_value(htx, blk);
147 v.ptr += offset;
148 v.len -= offset;
149 offset = 0;
150
151 if (v.len > len)
152 v.len = len;
153 len -= v.len;
Christopher Faulet2d7c5392019-06-03 10:41:26 +0200154 if (type == HTX_BLK_DATA)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100155 trace_hexdump(v);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100156 }
157}
158
Christopher Faulete6c3b692015-09-02 17:15:16 +0200159/***************************************************************************
160 * Hooks that manage the filter lifecycle (init/check/deinit)
161 **************************************************************************/
162/* Initialize the filter. Returns -1 on error, else 0. */
163static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100164trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200165{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100166 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200167
168 if (conf->name)
169 memprintf(&conf->name, "%s/%s", conf->name, px->id);
170 else
171 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100172
Christopher Faulet6e540952018-12-03 22:43:41 +0100173 fconf->flags |= FLT_CFG_FL_HTX;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100174 fconf->conf = conf;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100175
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100176 TRACE(conf, "filter initialized [read random=%s - fwd random=%s - hexdump=%s]",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200177 (conf->rand_parsing ? "true" : "false"),
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100178 (conf->rand_forwarding ? "true" : "false"),
179 (conf->hexdump ? "true" : "false"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200180 return 0;
181}
182
183/* Free ressources allocated by the trace filter. */
184static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100185trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200186{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100187 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200188
189 if (conf) {
190 TRACE(conf, "filter deinitialized");
191 free(conf->name);
192 free(conf);
193 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100194 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200195}
196
197/* Check configuration of a trace filter for a specified proxy.
198 * Return 1 on error, else 0. */
199static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100200trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200201{
202 return 0;
203}
204
Christopher Fauletf2273722017-07-27 16:58:42 +0200205/* Initialize the filter for each thread. Return -1 on error, else 0. */
206static int
207trace_init_per_thread(struct proxy *px, struct flt_conf *fconf)
208{
209 struct trace_config *conf = fconf->conf;
210
211 TRACE(conf, "filter initialized for thread tid %u", tid);
212 return 0;
213}
214
215/* Free ressources allocate by the trace filter for each thread. */
216static void
217trace_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
218{
219 struct trace_config *conf = fconf->conf;
220
221 if (conf)
222 TRACE(conf, "filter deinitialized for thread tid %u", tid);
223}
224
Christopher Faulete6c3b692015-09-02 17:15:16 +0200225/**************************************************************************
226 * Hooks to handle start/stop of streams
227 *************************************************************************/
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200228/* Called when a filter instance is created and attach to a stream */
229static int
230trace_attach(struct stream *s, struct filter *filter)
231{
232 struct trace_config *conf = FLT_CONF(filter);
233
234 STRM_TRACE(conf, s, "%-25s: filter-type=%s",
235 __FUNCTION__, filter_type(filter));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100236
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200237 return 1;
238}
239
240/* Called when a filter instance is detach from a stream, just before its
241 * destruction */
242static void
243trace_detach(struct stream *s, struct filter *filter)
244{
245 struct trace_config *conf = FLT_CONF(filter);
246
247 STRM_TRACE(conf, s, "%-25s: filter-type=%s",
248 __FUNCTION__, filter_type(filter));
249}
250
Christopher Faulete6c3b692015-09-02 17:15:16 +0200251/* Called when a stream is created */
252static int
253trace_stream_start(struct stream *s, struct filter *filter)
254{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100255 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200256
257 STRM_TRACE(conf, s, "%-25s",
258 __FUNCTION__);
259 return 0;
260}
261
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200262
263/* Called when a backend is set for a stream */
264static int
265trace_stream_set_backend(struct stream *s, struct filter *filter,
266 struct proxy *be)
267{
268 struct trace_config *conf = FLT_CONF(filter);
269
270 STRM_TRACE(conf, s, "%-25s: backend=%s",
271 __FUNCTION__, be->id);
272 return 0;
273}
274
Christopher Faulete6c3b692015-09-02 17:15:16 +0200275/* Called when a stream is destroyed */
276static void
277trace_stream_stop(struct stream *s, struct filter *filter)
278{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100279 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200280
281 STRM_TRACE(conf, s, "%-25s",
282 __FUNCTION__);
283}
284
Christopher Fauleta00d8172016-11-10 14:58:05 +0100285/* Called when the stream is woken up because of an expired timer */
286static void
287trace_check_timeouts(struct stream *s, struct filter *filter)
288{
289 struct trace_config *conf = FLT_CONF(filter);
290
291 STRM_TRACE(conf, s, "%-25s",
292 __FUNCTION__);
293}
294
Christopher Faulete6c3b692015-09-02 17:15:16 +0200295/**************************************************************************
296 * Hooks to handle channels activity
297 *************************************************************************/
298/* Called when analyze starts for a given channel */
299static int
300trace_chn_start_analyze(struct stream *s, struct filter *filter,
301 struct channel *chn)
302{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100303 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200304
305 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
306 __FUNCTION__,
307 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200308 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
309 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100310 register_data_filter(s, chn, filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200311 return 1;
312}
313
314/* Called before a processing happens on a given channel */
315static int
316trace_chn_analyze(struct stream *s, struct filter *filter,
317 struct channel *chn, unsigned an_bit)
318{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100319 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200320 char *ana;
321
322 switch (an_bit) {
323 case AN_REQ_INSPECT_FE:
324 ana = "AN_REQ_INSPECT_FE";
325 break;
326 case AN_REQ_WAIT_HTTP:
327 ana = "AN_REQ_WAIT_HTTP";
328 break;
329 case AN_REQ_HTTP_BODY:
330 ana = "AN_REQ_HTTP_BODY";
331 break;
332 case AN_REQ_HTTP_PROCESS_FE:
333 ana = "AN_REQ_HTTP_PROCESS_FE";
334 break;
335 case AN_REQ_SWITCHING_RULES:
336 ana = "AN_REQ_SWITCHING_RULES";
337 break;
338 case AN_REQ_INSPECT_BE:
339 ana = "AN_REQ_INSPECT_BE";
340 break;
341 case AN_REQ_HTTP_PROCESS_BE:
342 ana = "AN_REQ_HTTP_PROCESS_BE";
343 break;
344 case AN_REQ_SRV_RULES:
345 ana = "AN_REQ_SRV_RULES";
346 break;
347 case AN_REQ_HTTP_INNER:
348 ana = "AN_REQ_HTTP_INNER";
349 break;
350 case AN_REQ_HTTP_TARPIT:
351 ana = "AN_REQ_HTTP_TARPIT";
352 break;
353 case AN_REQ_STICKING_RULES:
354 ana = "AN_REQ_STICKING_RULES";
355 break;
356 case AN_REQ_PRST_RDP_COOKIE:
357 ana = "AN_REQ_PRST_RDP_COOKIE";
358 break;
359 case AN_REQ_HTTP_XFER_BODY:
360 ana = "AN_REQ_HTTP_XFER_BODY";
361 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200362 case AN_RES_INSPECT:
363 ana = "AN_RES_INSPECT";
364 break;
365 case AN_RES_WAIT_HTTP:
366 ana = "AN_RES_WAIT_HTTP";
367 break;
368 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
369 ana = "AN_RES_HTTP_PROCESS_FE/BE";
370 break;
371 case AN_RES_STORE_RULES:
372 ana = "AN_RES_STORE_RULES";
373 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200374 case AN_RES_HTTP_XFER_BODY:
375 ana = "AN_RES_HTTP_XFER_BODY";
376 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200377 default:
378 ana = "unknown";
379 }
380
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200381 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
382 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200383 __FUNCTION__,
384 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200385 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200386 return 1;
387}
388
389/* Called when analyze ends for a given channel */
390static int
391trace_chn_end_analyze(struct stream *s, struct filter *filter,
392 struct channel *chn)
393{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100394 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200395
396 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
397 __FUNCTION__,
398 channel_label(chn), proxy_mode(s), stream_pos(s));
399 return 1;
400}
401
402/**************************************************************************
403 * Hooks to filter HTTP messages
404 *************************************************************************/
405static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200406trace_http_headers(struct stream *s, struct filter *filter,
407 struct http_msg *msg)
408{
409 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulet1339d742016-05-11 16:48:33 +0200410
411 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
412 __FUNCTION__,
413 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
414
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100415 if (IS_HTX_STRM(s)) {
Christopher Faulet27ba2dc2018-12-05 11:53:24 +0100416 struct htx *htx = htxbuf(&msg->chn->buf);
Christopher Faulet297fbb42019-05-13 14:41:27 +0200417 struct htx_sl *sl = http_get_stline(htx);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100418 int32_t pos;
419
420 STRM_TRACE(conf, s, "\t%.*s %.*s %.*s",
421 HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl),
422 HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
423 HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
424
Christopher Fauleta3f15502019-05-13 15:27:23 +0200425 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100426 struct htx_blk *blk = htx_get_blk(htx, pos);
427 enum htx_blk_type type = htx_get_blk_type(blk);
428 struct ist n, v;
429
430 if (type == HTX_BLK_EOH)
431 break;
432 if (type != HTX_BLK_HDR)
433 continue;
434
435 n = htx_get_blk_name(htx, blk);
436 v = htx_get_blk_value(htx, blk);
437 STRM_TRACE(conf, s, "\t%.*s: %.*s",
438 (int)n.len, n.ptr, (int)v.len, v.ptr);
439 }
440 }
441 else {
442 struct hdr_idx *hdr_idx;
443 char *cur_hdr;
444 int cur_idx;
445
446 STRM_TRACE(conf, s, "\t%.*s", MIN(msg->sl.rq.l, 74), ci_head(msg->chn));
447 hdr_idx = &s->txn->hdr_idx;
448 cur_idx = hdr_idx_first_idx(hdr_idx);
449 cur_hdr = ci_head(msg->chn) + hdr_idx_first_pos(hdr_idx);
450 while (cur_idx) {
451 STRM_TRACE(conf, s, "\t%.*s",
452 MIN(hdr_idx->v[cur_idx].len, 74), cur_hdr);
453 cur_hdr += hdr_idx->v[cur_idx].len + hdr_idx->v[cur_idx].cr + 1;
454 cur_idx = hdr_idx->v[cur_idx].next;
455 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200456 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200457 return 1;
458}
459
460static int
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100461trace_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
462 unsigned int offset, unsigned int len)
463{
464 struct trace_config *conf = FLT_CONF(filter);
465 int ret = len;
466
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200467 if (ret && conf->rand_forwarding) {
468 struct htx *htx = htxbuf(&msg->chn->buf);
469 struct htx_blk *blk;
470 uint32_t sz, data = 0;
Christopher Faulet50fe9fb2019-06-11 10:20:57 +0200471 unsigned int off = offset;
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200472
473 for (blk = htx_get_first_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) {
474 if (htx_get_blk_type(blk) != HTX_BLK_DATA)
475 break;
476
477 sz = htx_get_blksz(blk);
Christopher Faulet50fe9fb2019-06-11 10:20:57 +0200478 if (off >= sz) {
479 off -= sz;
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200480 continue;
481 }
Christopher Faulet50fe9fb2019-06-11 10:20:57 +0200482 data += sz - off;
483 off = 0;
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200484 if (data > len) {
485 data = len;
486 break;
487 }
488 }
Christopher Faulet647fe1d2019-06-12 16:07:48 +0200489 if (data) {
490 ret = random() % (ret+1);
491 if (!ret || ret >= data)
492 ret = len;
493 }
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200494 }
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100495
496 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
497 "offset=%u - len=%u - forward=%d",
498 __FUNCTION__,
499 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
500 offset, len, ret);
501
502 if (conf->hexdump)
Christopher Faulet27ba2dc2018-12-05 11:53:24 +0100503 trace_htx_hexdump(htxbuf(&msg->chn->buf), offset, len);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100504
505 if (ret != len)
506 task_wakeup(s->task, TASK_WOKEN_MSG);
507 return ret;
508}
509
510static int
Christopher Faulete6c3b692015-09-02 17:15:16 +0200511trace_http_data(struct stream *s, struct filter *filter,
512 struct http_msg *msg)
513{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100514 struct trace_config *conf = FLT_CONF(filter);
Willy Tarreauf1589372018-06-19 07:22:43 +0200515 int avail = MIN(msg->chunk_len + msg->next, ci_data(msg->chn)) - FLT_NXT(filter, msg->chn);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200516 int ret = avail;
517
518 if (ret && conf->rand_parsing)
519 ret = random() % (ret+1);
520
521 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
522 "chunk_len=%llu - next=%u - fwd=%u - avail=%d - consume=%d",
523 __FUNCTION__,
524 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
525 msg->chunk_len, FLT_NXT(filter, msg->chn),
526 FLT_FWD(filter, msg->chn), avail, ret);
527 if (ret != avail)
528 task_wakeup(s->task, TASK_WOKEN_MSG);
529 return ret;
530}
531
532static int
533trace_http_chunk_trailers(struct stream *s, struct filter *filter,
534 struct http_msg *msg)
535{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100536 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200537
538 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
539 __FUNCTION__,
540 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
541 return 1;
542}
543
544static int
545trace_http_end(struct stream *s, struct filter *filter,
546 struct http_msg *msg)
547{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100548 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200549
550 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
551 __FUNCTION__,
552 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
553 return 1;
554}
555
556static void
557trace_http_reset(struct stream *s, struct filter *filter,
558 struct http_msg *msg)
559{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100560 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200561
562 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
563 __FUNCTION__,
564 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
565}
566
567static void
568trace_http_reply(struct stream *s, struct filter *filter, short status,
Willy Tarreau83061a82018-07-13 11:56:34 +0200569 const struct buffer *msg)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200570{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100571 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200572
573 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
574 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
575}
576
577static int
578trace_http_forward_data(struct stream *s, struct filter *filter,
579 struct http_msg *msg, unsigned int len)
580{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100581 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200582 int ret = len;
583
584 if (ret && conf->rand_forwarding)
585 ret = random() % (ret+1);
586
587 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
588 "len=%u - nxt=%u - fwd=%u - forward=%d",
589 __FUNCTION__,
590 channel_label(msg->chn), proxy_mode(s), stream_pos(s), len,
591 FLT_NXT(filter, msg->chn), FLT_FWD(filter, msg->chn), ret);
592
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100593 if (conf->hexdump) {
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200594 c_adv(msg->chn, FLT_FWD(filter, msg->chn));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100595 trace_raw_hexdump(&msg->chn->buf, ret, co_data(msg->chn));
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200596 c_rew(msg->chn, FLT_FWD(filter, msg->chn));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100597 }
598
Christopher Faulete6c3b692015-09-02 17:15:16 +0200599 if ((ret != len) ||
600 (FLT_NXT(filter, msg->chn) != FLT_FWD(filter, msg->chn) + ret))
601 task_wakeup(s->task, TASK_WOKEN_MSG);
602 return ret;
603}
604
605/**************************************************************************
606 * Hooks to filter TCP data
607 *************************************************************************/
608static int
609trace_tcp_data(struct stream *s, struct filter *filter, struct channel *chn)
610{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100611 struct trace_config *conf = FLT_CONF(filter);
Willy Tarreauf1589372018-06-19 07:22:43 +0200612 int avail = ci_data(chn) - FLT_NXT(filter, chn);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200613 int ret = avail;
614
615 if (ret && conf->rand_parsing)
616 ret = random() % (ret+1);
617
618 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - next=%u - avail=%u - consume=%d",
619 __FUNCTION__,
620 channel_label(chn), proxy_mode(s), stream_pos(s),
621 FLT_NXT(filter, chn), avail, ret);
622
623 if (ret != avail)
624 task_wakeup(s->task, TASK_WOKEN_MSG);
625 return ret;
626}
627
628static int
629trace_tcp_forward_data(struct stream *s, struct filter *filter, struct channel *chn,
630 unsigned int len)
631{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100632 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200633 int ret = len;
634
635 if (ret && conf->rand_forwarding)
636 ret = random() % (ret+1);
637
638 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - len=%u - fwd=%u - forward=%d",
639 __FUNCTION__,
640 channel_label(chn), proxy_mode(s), stream_pos(s), len,
641 FLT_FWD(filter, chn), ret);
642
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100643 if (conf->hexdump) {
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200644 c_adv(chn, FLT_FWD(filter, chn));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100645 trace_raw_hexdump(&chn->buf, ret, co_data(chn));
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200646 c_rew(chn, FLT_FWD(filter, chn));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100647 }
648
Christopher Faulete6c3b692015-09-02 17:15:16 +0200649 if (ret != len)
650 task_wakeup(s->task, TASK_WOKEN_MSG);
651 return ret;
652}
653
654/********************************************************************
655 * Functions that manage the filter initialization
656 ********************************************************************/
657struct flt_ops trace_ops = {
658 /* Manage trace filter, called for each filter declaration */
Christopher Fauletf2273722017-07-27 16:58:42 +0200659 .init = trace_init,
660 .deinit = trace_deinit,
661 .check = trace_check,
662 .init_per_thread = trace_init_per_thread,
663 .deinit_per_thread = trace_deinit_per_thread,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200664
665 /* Handle start/stop of streams */
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200666 .attach = trace_attach,
667 .detach = trace_detach,
668 .stream_start = trace_stream_start,
669 .stream_set_backend = trace_stream_set_backend,
670 .stream_stop = trace_stream_stop,
Christopher Fauleta00d8172016-11-10 14:58:05 +0100671 .check_timeouts = trace_check_timeouts,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200672
673 /* Handle channels activity */
674 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200675 .channel_pre_analyze = trace_chn_analyze,
676 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200677 .channel_end_analyze = trace_chn_end_analyze,
678
679 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200680 .http_headers = trace_http_headers,
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100681 .http_payload = trace_http_payload,
682
Christopher Faulete6c3b692015-09-02 17:15:16 +0200683 .http_data = trace_http_data,
684 .http_chunk_trailers = trace_http_chunk_trailers,
685 .http_end = trace_http_end,
686
687 .http_reset = trace_http_reset,
688 .http_reply = trace_http_reply,
689 .http_forward_data = trace_http_forward_data,
690
691 /* Filter TCP data */
692 .tcp_data = trace_tcp_data,
693 .tcp_forward_data = trace_tcp_forward_data,
694};
695
696/* Return -1 on error, else 0 */
697static int
698parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200699 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200700{
701 struct trace_config *conf;
702 int pos = *cur_arg;
703
704 conf = calloc(1, sizeof(*conf));
705 if (!conf) {
706 memprintf(err, "%s: out of memory", args[*cur_arg]);
707 return -1;
708 }
709 conf->proxy = px;
710
711 if (!strcmp(args[pos], "trace")) {
712 pos++;
713
714 while (*args[pos]) {
715 if (!strcmp(args[pos], "name")) {
716 if (!*args[pos + 1]) {
717 memprintf(err, "'%s' : '%s' option without value",
718 args[*cur_arg], args[pos]);
719 goto error;
720 }
721 conf->name = strdup(args[pos + 1]);
722 if (!conf->name) {
723 memprintf(err, "%s: out of memory", args[*cur_arg]);
724 goto error;
725 }
726 pos++;
727 }
728 else if (!strcmp(args[pos], "random-parsing"))
729 conf->rand_parsing = 1;
730 else if (!strcmp(args[pos], "random-forwarding"))
731 conf->rand_forwarding = 1;
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100732 else if (!strcmp(args[pos], "hexdump"))
733 conf->hexdump = 1;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200734 else
735 break;
736 pos++;
737 }
738 *cur_arg = pos;
Christopher Fauletf4a4ef72018-12-07 17:39:53 +0100739 fconf->id = trace_flt_id;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100740 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200741 }
742
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100743 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200744 return 0;
745
746 error:
747 if (conf->name)
748 free(conf->name);
749 free(conf);
750 return -1;
751}
752
753/* Declare the filter parser for "trace" keyword */
754static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200755 { "trace", parse_trace_flt, NULL },
756 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200757 }
758};
759
Willy Tarreau0108d902018-11-25 19:14:37 +0100760INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);