blob: a79cddc6ab3156b5a7944f88c1c4f615bc698f6c [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 Tarreau4c7e4b72020-05-27 12:58:42 +020015#include <haproxy/api.h>
Willy Tarreauf1d32c42020-06-04 21:07:02 +020016#include <haproxy/channel-t.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020017#include <haproxy/errors.h>
Willy Tarreauc7babd82020-06-04 21:29:29 +020018#include <haproxy/filters.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020019#include <haproxy/global.h>
Willy Tarreauc2b1ff02020-06-04 21:21:03 +020020#include <haproxy/http_ana-t.h>
Willy Tarreau87735332020-06-04 09:08:41 +020021#include <haproxy/http_htx.h>
Willy Tarreau16f958c2020-06-03 08:44:35 +020022#include <haproxy/htx.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020023#include <haproxy/proxy-t.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020024#include <haproxy/stream.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020025#include <haproxy/time.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020026#include <haproxy/tools.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020027
Christopher Fauletf4a4ef72018-12-07 17:39:53 +010028const char *trace_flt_id = "trace filter";
29
Christopher Faulete6c3b692015-09-02 17:15:16 +020030struct flt_ops trace_ops;
31
Christopher Faulet47d9a4e2020-11-17 11:33:36 +010032#define TRACE_F_QUIET 0x00000001
33#define TRACE_F_RAND_FWD 0x00000002
34#define TRACE_F_HEXDUMP 0x00000004
35
Christopher Faulete6c3b692015-09-02 17:15:16 +020036struct trace_config {
37 struct proxy *proxy;
38 char *name;
Christopher Faulet47d9a4e2020-11-17 11:33:36 +010039 unsigned int flags;
Christopher Faulete6c3b692015-09-02 17:15:16 +020040};
41
Christopher Fauleta3ed2712019-11-04 11:35:42 +010042#define FLT_TRACE(conf, fmt, ...) \
Christopher Faulet96a577a2020-11-17 10:45:05 +010043 do { \
Christopher Faulet47d9a4e2020-11-17 11:33:36 +010044 if (!(conf->flags & TRACE_F_QUIET)) \
Christopher Faulet96a577a2020-11-17 10:45:05 +010045 fprintf(stderr, "%d.%06d [%-20s] " fmt "\n", \
46 (int)now.tv_sec, (int)now.tv_usec, (conf)->name,\
47 ##__VA_ARGS__); \
48 } while (0)
Christopher Faulete6c3b692015-09-02 17:15:16 +020049
Christopher Faulet96a577a2020-11-17 10:45:05 +010050#define FLT_STRM_TRACE(conf, strm, fmt, ...) \
51 do { \
Christopher Faulet47d9a4e2020-11-17 11:33:36 +010052 if (!(conf->flags & TRACE_F_QUIET)) \
Christopher Faulet96a577a2020-11-17 10:45:05 +010053 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), \
57 ##__VA_ARGS__); \
58 } while (0)
Christopher Faulete6c3b692015-09-02 17:15:16 +020059
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 Faulet386a0cd2019-07-15 21:22:44 +020072 return ((px->mode == PR_MODE_HTTP) ? "HTTP" : "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++)
Willy Tarreau90807112020-02-25 08:16:33 +0100108 fprintf(stderr, "%c", (isprint((unsigned char)*(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
Christopher Fauletb2e58492019-11-12 11:13:01 +0100115trace_raw_hexdump(struct buffer *buf, unsigned int offset, unsigned int len)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100116{
117 unsigned char p[len];
118 int block1, block2;
119
120 block1 = len;
Christopher Fauletb2e58492019-11-12 11:13:01 +0100121 if (block1 > b_contig_data(buf, offset))
122 block1 = b_contig_data(buf, offset);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100123 block2 = len - block1;
124
Christopher Fauletb2e58492019-11-12 11:13:01 +0100125 memcpy(p, b_peek(buf, offset), block1);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100126 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{
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100133 struct htx_blk *blk;
134
Christopher Fauletee847d42019-05-23 11:55:33 +0200135 for (blk = htx_get_first_blk(htx); blk && len; blk = htx_get_next_blk(htx, blk)) {
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100136 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Fauletee847d42019-05-23 11:55:33 +0200137 uint32_t sz = htx_get_blksz(blk);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100138 struct ist v;
139
Christopher Fauletee847d42019-05-23 11:55:33 +0200140 if (offset >= sz) {
141 offset -= sz;
142 continue;
143 }
144
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100145 v = htx_get_blk_value(htx, blk);
146 v.ptr += offset;
147 v.len -= offset;
148 offset = 0;
149
150 if (v.len > len)
151 v.len = len;
152 len -= v.len;
Christopher Faulet2d7c5392019-06-03 10:41:26 +0200153 if (type == HTX_BLK_DATA)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100154 trace_hexdump(v);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100155 }
156}
157
Christopher Fauletb2e58492019-11-12 11:13:01 +0100158static unsigned int
159trace_get_htx_datalen(struct htx *htx, unsigned int offset, unsigned int len)
160{
161 struct htx_blk *blk;
Christopher Faulet24598a42020-02-26 22:06:11 +0100162 struct htx_ret htxret = htx_find_offset(htx, offset);
163 uint32_t data = 0;
Christopher Fauletb2e58492019-11-12 11:13:01 +0100164
Christopher Faulet24598a42020-02-26 22:06:11 +0100165 blk = htxret.blk;
166 if (blk && htxret.ret && htx_get_blk_type(blk) == HTX_BLK_DATA) {
167 data += htxret.ret;
168 blk = htx_get_next_blk(htx, blk);
169 }
170 while (blk) {
171 if (htx_get_blk_type(blk) == HTX_BLK_UNUSED)
172 goto next;
173 else if (htx_get_blk_type(blk) != HTX_BLK_DATA)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100174 break;
Christopher Faulet24598a42020-02-26 22:06:11 +0100175 data += htx_get_blksz(blk);
176 next:
177 blk = htx_get_next_blk(htx, blk);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100178 }
179 return data;
180}
181
Christopher Faulete6c3b692015-09-02 17:15:16 +0200182/***************************************************************************
183 * Hooks that manage the filter lifecycle (init/check/deinit)
184 **************************************************************************/
185/* Initialize the filter. Returns -1 on error, else 0. */
186static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100187trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200188{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100189 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200190
191 if (conf->name)
192 memprintf(&conf->name, "%s/%s", conf->name, px->id);
193 else
194 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100195
Christopher Faulet6e540952018-12-03 22:43:41 +0100196 fconf->flags |= FLT_CFG_FL_HTX;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100197 fconf->conf = conf;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100198
Christopher Faulet96a577a2020-11-17 10:45:05 +0100199 FLT_TRACE(conf, "filter initialized [quiet=%s - fwd random=%s - hexdump=%s]",
Christopher Faulet47d9a4e2020-11-17 11:33:36 +0100200 ((conf->flags & TRACE_F_QUIET) ? "true" : "false"),
201 ((conf->flags & TRACE_F_RAND_FWD) ? "true" : "false"),
202 ((conf->flags & TRACE_F_HEXDUMP) ? "true" : "false"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200203 return 0;
204}
205
Ilya Shipitsin6b79f382020-07-23 00:32:55 +0500206/* Free resources allocated by the trace filter. */
Christopher Faulete6c3b692015-09-02 17:15:16 +0200207static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100208trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200209{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100210 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200211
212 if (conf) {
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100213 FLT_TRACE(conf, "filter deinitialized");
Christopher Faulete6c3b692015-09-02 17:15:16 +0200214 free(conf->name);
215 free(conf);
216 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100217 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200218}
219
220/* Check configuration of a trace filter for a specified proxy.
221 * Return 1 on error, else 0. */
222static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100223trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200224{
225 return 0;
226}
227
Christopher Fauletf2273722017-07-27 16:58:42 +0200228/* Initialize the filter for each thread. Return -1 on error, else 0. */
229static int
230trace_init_per_thread(struct proxy *px, struct flt_conf *fconf)
231{
232 struct trace_config *conf = fconf->conf;
233
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100234 FLT_TRACE(conf, "filter initialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200235 return 0;
236}
237
Ilya Shipitsin6b79f382020-07-23 00:32:55 +0500238/* Free resources allocate by the trace filter for each thread. */
Christopher Fauletf2273722017-07-27 16:58:42 +0200239static void
240trace_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
241{
242 struct trace_config *conf = fconf->conf;
243
244 if (conf)
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100245 FLT_TRACE(conf, "filter deinitialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200246}
247
Christopher Faulete6c3b692015-09-02 17:15:16 +0200248/**************************************************************************
249 * Hooks to handle start/stop of streams
250 *************************************************************************/
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200251/* Called when a filter instance is created and attach to a stream */
252static int
253trace_attach(struct stream *s, struct filter *filter)
254{
255 struct trace_config *conf = FLT_CONF(filter);
256
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100257 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200258 __FUNCTION__, filter_type(filter));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100259
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200260 return 1;
261}
262
263/* Called when a filter instance is detach from a stream, just before its
264 * destruction */
265static void
266trace_detach(struct stream *s, struct filter *filter)
267{
268 struct trace_config *conf = FLT_CONF(filter);
269
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100270 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200271 __FUNCTION__, filter_type(filter));
272}
273
Christopher Faulete6c3b692015-09-02 17:15:16 +0200274/* Called when a stream is created */
275static int
276trace_stream_start(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
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100280 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200281 __FUNCTION__);
282 return 0;
283}
284
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200285
286/* Called when a backend is set for a stream */
287static int
288trace_stream_set_backend(struct stream *s, struct filter *filter,
289 struct proxy *be)
290{
291 struct trace_config *conf = FLT_CONF(filter);
292
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100293 FLT_STRM_TRACE(conf, s, "%-25s: backend=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200294 __FUNCTION__, be->id);
295 return 0;
296}
297
Christopher Faulete6c3b692015-09-02 17:15:16 +0200298/* Called when a stream is destroyed */
299static void
300trace_stream_stop(struct stream *s, struct filter *filter)
301{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100302 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200303
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100304 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200305 __FUNCTION__);
306}
307
Christopher Fauleta00d8172016-11-10 14:58:05 +0100308/* Called when the stream is woken up because of an expired timer */
309static void
310trace_check_timeouts(struct stream *s, struct filter *filter)
311{
312 struct trace_config *conf = FLT_CONF(filter);
313
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100314 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Fauleta00d8172016-11-10 14:58:05 +0100315 __FUNCTION__);
316}
317
Christopher Faulete6c3b692015-09-02 17:15:16 +0200318/**************************************************************************
319 * Hooks to handle channels activity
320 *************************************************************************/
321/* Called when analyze starts for a given channel */
322static int
323trace_chn_start_analyze(struct stream *s, struct filter *filter,
324 struct channel *chn)
325{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100326 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200327
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100328 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200329 __FUNCTION__,
330 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200331 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
332 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100333 register_data_filter(s, chn, filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200334 return 1;
335}
336
337/* Called before a processing happens on a given channel */
338static int
339trace_chn_analyze(struct stream *s, struct filter *filter,
340 struct channel *chn, unsigned an_bit)
341{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100342 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200343 char *ana;
344
345 switch (an_bit) {
346 case AN_REQ_INSPECT_FE:
347 ana = "AN_REQ_INSPECT_FE";
348 break;
349 case AN_REQ_WAIT_HTTP:
350 ana = "AN_REQ_WAIT_HTTP";
351 break;
352 case AN_REQ_HTTP_BODY:
353 ana = "AN_REQ_HTTP_BODY";
354 break;
355 case AN_REQ_HTTP_PROCESS_FE:
356 ana = "AN_REQ_HTTP_PROCESS_FE";
357 break;
358 case AN_REQ_SWITCHING_RULES:
359 ana = "AN_REQ_SWITCHING_RULES";
360 break;
361 case AN_REQ_INSPECT_BE:
362 ana = "AN_REQ_INSPECT_BE";
363 break;
364 case AN_REQ_HTTP_PROCESS_BE:
365 ana = "AN_REQ_HTTP_PROCESS_BE";
366 break;
367 case AN_REQ_SRV_RULES:
368 ana = "AN_REQ_SRV_RULES";
369 break;
370 case AN_REQ_HTTP_INNER:
371 ana = "AN_REQ_HTTP_INNER";
372 break;
373 case AN_REQ_HTTP_TARPIT:
374 ana = "AN_REQ_HTTP_TARPIT";
375 break;
376 case AN_REQ_STICKING_RULES:
377 ana = "AN_REQ_STICKING_RULES";
378 break;
379 case AN_REQ_PRST_RDP_COOKIE:
380 ana = "AN_REQ_PRST_RDP_COOKIE";
381 break;
382 case AN_REQ_HTTP_XFER_BODY:
383 ana = "AN_REQ_HTTP_XFER_BODY";
384 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200385 case AN_RES_INSPECT:
386 ana = "AN_RES_INSPECT";
387 break;
388 case AN_RES_WAIT_HTTP:
389 ana = "AN_RES_WAIT_HTTP";
390 break;
391 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
392 ana = "AN_RES_HTTP_PROCESS_FE/BE";
393 break;
394 case AN_RES_STORE_RULES:
395 ana = "AN_RES_STORE_RULES";
396 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200397 case AN_RES_HTTP_XFER_BODY:
398 ana = "AN_RES_HTTP_XFER_BODY";
399 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200400 default:
401 ana = "unknown";
402 }
403
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100404 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200405 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200406 __FUNCTION__,
407 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200408 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200409 return 1;
410}
411
412/* Called when analyze ends for a given channel */
413static int
414trace_chn_end_analyze(struct stream *s, struct filter *filter,
415 struct channel *chn)
416{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100417 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200418
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100419 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200420 __FUNCTION__,
421 channel_label(chn), proxy_mode(s), stream_pos(s));
422 return 1;
423}
424
425/**************************************************************************
426 * Hooks to filter HTTP messages
427 *************************************************************************/
428static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200429trace_http_headers(struct stream *s, struct filter *filter,
430 struct http_msg *msg)
431{
432 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200433 struct htx *htx = htxbuf(&msg->chn->buf);
434 struct htx_sl *sl = http_get_stline(htx);
435 int32_t pos;
Christopher Faulet1339d742016-05-11 16:48:33 +0200436
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100437 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)\t%.*s %.*s %.*s",
Christopher Faulet1339d742016-05-11 16:48:33 +0200438 __FUNCTION__,
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200439 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
440 HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl),
441 HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
442 HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100443
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200444 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
445 struct htx_blk *blk = htx_get_blk(htx, pos);
446 enum htx_blk_type type = htx_get_blk_type(blk);
447 struct ist n, v;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100448
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200449 if (type == HTX_BLK_EOH)
450 break;
451 if (type != HTX_BLK_HDR)
452 continue;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100453
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200454 n = htx_get_blk_name(htx, blk);
455 v = htx_get_blk_value(htx, blk);
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100456 FLT_STRM_TRACE(conf, s, "\t%.*s: %.*s",
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200457 (int)n.len, n.ptr, (int)v.len, v.ptr);
Christopher Faulet1339d742016-05-11 16:48:33 +0200458 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200459 return 1;
460}
461
462static int
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100463trace_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
464 unsigned int offset, unsigned int len)
465{
466 struct trace_config *conf = FLT_CONF(filter);
467 int ret = len;
468
Christopher Faulet47d9a4e2020-11-17 11:33:36 +0100469 if (ret && (conf->flags & TRACE_F_RAND_FWD)) {
Christopher Fauletb2e58492019-11-12 11:13:01 +0100470 unsigned int data = trace_get_htx_datalen(htxbuf(&msg->chn->buf), offset, len);
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200471
Christopher Fauletb2e58492019-11-12 11:13:01 +0100472 if (data) {
Willy Tarreau52bf8392020-03-08 00:42:37 +0100473 ret = ha_random() % (ret+1);
Christopher Faulet647fe1d2019-06-12 16:07:48 +0200474 if (!ret || ret >= data)
475 ret = len;
476 }
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200477 }
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100478
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100479 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100480 "offset=%u - len=%u - forward=%d",
481 __FUNCTION__,
482 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
483 offset, len, ret);
484
Christopher Faulet47d9a4e2020-11-17 11:33:36 +0100485 if (conf->flags & TRACE_F_HEXDUMP)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100486 trace_htx_hexdump(htxbuf(&msg->chn->buf), offset, ret);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100487
488 if (ret != len)
489 task_wakeup(s->task, TASK_WOKEN_MSG);
490 return ret;
491}
492
493static int
Christopher Faulete6c3b692015-09-02 17:15:16 +0200494trace_http_end(struct stream *s, struct filter *filter,
495 struct http_msg *msg)
496{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100497 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200498
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100499 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200500 __FUNCTION__,
501 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
502 return 1;
503}
504
505static void
506trace_http_reset(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
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100511 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200512 __FUNCTION__,
513 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
514}
515
516static void
517trace_http_reply(struct stream *s, struct filter *filter, short status,
Willy Tarreau83061a82018-07-13 11:56:34 +0200518 const struct buffer *msg)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200519{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100520 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200521
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100522 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200523 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
524}
525
Christopher Faulete6c3b692015-09-02 17:15:16 +0200526/**************************************************************************
527 * Hooks to filter TCP data
528 *************************************************************************/
529static int
Christopher Fauletb2e58492019-11-12 11:13:01 +0100530trace_tcp_payload(struct stream *s, struct filter *filter, struct channel *chn,
531 unsigned int offset, unsigned int len)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200532{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100533 struct trace_config *conf = FLT_CONF(filter);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100534 int ret = len;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200535
Christopher Fauletb2e58492019-11-12 11:13:01 +0100536 if (s->flags & SF_HTX) {
Christopher Faulet47d9a4e2020-11-17 11:33:36 +0100537 if (ret && (conf->flags & TRACE_F_RAND_FWD)) {
Christopher Fauletb2e58492019-11-12 11:13:01 +0100538 unsigned int data = trace_get_htx_datalen(htxbuf(&chn->buf), offset, len);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200539
Christopher Fauletb2e58492019-11-12 11:13:01 +0100540 if (data) {
Willy Tarreau52bf8392020-03-08 00:42:37 +0100541 ret = ha_random() % (ret+1);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100542 if (!ret || ret >= data)
543 ret = len;
544 }
545 }
Christopher Faulete6c3b692015-09-02 17:15:16 +0200546
Christopher Fauletb2e58492019-11-12 11:13:01 +0100547 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
548 "offset=%u - len=%u - forward=%d",
549 __FUNCTION__,
550 channel_label(chn), proxy_mode(s), stream_pos(s),
551 offset, len, ret);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200552
Christopher Faulet47d9a4e2020-11-17 11:33:36 +0100553 if (conf->flags & TRACE_F_HEXDUMP)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100554 trace_htx_hexdump(htxbuf(&chn->buf), offset, ret);
555 }
556 else {
Christopher Faulete6c3b692015-09-02 17:15:16 +0200557
Christopher Faulet47d9a4e2020-11-17 11:33:36 +0100558 if (ret && (conf->flags & TRACE_F_RAND_FWD))
Willy Tarreau52bf8392020-03-08 00:42:37 +0100559 ret = ha_random() % (ret+1);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200560
Christopher Fauletb2e58492019-11-12 11:13:01 +0100561 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
562 "offset=%u - len=%u - forward=%d",
563 __FUNCTION__,
564 channel_label(chn), proxy_mode(s), stream_pos(s),
565 offset, len, ret);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200566
Christopher Faulet47d9a4e2020-11-17 11:33:36 +0100567 if (conf->flags & TRACE_F_HEXDUMP)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100568 trace_raw_hexdump(&chn->buf, offset, ret);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100569 }
570
Christopher Fauletb2e58492019-11-12 11:13:01 +0100571 if (ret != len)
572 task_wakeup(s->task, TASK_WOKEN_MSG);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200573 return ret;
574}
Christopher Faulete6c3b692015-09-02 17:15:16 +0200575/********************************************************************
576 * Functions that manage the filter initialization
577 ********************************************************************/
578struct flt_ops trace_ops = {
579 /* Manage trace filter, called for each filter declaration */
Christopher Fauletf2273722017-07-27 16:58:42 +0200580 .init = trace_init,
581 .deinit = trace_deinit,
582 .check = trace_check,
583 .init_per_thread = trace_init_per_thread,
584 .deinit_per_thread = trace_deinit_per_thread,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200585
586 /* Handle start/stop of streams */
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200587 .attach = trace_attach,
588 .detach = trace_detach,
589 .stream_start = trace_stream_start,
590 .stream_set_backend = trace_stream_set_backend,
591 .stream_stop = trace_stream_stop,
Christopher Fauleta00d8172016-11-10 14:58:05 +0100592 .check_timeouts = trace_check_timeouts,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200593
594 /* Handle channels activity */
595 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200596 .channel_pre_analyze = trace_chn_analyze,
597 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200598 .channel_end_analyze = trace_chn_end_analyze,
599
600 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200601 .http_headers = trace_http_headers,
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100602 .http_payload = trace_http_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200603 .http_end = trace_http_end,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200604 .http_reset = trace_http_reset,
605 .http_reply = trace_http_reply,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200606
607 /* Filter TCP data */
Christopher Fauletb2e58492019-11-12 11:13:01 +0100608 .tcp_payload = trace_tcp_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200609};
610
611/* Return -1 on error, else 0 */
612static int
613parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200614 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200615{
616 struct trace_config *conf;
617 int pos = *cur_arg;
618
619 conf = calloc(1, sizeof(*conf));
620 if (!conf) {
621 memprintf(err, "%s: out of memory", args[*cur_arg]);
622 return -1;
623 }
624 conf->proxy = px;
Christopher Faulet47d9a4e2020-11-17 11:33:36 +0100625 conf->flags = 0;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200626 if (!strcmp(args[pos], "trace")) {
627 pos++;
628
629 while (*args[pos]) {
630 if (!strcmp(args[pos], "name")) {
631 if (!*args[pos + 1]) {
632 memprintf(err, "'%s' : '%s' option without value",
633 args[*cur_arg], args[pos]);
634 goto error;
635 }
636 conf->name = strdup(args[pos + 1]);
637 if (!conf->name) {
638 memprintf(err, "%s: out of memory", args[*cur_arg]);
639 goto error;
640 }
641 pos++;
642 }
Christopher Faulet96a577a2020-11-17 10:45:05 +0100643 else if (!strcmp(args[pos], "quiet"))
Christopher Faulet47d9a4e2020-11-17 11:33:36 +0100644 conf->flags |= TRACE_F_QUIET;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200645 else if (!strcmp(args[pos], "random-parsing"))
Christopher Fauletc41d8bd2020-11-17 10:43:26 +0100646 continue; // ignore
Christopher Faulete6c3b692015-09-02 17:15:16 +0200647 else if (!strcmp(args[pos], "random-forwarding"))
Christopher Faulet47d9a4e2020-11-17 11:33:36 +0100648 conf->flags |= TRACE_F_RAND_FWD;
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100649 else if (!strcmp(args[pos], "hexdump"))
Christopher Faulet47d9a4e2020-11-17 11:33:36 +0100650 conf->flags |= TRACE_F_HEXDUMP;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200651 else
652 break;
653 pos++;
654 }
655 *cur_arg = pos;
Christopher Fauletf4a4ef72018-12-07 17:39:53 +0100656 fconf->id = trace_flt_id;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100657 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200658 }
659
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100660 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200661 return 0;
662
663 error:
664 if (conf->name)
665 free(conf->name);
666 free(conf);
667 return -1;
668}
669
670/* Declare the filter parser for "trace" keyword */
671static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200672 { "trace", parse_trace_flt, NULL },
673 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200674 }
675};
676
Willy Tarreau0108d902018-11-25 19:14:37 +0100677INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);