]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: filters: Add an filter example
authorChristopher Faulet <cfaulet@qualys.com>
Wed, 2 Sep 2015 15:15:16 +0000 (17:15 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 9 Feb 2016 13:53:15 +0000 (14:53 +0100)
The "trace" filter has been added. It defines all available callbacks and for
each one it prints a trace message. To enable it:

  listener test
      ...
      filter trace
      ...

Makefile
src/flt_trace.c [new file with mode: 0644]

index b38964476f0975c6cae9bb94b59f7d62e7a73f67..8087eb1576a80692817083d385f7562d87088c8b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -751,7 +751,7 @@ OBJS = src/haproxy.o src/base64.o src/protocol.o \
        src/acl.o src/sample.o src/memory.o src/freq_ctr.o src/auth.o src/proto_udp.o \
        src/compression.o src/payload.o src/hash.o src/pattern.o src/map.o \
        src/namespace.o src/mailers.o src/dns.o src/vars.o src/filters.o \
-       src/flt_http_comp.o
+       src/flt_http_comp.o src/flt_trace.o
 
 EBTREE_OBJS = $(EBTREE_DIR)/ebtree.o \
               $(EBTREE_DIR)/eb32tree.o $(EBTREE_DIR)/eb64tree.o \
diff --git a/src/flt_trace.c b/src/flt_trace.c
new file mode 100644 (file)
index 0000000..94664eb
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * Stream filters related variables and functions.
+ *
+ * Copyright (C) 2015 Qualys Inc., Christopher Faulet <cfaulet@qualys.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <common/standard.h>
+#include <common/time.h>
+#include <common/tools.h>
+
+#include <types/channel.h>
+#include <types/filters.h>
+#include <types/global.h>
+#include <types/proxy.h>
+#include <types/stream.h>
+
+#include <proto/filters.h>
+#include <proto/log.h>
+#include <proto/stream.h>
+
+struct flt_ops trace_ops;
+
+struct trace_config {
+       struct proxy *proxy;
+       char         *name;
+       int           rand_parsing;
+       int           rand_forwarding;
+};
+
+#define TRACE(conf, fmt, ...)                                          \
+       fprintf(stderr, "%d.%06d [%-20s] " fmt "\n",                    \
+               (int)now.tv_sec, (int)now.tv_usec, (conf)->name,        \
+               ##__VA_ARGS__)
+
+#define STRM_TRACE(conf, strm, fmt, ...)                               \
+       fprintf(stderr, "%d.%06d [%-20s] [strm %p(%x)] " fmt "\n",      \
+               (int)now.tv_sec, (int)now.tv_usec, (conf)->name,        \
+               strm, (strm ? ((struct stream *)strm)->uniq_id : ~0U),  \
+               ##__VA_ARGS__)
+
+
+static const char *
+channel_label(const struct channel *chn)
+{
+       return (chn->flags & CF_ISRESP) ? "RESPONSE" : "REQUEST";
+}
+
+static const char *
+proxy_mode(const struct stream *s)
+{
+       struct proxy *px = (s->flags & SF_BE_ASSIGNED ? s->be : strm_fe(s));
+
+       return (px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP";
+}
+
+static const char *
+stream_pos(const struct stream *s)
+{
+       return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
+}
+
+/***************************************************************************
+ * Hooks that manage the filter lifecycle (init/check/deinit)
+ **************************************************************************/
+/* Initialize the filter. Returns -1 on error, else 0. */
+static int
+trace_init(struct proxy *px, struct filter *filter)
+{
+       struct trace_config *conf = filter->conf;
+
+       if (conf->name)
+               memprintf(&conf->name, "%s/%s", conf->name, px->id);
+       else
+               memprintf(&conf->name, "TRACE/%s", px->id);
+       filter->conf = conf;
+       TRACE(conf, "filter initialized [read random=%s - fwd random=%s]",
+             (conf->rand_parsing ? "true" : "false"),
+             (conf->rand_forwarding ? "true" : "false"));
+       return 0;
+}
+
+/* Free ressources allocated by the trace filter. */
+static void
+trace_deinit(struct proxy *px, struct filter *filter)
+{
+       struct trace_config *conf = filter->conf;
+
+       if (conf) {
+               TRACE(conf, "filter deinitialized");
+               free(conf->name);
+               free(conf);
+       }
+       filter->conf = NULL;
+}
+
+/* Check configuration of a trace filter for a specified proxy.
+ * Return 1 on error, else 0. */
+static int
+trace_check(struct proxy *px, struct filter *filter)
+{
+       return 0;
+}
+
+/**************************************************************************
+ * Hooks to handle start/stop of streams
+ *************************************************************************/
+/* Called when a stream is created */
+static int
+trace_stream_start(struct stream *s, struct filter *filter)
+{
+       struct trace_config *conf = filter->conf;
+
+       STRM_TRACE(conf, s, "%-25s",
+                  __FUNCTION__);
+       return 0;
+}
+
+/* Called when a stream is destroyed */
+static void
+trace_stream_stop(struct stream *s, struct filter *filter)
+{
+       struct trace_config *conf = filter->conf;
+
+       STRM_TRACE(conf, s, "%-25s",
+                  __FUNCTION__);
+}
+
+/**************************************************************************
+ * Hooks to handle channels activity
+ *************************************************************************/
+/* Called when analyze starts for a given channel */
+static int
+trace_chn_start_analyze(struct stream *s, struct filter *filter,
+                       struct channel *chn)
+{
+       struct trace_config *conf = filter->conf;
+
+       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
+                  __FUNCTION__,
+                  channel_label(chn), proxy_mode(s), stream_pos(s));
+       register_data_filter(s, chn, filter);
+       return 1;
+}
+
+/* Called before a processing happens on a given channel */
+static int
+trace_chn_analyze(struct stream *s, struct filter *filter,
+                 struct channel *chn, unsigned an_bit)
+{
+       struct trace_config *conf = filter->conf;
+       char                *ana;
+
+       switch (an_bit) {
+               case AN_REQ_INSPECT_FE:
+                       ana = "AN_REQ_INSPECT_FE";
+                       break;
+               case AN_REQ_WAIT_HTTP:
+                       ana = "AN_REQ_WAIT_HTTP";
+                       break;
+               case AN_REQ_HTTP_BODY:
+                       ana = "AN_REQ_HTTP_BODY";
+                       break;
+               case AN_REQ_HTTP_PROCESS_FE:
+                       ana = "AN_REQ_HTTP_PROCESS_FE";
+                       break;
+               case AN_REQ_SWITCHING_RULES:
+                       ana = "AN_REQ_SWITCHING_RULES";
+                       break;
+               case AN_REQ_INSPECT_BE:
+                       ana = "AN_REQ_INSPECT_BE";
+                       break;
+               case AN_REQ_HTTP_PROCESS_BE:
+                       ana = "AN_REQ_HTTP_PROCESS_BE";
+                       break;
+               case AN_REQ_SRV_RULES:
+                       ana = "AN_REQ_SRV_RULES";
+                       break;
+               case AN_REQ_HTTP_INNER:
+                       ana = "AN_REQ_HTTP_INNER";
+                       break;
+               case AN_REQ_HTTP_TARPIT:
+                       ana = "AN_REQ_HTTP_TARPIT";
+                       break;
+               case AN_REQ_STICKING_RULES:
+                       ana = "AN_REQ_STICKING_RULES";
+                       break;
+               case AN_REQ_PRST_RDP_COOKIE:
+                       ana = "AN_REQ_PRST_RDP_COOKIE";
+                       break;
+               case AN_REQ_HTTP_XFER_BODY:
+                       ana = "AN_REQ_HTTP_XFER_BODY";
+                       break;
+               case AN_REQ_ALL:
+                       ana = "AN_REQ_ALL";
+                       break;
+               case AN_RES_INSPECT:
+                       ana = "AN_RES_INSPECT";
+                       break;
+               case AN_RES_WAIT_HTTP:
+                       ana = "AN_RES_WAIT_HTTP";
+                       break;
+               case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
+                       ana = "AN_RES_HTTP_PROCESS_FE/BE";
+                       break;
+               case AN_RES_STORE_RULES:
+                       ana = "AN_RES_STORE_RULES";
+                       break;
+               case AN_FLT_HTTP_HDRS:
+                       ana = "AN_FLT_HTTP_HDRS";
+                       break;
+               case AN_RES_HTTP_XFER_BODY:
+                       ana = "AN_RES_HTTP_XFER_BODY";
+                       break;
+               case AN_FLT_XFER_DATA:
+                       ana = "AN_FLT_XFER_DATA";
+                       break;
+               default:
+                       ana = "unknown";
+       }
+
+       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - analyzer=%s",
+                  __FUNCTION__,
+                  channel_label(chn), proxy_mode(s), stream_pos(s),
+                  ana);
+       return 1;
+}
+
+/* Called when analyze ends for a given channel */
+static int
+trace_chn_end_analyze(struct stream *s, struct filter *filter,
+                     struct channel *chn)
+{
+       struct trace_config *conf = filter->conf;
+
+       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
+                  __FUNCTION__,
+                  channel_label(chn), proxy_mode(s), stream_pos(s));
+       return 1;
+}
+
+/**************************************************************************
+ * Hooks to filter HTTP messages
+ *************************************************************************/
+static int
+trace_http_data(struct stream *s, struct filter *filter,
+                     struct http_msg *msg)
+{
+       struct trace_config *conf = filter->conf;
+       int avail = MIN(msg->chunk_len + msg->next, msg->chn->buf->i) - FLT_NXT(filter, msg->chn);
+       int ret   = avail;
+
+       if (ret && conf->rand_parsing)
+               ret = random() % (ret+1);
+
+       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
+                  "chunk_len=%llu - next=%u - fwd=%u - avail=%d - consume=%d",
+                  __FUNCTION__,
+                  channel_label(msg->chn), proxy_mode(s), stream_pos(s),
+                  msg->chunk_len, FLT_NXT(filter, msg->chn),
+                  FLT_FWD(filter, msg->chn), avail, ret);
+       if (ret != avail)
+               task_wakeup(s->task, TASK_WOKEN_MSG);
+       return ret;
+}
+
+static int
+trace_http_chunk_trailers(struct stream *s, struct filter *filter,
+                         struct http_msg *msg)
+{
+       struct trace_config *conf = filter->conf;
+
+       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
+                  __FUNCTION__,
+                  channel_label(msg->chn), proxy_mode(s), stream_pos(s));
+       return 1;
+}
+
+static int
+trace_http_end(struct stream *s, struct filter *filter,
+              struct http_msg *msg)
+{
+       struct trace_config *conf = filter->conf;
+
+       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
+                  __FUNCTION__,
+                  channel_label(msg->chn), proxy_mode(s), stream_pos(s));
+       return 1;
+}
+
+static void
+trace_http_reset(struct stream *s, struct filter *filter,
+                struct http_msg *msg)
+{
+       struct trace_config *conf = filter->conf;
+
+       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
+                  __FUNCTION__,
+                  channel_label(msg->chn), proxy_mode(s), stream_pos(s));
+}
+
+static void
+trace_http_reply(struct stream *s, struct filter *filter, short status,
+                const struct chunk *msg)
+{
+       struct trace_config *conf = filter->conf;
+
+       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
+                  __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
+}
+
+static int
+trace_http_forward_data(struct stream *s, struct filter *filter,
+                       struct http_msg *msg, unsigned int len)
+{
+       struct trace_config *conf = filter->conf;
+       int                  ret  = len;
+
+       if (ret && conf->rand_forwarding)
+               ret = random() % (ret+1);
+
+       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
+                  "len=%u - nxt=%u - fwd=%u - forward=%d",
+                  __FUNCTION__,
+                  channel_label(msg->chn), proxy_mode(s), stream_pos(s), len,
+                  FLT_NXT(filter, msg->chn), FLT_FWD(filter, msg->chn), ret);
+
+       if ((ret != len) ||
+           (FLT_NXT(filter, msg->chn) != FLT_FWD(filter, msg->chn) + ret))
+               task_wakeup(s->task, TASK_WOKEN_MSG);
+       return ret;
+}
+
+/**************************************************************************
+ * Hooks to filter TCP data
+ *************************************************************************/
+static int
+trace_tcp_data(struct stream *s, struct filter *filter, struct channel *chn)
+{
+       struct trace_config *conf = filter->conf;
+       int                  avail = chn->buf->i - FLT_NXT(filter, chn);
+       int                  ret  = avail;
+
+       if (ret && conf->rand_parsing)
+               ret = random() % (ret+1);
+
+       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - next=%u - avail=%u - consume=%d",
+                  __FUNCTION__,
+                  channel_label(chn), proxy_mode(s), stream_pos(s),
+                  FLT_NXT(filter, chn), avail, ret);
+
+       if (ret != avail)
+               task_wakeup(s->task, TASK_WOKEN_MSG);
+       return ret;
+}
+
+static int
+trace_tcp_forward_data(struct stream *s, struct filter *filter, struct channel *chn,
+                unsigned int len)
+{
+       struct trace_config *conf = filter->conf;
+       int                  ret  = len;
+
+       if (ret && conf->rand_forwarding)
+               ret = random() % (ret+1);
+
+       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - len=%u - fwd=%u - forward=%d",
+                  __FUNCTION__,
+                  channel_label(chn), proxy_mode(s), stream_pos(s), len,
+                  FLT_FWD(filter, chn), ret);
+
+       if (ret != len)
+               task_wakeup(s->task, TASK_WOKEN_MSG);
+       return ret;
+}
+
+/********************************************************************
+ * Functions that manage the filter initialization
+ ********************************************************************/
+struct flt_ops trace_ops = {
+       /* Manage trace filter, called for each filter declaration */
+       .init   = trace_init,
+       .deinit = trace_deinit,
+       .check  = trace_check,
+
+       /* Handle start/stop of streams */
+       .stream_start = trace_stream_start,
+       .stream_stop  = trace_stream_stop,
+
+       /* Handle channels activity */
+       .channel_start_analyze = trace_chn_start_analyze,
+       .channel_analyze       = trace_chn_analyze,
+       .channel_end_analyze   = trace_chn_end_analyze,
+
+       /* Filter HTTP requests and responses */
+       .http_data           = trace_http_data,
+       .http_chunk_trailers = trace_http_chunk_trailers,
+       .http_end            = trace_http_end,
+
+       .http_reset          = trace_http_reset,
+       .http_reply          = trace_http_reply,
+       .http_forward_data   = trace_http_forward_data,
+
+       /* Filter TCP data */
+       .tcp_data         = trace_tcp_data,
+       .tcp_forward_data = trace_tcp_forward_data,
+};
+
+/* Return -1 on error, else 0 */
+static int
+parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
+               struct filter *filter, char **err)
+{
+       struct trace_config *conf;
+       int                  pos = *cur_arg;
+
+       conf = calloc(1, sizeof(*conf));
+       if (!conf) {
+               memprintf(err, "%s: out of memory", args[*cur_arg]);
+               return -1;
+       }
+       conf->proxy = px;
+
+       if (!strcmp(args[pos], "trace")) {
+               pos++;
+
+               while (*args[pos]) {
+                       if (!strcmp(args[pos], "name")) {
+                               if (!*args[pos + 1]) {
+                                       memprintf(err, "'%s' : '%s' option without value",
+                                                 args[*cur_arg], args[pos]);
+                                       goto error;
+                               }
+                               conf->name = strdup(args[pos + 1]);
+                               if (!conf->name) {
+                                       memprintf(err, "%s: out of memory", args[*cur_arg]);
+                                       goto error;
+                               }
+                               pos++;
+                       }
+                       else if (!strcmp(args[pos], "random-parsing"))
+                               conf->rand_parsing = 1;
+                       else if (!strcmp(args[pos], "random-forwarding"))
+                               conf->rand_forwarding = 1;
+                       else
+                               break;
+                       pos++;
+               }
+               *cur_arg = pos;
+               filter->ops  = &trace_ops;
+       }
+
+       filter->conf = conf;
+       return 0;
+
+ error:
+       if (conf->name)
+               free(conf->name);
+       free(conf);
+       return -1;
+}
+
+/* Declare the filter parser for "trace" keyword */
+static struct flt_kw_list flt_kws = { "TRACE", { }, {
+               { "trace", parse_trace_flt },
+               { NULL, NULL },
+       }
+};
+
+__attribute__((constructor))
+static void
+__flt_trace_init(void)
+{
+       flt_register_keywords(&flt_kws);
+}