blob: 0ccf1fc3f5ca288fd3da25de3ebd0e806b78857f [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>
16#include <common/initcall.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020017#include <common/standard.h>
18#include <common/time.h>
19#include <common/tools.h>
20
21#include <types/channel.h>
22#include <types/filters.h>
23#include <types/global.h>
Christopher Faulete0aa6f72018-11-30 22:23:32 +010024#include <types/h1.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020025#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>
31#include <proto/htx.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020032#include <proto/log.h>
Christopher Faulete0aa6f72018-11-30 22:23:32 +010033#include <proto/proto_http.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020034#include <proto/stream.h>
35
Christopher Fauletf4a4ef72018-12-07 17:39:53 +010036const char *trace_flt_id = "trace filter";
37
Christopher Faulete6c3b692015-09-02 17:15:16 +020038struct flt_ops trace_ops;
39
40struct trace_config {
41 struct proxy *proxy;
42 char *name;
43 int rand_parsing;
44 int rand_forwarding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010045 int hexdump;
Christopher Faulete6c3b692015-09-02 17:15:16 +020046};
47
48#define TRACE(conf, fmt, ...) \
49 fprintf(stderr, "%d.%06d [%-20s] " fmt "\n", \
50 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
51 ##__VA_ARGS__)
52
Christopher Fauletfcd99f82016-10-31 11:27:21 +010053#define STRM_TRACE(conf, strm, fmt, ...) \
54 fprintf(stderr, "%d.%06d [%-20s] [strm %p(%x) 0x%08x 0x%08x] " fmt "\n", \
55 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
56 strm, (strm ? ((struct stream *)strm)->uniq_id : ~0U), \
57 (strm ? strm->req.analysers : 0), (strm ? strm->res.analysers : 0), \
Christopher Faulete6c3b692015-09-02 17:15:16 +020058 ##__VA_ARGS__)
59
60
61static const char *
62channel_label(const struct channel *chn)
63{
64 return (chn->flags & CF_ISRESP) ? "RESPONSE" : "REQUEST";
65}
66
67static const char *
68proxy_mode(const struct stream *s)
69{
70 struct proxy *px = (s->flags & SF_BE_ASSIGNED ? s->be : strm_fe(s));
71
Christopher Faulete0aa6f72018-11-30 22:23:32 +010072 return ((px->mode == PR_MODE_HTTP)
73 ? (IS_HTX_STRM(s) ? "HTX" : "HTTP")
74 : "TCP");
Christopher Faulete6c3b692015-09-02 17:15:16 +020075}
76
77static const char *
78stream_pos(const struct stream *s)
79{
80 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
81}
82
Christopher Faulet31ed32d2016-06-21 11:42:37 +020083static const char *
84filter_type(const struct filter *f)
85{
86 return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
87}
88
Christopher Fauletfcd99f82016-10-31 11:27:21 +010089static void
Christopher Faulete0aa6f72018-11-30 22:23:32 +010090trace_hexdump(struct ist ist)
Christopher Fauletfcd99f82016-10-31 11:27:21 +010091{
Christopher Faulete0aa6f72018-11-30 22:23:32 +010092 int i, j, padding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010093
Christopher Faulete0aa6f72018-11-30 22:23:32 +010094 padding = ((ist.len % 16) ? (16 - ist.len % 16) : 0);
95 for (i = 0; i < ist.len + padding; i++) {
Christopher Fauletfcd99f82016-10-31 11:27:21 +010096 if (!(i % 16))
97 fprintf(stderr, "\t0x%06x: ", i);
98 else if (!(i % 8))
99 fprintf(stderr, " ");
100
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100101 if (i < ist.len)
102 fprintf(stderr, "%02x ", (unsigned char)*(ist.ptr+i));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100103 else
104 fprintf(stderr, " ");
105
106 /* print ASCII dump */
107 if (i % 16 == 15) {
108 fprintf(stderr, " |");
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100109 for(j = i - 15; j <= i && j < ist.len; j++)
110 fprintf(stderr, "%c", (isprint(*(ist.ptr+j)) ? *(ist.ptr+j) : '.'));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100111 fprintf(stderr, "|\n");
112 }
113 }
114}
115
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100116static void
117trace_raw_hexdump(struct buffer *buf, int len, int out)
118{
119 unsigned char p[len];
120 int block1, block2;
121
122 block1 = len;
123 if (block1 > b_contig_data(buf, out))
124 block1 = b_contig_data(buf, out);
125 block2 = len - block1;
126
127 memcpy(p, b_head(buf), block1);
128 memcpy(p+block1, b_orig(buf), block2);
129 trace_hexdump(ist2(p, len));
130}
131
132static void
133trace_htx_hexdump(struct htx *htx, unsigned int offset, unsigned int len)
134{
135 struct htx_ret htx_ret;
136 struct htx_blk *blk;
137
138 htx_ret = htx_find_blk(htx, offset);
139 blk = htx_ret.blk;
140 offset = htx_ret.ret;
141
142 while (blk) {
143 enum htx_blk_type type = htx_get_blk_type(blk);
144 struct ist v;
145
146 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;
154 if (type == HTX_BLK_DATA || type == HTX_BLK_TLR)
155 trace_hexdump(v);
156 blk = htx_get_next_blk(htx, blk);
157 }
158}
159
Christopher Faulete6c3b692015-09-02 17:15:16 +0200160/***************************************************************************
161 * Hooks that manage the filter lifecycle (init/check/deinit)
162 **************************************************************************/
163/* Initialize the filter. Returns -1 on error, else 0. */
164static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100165trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200166{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100167 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200168
169 if (conf->name)
170 memprintf(&conf->name, "%s/%s", conf->name, px->id);
171 else
172 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100173
Christopher Faulet6e540952018-12-03 22:43:41 +0100174 fconf->flags |= FLT_CFG_FL_HTX;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100175 fconf->conf = conf;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100176
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100177 TRACE(conf, "filter initialized [read random=%s - fwd random=%s - hexdump=%s]",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200178 (conf->rand_parsing ? "true" : "false"),
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100179 (conf->rand_forwarding ? "true" : "false"),
180 (conf->hexdump ? "true" : "false"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200181 return 0;
182}
183
184/* Free ressources allocated by the trace filter. */
185static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100186trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200187{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100188 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200189
190 if (conf) {
191 TRACE(conf, "filter deinitialized");
192 free(conf->name);
193 free(conf);
194 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100195 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200196}
197
198/* Check configuration of a trace filter for a specified proxy.
199 * Return 1 on error, else 0. */
200static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100201trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200202{
203 return 0;
204}
205
Christopher Fauletf2273722017-07-27 16:58:42 +0200206/* Initialize the filter for each thread. Return -1 on error, else 0. */
207static int
208trace_init_per_thread(struct proxy *px, struct flt_conf *fconf)
209{
210 struct trace_config *conf = fconf->conf;
211
212 TRACE(conf, "filter initialized for thread tid %u", tid);
213 return 0;
214}
215
216/* Free ressources allocate by the trace filter for each thread. */
217static void
218trace_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
219{
220 struct trace_config *conf = fconf->conf;
221
222 if (conf)
223 TRACE(conf, "filter deinitialized for thread tid %u", tid);
224}
225
Christopher Faulete6c3b692015-09-02 17:15:16 +0200226/**************************************************************************
227 * Hooks to handle start/stop of streams
228 *************************************************************************/
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200229/* Called when a filter instance is created and attach to a stream */
230static int
231trace_attach(struct stream *s, struct filter *filter)
232{
233 struct trace_config *conf = FLT_CONF(filter);
234
235 STRM_TRACE(conf, s, "%-25s: filter-type=%s",
236 __FUNCTION__, filter_type(filter));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100237
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200238 return 1;
239}
240
241/* Called when a filter instance is detach from a stream, just before its
242 * destruction */
243static void
244trace_detach(struct stream *s, struct filter *filter)
245{
246 struct trace_config *conf = FLT_CONF(filter);
247
248 STRM_TRACE(conf, s, "%-25s: filter-type=%s",
249 __FUNCTION__, filter_type(filter));
250}
251
Christopher Faulete6c3b692015-09-02 17:15:16 +0200252/* Called when a stream is created */
253static int
254trace_stream_start(struct stream *s, struct filter *filter)
255{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100256 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200257
258 STRM_TRACE(conf, s, "%-25s",
259 __FUNCTION__);
260 return 0;
261}
262
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200263
264/* Called when a backend is set for a stream */
265static int
266trace_stream_set_backend(struct stream *s, struct filter *filter,
267 struct proxy *be)
268{
269 struct trace_config *conf = FLT_CONF(filter);
270
271 STRM_TRACE(conf, s, "%-25s: backend=%s",
272 __FUNCTION__, be->id);
273 return 0;
274}
275
Christopher Faulete6c3b692015-09-02 17:15:16 +0200276/* Called when a stream is destroyed */
277static void
278trace_stream_stop(struct stream *s, struct filter *filter)
279{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100280 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200281
282 STRM_TRACE(conf, s, "%-25s",
283 __FUNCTION__);
284}
285
Christopher Fauleta00d8172016-11-10 14:58:05 +0100286/* Called when the stream is woken up because of an expired timer */
287static void
288trace_check_timeouts(struct stream *s, struct filter *filter)
289{
290 struct trace_config *conf = FLT_CONF(filter);
291
292 STRM_TRACE(conf, s, "%-25s",
293 __FUNCTION__);
294}
295
Christopher Faulete6c3b692015-09-02 17:15:16 +0200296/**************************************************************************
297 * Hooks to handle channels activity
298 *************************************************************************/
299/* Called when analyze starts for a given channel */
300static int
301trace_chn_start_analyze(struct stream *s, struct filter *filter,
302 struct channel *chn)
303{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100304 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200305
306 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
307 __FUNCTION__,
308 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200309 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
310 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100311 register_data_filter(s, chn, filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200312 return 1;
313}
314
315/* Called before a processing happens on a given channel */
316static int
317trace_chn_analyze(struct stream *s, struct filter *filter,
318 struct channel *chn, unsigned an_bit)
319{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100320 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200321 char *ana;
322
323 switch (an_bit) {
324 case AN_REQ_INSPECT_FE:
325 ana = "AN_REQ_INSPECT_FE";
326 break;
327 case AN_REQ_WAIT_HTTP:
328 ana = "AN_REQ_WAIT_HTTP";
329 break;
330 case AN_REQ_HTTP_BODY:
331 ana = "AN_REQ_HTTP_BODY";
332 break;
333 case AN_REQ_HTTP_PROCESS_FE:
334 ana = "AN_REQ_HTTP_PROCESS_FE";
335 break;
336 case AN_REQ_SWITCHING_RULES:
337 ana = "AN_REQ_SWITCHING_RULES";
338 break;
339 case AN_REQ_INSPECT_BE:
340 ana = "AN_REQ_INSPECT_BE";
341 break;
342 case AN_REQ_HTTP_PROCESS_BE:
343 ana = "AN_REQ_HTTP_PROCESS_BE";
344 break;
345 case AN_REQ_SRV_RULES:
346 ana = "AN_REQ_SRV_RULES";
347 break;
348 case AN_REQ_HTTP_INNER:
349 ana = "AN_REQ_HTTP_INNER";
350 break;
351 case AN_REQ_HTTP_TARPIT:
352 ana = "AN_REQ_HTTP_TARPIT";
353 break;
354 case AN_REQ_STICKING_RULES:
355 ana = "AN_REQ_STICKING_RULES";
356 break;
357 case AN_REQ_PRST_RDP_COOKIE:
358 ana = "AN_REQ_PRST_RDP_COOKIE";
359 break;
360 case AN_REQ_HTTP_XFER_BODY:
361 ana = "AN_REQ_HTTP_XFER_BODY";
362 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200363 case AN_RES_INSPECT:
364 ana = "AN_RES_INSPECT";
365 break;
366 case AN_RES_WAIT_HTTP:
367 ana = "AN_RES_WAIT_HTTP";
368 break;
369 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
370 ana = "AN_RES_HTTP_PROCESS_FE/BE";
371 break;
372 case AN_RES_STORE_RULES:
373 ana = "AN_RES_STORE_RULES";
374 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200375 case AN_RES_HTTP_XFER_BODY:
376 ana = "AN_RES_HTTP_XFER_BODY";
377 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200378 default:
379 ana = "unknown";
380 }
381
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200382 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
383 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200384 __FUNCTION__,
385 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200386 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200387 return 1;
388}
389
390/* Called when analyze ends for a given channel */
391static int
392trace_chn_end_analyze(struct stream *s, struct filter *filter,
393 struct channel *chn)
394{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100395 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200396
397 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
398 __FUNCTION__,
399 channel_label(chn), proxy_mode(s), stream_pos(s));
400 return 1;
401}
402
403/**************************************************************************
404 * Hooks to filter HTTP messages
405 *************************************************************************/
406static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200407trace_http_headers(struct stream *s, struct filter *filter,
408 struct http_msg *msg)
409{
410 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulet1339d742016-05-11 16:48:33 +0200411
412 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
413 __FUNCTION__,
414 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
415
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100416 if (IS_HTX_STRM(s)) {
Christopher Faulet27ba2dc2018-12-05 11:53:24 +0100417 struct htx *htx = htxbuf(&msg->chn->buf);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100418 struct htx_sl *sl = http_find_stline(htx);
419 int32_t pos;
420
421 STRM_TRACE(conf, s, "\t%.*s %.*s %.*s",
422 HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl),
423 HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
424 HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
425
426 for (pos = htx_get_head(htx); pos != -1; pos = htx_get_next(htx, pos)) {
427 struct htx_blk *blk = htx_get_blk(htx, pos);
428 enum htx_blk_type type = htx_get_blk_type(blk);
429 struct ist n, v;
430
431 if (type == HTX_BLK_EOH)
432 break;
433 if (type != HTX_BLK_HDR)
434 continue;
435
436 n = htx_get_blk_name(htx, blk);
437 v = htx_get_blk_value(htx, blk);
438 STRM_TRACE(conf, s, "\t%.*s: %.*s",
439 (int)n.len, n.ptr, (int)v.len, v.ptr);
440 }
441 }
442 else {
443 struct hdr_idx *hdr_idx;
444 char *cur_hdr;
445 int cur_idx;
446
447 STRM_TRACE(conf, s, "\t%.*s", MIN(msg->sl.rq.l, 74), ci_head(msg->chn));
448 hdr_idx = &s->txn->hdr_idx;
449 cur_idx = hdr_idx_first_idx(hdr_idx);
450 cur_hdr = ci_head(msg->chn) + hdr_idx_first_pos(hdr_idx);
451 while (cur_idx) {
452 STRM_TRACE(conf, s, "\t%.*s",
453 MIN(hdr_idx->v[cur_idx].len, 74), cur_hdr);
454 cur_hdr += hdr_idx->v[cur_idx].len + hdr_idx->v[cur_idx].cr + 1;
455 cur_idx = hdr_idx->v[cur_idx].next;
456 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200457 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200458 return 1;
459}
460
461static int
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100462trace_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
463 unsigned int offset, unsigned int len)
464{
465 struct trace_config *conf = FLT_CONF(filter);
466 int ret = len;
467
468 if (ret && conf->rand_forwarding)
469 ret = random() % (ret+1);
470
471 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
472 "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 Faulet27ba2dc2018-12-05 11:53:24 +0100478 trace_htx_hexdump(htxbuf(&msg->chn->buf), offset, len);
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_data(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);
Willy Tarreauf1589372018-06-19 07:22:43 +0200490 int avail = MIN(msg->chunk_len + msg->next, ci_data(msg->chn)) - FLT_NXT(filter, msg->chn);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200491 int ret = avail;
492
493 if (ret && conf->rand_parsing)
494 ret = random() % (ret+1);
495
496 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
497 "chunk_len=%llu - next=%u - fwd=%u - avail=%d - consume=%d",
498 __FUNCTION__,
499 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
500 msg->chunk_len, FLT_NXT(filter, msg->chn),
501 FLT_FWD(filter, msg->chn), avail, ret);
502 if (ret != avail)
503 task_wakeup(s->task, TASK_WOKEN_MSG);
504 return ret;
505}
506
507static int
508trace_http_chunk_trailers(struct stream *s, struct filter *filter,
509 struct http_msg *msg)
510{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100511 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200512
513 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
514 __FUNCTION__,
515 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
516 return 1;
517}
518
519static int
520trace_http_end(struct stream *s, struct filter *filter,
521 struct http_msg *msg)
522{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100523 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200524
525 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
526 __FUNCTION__,
527 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
528 return 1;
529}
530
531static void
532trace_http_reset(struct stream *s, struct filter *filter,
533 struct http_msg *msg)
534{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100535 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200536
537 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
538 __FUNCTION__,
539 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
540}
541
542static void
543trace_http_reply(struct stream *s, struct filter *filter, short status,
Willy Tarreau83061a82018-07-13 11:56:34 +0200544 const struct buffer *msg)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200545{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100546 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200547
548 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
549 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
550}
551
552static int
553trace_http_forward_data(struct stream *s, struct filter *filter,
554 struct http_msg *msg, unsigned int len)
555{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100556 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200557 int ret = len;
558
559 if (ret && conf->rand_forwarding)
560 ret = random() % (ret+1);
561
562 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
563 "len=%u - nxt=%u - fwd=%u - forward=%d",
564 __FUNCTION__,
565 channel_label(msg->chn), proxy_mode(s), stream_pos(s), len,
566 FLT_NXT(filter, msg->chn), FLT_FWD(filter, msg->chn), ret);
567
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100568 if (conf->hexdump) {
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200569 c_adv(msg->chn, FLT_FWD(filter, msg->chn));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100570 trace_raw_hexdump(&msg->chn->buf, ret, co_data(msg->chn));
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200571 c_rew(msg->chn, FLT_FWD(filter, msg->chn));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100572 }
573
Christopher Faulete6c3b692015-09-02 17:15:16 +0200574 if ((ret != len) ||
575 (FLT_NXT(filter, msg->chn) != FLT_FWD(filter, msg->chn) + ret))
576 task_wakeup(s->task, TASK_WOKEN_MSG);
577 return ret;
578}
579
580/**************************************************************************
581 * Hooks to filter TCP data
582 *************************************************************************/
583static int
584trace_tcp_data(struct stream *s, struct filter *filter, struct channel *chn)
585{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100586 struct trace_config *conf = FLT_CONF(filter);
Willy Tarreauf1589372018-06-19 07:22:43 +0200587 int avail = ci_data(chn) - FLT_NXT(filter, chn);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200588 int ret = avail;
589
590 if (ret && conf->rand_parsing)
591 ret = random() % (ret+1);
592
593 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - next=%u - avail=%u - consume=%d",
594 __FUNCTION__,
595 channel_label(chn), proxy_mode(s), stream_pos(s),
596 FLT_NXT(filter, chn), avail, ret);
597
598 if (ret != avail)
599 task_wakeup(s->task, TASK_WOKEN_MSG);
600 return ret;
601}
602
603static int
604trace_tcp_forward_data(struct stream *s, struct filter *filter, struct channel *chn,
605 unsigned int len)
606{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100607 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200608 int ret = len;
609
610 if (ret && conf->rand_forwarding)
611 ret = random() % (ret+1);
612
613 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - len=%u - fwd=%u - forward=%d",
614 __FUNCTION__,
615 channel_label(chn), proxy_mode(s), stream_pos(s), len,
616 FLT_FWD(filter, chn), ret);
617
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100618 if (conf->hexdump) {
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200619 c_adv(chn, FLT_FWD(filter, chn));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100620 trace_raw_hexdump(&chn->buf, ret, co_data(chn));
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200621 c_rew(chn, FLT_FWD(filter, chn));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100622 }
623
Christopher Faulete6c3b692015-09-02 17:15:16 +0200624 if (ret != len)
625 task_wakeup(s->task, TASK_WOKEN_MSG);
626 return ret;
627}
628
629/********************************************************************
630 * Functions that manage the filter initialization
631 ********************************************************************/
632struct flt_ops trace_ops = {
633 /* Manage trace filter, called for each filter declaration */
Christopher Fauletf2273722017-07-27 16:58:42 +0200634 .init = trace_init,
635 .deinit = trace_deinit,
636 .check = trace_check,
637 .init_per_thread = trace_init_per_thread,
638 .deinit_per_thread = trace_deinit_per_thread,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200639
640 /* Handle start/stop of streams */
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200641 .attach = trace_attach,
642 .detach = trace_detach,
643 .stream_start = trace_stream_start,
644 .stream_set_backend = trace_stream_set_backend,
645 .stream_stop = trace_stream_stop,
Christopher Fauleta00d8172016-11-10 14:58:05 +0100646 .check_timeouts = trace_check_timeouts,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200647
648 /* Handle channels activity */
649 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200650 .channel_pre_analyze = trace_chn_analyze,
651 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200652 .channel_end_analyze = trace_chn_end_analyze,
653
654 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200655 .http_headers = trace_http_headers,
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100656 .http_payload = trace_http_payload,
657
Christopher Faulete6c3b692015-09-02 17:15:16 +0200658 .http_data = trace_http_data,
659 .http_chunk_trailers = trace_http_chunk_trailers,
660 .http_end = trace_http_end,
661
662 .http_reset = trace_http_reset,
663 .http_reply = trace_http_reply,
664 .http_forward_data = trace_http_forward_data,
665
666 /* Filter TCP data */
667 .tcp_data = trace_tcp_data,
668 .tcp_forward_data = trace_tcp_forward_data,
669};
670
671/* Return -1 on error, else 0 */
672static int
673parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200674 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200675{
676 struct trace_config *conf;
677 int pos = *cur_arg;
678
679 conf = calloc(1, sizeof(*conf));
680 if (!conf) {
681 memprintf(err, "%s: out of memory", args[*cur_arg]);
682 return -1;
683 }
684 conf->proxy = px;
685
686 if (!strcmp(args[pos], "trace")) {
687 pos++;
688
689 while (*args[pos]) {
690 if (!strcmp(args[pos], "name")) {
691 if (!*args[pos + 1]) {
692 memprintf(err, "'%s' : '%s' option without value",
693 args[*cur_arg], args[pos]);
694 goto error;
695 }
696 conf->name = strdup(args[pos + 1]);
697 if (!conf->name) {
698 memprintf(err, "%s: out of memory", args[*cur_arg]);
699 goto error;
700 }
701 pos++;
702 }
703 else if (!strcmp(args[pos], "random-parsing"))
704 conf->rand_parsing = 1;
705 else if (!strcmp(args[pos], "random-forwarding"))
706 conf->rand_forwarding = 1;
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100707 else if (!strcmp(args[pos], "hexdump"))
708 conf->hexdump = 1;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200709 else
710 break;
711 pos++;
712 }
713 *cur_arg = pos;
Christopher Fauletf4a4ef72018-12-07 17:39:53 +0100714 fconf->id = trace_flt_id;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100715 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200716 }
717
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100718 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200719 return 0;
720
721 error:
722 if (conf->name)
723 free(conf->name);
724 free(conf);
725 return -1;
726}
727
728/* Declare the filter parser for "trace" keyword */
729static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200730 { "trace", parse_trace_flt, NULL },
731 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200732 }
733};
734
Willy Tarreau0108d902018-11-25 19:14:37 +0100735INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);