blob: 01278bb0bac9a9f8d49dc021639fc4756eb94d15 [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 Tarreauc7babd82020-06-04 21:29:29 +020017#include <haproxy/filters.h>
Willy Tarreauc2b1ff02020-06-04 21:21:03 +020018#include <haproxy/http_ana-t.h>
Willy Tarreau87735332020-06-04 09:08:41 +020019#include <haproxy/http_htx.h>
Willy Tarreau16f958c2020-06-03 08:44:35 +020020#include <haproxy/htx.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020021#include <haproxy/log.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020022#include <haproxy/tools.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020023#include <haproxy/time.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020024
Willy Tarreauf268ee82020-06-04 17:05:57 +020025#include <haproxy/global.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020026#include <types/proxy.h>
27#include <types/stream.h>
28
Christopher Faulete6c3b692015-09-02 17:15:16 +020029#include <proto/stream.h>
30
Christopher Fauletf4a4ef72018-12-07 17:39:53 +010031const char *trace_flt_id = "trace filter";
32
Christopher Faulete6c3b692015-09-02 17:15:16 +020033struct flt_ops trace_ops;
34
35struct trace_config {
36 struct proxy *proxy;
37 char *name;
38 int rand_parsing;
39 int rand_forwarding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010040 int hexdump;
Christopher Faulete6c3b692015-09-02 17:15:16 +020041};
42
Christopher Fauleta3ed2712019-11-04 11:35:42 +010043#define FLT_TRACE(conf, fmt, ...) \
Christopher Faulete6c3b692015-09-02 17:15:16 +020044 fprintf(stderr, "%d.%06d [%-20s] " fmt "\n", \
45 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
46 ##__VA_ARGS__)
47
Christopher Fauleta3ed2712019-11-04 11:35:42 +010048#define FLT_STRM_TRACE(conf, strm, fmt, ...) \
Christopher Fauletfcd99f82016-10-31 11:27:21 +010049 fprintf(stderr, "%d.%06d [%-20s] [strm %p(%x) 0x%08x 0x%08x] " fmt "\n", \
50 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
51 strm, (strm ? ((struct stream *)strm)->uniq_id : ~0U), \
52 (strm ? strm->req.analysers : 0), (strm ? strm->res.analysers : 0), \
Christopher Faulete6c3b692015-09-02 17:15:16 +020053 ##__VA_ARGS__)
54
55
56static const char *
57channel_label(const struct channel *chn)
58{
59 return (chn->flags & CF_ISRESP) ? "RESPONSE" : "REQUEST";
60}
61
62static const char *
63proxy_mode(const struct stream *s)
64{
65 struct proxy *px = (s->flags & SF_BE_ASSIGNED ? s->be : strm_fe(s));
66
Christopher Faulet386a0cd2019-07-15 21:22:44 +020067 return ((px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
Christopher Faulete6c3b692015-09-02 17:15:16 +020068}
69
70static const char *
71stream_pos(const struct stream *s)
72{
73 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
74}
75
Christopher Faulet31ed32d2016-06-21 11:42:37 +020076static const char *
77filter_type(const struct filter *f)
78{
79 return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
80}
81
Christopher Fauletfcd99f82016-10-31 11:27:21 +010082static void
Christopher Faulete0aa6f72018-11-30 22:23:32 +010083trace_hexdump(struct ist ist)
Christopher Fauletfcd99f82016-10-31 11:27:21 +010084{
Christopher Faulete0aa6f72018-11-30 22:23:32 +010085 int i, j, padding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010086
Christopher Faulete0aa6f72018-11-30 22:23:32 +010087 padding = ((ist.len % 16) ? (16 - ist.len % 16) : 0);
88 for (i = 0; i < ist.len + padding; i++) {
Christopher Fauletfcd99f82016-10-31 11:27:21 +010089 if (!(i % 16))
90 fprintf(stderr, "\t0x%06x: ", i);
91 else if (!(i % 8))
92 fprintf(stderr, " ");
93
Christopher Faulete0aa6f72018-11-30 22:23:32 +010094 if (i < ist.len)
95 fprintf(stderr, "%02x ", (unsigned char)*(ist.ptr+i));
Christopher Fauletfcd99f82016-10-31 11:27:21 +010096 else
97 fprintf(stderr, " ");
98
99 /* print ASCII dump */
100 if (i % 16 == 15) {
101 fprintf(stderr, " |");
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100102 for(j = i - 15; j <= i && j < ist.len; j++)
Willy Tarreau90807112020-02-25 08:16:33 +0100103 fprintf(stderr, "%c", (isprint((unsigned char)*(ist.ptr+j)) ? *(ist.ptr+j) : '.'));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100104 fprintf(stderr, "|\n");
105 }
106 }
107}
108
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100109static void
Christopher Fauletb2e58492019-11-12 11:13:01 +0100110trace_raw_hexdump(struct buffer *buf, unsigned int offset, unsigned int len)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100111{
112 unsigned char p[len];
113 int block1, block2;
114
115 block1 = len;
Christopher Fauletb2e58492019-11-12 11:13:01 +0100116 if (block1 > b_contig_data(buf, offset))
117 block1 = b_contig_data(buf, offset);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100118 block2 = len - block1;
119
Christopher Fauletb2e58492019-11-12 11:13:01 +0100120 memcpy(p, b_peek(buf, offset), block1);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100121 memcpy(p+block1, b_orig(buf), block2);
122 trace_hexdump(ist2(p, len));
123}
124
125static void
126trace_htx_hexdump(struct htx *htx, unsigned int offset, unsigned int len)
127{
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100128 struct htx_blk *blk;
129
Christopher Fauletee847d42019-05-23 11:55:33 +0200130 for (blk = htx_get_first_blk(htx); blk && len; blk = htx_get_next_blk(htx, blk)) {
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100131 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Fauletee847d42019-05-23 11:55:33 +0200132 uint32_t sz = htx_get_blksz(blk);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100133 struct ist v;
134
Christopher Fauletee847d42019-05-23 11:55:33 +0200135 if (offset >= sz) {
136 offset -= sz;
137 continue;
138 }
139
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100140 v = htx_get_blk_value(htx, blk);
141 v.ptr += offset;
142 v.len -= offset;
143 offset = 0;
144
145 if (v.len > len)
146 v.len = len;
147 len -= v.len;
Christopher Faulet2d7c5392019-06-03 10:41:26 +0200148 if (type == HTX_BLK_DATA)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100149 trace_hexdump(v);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100150 }
151}
152
Christopher Fauletb2e58492019-11-12 11:13:01 +0100153static unsigned int
154trace_get_htx_datalen(struct htx *htx, unsigned int offset, unsigned int len)
155{
156 struct htx_blk *blk;
Christopher Faulet24598a42020-02-26 22:06:11 +0100157 struct htx_ret htxret = htx_find_offset(htx, offset);
158 uint32_t data = 0;
Christopher Fauletb2e58492019-11-12 11:13:01 +0100159
Christopher Faulet24598a42020-02-26 22:06:11 +0100160 blk = htxret.blk;
161 if (blk && htxret.ret && htx_get_blk_type(blk) == HTX_BLK_DATA) {
162 data += htxret.ret;
163 blk = htx_get_next_blk(htx, blk);
164 }
165 while (blk) {
166 if (htx_get_blk_type(blk) == HTX_BLK_UNUSED)
167 goto next;
168 else if (htx_get_blk_type(blk) != HTX_BLK_DATA)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100169 break;
Christopher Faulet24598a42020-02-26 22:06:11 +0100170 data += htx_get_blksz(blk);
171 next:
172 blk = htx_get_next_blk(htx, blk);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100173 }
174 return data;
175}
176
Christopher Faulete6c3b692015-09-02 17:15:16 +0200177/***************************************************************************
178 * Hooks that manage the filter lifecycle (init/check/deinit)
179 **************************************************************************/
180/* Initialize the filter. Returns -1 on error, else 0. */
181static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100182trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200183{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100184 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200185
186 if (conf->name)
187 memprintf(&conf->name, "%s/%s", conf->name, px->id);
188 else
189 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100190
Christopher Faulet6e540952018-12-03 22:43:41 +0100191 fconf->flags |= FLT_CFG_FL_HTX;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100192 fconf->conf = conf;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100193
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100194 FLT_TRACE(conf, "filter initialized [read random=%s - fwd random=%s - hexdump=%s]",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200195 (conf->rand_parsing ? "true" : "false"),
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100196 (conf->rand_forwarding ? "true" : "false"),
197 (conf->hexdump ? "true" : "false"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200198 return 0;
199}
200
201/* Free ressources allocated by the trace filter. */
202static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100203trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200204{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100205 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200206
207 if (conf) {
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100208 FLT_TRACE(conf, "filter deinitialized");
Christopher Faulete6c3b692015-09-02 17:15:16 +0200209 free(conf->name);
210 free(conf);
211 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100212 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200213}
214
215/* Check configuration of a trace filter for a specified proxy.
216 * Return 1 on error, else 0. */
217static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100218trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200219{
220 return 0;
221}
222
Christopher Fauletf2273722017-07-27 16:58:42 +0200223/* Initialize the filter for each thread. Return -1 on error, else 0. */
224static int
225trace_init_per_thread(struct proxy *px, struct flt_conf *fconf)
226{
227 struct trace_config *conf = fconf->conf;
228
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100229 FLT_TRACE(conf, "filter initialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200230 return 0;
231}
232
233/* Free ressources allocate by the trace filter for each thread. */
234static void
235trace_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
236{
237 struct trace_config *conf = fconf->conf;
238
239 if (conf)
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100240 FLT_TRACE(conf, "filter deinitialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200241}
242
Christopher Faulete6c3b692015-09-02 17:15:16 +0200243/**************************************************************************
244 * Hooks to handle start/stop of streams
245 *************************************************************************/
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200246/* Called when a filter instance is created and attach to a stream */
247static int
248trace_attach(struct stream *s, struct filter *filter)
249{
250 struct trace_config *conf = FLT_CONF(filter);
251
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100252 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200253 __FUNCTION__, filter_type(filter));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100254
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200255 return 1;
256}
257
258/* Called when a filter instance is detach from a stream, just before its
259 * destruction */
260static void
261trace_detach(struct stream *s, struct filter *filter)
262{
263 struct trace_config *conf = FLT_CONF(filter);
264
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100265 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200266 __FUNCTION__, filter_type(filter));
267}
268
Christopher Faulete6c3b692015-09-02 17:15:16 +0200269/* Called when a stream is created */
270static int
271trace_stream_start(struct stream *s, struct filter *filter)
272{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100273 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200274
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100275 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200276 __FUNCTION__);
277 return 0;
278}
279
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200280
281/* Called when a backend is set for a stream */
282static int
283trace_stream_set_backend(struct stream *s, struct filter *filter,
284 struct proxy *be)
285{
286 struct trace_config *conf = FLT_CONF(filter);
287
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100288 FLT_STRM_TRACE(conf, s, "%-25s: backend=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200289 __FUNCTION__, be->id);
290 return 0;
291}
292
Christopher Faulete6c3b692015-09-02 17:15:16 +0200293/* Called when a stream is destroyed */
294static void
295trace_stream_stop(struct stream *s, struct filter *filter)
296{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100297 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200298
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100299 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200300 __FUNCTION__);
301}
302
Christopher Fauleta00d8172016-11-10 14:58:05 +0100303/* Called when the stream is woken up because of an expired timer */
304static void
305trace_check_timeouts(struct stream *s, struct filter *filter)
306{
307 struct trace_config *conf = FLT_CONF(filter);
308
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100309 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Fauleta00d8172016-11-10 14:58:05 +0100310 __FUNCTION__);
311}
312
Christopher Faulete6c3b692015-09-02 17:15:16 +0200313/**************************************************************************
314 * Hooks to handle channels activity
315 *************************************************************************/
316/* Called when analyze starts for a given channel */
317static int
318trace_chn_start_analyze(struct stream *s, struct filter *filter,
319 struct channel *chn)
320{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100321 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200322
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100323 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200324 __FUNCTION__,
325 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200326 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
327 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100328 register_data_filter(s, chn, filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200329 return 1;
330}
331
332/* Called before a processing happens on a given channel */
333static int
334trace_chn_analyze(struct stream *s, struct filter *filter,
335 struct channel *chn, unsigned an_bit)
336{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100337 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200338 char *ana;
339
340 switch (an_bit) {
341 case AN_REQ_INSPECT_FE:
342 ana = "AN_REQ_INSPECT_FE";
343 break;
344 case AN_REQ_WAIT_HTTP:
345 ana = "AN_REQ_WAIT_HTTP";
346 break;
347 case AN_REQ_HTTP_BODY:
348 ana = "AN_REQ_HTTP_BODY";
349 break;
350 case AN_REQ_HTTP_PROCESS_FE:
351 ana = "AN_REQ_HTTP_PROCESS_FE";
352 break;
353 case AN_REQ_SWITCHING_RULES:
354 ana = "AN_REQ_SWITCHING_RULES";
355 break;
356 case AN_REQ_INSPECT_BE:
357 ana = "AN_REQ_INSPECT_BE";
358 break;
359 case AN_REQ_HTTP_PROCESS_BE:
360 ana = "AN_REQ_HTTP_PROCESS_BE";
361 break;
362 case AN_REQ_SRV_RULES:
363 ana = "AN_REQ_SRV_RULES";
364 break;
365 case AN_REQ_HTTP_INNER:
366 ana = "AN_REQ_HTTP_INNER";
367 break;
368 case AN_REQ_HTTP_TARPIT:
369 ana = "AN_REQ_HTTP_TARPIT";
370 break;
371 case AN_REQ_STICKING_RULES:
372 ana = "AN_REQ_STICKING_RULES";
373 break;
374 case AN_REQ_PRST_RDP_COOKIE:
375 ana = "AN_REQ_PRST_RDP_COOKIE";
376 break;
377 case AN_REQ_HTTP_XFER_BODY:
378 ana = "AN_REQ_HTTP_XFER_BODY";
379 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200380 case AN_RES_INSPECT:
381 ana = "AN_RES_INSPECT";
382 break;
383 case AN_RES_WAIT_HTTP:
384 ana = "AN_RES_WAIT_HTTP";
385 break;
386 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
387 ana = "AN_RES_HTTP_PROCESS_FE/BE";
388 break;
389 case AN_RES_STORE_RULES:
390 ana = "AN_RES_STORE_RULES";
391 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200392 case AN_RES_HTTP_XFER_BODY:
393 ana = "AN_RES_HTTP_XFER_BODY";
394 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200395 default:
396 ana = "unknown";
397 }
398
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100399 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200400 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200401 __FUNCTION__,
402 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200403 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200404 return 1;
405}
406
407/* Called when analyze ends for a given channel */
408static int
409trace_chn_end_analyze(struct stream *s, struct filter *filter,
410 struct channel *chn)
411{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100412 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200413
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100414 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200415 __FUNCTION__,
416 channel_label(chn), proxy_mode(s), stream_pos(s));
417 return 1;
418}
419
420/**************************************************************************
421 * Hooks to filter HTTP messages
422 *************************************************************************/
423static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200424trace_http_headers(struct stream *s, struct filter *filter,
425 struct http_msg *msg)
426{
427 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200428 struct htx *htx = htxbuf(&msg->chn->buf);
429 struct htx_sl *sl = http_get_stline(htx);
430 int32_t pos;
Christopher Faulet1339d742016-05-11 16:48:33 +0200431
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100432 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)\t%.*s %.*s %.*s",
Christopher Faulet1339d742016-05-11 16:48:33 +0200433 __FUNCTION__,
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200434 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
435 HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl),
436 HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
437 HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100438
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200439 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
440 struct htx_blk *blk = htx_get_blk(htx, pos);
441 enum htx_blk_type type = htx_get_blk_type(blk);
442 struct ist n, v;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100443
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200444 if (type == HTX_BLK_EOH)
445 break;
446 if (type != HTX_BLK_HDR)
447 continue;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100448
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200449 n = htx_get_blk_name(htx, blk);
450 v = htx_get_blk_value(htx, blk);
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100451 FLT_STRM_TRACE(conf, s, "\t%.*s: %.*s",
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200452 (int)n.len, n.ptr, (int)v.len, v.ptr);
Christopher Faulet1339d742016-05-11 16:48:33 +0200453 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200454 return 1;
455}
456
457static int
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100458trace_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
459 unsigned int offset, unsigned int len)
460{
461 struct trace_config *conf = FLT_CONF(filter);
462 int ret = len;
463
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200464 if (ret && conf->rand_forwarding) {
Christopher Fauletb2e58492019-11-12 11:13:01 +0100465 unsigned int data = trace_get_htx_datalen(htxbuf(&msg->chn->buf), offset, len);
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200466
Christopher Fauletb2e58492019-11-12 11:13:01 +0100467 if (data) {
Willy Tarreau52bf8392020-03-08 00:42:37 +0100468 ret = ha_random() % (ret+1);
Christopher Faulet647fe1d2019-06-12 16:07:48 +0200469 if (!ret || ret >= data)
470 ret = len;
471 }
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200472 }
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100473
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100474 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100475 "offset=%u - len=%u - forward=%d",
476 __FUNCTION__,
477 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
478 offset, len, ret);
479
480 if (conf->hexdump)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100481 trace_htx_hexdump(htxbuf(&msg->chn->buf), offset, ret);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100482
483 if (ret != len)
484 task_wakeup(s->task, TASK_WOKEN_MSG);
485 return ret;
486}
487
488static int
Christopher Faulete6c3b692015-09-02 17:15:16 +0200489trace_http_end(struct stream *s, struct filter *filter,
490 struct http_msg *msg)
491{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100492 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200493
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100494 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200495 __FUNCTION__,
496 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
497 return 1;
498}
499
500static void
501trace_http_reset(struct stream *s, struct filter *filter,
502 struct http_msg *msg)
503{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100504 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200505
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100506 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200507 __FUNCTION__,
508 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
509}
510
511static void
512trace_http_reply(struct stream *s, struct filter *filter, short status,
Willy Tarreau83061a82018-07-13 11:56:34 +0200513 const struct buffer *msg)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200514{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100515 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200516
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100517 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200518 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
519}
520
Christopher Faulete6c3b692015-09-02 17:15:16 +0200521/**************************************************************************
522 * Hooks to filter TCP data
523 *************************************************************************/
524static int
Christopher Fauletb2e58492019-11-12 11:13:01 +0100525trace_tcp_payload(struct stream *s, struct filter *filter, struct channel *chn,
526 unsigned int offset, unsigned int len)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200527{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100528 struct trace_config *conf = FLT_CONF(filter);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100529 int ret = len;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200530
Christopher Fauletb2e58492019-11-12 11:13:01 +0100531 if (s->flags & SF_HTX) {
532 if (ret && conf->rand_forwarding) {
533 unsigned int data = trace_get_htx_datalen(htxbuf(&chn->buf), offset, len);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200534
Christopher Fauletb2e58492019-11-12 11:13:01 +0100535 if (data) {
Willy Tarreau52bf8392020-03-08 00:42:37 +0100536 ret = ha_random() % (ret+1);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100537 if (!ret || ret >= data)
538 ret = len;
539 }
540 }
Christopher Faulete6c3b692015-09-02 17:15:16 +0200541
Christopher Fauletb2e58492019-11-12 11:13:01 +0100542 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
543 "offset=%u - len=%u - forward=%d",
544 __FUNCTION__,
545 channel_label(chn), proxy_mode(s), stream_pos(s),
546 offset, len, ret);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200547
Christopher Fauletb2e58492019-11-12 11:13:01 +0100548 if (conf->hexdump)
549 trace_htx_hexdump(htxbuf(&chn->buf), offset, ret);
550 }
551 else {
Christopher Faulete6c3b692015-09-02 17:15:16 +0200552
Christopher Fauletb2e58492019-11-12 11:13:01 +0100553 if (ret && conf->rand_forwarding)
Willy Tarreau52bf8392020-03-08 00:42:37 +0100554 ret = ha_random() % (ret+1);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200555
Christopher Fauletb2e58492019-11-12 11:13:01 +0100556 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
557 "offset=%u - len=%u - forward=%d",
558 __FUNCTION__,
559 channel_label(chn), proxy_mode(s), stream_pos(s),
560 offset, len, ret);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200561
Christopher Fauletb2e58492019-11-12 11:13:01 +0100562 if (conf->hexdump)
563 trace_raw_hexdump(&chn->buf, offset, ret);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100564 }
565
Christopher Fauletb2e58492019-11-12 11:13:01 +0100566 if (ret != len)
567 task_wakeup(s->task, TASK_WOKEN_MSG);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200568 return ret;
569}
Christopher Faulete6c3b692015-09-02 17:15:16 +0200570/********************************************************************
571 * Functions that manage the filter initialization
572 ********************************************************************/
573struct flt_ops trace_ops = {
574 /* Manage trace filter, called for each filter declaration */
Christopher Fauletf2273722017-07-27 16:58:42 +0200575 .init = trace_init,
576 .deinit = trace_deinit,
577 .check = trace_check,
578 .init_per_thread = trace_init_per_thread,
579 .deinit_per_thread = trace_deinit_per_thread,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200580
581 /* Handle start/stop of streams */
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200582 .attach = trace_attach,
583 .detach = trace_detach,
584 .stream_start = trace_stream_start,
585 .stream_set_backend = trace_stream_set_backend,
586 .stream_stop = trace_stream_stop,
Christopher Fauleta00d8172016-11-10 14:58:05 +0100587 .check_timeouts = trace_check_timeouts,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200588
589 /* Handle channels activity */
590 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200591 .channel_pre_analyze = trace_chn_analyze,
592 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200593 .channel_end_analyze = trace_chn_end_analyze,
594
595 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200596 .http_headers = trace_http_headers,
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100597 .http_payload = trace_http_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200598 .http_end = trace_http_end,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200599 .http_reset = trace_http_reset,
600 .http_reply = trace_http_reply,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200601
602 /* Filter TCP data */
Christopher Fauletb2e58492019-11-12 11:13:01 +0100603 .tcp_payload = trace_tcp_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200604};
605
606/* Return -1 on error, else 0 */
607static int
608parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200609 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200610{
611 struct trace_config *conf;
612 int pos = *cur_arg;
613
614 conf = calloc(1, sizeof(*conf));
615 if (!conf) {
616 memprintf(err, "%s: out of memory", args[*cur_arg]);
617 return -1;
618 }
619 conf->proxy = px;
620
621 if (!strcmp(args[pos], "trace")) {
622 pos++;
623
624 while (*args[pos]) {
625 if (!strcmp(args[pos], "name")) {
626 if (!*args[pos + 1]) {
627 memprintf(err, "'%s' : '%s' option without value",
628 args[*cur_arg], args[pos]);
629 goto error;
630 }
631 conf->name = strdup(args[pos + 1]);
632 if (!conf->name) {
633 memprintf(err, "%s: out of memory", args[*cur_arg]);
634 goto error;
635 }
636 pos++;
637 }
638 else if (!strcmp(args[pos], "random-parsing"))
639 conf->rand_parsing = 1;
640 else if (!strcmp(args[pos], "random-forwarding"))
641 conf->rand_forwarding = 1;
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100642 else if (!strcmp(args[pos], "hexdump"))
643 conf->hexdump = 1;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200644 else
645 break;
646 pos++;
647 }
648 *cur_arg = pos;
Christopher Fauletf4a4ef72018-12-07 17:39:53 +0100649 fconf->id = trace_flt_id;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100650 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200651 }
652
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100653 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200654 return 0;
655
656 error:
657 if (conf->name)
658 free(conf->name);
659 free(conf);
660 return -1;
661}
662
663/* Declare the filter parser for "trace" keyword */
664static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200665 { "trace", parse_trace_flt, NULL },
666 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200667 }
668};
669
Willy Tarreau0108d902018-11-25 19:14:37 +0100670INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);