|
@@ -40,6 +40,13 @@
|
|
|
#include <net/if.h>
|
|
|
#include <netdb.h>
|
|
|
|
|
|
+#ifndef __USE_BSD
|
|
|
+#define __USE_BSD /* on linux use bsd version of iphdr (more portable) */
|
|
|
+#endif /* __USE_BSD */
|
|
|
+#include <netinet/ip.h>
|
|
|
+#define __FAVOR_BSD /* on linux use bsd version of udphdr (more portable) */
|
|
|
+#include <netinet/udp.h>
|
|
|
+
|
|
|
#include "../../sr_module.h"
|
|
|
#include "../../dprint.h"
|
|
|
#include "../../events.h"
|
|
@@ -62,13 +69,9 @@
|
|
|
#include "../../raw_sock.h"
|
|
|
#include "../../raw_listener.h"
|
|
|
#include "../../resolve.h"
|
|
|
+#include "../../receive.h"
|
|
|
#include "sipcapture.h"
|
|
|
|
|
|
-#ifdef __OS_linux
|
|
|
- #include <sys/ioctl.h>
|
|
|
- #include <net/if.h>
|
|
|
-#endif
|
|
|
-
|
|
|
#ifdef STATISTICS
|
|
|
#include "../../lib/kcore/statistics.h"
|
|
|
#endif
|
|
@@ -130,6 +133,9 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2);
|
|
|
int hep_msg_received(void *data);
|
|
|
int init_rawsock_children(void);
|
|
|
int extract_host_port(void);
|
|
|
+int raw_moni_socket(str* iface, int port_start, int port_end);
|
|
|
+int raw_moni_rcv_loop(int rsock, int port1, int port2);
|
|
|
+
|
|
|
|
|
|
|
|
|
static struct mi_root* sip_capture_mi(struct mi_root* cmd, void* param );
|
|
@@ -189,6 +195,7 @@ int *capture_on_flag = NULL;
|
|
|
int db_insert_mode = 0;
|
|
|
int partitioning_mode = 1;
|
|
|
int promisc_on = 0;
|
|
|
+int bpf_on = 0;
|
|
|
|
|
|
str raw_socket_listen = { 0, 0 };
|
|
|
str raw_interface = { 0, 0 };
|
|
@@ -263,6 +270,7 @@ static param_export_t params[] = {
|
|
|
{"partitioning_mode", INT_PARAM, &partitioning_mode },
|
|
|
{"raw_interface", STR_PARAM, &raw_interface.s },
|
|
|
{"promiscious_on", INT_PARAM, &promisc_on },
|
|
|
+ {"raw_moni_bpf_on", INT_PARAM, &bpf_on },
|
|
|
{0, 0, 0}
|
|
|
};
|
|
|
|
|
@@ -428,12 +436,13 @@ static int mod_init(void) {
|
|
|
{
|
|
|
LM_ERR("sipcapture mod_init: bad RAW IP: %.*s\n", raw_socket_listen.len, raw_socket_listen.s);
|
|
|
return -1;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- raw_sock_desc = raw_socket(ipip_capture_on ? IPPROTO_IPIP : IPPROTO_UDP ,
|
|
|
- raw_socket_listen.len ? ip : 0, raw_interface.len ? &raw_interface : 0, 0);
|
|
|
-
|
|
|
+ }
|
|
|
+
|
|
|
+ raw_sock_desc = ipip_capture_on ? raw_socket( IPPROTO_IPIP, raw_socket_listen.len ? ip : 0,
|
|
|
+ raw_interface.len ? &raw_interface : 0, 0) :
|
|
|
+ raw_moni_socket(raw_interface.len ? &raw_interface : 0,
|
|
|
+ moni_port_start, moni_port_end ? moni_port_end : moni_port_start);
|
|
|
+
|
|
|
if(raw_sock_desc < 0) {
|
|
|
LM_ERR("could not initialize raw udp socket:"
|
|
|
" %s (%d)\n", strerror(errno), errno);
|
|
@@ -451,6 +460,8 @@ static int mod_init(void) {
|
|
|
|
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
|
memcpy(ifr.ifr_name, raw_interface.s, raw_interface.len);
|
|
|
+
|
|
|
+
|
|
|
#ifdef __OS_linux
|
|
|
if(ioctl(raw_sock_desc, SIOCGIFFLAGS, &ifr) < 0) {
|
|
|
LM_ERR("could not get flags from interface [%.*s]:"
|
|
@@ -535,8 +546,10 @@ int init_rawsock_children(void)
|
|
|
ERR("Unable to fork: %s\n", strerror(errno));
|
|
|
return -1;
|
|
|
} else if (pid == 0) { /* child */
|
|
|
- raw_udp4_rcv_loop(raw_sock_desc, moni_capture_on ? moni_port_start : 0,
|
|
|
- moni_capture_on ? moni_port_end : 0);
|
|
|
+ if(moni_capture_on)
|
|
|
+ raw_moni_rcv_loop(raw_sock_desc, moni_port_start, moni_port_end);
|
|
|
+ else
|
|
|
+ raw_udp4_rcv_loop(raw_sock_desc, 0, 0);
|
|
|
}
|
|
|
/* Parent */
|
|
|
}
|
|
@@ -731,6 +744,7 @@ static int sip_capture_store(struct _sipcapture_object *sco)
|
|
|
char tmptable[TABLE_LEN];
|
|
|
int ret = 0;
|
|
|
struct tm *t;
|
|
|
+ str dbtable;
|
|
|
|
|
|
if(sco==NULL)
|
|
|
{
|
|
@@ -755,7 +769,7 @@ static int sip_capture_store(struct _sipcapture_object *sco)
|
|
|
db_keys[2] = µ_ts_column;
|
|
|
db_vals[2].type = DB1_BIGINT;
|
|
|
db_vals[2].nul = 0;
|
|
|
- db_vals[2].val.ll_val = (unsigned long long)(tvb.tv_sec*1000000+tvb.tv_usec); /* micro ts */
|
|
|
+ db_vals[2].val.ll_val = (unsigned long long)tvb.tv_sec*1000000+tvb.tv_usec; /* micro ts */
|
|
|
|
|
|
db_keys[3] = &method_column;
|
|
|
db_vals[3].type = DB1_STR;
|
|
@@ -927,6 +941,7 @@ static int sip_capture_store(struct _sipcapture_object *sco)
|
|
|
db_vals[36].nul = 0;
|
|
|
db_vals[36].val.blob_val = sco->msg;
|
|
|
|
|
|
+ DBG("TABLE =====================: [%.*s]\n", table_name.len, table_name.s);
|
|
|
if(!partitioning_mode) {
|
|
|
ret = snprintf(tmptable, TABLE_LEN, "%.*s_%02d_%02d",
|
|
|
table_name.len, table_name.s, (t->tm_wday == 0) ? 7 : t->tm_wday , t->tm_hour);
|
|
@@ -935,14 +950,17 @@ static int sip_capture_store(struct _sipcapture_object *sco)
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- table_name.s = tmptable;
|
|
|
- table_name.len = strlen(tmptable);
|
|
|
+ dbtable.s = tmptable;
|
|
|
+ dbtable.len = strlen(tmptable);
|
|
|
}
|
|
|
-
|
|
|
- db_funcs.use_table(db_con, &table_name);
|
|
|
+ else {
|
|
|
+ dbtable = table_name;
|
|
|
+ }
|
|
|
+
|
|
|
+ db_funcs.use_table(db_con, &dbtable);
|
|
|
|
|
|
LM_DBG("storing info...\n");
|
|
|
-
|
|
|
+
|
|
|
if(db_insert_mode==1 && db_funcs.insert_delayed!=NULL) {
|
|
|
if (db_funcs.insert_delayed(db_con, db_keys, db_vals, NR_KEYS) < 0) {
|
|
|
LM_ERR("failed to insert delayed into database\n");
|
|
@@ -1053,38 +1071,29 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
|
|
|
EMPTY_STR(sco.to_tag);
|
|
|
}
|
|
|
|
|
|
+ /* Call-id */
|
|
|
+ if(msg->callid) sco.callid = msg->callid->body;
|
|
|
+ else { EMPTY_STR(sco.callid); }
|
|
|
+
|
|
|
/* P-Asserted-Id */
|
|
|
- if(msg->pai) {
|
|
|
-
|
|
|
- if(parse_pai_header(msg)==-1)
|
|
|
- {
|
|
|
- LM_DBG("no P-Asserted-Identity header\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ if(msg->pai && (parse_pai_header(msg) == 0)) {
|
|
|
|
|
|
if (parse_uri(get_pai(msg)->uri.s, get_pai(msg)->uri.len, &pai)<0){
|
|
|
- LOG(L_ERR, "ERROR: do_action: bad pai dropping"" packet\n");
|
|
|
- return -1;
|
|
|
+ LM_DBG("DEBUG: do_action: bad pai: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ LM_DBG("PARSE PAI: (%.*s)\n",get_pai(msg)->uri.len, get_pai(msg)->uri.s);
|
|
|
+ sco.pid_user = pai.user;
|
|
|
}
|
|
|
-
|
|
|
- LM_DBG("PARSE PAI: (%.*s)\n",get_pai(msg)->uri.len, get_pai(msg)->uri.s);
|
|
|
-
|
|
|
- sco.pid_user = pai.user;
|
|
|
}
|
|
|
- else if(msg->ppi) {
|
|
|
-
|
|
|
- if(parse_ppi_header(msg)==-1)
|
|
|
- {
|
|
|
- LM_DBG("no P-Preferred-Identity header\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ else if(msg->ppi && (parse_ppi_header(msg) == 0)) {
|
|
|
|
|
|
if (parse_uri(get_ppi(msg)->uri.s, get_ppi(msg)->uri.len, &pai)<0){
|
|
|
- LOG(L_ERR, "ERROR: do_action: bad ppi dropping"" packet\n");
|
|
|
- return -1;
|
|
|
+ LM_DBG("DEBUG: do_action: bad ppi: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ sco.pid_user = pai.user;
|
|
|
}
|
|
|
-
|
|
|
- sco.pid_user = pai.user;
|
|
|
}
|
|
|
else { EMPTY_STR(sco.pid_user); }
|
|
|
|
|
@@ -1115,11 +1124,6 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /* Call-id */
|
|
|
- if(msg->callid) sco.callid = msg->callid->body;
|
|
|
- else { EMPTY_STR(sco.callid); }
|
|
|
-
|
|
|
-
|
|
|
/* get header x-cid: */
|
|
|
/* callid_aleg X-CID */
|
|
|
if((tmphdr[0] = get_hdr_by_name(msg,"X-CID", 5)) != NULL) {
|
|
@@ -1167,7 +1171,6 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
|
|
|
}
|
|
|
|
|
|
/* X-OIP */
|
|
|
- //if(msg->xoip) {
|
|
|
if((tmphdr[2] = get_hdr_by_name(msg,"X-OIP", 5)) != NULL) {
|
|
|
sco.originator_ip = tmphdr[2]->body;
|
|
|
/* Originator port. Should be parsed from XOIP header as ":" param */
|
|
@@ -1293,3 +1296,157 @@ static struct mi_root* sip_capture_mi(struct mi_root* cmd_tree, void* param )
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+int raw_moni_socket(str* iface, int port_start, int port_end)
|
|
|
+{
|
|
|
+ int sock;
|
|
|
+
|
|
|
+#if defined (SO_BINDTODEVICE)
|
|
|
+ char short_ifname[sizeof(int)];
|
|
|
+ int ifname_len;
|
|
|
+ char* ifname;
|
|
|
+#endif /* SO_BINDTODEVICE */
|
|
|
+
|
|
|
+ //0x0003 - all packets
|
|
|
+ sock = socket(PF_PACKET, SOCK_RAW, htons(0x0800));
|
|
|
+
|
|
|
+ if (sock==-1)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ /* set socket options */
|
|
|
+ if (iface && iface->s){
|
|
|
+#if defined (SO_BINDTODEVICE)
|
|
|
+ /* workaround for linux bug: arg to setsockopt must have at least
|
|
|
+ * sizeof(int) size or EINVAL would be returned */
|
|
|
+ if (iface->len<sizeof(int)){
|
|
|
+ memcpy(short_ifname, iface->s, iface->len);
|
|
|
+ short_ifname[iface->len]=0; /* make sure it's zero term */
|
|
|
+ ifname_len=sizeof(short_ifname);
|
|
|
+ ifname=short_ifname;
|
|
|
+ }else{
|
|
|
+ ifname_len=iface->len;
|
|
|
+ ifname=iface->s;
|
|
|
+ }
|
|
|
+ if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, ifname_len)
|
|
|
+ <0){
|
|
|
+ ERR("raw_socket: could not bind to %.*s: %s [%d]\n",
|
|
|
+ iface->len, ZSW(iface->s), strerror(errno), errno);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+#else /* !SO_BINDTODEVICE */
|
|
|
+ /* SO_BINDTODEVICE is linux specific => cannot bind to a device */
|
|
|
+ ERR("raw_socket: bind to device supported only on linux\n");
|
|
|
+ goto error;
|
|
|
+#endif /* SO_BINDTODEVICE */
|
|
|
+ }
|
|
|
+
|
|
|
+ if(bpf_on) {
|
|
|
+
|
|
|
+ /* Start PORT */
|
|
|
+ BPF_code[5] = (struct my_sock_filter)BPF_JUMP(0x35, port_start, 0, 1);
|
|
|
+ BPF_code[8] = (struct my_sock_filter)BPF_JUMP(0x35, port_start, 11, 13);
|
|
|
+ BPF_code[16] = (struct my_sock_filter)BPF_JUMP(0x35, port_start, 0, 1);
|
|
|
+ BPF_code[19] = (struct my_sock_filter)BPF_JUMP(0x35, port_start, 0, 2);
|
|
|
+ /* Stop PORT */
|
|
|
+ BPF_code[6] = (struct my_sock_filter)BPF_JUMP(0x25, port_end, 0, 14);
|
|
|
+ BPF_code[17] = (struct my_sock_filter)BPF_JUMP(0x25, port_end, 0, 3);
|
|
|
+ BPF_code[20] = (struct my_sock_filter)BPF_JUMP(0x25, port_end, 1, 0);
|
|
|
+
|
|
|
+ /* Attach the filter to the socket */
|
|
|
+ if(setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter)) < 0 ) {
|
|
|
+ ERR(" setsockopt filter: [%s] [%d]\n", strerror(errno), errno);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return sock;
|
|
|
+error:
|
|
|
+ if (sock!=-1) close(sock);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int raw_moni_rcv_loop(int rsock, int port1, int port2) {
|
|
|
+
|
|
|
+ static char buf [BUF_SIZE+1];
|
|
|
+ union sockaddr_union from;
|
|
|
+ union sockaddr_union to;
|
|
|
+ struct receive_info ri;
|
|
|
+ int len;
|
|
|
+ struct ip *iph;
|
|
|
+ struct udphdr *udph;
|
|
|
+ int offset = 0;
|
|
|
+ char* end;
|
|
|
+ unsigned short dst_port;
|
|
|
+ unsigned short src_port;
|
|
|
+ struct ip_addr dst_ip, src_ip;
|
|
|
+
|
|
|
+ for(;;){
|
|
|
+
|
|
|
+ len = recvfrom(rsock, buf, BUF_SIZE, 0x20, 0, 0);
|
|
|
+
|
|
|
+ if (len<0){
|
|
|
+ if (len==-1){
|
|
|
+ LOG(L_ERR, "ERROR: raw_moni_rcv_loop:recvfrom: %s [%d]\n",
|
|
|
+ strerror(errno), errno);
|
|
|
+ if ((errno==EINTR)||(errno==EWOULDBLOCK))
|
|
|
+ continue;
|
|
|
+ }else{
|
|
|
+ DBG("raw_moni_rcv_loop: recvfrom error: %d\n", len);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ end=buf+len;
|
|
|
+
|
|
|
+
|
|
|
+ if (unlikely(len<(sizeof(struct ip)+sizeof(struct udphdr) + ETHHDR))) {
|
|
|
+ LOG(L_ERR, "ERROR: small packet: %d\n",len);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ offset = ETHHDR;
|
|
|
+
|
|
|
+ iph = (struct ip*) (buf + offset);
|
|
|
+ offset+=iph->ip_hl*4;
|
|
|
+
|
|
|
+ udph = (struct udphdr*)(buf + offset);
|
|
|
+ offset +=sizeof(struct udphdr);
|
|
|
+
|
|
|
+ if (unlikely((buf+offset)>end)){
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /*FIL IPs*/
|
|
|
+ dst_ip.af=AF_INET;
|
|
|
+ dst_ip.len=4;
|
|
|
+ dst_ip.u.addr32[0]=iph->ip_dst.s_addr;
|
|
|
+ /* fill dst_port */
|
|
|
+ dst_port=ntohs(udph->uh_dport);
|
|
|
+ ip_addr2su(&to, &dst_ip, dst_port);
|
|
|
+ /* fill src_port */
|
|
|
+ src_port=ntohs(udph->uh_sport);
|
|
|
+ src_ip.af=AF_INET;
|
|
|
+ src_ip.len=4;
|
|
|
+ src_ip.u.addr32[0]=iph->ip_src.s_addr;
|
|
|
+ ip_addr2su(&from, &src_ip, src_port);
|
|
|
+ su_setport(&from, src_port);
|
|
|
+
|
|
|
+ ri.src_su=from;
|
|
|
+ su2ip_addr(&ri.src_ip, &from);
|
|
|
+ ri.src_port=src_port;
|
|
|
+ su2ip_addr(&ri.dst_ip, &to);
|
|
|
+ ri.dst_port=dst_port;
|
|
|
+
|
|
|
+ /* cut off the offset */
|
|
|
+ len -= offset;
|
|
|
+
|
|
|
+ if (len<MIN_UDP_PACKET){
|
|
|
+ DBG("raw_udp4_rcv_loop: probing packet received from\n");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if((src_port >= port1 && src_port <= port2) || (dst_port >= port1 && dst_port <= port2))
|
|
|
+ receive_msg(buf+offset, len, &ri);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|