blob: a45f4a089fdeb6b3ea61638917ee4a34de2cc1cc [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>
24#include <proto/log.h>
25#include <proto/stream.h>
26
27struct flt_ops trace_ops;
28
29struct trace_config {
30 struct proxy *proxy;
31 char *name;
32 int rand_parsing;
33 int rand_forwarding;
34};
35
36#define TRACE(conf, fmt, ...) \
37 fprintf(stderr, "%d.%06d [%-20s] " fmt "\n", \
38 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
39 ##__VA_ARGS__)
40
41#define STRM_TRACE(conf, strm, fmt, ...) \
42 fprintf(stderr, "%d.%06d [%-20s] [strm %p(%x)] " fmt "\n", \
43 (int)now.tv_sec, (int)now.tv_usec, (conf)->name, \
44 strm, (strm ? ((struct stream *)strm)->uniq_id : ~0U), \
45 ##__VA_ARGS__)
46
47
48static const char *
49channel_label(const struct channel *chn)
50{
51 return (chn->flags & CF_ISRESP) ? "RESPONSE" : "REQUEST";
52}
53
54static const char *
55proxy_mode(const struct stream *s)
56{
57 struct proxy *px = (s->flags & SF_BE_ASSIGNED ? s->be : strm_fe(s));
58
59 return (px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP";
60}
61
62static const char *
63stream_pos(const struct stream *s)
64{
65 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
66}
67
68/***************************************************************************
69 * Hooks that manage the filter lifecycle (init/check/deinit)
70 **************************************************************************/
71/* Initialize the filter. Returns -1 on error, else 0. */
72static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +010073trace_init(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +020074{
Christopher Faulet443ea1a2016-02-04 13:40:26 +010075 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +020076
77 if (conf->name)
78 memprintf(&conf->name, "%s/%s", conf->name, px->id);
79 else
80 memprintf(&conf->name, "TRACE/%s", px->id);
Christopher Faulet443ea1a2016-02-04 13:40:26 +010081 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +020082 TRACE(conf, "filter initialized [read random=%s - fwd random=%s]",
83 (conf->rand_parsing ? "true" : "false"),
84 (conf->rand_forwarding ? "true" : "false"));
85 return 0;
86}
87
88/* Free ressources allocated by the trace filter. */
89static void
Christopher Faulet443ea1a2016-02-04 13:40:26 +010090trace_deinit(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +020091{
Christopher Faulet443ea1a2016-02-04 13:40:26 +010092 struct trace_config *conf = fconf->conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +020093
94 if (conf) {
95 TRACE(conf, "filter deinitialized");
96 free(conf->name);
97 free(conf);
98 }
Christopher Faulet443ea1a2016-02-04 13:40:26 +010099 fconf->conf = NULL;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200100}
101
102/* Check configuration of a trace filter for a specified proxy.
103 * Return 1 on error, else 0. */
104static int
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100105trace_check(struct proxy *px, struct flt_conf *fconf)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200106{
107 return 0;
108}
109
110/**************************************************************************
111 * Hooks to handle start/stop of streams
112 *************************************************************************/
113/* Called when a stream is created */
114static int
115trace_stream_start(struct stream *s, struct filter *filter)
116{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100117 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200118
119 STRM_TRACE(conf, s, "%-25s",
120 __FUNCTION__);
121 return 0;
122}
123
124/* Called when a stream is destroyed */
125static void
126trace_stream_stop(struct stream *s, struct filter *filter)
127{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100128 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200129
130 STRM_TRACE(conf, s, "%-25s",
131 __FUNCTION__);
132}
133
134/**************************************************************************
135 * Hooks to handle channels activity
136 *************************************************************************/
137/* Called when analyze starts for a given channel */
138static int
139trace_chn_start_analyze(struct stream *s, struct filter *filter,
140 struct channel *chn)
141{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100142 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200143
144 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
145 __FUNCTION__,
146 channel_label(chn), proxy_mode(s), stream_pos(s));
147 register_data_filter(s, chn, filter);
148 return 1;
149}
150
151/* Called before a processing happens on a given channel */
152static int
153trace_chn_analyze(struct stream *s, struct filter *filter,
154 struct channel *chn, unsigned an_bit)
155{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100156 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200157 char *ana;
158
159 switch (an_bit) {
160 case AN_REQ_INSPECT_FE:
161 ana = "AN_REQ_INSPECT_FE";
162 break;
163 case AN_REQ_WAIT_HTTP:
164 ana = "AN_REQ_WAIT_HTTP";
165 break;
166 case AN_REQ_HTTP_BODY:
167 ana = "AN_REQ_HTTP_BODY";
168 break;
169 case AN_REQ_HTTP_PROCESS_FE:
170 ana = "AN_REQ_HTTP_PROCESS_FE";
171 break;
172 case AN_REQ_SWITCHING_RULES:
173 ana = "AN_REQ_SWITCHING_RULES";
174 break;
175 case AN_REQ_INSPECT_BE:
176 ana = "AN_REQ_INSPECT_BE";
177 break;
178 case AN_REQ_HTTP_PROCESS_BE:
179 ana = "AN_REQ_HTTP_PROCESS_BE";
180 break;
181 case AN_REQ_SRV_RULES:
182 ana = "AN_REQ_SRV_RULES";
183 break;
184 case AN_REQ_HTTP_INNER:
185 ana = "AN_REQ_HTTP_INNER";
186 break;
187 case AN_REQ_HTTP_TARPIT:
188 ana = "AN_REQ_HTTP_TARPIT";
189 break;
190 case AN_REQ_STICKING_RULES:
191 ana = "AN_REQ_STICKING_RULES";
192 break;
193 case AN_REQ_PRST_RDP_COOKIE:
194 ana = "AN_REQ_PRST_RDP_COOKIE";
195 break;
196 case AN_REQ_HTTP_XFER_BODY:
197 ana = "AN_REQ_HTTP_XFER_BODY";
198 break;
199 case AN_REQ_ALL:
200 ana = "AN_REQ_ALL";
201 break;
202 case AN_RES_INSPECT:
203 ana = "AN_RES_INSPECT";
204 break;
205 case AN_RES_WAIT_HTTP:
206 ana = "AN_RES_WAIT_HTTP";
207 break;
208 case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
209 ana = "AN_RES_HTTP_PROCESS_FE/BE";
210 break;
211 case AN_RES_STORE_RULES:
212 ana = "AN_RES_STORE_RULES";
213 break;
214 case AN_FLT_HTTP_HDRS:
215 ana = "AN_FLT_HTTP_HDRS";
216 break;
217 case AN_RES_HTTP_XFER_BODY:
218 ana = "AN_RES_HTTP_XFER_BODY";
219 break;
220 case AN_FLT_XFER_DATA:
221 ana = "AN_FLT_XFER_DATA";
222 break;
223 default:
224 ana = "unknown";
225 }
226
227 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - analyzer=%s",
228 __FUNCTION__,
229 channel_label(chn), proxy_mode(s), stream_pos(s),
230 ana);
231 return 1;
232}
233
234/* Called when analyze ends for a given channel */
235static int
236trace_chn_end_analyze(struct stream *s, struct filter *filter,
237 struct channel *chn)
238{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100239 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200240
241 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
242 __FUNCTION__,
243 channel_label(chn), proxy_mode(s), stream_pos(s));
244 return 1;
245}
246
247/**************************************************************************
248 * Hooks to filter HTTP messages
249 *************************************************************************/
250static int
251trace_http_data(struct stream *s, struct filter *filter,
252 struct http_msg *msg)
253{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100254 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200255 int avail = MIN(msg->chunk_len + msg->next, msg->chn->buf->i) - FLT_NXT(filter, msg->chn);
256 int ret = avail;
257
258 if (ret && conf->rand_parsing)
259 ret = random() % (ret+1);
260
261 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
262 "chunk_len=%llu - next=%u - fwd=%u - avail=%d - consume=%d",
263 __FUNCTION__,
264 channel_label(msg->chn), proxy_mode(s), stream_pos(s),
265 msg->chunk_len, FLT_NXT(filter, msg->chn),
266 FLT_FWD(filter, msg->chn), avail, ret);
267 if (ret != avail)
268 task_wakeup(s->task, TASK_WOKEN_MSG);
269 return ret;
270}
271
272static int
273trace_http_chunk_trailers(struct stream *s, struct filter *filter,
274 struct http_msg *msg)
275{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100276 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200277
278 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
279 __FUNCTION__,
280 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
281 return 1;
282}
283
284static int
285trace_http_end(struct stream *s, struct filter *filter,
286 struct http_msg *msg)
287{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100288 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200289
290 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
291 __FUNCTION__,
292 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
293 return 1;
294}
295
296static void
297trace_http_reset(struct stream *s, struct filter *filter,
298 struct http_msg *msg)
299{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100300 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200301
302 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
303 __FUNCTION__,
304 channel_label(msg->chn), proxy_mode(s), stream_pos(s));
305}
306
307static void
308trace_http_reply(struct stream *s, struct filter *filter, short status,
309 const struct chunk *msg)
310{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100311 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200312
313 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
314 __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
315}
316
317static int
318trace_http_forward_data(struct stream *s, struct filter *filter,
319 struct http_msg *msg, unsigned int len)
320{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100321 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200322 int ret = len;
323
324 if (ret && conf->rand_forwarding)
325 ret = random() % (ret+1);
326
327 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
328 "len=%u - nxt=%u - fwd=%u - forward=%d",
329 __FUNCTION__,
330 channel_label(msg->chn), proxy_mode(s), stream_pos(s), len,
331 FLT_NXT(filter, msg->chn), FLT_FWD(filter, msg->chn), ret);
332
333 if ((ret != len) ||
334 (FLT_NXT(filter, msg->chn) != FLT_FWD(filter, msg->chn) + ret))
335 task_wakeup(s->task, TASK_WOKEN_MSG);
336 return ret;
337}
338
339/**************************************************************************
340 * Hooks to filter TCP data
341 *************************************************************************/
342static int
343trace_tcp_data(struct stream *s, struct filter *filter, struct channel *chn)
344{
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100345 struct trace_config *conf = FLT_CONF(filter);
Christopher Faulete6c3b692015-09-02 17:15:16 +0200346 int avail = chn->buf->i - FLT_NXT(filter, chn);
347 int ret = avail;
348
349 if (ret && conf->rand_parsing)
350 ret = random() % (ret+1);
351
352 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - next=%u - avail=%u - consume=%d",
353 __FUNCTION__,
354 channel_label(chn), proxy_mode(s), stream_pos(s),
355 FLT_NXT(filter, chn), avail, ret);
356
357 if (ret != avail)
358 task_wakeup(s->task, TASK_WOKEN_MSG);
359 return ret;
360}
361
362static int
363trace_tcp_forward_data(struct stream *s, struct filter *filter, struct channel *chn,
364 unsigned int len)
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 ret = len;
368
369 if (ret && conf->rand_forwarding)
370 ret = random() % (ret+1);
371
372 STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - len=%u - fwd=%u - forward=%d",
373 __FUNCTION__,
374 channel_label(chn), proxy_mode(s), stream_pos(s), len,
375 FLT_FWD(filter, chn), ret);
376
377 if (ret != len)
378 task_wakeup(s->task, TASK_WOKEN_MSG);
379 return ret;
380}
381
382/********************************************************************
383 * Functions that manage the filter initialization
384 ********************************************************************/
385struct flt_ops trace_ops = {
386 /* Manage trace filter, called for each filter declaration */
387 .init = trace_init,
388 .deinit = trace_deinit,
389 .check = trace_check,
390
391 /* Handle start/stop of streams */
392 .stream_start = trace_stream_start,
393 .stream_stop = trace_stream_stop,
394
395 /* Handle channels activity */
396 .channel_start_analyze = trace_chn_start_analyze,
397 .channel_analyze = trace_chn_analyze,
398 .channel_end_analyze = trace_chn_end_analyze,
399
400 /* Filter HTTP requests and responses */
401 .http_data = trace_http_data,
402 .http_chunk_trailers = trace_http_chunk_trailers,
403 .http_end = trace_http_end,
404
405 .http_reset = trace_http_reset,
406 .http_reply = trace_http_reply,
407 .http_forward_data = trace_http_forward_data,
408
409 /* Filter TCP data */
410 .tcp_data = trace_tcp_data,
411 .tcp_forward_data = trace_tcp_forward_data,
412};
413
414/* Return -1 on error, else 0 */
415static int
416parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100417 struct flt_conf *fconf, char **err)
Christopher Faulete6c3b692015-09-02 17:15:16 +0200418{
419 struct trace_config *conf;
420 int pos = *cur_arg;
421
422 conf = calloc(1, sizeof(*conf));
423 if (!conf) {
424 memprintf(err, "%s: out of memory", args[*cur_arg]);
425 return -1;
426 }
427 conf->proxy = px;
428
429 if (!strcmp(args[pos], "trace")) {
430 pos++;
431
432 while (*args[pos]) {
433 if (!strcmp(args[pos], "name")) {
434 if (!*args[pos + 1]) {
435 memprintf(err, "'%s' : '%s' option without value",
436 args[*cur_arg], args[pos]);
437 goto error;
438 }
439 conf->name = strdup(args[pos + 1]);
440 if (!conf->name) {
441 memprintf(err, "%s: out of memory", args[*cur_arg]);
442 goto error;
443 }
444 pos++;
445 }
446 else if (!strcmp(args[pos], "random-parsing"))
447 conf->rand_parsing = 1;
448 else if (!strcmp(args[pos], "random-forwarding"))
449 conf->rand_forwarding = 1;
450 else
451 break;
452 pos++;
453 }
454 *cur_arg = pos;
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100455 fconf->ops = &trace_ops;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200456 }
457
Christopher Faulet443ea1a2016-02-04 13:40:26 +0100458 fconf->conf = conf;
Christopher Faulete6c3b692015-09-02 17:15:16 +0200459 return 0;
460
461 error:
462 if (conf->name)
463 free(conf->name);
464 free(conf);
465 return -1;
466}
467
468/* Declare the filter parser for "trace" keyword */
469static struct flt_kw_list flt_kws = { "TRACE", { }, {
470 { "trace", parse_trace_flt },
471 { NULL, NULL },
472 }
473};
474
475__attribute__((constructor))
476static void
477__flt_trace_init(void)
478{
479 flt_register_keywords(&flt_kws);
480}