|
@@ -50,6 +50,8 @@
|
|
|
#include "../../str.h"
|
|
|
#include "../../onsend.h"
|
|
|
|
|
|
+#include "../../modules/sipcapture/sipcapture.h"
|
|
|
+
|
|
|
#ifdef STATISTICS
|
|
|
#include "../../lib/kcore/statistics.h"
|
|
|
#endif
|
|
@@ -97,6 +99,10 @@ 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_ack_in(sl_cbp_t *slcb);
|
|
|
|
|
|
+static int trace_send_hep_duplicate(str *body, str *from, str *to);
|
|
|
+static int pipport2su (char *pipport, union sockaddr_union *tmp_su, unsigned int proto);
|
|
|
+
|
|
|
+
|
|
|
static struct mi_root* sip_trace_mi(struct mi_root* cmd, void* param );
|
|
|
|
|
|
static str db_url = str_init(DEFAULT_RODB_URL);
|
|
@@ -145,6 +151,8 @@ static str trace_table_avp_str = {NULL, 0};
|
|
|
|
|
|
static str trace_local_ip = {NULL, 0};
|
|
|
|
|
|
+int hep_mode_on = 0;
|
|
|
+
|
|
|
db1_con_t *db_con = NULL; /*!< database connection */
|
|
|
db_func_t db_funcs; /*!< Database functions */
|
|
|
|
|
@@ -184,6 +192,7 @@ static param_export_t params[] = {
|
|
|
{"trace_sl_acks", INT_PARAM, &trace_sl_acks },
|
|
|
{"xheaders_write", INT_PARAM, &xheaders_write },
|
|
|
{"xheaders_read", INT_PARAM, &xheaders_read },
|
|
|
+ {"hep_mode_on", INT_PARAM, &hep_mode_on },
|
|
|
{0, 0, 0}
|
|
|
};
|
|
|
|
|
@@ -276,19 +285,29 @@ static int mod_init(void)
|
|
|
return -1;
|
|
|
}
|
|
|
trace_flag = 1<<trace_flag;
|
|
|
-
|
|
|
- /* Find a database module */
|
|
|
- if (db_bind_mod(&db_url, &db_funcs))
|
|
|
- {
|
|
|
- LM_ERR("unable to bind database module\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (!DB_CAPABILITY(db_funcs, DB_CAP_INSERT))
|
|
|
- {
|
|
|
- LM_ERR("database modules does not provide all functions needed"
|
|
|
- " by module\n");
|
|
|
+
|
|
|
+ trace_to_database_flag = (int*)shm_malloc(sizeof(int));
|
|
|
+ if(trace_to_database_flag==NULL) {
|
|
|
+ LM_ERR("no more shm memory left\n");
|
|
|
return -1;
|
|
|
}
|
|
|
+
|
|
|
+ *trace_to_database_flag = trace_to_database;
|
|
|
+
|
|
|
+ /* Find a database module if needed */
|
|
|
+ if(trace_to_database_flag!=NULL && *trace_to_database_flag!=0) {
|
|
|
+ if (db_bind_mod(&db_url, &db_funcs))
|
|
|
+ {
|
|
|
+ LM_ERR("unable to bind database module\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (trace_to_database_flag && !DB_CAPABILITY(db_funcs, DB_CAP_INSERT))
|
|
|
+ {
|
|
|
+ LM_ERR("database modules does not provide all functions needed"
|
|
|
+ " by module\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
trace_on_flag = (int*)shm_malloc(sizeof(int));
|
|
|
if(trace_on_flag==NULL) {
|
|
@@ -297,15 +316,7 @@ static int mod_init(void)
|
|
|
}
|
|
|
|
|
|
*trace_on_flag = trace_on;
|
|
|
-
|
|
|
- trace_to_database_flag = (int*)shm_malloc(sizeof(int));
|
|
|
- if(trace_to_database_flag==NULL) {
|
|
|
- LM_ERR("no more shm memory left\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- *trace_to_database_flag = trace_to_database;
|
|
|
-
|
|
|
+
|
|
|
xheaders_write_flag = (int*)shm_malloc(sizeof(int));
|
|
|
xheaders_read_flag = (int*)shm_malloc(sizeof(int));
|
|
|
if (!(xheaders_write_flag && xheaders_read_flag)) {
|
|
@@ -423,12 +434,14 @@ static int child_init(int rank)
|
|
|
if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
|
|
|
return 0; /* do nothing for the main process */
|
|
|
|
|
|
- db_con = db_funcs.init(&db_url);
|
|
|
- if (!db_con)
|
|
|
- {
|
|
|
- LM_ERR("unable to connect to database. Please check configuration.\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ if(trace_to_database_flag!=NULL && *trace_to_database_flag!=0) {
|
|
|
+ db_con = db_funcs.init(&db_url);
|
|
|
+ if (!db_con)
|
|
|
+ {
|
|
|
+ LM_ERR("unable to connect to database. Please check configuration.\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -436,10 +449,14 @@ static int child_init(int rank)
|
|
|
|
|
|
static void destroy(void)
|
|
|
{
|
|
|
- if (db_con!=NULL)
|
|
|
- db_funcs.close(db_con);
|
|
|
- if (trace_on_flag)
|
|
|
- shm_free(trace_on_flag);
|
|
|
+ if(trace_to_database_flag!=NULL && *trace_to_database_flag!=0) {
|
|
|
+ if (db_con!=NULL)
|
|
|
+ db_funcs.close(db_con);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (trace_on_flag)
|
|
|
+ shm_free(trace_on_flag);
|
|
|
+
|
|
|
}
|
|
|
|
|
|
static inline int siptrace_copy_proto(int proto, char *buf)
|
|
@@ -688,7 +705,8 @@ static int sip_trace_store(struct _siptrace_data *sto)
|
|
|
if (sip_trace_xheaders_write(sto) != 0)
|
|
|
return -1;
|
|
|
|
|
|
- trace_send_duplicate(sto->body.s, sto->body.len);
|
|
|
+ if(hep_mode_on) trace_send_hep_duplicate(&sto->body, &sto->fromip, &sto->toip);
|
|
|
+ else trace_send_duplicate(sto->body.s, sto->body.len);
|
|
|
|
|
|
if (sip_trace_xheaders_free(sto) != 0)
|
|
|
return -1;
|
|
@@ -1424,3 +1442,241 @@ error:
|
|
|
pkg_free(p);
|
|
|
return -1;
|
|
|
}
|
|
|
+
|
|
|
+static int trace_send_hep_duplicate(str *body, str *from, str *to)
|
|
|
+{
|
|
|
+ struct dest_info dst;
|
|
|
+ struct proxy_l * p=NULL /* make gcc happy */;
|
|
|
+ void* buffer;
|
|
|
+ union sockaddr_union from_su;
|
|
|
+ union sockaddr_union to_su;
|
|
|
+ unsigned int len, buflen, proto;
|
|
|
+ struct hep_hdr hdr;
|
|
|
+ struct hep_iphdr hep_ipheader;
|
|
|
+#if USE_IPV6
|
|
|
+ struct hep_ip6hdr hep_ip6header;
|
|
|
+#endif
|
|
|
+
|
|
|
+ if(body->s==NULL || body->len <= 0)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if(dup_uri_str.s==0 || dup_uri==NULL)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+
|
|
|
+ /* message length */
|
|
|
+ len = body->len
|
|
|
+#if USE_IPV6
|
|
|
+ + sizeof(struct hep_ip6hdr)
|
|
|
+#else
|
|
|
+ + sizeof(struct hep_iphdr)
|
|
|
+#endif
|
|
|
+ + sizeof(struct hep_hdr);
|
|
|
+
|
|
|
+
|
|
|
+ /* The packet is too big for us */
|
|
|
+ if (unlikely(len>BUF_SIZE)){
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Convert proto:ip:port to sockaddress union SRC IP */
|
|
|
+ if (pipport2su(from->s, &from_su, proto)==-1 || (pipport2su(to->s, &to_su, proto)==-1))
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ /* check if from and to are in the same family*/
|
|
|
+ if(from_su.s.sa_family != to_su.s.sa_family) {
|
|
|
+ LOG(L_ERR, "ERROR: trace_send_hep_duplicate: interworking detected ?\n");
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ init_dest_info(&dst);
|
|
|
+ /* create a temporary proxy*/
|
|
|
+ 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);
|
|
|
+
|
|
|
+ dst.send_sock=get_send_socket(0, &dst.to, dst.proto);
|
|
|
+ if (dst.send_sock==0)
|
|
|
+ {
|
|
|
+ LM_ERR("can't forward to af %d, proto %d no corresponding"
|
|
|
+ " listening socket\n", dst.to.s.sa_family, dst.proto);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Version && proto && length */
|
|
|
+ hdr.hp_l = sizeof(struct hep_hdr);
|
|
|
+ hdr.hp_v = 1;
|
|
|
+ hdr.hp_p = proto;
|
|
|
+
|
|
|
+ /* AND the last */
|
|
|
+ if (from_su.s.sa_family==AF_INET){
|
|
|
+ /* prepare the hep headers */
|
|
|
+
|
|
|
+ hdr.hp_f = AF_INET;
|
|
|
+ hdr.hp_sport = htons(from_su.sin.sin_port);
|
|
|
+ hdr.hp_dport = htons(to_su.sin.sin_port);
|
|
|
+
|
|
|
+ hep_ipheader.hp_src = from_su.sin.sin_addr;
|
|
|
+ hep_ipheader.hp_dst = to_su.sin.sin_addr;
|
|
|
+
|
|
|
+ len = sizeof(struct hep_iphdr);
|
|
|
+ }
|
|
|
+#ifdef USE_IPV6
|
|
|
+ else if (from_su.s.sa_family==AF_INET6){
|
|
|
+ /* prepare the hep6 headers */
|
|
|
+
|
|
|
+ hdr.hp_f = AF_INET6;
|
|
|
+
|
|
|
+ hdr.hp_sport = htons(from_su.sin6.sin6_port);
|
|
|
+ hdr.hp_dport = htons(to_su.sin6.sin6_port);
|
|
|
+
|
|
|
+ hep_ip6header.hp6_src = from_su.sin6.sin6_addr;
|
|
|
+ hep_ip6header.hp6_dst = to_su.sin6.sin6_addr;
|
|
|
+
|
|
|
+ len = sizeof(struct hep_ip6hdr);
|
|
|
+ }
|
|
|
+#endif /* USE_IPV6 */
|
|
|
+ else {
|
|
|
+ LOG(L_ERR, "ERROR: trace_send_hep_duplicate: Unsupported protocol family\n");
|
|
|
+ goto error;;
|
|
|
+ }
|
|
|
+
|
|
|
+ hdr.hp_l +=len;
|
|
|
+ len += sizeof(struct hep_hdr) + body->len;
|
|
|
+ buffer = (void *)pkg_malloc(len+1);
|
|
|
+ if (buffer==0){
|
|
|
+ LOG(L_ERR, "ERROR: trace_send_hep_duplicate: out of memory\n");
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Copy job */
|
|
|
+ memset(buffer, '\0', len+1);
|
|
|
+
|
|
|
+ /* copy hep_hdr */
|
|
|
+ memcpy((void*)buffer, &hdr, sizeof(struct hep_hdr));
|
|
|
+ buflen = sizeof(struct hep_hdr);
|
|
|
+
|
|
|
+ /* hep_ip_hdr */
|
|
|
+ if(from_su.s.sa_family==AF_INET) {
|
|
|
+ memcpy((void*)buffer + buflen, &hep_ipheader, sizeof(struct hep_iphdr));
|
|
|
+ buflen += sizeof(struct hep_iphdr);
|
|
|
+ }
|
|
|
+#if USE_IPV6
|
|
|
+ else {
|
|
|
+ memcpy((void*)buffer+buflen, &hep_ip6header, sizeof(struct hep_ip6hdr));
|
|
|
+ buflen += sizeof(struct hep_ip6hdr);
|
|
|
+ }
|
|
|
+#endif /* USE_IPV6 */
|
|
|
+
|
|
|
+ /* PAYLOAD */
|
|
|
+ memcpy((void*)(buffer + buflen) , (void*)body->s, body->len);
|
|
|
+ buflen +=body->len;
|
|
|
+
|
|
|
+ if (msg_send(&dst, buffer, buflen)<0)
|
|
|
+ {
|
|
|
+ LM_ERR("cannot send hep duplicate message\n");
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ free_proxy(p); /* frees only p content, not p itself */
|
|
|
+ pkg_free(p);
|
|
|
+ pkg_free(buffer);
|
|
|
+ return 0;
|
|
|
+error:
|
|
|
+ free_proxy(p); /* frees only p content, not p itself */
|
|
|
+ pkg_free(p);
|
|
|
+ pkg_free(buffer);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ * \brief Convert a STR [proto:]ip[:port] into socket address.
|
|
|
+ * [proto:]ip[:port]
|
|
|
+ * \param pipport (udp:127.0.0.1:5060 or tcp:2001:0DB8:AC10:FE01:5060)
|
|
|
+ * \param tmp_su target structure
|
|
|
+ * \param proto uint protocol type
|
|
|
+ * \return success / unsuccess
|
|
|
+ */
|
|
|
+static int pipport2su (char *pipport, union sockaddr_union *tmp_su, unsigned int proto)
|
|
|
+{
|
|
|
+ unsigned int port_no, cutlen = 4;
|
|
|
+ struct ip_addr *ip;
|
|
|
+ char *p, *host_s;
|
|
|
+ str port_str, host_uri;
|
|
|
+ unsigned len = 0;
|
|
|
+
|
|
|
+ /*parse protocol */
|
|
|
+ if(strncmp(pipport, "udp:",4) == 0) proto = IPPROTO_UDP;
|
|
|
+ else if(strncmp(pipport, "tcp:",4) == 0) proto = IPPROTO_TCP;
|
|
|
+ else if(strncmp(pipport, "tls:",4) == 0) proto = IPPROTO_IDP; /* fake proto type */
|
|
|
+ else if(strncmp(pipport, "sctp:",5) == 0) cutlen = 5, proto = IPPROTO_SCTP;
|
|
|
+ else if(strncmp(pipport, "any:",4) == 0) proto = IPPROTO_UDP;
|
|
|
+ else {
|
|
|
+ LM_ERR("bad protocol %s\n", pipport);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*separate proto and host */
|
|
|
+ p = pipport+cutlen;
|
|
|
+ if( (*(p)) == '\0') {
|
|
|
+ LM_ERR("malformed ip address\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ host_s=p;
|
|
|
+
|
|
|
+ if( (p = strrchr(p+1, ':')) == 0 ) {
|
|
|
+ LM_ERR("no port specified\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ /*the address contains a port number*/
|
|
|
+ *p = '\0';
|
|
|
+ p++;
|
|
|
+ port_str.s = p;
|
|
|
+ port_str.len = strlen(p);
|
|
|
+ LM_DBG("the port string is %s\n", p);
|
|
|
+ if(str2int(&port_str, &port_no) != 0 ) {
|
|
|
+ LM_ERR("there is not a valid number port\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ *p = '\0';
|
|
|
+ if (port_no<1024 || port_no>65536)
|
|
|
+ {
|
|
|
+ LM_ERR("invalid port number; must be in [1024,65536]\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* now IPv6 address has no brakets. It should be fixed! */
|
|
|
+ if (host_s[0] == '[') {
|
|
|
+ len = strlen(host_s + 1) - 1;
|
|
|
+ if(host_s[len+1] != ']') {
|
|
|
+ LM_ERR("bracket not closed\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ memmove(host_s, host_s + 1, len);
|
|
|
+ host_s[len] = '\0';
|
|
|
+ }
|
|
|
+
|
|
|
+ host_uri.s = host_s;
|
|
|
+ host_uri.len = strlen(host_s);
|
|
|
+
|
|
|
+
|
|
|
+ /* check if it's an ip address */
|
|
|
+ if (((ip=str2ip(&host_uri))!=0)
|
|
|
+#ifdef USE_IPV6
|
|
|
+ || ((ip=str2ip6(&host_uri))!=0)
|
|
|
+#endif
|
|
|
+ ) {
|
|
|
+ ip_addr2su(tmp_su, ip, ntohs(port_no));
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return -1;
|
|
|
+}
|