blob: a052ab59bad98d55bd1715a67f47ebff5ebe9506 [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
13#include <common/standard.h>
14#include <common/time.h>
15#include <common/tools.h>
16
17#include <types/channel.h>
18#include <types/filters.h>
19#include <types/global.h>
20#include <types/proxy.h>
21#include <types/stream.h>
22
23#include <proto/filters.h>
Christopher Faulet1339d742016-05-11 16:48:33 +020024#include <proto/hdr_idx.h>
Christopher Faulete6c3b692015-09-02 17:15:16 +020025#include <proto/log.h>
26#include <proto/stream.h>
27
28struct flt_ops trace_ops;
29
30struct trace_config {
31 struct proxy *proxy;
32 char *name;
33 int rand_parsing;
34 int rand_forwarding;
35};
36
37#define TRACE(conf, fmt, ...) \
38 fprintf(stderr, "%d.%06d [%-20s] " fmt "\n", \
39 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
40 ##__VA_ARGS__)
41
42#define STRM_TRACE(conf, strm, fmt, ...) \
43 fprintf(stderr, "%d.%06d [%-20s] [strm %p(%x)] " fmt "\n", \
44 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
45 strm, (strm ? ((struct stream *)strm)->uniq_id : ~0U), \
46 ##__VA_ARGS__)
47
48
49static const char *
50channel_label(const struct channel *chn)
51{
52 return (chn->flags & CF_ISRESP) ? "RESPONSE" : "REQUEST";
53}
54
55static const char *
56proxy_mode(const struct stream *s)
57{
58 struct proxy *px = (s->flags & SF_BE_ASSIGNED ? s->be : strm_fe(s));
59
60 return (px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP";
61}
62
63static const char *
64stream_pos(const struct stream *s)
65{
66 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
67}
68
69/***************************************************************************
70 * Hooks that manage the filter lifecycle (init/check/deinit)
71 **************************************************************************/
72/* Initialize the filter. Returns -1 on error, else 0. */
73static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +010074trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +020075{
Christopher Faulet443ea1a2016-02-04 13:40:26 +010076 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +020077
78 if (conf->name)
79 memprintf(&conf->name, "%s/%s", conf->name, px->id);
80 else
81 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulet443ea1a2016-02-04 13:40:26 +010082 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +020083 TRACE(conf, "filter initialized [read random=%s - fwd random=%s]",
84 (conf->rand_parsing ? "true" : "false"),
85 (conf->rand_forwarding ? "true" : "false"));
86 return 0;
87}
88
89/* Free ressources allocated by the trace filter. */
90static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +010091trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +020092{
Christopher Faulet443ea1a2016-02-04 13:40:26 +010093 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +020094
95 if (conf) {
96 TRACE(conf, "filter deinitialized");
97 free(conf->name);
98 free(conf);
99 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100100 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200101}
102
103/* Check configuration of a trace filter for a specified proxy.
104 * Return 1 on error, else 0. */
105static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100106trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200107{
108 return 0;
109}
110
111/**************************************************************************
112 * Hooks to handle start/stop of streams
113 *************************************************************************/
114/* Called when a stream is created */
115static int
116trace_stream_start(struct stream *s, struct filter *filter)
117{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100118 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200119
120 STRM_TRACE(conf, s, "%-25s",
121 __FUNCTION__);
122 return 0;
123}
124
125/* Called when a stream is destroyed */
126static void
127trace_stream_stop(struct stream *s, struct filter *filter)
128{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100129 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200130
131 STRM_TRACE(conf, s, "%-25s",
132 __FUNCTION__);
133}
134
135/**************************************************************************
136 * Hooks to handle channels activity
137 *************************************************************************/
138/* Called when analyze starts for a given channel */
139static int
140trace_chn_start_analyze(struct stream *s, struct filter *filter,
141 struct channel *chn)
142{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100143 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200144
145 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
146 __FUNCTION__,
147 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200148 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
149 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200150 return 1;
151}
152
153/* Called before a processing happens on a given channel */
154static int
155trace_chn_analyze(struct stream *s, struct filter *filter,
156 struct channel *chn, unsigned an_bit)
157{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100158 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200159 char *ana;
160
161 switch (an_bit) {
162 case AN_REQ_INSPECT_FE:
163 ana = "AN_REQ_INSPECT_FE";
164 break;
165 case AN_REQ_WAIT_HTTP:
166 ana = "AN_REQ_WAIT_HTTP";
167 break;
168 case AN_REQ_HTTP_BODY:
169 ana = "AN_REQ_HTTP_BODY";
170 break;
171 case AN_REQ_HTTP_PROCESS_FE:
172 ana = "AN_REQ_HTTP_PROCESS_FE";
173 break;
174 case AN_REQ_SWITCHING_RULES:
175 ana = "AN_REQ_SWITCHING_RULES";
176 break;
177 case AN_REQ_INSPECT_BE:
178 ana = "AN_REQ_INSPECT_BE";
179 break;
180 case AN_REQ_HTTP_PROCESS_BE:
181 ana = "AN_REQ_HTTP_PROCESS_BE";
182 break;
183 case AN_REQ_SRV_RULES:
184 ana = "AN_REQ_SRV_RULES";
185 break;
186 case AN_REQ_HTTP_INNER:
187 ana = "AN_REQ_HTTP_INNER";
188 break;
189 case AN_REQ_HTTP_TARPIT:
190 ana = "AN_REQ_HTTP_TARPIT";
191 break;
192 case AN_REQ_STICKING_RULES:
193 ana = "AN_REQ_STICKING_RULES";
194 break;
195 case AN_REQ_PRST_RDP_COOKIE:
196 ana = "AN_REQ_PRST_RDP_COOKIE";
197 break;
198 case AN_REQ_HTTP_XFER_BODY:
199 ana = "AN_REQ_HTTP_XFER_BODY";
200 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200201 case AN_RES_INSPECT:
202 ana = "AN_RES_INSPECT";
203 break;
204 case AN_RES_WAIT_HTTP:
205 ana = "AN_RES_WAIT_HTTP";
206 break;
207 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
208 ana = "AN_RES_HTTP_PROCESS_FE/BE";
209 break;
210 case AN_RES_STORE_RULES:
211 ana = "AN_RES_STORE_RULES";
212 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200213 case AN_RES_HTTP_XFER_BODY:
214 ana = "AN_RES_HTTP_XFER_BODY";
215 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200216 default:
217 ana = "unknown";
218 }
219
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200220 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
221 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200222 __FUNCTION__,
223 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200224 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200225 return 1;
226}
227
228/* Called when analyze ends for a given channel */
229static int
230trace_chn_end_analyze(struct stream *s, struct filter *filter,
231 struct channel *chn)
232{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100233 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200234
235 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
236 __FUNCTION__,
237 channel_label(chn), proxy_mode(s), stream_pos(s));
238 return 1;
239}
240
241/**************************************************************************
242 * Hooks to filter HTTP messages
243 *************************************************************************/
244static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200245trace_http_headers(struct stream *s, struct filter *filter,
246 struct http_msg *msg)
247{
248 struct trace_config *conf = FLT_CONF(filter);
249 struct hdr_idx *hdr_idx;
250 char *cur_hdr;
251 int cur_idx;
252
253 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
254 __FUNCTION__,
255 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
256
257 STRM_TRACE(conf, s, "\t%.*s", MIN(msg->sl.rq.l, 74), msg->chn->buf->p);
258 hdr_idx = &s->txn->hdr_idx;
259 cur_idx = hdr_idx_first_idx(hdr_idx);
260 cur_hdr = msg->chn->buf->p + hdr_idx_first_pos(hdr_idx);
261 while (cur_idx) {
262 STRM_TRACE(conf, s, "\t%.*s",
263 MIN(hdr_idx->v[cur_idx].len, 74), cur_hdr);
264 cur_hdr += hdr_idx->v[cur_idx].len + hdr_idx->v[cur_idx].cr + 1;
265 cur_idx = hdr_idx->v[cur_idx].next;
266 }
267 register_data_filter(s, msg->chn, filter);
268 return 1;
269}
270
271static int
Christopher Faulete6c3b692015-09-02 17:15:16 +0200272trace_http_data(struct stream *s, struct filter *filter,
273 struct http_msg *msg)
274{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100275 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200276 int avail = MIN(msg->chunk_len + msg->next, msg->chn->buf->i) - FLT_NXT(filter, msg->chn);
277 int ret = avail;
278
279 if (ret && conf->rand_parsing)
280 ret = random() % (ret+1);
281
282 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
283 "chunk_len=%llu - next=%u - fwd=%u - avail=%d - consume=%d",
284 __FUNCTION__,
285 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
286 msg->chunk_len, FLT_NXT(filter, msg->chn),
287 FLT_FWD(filter, msg->chn), avail, ret);
288 if (ret != avail)
289 task_wakeup(s->task, TASK_WOKEN_MSG);
290 return ret;
291}
292
293static int
294trace_http_chunk_trailers(struct stream *s, struct filter *filter,
295 struct http_msg *msg)
296{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100297 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200298
299 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
300 __FUNCTION__,
301 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
302 return 1;
303}
304
305static int
306trace_http_end(struct stream *s, struct filter *filter,
307 struct http_msg *msg)
308{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100309 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200310
311 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
312 __FUNCTION__,
313 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
314 return 1;
315}
316
317static void
318trace_http_reset(struct stream *s, struct filter *filter,
319 struct http_msg *msg)
320{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100321 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200322
323 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
324 __FUNCTION__,
325 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
326}
327
328static void
329trace_http_reply(struct stream *s, struct filter *filter, short status,
330 const struct chunk *msg)
331{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100332 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200333
334 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
335 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
336}
337
338static int
339trace_http_forward_data(struct stream *s, struct filter *filter,
340 struct http_msg *msg, unsigned int len)
341{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100342 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200343 int ret = len;
344
345 if (ret && conf->rand_forwarding)
346 ret = random() % (ret+1);
347
348 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
349 "len=%u - nxt=%u - fwd=%u - forward=%d",
350 __FUNCTION__,
351 channel_label(msg->chn), proxy_mode(s), stream_pos(s), len,
352 FLT_NXT(filter, msg->chn), FLT_FWD(filter, msg->chn), ret);
353
354 if ((ret != len) ||
355 (FLT_NXT(filter, msg->chn) != FLT_FWD(filter, msg->chn) + ret))
356 task_wakeup(s->task, TASK_WOKEN_MSG);
357 return ret;
358}
359
360/**************************************************************************
361 * Hooks to filter TCP data
362 *************************************************************************/
363static int
364trace_tcp_data(struct stream *s, struct filter *filter, struct channel *chn)
365{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100366 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200367 int avail = chn->buf->i - FLT_NXT(filter, chn);
368 int ret = avail;
369
370 if (ret && conf->rand_parsing)
371 ret = random() % (ret+1);
372
373 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - next=%u - avail=%u - consume=%d",
374 __FUNCTION__,
375 channel_label(chn), proxy_mode(s), stream_pos(s),
376 FLT_NXT(filter, chn), avail, ret);
377
378 if (ret != avail)
379 task_wakeup(s->task, TASK_WOKEN_MSG);
380 return ret;
381}
382
383static int
384trace_tcp_forward_data(struct stream *s, struct filter *filter, struct channel *chn,
385 unsigned int len)
386{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100387 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200388 int ret = len;
389
390 if (ret && conf->rand_forwarding)
391 ret = random() % (ret+1);
392
393 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - len=%u - fwd=%u - forward=%d",
394 __FUNCTION__,
395 channel_label(chn), proxy_mode(s), stream_pos(s), len,
396 FLT_FWD(filter, chn), ret);
397
398 if (ret != len)
399 task_wakeup(s->task, TASK_WOKEN_MSG);
400 return ret;
401}
402
403/********************************************************************
404 * Functions that manage the filter initialization
405 ********************************************************************/
406struct flt_ops trace_ops = {
407 /* Manage trace filter, called for each filter declaration */
408 .init = trace_init,
409 .deinit = trace_deinit,
410 .check = trace_check,
411
412 /* Handle start/stop of streams */
413 .stream_start = trace_stream_start,
414 .stream_stop = trace_stream_stop,
415
416 /* Handle channels activity */
417 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200418 .channel_pre_analyze = trace_chn_analyze,
419 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200420 .channel_end_analyze = trace_chn_end_analyze,
421
422 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200423 .http_headers = trace_http_headers,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200424 .http_data = trace_http_data,
425 .http_chunk_trailers = trace_http_chunk_trailers,
426 .http_end = trace_http_end,
427
428 .http_reset = trace_http_reset,
429 .http_reply = trace_http_reply,
430 .http_forward_data = trace_http_forward_data,
431
432 /* Filter TCP data */
433 .tcp_data = trace_tcp_data,
434 .tcp_forward_data = trace_tcp_forward_data,
435};
436
437/* Return -1 on error, else 0 */
438static int
439parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200440 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200441{
442 struct trace_config *conf;
443 int pos = *cur_arg;
444
445 conf = calloc(1, sizeof(*conf));
446 if (!conf) {
447 memprintf(err, "%s: out of memory", args[*cur_arg]);
448 return -1;
449 }
450 conf->proxy = px;
451
452 if (!strcmp(args[pos], "trace")) {
453 pos++;
454
455 while (*args[pos]) {
456 if (!strcmp(args[pos], "name")) {
457 if (!*args[pos + 1]) {
458 memprintf(err, "'%s' : '%s' option without value",
459 args[*cur_arg], args[pos]);
460 goto error;
461 }
462 conf->name = strdup(args[pos + 1]);
463 if (!conf->name) {
464 memprintf(err, "%s: out of memory", args[*cur_arg]);
465 goto error;
466 }
467 pos++;
468 }
469 else if (!strcmp(args[pos], "random-parsing"))
470 conf->rand_parsing = 1;
471 else if (!strcmp(args[pos], "random-forwarding"))
472 conf->rand_forwarding = 1;
473 else
474 break;
475 pos++;
476 }
477 *cur_arg = pos;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100478 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200479 }
480
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100481 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200482 return 0;
483
484 error:
485 if (conf->name)
486 free(conf->name);
487 free(conf);
488 return -1;
489}
490
491/* Declare the filter parser for "trace" keyword */
492static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200493 { "trace", parse_trace_flt, NULL },
494 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200495 }
496};
497
498__attribute__((constructor))
499static void
500__flt_trace_init(void)
501{
502 flt_register_keywords(&flt_kws);
503}