/*
* $Id: siptrace.c 2124 2007-05-03 10:37:47Z miconda $
*
* siptrace module - helper module to trace sip messages
*
* Copyright (C) 2006 Voice Sistem S.R.L.
*
* This file is part of openser, a free SIP server.
*
* openser 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
*
* openser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../../sr_module.h"
#include "../../dprint.h"
#include "../../ut.h"
#include "../../ip_addr.h"
#include "../../mem/mem.h"
#include "../../mem/shm_mem.h"
#include "../../mi/mi.h"
#include "../../db/db.h"
#include "../../parser/parse_content.h"
#include "../../parser/parse_from.h"
#include "../../items.h"
#include "../tm/tm_load.h"
#include "../sl/sl_cb.h"
MODULE_VERSION
struct tm_binds tmb;
/* module function prototypes */
static int mod_init(void);
static int child_init(int rank);
static void destroy(void);
static int sip_trace(struct sip_msg*, char*, char*);
static int trace_send_duplicate(char *buf, int len);
static void trace_onreq_in(struct cell* t, int type, struct tmcb_params *ps);
static void trace_onreq_out(struct cell* t, int type, struct tmcb_params *ps);
static void trace_onreply_in(struct cell* t, int type, struct tmcb_params *ps);
static void trace_onreply_out(struct cell* t, int type, struct tmcb_params *ps);
static void trace_sl_onreply_out(struct sip_msg* req,
struct sl_cb_param *sl_param);
static struct mi_root* sip_trace_mi(struct mi_root* cmd, void* param );
char* db_url = DEFAULT_RODB_URL;
char* siptrace_table = "sip_trace";
char* date_column = "date"; /* 00 */
char* callid_column = "callid"; /* 01 */
char* traced_user_column = "traced_user"; /* 02 */
char* msg_column = "msg"; /* 03 */
char* method_column = "method"; /* 04 */
char* status_column = "status"; /* 05 */
char* fromip_column = "fromip"; /* 06 */
char* toip_column = "toip"; /* 07 */
char* fromtag_column = "fromtag"; /* 08 */
char* direction_column = "direction"; /* 09 */
#define NR_KEYS 10
int trace_flag = -1;
int trace_on = 0;
str dup_uri_str = {0, 0};
struct sip_uri *dup_uri = 0;
int *trace_on_flag = NULL;
static unsigned short traced_user_avp_type;
static int_str traced_user_avp;
char *traced_user_avp_str = NULL;
static unsigned short trace_table_avp_type;
static int_str trace_table_avp;
char *trace_table_avp_str = NULL;
char* trace_local_ip = NULL;
/** database connection */
db_con_t *db_con = NULL;
db_func_t db_funcs; /* Database functions */
/* sl callback registration */
register_slcb_t register_slcb_f=NULL;
/*
* Exported functions
*/
static cmd_export_t cmds[] = {
{"sip_trace", sip_trace, 0, 0,
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE},
{0, 0, 0, 0, 0}
};
/*
* Exported parameters
*/
static param_export_t params[] = {
{"db_url", STR_PARAM, &db_url },
{"table", STR_PARAM, &siptrace_table },
{"date_column", STR_PARAM, &date_column },
{"callid_column", STR_PARAM, &callid_column },
{"traced_user_column", STR_PARAM, &traced_user_column },
{"msg_column", STR_PARAM, &msg_column },
{"method_column", STR_PARAM, &method_column },
{"status_column", STR_PARAM, &status_column },
{"fromip_column", STR_PARAM, &fromip_column },
{"toip_column", STR_PARAM, &toip_column },
{"fromtag_column", STR_PARAM, &fromtag_column },
{"direction_column", STR_PARAM, &direction_column },
{"trace_flag", INT_PARAM, &trace_flag },
{"trace_on", INT_PARAM, &trace_on },
{"traced_user_avp", STR_PARAM, &traced_user_avp_str},
{"trace_table_avp", STR_PARAM, &trace_table_avp_str},
{"duplicate_uri", STR_PARAM, &dup_uri_str.s },
{"trace_local_ip", STR_PARAM, &trace_local_ip },
{0, 0, 0}
};
static mi_export_t mi_cmds[] = {
{ "sip_trace", sip_trace_mi, 0, 0, 0 },
{ 0, 0, 0, 0, 0}
};
#ifdef STATISTICS
#include "../../statistics.h"
stat_var* siptrace_req;
stat_var* siptrace_rpl;
stat_export_t siptrace_stats[] = {
{"traced_requests" , 0, &siptrace_req },
{"traced_replies" , 0, &siptrace_rpl },
{0,0,0}
};
#endif
/* module exports */
struct module_exports exports = {
"siptrace",
DEFAULT_DLFLAGS, /* dlopen flags */
cmds, /* Exported functions */
params, /* Exported parameters */
#ifdef STATISTICS
siptrace_stats,
#else
0, /* exported statistics */
#endif
mi_cmds, /* exported MI functions */
0, /* exported pseudo-variables */
mod_init, /* module initialization function */
0, /* response function */
destroy, /* destroy function */
child_init /* child initialization function */
};
static int mod_init(void)
{
xl_spec_t avp_spec;
DBG("siptrace - initializing\n");
if(siptrace_table==0 || strlen(siptrace_table)<=0)
{
LOG(L_ERR,
"siptrace:mod_init:ERROR: invalid table name\n");
return -1;
}
if (flag_idx2mask(&trace_flag)<0)
return -1;
/* Find a database module */
if (bind_dbmod(db_url, &db_funcs))
{
LOG(L_ERR, "siptrace:mod_init: Unable to bind database module\n");
return -1;
}
if (!DB_CAPABILITY(db_funcs, DB_CAP_INSERT))
{
LOG(L_ERR, "siptrace:mod_init: 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)
{
LOG(L_ERR, "siptrace:mod_init:ERROR: no more shm\n");
return -1;
}
*trace_on_flag = trace_on;
/* register callbacks to TM */
if (load_tm_api(&tmb)!=0)
{
LOG(L_ERR, "siptrace:mod_init:ERROR: can't load tm api\n");
return -1;
}
if(tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, trace_onreq_in, 0) <=0)
{
LOG(L_ERR,"siptrace:mod_init:ERROR: can't register trace_onreq_in\n");
return -1;
}
/* register sl callback */
register_slcb_f = (register_slcb_t)find_export("register_slcb", 0, 0);
if(register_slcb_f==NULL)
{
LOG(L_ERR, "siptrace:mod_init:ERROR: can't load sl api\n");
return -1;
}
if(register_slcb_f(trace_sl_onreply_out, NULL)!=0)
{
LOG(L_ERR,
"siptrace:mod_init:ERROR: can't register trace_sl_onreply_out\n");
return -1;
}
if(dup_uri_str.s!=0) {
dup_uri_str.len = strlen(dup_uri_str.s);
dup_uri = (struct sip_uri *)pkg_malloc(sizeof(struct sip_uri));
if(dup_uri==0) {
LOG(L_ERR, "siptrace:mod_init:ERROR: no more pkg memory\n");
return -1;
}
memset(dup_uri, 0, sizeof(struct sip_uri));
if(parse_uri(dup_uri_str.s, dup_uri_str.len, dup_uri)<0) {
LOG(L_ERR, "siptrace:mod_init:ERROR: bad dup uri\n");
return -1;
}
}
if(traced_user_avp_str && *traced_user_avp_str)
{
if (xl_parse_spec(traced_user_avp_str, &avp_spec,
XL_THROW_ERROR|XL_DISABLE_MULTI|XL_DISABLE_COLORS)==0
|| avp_spec.type!=XL_AVP) {
LOG(L_ERR, "ERROR:siptrace:mod_init: malformed or non AVP %s "
"AVP definition\n", traced_user_avp_str);
return -1;
}
if(xl_get_avp_name(0, &avp_spec, &traced_user_avp,
&traced_user_avp_type)!=0)
{
LOG(L_ERR, "ERROR:siptrace:mod_init: [%s]- invalid "
"AVP definition\n", traced_user_avp_str);
return -1;
}
} else {
traced_user_avp.n = 0;
traced_user_avp_type = 0;
}
if(trace_table_avp_str && *trace_table_avp_str)
{
if (xl_parse_spec(trace_table_avp_str, &avp_spec,
XL_THROW_ERROR|XL_DISABLE_MULTI|XL_DISABLE_COLORS)==0
|| avp_spec.type!=XL_AVP) {
LOG(L_ERR, "ERROR:siptrace:mod_init: malformed or non AVP %s "
"AVP definition\n", trace_table_avp_str);
return -1;
}
if(xl_get_avp_name(0, &avp_spec, &trace_table_avp,
&trace_table_avp_type)!=0)
{
LOG(L_ERR, "ERROR:siptrace:mod_init: [%s]- invalid "
"AVP definition\n", trace_table_avp_str);
return -1;
}
} else {
trace_table_avp.n = 0;
trace_table_avp_type = 0;
}
return 0;
}
static int child_init(int rank)
{
db_con = db_funcs.init(db_url);
if (!db_con)
{
LOG(L_ERR, "siptrace:init_child: Unable to connect database\n");
return -1;
}
return 0;
}
static void destroy(void)
{
if (db_con!=NULL)
db_funcs.close(db_con);
if (trace_on_flag)
shm_free(trace_on_flag);
}
static inline char* siptrace_get_table()
{
int_str avp_value;
struct usr_avp *avp;
if(trace_table_avp.n==0)
return siptrace_table;
avp = NULL;
if(trace_table_avp.n!=0)
avp=search_first_avp(trace_table_avp_type, trace_table_avp,
&avp_value, 0);
if(avp==NULL || !is_avp_str_val(avp) || avp_value.s.len<=0)
return siptrace_table;
return avp_value.s.s;
}
static int sip_trace(struct sip_msg *msg, char *s1, char *s2)
{
db_key_t db_keys[NR_KEYS];
db_val_t db_vals[NR_KEYS];
static char toip_buff[IP_ADDR_MAX_STR_SIZE+6];
static char fromip_buff[IP_ADDR_MAX_STR_SIZE+6];
int_str avp_value;
struct usr_avp *avp;
if(msg==NULL)
{
DBG("sip_trace: no uas request, local transaction\n");
return -1;
}
avp = NULL;
if(traced_user_avp.n!=0)
avp=search_first_avp(traced_user_avp_type, traced_user_avp,
&avp_value, 0);
if((avp==NULL) && (trace_on_flag==NULL || *trace_on_flag==0))
{
DBG("sip_trace: trace off...\n");
return -1;
}
if(parse_from_header(msg)==-1 || msg->from==NULL || get_from(msg)==NULL)
{
LOG(L_ERR, "sip_trace: ERROR cannot parse FROM header\n");
goto error;
}
if(parse_headers(msg, HDR_CALLID_F, 0)!=0 || msg->callid==NULL
|| msg->callid->body.s==NULL)
{
LOG(L_ERR, "sip_trace: ERROR cannot parse call-id\n");
goto error;
}
db_keys[0] = msg_column;
db_vals[0].type = DB_BLOB;
db_vals[0].nul = 0;
db_vals[0].val.blob_val.s = msg->buf;
db_vals[0].val.blob_val.len = msg->len;
db_keys[1] = callid_column;
db_vals[1].type = DB_STR;
db_vals[1].nul = 0;
db_vals[1].val.str_val.s = msg->callid->body.s;
db_vals[1].val.str_val.len = msg->callid->body.len;
db_keys[2] = method_column;
db_vals[2].type = DB_STR;
db_vals[2].nul = 0;
if(msg->first_line.type==SIP_REQUEST)
{
db_vals[2].val.str_val.s = msg->first_line.u.request.method.s;
db_vals[2].val.str_val.len = msg->first_line.u.request.method.len;
} else {
db_vals[2].val.str_val.s = "";
db_vals[2].val.str_val.len = 0;
}
db_keys[3] = status_column;
db_vals[3].type = DB_STR;
db_vals[3].nul = 0;
if(msg->first_line.type==SIP_REPLY)
{
db_vals[3].val.str_val.s = msg->first_line.u.reply.status.s;
db_vals[3].val.str_val.len = msg->first_line.u.reply.status.len;
} else {
db_vals[3].val.str_val.s = "";
db_vals[3].val.str_val.len = 0;
}
db_keys[4] = fromip_column;
db_vals[4].type = DB_STRING;
db_vals[4].nul = 0;
strcpy(fromip_buff, ip_addr2a(&msg->rcv.src_ip));
strcat(fromip_buff,":");
strcat(fromip_buff, int2str(msg->rcv.src_port, NULL));
db_vals[4].val.string_val = fromip_buff;
db_keys[5] = toip_column;
db_vals[5].type = DB_STRING;
db_vals[5].nul = 0;
// db_vals[5].val.string_val = ip_addr2a(&msg->rcv.dst_ip);;
if(msg->rcv.proto==PROTO_TCP) {
memcpy(toip_buff, "tcp:", 4);
} else if(msg->rcv.proto==PROTO_TLS) {
memcpy(toip_buff, "tls:", 4);
} else {
memcpy(toip_buff, "udp:", 4);
}
strcpy(toip_buff+4, ip_addr2a(&msg->rcv.dst_ip));
strcat(toip_buff+4,":");
strcat(toip_buff+4, int2str(msg->rcv.dst_port, NULL));
db_vals[5].val.string_val = toip_buff;
db_keys[6] = date_column;
db_vals[6].type = DB_DATETIME;
db_vals[6].nul = 0;
db_vals[6].val.int_val = time(NULL);
db_keys[7] = direction_column;
db_vals[7].type = DB_STRING;
db_vals[7].nul = 0;
db_vals[7].val.string_val = "in";
db_keys[8] = fromtag_column;
db_vals[8].type = DB_STR;
db_vals[8].nul = 0;
db_vals[8].val.str_val.s = get_from(msg)->tag_value.s;
db_vals[8].val.str_val.len = get_from(msg)->tag_value.len;
db_funcs.use_table(db_con, siptrace_get_table());
db_keys[9] = traced_user_column;
db_vals[9].type = DB_STR;
db_vals[9].nul = 0;
if(trace_on_flag!=NULL && *trace_on_flag!=0) {
db_vals[9].val.str_val.s = "";
db_vals[9].val.str_val.len = 0;
DBG("sip_trace: storing info...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "sip_trace: error storing trace\n");
goto error;
}
#ifdef STATISTICS
update_stat(siptrace_req, 1);
#endif
}
if(avp==NULL)
goto done;
trace_send_duplicate(db_vals[0].val.blob_val.s,
db_vals[0].val.blob_val.len);
db_vals[9].val.str_val.s = avp_value.s.s;
db_vals[9].val.str_val.len = avp_value.s.len;
DBG("sip_trace: storing info...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "sip_trace: error storing trace\n");
goto error;
}
avp = search_next_avp( avp, &avp_value);
while(avp!=NULL)
{
db_vals[9].val.str_val.s = avp_value.s.s;
db_vals[9].val.str_val.len = avp_value.s.len;
DBG("sip_trace: storing info...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "sip_trace: error storing trace\n");
goto error;
}
avp = search_next_avp( avp, &avp_value);
}
done:
return 1;
error:
return -1;
}
#define trace_is_off(_msg) \
(trace_on_flag==NULL || *trace_on_flag==0 || \
((_msg)->flags&trace_flag)==0)
static void trace_onreq_in(struct cell* t, int type, struct tmcb_params *ps)
{
struct sip_msg* msg;
int_str avp_value;
struct usr_avp *avp;
if(t==NULL || ps==NULL)
{
DBG("trace_onreq_in: no uas request, local transaction\n");
return;
}
msg = ps->req;
if(msg==NULL)
{
DBG("trace_onreq_in: no uas request, local transaction\n");
return;
}
avp = NULL;
if(traced_user_avp.n!=0)
avp=search_first_avp(traced_user_avp_type, traced_user_avp,
&avp_value, 0);
if((avp==NULL) && trace_is_off(msg))
{
DBG("trace_onreq_in: trace off...\n");
return;
}
if(parse_from_header(msg)==-1 || msg->from==NULL || get_from(msg)==NULL)
{
LOG(L_ERR, "trace_onreq_in: ERROR cannot parse FROM header\n");
return;
}
if(parse_headers(msg, HDR_CALLID_F, 0)!=0)
{
LOG(L_ERR, "trace_onreq_in: ERROR cannot parse call-id\n");
return;
}
if (msg->REQ_METHOD==METHOD_INVITE)
{
DBG("trace_onreq_in: noisy_timer set for tracing\n");
t->flags |= T_NOISY_CTIMER_FLAG;
}
if(tmb.register_tmcb( 0, t, TMCB_REQUEST_BUILT, trace_onreq_out, 0) <=0)
{
LOG(L_ERR,"trace_onreq_in:ERROR: can't register trace_onreq_out\n");
return;
}
if(tmb.register_tmcb( 0, t, TMCB_RESPONSE_IN, trace_onreply_in, 0) <=0)
{
LOG(L_ERR,
"trace_onreq_in:ERROR: can't register trace_onreply_in\n");
return;
}
if(tmb.register_tmcb( 0, t, TMCB_RESPONSE_OUT, trace_onreply_out, 0) <=0)
{
LOG(L_ERR,
"trace_onreq_in:ERROR: can't register trace_onreply_out\n");
return;
}
}
static void trace_onreq_out(struct cell* t, int type, struct tmcb_params *ps)
{
db_key_t db_keys[NR_KEYS];
db_val_t db_vals[NR_KEYS];
static char fromip_buff[IP_ADDR_MAX_STR_SIZE+12];
static char toip_buff[IP_ADDR_MAX_STR_SIZE+12];
struct sip_msg* msg;
int_str avp_value;
struct usr_avp *avp;
struct ip_addr to_ip;
int len;
str *sbuf;
struct dest_info *dst;
if(t==NULL || ps==NULL)
{
DBG("trace_onreq_out: no uas request, local transaction\n");
return;
}
msg=ps->req;
if(msg==NULL)
{
DBG("trace_onreq_out: no uas msg, local transaction\n");
return;
}
avp = NULL;
if(traced_user_avp.n!=0)
avp=search_first_avp(traced_user_avp_type, traced_user_avp,
&avp_value, 0);
if((avp==NULL) && trace_is_off(msg) )
{
DBG("trace_onreq_out: trace off...\n");
return;
}
if(parse_from_header(msg)==-1 || msg->from==NULL || get_from(msg)==NULL)
{
LOG(L_ERR, "trace_onreq_out: ERROR cannot parse FROM header\n");
goto error;
}
if(parse_headers(msg, HDR_CALLID_F, 0)!=0)
{
LOG(L_ERR, "trace_onreq_out: ERROR cannot parse call-id\n");
return;
}
db_keys[0] = msg_column;
db_vals[0].type = DB_BLOB;
db_vals[0].nul = 0;
sbuf = (str*)ps->extra1;
if(sbuf!=NULL && sbuf->len>0)
{
db_vals[0].val.blob_val.s = sbuf->s;
db_vals[0].val.blob_val.len = sbuf->len;
} else {
db_vals[0].val.blob_val.s = "No request buffer";
db_vals[0].val.blob_val.len = sizeof("No request buffer")-1;
}
/* check Call-ID header */
if(msg->callid==NULL || msg->callid->body.s==NULL)
{
LOG(L_ERR, "trace_onreq_out: ERROR cannot find Call-ID header!\n");
goto error;
}
db_keys[1] = callid_column;
db_vals[1].type = DB_STR;
db_vals[1].nul = 0;
db_vals[1].val.str_val.s = msg->callid->body.s;
db_vals[1].val.str_val.len = msg->callid->body.len;
db_keys[2] = method_column;
db_vals[2].type = DB_STR;
db_vals[2].nul = 0;
sbuf = (str*)ps->extra1;
if(sbuf!=NULL && sbuf->len > 7 && !strncasecmp(sbuf->s, "CANCEL ", 7))
{
db_vals[2].val.str_val.s = "CANCEL";
db_vals[2].val.str_val.len = 6;
} else {
db_vals[2].val.str_val.s = t->method.s;
db_vals[2].val.str_val.len = t->method.len;
}
db_keys[3] = status_column;
db_vals[3].type = DB_STR;
db_vals[3].nul = 0;
db_vals[3].val.str_val.s = "";
db_vals[3].val.str_val.len = 0;
db_keys[4] = fromip_column;
db_vals[4].type = DB_STRING;
db_vals[4].nul = 0;
if (trace_local_ip)
db_vals[4].val.string_val = trace_local_ip;
else {
strcpy(fromip_buff, ip_addr2a(&msg->rcv.dst_ip));
strcat(fromip_buff,":");
strcat(fromip_buff, int2str(msg->rcv.dst_port, NULL));
db_vals[4].val.string_val = fromip_buff;
}
db_keys[5] = toip_column;
db_vals[5].type = DB_STRING;
db_vals[5].nul = 0;
memset(&to_ip, 0, sizeof(struct ip_addr));
dst = (struct dest_info*)ps->extra2;
if(dst==0)
{
db_vals[5].val.string_val = "255.255.255.255";
} else {
su2ip_addr(&to_ip, &dst->to);
if(dst->proto==PROTO_TCP) {
memcpy(toip_buff, "tcp:", 4);
} else if(dst->proto==PROTO_TLS) {
memcpy(toip_buff, "tls:", 4);
} else {
memcpy(toip_buff, "udp:", 4);
}
strcpy(toip_buff+4, ip_addr2a(&to_ip));
strcat(toip_buff+4, ":");
strcat(toip_buff+4,
int2str((unsigned long)su_getport(&dst->to), &len));
DBG("siptrace:trace_onreq_out: dest [%s]\n", toip_buff);
db_vals[5].val.string_val = toip_buff;
}
db_keys[6] = date_column;
db_vals[6].type = DB_DATETIME;
db_vals[6].nul = 0;
db_vals[6].val.int_val = time(NULL);
db_keys[7] = direction_column;
db_vals[7].type = DB_STRING;
db_vals[7].nul = 0;
db_vals[7].val.string_val = "out";
db_keys[8] = fromtag_column;
db_vals[8].type = DB_STR;
db_vals[8].nul = 0;
db_vals[8].val.str_val.s = get_from(msg)->tag_value.s;
db_vals[8].val.str_val.len = get_from(msg)->tag_value.len;
db_funcs.use_table(db_con, siptrace_get_table());
db_keys[9] = traced_user_column;
db_vals[9].type = DB_STR;
db_vals[9].nul = 0;
if( !trace_is_off(msg) ) {
db_vals[9].val.str_val.s = "";
db_vals[9].val.str_val.len = 0;
DBG("trace_onreq_out: storing info...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "trace_onreq_out: error storing trace\n");
goto error;
}
#ifdef STATISTICS
update_stat(siptrace_req, 1);
#endif
}
if(avp==NULL)
goto done;
trace_send_duplicate(db_vals[0].val.blob_val.s,
db_vals[0].val.blob_val.len);
db_vals[9].val.str_val.s = avp_value.s.s;
db_vals[9].val.str_val.len = avp_value.s.len;
DBG("trace_onreq_out: storing info...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "trace_onreq_out: error storing trace\n");
goto error;
}
avp = search_next_avp( avp, &avp_value);
while(avp!=NULL)
{
db_vals[9].val.str_val.s = avp_value.s.s;
db_vals[9].val.str_val.len = avp_value.s.len;
DBG("trace_onreq_out: storing info...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "trace_onreq_out: error storing trace\n");
goto error;
}
avp = search_next_avp( avp, &avp_value);
}
done:
return;
error:
return;
}
static void trace_onreply_in(struct cell* t, int type, struct tmcb_params *ps)
{
db_key_t db_keys[NR_KEYS];
db_val_t db_vals[NR_KEYS];
static char fromip_buff[IP_ADDR_MAX_STR_SIZE+12];
static char toip_buff[IP_ADDR_MAX_STR_SIZE+12];
struct sip_msg* msg;
struct sip_msg* req;
int_str avp_value;
struct usr_avp *avp;
char statusbuf[8];
if(t==NULL || t->uas.request==0 || ps==NULL)
{
DBG("trace_onreply_in: no uas request, local transaction\n");
return;
}
req = ps->req;
msg = ps->rpl;
if(msg==NULL || req==NULL)
{
DBG("trace_onreply_in: no reply\n");
return;
}
avp = NULL;
if(traced_user_avp.n!=0)
avp=search_first_avp(traced_user_avp_type, traced_user_avp,
&avp_value, 0);
if((avp==NULL) && trace_is_off(req))
{
DBG("trace_onreply_in: trace off...\n");
return;
}
if(parse_from_header(msg)==-1 || msg->from==NULL || get_from(msg)==NULL)
{
LOG(L_ERR, "trace_onreply_in: ERROR cannot parse FROM header\n");
goto error;
}
if(parse_headers(msg, HDR_CALLID_F, 0)!=0)
{
LOG(L_ERR, "trace_onreply_in: ERROR cannot parse call-id\n");
return;
}
db_keys[0] = msg_column;
db_vals[0].type = DB_BLOB;
db_vals[0].nul = 0;
if(msg->len>0) {
db_vals[0].val.blob_val.s = msg->buf;
db_vals[0].val.blob_val.len = msg->len;
} else {
db_vals[0].val.blob_val.s = "No reply buffer";
db_vals[0].val.blob_val.len = sizeof("No reply buffer")-1;
}
/* check Call-ID header */
if(msg->callid==NULL || msg->callid->body.s==NULL)
{
LOG(L_ERR, "trace_onreply_in: ERROR cannot find Call-ID header!\n");
goto error;
}
db_keys[1] = callid_column;
db_vals[1].type = DB_STR;
db_vals[1].nul = 0;
db_vals[1].val.str_val.s = msg->callid->body.s;
db_vals[1].val.str_val.len = msg->callid->body.len;
db_keys[2] = method_column;
db_vals[2].type = DB_STR;
db_vals[2].nul = 0;
db_vals[2].val.str_val.s = t->method.s;
db_vals[2].val.str_val.len = t->method.len;
db_keys[3] = status_column;
db_vals[3].type = DB_STRING;
db_vals[3].nul = 0;
strcpy(statusbuf, int2str(ps->code, NULL));
db_vals[3].val.string_val = statusbuf;
db_keys[4] = fromip_column;
db_vals[4].type = DB_STRING;
db_vals[4].nul = 0;
strcpy(fromip_buff, ip_addr2a(&msg->rcv.src_ip));
strcat(fromip_buff,":");
strcat(fromip_buff, int2str(msg->rcv.src_port, NULL));
db_vals[4].val.string_val = fromip_buff;
db_keys[5] = toip_column;
db_vals[5].type = DB_STRING;
db_vals[5].nul = 0;
// db_vals[5].val.string_val = ip_addr2a(&msg->rcv.dst_ip);;
if(trace_local_ip)
db_vals[5].val.string_val = trace_local_ip;
else {
if(msg->rcv.proto==PROTO_TCP) {
memcpy(toip_buff, "tcp:", 4);
} else if(msg->rcv.proto==PROTO_TLS) {
memcpy(toip_buff, "tls:", 4);
} else {
memcpy(toip_buff, "udp:", 4);
}
strcpy(toip_buff+4, ip_addr2a(&msg->rcv.dst_ip));
strcat(toip_buff+4,":");
strcat(toip_buff+4, int2str(msg->rcv.dst_port, NULL));
db_vals[5].val.string_val = toip_buff;
}
db_keys[6] = date_column;
db_vals[6].type = DB_DATETIME;
db_vals[6].nul = 0;
db_vals[6].val.int_val = time(NULL);
db_keys[7] = direction_column;
db_vals[7].type = DB_STRING;
db_vals[7].nul = 0;
db_vals[7].val.string_val = "in";
db_keys[8] = fromtag_column;
db_vals[8].type = DB_STR;
db_vals[8].nul = 0;
db_vals[8].val.str_val.s = get_from(msg)->tag_value.s;
db_vals[8].val.str_val.len = get_from(msg)->tag_value.len;
db_funcs.use_table(db_con, siptrace_get_table());
db_keys[9] = traced_user_column;
db_vals[9].type = DB_STR;
db_vals[9].nul = 0;
if( !trace_is_off(req) ) {
db_vals[9].val.str_val.s = "";
db_vals[9].val.str_val.len = 0;
DBG("trace_onreply_in: storing info...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "trace_onreply_out: error storing trace\n");
goto error;
}
}
if(avp==NULL)
goto done;
trace_send_duplicate(db_vals[0].val.blob_val.s,
db_vals[0].val.blob_val.len);
db_vals[9].val.str_val.s = avp_value.s.s;
db_vals[9].val.str_val.len = avp_value.s.len;
DBG("trace_onreply_in: storing info...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "trace_onreply_in: error storing trace\n");
goto error;
}
avp = search_next_avp( avp, &avp_value);
while(avp!=NULL)
{
db_vals[9].val.str_val.s = avp_value.s.s;
db_vals[9].val.str_val.len = avp_value.s.len;
DBG("### - trace_onreply_in: storing info ...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "trace_onreply_in: error storing trace\n");
goto error;
}
avp = search_next_avp( avp, &avp_value);
}
done:
return;
error:
return;
}
static void trace_onreply_out(struct cell* t, int type, struct tmcb_params *ps)
{
db_key_t db_keys[NR_KEYS];
db_val_t db_vals[NR_KEYS];
int faked = 0;
static char fromip_buff[IP_ADDR_MAX_STR_SIZE+12];
static char toip_buff[IP_ADDR_MAX_STR_SIZE+12];
struct sip_msg* msg;
struct sip_msg* req;
int_str avp_value;
struct usr_avp *avp;
struct ip_addr to_ip;
int len;
char statusbuf[8];
str *sbuf;
struct dest_info *dst;
if (t==NULL || t->uas.request==0 || ps==NULL)
{
DBG("trace_onreply_out: no uas request, local transaction\n");
return;
}
avp = NULL;
if(traced_user_avp.n!=0)
avp=search_first_avp(traced_user_avp_type, traced_user_avp,
&avp_value, 0);
if((avp==NULL) && trace_is_off(t->uas.request))
{
DBG("trace_onreply_out: trace off...\n");
return;
}
req = ps->req;
msg = ps->rpl;
if(msg==NULL || msg==FAKED_REPLY)
{
msg = t->uas.request;
faked = 1;
}
if(parse_from_header(msg)==-1 || msg->from==NULL || get_from(msg)==NULL)
{
LOG(L_ERR, "trace_onreply_out: ERROR cannot parse FROM header\n");
goto error;
}
if(parse_headers(msg, HDR_CALLID_F, 0)!=0)
{
LOG(L_ERR, "trace_onreply_out: ERROR cannot parse call-id\n");
return;
}
db_keys[0] = msg_column;
db_vals[0].type = DB_BLOB;
db_vals[0].nul = 0;
sbuf = (str*)ps->extra1;
if(faked==0)
{
if(sbuf!=0 && sbuf->len>0) {
db_vals[0].val.blob_val.s = sbuf->s;
db_vals[0].val.blob_val.len = sbuf->len;
} else if(t->uas.response.buffer.s!=NULL) {
db_vals[0].val.blob_val.s = t->uas.response.buffer.s;
db_vals[0].val.blob_val.len = t->uas.response.buffer.len;
} else if(msg->len>0) {
db_vals[0].val.blob_val.s = msg->buf;
db_vals[0].val.blob_val.len = msg->len;
} else {
db_vals[0].val.blob_val.s = "No reply buffer";
db_vals[0].val.blob_val.len = sizeof("No reply buffer")-1;
}
} else {
if(sbuf!=0 && sbuf->len>0) {
db_vals[0].val.blob_val.s = sbuf->s;
db_vals[0].val.blob_val.len = sbuf->len;
} else if(t->uas.response.buffer.s==NULL) {
db_vals[0].val.blob_val.s = "No reply buffer";
db_vals[0].val.blob_val.len = sizeof("No reply buffer")-1;
} else {
db_vals[0].val.blob_val.s = t->uas.response.buffer.s;
db_vals[0].val.blob_val.len = t->uas.response.buffer.len;
}
}
/* check Call-ID header */
if(msg->callid==NULL || msg->callid->body.s==NULL)
{
LOG(L_ERR, "trace_onreply_out: ERROR cannot find Call-ID header!\n");
goto error;
}
db_keys[1] = callid_column;
db_vals[1].type = DB_STR;
db_vals[1].nul = 0;
db_vals[1].val.str_val.s = msg->callid->body.s;
db_vals[1].val.str_val.len = msg->callid->body.len;
db_keys[2] = method_column;
db_vals[2].type = DB_STR;
db_vals[2].nul = 0;
db_vals[2].val.str_val.s = t->method.s;
db_vals[2].val.str_val.len = t->method.len;
db_keys[4] = fromip_column;
db_vals[4].type = DB_STRING;
db_vals[4].nul = 0;
if(trace_local_ip)
db_vals[4].val.string_val = trace_local_ip;
else {
strcpy(fromip_buff, ip_addr2a(&req->rcv.dst_ip));
strcat(fromip_buff,":");
strcat(fromip_buff, int2str(req->rcv.dst_port, NULL));
db_vals[4].val.string_val = fromip_buff;
}
db_keys[3] = status_column;
db_vals[3].type = DB_STRING;
db_vals[3].nul = 0;
strcpy(statusbuf, int2str(ps->code, NULL));
db_vals[3].val.string_val = statusbuf;
db_keys[5] = toip_column;
db_vals[5].type = DB_STRING;
db_vals[5].nul = 0;
memset(&to_ip, 0, sizeof(struct ip_addr));
dst = (struct dest_info*)ps->extra2;
if(dst==0)
{
db_vals[5].val.string_val = "255.255.255.255";
} else {
su2ip_addr(&to_ip, &dst->to);
if(dst->proto==PROTO_TCP) {
memcpy(toip_buff, "tcp:", 4);
} else if(dst->proto==PROTO_TLS) {
memcpy(toip_buff, "tls:", 4);
} else {
memcpy(toip_buff, "udp:", 4);
}
strcpy(toip_buff+4, ip_addr2a(&to_ip));
strcat(toip_buff+4, ":");
strcat(toip_buff+4,
int2str((unsigned long)su_getport(&dst->to), &len));
DBG("siptrace:trace_onreply_out: dest [%s]\n", toip_buff);
db_vals[5].val.string_val = toip_buff;
}
db_keys[6] = date_column;
db_vals[6].type = DB_DATETIME;
db_vals[6].nul = 0;
db_vals[6].val.int_val = time(NULL);
db_keys[7] = direction_column;
db_vals[7].type = DB_STRING;
db_vals[7].nul = 0;
db_vals[7].val.string_val = "out";
db_keys[8] = fromtag_column;
db_vals[8].type = DB_STR;
db_vals[8].nul = 0;
db_vals[8].val.str_val.s = get_from(msg)->tag_value.s;
db_vals[8].val.str_val.len = get_from(msg)->tag_value.len;
db_funcs.use_table(db_con, siptrace_get_table());
db_keys[9] = traced_user_column;
db_vals[9].type = DB_STR;
db_vals[9].nul = 0;
if( !trace_is_off(req) ) {
db_vals[9].val.str_val.s = "";
db_vals[9].val.str_val.len = 0;
DBG("trace_onreply_out: storing info...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "trace_onreply_out: error storing trace\n");
goto error;
}
}
if(avp==NULL)
goto done;
trace_send_duplicate(db_vals[0].val.blob_val.s,
db_vals[0].val.blob_val.len);
db_vals[9].val.str_val.s = avp_value.s.s;
db_vals[9].val.str_val.len = avp_value.s.len;
DBG("trace_onreply_out: storing info...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "trace_onreply_out: error storing trace\n");
goto error;
}
avp = search_next_avp( avp, &avp_value);
while(avp!=NULL)
{
db_vals[9].val.str_val.s = avp_value.s.s;
db_vals[9].val.str_val.len = avp_value.s.len;
DBG("### - trace_onreply_out: storing info (%d) ...\n", faked);
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "trace_onreply_out: error storing trace\n");
goto error;
}
avp = search_next_avp( avp, &avp_value);
}
done:
return;
error:
return;
}
static void trace_sl_onreply_out(struct sip_msg* req,
struct sl_cb_param *sl_param)
{
db_key_t db_keys[NR_KEYS];
db_val_t db_vals[NR_KEYS];
static char fromip_buff[IP_ADDR_MAX_STR_SIZE+12];
static char toip_buff[IP_ADDR_MAX_STR_SIZE+12];
int faked = 0;
struct sip_msg* msg;
int_str avp_value;
struct usr_avp *avp;
struct ip_addr to_ip;
int len;
char statusbuf[5];
if(req==NULL || sl_param==NULL)
{
LOG(L_ERR, "trace_sl_onreply_out: bad parameters\n");
goto error;
}
avp = NULL;
if(traced_user_avp.n!=0)
avp=search_first_avp(traced_user_avp_type, traced_user_avp,
&avp_value, 0);
if((avp==NULL) && trace_is_off(req))
{
DBG("trace_sl_onreply_out: trace off...\n");
return;
}
msg = req;
faked = 1;
if(parse_from_header(msg)==-1 || msg->from==NULL || get_from(msg)==NULL)
{
LOG(L_ERR, "trace_sl_onreply_out: ERROR cannot parse FROM header\n");
goto error;
}
if(parse_headers(msg, HDR_CALLID_F, 0)!=0)
{
LOG(L_ERR, "trace_sl_onreply_out: ERROR cannot parse call-id\n");
return;
}
db_keys[0] = msg_column;
db_vals[0].type = DB_BLOB;
db_vals[0].nul = 0;
db_vals[0].val.blob_val.s = (sl_param->buffer)?sl_param->buffer->s:"";
db_vals[0].val.blob_val.len = (sl_param->buffer)?sl_param->buffer->len:0;
/* check Call-ID header */
if(msg->callid==NULL || msg->callid->body.s==NULL)
{
LOG(L_ERR, "trace_sl_onreply_out: ERROR cannot find Call-ID header!\n");
goto error;
}
db_keys[1] = callid_column;
db_vals[1].type = DB_STR;
db_vals[1].nul = 0;
db_vals[1].val.str_val.s = msg->callid->body.s;
db_vals[1].val.str_val.len = msg->callid->body.len;
db_keys[2] = method_column;
db_vals[2].type = DB_STR;
db_vals[2].nul = 0;
db_vals[2].val.str_val.s = msg->first_line.u.request.method.s;
db_vals[2].val.str_val.len = msg->first_line.u.request.method.len;
db_keys[4] = fromip_column;
db_vals[4].type = DB_STRING;
db_vals[4].nul = 0;
if(trace_local_ip)
db_vals[4].val.string_val = trace_local_ip;
else {
strcpy(fromip_buff, ip_addr2a(&req->rcv.dst_ip));
strcat(fromip_buff,":");
strcat(fromip_buff, int2str(req->rcv.dst_port, NULL));
db_vals[4].val.string_val = fromip_buff;
}
db_keys[3] = status_column;
db_vals[3].type = DB_STRING;
db_vals[3].nul = 0;
strcpy(statusbuf, int2str(sl_param->code, NULL));
db_vals[3].val.string_val = statusbuf;
db_keys[5] = toip_column;
db_vals[5].type = DB_STRING;
db_vals[5].nul = 0;
memset(&to_ip, 0, sizeof(struct ip_addr));
if(sl_param->dst==0)
{
db_vals[5].val.string_val = "255.255.255.255";
} else {
su2ip_addr(&to_ip, sl_param->dst);
if(req->rcv.proto==PROTO_TCP) {
memcpy(toip_buff, "tcp:", 4);
} else if(req->rcv.proto==PROTO_TLS) {
memcpy(toip_buff, "tls:", 4);
} else {
memcpy(toip_buff, "udp:", 4);
}
strcpy(toip_buff+4, ip_addr2a(&to_ip));
strcat(toip_buff+4, ":");
strcat(toip_buff+4,
int2str((unsigned long)su_getport(sl_param->dst), &len));
DBG("siptrace:trace_sl_onreply_out: dest [%s]\n", toip_buff);
db_vals[5].val.string_val = toip_buff;
}
db_keys[6] = date_column;
db_vals[6].type = DB_DATETIME;
db_vals[6].nul = 0;
db_vals[6].val.int_val = time(NULL);
db_keys[7] = direction_column;
db_vals[7].type = DB_STRING;
db_vals[7].nul = 0;
db_vals[7].val.string_val = "out";
db_keys[8] = fromtag_column;
db_vals[8].type = DB_STR;
db_vals[8].nul = 0;
db_vals[8].val.str_val.s = get_from(msg)->tag_value.s;
db_vals[8].val.str_val.len = get_from(msg)->tag_value.len;
db_funcs.use_table(db_con, siptrace_get_table());
db_keys[9] = traced_user_column;
db_vals[9].type = DB_STR;
db_vals[9].nul = 0;
if( !trace_is_off(msg) ) {
db_vals[9].val.str_val.s = "";
db_vals[9].val.str_val.len = 0;
DBG("trace_sl_onreply_out: storing info...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "trace_sl_onreply_out: error storing trace\n");
goto error;
}
}
if(avp==NULL)
goto done;
trace_send_duplicate(db_vals[0].val.blob_val.s,
db_vals[0].val.blob_val.len);
db_vals[9].val.str_val.s = avp_value.s.s;
db_vals[9].val.str_val.len = avp_value.s.len;
DBG("trace_sl_onreply_out: storing info...\n");
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "trace_sl_onreply_out: error storing trace\n");
goto error;
}
avp = search_next_avp( avp, &avp_value);
while(avp!=NULL)
{
db_vals[9].val.str_val.s = avp_value.s.s;
db_vals[9].val.str_val.len = avp_value.s.len;
DBG("### - trace_sl_onreply_out: storing info (%d) ...\n", faked);
if(db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0)
{
LOG(L_ERR, "trace_sl_onreply_out: error storing trace\n");
goto error;
}
avp = search_next_avp( avp, &avp_value);
}
done:
return;
error:
return;
}
/**
* MI command format:
* name: sip_trace
* attribute: name=none, value=[on|off]
*/
static struct mi_root* sip_trace_mi(struct mi_root* cmd_tree, void* param )
{
struct mi_node* node;
node = cmd_tree->node.kids;
if(node == NULL)
return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
if(trace_on_flag==NULL)
return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
if ( node->value.len==2 &&
(node->value.s[0]=='o'|| node->value.s[0]=='O') &&
(node->value.s[1]=='n'|| node->value.s[1]=='N'))
{
*trace_on_flag = 1;
return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
} else if ( node->value.len==3 &&
(node->value.s[0]=='o'|| node->value.s[0]=='O') &&
(node->value.s[1]=='f'|| node->value.s[1]=='F') &&
(node->value.s[2]=='f'|| node->value.s[2]=='F'))
{
*trace_on_flag = 0;
return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
} else {
return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
}
}
static int trace_send_duplicate(char *buf, int len)
{
union sockaddr_union* to;
struct socket_info* send_sock;
struct proxy_l * p;
int proto;
int ret;
if(buf==NULL || len <= 0)
return -1;
if(dup_uri_str.s==0 || dup_uri==NULL)
return 0;
to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union));
if (to==0){
LOG(L_ERR, "trace_send_duplicate:ERROR: out of memory\n");
return -1;
}
/* create a temporary proxy*/
proto = PROTO_UDP;
p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,
proto, 0);
if (p==0){
LOG(L_ERR, "trace_send_duplicate:ERROR: bad host name in uri\n");
pkg_free(to);
return -1;
}
hostent2su(to, &p->host, p->addr_idx,
(p->port)?p->port:SIP_PORT);
ret = -1;
do {
send_sock=get_send_socket(0, to, proto);
if (send_sock==0){
LOG(L_ERR,
"trace_send_duplicate:ERROR: cannot forward to af %d, proto %d"
" no corresponding listening socket\n", to->s.sa_family,proto);
continue;
}
if (msg_send(send_sock, proto, to, 0, buf, len)<0){
LOG(L_ERR,
"trace_send_duplicate:ERROR: cannot send duplicate message\n");
continue;
}
ret = 0;
break;
}while( get_next_su( p, to, 0)==0 );
free_proxy(p); /* frees only p content, not p itself */
pkg_free(p);
pkg_free(to);
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1