Browse Source

Merge pull request #1006 from giavac/master

Add HEPv3 support to siptrace
Giacomo Vacca 8 years ago
parent
commit
103e503fa5

+ 47 - 0
src/modules/sipcapture/hep.h

@@ -177,5 +177,52 @@ struct hep_generic_recv {
 
 
 typedef struct hep_generic_recv hep_generic_recv_t;
 typedef struct hep_generic_recv hep_generic_recv_t;
 
 
+#define HEP3_PACK_INIT(buf) \
+		union { \
+			hep_chunk_uint8_t chunk8; \
+			hep_chunk_uint16_t chunk16; \
+			hep_chunk_uint32_t chunk32; \
+			hep_chunk_t chunkpl; \
+			uint16_t len; \
+		} _tmpu; \
+		char *_tmp_p = (buf); \
+		memcpy(_tmp_p, "HEP3", 4); \
+		_tmp_p += 4 + 2/* skip length */;
+
+#define HEP3_PACK_FINALIZE(buf, lenp) \
+		do { \
+			_tmpu.len = htons(_tmp_p - (char *)(buf)); \
+			memcpy((void *)(&(((hep_ctrl_t *)(buf))->length)), (void*)&_tmpu.len, 2); \
+			*lenp = _tmp_p - (char *)(buf); \
+		} while (0)
+
+#define _HEP3_PACK_CHUNK_GENERIC(type, tmpvar, vid, tid, val) \
+		do { \
+			(tmpvar).chunk.vendor_id = htons(vid); \
+			(tmpvar).chunk.type_id = htons(tid); \
+			(tmpvar).chunk.length = htons(sizeof(type)); \
+			(tmpvar).data = (val); \
+			memcpy(_tmp_p, (void *) &(tmpvar), sizeof(type)); \
+			_tmp_p += sizeof(type); \
+		} while (0)
+
+#define HEP3_PACK_CHUNK_UINT8(vid, tid, val) _HEP3_PACK_CHUNK_GENERIC(hep_chunk_uint8_t, _tmpu.chunk8, vid, tid, val)
+#define HEP3_PACK_CHUNK_UINT16(vid, tid, val) _HEP3_PACK_CHUNK_GENERIC(hep_chunk_uint16_t, _tmpu.chunk16, vid, tid, htons(val))
+#define HEP3_PACK_CHUNK_UINT16_NBO(vid, tid, val) _HEP3_PACK_CHUNK_GENERIC(hep_chunk_uint16_t, _tmpu.chunk16, vid, tid, (val))
+#define HEP3_PACK_CHUNK_UINT32(vid, tid, val) _HEP3_PACK_CHUNK_GENERIC(hep_chunk_uint32_t, _tmpu.chunk32, vid, tid, htonl(val))
+#define HEP3_PACK_CHUNK_UINT32_NBO(vid, tid, val) _HEP3_PACK_CHUNK_GENERIC(hep_chunk_uint32_t, _tmpu.chunk32, vid, tid, (val))
+
+#define HEP3_PACK_CHUNK_DATA(vid, tid, val, len) \
+		do { \
+			_tmpu.chunkpl.vendor_id = htons(vid); \
+			_tmpu.chunkpl.type_id = htons(tid); \
+			_tmpu.chunkpl.length = htons(sizeof(hep_chunk_t) + (len)); \
+			memcpy(_tmp_p, (void *) &_tmpu.chunkpl, sizeof(hep_chunk_t)); \
+			_tmp_p += sizeof(hep_chunk_t); \
+			memcpy(_tmp_p, (void *) (val), len); \
+			_tmp_p += len; \
+		} while (0)
+
+#define HEP3_PACK_CHUNK_IP6(vid, tid, paddr) HEP3_PACK_CHUNK_DATA(vid, tid, paddr, sizeof(struct in6_addr))
 
 
 #endif
 #endif

+ 5 - 0
src/modules/siptrace/doc/siptrace.xml

@@ -28,6 +28,11 @@
 		<surname>Mierla</surname>
 		<surname>Mierla</surname>
 		    <email>[email protected]</email>
 		    <email>[email protected]</email>
 	    </editor>
 	    </editor>
+	<editor>
+		<firstname>Giacomo</firstname>
+		<surname>Vacca</surname>
+		<email>[email protected]</email>
+	</editor>
 	</authorgroup>
 	</authorgroup>
 	<copyright>
 	<copyright>
 	    <year>2010</year>
 	    <year>2010</year>

+ 42 - 18
src/modules/siptrace/doc/siptrace_admin.xml

@@ -17,8 +17,8 @@
 	<title>Overview</title>
 	<title>Overview</title>
 	<para>
 	<para>
 		The SIPtrace module offer a possibility to store incoming and outgoing SIP
 		The SIPtrace module offer a possibility to store incoming and outgoing SIP
-		messages in a database and/or duplicate to the capturing server (using <acronym>HEP</acronym>
-		the Homer encapsulation protocol or plain SIP mode)
+		messages in a database and/or duplicate to the capturing server (using <acronym>HEP</acronym>,
+		the Homer encapsulation protocol, or plain SIP mode)
 	</para>
 	</para>
 	<para>
 	<para>
 		There are two ways of storing information:
 		There are two ways of storing information:
@@ -42,8 +42,7 @@
 	</para>
 	</para>
 
 
 	<para>
 	<para>
-	The tracing can be turned on/off using Kamailio <acronym>mi</acronym> or <acronym>RPC</acronym>
-	commands.
+	The tracing can be turned on/off using Kamailio <acronym>RPC</acronym> commands.
 	</para>
 	</para>
 	<para>
 	<para>
 	&ctltool; fifo sip_trace on
 	&ctltool; fifo sip_trace on
@@ -57,12 +56,12 @@
 	<section>
 	<section>
 		<title>&kamailio; Modules</title>
 		<title>&kamailio; Modules</title>
 		<para>
 		<para>
-		The following modules must be loaded before this module:
+		The following modules must be conditionally loaded before this module:
 			<itemizedlist>
 			<itemizedlist>
 			<listitem>
 			<listitem>
 			<para>
 			<para>
 				<emphasis>A database module</emphasis> - Mysql, Postgres,
 				<emphasis>A database module</emphasis> - Mysql, Postgres,
-				dbtext, unixODBC...
+				dbtext, unixODBC... Optional, if tracing to DB is enabled.
 			</para>
 			</para>
 			</listitem>
 			</listitem>
 			<listitem>
 			<listitem>
@@ -199,7 +198,7 @@ modparam("siptrace", "traced_user_avp", "$avp(s:user)")
 		store the SIP messages. If it is not set, the value of
 		store the SIP messages. If it is not set, the value of
 		<quote>table</quote> parameter is used. In this way one can select
 		<quote>table</quote> parameter is used. In this way one can select
 		dynamically where to store the traced messages. The table
 		dynamically where to store the traced messages. The table
-		must exists, and must have the same structure as the <quote>sip_trace</quote>
+		must exist, and must have the same structure as the <quote>sip_trace</quote>
 		table.
 		table.
 		</para>
 		</para>
 		<para>
 		<para>
@@ -395,8 +394,9 @@ modparam("siptrace", "hep_mode_on", 1)
                 <title><varname>hep_version</varname> (integer)</title>
                 <title><varname>hep_version</varname> (integer)</title>
                 <para>
                 <para>
                 The parameter indicate the version of the HEP protocol.
                 The parameter indicate the version of the HEP protocol.
-                Can be <quote>1</quote> or <quote>2</quote>. In HEPv2 the timestamp and capture agent ID
-                will be included to HEP header.
+                Can be <quote>1</quote>, <quote>2</quote> or <quote>3</quote>.
+                In HEPv2 and HEPv3 the timestamp and capture agent ID will be
+                included in the HEP header.
                 </para>
                 </para>
                 <para>
                 <para>
                 <emphasis>
                 <emphasis>
@@ -407,7 +407,7 @@ modparam("siptrace", "hep_mode_on", 1)
                 <title>Set <varname>hep_version</varname> parameter</title>
                 <title>Set <varname>hep_version</varname> parameter</title>
                 <programlisting format="linespecific">
                 <programlisting format="linespecific">
 ...
 ...
-modparam("siptrace", "hep_version", 2)
+modparam("siptrace", "hep_version", 3)
 ...
 ...
 </programlisting>
 </programlisting>
                 </example>
                 </example>
@@ -416,8 +416,8 @@ modparam("siptrace", "hep_version", 2)
                 <title><varname>hep_capture_id</varname> (integer)</title>
                 <title><varname>hep_capture_id</varname> (integer)</title>
                 <para>
                 <para>
                 The parameter indicate the capture agent ID for the <acronym>HEPv2</acronym>
                 The parameter indicate the capture agent ID for the <acronym>HEPv2</acronym>
-                protocol.
-                Limitation: 16-bit integer.
+                or <acronym>HEPv3</acronym> protocol.
+                Limitation: 16-bit integer for HEPv2, 32-bit for HEPv3.
                 </para>
                 </para>
                 <para>
                 <para>
                 <emphasis>
                 <emphasis>
@@ -425,8 +425,7 @@ modparam("siptrace", "hep_version", 2)
                 </emphasis>
                 </emphasis>
                 </para>
                 </para>
                 <example>
                 <example>
-                <title>Set <varname>hep_capture_id</varname>
-                parameter</title>
+                <title>Set <varname>hep_capture_id</varname> parameter</title>
                 <programlisting format="linespecific">
                 <programlisting format="linespecific">
 ...
 ...
 modparam("siptrace", "hep_capture_id", 234)
 modparam("siptrace", "hep_capture_id", 234)
@@ -456,7 +455,7 @@ modparam("siptrace", "trace_delayed", 1)
 	<section id="siptrace.p.force_send_sock">
 	<section id="siptrace.p.force_send_sock">
                 <title><varname>force_send_sock</varname> (str)</title>
                 <title><varname>force_send_sock</varname> (str)</title>
                 <para>
                 <para>
-			The local interface in the form of SIP uri from where to send
+			The local interface in the form of SIP URI from where to send
 			the duplicated traffic. In the absence of this parameter
 			the duplicated traffic. In the absence of this parameter
 			&kamailio; automatically picks an interface.
 			&kamailio; automatically picks an interface.
                 </para>
                 </para>
@@ -490,6 +489,25 @@ modparam("siptrace", "force_send_sock", "sip:10.1.1.2:5000")
 ...
 ...
 modparam("siptrace", "trace_mode", 1)
 modparam("siptrace", "trace_mode", 1)
 ...
 ...
+</programlisting>
+                </example>
+        </section>
+	<section id="siptrace.p.auth_key">
+                <title><varname>auth_key</varname> (integer)</title>
+                <para>
+A string with an authorization key.
+Supported on HEPv3 only.
+                </para>
+                <para>
+                Default value is empty.
+                </para>
+                <example>
+                <title>Set <varname>auth_key</varname>
+                parameter</title>
+                <programlisting format="linespecific">
+...
+modparam("siptrace", "auth_key", "spoihepuirthpeuia")
+...
 </programlisting>
 </programlisting>
                 </example>
                 </example>
         </section>
         </section>
@@ -499,7 +517,7 @@ modparam("siptrace", "trace_mode", 1)
 	<title>Functions</title>
 	<title>Functions</title>
 	<section id="siptrace.f.sip_trace">
 	<section id="siptrace.f.sip_trace">
 		<title>
 		<title>
-		<function moreinfo="none">sip_trace([address])</function>
+		<function moreinfo="none">sip_trace([address][, correlation_id])</function>
 		</title>
 		</title>
 		<para>
 		<para>
 		Store or forward the current processed SIP message in database. It is stored in the
 		Store or forward the current processed SIP message in database. It is stored in the
@@ -508,10 +526,14 @@ modparam("siptrace", "trace_mode", 1)
 		<para>Meaning of the parameters is as follows:</para>
 		<para>Meaning of the parameters is as follows:</para>
 		<itemizedlist>
 		<itemizedlist>
 		<listitem>
 		<listitem>
-		<para><emphasis>address</emphasis> - The address in form of SIP uri
+		<para><emphasis>address</emphasis> - The address in form of SIP URI
 		where to send a duplicate of traced message. This parameter trumps
 		where to send a duplicate of traced message. This parameter trumps
 		duplicate_uri and allows tracing to more than one server.
 		duplicate_uri and allows tracing to more than one server.
 		</para>
 		</para>
+		<para><emphasis>correlation_id</emphasis> - A string with a correlation ID
+		to be added to the HEP header when using HEPv3.
+		It's possible to use PVs.
+		</para>
 		</listitem>
 		</listitem>
 		</itemizedlist>
 		</itemizedlist>
 		<para>
 		<para>
@@ -529,6 +551,8 @@ sip_trace();
 ...
 ...
 sip_trace("sip:10.1.1.2:5085");
 sip_trace("sip:10.1.1.2:5085");
 ...
 ...
+sip_trace("sip:10.1.1.2:5085", "$ci-abc");
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
@@ -549,7 +573,7 @@ sip_trace("sip:10.1.1.2:5085");
 		</para>
 		</para>
 		<para>Parameters: </para>
 		<para>Parameters: </para>
 		<itemizedlist>
 		<itemizedlist>
-			<listitem><para>on or off: turns on/off SIP message tracing..
+			<listitem><para>on or off: turns on/off SIP message tracing.
 			Possible values are:</para>
 			Possible values are:</para>
 			<itemizedlist>
 			<itemizedlist>
 				<listitem><para>on</para></listitem>
 				<listitem><para>on</para></listitem>

+ 291 - 30
src/modules/siptrace/siptrace.c

@@ -33,6 +33,7 @@
 #include <string.h>
 #include <string.h>
 #include <time.h>
 #include <time.h>
 #include "../../core/sr_module.h"
 #include "../../core/sr_module.h"
+#include "../../core/mod_fix.h"
 #include "../../core/dprint.h"
 #include "../../core/dprint.h"
 #include "../../core/ut.h"
 #include "../../core/ut.h"
 #include "../../core/ip_addr.h"
 #include "../../core/ip_addr.h"
@@ -90,7 +91,8 @@ static int mod_init(void);
 static int siptrace_init_rpc(void);
 static int siptrace_init_rpc(void);
 static int child_init(int rank);
 static int child_init(int rank);
 static void destroy(void);
 static void destroy(void);
-static int sip_trace(struct sip_msg*, struct dest_info*, char*);
+static int sip_trace(struct sip_msg*, struct dest_info*, str *correlation_id_str, char*);
+static int sip_trace2(struct sip_msg *, char *dest, char *correlation_id);
 static int fixup_siptrace(void ** param, int param_no);
 static int fixup_siptrace(void ** param, int param_no);
 
 
 static int sip_trace_store_db(struct _siptrace_data* sto);
 static int sip_trace_store_db(struct _siptrace_data* sto);
@@ -103,7 +105,9 @@ static void trace_onreply_out(struct cell* t, int type, struct tmcb_params *ps);
 static void trace_sl_onreply_out(sl_cbp_t *slcb);
 static void trace_sl_onreply_out(sl_cbp_t *slcb);
 static void trace_sl_ack_in(sl_cbp_t *slcb);
 static void trace_sl_ack_in(sl_cbp_t *slcb);
 
 
-static int trace_send_hep_duplicate(str *body, str *from, str *to, struct dest_info*);
+static int trace_send_hep_duplicate(str *body, str *from, str *to, struct dest_info*, str *correlation_id);
+static int trace_send_hep2_duplicate(str *body, str *from, str *to, struct dest_info*);
+static int trace_send_hep3_duplicate(str *body, str *from, str *to, struct dest_info*, str *correlation_id);
 static int pipport2su (char *pipport, union sockaddr_union *tmp_su, unsigned int *proto);
 static int pipport2su (char *pipport, union sockaddr_union *tmp_su, unsigned int *proto);
 
 
 int siptrace_net_data_recv(void *data);
 int siptrace_net_data_recv(void *data);
@@ -140,6 +144,8 @@ int trace_delayed = 0;
 
 
 int hep_version = 1;
 int hep_version = 1;
 int hep_capture_id = 1;
 int hep_capture_id = 1;
+int hep_vendor_id = 0;
+str auth_key_str = {0, 0};
 
 
 int xheaders_write = 0;
 int xheaders_write = 0;
 int xheaders_read = 0;
 int xheaders_read = 0;
@@ -177,6 +183,7 @@ db_func_t db_funcs;      		/*!< Database functions */
 static cmd_export_t cmds[] = {
 static cmd_export_t cmds[] = {
 	{"sip_trace", (cmd_function)sip_trace, 0, 0, 0, ANY_ROUTE},
 	{"sip_trace", (cmd_function)sip_trace, 0, 0, 0, ANY_ROUTE},
 	{"sip_trace", (cmd_function)sip_trace, 1, fixup_siptrace, 0, ANY_ROUTE},
 	{"sip_trace", (cmd_function)sip_trace, 1, fixup_siptrace, 0, ANY_ROUTE},
+	{"sip_trace", (cmd_function)sip_trace2, 2, fixup_spve_spve, 0, ANY_ROUTE},
 	{0, 0, 0, 0, 0, 0}
 	{0, 0, 0, 0, 0, 0}
 };
 };
 
 
@@ -185,6 +192,7 @@ static cmd_export_t cmds[] = {
  * Exported parameters
  * Exported parameters
  */
  */
 static param_export_t params[] = {
 static param_export_t params[] = {
+	{"auth_key",           PARAM_STR, &auth_key_str       },
 	{"db_url",             PARAM_STR, &db_url            },
 	{"db_url",             PARAM_STR, &db_url            },
 	{"table",              PARAM_STR, &siptrace_table     },
 	{"table",              PARAM_STR, &siptrace_table     },
 	{"date_column",        PARAM_STR, &date_column        },
 	{"date_column",        PARAM_STR, &date_column        },
@@ -285,7 +293,7 @@ static int mod_init(void)
 
 
 	*trace_to_database_flag = trace_to_database;
 	*trace_to_database_flag = trace_to_database;
 
 
-	if(hep_version != 1 && hep_version != 2) {
+	if(hep_version != 1 && hep_version != 2 && hep_version != 3) {
 		LM_ERR("unsupported version of HEP");
 		LM_ERR("unsupported version of HEP");
 		return -1;
 		return -1;
 	}
 	}
@@ -305,8 +313,7 @@ static int mod_init(void)
 		}
 		}
 	}
 	}
 
 
-	if(hep_version != 1 && hep_version != 2) {
-
+	if(hep_version != 1 && hep_version != 2 && hep_version != 3) {
 		LM_ERR("unsupported version of HEP");
 		LM_ERR("unsupported version of HEP");
 		return -1;
 		return -1;
 	}
 	}
@@ -726,7 +733,7 @@ static int sip_trace_xheaders_free(struct _siptrace_data *sto)
 	return 0;
 	return 0;
 }
 }
 
 
-static int sip_trace_store(struct _siptrace_data *sto, struct dest_info *dst)
+static int sip_trace_store(struct _siptrace_data *sto, struct dest_info *dst, str *correlation_id_str)
 {
 {
 	if(sto==NULL)
 	if(sto==NULL)
 	{
 	{
@@ -743,7 +750,7 @@ static int sip_trace_store(struct _siptrace_data *sto, struct dest_info *dst)
 	if (sip_trace_xheaders_write(sto) != 0)
 	if (sip_trace_xheaders_write(sto) != 0)
 		return -1;
 		return -1;
 
 
-	if(hep_mode_on) trace_send_hep_duplicate(&sto->body, &sto->fromip, &sto->toip, dst);
+	if(hep_mode_on) trace_send_hep_duplicate(&sto->body, &sto->fromip, &sto->toip, dst, correlation_id_str);
 	else trace_send_duplicate(sto->body.s, sto->body.len, dst);
 	else trace_send_duplicate(sto->body.s, sto->body.len, dst);
 
 
 	if (sip_trace_xheaders_free(sto) != 0)
 	if (sip_trace_xheaders_free(sto) != 0)
@@ -894,8 +901,8 @@ error:
 }
 }
 
 
 static int fixup_siptrace(void** param, int param_no) {
 static int fixup_siptrace(void** param, int param_no) {
-	char *duri = (char*) *param;
-	struct sip_uri dup_uri;
+	char *duri;
+	struct sip_uri uri;
 	struct dest_info *dst = NULL;
 	struct dest_info *dst = NULL;
 	struct proxy_l * p = NULL;
 	struct proxy_l * p = NULL;
 	str dup_uri_str = { 0, 0 };
 	str dup_uri_str = { 0, 0 };
@@ -904,19 +911,35 @@ static int fixup_siptrace(void** param, int param_no) {
 		LM_DBG("params:%s\n", (char*)*param);
 		LM_DBG("params:%s\n", (char*)*param);
 		return 0;
 		return 0;
 	}
 	}
-	if (!(*duri)) {
-		LM_ERR("invalid dup URI\n");
-		return -1;
+
+	if (((char*)(*param))[0] == '\0') {
+		// Empty URI, use the URI set at module level (dup_uri)
+		if (dup_uri) {
+			uri = *dup_uri;
+		}
+		else {
+			LM_ERR("Missing duplicate URI\n");
+			return -1;
+		}
 	}
 	}
-	LM_DBG("sip_trace URI:%s\n", (char*)*param);
+	else {
+		duri = (char*) *param;
 
 
-	dup_uri_str.s = duri;
-	dup_uri_str.len = strlen(dup_uri_str.s);
-	memset(&dup_uri, 0, sizeof(struct sip_uri));
+		if (!(*duri)) {
+			LM_ERR("invalid dup URI\n");
+			return -1;
+		}
 
 
-	if (parse_uri(dup_uri_str.s, dup_uri_str.len, &dup_uri) < 0) {
-		LM_ERR("bad dup uri\n");
-		return -1;
+		LM_DBG("sip_trace URI:%s\n", duri);
+
+		dup_uri_str.s = duri;
+		dup_uri_str.len = strlen(dup_uri_str.s);
+		memset(&uri, 0, sizeof(struct sip_uri));
+
+		if (parse_uri(dup_uri_str.s, dup_uri_str.len, &uri) < 0) {
+			LM_ERR("bad dup uri\n");
+			return -1;
+		}
 	}
 	}
 
 
 	dst = (struct dest_info *) pkg_malloc(sizeof(struct dest_info));
 	dst = (struct dest_info *) pkg_malloc(sizeof(struct dest_info));
@@ -927,7 +950,7 @@ static int fixup_siptrace(void** param, int param_no) {
 	init_dest_info(dst);
 	init_dest_info(dst);
 	/* create a temporary proxy*/
 	/* create a temporary proxy*/
 	dst->proto = PROTO_UDP;
 	dst->proto = PROTO_UDP;
-	p = mk_proxy(&dup_uri.host, (dup_uri.port_no) ? dup_uri.port_no : SIP_PORT,
+	p = mk_proxy(&uri.host, (uri.port_no) ? uri.port_no : SIP_PORT,
 			dst->proto);
 			dst->proto);
 	if (p == 0) {
 	if (p == 0) {
 		LM_ERR("bad host name in uri\n");
 		LM_ERR("bad host name in uri\n");
@@ -947,7 +970,71 @@ static int fixup_siptrace(void** param, int param_no) {
 	return 0;
 	return 0;
 }
 }
 
 
-static int sip_trace(struct sip_msg *msg, struct dest_info * dst, char *dir)
+static int sip_trace2(struct sip_msg *msg, char *dest, char *correlation_id)
+{
+	struct dest_info *dst = NULL;
+	struct sip_uri uri;
+	struct proxy_l * p = NULL;
+	str dup_uri_str = { 0, 0 };
+	str correlation_id_str = {0, 0};;
+
+	if(fixup_get_svalue(msg, (gparam_t*)dest, &dup_uri_str)!=0) {
+		LM_ERR("unable to parse the dest URI string\n");
+		return -1;
+	}
+
+	// If the dest is empty, use the module parameter, if set
+	if (dup_uri_str.len == 0) {
+		if (dup_uri) {
+			uri = *dup_uri;
+		}
+		else {
+			LM_ERR("Missing duplicate URI\n");
+			return -1;
+		}
+	}
+	else {
+		memset(&uri, 0, sizeof(struct sip_uri));
+		if (parse_uri(dup_uri_str.s, dup_uri_str.len, &uri) < 0) {
+			LM_ERR("bad dup uri\n");
+			return -1;
+		}
+	}
+
+	dst = (struct dest_info *)pkg_malloc(sizeof(struct dest_info));
+	if (dst == 0) {
+		LM_ERR("no more pkg memory left\n");
+		return -1;
+	}
+	init_dest_info(dst);
+
+	/* create a temporary proxy*/
+	dst->proto = PROTO_UDP;
+	p = mk_proxy(&uri.host, (uri.port_no) ? uri.port_no : SIP_PORT,
+			dst->proto);
+	if (p == 0) {
+		LM_ERR("bad host name in uri\n");
+		pkg_free(dst);
+		return -1;
+	}
+
+	hostent2su(&dst->to, &p->host, p->addr_idx, (p->port) ? p->port : SIP_PORT);
+
+	/* free temporary proxy*/
+	if (p) {
+		free_proxy(p); /* frees only p content, not p itself */
+		pkg_free(p);
+	}
+
+	if(fixup_get_svalue(msg, (gparam_t*)correlation_id, &correlation_id_str)!=0) {
+		LM_ERR("unable to parse the correlation id\n");
+		return -1;
+	}
+
+	return sip_trace(msg, dst, &correlation_id_str, NULL);
+}
+
+static int sip_trace(struct sip_msg *msg, struct dest_info * dst, str *correlation_id_str, char *dir)
 {
 {
 	struct _siptrace_data sto;
 	struct _siptrace_data sto;
 	struct onsend_info *snd_inf = NULL;
 	struct onsend_info *snd_inf = NULL;
@@ -1061,7 +1148,7 @@ static int sip_trace(struct sip_msg *msg, struct dest_info * dst, char *dir)
 		sto.stat = siptrace_req;
 		sto.stat = siptrace_req;
 	}
 	}
 #endif
 #endif
-	return sip_trace_store(&sto, dst);
+	return sip_trace_store(&sto, dst, correlation_id_str);
 }
 }
 
 
 #define trace_is_off(_msg) \
 #define trace_is_off(_msg) \
@@ -1244,7 +1331,7 @@ static void trace_onreq_out(struct cell* t, int type, struct tmcb_params *ps)
 	sto.stat = siptrace_req;
 	sto.stat = siptrace_req;
 #endif
 #endif
 
 
-	sip_trace_store(&sto, NULL);
+	sip_trace_store(&sto, NULL, NULL);
 	return;
 	return;
 }
 }
 
 
@@ -1316,7 +1403,7 @@ static void trace_onreply_in(struct cell* t, int type, struct tmcb_params *ps)
 	sto.stat = siptrace_rpl;
 	sto.stat = siptrace_rpl;
 #endif
 #endif
 
 
-	sip_trace_store(&sto, NULL);
+	sip_trace_store(&sto, NULL, NULL);
 	return;
 	return;
 }
 }
 
 
@@ -1426,7 +1513,7 @@ static void trace_onreply_out(struct cell* t, int type, struct tmcb_params *ps)
 	sto.stat = siptrace_rpl;
 	sto.stat = siptrace_rpl;
 #endif
 #endif
 
 
-	sip_trace_store(&sto, NULL);
+	sip_trace_store(&sto, NULL, NULL);
 	return;
 	return;
 }
 }
 
 
@@ -1435,7 +1522,7 @@ static void trace_sl_ack_in(sl_cbp_t *slcbp)
 	sip_msg_t *req;
 	sip_msg_t *req;
 	LM_DBG("storing ack...\n");
 	LM_DBG("storing ack...\n");
 	req = slcbp->req;
 	req = slcbp->req;
-	sip_trace(req, 0, 0);
+	sip_trace(req, 0, NULL, 0);
 }
 }
 
 
 static void trace_sl_onreply_out(sl_cbp_t *slcbp)
 static void trace_sl_onreply_out(sl_cbp_t *slcbp)
@@ -1513,7 +1600,7 @@ static void trace_sl_onreply_out(sl_cbp_t *slcbp)
 	sto.stat = siptrace_rpl;
 	sto.stat = siptrace_rpl;
 #endif
 #endif
 
 
-	sip_trace_store(&sto, NULL);
+	sip_trace_store(&sto, NULL, NULL);
 	return;
 	return;
 }
 }
 
 
@@ -1579,7 +1666,181 @@ error:
 	return -1;
 	return -1;
 }
 }
 
 
-static int trace_send_hep_duplicate(str *body, str *from, str *to, struct dest_info * dst2)
+static int trace_send_hep_duplicate(str *body, str *from, str *to, struct dest_info * dst2, str *correlation_id_str)
+{
+	switch (hep_version) {
+		case 1:
+		case 2:
+			return trace_send_hep2_duplicate(body, from, to, dst2);
+		case 3:
+			return trace_send_hep3_duplicate(body, from, to, dst2, correlation_id_str);
+		default:
+			LM_ERR("Unsupported HEP version\n");
+			return -1;
+	}
+}
+
+static int trace_send_hep3_duplicate(str *body, str *from, str *to, struct dest_info * dst2, str *correlation_id_str)
+{
+	struct socket_info *si;
+	void* buffer = NULL;
+	unsigned int len, proto;
+	struct dest_info dst;
+	struct dest_info* dst_fin = NULL;
+	struct proxy_l* p = NULL;
+	union sockaddr_union from_su;
+	union sockaddr_union to_su;
+	struct timeval tvb;
+	struct timezone tz;
+
+	gettimeofday( &tvb, &tz );
+
+	if (pipport2su(from->s, &from_su, &proto)==-1 || (pipport2su(to->s, &to_su, &proto)==-1))
+		goto error;
+
+	if(from_su.s.sa_family != to_su.s.sa_family) {
+		LM_ERR("interworking detected ?\n");
+		goto error;
+	}
+
+	len = sizeof(struct hep_ctrl);         // header
+	len += sizeof(struct hep_chunk_uint8); // proto_family
+	len += sizeof(struct hep_chunk_uint8); // proto_id
+	if (from_su.s.sa_family == AF_INET6) {
+		len += sizeof(struct hep_chunk_ip6); // src IPv6 address
+		len += sizeof(struct hep_chunk_ip6); // dst IPv6 address
+	}
+	else {
+		len += sizeof(struct hep_chunk_ip4); // src IPv4 address
+		len += sizeof(struct hep_chunk_ip4); // dst IPv4 address
+	}
+	len += sizeof(struct hep_chunk_uint16); // source port
+	len += sizeof(struct hep_chunk_uint16); // destination port
+	len += sizeof(struct hep_chunk_uint32); // timestamp
+	len += sizeof(struct hep_chunk_uint32); // timestamp us
+	len += sizeof(struct hep_chunk_uint8); // proto_type (SIP)
+	len += sizeof(struct hep_chunk_uint32); // capture ID
+	len += sizeof(struct hep_chunk); // payload
+
+	if (auth_key_str.s && auth_key_str.len > 0) {
+		len += sizeof(struct hep_chunk) + auth_key_str.len;
+	}
+
+	if (correlation_id_str) {
+		if (correlation_id_str->len > 0) {
+			len += sizeof(struct hep_chunk) + correlation_id_str->len;
+		}
+	}
+
+	len += body->len;
+
+	if (unlikely(len>BUF_SIZE)){
+		goto error;
+	}
+
+	buffer = (void *)pkg_malloc(len);
+	if (!buffer) {
+		LM_ERR("out of memory\n");
+		goto error;
+	}
+
+	HEP3_PACK_INIT(buffer);
+	HEP3_PACK_CHUNK_UINT8 (0, 0x0001, from_su.s.sa_family);
+	HEP3_PACK_CHUNK_UINT8 (0, 0x0002, proto);
+	if (from_su.s.sa_family == AF_INET) {
+		HEP3_PACK_CHUNK_UINT32_NBO(0, 0x0003, from_su.sin.sin_addr.s_addr);
+		HEP3_PACK_CHUNK_UINT32_NBO(0, 0x0004, to_su.sin.sin_addr.s_addr);
+		HEP3_PACK_CHUNK_UINT16_NBO(0, 0x0007, htons(from_su.sin.sin_port));
+		HEP3_PACK_CHUNK_UINT16_NBO(0, 0x0008, htons(to_su.sin.sin_port));
+	} else if (from_su.s.sa_family == AF_INET6) {
+		HEP3_PACK_CHUNK_IP6 (0, 0x0005, &from_su.sin6.sin6_addr);
+		HEP3_PACK_CHUNK_IP6 (0, 0x0006, &to_su.sin6.sin6_addr);
+		HEP3_PACK_CHUNK_UINT16_NBO(0, 0x0007, htons(from_su.sin6.sin6_port));
+		HEP3_PACK_CHUNK_UINT16_NBO(0, 0x0008, htons(to_su.sin6.sin6_port));
+	} else {
+		LM_ERR("unknown address family [%u]\n", dst.send_sock->address.af);
+		goto error;
+	}
+
+	HEP3_PACK_CHUNK_UINT32(0, 0x0009, tvb.tv_sec);
+	HEP3_PACK_CHUNK_UINT32(0, 0x000a, tvb.tv_usec);
+	HEP3_PACK_CHUNK_UINT8 (0, 0x000b, 0x01); /* protocol type: SIP */
+	HEP3_PACK_CHUNK_UINT32(0, 0x000c, hep_capture_id);
+
+	if (correlation_id_str) {
+		if (correlation_id_str->len > 0) {
+			HEP3_PACK_CHUNK_DATA (0, 0x0011, correlation_id_str->s, correlation_id_str->len);
+		}
+	}
+	if (auth_key_str.len) {
+		HEP3_PACK_CHUNK_DATA(0, 0x000e, auth_key_str.s, auth_key_str.len);
+	}
+	HEP3_PACK_CHUNK_DATA (0, 0x000f, body->s, body->len);
+	HEP3_PACK_FINALIZE(buffer, &len);
+
+	if (!dst2){
+		init_dest_info(&dst);
+		dst.proto = PROTO_UDP;
+		p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,
+		dst.proto);
+		if (p==0)
+		{
+			LM_ERR("bad host name in uri\n");
+			goto error;
+		}
+
+		hostent2su(&dst.to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT);
+		LM_DBG("setting up the socket_info\n");
+		dst_fin = &dst;
+	} else {
+		dst_fin = dst2;
+	}
+
+	if (force_send_sock_str.s) {
+		LM_DBG("force_send_sock activated, grep for the sock_info\n");
+		si = grep_sock_info(&force_send_sock_uri->host,
+				(force_send_sock_uri->port_no)?force_send_sock_uri->port_no:SIP_PORT,
+				PROTO_UDP);
+		if (!si) {
+			LM_WARN("cannot grep socket info\n");
+		} else {
+			LM_DBG("found socket while grep: [%.*s] [%.*s]\n", si->name.len, si->name.s, si->address_str.len, si->address_str.s);
+			dst_fin->send_sock = si;
+		}
+	}
+
+	if (dst_fin->send_sock == 0) {
+		dst_fin->send_sock=get_send_socket(0, &dst_fin->to, dst_fin->proto);
+		if (dst_fin->send_sock == 0) {
+			LM_ERR("can't forward to af %d, proto %d no corresponding"
+					" listening socket\n", dst_fin->to.s.sa_family, dst_fin->proto);
+			goto error;
+		}
+	}
+
+	if (msg_send_buffer(dst_fin, buffer, len, 1)<0)
+	{
+		LM_ERR("cannot send hep duplicate message\n");
+		goto error;
+	}
+
+	if (p) {
+		free_proxy(p); /* frees only p content, not p itself */
+		pkg_free(p);
+	}
+	pkg_free(buffer);
+	return 0;
+error:
+	if(p)
+	{
+		free_proxy(p); /* frees only p content, not p itself */
+		pkg_free(p);
+	}
+	if(buffer) pkg_free(buffer);
+	return -1;
+}
+
+static int trace_send_hep2_duplicate(str *body, str *from, str *to, struct dest_info * dst2)
 {
 {
 	struct dest_info dst;
 	struct dest_info dst;
 	struct socket_info *si;
 	struct socket_info *si;
@@ -1901,7 +2162,7 @@ int siptrace_net_data_recv(void *data)
 
 
 	sto.dir = "in";
 	sto.dir = "in";
 
 
-	trace_send_hep_duplicate(&sto.body, &sto.fromip, &sto.toip, NULL);
+	trace_send_hep_duplicate(&sto.body, &sto.fromip, &sto.toip, NULL, NULL);
 	return 0;
 	return 0;
 
 
 }
 }
@@ -1949,7 +2210,7 @@ int siptrace_net_data_send(void *data)
 
 
 	sto.dir = "out";
 	sto.dir = "out";
 
 
-	trace_send_hep_duplicate(&sto.body, &sto.fromip, &sto.toip, NULL);
+	trace_send_hep_duplicate(&sto.body, &sto.fromip, &sto.toip, NULL, NULL);
 	return 0;
 	return 0;
 }
 }