blob: 4b27cd541c7cf0e2514355e3f3332d3113a473c6 [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
32struct trace_config {
33 struct proxy *proxy;
34 char *name;
Christopher Faulete6c3b692015-09-02 17:15:16 +020035 int rand_forwarding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010036 int hexdump;
Christopher Faulete6c3b692015-09-02 17:15:16 +020037};
38
Christopher Fauleta3ed2712019-11-04 11:35:42 +010039#define FLT_TRACE(conf, fmt, ...) \
Christopher Faulete6c3b692015-09-02 17:15:16 +020040 fprintf(stderr, "%d.%06d [%-20s] " fmt "\n", \
41 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
42 ##__VA_ARGS__)
43
Christopher Fauleta3ed2712019-11-04 11:35:42 +010044#define FLT_STRM_TRACE(conf, strm, fmt, ...) \
Christopher Fauletfcd99f82016-10-31 11:27:21 +010045 fprintf(stderr, "%d.%06d [%-20s] [strm %p(%x) 0x%08x 0x%08x] " fmt "\n", \
46 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
47 strm, (strm ? ((struct stream *)strm)->uniq_id : ~0U), \
48 (strm ? strm->req.analysers : 0), (strm ? strm->res.analysers : 0), \
Christopher Faulete6c3b692015-09-02 17:15:16 +020049 ##__VA_ARGS__)
50
51
52static const char *
53channel_label(const struct channel *chn)
54{
55 return (chn->flags & CF_ISRESP) ? "RESPONSE" : "REQUEST";
56}
57
58static const char *
59proxy_mode(const struct stream *s)
60{
61 struct proxy *px = (s->flags & SF_BE_ASSIGNED ? s->be : strm_fe(s));
62
Christopher Faulet386a0cd2019-07-15 21:22:44 +020063 return ((px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
Christopher Faulete6c3b692015-09-02 17:15:16 +020064}
65
66static const char *
67stream_pos(const struct stream *s)
68{
69 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
70}
71
Christopher Faulet31ed32d2016-06-21 11:42:37 +020072static const char *
73filter_type(const struct filter *f)
74{
75 return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
76}
77
Christopher Fauletfcd99f82016-10-31 11:27:21 +010078static void
Christopher Faulete0aa6f72018-11-30 22:23:32 +010079trace_hexdump(struct ist ist)
Christopher Fauletfcd99f82016-10-31 11:27:21 +010080{
Christopher Faulete0aa6f72018-11-30 22:23:32 +010081 int i, j, padding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010082
Christopher Faulete0aa6f72018-11-30 22:23:32 +010083 padding = ((ist.len % 16) ? (16 - ist.len % 16) : 0);
84 for (i = 0; i < ist.len + padding; i++) {
Christopher Fauletfcd99f82016-10-31 11:27:21 +010085 if (!(i % 16))
86 fprintf(stderr, "\t0x%06x: ", i);
87 else if (!(i % 8))
88 fprintf(stderr, " ");
89
Christopher Faulete0aa6f72018-11-30 22:23:32 +010090 if (i < ist.len)
91 fprintf(stderr, "%02x ", (unsigned char)*(ist.ptr+i));
Christopher Fauletfcd99f82016-10-31 11:27:21 +010092 else
93 fprintf(stderr, " ");
94
95 /* print ASCII dump */
96 if (i % 16 == 15) {
97 fprintf(stderr, " |");
Christopher Faulete0aa6f72018-11-30 22:23:32 +010098 for(j = i - 15; j <= i && j < ist.len; j++)
Willy Tarreau90807112020-02-25 08:16:33 +010099 fprintf(stderr, "%c", (isprint((unsigned char)*(ist.ptr+j)) ? *(ist.ptr+j) : '.'));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100100 fprintf(stderr, "|\n");
101 }
102 }
103}
104
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100105static void
Christopher Fauletb2e58492019-11-12 11:13:01 +0100106trace_raw_hexdump(struct buffer *buf, unsigned int offset, unsigned int len)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100107{
108 unsigned char p[len];
109 int block1, block2;
110
111 block1 = len;
Christopher Fauletb2e58492019-11-12 11:13:01 +0100112 if (block1 > b_contig_data(buf, offset))
113 block1 = b_contig_data(buf, offset);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100114 block2 = len - block1;
115
Christopher Fauletb2e58492019-11-12 11:13:01 +0100116 memcpy(p, b_peek(buf, offset), block1);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100117 memcpy(p+block1, b_orig(buf), block2);
118 trace_hexdump(ist2(p, len));
119}
120
121static void
122trace_htx_hexdump(struct htx *htx, unsigned int offset, unsigned int len)
123{
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100124 struct htx_blk *blk;
125
Christopher Fauletee847d42019-05-23 11:55:33 +0200126 for (blk = htx_get_first_blk(htx); blk && len; blk = htx_get_next_blk(htx, blk)) {
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100127 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Fauletee847d42019-05-23 11:55:33 +0200128 uint32_t sz = htx_get_blksz(blk);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100129 struct ist v;
130
Christopher Fauletee847d42019-05-23 11:55:33 +0200131 if (offset >= sz) {
132 offset -= sz;
133 continue;
134 }
135
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100136 v = htx_get_blk_value(htx, blk);
137 v.ptr += offset;
138 v.len -= offset;
139 offset = 0;
140
141 if (v.len > len)
142 v.len = len;
143 len -= v.len;
Christopher Faulet2d7c5392019-06-03 10:41:26 +0200144 if (type == HTX_BLK_DATA)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100145 trace_hexdump(v);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100146 }
147}
148
Christopher Fauletb2e58492019-11-12 11:13:01 +0100149static unsigned int
150trace_get_htx_datalen(struct htx *htx, unsigned int offset, unsigned int len)
151{
152 struct htx_blk *blk;
Christopher Faulet24598a42020-02-26 22:06:11 +0100153 struct htx_ret htxret = htx_find_offset(htx, offset);
154 uint32_t data = 0;
Christopher Fauletb2e58492019-11-12 11:13:01 +0100155
Christopher Faulet24598a42020-02-26 22:06:11 +0100156 blk = htxret.blk;
157 if (blk && htxret.ret && htx_get_blk_type(blk) == HTX_BLK_DATA) {
158 data += htxret.ret;
159 blk = htx_get_next_blk(htx, blk);
160 }
161 while (blk) {
162 if (htx_get_blk_type(blk) == HTX_BLK_UNUSED)
163 goto next;
164 else if (htx_get_blk_type(blk) != HTX_BLK_DATA)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100165 break;
Christopher Faulet24598a42020-02-26 22:06:11 +0100166 data += htx_get_blksz(blk);
167 next:
168 blk = htx_get_next_blk(htx, blk);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100169 }
170 return data;
171}
172
Christopher Faulete6c3b692015-09-02 17:15:16 +0200173/***************************************************************************
174 * Hooks that manage the filter lifecycle (init/check/deinit)
175 **************************************************************************/
176/* Initialize the filter. Returns -1 on error, else 0. */
177static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100178trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200179{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100180 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200181
182 if (conf->name)
183 memprintf(&conf->name, "%s/%s", conf->name, px->id);
184 else
185 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100186
Christopher Faulet6e540952018-12-03 22:43:41 +0100187 fconf->flags |= FLT_CFG_FL_HTX;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100188 fconf->conf = conf;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100189
Christopher Fauletc41d8bd2020-11-17 10:43:26 +0100190 FLT_TRACE(conf, "filter initialized [fwd random=%s - hexdump=%s]",
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100191 (conf->rand_forwarding ? "true" : "false"),
192 (conf->hexdump ? "true" : "false"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200193 return 0;
194}
195
Ilya Shipitsin6b79f382020-07-23 00:32:55 +0500196/* Free resources allocated by the trace filter. */
Christopher Faulete6c3b692015-09-02 17:15:16 +0200197static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100198trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200199{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100200 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200201
202 if (conf) {
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100203 FLT_TRACE(conf, "filter deinitialized");
Christopher Faulete6c3b692015-09-02 17:15:16 +0200204 free(conf->name);
205 free(conf);
206 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100207 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200208}
209
210/* Check configuration of a trace filter for a specified proxy.
211 * Return 1 on error, else 0. */
212static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100213trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200214{
215 return 0;
216}
217
Christopher Fauletf2273722017-07-27 16:58:42 +0200218/* Initialize the filter for each thread. Return -1 on error, else 0. */
219static int
220trace_init_per_thread(struct proxy *px, struct flt_conf *fconf)
221{
222 struct trace_config *conf = fconf->conf;
223
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100224 FLT_TRACE(conf, "filter initialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200225 return 0;
226}
227
Ilya Shipitsin6b79f382020-07-23 00:32:55 +0500228/* Free resources allocate by the trace filter for each thread. */
Christopher Fauletf2273722017-07-27 16:58:42 +0200229static void
230trace_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
231{
232 struct trace_config *conf = fconf->conf;
233
234 if (conf)
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100235 FLT_TRACE(conf, "filter deinitialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200236}
237
Christopher Faulete6c3b692015-09-02 17:15:16 +0200238/**************************************************************************
239 * Hooks to handle start/stop of streams
240 *************************************************************************/
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200241/* Called when a filter instance is created and attach to a stream */
242static int
243trace_attach(struct stream *s, struct filter *filter)
244{
245 struct trace_config *conf = FLT_CONF(filter);
246
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100247 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200248 __FUNCTION__, filter_type(filter));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100249
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200250 return 1;
251}
252
253/* Called when a filter instance is detach from a stream, just before its
254 * destruction */
255static void
256trace_detach(struct stream *s, struct filter *filter)
257{
258 struct trace_config *conf = FLT_CONF(filter);
259
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100260 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200261 __FUNCTION__, filter_type(filter));
262}
263
Christopher Faulete6c3b692015-09-02 17:15:16 +0200264/* Called when a stream is created */
265static int
266trace_stream_start(struct stream *s, struct filter *filter)
267{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100268 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200269
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100270 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200271 __FUNCTION__);
272 return 0;
273}
274
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200275
276/* Called when a backend is set for a stream */
277static int
278trace_stream_set_backend(struct stream *s, struct filter *filter,
279 struct proxy *be)
280{
281 struct trace_config *conf = FLT_CONF(filter);
282
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100283 FLT_STRM_TRACE(conf, s, "%-25s: backend=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200284 __FUNCTION__, be->id);
285 return 0;
286}
287
Christopher Faulete6c3b692015-09-02 17:15:16 +0200288/* Called when a stream is destroyed */
289static void
290trace_stream_stop(struct stream *s, struct filter *filter)
291{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100292 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200293
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100294 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200295 __FUNCTION__);
296}
297
Christopher Fauleta00d8172016-11-10 14:58:05 +0100298/* Called when the stream is woken up because of an expired timer */
299static void
300trace_check_timeouts(struct stream *s, struct filter *filter)
301{
302 struct trace_config *conf = FLT_CONF(filter);
303
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100304 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Fauleta00d8172016-11-10 14:58:05 +0100305 __FUNCTION__);
306}
307
Christopher Faulete6c3b692015-09-02 17:15:16 +0200308/**************************************************************************
309 * Hooks to handle channels activity
310 *************************************************************************/
311/* Called when analyze starts for a given channel */
312static int
313trace_chn_start_analyze(struct stream *s, struct filter *filter,
314 struct channel *chn)
315{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100316 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200317
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100318 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200319 __FUNCTION__,
320 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200321 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
322 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100323 register_data_filter(s, chn, filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200324 return 1;
325}
326
327/* Called before a processing happens on a given channel */
328static int
329trace_chn_analyze(struct stream *s, struct filter *filter,
330 struct channel *chn, unsigned an_bit)
331{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100332 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200333 char *ana;
334
335 switch (an_bit) {
336 case AN_REQ_INSPECT_FE:
337 ana = "AN_REQ_INSPECT_FE";
338 break;
339 case AN_REQ_WAIT_HTTP:
340 ana = "AN_REQ_WAIT_HTTP";
341 break;
342 case AN_REQ_HTTP_BODY:
343 ana = "AN_REQ_HTTP_BODY";
344 break;
345 case AN_REQ_HTTP_PROCESS_FE:
346 ana = "AN_REQ_HTTP_PROCESS_FE";
347 break;
348 case AN_REQ_SWITCHING_RULES:
349 ana = "AN_REQ_SWITCHING_RULES";
350 break;
351 case AN_REQ_INSPECT_BE:
352 ana = "AN_REQ_INSPECT_BE";
353 break;
354 case AN_REQ_HTTP_PROCESS_BE:
355 ana = "AN_REQ_HTTP_PROCESS_BE";
356 break;
357 case AN_REQ_SRV_RULES:
358 ana = "AN_REQ_SRV_RULES";
359 break;
360 case AN_REQ_HTTP_INNER:
361 ana = "AN_REQ_HTTP_INNER";
362 break;
363 case AN_REQ_HTTP_TARPIT:
364 ana = "AN_REQ_HTTP_TARPIT";
365 break;
366 case AN_REQ_STICKING_RULES:
367 ana = "AN_REQ_STICKING_RULES";
368 break;
369 case AN_REQ_PRST_RDP_COOKIE:
370 ana = "AN_REQ_PRST_RDP_COOKIE";
371 break;
372 case AN_REQ_HTTP_XFER_BODY:
373 ana = "AN_REQ_HTTP_XFER_BODY";
374 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200375 case AN_RES_INSPECT:
376 ana = "AN_RES_INSPECT";
377 break;
378 case AN_RES_WAIT_HTTP:
379 ana = "AN_RES_WAIT_HTTP";
380 break;
381 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
382 ana = "AN_RES_HTTP_PROCESS_FE/BE";
383 break;
384 case AN_RES_STORE_RULES:
385 ana = "AN_RES_STORE_RULES";
386 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200387 case AN_RES_HTTP_XFER_BODY:
388 ana = "AN_RES_HTTP_XFER_BODY";
389 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200390 default:
391 ana = "unknown";
392 }
393
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100394 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200395 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200396 __FUNCTION__,
397 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200398 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200399 return 1;
400}
401
402/* Called when analyze ends for a given channel */
403static int
404trace_chn_end_analyze(struct stream *s, struct filter *filter,
405 struct channel *chn)
406{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100407 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200408
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100409 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200410 __FUNCTION__,
411 channel_label(chn), proxy_mode(s), stream_pos(s));
412 return 1;
413}
414
415/**************************************************************************
416 * Hooks to filter HTTP messages
417 *************************************************************************/
418static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200419trace_http_headers(struct stream *s, struct filter *filter,
420 struct http_msg *msg)
421{
422 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200423 struct htx *htx = htxbuf(&msg->chn->buf);
424 struct htx_sl *sl = http_get_stline(htx);
425 int32_t pos;
Christopher Faulet1339d742016-05-11 16:48:33 +0200426
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100427 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)\t%.*s %.*s %.*s",
Christopher Faulet1339d742016-05-11 16:48:33 +0200428 __FUNCTION__,
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200429 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
430 HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl),
431 HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
432 HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100433
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200434 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
435 struct htx_blk *blk = htx_get_blk(htx, pos);
436 enum htx_blk_type type = htx_get_blk_type(blk);
437 struct ist n, v;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100438
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200439 if (type == HTX_BLK_EOH)
440 break;
441 if (type != HTX_BLK_HDR)
442 continue;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100443
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200444 n = htx_get_blk_name(htx, blk);
445 v = htx_get_blk_value(htx, blk);
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100446 FLT_STRM_TRACE(conf, s, "\t%.*s: %.*s",
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200447 (int)n.len, n.ptr, (int)v.len, v.ptr);
Christopher Faulet1339d742016-05-11 16:48:33 +0200448 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200449 return 1;
450}
451
452static int
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100453trace_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
454 unsigned int offset, unsigned int len)
455{
456 struct trace_config *conf = FLT_CONF(filter);
457 int ret = len;
458
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200459 if (ret && conf->rand_forwarding) {
Christopher Fauletb2e58492019-11-12 11:13:01 +0100460 unsigned int data = trace_get_htx_datalen(htxbuf(&msg->chn->buf), offset, len);
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200461
Christopher Fauletb2e58492019-11-12 11:13:01 +0100462 if (data) {
Willy Tarreau52bf8392020-03-08 00:42:37 +0100463 ret = ha_random() % (ret+1);
Christopher Faulet647fe1d2019-06-12 16:07:48 +0200464 if (!ret || ret >= data)
465 ret = len;
466 }
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200467 }
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100468
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100469 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100470 "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 Fauletb2e58492019-11-12 11:13:01 +0100476 trace_htx_hexdump(htxbuf(&msg->chn->buf), offset, ret);
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_end(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);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200488
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100489 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200490 __FUNCTION__,
491 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
492 return 1;
493}
494
495static void
496trace_http_reset(struct stream *s, struct filter *filter,
497 struct http_msg *msg)
498{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100499 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200500
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100501 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200502 __FUNCTION__,
503 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
504}
505
506static void
507trace_http_reply(struct stream *s, struct filter *filter, short status,
Willy Tarreau83061a82018-07-13 11:56:34 +0200508 const struct buffer *msg)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200509{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100510 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200511
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100512 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200513 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
514}
515
Christopher Faulete6c3b692015-09-02 17:15:16 +0200516/**************************************************************************
517 * Hooks to filter TCP data
518 *************************************************************************/
519static int
Christopher Fauletb2e58492019-11-12 11:13:01 +0100520trace_tcp_payload(struct stream *s, struct filter *filter, struct channel *chn,
521 unsigned int offset, unsigned int len)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200522{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100523 struct trace_config *conf = FLT_CONF(filter);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100524 int ret = len;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200525
Christopher Fauletb2e58492019-11-12 11:13:01 +0100526 if (s->flags & SF_HTX) {
527 if (ret && conf->rand_forwarding) {
528 unsigned int data = trace_get_htx_datalen(htxbuf(&chn->buf), offset, len);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200529
Christopher Fauletb2e58492019-11-12 11:13:01 +0100530 if (data) {
Willy Tarreau52bf8392020-03-08 00:42:37 +0100531 ret = ha_random() % (ret+1);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100532 if (!ret || ret >= data)
533 ret = len;
534 }
535 }
Christopher Faulete6c3b692015-09-02 17:15:16 +0200536
Christopher Fauletb2e58492019-11-12 11:13:01 +0100537 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
538 "offset=%u - len=%u - forward=%d",
539 __FUNCTION__,
540 channel_label(chn), proxy_mode(s), stream_pos(s),
541 offset, len, ret);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200542
Christopher Fauletb2e58492019-11-12 11:13:01 +0100543 if (conf->hexdump)
544 trace_htx_hexdump(htxbuf(&chn->buf), offset, ret);
545 }
546 else {
Christopher Faulete6c3b692015-09-02 17:15:16 +0200547
Christopher Fauletb2e58492019-11-12 11:13:01 +0100548 if (ret && conf->rand_forwarding)
Willy Tarreau52bf8392020-03-08 00:42:37 +0100549 ret = ha_random() % (ret+1);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200550
Christopher Fauletb2e58492019-11-12 11:13:01 +0100551 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
552 "offset=%u - len=%u - forward=%d",
553 __FUNCTION__,
554 channel_label(chn), proxy_mode(s), stream_pos(s),
555 offset, len, ret);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200556
Christopher Fauletb2e58492019-11-12 11:13:01 +0100557 if (conf->hexdump)
558 trace_raw_hexdump(&chn->buf, offset, ret);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100559 }
560
Christopher Fauletb2e58492019-11-12 11:13:01 +0100561 if (ret != len)
562 task_wakeup(s->task, TASK_WOKEN_MSG);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200563 return ret;
564}
Christopher Faulete6c3b692015-09-02 17:15:16 +0200565/********************************************************************
566 * Functions that manage the filter initialization
567 ********************************************************************/
568struct flt_ops trace_ops = {
569 /* Manage trace filter, called for each filter declaration */
Christopher Fauletf2273722017-07-27 16:58:42 +0200570 .init = trace_init,
571 .deinit = trace_deinit,
572 .check = trace_check,
573 .init_per_thread = trace_init_per_thread,
574 .deinit_per_thread = trace_deinit_per_thread,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200575
576 /* Handle start/stop of streams */
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200577 .attach = trace_attach,
578 .detach = trace_detach,
579 .stream_start = trace_stream_start,
580 .stream_set_backend = trace_stream_set_backend,
581 .stream_stop = trace_stream_stop,
Christopher Fauleta00d8172016-11-10 14:58:05 +0100582 .check_timeouts = trace_check_timeouts,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200583
584 /* Handle channels activity */
585 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200586 .channel_pre_analyze = trace_chn_analyze,
587 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200588 .channel_end_analyze = trace_chn_end_analyze,
589
590 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200591 .http_headers = trace_http_headers,
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100592 .http_payload = trace_http_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200593 .http_end = trace_http_end,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200594 .http_reset = trace_http_reset,
595 .http_reply = trace_http_reply,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200596
597 /* Filter TCP data */
Christopher Fauletb2e58492019-11-12 11:13:01 +0100598 .tcp_payload = trace_tcp_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200599};
600
601/* Return -1 on error, else 0 */
602static int
603parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200604 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200605{
606 struct trace_config *conf;
607 int pos = *cur_arg;
608
609 conf = calloc(1, sizeof(*conf));
610 if (!conf) {
611 memprintf(err, "%s: out of memory", args[*cur_arg]);
612 return -1;
613 }
614 conf->proxy = px;
615
616 if (!strcmp(args[pos], "trace")) {
617 pos++;
618
619 while (*args[pos]) {
620 if (!strcmp(args[pos], "name")) {
621 if (!*args[pos + 1]) {
622 memprintf(err, "'%s' : '%s' option without value",
623 args[*cur_arg], args[pos]);
624 goto error;
625 }
626 conf->name = strdup(args[pos + 1]);
627 if (!conf->name) {
628 memprintf(err, "%s: out of memory", args[*cur_arg]);
629 goto error;
630 }
631 pos++;
632 }
633 else if (!strcmp(args[pos], "random-parsing"))
Christopher Fauletc41d8bd2020-11-17 10:43:26 +0100634 continue; // ignore
Christopher Faulete6c3b692015-09-02 17:15:16 +0200635 else if (!strcmp(args[pos], "random-forwarding"))
636 conf->rand_forwarding = 1;
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100637 else if (!strcmp(args[pos], "hexdump"))
638 conf->hexdump = 1;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200639 else
640 break;
641 pos++;
642 }
643 *cur_arg = pos;
Christopher Fauletf4a4ef72018-12-07 17:39:53 +0100644 fconf->id = trace_flt_id;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100645 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200646 }
647
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100648 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200649 return 0;
650
651 error:
652 if (conf->name)
653 free(conf->name);
654 free(conf);
655 return -1;
656}
657
658/* Declare the filter parser for "trace" keyword */
659static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200660 { "trace", parse_trace_flt, NULL },
661 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200662 }
663};
664
Willy Tarreau0108d902018-11-25 19:14:37 +0100665INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);