1 /*
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 <ctype.h>
14 
15 #include <common/hathreads.h>
16 #include <common/htx.h>
17 #include <common/initcall.h>
18 #include <common/standard.h>
19 #include <common/time.h>
20 #include <common/tools.h>
21 
22 #include <types/channel.h>
23 #include <types/filters.h>
24 #include <types/global.h>
25 #include <types/proxy.h>
26 #include <types/stream.h>
27 
28 #include <proto/filters.h>
29 #include <proto/http_htx.h>
30 #include <proto/log.h>
31 #include <proto/http_ana.h>
32 #include <proto/stream.h>
33 
34 const char *trace_flt_id = "trace filter";
35 
36 struct flt_ops trace_ops;
37 
38 struct trace_config {
39 	struct proxy *proxy;
40 	char         *name;
41 	int           rand_parsing;
42 	int           rand_forwarding;
43 	int           hexdump;
44 };
45 
46 #define FLT_TRACE(conf, fmt, ...)						\
47 	fprintf(stderr, "%d.%06d [%-20s] " fmt "\n",			\
48 		(int)now.tv_sec, (int)now.tv_usec, (conf)->name,	\
49 		##__VA_ARGS__)
50 
51 #define FLT_STRM_TRACE(conf, strm, fmt, ...)						\
52 	fprintf(stderr, "%d.%06d [%-20s] [strm %p(%x) 0x%08x 0x%08x] " fmt "\n",	\
53 		(int)now.tv_sec, (int)now.tv_usec, (conf)->name,			\
54 		strm, (strm ? ((struct stream *)strm)->uniq_id : ~0U),			\
55 		(strm ? strm->req.analysers : 0), (strm ? strm->res.analysers : 0),	\
56 		##__VA_ARGS__)
57 
58 
59 static const char *
channel_label(const struct channel * chn)60 channel_label(const struct channel *chn)
61 {
62 	return (chn->flags & CF_ISRESP) ? "RESPONSE" : "REQUEST";
63 }
64 
65 static const char *
proxy_mode(const struct stream * s)66 proxy_mode(const struct stream *s)
67 {
68 	struct proxy *px = (s->flags & SF_BE_ASSIGNED ? s->be : strm_fe(s));
69 
70 	return ((px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
71 }
72 
73 static const char *
stream_pos(const struct stream * s)74 stream_pos(const struct stream *s)
75 {
76 	return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
77 }
78 
79 static const char *
filter_type(const struct filter * f)80 filter_type(const struct filter *f)
81 {
82 	return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
83 }
84 
85 static void
trace_hexdump(struct ist ist)86 trace_hexdump(struct ist ist)
87 {
88 	int i, j, padding;
89 
90 	padding = ((ist.len % 16) ? (16 - ist.len % 16) : 0);
91 	for (i = 0; i < ist.len + padding; i++) {
92                 if (!(i % 16))
93                         fprintf(stderr, "\t0x%06x: ", i);
94 		else if (!(i % 8))
95                         fprintf(stderr, "  ");
96 
97                 if (i < ist.len)
98                         fprintf(stderr, "%02x ", (unsigned char)*(ist.ptr+i));
99                 else
100                         fprintf(stderr, "   ");
101 
102                 /* print ASCII dump */
103                 if (i % 16 == 15) {
104                         fprintf(stderr, "  |");
105                         for(j = i - 15; j <= i && j < ist.len; j++)
106 				fprintf(stderr, "%c", (isprint(*(ist.ptr+j)) ? *(ist.ptr+j) : '.'));
107                         fprintf(stderr, "|\n");
108                 }
109         }
110 }
111 
112 static void
trace_raw_hexdump(struct buffer * buf,unsigned int offset,unsigned int len)113 trace_raw_hexdump(struct buffer *buf, unsigned int offset, unsigned int len)
114 {
115 	unsigned char p[len];
116 	int block1, block2;
117 
118 	block1 = len;
119 	if (block1 > b_contig_data(buf, offset))
120 		block1 = b_contig_data(buf, offset);
121 	block2 = len - block1;
122 
123 	memcpy(p, b_peek(buf, offset), block1);
124 	memcpy(p+block1, b_orig(buf), block2);
125 	trace_hexdump(ist2(p, len));
126 }
127 
128 static void
trace_htx_hexdump(struct htx * htx,unsigned int offset,unsigned int len)129 trace_htx_hexdump(struct htx *htx, unsigned int offset, unsigned int len)
130 {
131 	struct htx_blk *blk;
132 
133 	for (blk = htx_get_first_blk(htx); blk && len; blk = htx_get_next_blk(htx, blk)) {
134 		enum htx_blk_type type = htx_get_blk_type(blk);
135 		uint32_t sz = htx_get_blksz(blk);
136 		struct ist v;
137 
138 		if (offset >= sz) {
139 			offset -= sz;
140 			continue;
141 		}
142 
143 		v = htx_get_blk_value(htx, blk);
144 		v.ptr += offset;
145 		v.len -= offset;
146 		offset = 0;
147 
148 		if (v.len > len)
149 			v.len = len;
150 		len -= v.len;
151 		if (type == HTX_BLK_DATA)
152 			trace_hexdump(v);
153 	}
154 }
155 
156 static unsigned int
trace_get_htx_datalen(struct htx * htx,unsigned int offset,unsigned int len)157 trace_get_htx_datalen(struct htx *htx, unsigned int offset, unsigned int len)
158 {
159 	struct htx_blk *blk;
160 	uint32_t sz, data = 0;
161 
162 	for (blk = htx_get_first_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) {
163 		if (htx_get_blk_type(blk) != HTX_BLK_DATA)
164 			break;
165 
166 		sz = htx_get_blksz(blk);
167 		if (offset >= sz) {
168 			offset -= sz;
169 			continue;
170 		}
171 		data  += sz - offset;
172 		offset = 0;
173 		if (data > len) {
174 			data = len;
175 			break;
176 		}
177 	}
178 	return data;
179 }
180 
181 /***************************************************************************
182  * Hooks that manage the filter lifecycle (init/check/deinit)
183  **************************************************************************/
184 /* Initialize the filter. Returns -1 on error, else 0. */
185 static int
trace_init(struct proxy * px,struct flt_conf * fconf)186 trace_init(struct proxy *px, struct flt_conf *fconf)
187 {
188 	struct trace_config *conf = fconf->conf;
189 
190 	if (conf->name)
191 		memprintf(&conf->name, "%s/%s", conf->name, px->id);
192 	else
193 		memprintf(&conf->name, "TRACE/%s", px->id);
194 
195 	fconf->flags |= FLT_CFG_FL_HTX;
196 	fconf->conf = conf;
197 
198 	FLT_TRACE(conf, "filter initialized [read random=%s - fwd random=%s - hexdump=%s]",
199 	      (conf->rand_parsing ? "true" : "false"),
200 	      (conf->rand_forwarding ? "true" : "false"),
201 	      (conf->hexdump ? "true" : "false"));
202 	return 0;
203 }
204 
205 /* Free ressources allocated by the trace filter. */
206 static void
trace_deinit(struct proxy * px,struct flt_conf * fconf)207 trace_deinit(struct proxy *px, struct flt_conf *fconf)
208 {
209 	struct trace_config *conf = fconf->conf;
210 
211 	if (conf) {
212 		FLT_TRACE(conf, "filter deinitialized");
213 		free(conf->name);
214 		free(conf);
215 	}
216 	fconf->conf = NULL;
217 }
218 
219 /* Check configuration of a trace filter for a specified proxy.
220  * Return 1 on error, else 0. */
221 static int
trace_check(struct proxy * px,struct flt_conf * fconf)222 trace_check(struct proxy *px, struct flt_conf *fconf)
223 {
224 	return 0;
225 }
226 
227 /* Initialize the filter for each thread. Return -1 on error, else 0. */
228 static int
trace_init_per_thread(struct proxy * px,struct flt_conf * fconf)229 trace_init_per_thread(struct proxy *px, struct flt_conf *fconf)
230 {
231 	struct trace_config *conf = fconf->conf;
232 
233 	FLT_TRACE(conf, "filter initialized for thread tid %u", tid);
234 	return 0;
235 }
236 
237 /* Free ressources allocate by the trace filter for each thread. */
238 static void
trace_deinit_per_thread(struct proxy * px,struct flt_conf * fconf)239 trace_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
240 {
241 	struct trace_config *conf = fconf->conf;
242 
243 	if (conf)
244 		FLT_TRACE(conf, "filter deinitialized for thread tid %u", tid);
245 }
246 
247 /**************************************************************************
248  * Hooks to handle start/stop of streams
249  *************************************************************************/
250 /* Called when a filter instance is created and attach to a stream */
251 static int
trace_attach(struct stream * s,struct filter * filter)252 trace_attach(struct stream *s, struct filter *filter)
253 {
254 	struct trace_config *conf = FLT_CONF(filter);
255 
256 	FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
257 		   __FUNCTION__, filter_type(filter));
258 
259 	return 1;
260 }
261 
262 /* Called when a filter instance is detach from a stream, just before its
263  * destruction */
264 static void
trace_detach(struct stream * s,struct filter * filter)265 trace_detach(struct stream *s, struct filter *filter)
266 {
267 	struct trace_config *conf = FLT_CONF(filter);
268 
269 	FLT_STRM_TRACE(conf, s, "%-25s: filter-type=%s",
270 		   __FUNCTION__, filter_type(filter));
271 }
272 
273 /* Called when a stream is created */
274 static int
trace_stream_start(struct stream * s,struct filter * filter)275 trace_stream_start(struct stream *s, struct filter *filter)
276 {
277 	struct trace_config *conf = FLT_CONF(filter);
278 
279 	FLT_STRM_TRACE(conf, s, "%-25s",
280 		   __FUNCTION__);
281 	return 0;
282 }
283 
284 
285 /* Called when a backend is set for a stream */
286 static int
trace_stream_set_backend(struct stream * s,struct filter * filter,struct proxy * be)287 trace_stream_set_backend(struct stream *s, struct filter *filter,
288 			 struct proxy *be)
289 {
290 	struct trace_config *conf = FLT_CONF(filter);
291 
292 	FLT_STRM_TRACE(conf, s, "%-25s: backend=%s",
293 		   __FUNCTION__, be->id);
294 	return 0;
295 }
296 
297 /* Called when a stream is destroyed */
298 static void
trace_stream_stop(struct stream * s,struct filter * filter)299 trace_stream_stop(struct stream *s, struct filter *filter)
300 {
301 	struct trace_config *conf = FLT_CONF(filter);
302 
303 	FLT_STRM_TRACE(conf, s, "%-25s",
304 		   __FUNCTION__);
305 }
306 
307 /* Called when the stream is woken up because of an expired timer */
308 static void
trace_check_timeouts(struct stream * s,struct filter * filter)309 trace_check_timeouts(struct stream *s, struct filter *filter)
310 {
311 	struct trace_config *conf = FLT_CONF(filter);
312 
313 	FLT_STRM_TRACE(conf, s, "%-25s",
314 		   __FUNCTION__);
315 }
316 
317 /**************************************************************************
318  * Hooks to handle channels activity
319  *************************************************************************/
320 /* Called when analyze starts for a given channel */
321 static int
trace_chn_start_analyze(struct stream * s,struct filter * filter,struct channel * chn)322 trace_chn_start_analyze(struct stream *s, struct filter *filter,
323 			struct channel *chn)
324 {
325 	struct trace_config *conf = FLT_CONF(filter);
326 
327 	FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
328 		   __FUNCTION__,
329 		   channel_label(chn), proxy_mode(s), stream_pos(s));
330 	filter->pre_analyzers  |= (AN_REQ_ALL | AN_RES_ALL);
331 	filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
332 	register_data_filter(s, chn, filter);
333 	return 1;
334 }
335 
336 /* Called before a processing happens on a given channel */
337 static int
trace_chn_analyze(struct stream * s,struct filter * filter,struct channel * chn,unsigned an_bit)338 trace_chn_analyze(struct stream *s, struct filter *filter,
339 		  struct channel *chn, unsigned an_bit)
340 {
341 	struct trace_config *conf = FLT_CONF(filter);
342 	char                *ana;
343 
344 	switch (an_bit) {
345 		case AN_REQ_INSPECT_FE:
346 			ana = "AN_REQ_INSPECT_FE";
347 			break;
348 		case AN_REQ_WAIT_HTTP:
349 			ana = "AN_REQ_WAIT_HTTP";
350 			break;
351 		case AN_REQ_HTTP_BODY:
352 			ana = "AN_REQ_HTTP_BODY";
353 			break;
354 		case AN_REQ_HTTP_PROCESS_FE:
355 			ana = "AN_REQ_HTTP_PROCESS_FE";
356 			break;
357 		case AN_REQ_SWITCHING_RULES:
358 			ana = "AN_REQ_SWITCHING_RULES";
359 			break;
360 		case AN_REQ_INSPECT_BE:
361 			ana = "AN_REQ_INSPECT_BE";
362 			break;
363 		case AN_REQ_HTTP_PROCESS_BE:
364 			ana = "AN_REQ_HTTP_PROCESS_BE";
365 			break;
366 		case AN_REQ_SRV_RULES:
367 			ana = "AN_REQ_SRV_RULES";
368 			break;
369 		case AN_REQ_HTTP_INNER:
370 			ana = "AN_REQ_HTTP_INNER";
371 			break;
372 		case AN_REQ_HTTP_TARPIT:
373 			ana = "AN_REQ_HTTP_TARPIT";
374 			break;
375 		case AN_REQ_STICKING_RULES:
376 			ana = "AN_REQ_STICKING_RULES";
377 			break;
378 		case AN_REQ_PRST_RDP_COOKIE:
379 			ana = "AN_REQ_PRST_RDP_COOKIE";
380 			break;
381 		case AN_REQ_HTTP_XFER_BODY:
382 			ana = "AN_REQ_HTTP_XFER_BODY";
383 			break;
384 		case AN_RES_INSPECT:
385 			ana = "AN_RES_INSPECT";
386 			break;
387 		case AN_RES_WAIT_HTTP:
388 			ana = "AN_RES_WAIT_HTTP";
389 			break;
390 		case AN_RES_HTTP_PROCESS_FE: // AN_RES_HTTP_PROCESS_BE
391 			ana = "AN_RES_HTTP_PROCESS_FE/BE";
392 			break;
393 		case AN_RES_STORE_RULES:
394 			ana = "AN_RES_STORE_RULES";
395 			break;
396 		case AN_RES_HTTP_XFER_BODY:
397 			ana = "AN_RES_HTTP_XFER_BODY";
398 			break;
399 		default:
400 			ana = "unknown";
401 	}
402 
403 	FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
404 		   "analyzer=%s - step=%s",
405 		   __FUNCTION__,
406 		   channel_label(chn), proxy_mode(s), stream_pos(s),
407 		   ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
408 	return 1;
409 }
410 
411 /* Called when analyze ends for a given channel */
412 static int
trace_chn_end_analyze(struct stream * s,struct filter * filter,struct channel * chn)413 trace_chn_end_analyze(struct stream *s, struct filter *filter,
414 		      struct channel *chn)
415 {
416 	struct trace_config *conf = FLT_CONF(filter);
417 
418 	FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
419 		   __FUNCTION__,
420 		   channel_label(chn), proxy_mode(s), stream_pos(s));
421 	return 1;
422 }
423 
424 /**************************************************************************
425  * Hooks to filter HTTP messages
426  *************************************************************************/
427 static int
trace_http_headers(struct stream * s,struct filter * filter,struct http_msg * msg)428 trace_http_headers(struct stream *s, struct filter *filter,
429 		   struct http_msg *msg)
430 {
431 	struct trace_config *conf = FLT_CONF(filter);
432 	struct htx *htx = htxbuf(&msg->chn->buf);
433 	struct htx_sl *sl = http_get_stline(htx);
434 	int32_t pos;
435 
436 	FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)\t%.*s %.*s %.*s",
437 		   __FUNCTION__,
438 		   channel_label(msg->chn), proxy_mode(s), stream_pos(s),
439 		   HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl),
440 		   HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
441 		   HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
442 
443 	for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
444 		struct htx_blk *blk = htx_get_blk(htx, pos);
445 		enum htx_blk_type type = htx_get_blk_type(blk);
446 		struct ist n, v;
447 
448 		if (type == HTX_BLK_EOH)
449 			break;
450 		if (type != HTX_BLK_HDR)
451 			continue;
452 
453 		n = htx_get_blk_name(htx, blk);
454 		v = htx_get_blk_value(htx, blk);
455 		FLT_STRM_TRACE(conf, s, "\t%.*s: %.*s",
456 			   (int)n.len, n.ptr, (int)v.len, v.ptr);
457 	}
458 	return 1;
459 }
460 
461 static int
trace_http_payload(struct stream * s,struct filter * filter,struct http_msg * msg,unsigned int offset,unsigned int len)462 trace_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
463 		   unsigned int offset, unsigned int len)
464 {
465 	struct trace_config *conf = FLT_CONF(filter);
466 	int ret = len;
467 
468 	if (ret && conf->rand_forwarding) {
469 		unsigned int data = trace_get_htx_datalen(htxbuf(&msg->chn->buf), offset, len);
470 
471 		if (data) {
472 			ret = ha_random() % (ret+1);
473 			if (!ret || ret >= data)
474 				ret = len;
475 		}
476 	}
477 
478 	FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
479 		   "offset=%u - len=%u - forward=%d",
480 		   __FUNCTION__,
481 		   channel_label(msg->chn), proxy_mode(s), stream_pos(s),
482 		   offset, len, ret);
483 
484 	 if (conf->hexdump)
485 		 trace_htx_hexdump(htxbuf(&msg->chn->buf), offset, ret);
486 
487 	 if (ret != len)
488 		 task_wakeup(s->task, TASK_WOKEN_MSG);
489 	return ret;
490 }
491 
492 static int
trace_http_end(struct stream * s,struct filter * filter,struct http_msg * msg)493 trace_http_end(struct stream *s, struct filter *filter,
494 	       struct http_msg *msg)
495 {
496 	struct trace_config *conf = FLT_CONF(filter);
497 
498 	FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
499 		   __FUNCTION__,
500 		   channel_label(msg->chn), proxy_mode(s), stream_pos(s));
501 	return 1;
502 }
503 
504 static void
trace_http_reset(struct stream * s,struct filter * filter,struct http_msg * msg)505 trace_http_reset(struct stream *s, struct filter *filter,
506 		 struct http_msg *msg)
507 {
508 	struct trace_config *conf = FLT_CONF(filter);
509 
510 	FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
511 		   __FUNCTION__,
512 		   channel_label(msg->chn), proxy_mode(s), stream_pos(s));
513 }
514 
515 static void
trace_http_reply(struct stream * s,struct filter * filter,short status,const struct buffer * msg)516 trace_http_reply(struct stream *s, struct filter *filter, short status,
517 		 const struct buffer *msg)
518 {
519 	struct trace_config *conf = FLT_CONF(filter);
520 
521 	FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
522 		   __FUNCTION__, "-", proxy_mode(s), stream_pos(s));
523 }
524 
525 /**************************************************************************
526  * Hooks to filter TCP data
527  *************************************************************************/
528 static int
trace_tcp_payload(struct stream * s,struct filter * filter,struct channel * chn,unsigned int offset,unsigned int len)529 trace_tcp_payload(struct stream *s, struct filter *filter, struct channel *chn,
530 		  unsigned int offset, unsigned int len)
531 {
532 	struct trace_config *conf = FLT_CONF(filter);
533 	int ret = len;
534 
535 	if (s->flags & SF_HTX) {
536 		if (ret && conf->rand_forwarding) {
537 			unsigned int data = trace_get_htx_datalen(htxbuf(&chn->buf), offset, len);
538 
539 			if (data) {
540 				ret = ha_random() % (ret+1);
541 				if (!ret || ret >= data)
542 					ret = len;
543 			}
544 		}
545 
546 		FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
547 			       "offset=%u - len=%u - forward=%d",
548 			       __FUNCTION__,
549 			       channel_label(chn), proxy_mode(s), stream_pos(s),
550 			       offset, len, ret);
551 
552 		if (conf->hexdump)
553 			trace_htx_hexdump(htxbuf(&chn->buf), offset, ret);
554 	}
555 	else {
556 
557 		if (ret && conf->rand_forwarding)
558 			ret = ha_random() % (ret+1);
559 
560 		FLT_STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
561 			       "offset=%u - len=%u - forward=%d",
562 			       __FUNCTION__,
563 			       channel_label(chn), proxy_mode(s), stream_pos(s),
564 			       offset, len, ret);
565 
566 		if (conf->hexdump)
567 			trace_raw_hexdump(&chn->buf, offset, ret);
568 	}
569 
570 	 if (ret != len)
571 		 task_wakeup(s->task, TASK_WOKEN_MSG);
572 	return ret;
573 }
574 /********************************************************************
575  * Functions that manage the filter initialization
576  ********************************************************************/
577 struct flt_ops trace_ops = {
578 	/* Manage trace filter, called for each filter declaration */
579 	.init              = trace_init,
580 	.deinit            = trace_deinit,
581 	.check             = trace_check,
582 	.init_per_thread   = trace_init_per_thread,
583 	.deinit_per_thread = trace_deinit_per_thread,
584 
585 	/* Handle start/stop of streams */
586 	.attach             = trace_attach,
587 	.detach             = trace_detach,
588 	.stream_start       = trace_stream_start,
589 	.stream_set_backend = trace_stream_set_backend,
590 	.stream_stop        = trace_stream_stop,
591 	.check_timeouts     = trace_check_timeouts,
592 
593 	/* Handle channels activity */
594 	.channel_start_analyze = trace_chn_start_analyze,
595 	.channel_pre_analyze   = trace_chn_analyze,
596 	.channel_post_analyze  = trace_chn_analyze,
597 	.channel_end_analyze   = trace_chn_end_analyze,
598 
599 	/* Filter HTTP requests and responses */
600 	.http_headers        = trace_http_headers,
601 	.http_payload        = trace_http_payload,
602 	.http_end            = trace_http_end,
603 	.http_reset          = trace_http_reset,
604 	.http_reply          = trace_http_reply,
605 
606 	/* Filter TCP data */
607 	.tcp_payload        = trace_tcp_payload,
608 };
609 
610 /* Return -1 on error, else 0 */
611 static int
parse_trace_flt(char ** args,int * cur_arg,struct proxy * px,struct flt_conf * fconf,char ** err,void * private)612 parse_trace_flt(char **args, int *cur_arg, struct proxy *px,
613                 struct flt_conf *fconf, char **err, void *private)
614 {
615 	struct trace_config *conf;
616 	int                  pos = *cur_arg;
617 
618 	conf = calloc(1, sizeof(*conf));
619 	if (!conf) {
620 		memprintf(err, "%s: out of memory", args[*cur_arg]);
621 		return -1;
622 	}
623 	conf->proxy = px;
624 
625 	if (!strcmp(args[pos], "trace")) {
626 		pos++;
627 
628 		while (*args[pos]) {
629 			if (!strcmp(args[pos], "name")) {
630 				if (!*args[pos + 1]) {
631 					memprintf(err, "'%s' : '%s' option without value",
632 						  args[*cur_arg], args[pos]);
633 					goto error;
634 				}
635 				conf->name = strdup(args[pos + 1]);
636 				if (!conf->name) {
637 					memprintf(err, "%s: out of memory", args[*cur_arg]);
638 					goto error;
639 				}
640 				pos++;
641 			}
642 			else if (!strcmp(args[pos], "random-parsing"))
643 				conf->rand_parsing = 1;
644 			else if (!strcmp(args[pos], "random-forwarding"))
645 				conf->rand_forwarding = 1;
646 			else if (!strcmp(args[pos], "hexdump"))
647 				conf->hexdump = 1;
648 			else
649 				break;
650 			pos++;
651 		}
652 		*cur_arg = pos;
653 		fconf->id   = trace_flt_id;
654 		fconf->ops  = &trace_ops;
655 	}
656 
657 	fconf->conf = conf;
658 	return 0;
659 
660  error:
661 	if (conf->name)
662 		free(conf->name);
663 	free(conf);
664 	return -1;
665 }
666 
667 /* Declare the filter parser for "trace" keyword */
668 static struct flt_kw_list flt_kws = { "TRACE", { }, {
669 		{ "trace", parse_trace_flt, NULL },
670 		{ NULL, NULL, NULL },
671 	}
672 };
673 
674 INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);
675