blob: ce3bf5ccc71b06af5db4469b4c0cc6ac6eba1196 [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
Christopher Faulet31ed32d2016-06-21 11:42:37 +020069static const char *
70filter_type(const struct filter *f)
71{
72 return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
73}
74
Christopher Faulete6c3b692015-09-02 17:15:16 +020075/***************************************************************************
76 * Hooks that manage the filter lifecycle (init/check/deinit)
77 **************************************************************************/
78/* Initialize the filter. Returns -1 on error, else 0. */
79static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +010080trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +020081{
Christopher Faulet443ea1a2016-02-04 13:40:26 +010082 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +020083
84 if (conf->name)
85 memprintf(&conf->name, "%s/%s", conf->name, px->id);
86 else
87 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulet443ea1a2016-02-04 13:40:26 +010088 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +020089 TRACE(conf, "filter initialized [read random=%s - fwd random=%s]",
90 (conf->rand_parsing ? "true" : "false"),
91 (conf->rand_forwarding ? "true" : "false"));
92 return 0;
93}
94
95/* Free ressources allocated by the trace filter. */
96static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +010097trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +020098{
Christopher Faulet443ea1a2016-02-04 13:40:26 +010099 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200100
101 if (conf) {
102 TRACE(conf, "filter deinitialized");
103 free(conf->name);
104 free(conf);
105 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100106 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200107}
108
109/* Check configuration of a trace filter for a specified proxy.
110 * Return 1 on error, else 0. */
111static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100112trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200113{
114 return 0;
115}
116
117/**************************************************************************
118 * Hooks to handle start/stop of streams
119 *************************************************************************/
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200120/* Called when a filter instance is created and attach to a stream */
121static int
122trace_attach(struct stream *s, struct filter *filter)
123{
124 struct trace_config *conf = FLT_CONF(filter);
125
126 STRM_TRACE(conf, s, "%-25s: filter-type=%s",
127 __FUNCTION__, filter_type(filter));
128 return 1;
129}
130
131/* Called when a filter instance is detach from a stream, just before its
132 * destruction */
133static void
134trace_detach(struct stream *s, struct filter *filter)
135{
136 struct trace_config *conf = FLT_CONF(filter);
137
138 STRM_TRACE(conf, s, "%-25s: filter-type=%s",
139 __FUNCTION__, filter_type(filter));
140}
141
Christopher Faulete6c3b692015-09-02 17:15:16 +0200142/* Called when a stream is created */
143static int
144trace_stream_start(struct stream *s, struct filter *filter)
145{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100146 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200147
148 STRM_TRACE(conf, s, "%-25s",
149 __FUNCTION__);
150 return 0;
151}
152
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200153
154/* Called when a backend is set for a stream */
155static int
156trace_stream_set_backend(struct stream *s, struct filter *filter,
157 struct proxy *be)
158{
159 struct trace_config *conf = FLT_CONF(filter);
160
161 STRM_TRACE(conf, s, "%-25s: backend=%s",
162 __FUNCTION__, be->id);
163 return 0;
164}
165
Christopher Faulete6c3b692015-09-02 17:15:16 +0200166/* Called when a stream is destroyed */
167static void
168trace_stream_stop(struct stream *s, struct filter *filter)
169{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100170 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200171
172 STRM_TRACE(conf, s, "%-25s",
173 __FUNCTION__);
174}
175
176/**************************************************************************
177 * Hooks to handle channels activity
178 *************************************************************************/
179/* Called when analyze starts for a given channel */
180static int
181trace_chn_start_analyze(struct stream *s, struct filter *filter,
182 struct channel *chn)
183{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100184 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200185
186 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
187 __FUNCTION__,
188 channel_label(chn), proxy_mode(s), stream_pos(s));
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200189 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
190 filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200191 return 1;
192}
193
194/* Called before a processing happens on a given channel */
195static int
196trace_chn_analyze(struct stream *s, struct filter *filter,
197 struct channel *chn, unsigned an_bit)
198{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100199 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200200 char *ana;
201
202 switch (an_bit) {
203 case AN_REQ_INSPECT_FE:
204 ana = "AN_REQ_INSPECT_FE";
205 break;
206 case AN_REQ_WAIT_HTTP:
207 ana = "AN_REQ_WAIT_HTTP";
208 break;
209 case AN_REQ_HTTP_BODY:
210 ana = "AN_REQ_HTTP_BODY";
211 break;
212 case AN_REQ_HTTP_PROCESS_FE:
213 ana = "AN_REQ_HTTP_PROCESS_FE";
214 break;
215 case AN_REQ_SWITCHING_RULES:
216 ana = "AN_REQ_SWITCHING_RULES";
217 break;
218 case AN_REQ_INSPECT_BE:
219 ana = "AN_REQ_INSPECT_BE";
220 break;
221 case AN_REQ_HTTP_PROCESS_BE:
222 ana = "AN_REQ_HTTP_PROCESS_BE";
223 break;
224 case AN_REQ_SRV_RULES:
225 ana = "AN_REQ_SRV_RULES";
226 break;
227 case AN_REQ_HTTP_INNER:
228 ana = "AN_REQ_HTTP_INNER";
229 break;
230 case AN_REQ_HTTP_TARPIT:
231 ana = "AN_REQ_HTTP_TARPIT";
232 break;
233 case AN_REQ_STICKING_RULES:
234 ana = "AN_REQ_STICKING_RULES";
235 break;
236 case AN_REQ_PRST_RDP_COOKIE:
237 ana = "AN_REQ_PRST_RDP_COOKIE";
238 break;
239 case AN_REQ_HTTP_XFER_BODY:
240 ana = "AN_REQ_HTTP_XFER_BODY";
241 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200242 case AN_RES_INSPECT:
243 ana = "AN_RES_INSPECT";
244 break;
245 case AN_RES_WAIT_HTTP:
246 ana = "AN_RES_WAIT_HTTP";
247 break;
248 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
249 ana = "AN_RES_HTTP_PROCESS_FE/BE";
250 break;
251 case AN_RES_STORE_RULES:
252 ana = "AN_RES_STORE_RULES";
253 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200254 case AN_RES_HTTP_XFER_BODY:
255 ana = "AN_RES_HTTP_XFER_BODY";
256 break;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200257 default:
258 ana = "unknown";
259 }
260
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200261 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
262 "analyzer=%s - step=%s",
Christopher Faulete6c3b692015-09-02 17:15:16 +0200263 __FUNCTION__,
264 channel_label(chn), proxy_mode(s), stream_pos(s),
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200265 ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
Christopher Faulete6c3b692015-09-02 17:15:16 +0200266 return 1;
267}
268
269/* Called when analyze ends for a given channel */
270static int
271trace_chn_end_analyze(struct stream *s, struct filter *filter,
272 struct channel *chn)
273{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100274 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200275
276 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
277 __FUNCTION__,
278 channel_label(chn), proxy_mode(s), stream_pos(s));
279 return 1;
280}
281
282/**************************************************************************
283 * Hooks to filter HTTP messages
284 *************************************************************************/
285static int
Christopher Faulet1339d742016-05-11 16:48:33 +0200286trace_http_headers(struct stream *s, struct filter *filter,
287 struct http_msg *msg)
288{
289 struct trace_config *conf = FLT_CONF(filter);
290 struct hdr_idx *hdr_idx;
291 char *cur_hdr;
292 int cur_idx;
293
294 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
295 __FUNCTION__,
296 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
297
298 STRM_TRACE(conf, s, "\t%.*s", MIN(msg->sl.rq.l, 74), msg->chn->buf->p);
299 hdr_idx = &s->txn->hdr_idx;
300 cur_idx = hdr_idx_first_idx(hdr_idx);
301 cur_hdr = msg->chn->buf->p + hdr_idx_first_pos(hdr_idx);
302 while (cur_idx) {
303 STRM_TRACE(conf, s, "\t%.*s",
304 MIN(hdr_idx->v[cur_idx].len, 74), cur_hdr);
305 cur_hdr += hdr_idx->v[cur_idx].len + hdr_idx->v[cur_idx].cr + 1;
306 cur_idx = hdr_idx->v[cur_idx].next;
307 }
308 register_data_filter(s, msg->chn, filter);
309 return 1;
310}
311
312static int
Christopher Faulete6c3b692015-09-02 17:15:16 +0200313trace_http_data(struct stream *s, struct filter *filter,
314 struct http_msg *msg)
315{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100316 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200317 int avail = MIN(msg->chunk_len + msg->next, msg->chn->buf->i) - FLT_NXT(filter, msg->chn);
318 int ret = avail;
319
320 if (ret && conf->rand_parsing)
321 ret = random() % (ret+1);
322
323 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
324 "chunk_len=%llu - next=%u - fwd=%u - avail=%d - consume=%d",
325 __FUNCTION__,
326 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
327 msg->chunk_len, FLT_NXT(filter, msg->chn),
328 FLT_FWD(filter, msg->chn), avail, ret);
329 if (ret != avail)
330 task_wakeup(s->task, TASK_WOKEN_MSG);
331 return ret;
332}
333
334static int
335trace_http_chunk_trailers(struct stream *s, struct filter *filter,
336 struct http_msg *msg)
337{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100338 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200339
340 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
341 __FUNCTION__,
342 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
343 return 1;
344}
345
346static int
347trace_http_end(struct stream *s, struct filter *filter,
348 struct http_msg *msg)
349{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100350 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200351
352 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
353 __FUNCTION__,
354 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
355 return 1;
356}
357
358static void
359trace_http_reset(struct stream *s, struct filter *filter,
360 struct http_msg *msg)
361{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100362 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200363
364 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
365 __FUNCTION__,
366 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
367}
368
369static void
370trace_http_reply(struct stream *s, struct filter *filter, short status,
371 const struct chunk *msg)
372{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100373 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200374
375 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
376 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
377}
378
379static int
380trace_http_forward_data(struct stream *s, struct filter *filter,
381 struct http_msg *msg, unsigned int len)
382{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100383 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200384 int ret = len;
385
386 if (ret && conf->rand_forwarding)
387 ret = random() % (ret+1);
388
389 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
390 "len=%u - nxt=%u - fwd=%u - forward=%d",
391 __FUNCTION__,
392 channel_label(msg->chn), proxy_mode(s), stream_pos(s), len,
393 FLT_NXT(filter, msg->chn), FLT_FWD(filter, msg->chn), ret);
394
395 if ((ret != len) ||
396 (FLT_NXT(filter, msg->chn) != FLT_FWD(filter, msg->chn) + ret))
397 task_wakeup(s->task, TASK_WOKEN_MSG);
398 return ret;
399}
400
401/**************************************************************************
402 * Hooks to filter TCP data
403 *************************************************************************/
404static int
405trace_tcp_data(struct stream *s, struct filter *filter, struct channel *chn)
406{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100407 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200408 int avail = chn->buf->i - FLT_NXT(filter, chn);
409 int ret = avail;
410
411 if (ret && conf->rand_parsing)
412 ret = random() % (ret+1);
413
414 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - next=%u - avail=%u - consume=%d",
415 __FUNCTION__,
416 channel_label(chn), proxy_mode(s), stream_pos(s),
417 FLT_NXT(filter, chn), avail, ret);
418
419 if (ret != avail)
420 task_wakeup(s->task, TASK_WOKEN_MSG);
421 return ret;
422}
423
424static int
425trace_tcp_forward_data(struct stream *s, struct filter *filter, struct channel *chn,
426 unsigned int len)
427{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100428 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200429 int ret = len;
430
431 if (ret && conf->rand_forwarding)
432 ret = random() % (ret+1);
433
434 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - len=%u - fwd=%u - forward=%d",
435 __FUNCTION__,
436 channel_label(chn), proxy_mode(s), stream_pos(s), len,
437 FLT_FWD(filter, chn), ret);
438
439 if (ret != len)
440 task_wakeup(s->task, TASK_WOKEN_MSG);
441 return ret;
442}
443
444/********************************************************************
445 * Functions that manage the filter initialization
446 ********************************************************************/
447struct flt_ops trace_ops = {
448 /* Manage trace filter, called for each filter declaration */
449 .init = trace_init,
450 .deinit = trace_deinit,
451 .check = trace_check,
452
453 /* Handle start/stop of streams */
Christopher Faulet31ed32d2016-06-21 11:42:37 +0200454 .attach = trace_attach,
455 .detach = trace_detach,
456 .stream_start = trace_stream_start,
457 .stream_set_backend = trace_stream_set_backend,
458 .stream_stop = trace_stream_stop,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200459
460 /* Handle channels activity */
461 .channel_start_analyze = trace_chn_start_analyze,
Christopher Faulet3a394fa2016-05-11 17:13:39 +0200462 .channel_pre_analyze = trace_chn_analyze,
463 .channel_post_analyze = trace_chn_analyze,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200464 .channel_end_analyze = trace_chn_end_analyze,
465
466 /* Filter HTTP requests and responses */
Christopher Faulet1339d742016-05-11 16:48:33 +0200467 .http_headers = trace_http_headers,
Christopher Faulete6c3b692015-09-02 17:15:16 +0200468 .http_data = trace_http_data,
469 .http_chunk_trailers = trace_http_chunk_trailers,
470 .http_end = trace_http_end,
471
472 .http_reset = trace_http_reset,
473 .http_reply = trace_http_reply,
474 .http_forward_data = trace_http_forward_data,
475
476 /* Filter TCP data */
477 .tcp_data = trace_tcp_data,
478 .tcp_forward_data = trace_tcp_forward_data,
479};
480
481/* Return -1 on error, else 0 */
482static int
483parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Thierry Fournier3610c392016-04-13 18:27:51 +0200484 struct flt_conf *fconf, char **err, void *private)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200485{
486 struct trace_config *conf;
487 int pos = *cur_arg;
488
489 conf = calloc(1, sizeof(*conf));
490 if (!conf) {
491 memprintf(err, "%s: out of memory", args[*cur_arg]);
492 return -1;
493 }
494 conf->proxy = px;
495
496 if (!strcmp(args[pos], "trace")) {
497 pos++;
498
499 while (*args[pos]) {
500 if (!strcmp(args[pos], "name")) {
501 if (!*args[pos + 1]) {
502 memprintf(err, "'%s' : '%s' option without value",
503 args[*cur_arg], args[pos]);
504 goto error;
505 }
506 conf->name = strdup(args[pos + 1]);
507 if (!conf->name) {
508 memprintf(err, "%s: out of memory", args[*cur_arg]);
509 goto error;
510 }
511 pos++;
512 }
513 else if (!strcmp(args[pos], "random-parsing"))
514 conf->rand_parsing = 1;
515 else if (!strcmp(args[pos], "random-forwarding"))
516 conf->rand_forwarding = 1;
517 else
518 break;
519 pos++;
520 }
521 *cur_arg = pos;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100522 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200523 }
524
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100525 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200526 return 0;
527
528 error:
529 if (conf->name)
530 free(conf->name);
531 free(conf);
532 return -1;
533}
534
535/* Declare the filter parser for "trace" keyword */
536static struct flt_kw_list flt_kws = { "TRACE", { }, {
Thierry Fournier3610c392016-04-13 18:27:51 +0200537 { "trace", parse_trace_flt, NULL },
538 { NULL, NULL, NULL },
Christopher Faulete6c3b692015-09-02 17:15:16 +0200539 }
540};
541
542__attribute__((constructor))
543static void
544__flt_trace_init(void)
545{
546 flt_register_keywords(&flt_kws);
547}