blob: 92a51bf156b1c40278eca7416c45a12dfd886695 [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
36struct 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
46#define TRACE(conf, fmt, ...) \
47 fprintf(stderr, "%d.%06d [%-20s] " fmt "\n", \
48 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
49 ##__VA_ARGS__)
50
Christopher Fauletfcd99f82016-10-31 11:27:21 +010051#define STRM_TRACE(conf, strm, fmt, ...) \
52 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 Faulete0aa6f72018-11-30 22:23:32 +010070 return ((px->mode == PR_MODE_HTTP)
71 ? (IS_HTX_STRM(s) ? "HTX" : "HTTP")
72 : "TCP");
Christopher Faulete6c3b692015-09-02 17:15:16 +020073}
74
75static const char *
76stream_pos(const struct stream *s)
77{
78 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
79}
80
Christopher Faulet31ed32d2016-06-21 11:42:37 +020081static const char *
82filter_type(const struct filter *f)
83{
84 return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
85}
86
Christopher Fauletfcd99f82016-10-31 11:27:21 +010087static void
Christopher Faulete0aa6f72018-11-30 22:23:32 +010088trace_hexdump(struct ist ist)
Christopher Fauletfcd99f82016-10-31 11:27:21 +010089{
Christopher Faulete0aa6f72018-11-30 22:23:32 +010090 int i, j, padding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010091
Christopher Faulete0aa6f72018-11-30 22:23:32 +010092 padding = ((ist.len % 16) ? (16 - ist.len % 16) : 0);
93 for (i = 0; i < ist.len + padding; i++) {
Christopher Fauletfcd99f82016-10-31 11:27:21 +010094 if (!(i % 16))
95 fprintf(stderr, "\t0x%06x: ", i);
96 else if (!(i % 8))
97 fprintf(stderr, " ");
98
Christopher Faulete0aa6f72018-11-30 22:23:32 +010099 if (i < ist.len)
100 fprintf(stderr, "%02x ", (unsigned char)*(ist.ptr+i));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100101 else
102 fprintf(stderr, " ");
103
104 /* print ASCII dump */
105 if (i % 16 == 15) {
106 fprintf(stderr, " |");
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100107 for(j = i - 15; j <= i && j < ist.len; j++)
108 fprintf(stderr, "%c", (isprint(*(ist.ptr+j)) ? *(ist.ptr+j) : '.'));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100109 fprintf(stderr, "|\n");
110 }
111 }
112}
113
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100114static void
115trace_raw_hexdump(struct buffer *buf, int len, int out)
116{
117 unsigned char p[len];
118 int block1, block2;
119
120 block1 = len;
121 if (block1 > b_contig_data(buf, out))
122 block1 = b_contig_data(buf, out);
123 block2 = len - block1;
124
125 memcpy(p, b_head(buf), block1);
126 memcpy(p+block1, b_orig(buf), block2);
127 trace_hexdump(ist2(p, len));
128}
129
130static void
131trace_htx_hexdump(struct htx *htx, unsigned int offset, unsigned int len)
132{
133 struct htx_ret htx_ret;
134 struct htx_blk *blk;
135
136 htx_ret = htx_find_blk(htx, offset);
137 blk = htx_ret.blk;
138 offset = htx_ret.ret;
139
140 while (blk) {
141 enum htx_blk_type type = htx_get_blk_type(blk);
142 struct ist v;
143
144 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;
152 if (type == HTX_BLK_DATA || type == HTX_BLK_TLR)
153 trace_hexdump(v);
154 blk = htx_get_next_blk(htx, blk);
155 }
156}
157
Christopher Faulete6c3b692015-09-02 17:15:16 +0200158/***************************************************************************
159 * Hooks that manage the filter lifecycle (init/check/deinit)
160 **************************************************************************/
161/* Initialize the filter. Returns -1 on error, else 0. */
162static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100163trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200164{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100165 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200166
167 if (conf->name)
168 memprintf(&conf->name, "%s/%s", conf->name, px->id);
169 else
170 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100171
Christopher Faulet6e540952018-12-03 22:43:41 +0100172 fconf->flags |= FLT_CFG_FL_HTX;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100173 fconf->conf = conf;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100174
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100175 TRACE(conf, "filter initialized [read random=%s - fwd random=%s - hexdump=%s]",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200176 (conf->rand_parsing ? "true" : "false"),
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100177 (conf->rand_forwarding ? "true" : "false"),
178 (conf->hexdump ? "true" : "false"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200179 return 0;
180}
181
182/* Free ressources allocated by the trace filter. */
183static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100184trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200185{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100186 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200187
188 if (conf) {
189 TRACE(conf, "filter deinitialized");
190 free(conf->name);
191 free(conf);
192 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100193 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200194}
195
196/* Check configuration of a trace filter for a specified proxy.
197 * Return 1 on error, else 0. */
198static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100199trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200200{
201 return 0;
202}
203
Christopher Fauletf2273722017-07-27 16:58:42 +0200204/* Initialize the filter for each thread. Return -1 on error, else 0. */
205static int
206trace_init_per_thread(struct proxy *px, struct flt_conf *fconf)
207{
208 struct trace_config *conf = fconf->conf;
209
210 TRACE(conf, "filter initialized for thread tid %u", tid);
211 return 0;
212}
213
214/* Free ressources allocate by the trace filter for each thread. */
215static void
216trace_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
217{
218 struct trace_config *conf = fconf->conf;
219
220 if (conf)
221 TRACE(conf, "filter deinitialized for thread tid %u", tid);
222}
223
Christopher Faulete6c3b692015-09-02 17:15:16 +0200224/**************************************************************************
225 * Hooks to handle start/stop of streams
226 *************************************************************************/
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200227/* Called when a filter instance is created and attach to a stream */
228static int
229trace_attach(struct stream *s, struct filter *filter)
230{
231 struct trace_config *conf = FLT_CONF(filter);
232
233 STRM_TRACE(conf, s, "%-25s: filter-type=%s",
234 __FUNCTION__, filter_type(filter));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100235
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200236 return 1;
237}
238
239/* Called when a filter instance is detach from a stream, just before its
240 * destruction */
241static void
242trace_detach(struct stream *s, struct filter *filter)
243{
244 struct trace_config *conf = FLT_CONF(filter);
245
246 STRM_TRACE(conf, s, "%-25s: filter-type=%s",
247 __FUNCTION__, filter_type(filter));
248}
249
Christopher Faulete6c3b692015-09-02 17:15:16 +0200250/* Called when a stream is created */
251static int
252trace_stream_start(struct stream *s, struct filter *filter)
253{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100254 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200255
256 STRM_TRACE(conf, s, "%-25s",
257 __FUNCTION__);
258 return 0;
259}
260
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200261
262/* Called when a backend is set for a stream */
263static int
264trace_stream_set_backend(struct stream *s, struct filter *filter,
265 struct proxy *be)
266{
267 struct trace_config *conf = FLT_CONF(filter);
268
269 STRM_TRACE(conf, s, "%-25s: backend=%s",
270 __FUNCTION__, be->id);
271 return 0;
272}
273
Christopher Faulete6c3b692015-09-02 17:15:16 +0200274/* Called when a stream is destroyed */
275static void
276trace_stream_stop(struct stream *s, struct filter *filter)
277{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100278 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200279
280 STRM_TRACE(conf, s, "%-25s",
281 __FUNCTION__);
282}
283
Christopher Fauleta00d8172016-11-10 14:58:05 +0100284/* Called when the stream is woken up because of an expired timer */
285static void
286trace_check_timeouts(struct stream *s, struct filter *filter)
287{
288 struct trace_config *conf = FLT_CONF(filter);
289
290 STRM_TRACE(conf, s, "%-25s",
291 __FUNCTION__);
292}
293
Christopher Faulete6c3b692015-09-02 17:15:16 +0200294/**************************************************************************
295 * Hooks to handle channels activity
296 *************************************************************************/
297/* Called when analyze starts for a given channel */
298static int
299trace_chn_start_analyze(struct stream *s, struct filter *filter,
300 struct channel *chn)
301{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100302 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200303
304 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
305 __FUNCTION__,
306 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200307 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
308 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100309 register_data_filter(s, chn, filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200310 return 1;
311}
312
313/* Called before a processing happens on a given channel */
314static int
315trace_chn_analyze(struct stream *s, struct filter *filter,
316 struct channel *chn, unsigned an_bit)
317{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100318 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200319 char *ana;
320
321 switch (an_bit) {
322 case AN_REQ_INSPECT_FE:
323 ana = "AN_REQ_INSPECT_FE";
324 break;
325 case AN_REQ_WAIT_HTTP:
326 ana = "AN_REQ_WAIT_HTTP";
327 break;
328 case AN_REQ_HTTP_BODY:
329 ana = "AN_REQ_HTTP_BODY";
330 break;
331 case AN_REQ_HTTP_PROCESS_FE:
332 ana = "AN_REQ_HTTP_PROCESS_FE";
333 break;
334 case AN_REQ_SWITCHING_RULES:
335 ana = "AN_REQ_SWITCHING_RULES";
336 break;
337 case AN_REQ_INSPECT_BE:
338 ana = "AN_REQ_INSPECT_BE";
339 break;
340 case AN_REQ_HTTP_PROCESS_BE:
341 ana = "AN_REQ_HTTP_PROCESS_BE";
342 break;
343 case AN_REQ_SRV_RULES:
344 ana = "AN_REQ_SRV_RULES";
345 break;
346 case AN_REQ_HTTP_INNER:
347 ana = "AN_REQ_HTTP_INNER";
348 break;
349 case AN_REQ_HTTP_TARPIT:
350 ana = "AN_REQ_HTTP_TARPIT";
351 break;
352 case AN_REQ_STICKING_RULES:
353 ana = "AN_REQ_STICKING_RULES";
354 break;
355 case AN_REQ_PRST_RDP_COOKIE:
356 ana = "AN_REQ_PRST_RDP_COOKIE";
357 break;
358 case AN_REQ_HTTP_XFER_BODY:
359 ana = "AN_REQ_HTTP_XFER_BODY";
360 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200361 case AN_RES_INSPECT:
362 ana = "AN_RES_INSPECT";
363 break;
364 case AN_RES_WAIT_HTTP:
365 ana = "AN_RES_WAIT_HTTP";
366 break;
367 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
368 ana = "AN_RES_HTTP_PROCESS_FE/BE";
369 break;
370 case AN_RES_STORE_RULES:
371 ana = "AN_RES_STORE_RULES";
372 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200373 case AN_RES_HTTP_XFER_BODY:
374 ana = "AN_RES_HTTP_XFER_BODY";
375 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200376 default:
377 ana = "unknown";
378 }
379
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200380 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
381 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200382 __FUNCTION__,
383 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200384 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200385 return 1;
386}
387
388/* Called when analyze ends for a given channel */
389static int
390trace_chn_end_analyze(struct stream *s, struct filter *filter,
391 struct channel *chn)
392{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100393 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200394
395 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
396 __FUNCTION__,
397 channel_label(chn), proxy_mode(s), stream_pos(s));
398 return 1;
399}
400
401/**************************************************************************
402 * Hooks to filter HTTP messages
403 *************************************************************************/
404static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200405trace_http_headers(struct stream *s, struct filter *filter,
406 struct http_msg *msg)
407{
408 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulet1339d742016-05-11 16:48:33 +0200409
410 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
411 __FUNCTION__,
412 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
413
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100414 if (IS_HTX_STRM(s)) {
Christopher Faulet27ba2dc2018-12-05 11:53:24 +0100415 struct htx *htx = htxbuf(&msg->chn->buf);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100416 struct htx_sl *sl = http_find_stline(htx);
417 int32_t pos;
418
419 STRM_TRACE(conf, s, "\t%.*s %.*s %.*s",
420 HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl),
421 HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
422 HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
423
424 for (pos = htx_get_head(htx); pos != -1; pos = htx_get_next(htx, pos)) {
425 struct htx_blk *blk = htx_get_blk(htx, pos);
426 enum htx_blk_type type = htx_get_blk_type(blk);
427 struct ist n, v;
428
429 if (type == HTX_BLK_EOH)
430 break;
431 if (type != HTX_BLK_HDR)
432 continue;
433
434 n = htx_get_blk_name(htx, blk);
435 v = htx_get_blk_value(htx, blk);
436 STRM_TRACE(conf, s, "\t%.*s: %.*s",
437 (int)n.len, n.ptr, (int)v.len, v.ptr);
438 }
439 }
440 else {
441 struct hdr_idx *hdr_idx;
442 char *cur_hdr;
443 int cur_idx;
444
445 STRM_TRACE(conf, s, "\t%.*s", MIN(msg->sl.rq.l, 74), ci_head(msg->chn));
446 hdr_idx = &s->txn->hdr_idx;
447 cur_idx = hdr_idx_first_idx(hdr_idx);
448 cur_hdr = ci_head(msg->chn) + hdr_idx_first_pos(hdr_idx);
449 while (cur_idx) {
450 STRM_TRACE(conf, s, "\t%.*s",
451 MIN(hdr_idx->v[cur_idx].len, 74), cur_hdr);
452 cur_hdr += hdr_idx->v[cur_idx].len + hdr_idx->v[cur_idx].cr + 1;
453 cur_idx = hdr_idx->v[cur_idx].next;
454 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200455 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200456 return 1;
457}
458
459static int
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100460trace_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
461 unsigned int offset, unsigned int len)
462{
463 struct trace_config *conf = FLT_CONF(filter);
464 int ret = len;
465
466 if (ret && conf->rand_forwarding)
467 ret = random() % (ret+1);
468
469 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
470 "offset=%u - len=%u - forward=%d",
471 __FUNCTION__,
472 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
473 offset, len, ret);
474
475 if (conf->hexdump)
Christopher Faulet27ba2dc2018-12-05 11:53:24 +0100476 trace_htx_hexdump(htxbuf(&msg->chn->buf), offset, len);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100477
478 if (ret != len)
479 task_wakeup(s->task, TASK_WOKEN_MSG);
480 return ret;
481}
482
483static int
Christopher Faulete6c3b692015-09-02 17:15:16 +0200484trace_http_data(struct stream *s, struct filter *filter,
485 struct http_msg *msg)
486{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100487 struct trace_config *conf = FLT_CONF(filter);
Willy Tarreauf1589372018-06-19 07:22:43 +0200488 int avail = MIN(msg->chunk_len + msg->next, ci_data(msg->chn)) - FLT_NXT(filter, msg->chn);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200489 int ret = avail;
490
491 if (ret && conf->rand_parsing)
492 ret = random() % (ret+1);
493
494 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
495 "chunk_len=%llu - next=%u - fwd=%u - avail=%d - consume=%d",
496 __FUNCTION__,
497 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
498 msg->chunk_len, FLT_NXT(filter, msg->chn),
499 FLT_FWD(filter, msg->chn), avail, ret);
500 if (ret != avail)
501 task_wakeup(s->task, TASK_WOKEN_MSG);
502 return ret;
503}
504
505static int
506trace_http_chunk_trailers(struct stream *s, struct filter *filter,
507 struct http_msg *msg)
508{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100509 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200510
511 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
512 __FUNCTION__,
513 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
514 return 1;
515}
516
517static int
518trace_http_end(struct stream *s, struct filter *filter,
519 struct http_msg *msg)
520{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100521 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200522
523 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
524 __FUNCTION__,
525 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
526 return 1;
527}
528
529static void
530trace_http_reset(struct stream *s, struct filter *filter,
531 struct http_msg *msg)
532{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100533 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200534
535 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
536 __FUNCTION__,
537 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
538}
539
540static void
541trace_http_reply(struct stream *s, struct filter *filter, short status,
Willy Tarreau83061a82018-07-13 11:56:34 +0200542 const struct buffer *msg)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200543{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100544 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200545
546 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
547 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
548}
549
550static int
551trace_http_forward_data(struct stream *s, struct filter *filter,
552 struct http_msg *msg, unsigned int len)
553{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100554 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200555 int ret = len;
556
557 if (ret && conf->rand_forwarding)
558 ret = random() % (ret+1);
559
560 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
561 "len=%u - nxt=%u - fwd=%u - forward=%d",
562 __FUNCTION__,
563 channel_label(msg->chn), proxy_mode(s), stream_pos(s), len,
564 FLT_NXT(filter, msg->chn), FLT_FWD(filter, msg->chn), ret);
565
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100566 if (conf->hexdump) {
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200567 c_adv(msg->chn, FLT_FWD(filter, msg->chn));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100568 trace_raw_hexdump(&msg->chn->buf, ret, co_data(msg->chn));
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200569 c_rew(msg->chn, FLT_FWD(filter, msg->chn));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100570 }
571
Christopher Faulete6c3b692015-09-02 17:15:16 +0200572 if ((ret != len) ||
573 (FLT_NXT(filter, msg->chn) != FLT_FWD(filter, msg->chn) + ret))
574 task_wakeup(s->task, TASK_WOKEN_MSG);
575 return ret;
576}
577
578/**************************************************************************
579 * Hooks to filter TCP data
580 *************************************************************************/
581static int
582trace_tcp_data(struct stream *s, struct filter *filter, struct channel *chn)
583{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100584 struct trace_config *conf = FLT_CONF(filter);
Willy Tarreauf1589372018-06-19 07:22:43 +0200585 int avail = ci_data(chn) - FLT_NXT(filter, chn);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200586 int ret = avail;
587
588 if (ret && conf->rand_parsing)
589 ret = random() % (ret+1);
590
591 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - next=%u - avail=%u - consume=%d",
592 __FUNCTION__,
593 channel_label(chn), proxy_mode(s), stream_pos(s),
594 FLT_NXT(filter, chn), avail, ret);
595
596 if (ret != avail)
597 task_wakeup(s->task, TASK_WOKEN_MSG);
598 return ret;
599}
600
601static int
602trace_tcp_forward_data(struct stream *s, struct filter *filter, struct channel *chn,
603 unsigned int len)
604{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100605 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200606 int ret = len;
607
608 if (ret && conf->rand_forwarding)
609 ret = random() % (ret+1);
610
611 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - len=%u - fwd=%u - forward=%d",
612 __FUNCTION__,
613 channel_label(chn), proxy_mode(s), stream_pos(s), len,
614 FLT_FWD(filter, chn), ret);
615
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100616 if (conf->hexdump) {
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200617 c_adv(chn, FLT_FWD(filter, chn));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100618 trace_raw_hexdump(&chn->buf, ret, co_data(chn));
Willy Tarreaubcbd3932018-06-06 07:13:22 +0200619 c_rew(chn, FLT_FWD(filter, chn));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100620 }
621
Christopher Faulete6c3b692015-09-02 17:15:16 +0200622 if (ret != len)
623 task_wakeup(s->task, TASK_WOKEN_MSG);
624 return ret;
625}
626
627/********************************************************************
628 * Functions that manage the filter initialization
629 ********************************************************************/
630struct flt_ops trace_ops = {
631 /* Manage trace filter, called for each filter declaration */
Christopher Fauletf2273722017-07-27 16:58:42 +0200632 .init = trace_init,
633 .deinit = trace_deinit,
634 .check = trace_check,
635 .init_per_thread = trace_init_per_thread,
636 .deinit_per_thread = trace_deinit_per_thread,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200637
638 /* Handle start/stop of streams */
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200639 .attach = trace_attach,
640 .detach = trace_detach,
641 .stream_start = trace_stream_start,
642 .stream_set_backend = trace_stream_set_backend,
643 .stream_stop = trace_stream_stop,
Christopher Fauleta00d8172016-11-10 14:58:05 +0100644 .check_timeouts = trace_check_timeouts,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200645
646 /* Handle channels activity */
647 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200648 .channel_pre_analyze = trace_chn_analyze,
649 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200650 .channel_end_analyze = trace_chn_end_analyze,
651
652 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200653 .http_headers = trace_http_headers,
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100654 .http_payload = trace_http_payload,
655
Christopher Faulete6c3b692015-09-02 17:15:16 +0200656 .http_data = trace_http_data,
657 .http_chunk_trailers = trace_http_chunk_trailers,
658 .http_end = trace_http_end,
659
660 .http_reset = trace_http_reset,
661 .http_reply = trace_http_reply,
662 .http_forward_data = trace_http_forward_data,
663
664 /* Filter TCP data */
665 .tcp_data = trace_tcp_data,
666 .tcp_forward_data = trace_tcp_forward_data,
667};
668
669/* Return -1 on error, else 0 */
670static int
671parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200672 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200673{
674 struct trace_config *conf;
675 int pos = *cur_arg;
676
677 conf = calloc(1, sizeof(*conf));
678 if (!conf) {
679 memprintf(err, "%s: out of memory", args[*cur_arg]);
680 return -1;
681 }
682 conf->proxy = px;
683
684 if (!strcmp(args[pos], "trace")) {
685 pos++;
686
687 while (*args[pos]) {
688 if (!strcmp(args[pos], "name")) {
689 if (!*args[pos + 1]) {
690 memprintf(err, "'%s' : '%s' option without value",
691 args[*cur_arg], args[pos]);
692 goto error;
693 }
694 conf->name = strdup(args[pos + 1]);
695 if (!conf->name) {
696 memprintf(err, "%s: out of memory", args[*cur_arg]);
697 goto error;
698 }
699 pos++;
700 }
701 else if (!strcmp(args[pos], "random-parsing"))
702 conf->rand_parsing = 1;
703 else if (!strcmp(args[pos], "random-forwarding"))
704 conf->rand_forwarding = 1;
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100705 else if (!strcmp(args[pos], "hexdump"))
706 conf->hexdump = 1;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200707 else
708 break;
709 pos++;
710 }
711 *cur_arg = pos;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100712 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200713 }
714
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100715 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200716 return 0;
717
718 error:
719 if (conf->name)
720 free(conf->name);
721 free(conf);
722 return -1;
723}
724
725/* Declare the filter parser for "trace" keyword */
726static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200727 { "trace", parse_trace_flt, NULL },
728 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200729 }
730};
731
Willy Tarreau0108d902018-11-25 19:14:37 +0100732INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);