blob: a3362963607146a9db906a161d674310778115af [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 Tarreau0108d902018-11-25 19:14:37 +010016#include <common/hathreads.h>
Willy Tarreaub96b77e2018-12-11 10:22:41 +010017#include <common/htx.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020018#include <common/standard.h>
19#include <common/time.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020020
21#include <types/channel.h>
22#include <types/filters.h>
23#include <types/global.h>
24#include <types/proxy.h>
25#include <types/stream.h>
26
27#include <proto/filters.h>
Christopher Faulete0aa6f72018-11-30 22:23:32 +010028#include <proto/http_htx.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020029#include <proto/log.h>
Christopher Fauletfc9cfe42019-07-16 14:54:53 +020030#include <proto/http_ana.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020031#include <proto/stream.h>
32
Christopher Fauletf4a4ef72018-12-07 17:39:53 +010033const char *trace_flt_id = "trace filter";
34
Christopher Faulete6c3b692015-09-02 17:15:16 +020035struct flt_ops trace_ops;
36
37struct trace_config {
38 struct proxy *proxy;
39 char *name;
40 int rand_parsing;
41 int rand_forwarding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010042 int hexdump;
Christopher Faulete6c3b692015-09-02 17:15:16 +020043};
44
Christopher Fauleta3ed2712019-11-04 11:35:42 +010045#define FLT_TRACE(conf, fmt, ...) \
Christopher Faulete6c3b692015-09-02 17:15:16 +020046 fprintf(stderr, "%d.%06d [%-20s] " fmt "\n", \
47 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
48 ##__VA_ARGS__)
49
Christopher Fauleta3ed2712019-11-04 11:35:42 +010050#define FLT_STRM_TRACE(conf, strm, fmt, ...) \
Christopher Fauletfcd99f82016-10-31 11:27:21 +010051 fprintf(stderr, "%d.%06d [%-20s] [strm %p(%x) 0x%08x 0x%08x] " fmt "\n", \
52 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
53 strm, (strm ? ((struct stream *)strm)->uniq_id : ~0U), \
54 (strm ? strm->req.analysers : 0), (strm ? strm->res.analysers : 0), \
Christopher Faulete6c3b692015-09-02 17:15:16 +020055 ##__VA_ARGS__)
56
57
58static const char *
59channel_label(const struct channel *chn)
60{
61 return (chn->flags & CF_ISRESP) ? "RESPONSE" : "REQUEST";
62}
63
64static const char *
65proxy_mode(const struct stream *s)
66{
67 struct proxy *px = (s->flags & SF_BE_ASSIGNED ? s->be : strm_fe(s));
68
Christopher Faulet386a0cd2019-07-15 21:22:44 +020069 return ((px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
Christopher Faulete6c3b692015-09-02 17:15:16 +020070}
71
72static const char *
73stream_pos(const struct stream *s)
74{
75 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
76}
77
Christopher Faulet31ed32d2016-06-21 11:42:37 +020078static const char *
79filter_type(const struct filter *f)
80{
81 return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
82}
83
Christopher Fauletfcd99f82016-10-31 11:27:21 +010084static void
Christopher Faulete0aa6f72018-11-30 22:23:32 +010085trace_hexdump(struct ist ist)
Christopher Fauletfcd99f82016-10-31 11:27:21 +010086{
Christopher Faulete0aa6f72018-11-30 22:23:32 +010087 int i, j, padding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010088
Christopher Faulete0aa6f72018-11-30 22:23:32 +010089 padding = ((ist.len % 16) ? (16 - ist.len % 16) : 0);
90 for (i = 0; i < ist.len + padding; i++) {
Christopher Fauletfcd99f82016-10-31 11:27:21 +010091 if (!(i % 16))
92 fprintf(stderr, "\t0x%06x: ", i);
93 else if (!(i % 8))
94 fprintf(stderr, " ");
95
Christopher Faulete0aa6f72018-11-30 22:23:32 +010096 if (i < ist.len)
97 fprintf(stderr, "%02x ", (unsigned char)*(ist.ptr+i));
Christopher Fauletfcd99f82016-10-31 11:27:21 +010098 else
99 fprintf(stderr, " ");
100
101 /* print ASCII dump */
102 if (i % 16 == 15) {
103 fprintf(stderr, " |");
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100104 for(j = i - 15; j <= i && j < ist.len; j++)
Willy Tarreau90807112020-02-25 08:16:33 +0100105 fprintf(stderr, "%c", (isprint((unsigned char)*(ist.ptr+j)) ? *(ist.ptr+j) : '.'));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100106 fprintf(stderr, "|\n");
107 }
108 }
109}
110
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100111static void
Christopher Fauletb2e58492019-11-12 11:13:01 +0100112trace_raw_hexdump(struct buffer *buf, unsigned int offset, unsigned int len)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100113{
114 unsigned char p[len];
115 int block1, block2;
116
117 block1 = len;
Christopher Fauletb2e58492019-11-12 11:13:01 +0100118 if (block1 > b_contig_data(buf, offset))
119 block1 = b_contig_data(buf, offset);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100120 block2 = len - block1;
121
Christopher Fauletb2e58492019-11-12 11:13:01 +0100122 memcpy(p, b_peek(buf, offset), block1);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100123 memcpy(p+block1, b_orig(buf), block2);
124 trace_hexdump(ist2(p, len));
125}
126
127static void
128trace_htx_hexdump(struct htx *htx, unsigned int offset, unsigned int len)
129{
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100130 struct htx_blk *blk;
131
Christopher Fauletee847d42019-05-23 11:55:33 +0200132 for (blk = htx_get_first_blk(htx); blk && len; blk = htx_get_next_blk(htx, blk)) {
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100133 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Fauletee847d42019-05-23 11:55:33 +0200134 uint32_t sz = htx_get_blksz(blk);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100135 struct ist v;
136
Christopher Fauletee847d42019-05-23 11:55:33 +0200137 if (offset >= sz) {
138 offset -= sz;
139 continue;
140 }
141
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100142 v = htx_get_blk_value(htx, blk);
143 v.ptr += offset;
144 v.len -= offset;
145 offset = 0;
146
147 if (v.len > len)
148 v.len = len;
149 len -= v.len;
Christopher Faulet2d7c5392019-06-03 10:41:26 +0200150 if (type == HTX_BLK_DATA)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100151 trace_hexdump(v);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100152 }
153}
154
Christopher Fauletb2e58492019-11-12 11:13:01 +0100155static unsigned int
156trace_get_htx_datalen(struct htx *htx, unsigned int offset, unsigned int len)
157{
158 struct htx_blk *blk;
Christopher Faulet24598a42020-02-26 22:06:11 +0100159 struct htx_ret htxret = htx_find_offset(htx, offset);
160 uint32_t data = 0;
Christopher Fauletb2e58492019-11-12 11:13:01 +0100161
Christopher Faulet24598a42020-02-26 22:06:11 +0100162 blk = htxret.blk;
163 if (blk && htxret.ret && htx_get_blk_type(blk) == HTX_BLK_DATA) {
164 data += htxret.ret;
165 blk = htx_get_next_blk(htx, blk);
166 }
167 while (blk) {
168 if (htx_get_blk_type(blk) == HTX_BLK_UNUSED)
169 goto next;
170 else if (htx_get_blk_type(blk) != HTX_BLK_DATA)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100171 break;
Christopher Faulet24598a42020-02-26 22:06:11 +0100172 data += htx_get_blksz(blk);
173 next:
174 blk = htx_get_next_blk(htx, blk);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100175 }
176 return data;
177}
178
Christopher Faulete6c3b692015-09-02 17:15:16 +0200179/***************************************************************************
180 * Hooks that manage the filter lifecycle (init/check/deinit)
181 **************************************************************************/
182/* Initialize the filter. Returns -1 on error, else 0. */
183static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100184trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200185{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100186 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200187
188 if (conf->name)
189 memprintf(&conf->name, "%s/%s", conf->name, px->id);
190 else
191 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100192
Christopher Faulet6e540952018-12-03 22:43:41 +0100193 fconf->flags |= FLT_CFG_FL_HTX;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100194 fconf->conf = conf;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100195
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100196 FLT_TRACE(conf, "filter initialized [read random=%s - fwd random=%s - hexdump=%s]",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200197 (conf->rand_parsing ? "true" : "false"),
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100198 (conf->rand_forwarding ? "true" : "false"),
199 (conf->hexdump ? "true" : "false"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200200 return 0;
201}
202
203/* Free ressources allocated by the trace filter. */
204static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100205trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200206{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100207 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200208
209 if (conf) {
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100210 FLT_TRACE(conf, "filter deinitialized");
Christopher Faulete6c3b692015-09-02 17:15:16 +0200211 free(conf->name);
212 free(conf);
213 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100214 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200215}
216
217/* Check configuration of a trace filter for a specified proxy.
218 * Return 1 on error, else 0. */
219static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100220trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200221{
222 return 0;
223}
224
Christopher Fauletf2273722017-07-27 16:58:42 +0200225/* Initialize the filter for each thread. Return -1 on error, else 0. */
226static int
227trace_init_per_thread(struct proxy *px, struct flt_conf *fconf)
228{
229 struct trace_config *conf = fconf->conf;
230
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100231 FLT_TRACE(conf, "filter initialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200232 return 0;
233}
234
235/* Free ressources allocate by the trace filter for each thread. */
236static void
237trace_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
238{
239 struct trace_config *conf = fconf->conf;
240
241 if (conf)
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100242 FLT_TRACE(conf, "filter deinitialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200243}
244
Christopher Faulete6c3b692015-09-02 17:15:16 +0200245/**************************************************************************
246 * Hooks to handle start/stop of streams
247 *************************************************************************/
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200248/* Called when a filter instance is created and attach to a stream */
249static int
250trace_attach(struct stream *s, struct filter *filter)
251{
252 struct trace_config *conf = FLT_CONF(filter);
253
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100254 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200255 __FUNCTION__, filter_type(filter));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100256
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200257 return 1;
258}
259
260/* Called when a filter instance is detach from a stream, just before its
261 * destruction */
262static void
263trace_detach(struct stream *s, struct filter *filter)
264{
265 struct trace_config *conf = FLT_CONF(filter);
266
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100267 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200268 __FUNCTION__, filter_type(filter));
269}
270
Christopher Faulete6c3b692015-09-02 17:15:16 +0200271/* Called when a stream is created */
272static int
273trace_stream_start(struct stream *s, struct filter *filter)
274{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100275 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200276
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100277 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200278 __FUNCTION__);
279 return 0;
280}
281
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200282
283/* Called when a backend is set for a stream */
284static int
285trace_stream_set_backend(struct stream *s, struct filter *filter,
286 struct proxy *be)
287{
288 struct trace_config *conf = FLT_CONF(filter);
289
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100290 FLT_STRM_TRACE(conf, s, "%-25s: backend=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200291 __FUNCTION__, be->id);
292 return 0;
293}
294
Christopher Faulete6c3b692015-09-02 17:15:16 +0200295/* Called when a stream is destroyed */
296static void
297trace_stream_stop(struct stream *s, struct filter *filter)
298{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100299 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200300
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100301 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200302 __FUNCTION__);
303}
304
Christopher Fauleta00d8172016-11-10 14:58:05 +0100305/* Called when the stream is woken up because of an expired timer */
306static void
307trace_check_timeouts(struct stream *s, struct filter *filter)
308{
309 struct trace_config *conf = FLT_CONF(filter);
310
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100311 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Fauleta00d8172016-11-10 14:58:05 +0100312 __FUNCTION__);
313}
314
Christopher Faulete6c3b692015-09-02 17:15:16 +0200315/**************************************************************************
316 * Hooks to handle channels activity
317 *************************************************************************/
318/* Called when analyze starts for a given channel */
319static int
320trace_chn_start_analyze(struct stream *s, struct filter *filter,
321 struct channel *chn)
322{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100323 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200324
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100325 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200326 __FUNCTION__,
327 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200328 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
329 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100330 register_data_filter(s, chn, filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200331 return 1;
332}
333
334/* Called before a processing happens on a given channel */
335static int
336trace_chn_analyze(struct stream *s, struct filter *filter,
337 struct channel *chn, unsigned an_bit)
338{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100339 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200340 char *ana;
341
342 switch (an_bit) {
343 case AN_REQ_INSPECT_FE:
344 ana = "AN_REQ_INSPECT_FE";
345 break;
346 case AN_REQ_WAIT_HTTP:
347 ana = "AN_REQ_WAIT_HTTP";
348 break;
349 case AN_REQ_HTTP_BODY:
350 ana = "AN_REQ_HTTP_BODY";
351 break;
352 case AN_REQ_HTTP_PROCESS_FE:
353 ana = "AN_REQ_HTTP_PROCESS_FE";
354 break;
355 case AN_REQ_SWITCHING_RULES:
356 ana = "AN_REQ_SWITCHING_RULES";
357 break;
358 case AN_REQ_INSPECT_BE:
359 ana = "AN_REQ_INSPECT_BE";
360 break;
361 case AN_REQ_HTTP_PROCESS_BE:
362 ana = "AN_REQ_HTTP_PROCESS_BE";
363 break;
364 case AN_REQ_SRV_RULES:
365 ana = "AN_REQ_SRV_RULES";
366 break;
367 case AN_REQ_HTTP_INNER:
368 ana = "AN_REQ_HTTP_INNER";
369 break;
370 case AN_REQ_HTTP_TARPIT:
371 ana = "AN_REQ_HTTP_TARPIT";
372 break;
373 case AN_REQ_STICKING_RULES:
374 ana = "AN_REQ_STICKING_RULES";
375 break;
376 case AN_REQ_PRST_RDP_COOKIE:
377 ana = "AN_REQ_PRST_RDP_COOKIE";
378 break;
379 case AN_REQ_HTTP_XFER_BODY:
380 ana = "AN_REQ_HTTP_XFER_BODY";
381 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200382 case AN_RES_INSPECT:
383 ana = "AN_RES_INSPECT";
384 break;
385 case AN_RES_WAIT_HTTP:
386 ana = "AN_RES_WAIT_HTTP";
387 break;
388 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
389 ana = "AN_RES_HTTP_PROCESS_FE/BE";
390 break;
391 case AN_RES_STORE_RULES:
392 ana = "AN_RES_STORE_RULES";
393 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200394 case AN_RES_HTTP_XFER_BODY:
395 ana = "AN_RES_HTTP_XFER_BODY";
396 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200397 default:
398 ana = "unknown";
399 }
400
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100401 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200402 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200403 __FUNCTION__,
404 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200405 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200406 return 1;
407}
408
409/* Called when analyze ends for a given channel */
410static int
411trace_chn_end_analyze(struct stream *s, struct filter *filter,
412 struct channel *chn)
413{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100414 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200415
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100416 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200417 __FUNCTION__,
418 channel_label(chn), proxy_mode(s), stream_pos(s));
419 return 1;
420}
421
422/**************************************************************************
423 * Hooks to filter HTTP messages
424 *************************************************************************/
425static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200426trace_http_headers(struct stream *s, struct filter *filter,
427 struct http_msg *msg)
428{
429 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200430 struct htx *htx = htxbuf(&msg->chn->buf);
431 struct htx_sl *sl = http_get_stline(htx);
432 int32_t pos;
Christopher Faulet1339d742016-05-11 16:48:33 +0200433
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100434 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)\t%.*s %.*s %.*s",
Christopher Faulet1339d742016-05-11 16:48:33 +0200435 __FUNCTION__,
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200436 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
437 HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl),
438 HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
439 HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100440
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200441 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
442 struct htx_blk *blk = htx_get_blk(htx, pos);
443 enum htx_blk_type type = htx_get_blk_type(blk);
444 struct ist n, v;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100445
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200446 if (type == HTX_BLK_EOH)
447 break;
448 if (type != HTX_BLK_HDR)
449 continue;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100450
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200451 n = htx_get_blk_name(htx, blk);
452 v = htx_get_blk_value(htx, blk);
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100453 FLT_STRM_TRACE(conf, s, "\t%.*s: %.*s",
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200454 (int)n.len, n.ptr, (int)v.len, v.ptr);
Christopher Faulet1339d742016-05-11 16:48:33 +0200455 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200456 return 1;
457}
458
459static int
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100460trace_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
461 unsigned int offset, unsigned int len)
462{
463 struct trace_config *conf = FLT_CONF(filter);
464 int ret = len;
465
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200466 if (ret && conf->rand_forwarding) {
Christopher Fauletb2e58492019-11-12 11:13:01 +0100467 unsigned int data = trace_get_htx_datalen(htxbuf(&msg->chn->buf), offset, len);
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200468
Christopher Fauletb2e58492019-11-12 11:13:01 +0100469 if (data) {
Willy Tarreau52bf8392020-03-08 00:42:37 +0100470 ret = ha_random() % (ret+1);
Christopher Faulet647fe1d2019-06-12 16:07:48 +0200471 if (!ret || ret >= data)
472 ret = len;
473 }
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200474 }
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100475
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100476 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100477 "offset=%u - len=%u - forward=%d",
478 __FUNCTION__,
479 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
480 offset, len, ret);
481
482 if (conf->hexdump)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100483 trace_htx_hexdump(htxbuf(&msg->chn->buf), offset, ret);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100484
485 if (ret != len)
486 task_wakeup(s->task, TASK_WOKEN_MSG);
487 return ret;
488}
489
490static int
Christopher Faulete6c3b692015-09-02 17:15:16 +0200491trace_http_end(struct stream *s, struct filter *filter,
492 struct http_msg *msg)
493{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100494 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200495
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100496 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200497 __FUNCTION__,
498 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
499 return 1;
500}
501
502static void
503trace_http_reset(struct stream *s, struct filter *filter,
504 struct http_msg *msg)
505{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100506 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200507
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100508 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200509 __FUNCTION__,
510 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
511}
512
513static void
514trace_http_reply(struct stream *s, struct filter *filter, short status,
Willy Tarreau83061a82018-07-13 11:56:34 +0200515 const struct buffer *msg)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200516{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100517 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200518
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100519 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200520 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
521}
522
Christopher Faulete6c3b692015-09-02 17:15:16 +0200523/**************************************************************************
524 * Hooks to filter TCP data
525 *************************************************************************/
526static int
Christopher Fauletb2e58492019-11-12 11:13:01 +0100527trace_tcp_payload(struct stream *s, struct filter *filter, struct channel *chn,
528 unsigned int offset, unsigned int len)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200529{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100530 struct trace_config *conf = FLT_CONF(filter);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100531 int ret = len;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200532
Christopher Fauletb2e58492019-11-12 11:13:01 +0100533 if (s->flags & SF_HTX) {
534 if (ret && conf->rand_forwarding) {
535 unsigned int data = trace_get_htx_datalen(htxbuf(&chn->buf), offset, len);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200536
Christopher Fauletb2e58492019-11-12 11:13:01 +0100537 if (data) {
Willy Tarreau52bf8392020-03-08 00:42:37 +0100538 ret = ha_random() % (ret+1);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100539 if (!ret || ret >= data)
540 ret = len;
541 }
542 }
Christopher Faulete6c3b692015-09-02 17:15:16 +0200543
Christopher Fauletb2e58492019-11-12 11:13:01 +0100544 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
545 "offset=%u - len=%u - forward=%d",
546 __FUNCTION__,
547 channel_label(chn), proxy_mode(s), stream_pos(s),
548 offset, len, ret);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200549
Christopher Fauletb2e58492019-11-12 11:13:01 +0100550 if (conf->hexdump)
551 trace_htx_hexdump(htxbuf(&chn->buf), offset, ret);
552 }
553 else {
Christopher Faulete6c3b692015-09-02 17:15:16 +0200554
Christopher Fauletb2e58492019-11-12 11:13:01 +0100555 if (ret && conf->rand_forwarding)
Willy Tarreau52bf8392020-03-08 00:42:37 +0100556 ret = ha_random() % (ret+1);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200557
Christopher Fauletb2e58492019-11-12 11:13:01 +0100558 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
559 "offset=%u - len=%u - forward=%d",
560 __FUNCTION__,
561 channel_label(chn), proxy_mode(s), stream_pos(s),
562 offset, len, ret);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200563
Christopher Fauletb2e58492019-11-12 11:13:01 +0100564 if (conf->hexdump)
565 trace_raw_hexdump(&chn->buf, offset, ret);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100566 }
567
Christopher Fauletb2e58492019-11-12 11:13:01 +0100568 if (ret != len)
569 task_wakeup(s->task, TASK_WOKEN_MSG);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200570 return ret;
571}
Christopher Faulete6c3b692015-09-02 17:15:16 +0200572/********************************************************************
573 * Functions that manage the filter initialization
574 ********************************************************************/
575struct flt_ops trace_ops = {
576 /* Manage trace filter, called for each filter declaration */
Christopher Fauletf2273722017-07-27 16:58:42 +0200577 .init = trace_init,
578 .deinit = trace_deinit,
579 .check = trace_check,
580 .init_per_thread = trace_init_per_thread,
581 .deinit_per_thread = trace_deinit_per_thread,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200582
583 /* Handle start/stop of streams */
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200584 .attach = trace_attach,
585 .detach = trace_detach,
586 .stream_start = trace_stream_start,
587 .stream_set_backend = trace_stream_set_backend,
588 .stream_stop = trace_stream_stop,
Christopher Fauleta00d8172016-11-10 14:58:05 +0100589 .check_timeouts = trace_check_timeouts,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200590
591 /* Handle channels activity */
592 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200593 .channel_pre_analyze = trace_chn_analyze,
594 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200595 .channel_end_analyze = trace_chn_end_analyze,
596
597 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200598 .http_headers = trace_http_headers,
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100599 .http_payload = trace_http_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200600 .http_end = trace_http_end,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200601 .http_reset = trace_http_reset,
602 .http_reply = trace_http_reply,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200603
604 /* Filter TCP data */
Christopher Fauletb2e58492019-11-12 11:13:01 +0100605 .tcp_payload = trace_tcp_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200606};
607
608/* Return -1 on error, else 0 */
609static int
610parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200611 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200612{
613 struct trace_config *conf;
614 int pos = *cur_arg;
615
616 conf = calloc(1, sizeof(*conf));
617 if (!conf) {
618 memprintf(err, "%s: out of memory", args[*cur_arg]);
619 return -1;
620 }
621 conf->proxy = px;
622
623 if (!strcmp(args[pos], "trace")) {
624 pos++;
625
626 while (*args[pos]) {
627 if (!strcmp(args[pos], "name")) {
628 if (!*args[pos + 1]) {
629 memprintf(err, "'%s' : '%s' option without value",
630 args[*cur_arg], args[pos]);
631 goto error;
632 }
633 conf->name = strdup(args[pos + 1]);
634 if (!conf->name) {
635 memprintf(err, "%s: out of memory", args[*cur_arg]);
636 goto error;
637 }
638 pos++;
639 }
640 else if (!strcmp(args[pos], "random-parsing"))
641 conf->rand_parsing = 1;
642 else if (!strcmp(args[pos], "random-forwarding"))
643 conf->rand_forwarding = 1;
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100644 else if (!strcmp(args[pos], "hexdump"))
645 conf->hexdump = 1;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200646 else
647 break;
648 pos++;
649 }
650 *cur_arg = pos;
Christopher Fauletf4a4ef72018-12-07 17:39:53 +0100651 fconf->id = trace_flt_id;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100652 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200653 }
654
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100655 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200656 return 0;
657
658 error:
659 if (conf->name)
660 free(conf->name);
661 free(conf);
662 return -1;
663}
664
665/* Declare the filter parser for "trace" keyword */
666static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200667 { "trace", parse_trace_flt, NULL },
668 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200669 }
670};
671
Willy Tarreau0108d902018-11-25 19:14:37 +0100672INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);