blob: 1c200cefcae766cb83bc464e1f75613019764baa [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 Tarreau87735332020-06-04 09:08:41 +020016#include <haproxy/http_htx.h>
Willy Tarreau16f958c2020-06-03 08:44:35 +020017#include <haproxy/htx.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020018#include <haproxy/tools.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020019#include <haproxy/time.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020020
21#include <types/channel.h>
22#include <types/filters.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020023#include <haproxy/global.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020024#include <types/proxy.h>
25#include <types/stream.h>
26
27#include <proto/filters.h>
28#include <proto/log.h>
Christopher Fauletfc9cfe42019-07-16 14:54:53 +020029#include <proto/http_ana.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020030#include <proto/stream.h>
31
Christopher Fauletf4a4ef72018-12-07 17:39:53 +010032const char *trace_flt_id = "trace filter";
33
Christopher Faulete6c3b692015-09-02 17:15:16 +020034struct flt_ops trace_ops;
35
36struct trace_config {
37 struct proxy *proxy;
38 char *name;
39 int rand_parsing;
40 int rand_forwarding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010041 int hexdump;
Christopher Faulete6c3b692015-09-02 17:15:16 +020042};
43
Christopher Fauleta3ed2712019-11-04 11:35:42 +010044#define FLT_TRACE(conf, fmt, ...) \
Christopher Faulete6c3b692015-09-02 17:15:16 +020045 fprintf(stderr, "%d.%06d [%-20s] " fmt "\n", \
46 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
47 ##__VA_ARGS__)
48
Christopher Fauleta3ed2712019-11-04 11:35:42 +010049#define FLT_STRM_TRACE(conf, strm, fmt, ...) \
Christopher Fauletfcd99f82016-10-31 11:27:21 +010050 fprintf(stderr, "%d.%06d [%-20s] [strm %p(%x) 0x%08x 0x%08x] " fmt "\n", \
51 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
52 strm, (strm ? ((struct stream *)strm)->uniq_id : ~0U), \
53 (strm ? strm->req.analysers : 0), (strm ? strm->res.analysers : 0), \
Christopher Faulete6c3b692015-09-02 17:15:16 +020054 ##__VA_ARGS__)
55
56
57static const char *
58channel_label(const struct channel *chn)
59{
60 return (chn->flags & CF_ISRESP) ? "RESPONSE" : "REQUEST";
61}
62
63static const char *
64proxy_mode(const struct stream *s)
65{
66 struct proxy *px = (s->flags & SF_BE_ASSIGNED ? s->be : strm_fe(s));
67
Christopher Faulet386a0cd2019-07-15 21:22:44 +020068 return ((px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
Christopher Faulete6c3b692015-09-02 17:15:16 +020069}
70
71static const char *
72stream_pos(const struct stream *s)
73{
74 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
75}
76
Christopher Faulet31ed32d2016-06-21 11:42:37 +020077static const char *
78filter_type(const struct filter *f)
79{
80 return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
81}
82
Christopher Fauletfcd99f82016-10-31 11:27:21 +010083static void
Christopher Faulete0aa6f72018-11-30 22:23:32 +010084trace_hexdump(struct ist ist)
Christopher Fauletfcd99f82016-10-31 11:27:21 +010085{
Christopher Faulete0aa6f72018-11-30 22:23:32 +010086 int i, j, padding;
Christopher Fauletfcd99f82016-10-31 11:27:21 +010087
Christopher Faulete0aa6f72018-11-30 22:23:32 +010088 padding = ((ist.len % 16) ? (16 - ist.len % 16) : 0);
89 for (i = 0; i < ist.len + padding; i++) {
Christopher Fauletfcd99f82016-10-31 11:27:21 +010090 if (!(i % 16))
91 fprintf(stderr, "\t0x%06x: ", i);
92 else if (!(i % 8))
93 fprintf(stderr, " ");
94
Christopher Faulete0aa6f72018-11-30 22:23:32 +010095 if (i < ist.len)
96 fprintf(stderr, "%02x ", (unsigned char)*(ist.ptr+i));
Christopher Fauletfcd99f82016-10-31 11:27:21 +010097 else
98 fprintf(stderr, " ");
99
100 /* print ASCII dump */
101 if (i % 16 == 15) {
102 fprintf(stderr, " |");
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100103 for(j = i - 15; j <= i && j < ist.len; j++)
Willy Tarreau90807112020-02-25 08:16:33 +0100104 fprintf(stderr, "%c", (isprint((unsigned char)*(ist.ptr+j)) ? *(ist.ptr+j) : '.'));
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100105 fprintf(stderr, "|\n");
106 }
107 }
108}
109
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100110static void
Christopher Fauletb2e58492019-11-12 11:13:01 +0100111trace_raw_hexdump(struct buffer *buf, unsigned int offset, unsigned int len)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100112{
113 unsigned char p[len];
114 int block1, block2;
115
116 block1 = len;
Christopher Fauletb2e58492019-11-12 11:13:01 +0100117 if (block1 > b_contig_data(buf, offset))
118 block1 = b_contig_data(buf, offset);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100119 block2 = len - block1;
120
Christopher Fauletb2e58492019-11-12 11:13:01 +0100121 memcpy(p, b_peek(buf, offset), block1);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100122 memcpy(p+block1, b_orig(buf), block2);
123 trace_hexdump(ist2(p, len));
124}
125
126static void
127trace_htx_hexdump(struct htx *htx, unsigned int offset, unsigned int len)
128{
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100129 struct htx_blk *blk;
130
Christopher Fauletee847d42019-05-23 11:55:33 +0200131 for (blk = htx_get_first_blk(htx); blk && len; blk = htx_get_next_blk(htx, blk)) {
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100132 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Fauletee847d42019-05-23 11:55:33 +0200133 uint32_t sz = htx_get_blksz(blk);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100134 struct ist v;
135
Christopher Fauletee847d42019-05-23 11:55:33 +0200136 if (offset >= sz) {
137 offset -= sz;
138 continue;
139 }
140
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100141 v = htx_get_blk_value(htx, blk);
142 v.ptr += offset;
143 v.len -= offset;
144 offset = 0;
145
146 if (v.len > len)
147 v.len = len;
148 len -= v.len;
Christopher Faulet2d7c5392019-06-03 10:41:26 +0200149 if (type == HTX_BLK_DATA)
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100150 trace_hexdump(v);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100151 }
152}
153
Christopher Fauletb2e58492019-11-12 11:13:01 +0100154static unsigned int
155trace_get_htx_datalen(struct htx *htx, unsigned int offset, unsigned int len)
156{
157 struct htx_blk *blk;
Christopher Faulet24598a42020-02-26 22:06:11 +0100158 struct htx_ret htxret = htx_find_offset(htx, offset);
159 uint32_t data = 0;
Christopher Fauletb2e58492019-11-12 11:13:01 +0100160
Christopher Faulet24598a42020-02-26 22:06:11 +0100161 blk = htxret.blk;
162 if (blk && htxret.ret && htx_get_blk_type(blk) == HTX_BLK_DATA) {
163 data += htxret.ret;
164 blk = htx_get_next_blk(htx, blk);
165 }
166 while (blk) {
167 if (htx_get_blk_type(blk) == HTX_BLK_UNUSED)
168 goto next;
169 else if (htx_get_blk_type(blk) != HTX_BLK_DATA)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100170 break;
Christopher Faulet24598a42020-02-26 22:06:11 +0100171 data += htx_get_blksz(blk);
172 next:
173 blk = htx_get_next_blk(htx, blk);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100174 }
175 return data;
176}
177
Christopher Faulete6c3b692015-09-02 17:15:16 +0200178/***************************************************************************
179 * Hooks that manage the filter lifecycle (init/check/deinit)
180 **************************************************************************/
181/* Initialize the filter. Returns -1 on error, else 0. */
182static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100183trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200184{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100185 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200186
187 if (conf->name)
188 memprintf(&conf->name, "%s/%s", conf->name, px->id);
189 else
190 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100191
Christopher Faulet6e540952018-12-03 22:43:41 +0100192 fconf->flags |= FLT_CFG_FL_HTX;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100193 fconf->conf = conf;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100194
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100195 FLT_TRACE(conf, "filter initialized [read random=%s - fwd random=%s - hexdump=%s]",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200196 (conf->rand_parsing ? "true" : "false"),
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100197 (conf->rand_forwarding ? "true" : "false"),
198 (conf->hexdump ? "true" : "false"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200199 return 0;
200}
201
202/* Free ressources allocated by the trace filter. */
203static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100204trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200205{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100206 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200207
208 if (conf) {
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100209 FLT_TRACE(conf, "filter deinitialized");
Christopher Faulete6c3b692015-09-02 17:15:16 +0200210 free(conf->name);
211 free(conf);
212 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100213 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200214}
215
216/* Check configuration of a trace filter for a specified proxy.
217 * Return 1 on error, else 0. */
218static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100219trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200220{
221 return 0;
222}
223
Christopher Fauletf2273722017-07-27 16:58:42 +0200224/* Initialize the filter for each thread. Return -1 on error, else 0. */
225static int
226trace_init_per_thread(struct proxy *px, struct flt_conf *fconf)
227{
228 struct trace_config *conf = fconf->conf;
229
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100230 FLT_TRACE(conf, "filter initialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200231 return 0;
232}
233
234/* Free ressources allocate by the trace filter for each thread. */
235static void
236trace_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
237{
238 struct trace_config *conf = fconf->conf;
239
240 if (conf)
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100241 FLT_TRACE(conf, "filter deinitialized for thread tid %u", tid);
Christopher Fauletf2273722017-07-27 16:58:42 +0200242}
243
Christopher Faulete6c3b692015-09-02 17:15:16 +0200244/**************************************************************************
245 * Hooks to handle start/stop of streams
246 *************************************************************************/
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200247/* Called when a filter instance is created and attach to a stream */
248static int
249trace_attach(struct stream *s, struct filter *filter)
250{
251 struct trace_config *conf = FLT_CONF(filter);
252
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100253 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200254 __FUNCTION__, filter_type(filter));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100255
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200256 return 1;
257}
258
259/* Called when a filter instance is detach from a stream, just before its
260 * destruction */
261static void
262trace_detach(struct stream *s, struct filter *filter)
263{
264 struct trace_config *conf = FLT_CONF(filter);
265
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100266 FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200267 __FUNCTION__, filter_type(filter));
268}
269
Christopher Faulete6c3b692015-09-02 17:15:16 +0200270/* Called when a stream is created */
271static int
272trace_stream_start(struct stream *s, struct filter *filter)
273{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100274 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200275
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100276 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200277 __FUNCTION__);
278 return 0;
279}
280
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200281
282/* Called when a backend is set for a stream */
283static int
284trace_stream_set_backend(struct stream *s, struct filter *filter,
285 struct proxy *be)
286{
287 struct trace_config *conf = FLT_CONF(filter);
288
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100289 FLT_STRM_TRACE(conf, s, "%-25s: backend=%s",
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200290 __FUNCTION__, be->id);
291 return 0;
292}
293
Christopher Faulete6c3b692015-09-02 17:15:16 +0200294/* Called when a stream is destroyed */
295static void
296trace_stream_stop(struct stream *s, struct filter *filter)
297{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100298 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200299
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100300 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200301 __FUNCTION__);
302}
303
Christopher Fauleta00d8172016-11-10 14:58:05 +0100304/* Called when the stream is woken up because of an expired timer */
305static void
306trace_check_timeouts(struct stream *s, struct filter *filter)
307{
308 struct trace_config *conf = FLT_CONF(filter);
309
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100310 FLT_STRM_TRACE(conf, s, "%-25s",
Christopher Fauleta00d8172016-11-10 14:58:05 +0100311 __FUNCTION__);
312}
313
Christopher Faulete6c3b692015-09-02 17:15:16 +0200314/**************************************************************************
315 * Hooks to handle channels activity
316 *************************************************************************/
317/* Called when analyze starts for a given channel */
318static int
319trace_chn_start_analyze(struct stream *s, struct filter *filter,
320 struct channel *chn)
321{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100322 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200323
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100324 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200325 __FUNCTION__,
326 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200327 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
328 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100329 register_data_filter(s, chn, filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200330 return 1;
331}
332
333/* Called before a processing happens on a given channel */
334static int
335trace_chn_analyze(struct stream *s, struct filter *filter,
336 struct channel *chn, unsigned an_bit)
337{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100338 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200339 char *ana;
340
341 switch (an_bit) {
342 case AN_REQ_INSPECT_FE:
343 ana = "AN_REQ_INSPECT_FE";
344 break;
345 case AN_REQ_WAIT_HTTP:
346 ana = "AN_REQ_WAIT_HTTP";
347 break;
348 case AN_REQ_HTTP_BODY:
349 ana = "AN_REQ_HTTP_BODY";
350 break;
351 case AN_REQ_HTTP_PROCESS_FE:
352 ana = "AN_REQ_HTTP_PROCESS_FE";
353 break;
354 case AN_REQ_SWITCHING_RULES:
355 ana = "AN_REQ_SWITCHING_RULES";
356 break;
357 case AN_REQ_INSPECT_BE:
358 ana = "AN_REQ_INSPECT_BE";
359 break;
360 case AN_REQ_HTTP_PROCESS_BE:
361 ana = "AN_REQ_HTTP_PROCESS_BE";
362 break;
363 case AN_REQ_SRV_RULES:
364 ana = "AN_REQ_SRV_RULES";
365 break;
366 case AN_REQ_HTTP_INNER:
367 ana = "AN_REQ_HTTP_INNER";
368 break;
369 case AN_REQ_HTTP_TARPIT:
370 ana = "AN_REQ_HTTP_TARPIT";
371 break;
372 case AN_REQ_STICKING_RULES:
373 ana = "AN_REQ_STICKING_RULES";
374 break;
375 case AN_REQ_PRST_RDP_COOKIE:
376 ana = "AN_REQ_PRST_RDP_COOKIE";
377 break;
378 case AN_REQ_HTTP_XFER_BODY:
379 ana = "AN_REQ_HTTP_XFER_BODY";
380 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200381 case AN_RES_INSPECT:
382 ana = "AN_RES_INSPECT";
383 break;
384 case AN_RES_WAIT_HTTP:
385 ana = "AN_RES_WAIT_HTTP";
386 break;
387 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
388 ana = "AN_RES_HTTP_PROCESS_FE/BE";
389 break;
390 case AN_RES_STORE_RULES:
391 ana = "AN_RES_STORE_RULES";
392 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200393 case AN_RES_HTTP_XFER_BODY:
394 ana = "AN_RES_HTTP_XFER_BODY";
395 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200396 default:
397 ana = "unknown";
398 }
399
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100400 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200401 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200402 __FUNCTION__,
403 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200404 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200405 return 1;
406}
407
408/* Called when analyze ends for a given channel */
409static int
410trace_chn_end_analyze(struct stream *s, struct filter *filter,
411 struct channel *chn)
412{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100413 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200414
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100415 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200416 __FUNCTION__,
417 channel_label(chn), proxy_mode(s), stream_pos(s));
418 return 1;
419}
420
421/**************************************************************************
422 * Hooks to filter HTTP messages
423 *************************************************************************/
424static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200425trace_http_headers(struct stream *s, struct filter *filter,
426 struct http_msg *msg)
427{
428 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200429 struct htx *htx = htxbuf(&msg->chn->buf);
430 struct htx_sl *sl = http_get_stline(htx);
431 int32_t pos;
Christopher Faulet1339d742016-05-11 16:48:33 +0200432
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100433 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)\t%.*s %.*s %.*s",
Christopher Faulet1339d742016-05-11 16:48:33 +0200434 __FUNCTION__,
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200435 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
436 HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl),
437 HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
438 HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100439
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200440 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
441 struct htx_blk *blk = htx_get_blk(htx, pos);
442 enum htx_blk_type type = htx_get_blk_type(blk);
443 struct ist n, v;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100444
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200445 if (type == HTX_BLK_EOH)
446 break;
447 if (type != HTX_BLK_HDR)
448 continue;
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100449
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200450 n = htx_get_blk_name(htx, blk);
451 v = htx_get_blk_value(htx, blk);
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100452 FLT_STRM_TRACE(conf, s, "\t%.*s: %.*s",
Christopher Faulet386a0cd2019-07-15 21:22:44 +0200453 (int)n.len, n.ptr, (int)v.len, v.ptr);
Christopher Faulet1339d742016-05-11 16:48:33 +0200454 }
Christopher Faulet1339d742016-05-11 16:48:33 +0200455 return 1;
456}
457
458static int
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100459trace_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
460 unsigned int offset, unsigned int len)
461{
462 struct trace_config *conf = FLT_CONF(filter);
463 int ret = len;
464
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200465 if (ret && conf->rand_forwarding) {
Christopher Fauletb2e58492019-11-12 11:13:01 +0100466 unsigned int data = trace_get_htx_datalen(htxbuf(&msg->chn->buf), offset, len);
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200467
Christopher Fauletb2e58492019-11-12 11:13:01 +0100468 if (data) {
Willy Tarreau52bf8392020-03-08 00:42:37 +0100469 ret = ha_random() % (ret+1);
Christopher Faulet647fe1d2019-06-12 16:07:48 +0200470 if (!ret || ret >= data)
471 ret = len;
472 }
Christopher Faulet0bdeeaa2019-06-04 22:09:53 +0200473 }
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100474
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100475 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100476 "offset=%u - len=%u - forward=%d",
477 __FUNCTION__,
478 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
479 offset, len, ret);
480
481 if (conf->hexdump)
Christopher Fauletb2e58492019-11-12 11:13:01 +0100482 trace_htx_hexdump(htxbuf(&msg->chn->buf), offset, ret);
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100483
484 if (ret != len)
485 task_wakeup(s->task, TASK_WOKEN_MSG);
486 return ret;
487}
488
489static int
Christopher Faulete6c3b692015-09-02 17:15:16 +0200490trace_http_end(struct stream *s, struct filter *filter,
491 struct http_msg *msg)
492{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100493 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200494
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100495 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200496 __FUNCTION__,
497 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
498 return 1;
499}
500
501static void
502trace_http_reset(struct stream *s, struct filter *filter,
503 struct http_msg *msg)
504{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100505 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200506
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100507 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200508 __FUNCTION__,
509 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
510}
511
512static void
513trace_http_reply(struct stream *s, struct filter *filter, short status,
Willy Tarreau83061a82018-07-13 11:56:34 +0200514 const struct buffer *msg)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200515{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100516 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200517
Christopher Fauleta3ed2712019-11-04 11:35:42 +0100518 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200519 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
520}
521
Christopher Faulete6c3b692015-09-02 17:15:16 +0200522/**************************************************************************
523 * Hooks to filter TCP data
524 *************************************************************************/
525static int
Christopher Fauletb2e58492019-11-12 11:13:01 +0100526trace_tcp_payload(struct stream *s, struct filter *filter, struct channel *chn,
527 unsigned int offset, unsigned int len)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200528{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100529 struct trace_config *conf = FLT_CONF(filter);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100530 int ret = len;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200531
Christopher Fauletb2e58492019-11-12 11:13:01 +0100532 if (s->flags & SF_HTX) {
533 if (ret && conf->rand_forwarding) {
534 unsigned int data = trace_get_htx_datalen(htxbuf(&chn->buf), offset, len);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200535
Christopher Fauletb2e58492019-11-12 11:13:01 +0100536 if (data) {
Willy Tarreau52bf8392020-03-08 00:42:37 +0100537 ret = ha_random() % (ret+1);
Christopher Fauletb2e58492019-11-12 11:13:01 +0100538 if (!ret || ret >= data)
539 ret = len;
540 }
541 }
Christopher Faulete6c3b692015-09-02 17:15:16 +0200542
Christopher Fauletb2e58492019-11-12 11:13:01 +0100543 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
544 "offset=%u - len=%u - forward=%d",
545 __FUNCTION__,
546 channel_label(chn), proxy_mode(s), stream_pos(s),
547 offset, len, ret);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200548
Christopher Fauletb2e58492019-11-12 11:13:01 +0100549 if (conf->hexdump)
550 trace_htx_hexdump(htxbuf(&chn->buf), offset, ret);
551 }
552 else {
Christopher Faulete6c3b692015-09-02 17:15:16 +0200553
Christopher Fauletb2e58492019-11-12 11:13:01 +0100554 if (ret && conf->rand_forwarding)
Willy Tarreau52bf8392020-03-08 00:42:37 +0100555 ret = ha_random() % (ret+1);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200556
Christopher Fauletb2e58492019-11-12 11:13:01 +0100557 FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
558 "offset=%u - len=%u - forward=%d",
559 __FUNCTION__,
560 channel_label(chn), proxy_mode(s), stream_pos(s),
561 offset, len, ret);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200562
Christopher Fauletb2e58492019-11-12 11:13:01 +0100563 if (conf->hexdump)
564 trace_raw_hexdump(&chn->buf, offset, ret);
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100565 }
566
Christopher Fauletb2e58492019-11-12 11:13:01 +0100567 if (ret != len)
568 task_wakeup(s->task, TASK_WOKEN_MSG);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200569 return ret;
570}
Christopher Faulete6c3b692015-09-02 17:15:16 +0200571/********************************************************************
572 * Functions that manage the filter initialization
573 ********************************************************************/
574struct flt_ops trace_ops = {
575 /* Manage trace filter, called for each filter declaration */
Christopher Fauletf2273722017-07-27 16:58:42 +0200576 .init = trace_init,
577 .deinit = trace_deinit,
578 .check = trace_check,
579 .init_per_thread = trace_init_per_thread,
580 .deinit_per_thread = trace_deinit_per_thread,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200581
582 /* Handle start/stop of streams */
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200583 .attach = trace_attach,
584 .detach = trace_detach,
585 .stream_start = trace_stream_start,
586 .stream_set_backend = trace_stream_set_backend,
587 .stream_stop = trace_stream_stop,
Christopher Fauleta00d8172016-11-10 14:58:05 +0100588 .check_timeouts = trace_check_timeouts,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200589
590 /* Handle channels activity */
591 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200592 .channel_pre_analyze = trace_chn_analyze,
593 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200594 .channel_end_analyze = trace_chn_end_analyze,
595
596 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200597 .http_headers = trace_http_headers,
Christopher Faulete0aa6f72018-11-30 22:23:32 +0100598 .http_payload = trace_http_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200599 .http_end = trace_http_end,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200600 .http_reset = trace_http_reset,
601 .http_reply = trace_http_reply,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200602
603 /* Filter TCP data */
Christopher Fauletb2e58492019-11-12 11:13:01 +0100604 .tcp_payload = trace_tcp_payload,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200605};
606
607/* Return -1 on error, else 0 */
608static int
609parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200610 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200611{
612 struct trace_config *conf;
613 int pos = *cur_arg;
614
615 conf = calloc(1, sizeof(*conf));
616 if (!conf) {
617 memprintf(err, "%s: out of memory", args[*cur_arg]);
618 return -1;
619 }
620 conf->proxy = px;
621
622 if (!strcmp(args[pos], "trace")) {
623 pos++;
624
625 while (*args[pos]) {
626 if (!strcmp(args[pos], "name")) {
627 if (!*args[pos + 1]) {
628 memprintf(err, "'%s' : '%s' option without value",
629 args[*cur_arg], args[pos]);
630 goto error;
631 }
632 conf->name = strdup(args[pos + 1]);
633 if (!conf->name) {
634 memprintf(err, "%s: out of memory", args[*cur_arg]);
635 goto error;
636 }
637 pos++;
638 }
639 else if (!strcmp(args[pos], "random-parsing"))
640 conf->rand_parsing = 1;
641 else if (!strcmp(args[pos], "random-forwarding"))
642 conf->rand_forwarding = 1;
Christopher Fauletfcd99f82016-10-31 11:27:21 +0100643 else if (!strcmp(args[pos], "hexdump"))
644 conf->hexdump = 1;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200645 else
646 break;
647 pos++;
648 }
649 *cur_arg = pos;
Christopher Fauletf4a4ef72018-12-07 17:39:53 +0100650 fconf->id = trace_flt_id;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100651 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200652 }
653
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100654 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200655 return 0;
656
657 error:
658 if (conf->name)
659 free(conf->name);
660 free(conf);
661 return -1;
662}
663
664/* Declare the filter parser for "trace" keyword */
665static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200666 { "trace", parse_trace_flt, NULL },
667 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200668 }
669};
670
Willy Tarreau0108d902018-11-25 19:14:37 +0100671INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);