From 7464a86e1cb123202947848365143046f92c058b Mon Sep 17 00:00:00 2001 From: ionutrazvanionita Date: Tue, 16 Feb 2016 13:29:19 +0200 Subject: [PATCH 1/5] have a predefined context before calling receive_msg --- modules/proto_hep/proto_hep.c | 4 ++-- modules/proto_sctp/sctp_server.c | 2 +- modules/proto_ws/ws_common.h | 2 +- net/proto_tcp/tcp_common.h | 2 +- net/proto_udp/proto_udp.c | 2 +- receive.c | 16 +++++++++++----- receive.h | 4 +++- 7 files changed, 20 insertions(+), 12 deletions(-) diff --git a/modules/proto_hep/proto_hep.c b/modules/proto_hep/proto_hep.c index 5f2dd327bf6..a3164608409 100644 --- a/modules/proto_hep/proto_hep.c +++ b/modules/proto_hep/proto_hep.c @@ -894,7 +894,7 @@ static inline int hep_handle_req(struct tcp_req *req, /* skip receive msg if we were told so from at least one callback */ if (ret != HEP_SCRIPT_SKIP && - receive_msg(msg_buf, msg_len, &local_rcv) <0) + receive_msg(msg_buf, msg_len, &local_rcv, NULL) <0) LM_ERR("receive_msg failed \n"); if (!size && req != &hep_current_req) { @@ -1192,7 +1192,7 @@ static int hep_udp_read_req(struct socket_info *si, int* bytes_read) if (ret != HEP_SCRIPT_SKIP) { /* receive_msg must free buf too!*/ - receive_msg( msg.s, msg.len, &ri); + receive_msg( msg.s, msg.len, &ri, NULL); } return 0; diff --git a/modules/proto_sctp/sctp_server.c b/modules/proto_sctp/sctp_server.c index 8c3400265f4..e056049efd4 100644 --- a/modules/proto_sctp/sctp_server.c +++ b/modules/proto_sctp/sctp_server.c @@ -193,7 +193,7 @@ int proto_sctp_read(struct socket_info *si, int* bytes_read) } /* receive_msg must free buf too!*/ - receive_msg(buf, len, &ri); + receive_msg(buf, len, &ri, NULL); return 0; } diff --git a/modules/proto_ws/ws_common.h b/modules/proto_ws/ws_common.h index 779ed71b362..808e8a6e941 100644 --- a/modules/proto_ws/ws_common.h +++ b/modules/proto_ws/ws_common.h @@ -531,7 +531,7 @@ static int ws_process(struct tcp_connection *con) "keeping connection \n"); } - if (receive_msg(msg_buf, msg_len, &local_rcv) <0) + if (receive_msg(msg_buf, msg_len, &local_rcv, NULL) <0) LM_ERR("receive_msg failed \n"); *req->tcp.parsed = bk; diff --git a/net/proto_tcp/tcp_common.h b/net/proto_tcp/tcp_common.h index 4f70d0e4a0c..d4953b949c9 100644 --- a/net/proto_tcp/tcp_common.h +++ b/net/proto_tcp/tcp_common.h @@ -411,7 +411,7 @@ static inline int tcp_handle_req(struct tcp_req *req, } if (receive_msg(msg_buf, msg_len, - &local_rcv) <0) + &local_rcv, NULL) <0) LM_ERR("receive_msg failed \n"); if (!size && req != &_tcp_common_current_req) { diff --git a/net/proto_udp/proto_udp.c b/net/proto_udp/proto_udp.c index 36c61374181..7cfe28a5e4b 100644 --- a/net/proto_udp/proto_udp.c +++ b/net/proto_udp/proto_udp.c @@ -187,7 +187,7 @@ static int udp_read_req(struct socket_info *si, int* bytes_read) } /* receive_msg must free buf too!*/ - receive_msg( msg.s, msg.len, &ri); + receive_msg( msg.s, msg.len, &ri, NULL); return 0; } diff --git a/receive.c b/receive.c index 913c1f302ad..27ddf5ea421 100644 --- a/receive.c +++ b/receive.c @@ -96,7 +96,8 @@ unsigned int get_next_msg_no(void) /*! \note WARNING: buf must be 0 terminated (buf[len]=0) or some things might * break (e.g.: modules/textops) */ -int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) +int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info, + context_p existing_context) { static context_p ctx = NULL; struct sip_msg* msg; @@ -107,6 +108,7 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) in_buff.len = len; in_buff.s = buf; + ctx = existing_context; /* the raw processing callbacks can change the buffer, further use in_buff.s and at the end try to free in_buff.s @@ -172,8 +174,10 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) /* set request route type --bogdan*/ set_route_type( REQUEST_ROUTE ); - /* prepare and set a new processing context for this request */ - prepare_context( ctx, parse_error ); + /* prepare and set a new processing context for this request only if + * no context was set from the upper layers */ + if (existing_context == NULL) + prepare_context( ctx, parse_error ); current_processing_ctx = ctx; /* execute pre-script callbacks, if any; @@ -213,8 +217,10 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) /* set reply route type --bogdan*/ set_route_type( ONREPLY_ROUTE ); - /* prepare and set a new processing context for this reply */ - prepare_context( ctx, parse_error ); + /* prepare and set a new processing context for this reply only if + * no context was set from the upper layers */ + if (existing_context == NULL) + prepare_context( ctx, parse_error ); current_processing_ctx = ctx; /* execute pre-script callbacks, if any ; diff --git a/receive.h b/receive.h index 811de8a41a7..1968bb4a228 100644 --- a/receive.h +++ b/receive.h @@ -28,8 +28,10 @@ #define receive_h #include "ip_addr.h" +#include "context.h" -int receive_msg(char* buf, unsigned int len, struct receive_info *ri); +int receive_msg(char* buf, unsigned int len, struct receive_info *ri, + context_p existing_context); unsigned int get_next_msg_no(void); From 1714db5372eac50063b71a45603730d14dac6150 Mon Sep 17 00:00:00 2001 From: ionutrazvanionita Date: Tue, 23 Feb 2016 17:19:58 +0200 Subject: [PATCH 2/5] [proto_hep]custom chunks, predefined context, bug fixes * proto_hep can now read custom chunks; * use 0x0000 vendor id for generic chunks instead of OpenSIPS vendor id; * what was being done in sipcapture(modify receive_info structure with data from the hep message) is now being done in proto_hep; * proto_hep populates a predefined context in which he holds its own data, passing this data to receive_msg() function; * don't use hardcoded generic chunk values; * fixed bug in hep udp(v1/2) --- modules/proto_hep/hep.c | 143 +++++++++++---------- modules/proto_hep/hep.h | 40 ++++++ modules/proto_hep/hep_cb.c | 7 ++ modules/proto_hep/hep_cb.h | 2 + modules/proto_hep/proto_hep.c | 226 ++++++++++++++++++++++++++++++---- modules/proto_hep/proto_hep.h | 31 +++++ 6 files changed, 360 insertions(+), 89 deletions(-) create mode 100644 modules/proto_hep/proto_hep.h diff --git a/modules/proto_hep/hep.c b/modules/proto_hep/hep.c index d0dda995450..6d81f584de8 100644 --- a/modules/proto_hep/hep.c +++ b/modules/proto_hep/hep.c @@ -41,7 +41,7 @@ #include "hep.h" #include "../compression/compression_api.h" -#define OSIP_VENDOR_ID 0x0003 +#define GENERIC_VENDOR_ID 0x0000 #define HEP_PROTO_SIP 0x01 extern int hep_version; @@ -133,13 +133,13 @@ static int pack_hepv3(union sockaddr_union* from_su, union sockaddr_union* to_su memcpy(hg.header.id, HEP_HEADER_ID, HEP_HEADER_ID_LEN); /* IP proto */ - hg.ip_family.chunk.vendor_id = htons(OSIP_VENDOR_ID); + hg.ip_family.chunk.vendor_id = htons(GENERIC_VENDOR_ID); hg.ip_family.chunk.type_id = htons(0x0001); hg.ip_family.data = from_su->s.sa_family; hg.ip_family.chunk.length = htons(sizeof(hg.ip_family)); /* Proto ID */ - hg.ip_proto.chunk.vendor_id = htons(OSIP_VENDOR_ID); + hg.ip_proto.chunk.vendor_id = htons(GENERIC_VENDOR_ID); hg.ip_proto.chunk.type_id = htons(0x0002); hg.ip_proto.data = proto; hg.ip_proto.chunk.length = htons(sizeof(hg.ip_proto)); @@ -148,13 +148,13 @@ static int pack_hepv3(union sockaddr_union* from_su, union sockaddr_union* to_su /* IPv4 */ if(from_su->s.sa_family == AF_INET) { /* SRC IP */ - src_ip4.chunk.vendor_id = htons(OSIP_VENDOR_ID); + src_ip4.chunk.vendor_id = htons(GENERIC_VENDOR_ID); src_ip4.chunk.type_id = htons(0x0003); src_ip4.data = from_su->sin.sin_addr; src_ip4.chunk.length = htons(sizeof(src_ip4)); /* DST IP */ - dst_ip4.chunk.vendor_id = htons(OSIP_VENDOR_ID); + dst_ip4.chunk.vendor_id = htons(GENERIC_VENDOR_ID); dst_ip4.chunk.type_id = htons(0x0004); dst_ip4.data = to_su->sin.sin_addr; dst_ip4.chunk.length = htons(sizeof(dst_ip4)); @@ -162,13 +162,13 @@ static int pack_hepv3(union sockaddr_union* from_su, union sockaddr_union* to_su iplen = sizeof(dst_ip4) + sizeof(src_ip4); /* SRC PORT */ - hg.src_port.chunk.vendor_id = htons(OSIP_VENDOR_ID); + hg.src_port.chunk.vendor_id = htons(GENERIC_VENDOR_ID); hg.src_port.chunk.type_id = htons(0x0007); hg.src_port.data = htons(from_su->sin.sin_port); hg.src_port.chunk.length = htons(sizeof(hg.src_port)); /* DST PORT */ - hg.dst_port.chunk.vendor_id = htons(OSIP_VENDOR_ID); + hg.dst_port.chunk.vendor_id = htons(GENERIC_VENDOR_ID); hg.dst_port.chunk.type_id = htons(0x0008); hg.dst_port.data = htons(to_su->sin.sin_port); hg.dst_port.chunk.length = htons(sizeof(hg.dst_port)); @@ -176,13 +176,13 @@ static int pack_hepv3(union sockaddr_union* from_su, union sockaddr_union* to_su /* IPv6 */ else if(from_su->s.sa_family == AF_INET6) { /* SRC IPv6 */ - src_ip6.chunk.vendor_id = htons(OSIP_VENDOR_ID); + src_ip6.chunk.vendor_id = htons(GENERIC_VENDOR_ID); src_ip6.chunk.type_id = htons(0x0005); src_ip6.data = from_su->sin6.sin6_addr; src_ip6.chunk.length = htonl(sizeof(src_ip6)); /* DST IPv6 */ - dst_ip6.chunk.vendor_id = htons(OSIP_VENDOR_ID); + dst_ip6.chunk.vendor_id = htons(GENERIC_VENDOR_ID); dst_ip6.chunk.type_id = htons(0x0006); dst_ip6.data = from_su->sin6.sin6_addr; dst_ip6.chunk.length = htonl(sizeof(dst_ip6)); @@ -190,33 +190,33 @@ static int pack_hepv3(union sockaddr_union* from_su, union sockaddr_union* to_su iplen = sizeof(dst_ip6) + sizeof(src_ip6); /* SRC PORT */ - hg.src_port.chunk.vendor_id = htons(OSIP_VENDOR_ID); + hg.src_port.chunk.vendor_id = htons(GENERIC_VENDOR_ID); hg.src_port.chunk.type_id = htons(0x0007); hg.src_port.data = htons(from_su->sin6.sin6_port); hg.src_port.chunk.length = htons(sizeof(hg.src_port)); /* DST PORT */ - hg.dst_port.chunk.vendor_id = htons(OSIP_VENDOR_ID); + hg.dst_port.chunk.vendor_id = htons(GENERIC_VENDOR_ID); hg.dst_port.chunk.type_id = htons(0x0008); hg.dst_port.data = htons(to_su->sin6.sin6_port); hg.dst_port.chunk.length = htons(sizeof(hg.dst_port)); } /* TIMESTAMP SEC */ - hg.time_sec.chunk.vendor_id = htons(OSIP_VENDOR_ID); + hg.time_sec.chunk.vendor_id = htons(GENERIC_VENDOR_ID); hg.time_sec.chunk.type_id = htons(0x0009); hg.time_sec.data = htonl(tvb.tv_sec); hg.time_sec.chunk.length = htons(sizeof(hg.time_sec)); /* TIMESTAMP USEC */ - hg.time_usec.chunk.vendor_id = htons(OSIP_VENDOR_ID); + hg.time_usec.chunk.vendor_id = htons(GENERIC_VENDOR_ID); hg.time_usec.chunk.type_id = htons(0x000a); hg.time_usec.data = htonl(tvb.tv_usec); hg.time_usec.chunk.length = htons(sizeof(hg.time_usec)); /* Protocol TYPE */ - hg.proto_t.chunk.vendor_id = htons(OSIP_VENDOR_ID); + hg.proto_t.chunk.vendor_id = htons(GENERIC_VENDOR_ID); hg.proto_t.chunk.type_id = htons(0x000b); hg.proto_t.data = HEP_PROTO_SIP; hg.proto_t.chunk.length = htons(sizeof(hg.proto_t)); @@ -225,13 +225,13 @@ static int pack_hepv3(union sockaddr_union* from_su, union sockaddr_union* to_su /* Capture ID */ - hg.capt_id.chunk.vendor_id = htons(OSIP_VENDOR_ID); + hg.capt_id.chunk.vendor_id = htons(GENERIC_VENDOR_ID); hg.capt_id.chunk.type_id = htons(0x000c); /* */ hg.capt_id.data = htons(hep_capture_id); hg.capt_id.chunk.length = htons(sizeof(hg.capt_id)); - payload_chunk.vendor_id = htons(OSIP_VENDOR_ID); + payload_chunk.vendor_id = htons(GENERIC_VENDOR_ID); payload_chunk.type_id = payload_compression ? htons(0x0010) : htons(0x000f); @@ -368,8 +368,6 @@ static int pack_hepv2(union sockaddr_union* from_su, union sockaddr_union* to_su return -1; } - /* copy hep_hdr */ - memcpy(buffer, &hdr, sizeof(struct hep_hdr)); buflen = sizeof(struct hep_hdr); switch (hdr.hp_f) { @@ -400,6 +398,10 @@ static int pack_hepv2(union sockaddr_union* from_su, union sockaddr_union* to_su break; } + + /* copy hep_hdr */ + memcpy(buffer, &hdr, sizeof(struct hep_hdr)); + /* Version 2 has timestamp, captnode ID */ if(hep_version == 2) { /* TIMING */ @@ -463,8 +465,12 @@ int unpack_hepv2(char *buf, int len, struct hep_desc* h) /* hep_hdr */ heph = (struct hep_hdr*) buf; + h12.hdr = *heph; + h12.hdr.hp_sport = ntohs(h12.hdr.hp_sport); + h12.hdr.hp_dport = ntohs(h12.hdr.hp_dport); + switch(heph->hp_f){ case AF_INET: hl += sizeof(struct hep_iphdr); @@ -563,9 +569,13 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) unsigned short tlen; unsigned long decompress_len; + generic_chunk_t* gen_chunk, *it; + u_int16_t chunk_id; str decompressed_payload={NULL, 0}; + memset(&h3, 0, sizeof(struct hepv3)); + h->version = 3; tlen = ntohs(((hep_ctrl_t*)buf)->length); @@ -577,7 +587,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) /* we don't look at vendor id; we only need to parse the buffer */ chunk_id = ((hep_chunk_t*)buf)->type_id; switch (ntohs(chunk_id)) { - case 0x0001: + case HEP_PROTO_FAMILY: /* ip family*/ h3.hg.ip_family = *((hep_chunk_uint8_t*)buf); @@ -585,7 +595,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.hg.ip_family.chunk.length); break; - case 0x0002: + case HEP_PROTO_ID: /* ip protocol ID*/ h3.hg.ip_proto = *((hep_chunk_uint8_t*)buf); @@ -593,7 +603,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.hg.ip_proto.chunk.length); break; - case 0x0003: + case HEP_IPV4_SRC: /* ipv4 source */ h3.addr.ip4_addr.src_ip4 = *((hep_chunk_ip4_t*)buf); @@ -601,7 +611,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.addr.ip4_addr.src_ip4.chunk.length); break; - case 0x0004: + case HEP_IPV4_DST: /* ipv4 dest */ h3.addr.ip4_addr.dst_ip4 = *((hep_chunk_ip4_t*)buf); @@ -609,7 +619,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.addr.ip4_addr.dst_ip4.chunk.length); break; - case 0x0005: + case HEP_IPV6_SRC: /* ipv6 source */ h3.addr.ip6_addr.src_ip6 = *((hep_chunk_ip6_t*)buf); @@ -617,7 +627,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.addr.ip6_addr.src_ip6.chunk.length); break; - case 0x0006: + case HEP_IPV6_DST: /* ipv6 dest */ h3.addr.ip6_addr.dst_ip6 = *((hep_chunk_ip6_t*)buf); @@ -625,7 +635,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.addr.ip6_addr.dst_ip6.chunk.length); break; - case 0x0007: + case HEP_SRC_PORT: /* source port */ h3.hg.src_port = *((hep_chunk_uint16_t*)buf); @@ -635,7 +645,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.hg.src_port.chunk.length); break; - case 0x0008: + case HEP_DST_PORT: /* dest port */ h3.hg.dst_port = *((hep_chunk_uint16_t*)buf); @@ -645,7 +655,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.hg.dst_port.chunk.length); break; - case 0x0009: + case HEP_TIMESTAMP: /* timestamp */ h3.hg.time_sec = *((hep_chunk_uint32_t*)buf); @@ -655,7 +665,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.hg.time_sec.chunk.length); break; - case 0x000a: + case HEP_TIMESTAMP_US: /* timestamp microsecs offset */ h3.hg.time_usec = *((hep_chunk_uint32_t*)buf); @@ -665,7 +675,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.hg.time_usec.chunk.length); break; - case 0x000b: + case HEP_PROTO_TYPE: /* proto type */ h3.hg.proto_t = *((hep_chunk_uint8_t*)buf); @@ -673,7 +683,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.hg.proto_t.chunk.length); break; - case 0x000c: + case HEP_AGENT_ID: /* capture agent id */ h3.hg.capt_id = *((hep_chunk_uint32_t*)buf); @@ -683,15 +693,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.hg.capt_id.chunk.length); break; - case 0x000d: - /* keep alive timer */ - LM_WARN("keep alive timer not implemented!\n"); - goto safe_exit; - case 0x000e: - /* authenticate key */ - LM_WARN("hep with tls not implemented!\n"); - goto safe_exit; - case 0x000f: + case HEP_PAYLOAD: /* captured packet payload */ h3.payload_chunk = *((hep_chunk_payload_t*)buf); h3.payload_chunk.data = (char *)buf + sizeof(hep_chunk_t); @@ -700,13 +702,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) UPDATE_BUFFER(buf, tlen, h3.payload_chunk.chunk.length); break; - case 0x0010: + case HEP_COMPRESSED_PAYLOAD: /* captured compressed payload(GZIP/inflate)*/ - if (!payload_compression) { - LM_ERR("Received compressed payload but you don't have " - "\"payload\" parameter set! Can't do decompression!"); - goto safe_exit; - } h3.payload_chunk = *((hep_chunk_payload_t*)buf); h3.payload_chunk.data = (char *)buf + sizeof(hep_chunk_t); @@ -716,39 +713,53 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h) CONVERT_TO_HBO(h3.payload_chunk.chunk); UPDATE_BUFFER(buf, tlen, h3.payload_chunk.chunk.length); - compressed_payload = (unsigned char *)h3.payload_chunk.data; - compress_len =(unsigned long) + if (payload_compression) { + compressed_payload = (unsigned char *)h3.payload_chunk.data; + compress_len =(unsigned long) (h3.payload_chunk.chunk.length - sizeof(hep_chunk_t)); - rc=compression_api.decompress(compressed_payload, compress_len, + rc=compression_api.decompress(compressed_payload, compress_len, &decompressed_payload, &decompress_len); - if (compression_api.check_rc(rc)) { - LM_ERR("payload decompression failed!\n"); - goto safe_exit; - } + if (compression_api.check_rc(rc)) { + LM_ERR("payload decompression failed!\n"); + goto safe_exit; + } - /* update the length based on the new length */ - h3.payload_chunk.chunk.length += (decompress_len - compress_len); - h3.payload_chunk.data = decompressed_payload.s; + /* update the length based on the new length */ + h3.payload_chunk.chunk.length += (decompress_len - compress_len); + h3.payload_chunk.data = decompressed_payload.s; + }/* else we're just a proxy; leaving everything as is */ break; - case 0x0011: - /* internal correlation id */ - LM_WARN("keep alive timer not implemented!\n"); - goto safe_exit; - case 0x0012: - /* vlan ID */ - LM_WARN("vlan ID not implemented!\n"); - goto safe_exit; default: - LM_ERR("invalid chunk type ID!\n"); - return -1; + /* FIXME hep struct will be in shm, but if we put these in shm + * locking will be required */ + if ((gen_chunk = pkg_malloc(sizeof(generic_chunk_t)))==NULL) { + LM_ERR("no more pkg mem!\n"); + return -1; + } + + memset(gen_chunk, 0, sizeof(generic_chunk_t)); + gen_chunk->chunk = *((hep_chunk_t*)buf); + gen_chunk->data = (char *)buf + sizeof(hep_chunk_t); + + + CONVERT_TO_HBO(gen_chunk->chunk); + UPDATE_BUFFER(buf, tlen, gen_chunk->chunk.length); + + if (h3.chunk_list == NULL) { + h3.chunk_list = gen_chunk; + } else { + for (it=h3.chunk_list; it->next; it=it->next); + it->next = gen_chunk; + } + + break; } } - safe_exit: h->u.hepv3 = h3; diff --git a/modules/proto_hep/hep.h b/modules/proto_hep/hep.h index d12fa2d37e2..5b3f6ae20f3 100644 --- a/modules/proto_hep/hep.h +++ b/modules/proto_hep/hep.h @@ -32,6 +32,30 @@ #define HEP_HEADER_ID_LEN (sizeof(HEP_HEADER_ID) - 1) #define HEP_SCRIPT_SKIP 0xFF +#define HEP_MIN_INDEX 0x0001 +#define HEP_MAX_INDEX 0x0012 + +#define HEP_IDENTIFIER 0x0fee0faa + +#define HEP_OPENSIPS_VENDOR_ID 0x0003 + +enum hep_generic_chunks { HEP_PROTO_FAMILY=0x0001, HEP_PROTO_ID=0x0002, + HEP_IPV4_SRC=0x0003, HEP_IPV4_DST=0x0004, HEP_IPV6_SRC=0x0005, + HEP_IPV6_DST=0x0006, HEP_SRC_PORT=0x0007, HEP_DST_PORT=0x0008, + HEP_TIMESTAMP=0x0009, HEP_TIMESTAMP_US=0x000A, HEP_PROTO_TYPE=0x000B, + HEP_AGENT_ID=0x000C, HEP_KEEP_ALIVE=0x000D, HEP_AUTH_KEY=0x000E, + HEP_PAYLOAD=0x000F, HEP_COMPRESSED_PAYLOAD=0x0010, + HEP_CORRELATION_ID=0x0011, HEP_VLAN_ID=0x0012}; + +#define HEP_STRUCT_CHUNKS ((1<=HEP_MIN_INDEX || _cid<=HEP_MAX_INDEX) + +#define CHUNK_IS_IN_HEPSTRUCT(_cid) ((1<<_cid)&HEP_STRUCT_CHUNKS) /* HEPv3 types */ @@ -151,6 +175,14 @@ struct hep_ip6hdr { struct in6_addr hp6_dst; /* destination address */ }; +typedef struct _generic_chunk { + hep_chunk_t chunk; + void* data; /* blob data */ + + struct _generic_chunk* next; +} generic_chunk_t; + + struct hep_desc { int version; @@ -185,10 +217,17 @@ struct hep_desc { } addr; hep_chunk_payload_t payload_chunk; + generic_chunk_t* chunk_list; } hepv3; } u; }; + +struct hep_context { + struct hep_desc h; + struct receive_info ri; +}; + int pack_hep(union sockaddr_union* from_su, union sockaddr_union* to_su, int proto, char *payload, int plen, char **retbuf, int *retlen); int unpack_hepv2(char *buf, int len, struct hep_desc* h); @@ -198,5 +237,6 @@ int unpack_hep(char *buf, int len, int version, struct hep_desc* h); typedef int (*pack_hep_t)(union sockaddr_union* from_su, union sockaddr_union* to_su, int proto, char *payload, int plen, char **retbuf, int *retlen); +typedef int (*get_hep_ctx_id_t)(void); #endif diff --git a/modules/proto_hep/hep_cb.c b/modules/proto_hep/hep_cb.c index 6c6da02db8b..4180c4a9230 100644 --- a/modules/proto_hep/hep_cb.c +++ b/modules/proto_hep/hep_cb.c @@ -42,6 +42,7 @@ #include "hep_cb.h" extern int hep_version; +extern int hep_ctx_idx; struct hep_cb_list { hep_cb_t cb; @@ -50,6 +51,11 @@ struct hep_cb_list { struct hep_cb_list *cb_list=0; +int get_hep_ctx_id(void) +{ + return hep_ctx_idx; +} + int register_hep_cb(hep_cb_t cb) { struct hep_cb_list *cb_el; @@ -120,6 +126,7 @@ int bind_proto_hep(proto_hep_api_t *api) api->pack_hep = pack_hep; api->register_hep_cb = register_hep_cb; + api->get_hep_ctx_id = get_hep_ctx_id; return 0; } diff --git a/modules/proto_hep/hep_cb.h b/modules/proto_hep/hep_cb.h index efdc1b4c844..22ffaa81a80 100644 --- a/modules/proto_hep/hep_cb.h +++ b/modules/proto_hep/hep_cb.h @@ -43,6 +43,8 @@ typedef struct proto_hep_api { register_hep_cb_t register_hep_cb; pack_hep_t pack_hep; + get_hep_ctx_id_t get_hep_ctx_id; + } proto_hep_api_t; diff --git a/modules/proto_hep/proto_hep.c b/modules/proto_hep/proto_hep.c index a3164608409..947d5b60e90 100644 --- a/modules/proto_hep/proto_hep.c +++ b/modules/proto_hep/proto_hep.c @@ -64,6 +64,9 @@ static int hep_udp_send (struct socket_info* send_sock, char *buf, unsigned int len, union sockaddr_union *to, int id); static int hep_tcp_send (struct socket_info* send_sock, char *buf, unsigned int len, union sockaddr_union *to, int id); +static void update_recv_info(struct receive_info *ri, struct hep_desc *h); + +void free_hep_context(void* ptr); static int hep_port = 5656; static int hep_async = 1; @@ -73,6 +76,8 @@ static int hep_max_msg_chunks = 32; static int hep_async_local_connect_timeout = 100; static int hep_async_local_write_timeout = 10; +int hep_ctx_idx=0; + int hep_version = 3; int hep_capture_id = 1; int payload_compression=0; @@ -193,6 +198,9 @@ static int mod_init(void) return -1; } } + + hep_ctx_idx = context_register_ptr(CONTEXT_GLOBAL, free_hep_context); + return 0; } @@ -201,6 +209,38 @@ static void destroy(void) free_hep_cbs(); } +void free_hep_context(void *ptr) +{ + struct hep_desc* h; + struct hep_context* ctx = (struct hep_context*)ptr; + + generic_chunk_t* it; + generic_chunk_t* foo=NULL; + + h = &ctx->h; + + /* for version 3 we may have custom chunks which are in shm so we + * need to free them */ + if (h->version == 3) { + it = h->u.hepv3.chunk_list; + while (it) { + if (foo) { + shm_free(foo->data); + shm_free(foo); + } + foo=it; + it=it->next; + } + + if (foo) { + shm_free(foo->data); + shm_free(foo); + } + } + + shm_free(ctx); +} + static int proto_hep_init(struct proto_info *pi) { @@ -833,13 +873,15 @@ static inline int hep_handle_req(struct tcp_req *req, struct tcp_connection *con, int _max_msg_chunks) { struct receive_info local_rcv; - struct hep_desc h; char *msg_buf; int msg_len; long size; int ret=0; + struct hep_context *hep_ctx; + context_p ctx=NULL; + if (req->complete){ /* update the timeout - we successfully read the request */ tcp_conn_set_lifetime( con, tcp_con_lifetime); @@ -874,27 +916,43 @@ static inline int hep_handle_req(struct tcp_req *req, } if( msg_buf[0] == 'H' && msg_buf[1] == 'E' && msg_buf[2] == 'P' ) { + if ((hep_ctx = shm_malloc(sizeof(struct hep_context))) == NULL) { + LM_ERR("no more shared memory!\n"); + return -1; + } + memcpy(&hep_ctx->ri, &local_rcv, sizeof(struct receive_info)); + /* HEP related */ - if (unpack_hepv3(msg_buf, msg_len, &h)) { + if (unpack_hepv3(msg_buf, msg_len, &hep_ctx->h)) { LM_ERR("failed to unpack hepV3\n"); - return -1; + goto error_free_hep; + } + update_recv_info(&local_rcv, &hep_ctx->h); + + /* set context for receive_msg */ + if ((ctx=context_alloc(CONTEXT_GLOBAL)) == NULL) { + LM_ERR("failed to allocate new context! skipping...\n"); + goto error_free_hep; } - ret=run_hep_cbs(&h, &local_rcv); + context_put_ptr(CONTEXT_GLOBAL, ctx, hep_ctx_idx, hep_ctx); + + /* run hep callbacks */ + ret=run_hep_cbs(&hep_ctx->h, &local_rcv); if (ret < 0) { LM_ERR("failed to run hep callbacks\n"); - return -1; + goto error_free_hep; } msg_len = h.u.hepv3.payload_chunk.chunk.length- sizeof(hep_chunk_payload_t); /* remove the hep header; leave only the payload */ - msg_buf = h.u.hepv3.payload_chunk.data; + msg_buf = hep_ctx->h.u.hepv3.payload_chunk.data; } /* skip receive msg if we were told so from at least one callback */ if (ret != HEP_SCRIPT_SKIP && - receive_msg(msg_buf, msg_len, &local_rcv, NULL) <0) + receive_msg(msg_buf, msg_len, &local_rcv, ctx) <0) LM_ERR("receive_msg failed \n"); if (!size && req != &hep_current_req) { @@ -959,9 +1017,12 @@ static inline int hep_handle_req(struct tcp_req *req, /* everything ok */ return 0; +error_free_hep: + shm_free(hep_ctx); error: /* report error */ return -1; + } @@ -1117,10 +1178,12 @@ static int hep_udp_read_req(struct socket_info *si, int* bytes_read) unsigned int fromlen; str msg; - struct hep_desc h; + struct hep_context *hep_ctx; int ret = 0; + context_p ctx=NULL; + #ifdef DYN_BUF buf=pkg_malloc(BUF_SIZE+1); if (buf==0){ @@ -1163,27 +1226,40 @@ static int hep_udp_read_req(struct socket_info *si, int* bytes_read) /* if udp we are sure that version 1 or 2 of the * protocol is used */ - if (unpack_hepv2(buf, len, &h)) { + if ((hep_ctx = shm_malloc(sizeof(struct hep_context))) == NULL) { + LM_ERR("no more shared memory!\n"); + return -1; + } + memcpy(&hep_ctx->ri, &ri, sizeof(struct receive_info)); + + if (unpack_hepv2(buf, len, &hep_ctx->h)) { LM_ERR("hep unpacking failed\n"); return -1; } - /* run hep callbacks if looks like non-SIP message*/ - if( !isalpha(msg.s[0]) ) { /* not-SIP related */ - ret=run_hep_cbs(&h, &ri); - if (ret < 0) { - LM_ERR("failed to run hep callbacks\n"); - return -1; - } + /* set context for receive_msg */ + if ((ctx=context_alloc(CONTEXT_GLOBAL)) == NULL) { + LM_ERR("failed to allocate new context! skipping...\n"); + goto error_free_hep; + } - /* remove the hep header; leave only the payload */ - memmove(buf, h.u.hepv12.payload, - /* also copy '\0' character */ - strlen(h.u.hepv12.payload)+1); - msg.s = buf; - msg.len = strlen(buf); + context_put_ptr(CONTEXT_GLOBAL, ctx, hep_ctx_idx, hep_ctx); + + update_recv_info(&ri, &hep_ctx->h); + + ret=run_hep_cbs(&hep_ctx->h, &ri); + if (ret < 0) { + LM_ERR("failed to run hep callbacks\n"); + return -1; } + /* remove the hep header; leave only the payload */ + memmove(buf, hep_ctx->h.u.hepv12.payload, + /* also copy '\0' character */ + strlen(hep_ctx->h.u.hepv12.payload)+1); + msg.s = buf; + msg.len = strlen(buf); + if (ri.src_port==0){ tmp=ip_addr2a(&ri.src_ip); LM_INFO("dropping 0 port packet for %s\n", tmp); @@ -1192,10 +1268,114 @@ static int hep_udp_read_req(struct socket_info *si, int* bytes_read) if (ret != HEP_SCRIPT_SKIP) { /* receive_msg must free buf too!*/ - receive_msg( msg.s, msg.len, &ri, NULL); + receive_msg( msg.s, msg.len, &ri, ctx); } return 0; + +error_free_hep: + shm_free(hep_ctx); + return -1; + } + +static void update_recv_info(struct receive_info *ri, struct hep_desc *h) +{ + unsigned proto; + unsigned ip_family; + unsigned sport, dport; + + struct ip_addr dst_ip, src_ip; + + switch (h->version) { + case 1: + case 2: + ip_family = h->u.hepv12.hdr.hp_f; + proto = h->u.hepv12.hdr.hp_p; + sport = h->u.hepv12.hdr.hp_sport; + dport = h->u.hepv12.hdr.hp_dport; + switch (ip_family) { + case AF_INET: + dst_ip.af = src_ip.af = AF_INET; + dst_ip.len = src_ip.len = 4; + + memcpy(&dst_ip.u.addr, + &h->u.hepv12.addr.hep_ipheader.hp_dst, 4); + memcpy(&src_ip.u.addr, + &h->u.hepv12.addr.hep_ipheader.hp_src, 4); + + break; + + case AF_INET6: + dst_ip.af = src_ip.af = AF_INET6; + dst_ip.len = src_ip.len = 16; + + memcpy(&dst_ip.u.addr, + &h->u.hepv12.addr.hep_ip6header.hp6_dst, 16); + memcpy(&src_ip.u.addr, + &h->u.hepv12.addr.hep_ip6header.hp6_src, 16); + + break; + } + + break; + case 3: + ip_family = h->u.hepv3.hg.ip_family.data; + proto = h->u.hepv3.hg.ip_proto.data; + sport = h->u.hepv3.hg.src_port.data; + dport = h->u.hepv3.hg.dst_port.data; + switch (ip_family) { + case AF_INET: + dst_ip.af = src_ip.af = AF_INET; + dst_ip.len = src_ip.len = 4; + + memcpy(&dst_ip.u.addr, + &h->u.hepv3.addr.ip4_addr.dst_ip4.data, 4); + memcpy(&src_ip.u.addr, + &h->u.hepv3.addr.ip4_addr.src_ip4.data, 4); + + break; + + case AF_INET6: + dst_ip.af = src_ip.af = AF_INET6; + dst_ip.len = src_ip.len = 16; + + memcpy(&dst_ip.u.addr, + &h->u.hepv3.addr.ip6_addr.dst_ip6.data, 16); + memcpy(&src_ip.u.addr, + &h->u.hepv3.addr.ip6_addr.src_ip6.data, 16); + + break; + } + + break; + default: + LM_ERR("invalid hep version!\n"); + return; + } + + if(proto == IPPROTO_UDP) ri->proto=PROTO_UDP; + else if(proto == IPPROTO_TCP) ri->proto=PROTO_TCP; + else if(proto == IPPROTO_IDP) ri->proto=PROTO_TLS; + /* fake protocol */ + else if(proto == IPPROTO_SCTP) ri->proto=PROTO_SCTP; + else if(proto == IPPROTO_ESP) ri->proto=PROTO_WS; + /* fake protocol */ + else { + LM_ERR("unknown protocol [%d]\n",proto); + proto = PROTO_NONE; + } + + + if (h->version == 3) + h->u.hepv3.hg.ip_proto.data = ri->proto; + + + ri->src_ip = src_ip; + ri->src_port = sport; + + ri->dst_ip = dst_ip; + ri->dst_port = dport; +} diff --git a/modules/proto_hep/proto_hep.h b/modules/proto_hep/proto_hep.h new file mode 100644 index 00000000000..d666fd8e7ee --- /dev/null +++ b/modules/proto_hep/proto_hep.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 - OpenSIPS Foundation + * Copyright (C) 2001-2003 FhG Fokus + * + * This file is part of opensips, a free SIP server. + * + * opensips 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 + * + * opensips 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 + * + * + * History: + * ------- + * 2016-01-22 first version (Ionut Ionita) + */ + + +#ifndef _PROTO_HEP_ +#define _PROTO_HEP_ +extern int proto_tcp_read(struct tcp_connection*, struct tcp_req*); +#endif From 67c7473675a2bcc0af12efae387e8c954cda083e Mon Sep 17 00:00:00 2001 From: ionutrazvanionita Date: Tue, 23 Feb 2016 17:52:32 +0200 Subject: [PATCH 3/5] [sipcapture] hep_chunks setter/getter/delete funcs; hep_net variable * hep version 3 chunks have now three functions with which they can be manipulated: hep_set(add/modify a chunk), hep_get(get vendor id and value of a chunk) and hep_del(remove a chunk); * hep_net is a pseudovariable which gives layer 3 and 4 information about hep communication(where does the packet comes from and on which interfaces it was received); * sip capture now holds an extra parameter - protocol type which gives information about the protocol of the encapsulated packet; --- modules/sipcapture/sipcapture.c | 3335 ++++++++++++++++++++----- modules/sipcapture/sql/sipcapture.sql | 1 + 2 files changed, 2655 insertions(+), 681 deletions(-) diff --git a/modules/sipcapture/sipcapture.c b/modules/sipcapture/sipcapture.c index 68572e3735b..bc9e38833eb 100644 --- a/modules/sipcapture/sipcapture.c +++ b/modules/sipcapture/sipcapture.c @@ -41,6 +41,8 @@ #include #include "../proto_hep/hep.h" #include "../proto_hep/hep_cb.h" +#include "../../context.h" +#include "../../mod_fix.h" /* BPF structure */ #ifdef __OS_linux @@ -80,6 +82,18 @@ #include "../../statistics.h" #endif +/* this value shall be put in proto_reserved2 field of + * the receive_info structure and help us identify a + * hep message */ +#define HEPBUF_LEN (1<<14) + +#define LOWER_DWORD(_c1, _c2, _c3, _c4) (((_c1<<24)|(_c2<<16)|(_c3<<8)|_c4)|0x20202020) +#define LOWER_WORD(_c1, _c2) (((_c1|0x20)<<8) | (_c2|0x20)) +#define LOWER_BYTE(_c1) (_c1|0x20) + +#define HEP_GET_CONTEXT(_api) \ + (struct hep_context*)context_get_ptr(CONTEXT_GLOBAL, current_processing_ctx, _api.get_hep_ctx_id()) + struct _sipcapture_object { str method; str reply_reason; @@ -112,6 +126,7 @@ struct _sipcapture_object { int originator_port; int proto; int family; + int proto_type; str rtp_stat; int type; long long tmstamp; @@ -125,7 +140,7 @@ struct _sipcapture_object { #define ETHHDR 14 /* sizeof of ethhdr structure */ #define EMPTY_STR(val) val.s=""; val.len=0; #define TABLE_LEN 256 -#define NR_KEYS 37 +#define NR_KEYS 38 typedef void* sc_async_param_t; db_key_t db_keys[NR_KEYS]; @@ -153,6 +168,37 @@ static int db_async_store(db_val_t* db_vals, async_resume_module **resume_f, void **resume_param); int resume_async_dbquery(int fd, struct sip_msg *msg, void *_param); +/* setter functions */ +static int set_hep_generic_fixup(void** param, int param_no); +static int set_hep_fixup(void** param, int param_no); +static int w_set_hep_generic(struct sip_msg* msg, char* id, char* data); +static int w_set_hep(struct sip_msg* msg, char* id, char* vid, char* data, char* type); + +/* getter functions */ +static int get_hep_fixup(void** param, int param_no); +static int get_hep_generic_fixup(void** param, int param_no); +static int +w_get_hep(struct sip_msg* msg, char* type, char* id, char* vid, char* data); +static int +w_get_hep_generic(struct sip_msg* msg, char* id, char* vid, char* data); + + +/* remove chunk functions */ +static int del_hep_fixup(void** param, int param_no); +static int w_del_hep(struct sip_msg* msg, char *id); + +static int pv_get_hep_net(struct sip_msg *msg, pv_param_t *param, + pv_value_t *res); + +static int +set_generic_hep_chunk(struct hepv3* h3, unsigned chunk_id, str *data); + + + +static int pv_parse_hep_net_name(pv_spec_p sp, str *in); + +static int parse_hep_index(str *s_index); + static str db_url = {NULL, 0}; static str table_name = str_init("sip_capture"); static str id_column = str_init("id"); @@ -167,6 +213,8 @@ static str from_tag_column = str_init("from_tag"); static str to_user_column = str_init("to_user"); static str to_tag_column = str_init("to_tag"); static str pid_user_column = str_init("pid_user"); + + /* FAMILY TYPE */ static str contact_user_column = str_init("contact_user"); static str auth_user_column = str_init("auth_user"); static str callid_column = str_init("callid"); @@ -190,10 +238,52 @@ static str orig_port_column = str_init("originator_port"); static str rtp_stat_column = str_init("rtp_stat"); static str proto_column = str_init("proto"); static str family_column = str_init("family"); +static str protot_column = str_init("proto_type"); static str type_column = str_init("type"); static str node_column = str_init("node"); static str msg_column = str_init("msg"); static str capture_node = str_init("homer01"); +/* hep pvar related */ +static str afinet_str = str_init("AF_INET"); +static str afinet6_str = str_init("AF_INET6"); +/* hep capture proto types */ +static str hep_net_protos[]={ + /* want same index as in opensips enum */ + {NULL, 0}, + str_init("UDP"), + str_init("TCP"), + str_init("TLS"), + str_init("SCTP"), + str_init("WS"), + str_init("WSS"), + str_init("BIN"), + str_init("HEP"), + {NULL, 0} +}; + +static str hep_app_protos[]= { + str_init("reserved"), + str_init("SIP"), + str_init("XMPP"), + str_init("SDP"), + str_init("RTP"), + str_init("RTCP"), + str_init("MGCP"), + str_init("MEGACO(H.248)"), + str_init("M2UA(SS7/SIGTRAN)"), + str_init("M3UA(SS7/SIGTRAN)"), + str_init("IAX"), + str_init("H322"), + str_init("H321"), + {NULL, 0} +}; + +#define MAX_PAYLOAD 32767 +static char payload_buf[MAX_PAYLOAD]; + + +/* values to be set from script for hep pvar */ + #define MAX_QUERY 65535 @@ -260,17 +350,31 @@ db_con_t* db_con = 0; /*!< database connection */ static db_ps_t sipcapture_ps = NULL; static query_list_t *ins_list = NULL; -struct hep_timehdr* heptime; - proto_hep_api_t hep_api; load_hep_f load_hep; + +static char hepbuf[HEPBUF_LEN]; +static str hep_str={hepbuf, 0}; + /*! \brief * Exported functions */ static cmd_export_t cmds[] = { {"sip_capture", (cmd_function)sip_capture, 0, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"hep_set", (cmd_function)w_set_hep_generic, 2, set_hep_generic_fixup, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"hep_set", (cmd_function)w_set_hep, 4, set_hep_fixup, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"hep_get", (cmd_function)w_get_hep_generic, 3, get_hep_generic_fixup, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"hep_get", (cmd_function)w_get_hep, 4, get_hep_fixup, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"hep_get", (cmd_function)w_get_hep, 4, get_hep_fixup, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"hep_del", (cmd_function)w_del_hep, 1, del_hep_fixup, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {0, 0, 0, 0, 0, 0} }; @@ -388,6 +492,15 @@ static dep_export_t deps = { }, }; + /** + * pseudo-variables + */ +static pv_export_t mod_items[] = { + {{"hep_net", sizeof("hep_net")-1}, 1201, pv_get_hep_net, 0, + pv_parse_hep_net_name, 0, 0, 0}, + {{0, 0}, 0, 0, 0, 0, 0, 0, 0} +}; + /*! \brief module exports */ struct module_exports exports = { "sipcapture", @@ -404,7 +517,7 @@ struct module_exports exports = { 0, /*!< exported statistics */ #endif mi_cmds, /*!< exported MI functions */ - 0, /*!< exported pseudo-variables */ + mod_items, /*!< exported pseudo-variables */ procs, /*!< extra processes */ mod_init, /*!< module initialization function */ 0, /*!< response function */ @@ -455,10 +568,11 @@ static int mod_init(void) { db_keys[30] = &orig_port_column; db_keys[31] = &proto_column; db_keys[32] = &family_column; - db_keys[33] = &rtp_stat_column; - db_keys[34] = &type_column; - db_keys[35] = &node_column; - db_keys[36] = &msg_column; + db_keys[33] = &protot_column; + db_keys[34] = &rtp_stat_column; + db_keys[35] = &type_column; + db_keys[36] = &node_column; + db_keys[37] = &msg_column; #ifdef STATISTICS @@ -656,911 +770,2770 @@ static int mod_init(void) { } -int extract_host_port(void) +/* + * returns hep index as an integer from a string + */ +static int parse_hep_index(str *s_index) { - if(raw_socket_listen.len) { - char *p1,*p2; - p1 = raw_socket_listen.s; + int p; + int index=0; + int hex_mode=0; + unsigned int dec_num; - if( (p1 = strrchr(p1, ':')) != 0 ) { - *p1 = '\0'; - p1++; - p2=p1; - if((p2 = strrchr(p2, '-')) != 0 ) { - p2++; - moni_port_end = atoi(p2); - p1[strlen(p1)-strlen(p2)-1]='\0'; - } - moni_port_start = atoi(p1); - raw_socket_listen.len = strlen(raw_socket_listen.s); - } - return 1; + if (s_index == NULL || s_index->s == NULL || s_index->len == 0) { + LM_ERR("null index!\n"); + return -1; } - return 0; -} - - -static int child_init(int rank) -{ - - if (rank==PROC_MAIN || rank==PROC_TCP_MAIN) - return 0; /* do nothing for the main process */ - - if (db_url.s) - return sipcapture_db_init(&db_url); - - LM_ERR("db_url is empty\n"); - - return 0; -} + if (!isdigit(s_index->s[0])) + return 0; -int sipcapture_db_init(const str* db_url) { - + /* cut the '0x' in the beginning if exists */ + if (s_index->len > 2 && s_index->s[0] == '0' && s_index->s[1] == 'x') { + s_index->s += 2; + s_index->len -= 2; + hex_mode=1; + } - if(db_funcs.init == 0) { - LM_CRIT("null dbf\n"); - goto error; - } + /**/ + while (s_index->s[0] == '0') + (s_index->s++, s_index->len--); - db_con = db_funcs.init(db_url); - if (!db_con) { - LM_ERR("unable to connect database\n"); - return -1; - } + /* decimal */ + if (!hex_mode) { + if (str2int(s_index, &dec_num) < 0) { + LM_ERR("Chunk identifier begins with a digit " + "but it's not a valid number!\n"); + return -1; + } - if (db_funcs.use_table(db_con, &table_name) < 0) { - LM_ERR("use_table failed\n"); - return -1; - } + return dec_num; + } - heptime = (struct hep_timehdr*)pkg_malloc(sizeof(struct hep_timehdr)); - if(heptime==NULL) { - LM_ERR("no more pkg memory left\n"); - return -1; - } + for (p=0; p < s_index->len; p++) { + switch (s_index->s[p]) { + case 'a': + case 'A': + index = (index<<4) + 0xA; + break; + case 'b': + case 'B': + index = (index<<4) + 0xB; + break; + case 'c': + case 'C': + index = (index<<4) + 0xC; + break; + case 'd': + case 'D': + index = (index<<4) + 0xD; + break; + case 'e': + case 'E': + index = (index<<4) + 0xE; + break; + case 'f': + case 'F': + index = (index<<4) + 0xF; + break; + default: + if (s_index->s[p] >= '0' && s_index->s[p] <= '9') { + index = (index<<4) + (s_index->s[p] -'0'); + break; + } + return -1; + } + } - return 0; + return index==0?-1:index; /* index can't be 0 */ -error: - return -1; } -void sipcapture_db_close(void) -{ - if (db_con && db_funcs.close){ - db_funcs.close(db_con); - db_con=0; - } - if(heptime) pkg_free(heptime); -} +enum hep_state { STATE_NONE=0, SOURCE=1, DEST, PROTO, TIME, AG_ID, PLOAD}; -static void raw_socket_process(int rank) +static int parse_hep_name(str *s_name, unsigned *chunk) { - if (sipcapture_db_init(&db_url) < 0 ){ - LM_ERR("unable to open database connection\n"); - return; - } + #define CHECK_IS_VALID(_str, _pattern) \ + do { \ + if (_str.len < (sizeof(_pattern)-1)) \ + goto error; \ + } while(0); - raw_capture_rcv_loop(raw_sock_desc, moni_port_start, moni_port_end, - moni_capture_on ? 0 : 1); - - /* Destroy DB socket */ - sipcapture_db_close(); -} - - -static void destroy(void) -{ - str query_str; + int ret=0; + int p=0; + enum hep_state state=STATE_NONE; - /* execute the uninserted queries */ - if (DB_CAPABILITY(db_funcs, DB_CAP_ASYNC_RAW_QUERY)) { - if (curr_queries) { - if (!db_con) { - db_con = db_funcs.init(&db_url); - if (!db_con) { - LM_ERR("unable to connect database\n"); - goto destroy_continue; - } + str s; - if (db_funcs.use_table(db_con, &table_name) < 0) { - LM_ERR("use_table failed\n"); - goto destroy_continue; - } - } + if (s_name == NULL || s_name->s == NULL || + s_name->len == 0 || chunk == NULL) { + LM_ERR("bad input!\n"); + return -1; + } - query_str.s = query_buf; - query_str.len = query_len; + str_trim_spaces_lr(*s_name); - if (db_funcs.raw_query(db_con, &query_str, NULL)) { - LM_ERR("failed to insert remaining queries\n"); - } - lock_destroy(&query_lock); - } + ret=parse_hep_index(s_name); + if (ret<0) { + goto error; + } else if (ret > 0) { + *chunk=ret; + return 0; + } /* else it's a name; continue */ - shm_free(async_query); + s = *s_name; + if (s.len < 4) { + LM_ERR("bad chunk name <%.*s>!\n", s_name->len, s_name->s); + return -1; } - /* Destroy DB socket */ - sipcapture_db_close(); - -destroy_continue: - - if (capture_on_flag) - shm_free(capture_on_flag); + switch (LOWER_DWORD(s.s[0], s.s[1], s.s[2], s.s[3])) { + case LOWER_DWORD('p','r','o','t'): + state=PROTO; + break; + case LOWER_DWORD('s','r','c','_'): + state=SOURCE; + break; + case LOWER_DWORD('d','s','t','_'): + state=DEST; + break; + case LOWER_DWORD('t','i','m','e'): + state=TIME; + break; + case LOWER_DWORD('c','a','p','t'): + state=AG_ID; + break; + case LOWER_DWORD('p','a','y','l'): + state=PLOAD; + break; + default: + goto error; + } - if(raw_sock_desc > 0) { - if(promisc_on && raw_interface.len) { -#ifdef __OS_linux - ifr.ifr_flags &= ~(IFF_PROMISC); + p+=4; - if (ioctl(raw_sock_desc, SIOCSIFFLAGS, &ifr) < 0) { - LM_ERR("could not remove PROMISC flag from interface [%.*s]:" - " %s (%d)\n", raw_interface.len, raw_interface.s, strerror(errno), errno); - } -#endif - } - close(raw_sock_desc); - } -} + switch (state) { + case PROTO: + /* we need at least 8 bytes protXXXX */ + CHECK_IS_VALID(s, "protXXXX"); -/** - * HEP message - */ -int hep_msg_received(struct hep_desc *h, struct receive_info *ri) -{ + switch LOWER_DWORD(s.s[p], s.s[p+1], s.s[p+2], s.s[p+3]){ + /*proto_family*/ + case LOWER_DWORD('o','_','f','a'): + p+=4; + CHECK_IS_VALID(s, "proto_faXXXX"); - char ip_family; - unsigned char proto; - unsigned short sport, dport; - struct ip_addr dst_ip, src_ip; + if (LOWER_DWORD(s.s[p],s.s[p+1], s.s[p+2], s.s[p+3]) != + LOWER_DWORD('m','i','l','y')) + goto error; - struct sip_msg msg; + *chunk=HEP_PROTO_FAMILY; + break; - if(!hep_capture_on) { - LM_ERR("HEP is not enabled\n"); - return 0; - } + /* protocol id */ + case LOWER_DWORD('o','_','i','d'): + *chunk=HEP_PROTO_ID; + break; - switch (h->version) { - case 1: - case 2: - ip_family = h->u.hepv12.hdr.hp_f; - proto = h->u.hepv12.hdr.hp_p; - dport = h->u.hepv12.hdr.hp_dport; - sport = h->u.hepv12.hdr.hp_sport; + case LOWER_DWORD('o','_','t','y'): + p+=4; + CHECK_IS_VALID(s, "proto_tyXX"); - switch (ip_family) { - case AF_INET: - dst_ip.af = src_ip.af = AF_INET; - dst_ip.len = src_ip.len = 4; + if (LOWER_WORD(s.s[p],s.s[p+1]) != LOWER_WORD('p','e')) + goto error; + *chunk=HEP_PROTO_TYPE; + break; - memcpy(&dst_ip.u.addr, - &h->u.hepv12.addr.hep_ipheader.hp_dst, 4); - memcpy(&src_ip.u.addr, - &h->u.hepv12.addr.hep_ipheader.hp_src, 4); + default: + goto error; + } + break; + case SOURCE: + CHECK_IS_VALID(s, "src_XX"); + switch LOWER_WORD(s.s[p], s.s[p+1]) { + case LOWER_WORD('i', 'p'): + *chunk=HEP_IPV4_SRC; break; + case LOWER_WORD('p', 'o'): + CHECK_IS_VALID(s, "src_poXX"); + p+=2; + if (LOWER_WORD(s.s[p], s.s[p+1]) != LOWER_WORD('r','t')) + goto error; - case AF_INET6: - dst_ip.af = src_ip.af = AF_INET6; - dst_ip.len = src_ip.len = 16; - - memcpy(&dst_ip.u.addr, - &h->u.hepv12.addr.hep_ip6header.hp6_dst, 16); - memcpy(&src_ip.u.addr, - &h->u.hepv12.addr.hep_ip6header.hp6_src, 16); + *chunk=HEP_SRC_PORT; + break; + default: + goto error; + } + break; + case DEST: + CHECK_IS_VALID(s, "dst_XX"); + switch LOWER_WORD(s.s[p], s.s[p+1]) { + case LOWER_WORD('i', 'p'): + *chunk=HEP_IPV4_DST; break; + case LOWER_WORD('p', 'o'): + CHECK_IS_VALID(s, "dst_poXX"); + p+=2; + if (LOWER_WORD(s.s[p], s.s[p+1]) != LOWER_WORD('r','t')) + goto error; + *chunk=HEP_DST_PORT; + break; default: - LM_ERR("unsupported family [%d]\n", ip_family); - return -1; + goto error; + } + + break; + case TIME: + CHECK_IS_VALID(s, "timestamp"); + if (s.len == sizeof("timestamp")-1 && + !strncasecmp(s.s, "timestamp", s.len)) { + *chunk = HEP_TIMESTAMP; + break; } - /* timestamp and capture id */ - if (h->version == 2) { - heptime->tv_sec = h->u.hepv12.hep_time.tv_sec; - heptime->tv_usec = h->u.hepv12.hep_time.tv_usec; - heptime->captid = h->u.hepv12.hep_time.captid; + CHECK_IS_VALID(s, "timestampXXX"); + if (s.len == sizeof("timestamp_us")-1 && + !strncasecmp(s.s, "timestamp_us", s.len)) { + *chunk=HEP_TIMESTAMP_US; + break; } + goto error; + case AG_ID: + CHECK_IS_VALID(s, "captXXXXXXXX"); + if ((LOWER_DWORD(s.s[p], s.s[p+1], s.s[p+2], s.s[p+3]) + != LOWER_DWORD('a','g','e','n')) || (p+=4,0) || + LOWER_DWORD(s.s[p], s.s[p+1], s.s[p+2], s.s[p+3]) + != LOWER_DWORD('t','_','i','d')) + goto error; + + *chunk = HEP_AGENT_ID; break; + case PLOAD: + CHECK_IS_VALID(s, "paylXXX"); + if ((LOWER_WORD(s.s[p], s.s[p+1]) != LOWER_WORD('o', 'a') + || s.s[p+2] != 'd')) + goto error; - case 3: - ip_family = h->u.hepv3.hg.ip_family.data; - proto = h->u.hepv3.hg.ip_proto.data; - dport = h->u.hepv3.hg.dst_port.data; - sport = h->u.hepv3.hg.src_port.data; + *chunk = HEP_PAYLOAD; + break; + default: + goto error; + } - switch (ip_family) { - case AF_INET: - dst_ip.af = src_ip.af = AF_INET; - dst_ip.len = src_ip.len = 4; + return 0; +error: + LM_ERR("invalid hepvar name <%.*s>! parsed until <%.*s>!\n", + s_name->len, s_name->s, s_name->len-p, s_name->s+p); + return -1; - memcpy(&dst_ip.u.addr, - &h->u.hepv3.addr.ip4_addr.dst_ip4.data, 4); - memcpy(&src_ip.u.addr, - &h->u.hepv3.addr.ip4_addr.src_ip4.data, 4); +#undef CHECK_IS_VALID +} - break; - case AF_INET6: - dst_ip.af = src_ip.af = AF_INET6; - dst_ip.len = src_ip.len = 16; +static int pv_parse_hep_net_name(pv_spec_p sp, str* in) +{ + pv_spec_p e; - memcpy(&dst_ip.u.addr, - &h->u.hepv3.addr.ip6_addr.dst_ip6.data, 16); - memcpy(&src_ip.u.addr, - &h->u.hepv3.addr.ip6_addr.src_ip6.data, 16); + unsigned id; - break; + if (in==NULL || in->s == NULL || in->len == 0) { + LM_ERR("bad name!\n"); + return -1; + } - default: - LM_ERR("unsupported family [%d]\n", ip_family); - return -1; - } + str_trim_spaces_lr(*in); - /* timestamp and capture id */ - heptime->tv_sec = h->u.hepv3.hg.time_sec.data; - heptime->tv_usec = h->u.hepv3.hg.time_usec.data; - heptime->captid = h->u.hepv3.hg.capt_id.data; + if (in->s[0] != PV_MARKER) { + if (parse_hep_name(in, &id) < 0) { + LM_ERR("Invalid hep net name <%.*s>!\n", in->len, in->s); + return -1; + } - break; + sp->pvp.pvn.type = PV_NAME_INTSTR; + sp->pvp.pvn.u.isname.name.n = id; + sp->pvp.pvn.u.isname.type = 0; + } else { + e = pkg_malloc(sizeof(pv_spec_p)); + if (e==NULL) { + LM_ERR("no more pkg mem!\n"); + return -1; + } - default: - LM_ERR("unknown hep proto [%d]\n", h->version); + if (pv_parse_spec(in, e)==NULL) { + LM_ERR("invalid pvar!\n"); return -1; - } + } - /* PROTO */ - if(proto == IPPROTO_UDP) ri->proto=PROTO_UDP; - else if(proto == IPPROTO_TCP) ri->proto=PROTO_TCP; - else if(proto == IPPROTO_IDP) ri->proto=PROTO_TLS; - /* fake protocol */ - else if(proto == IPPROTO_SCTP) ri->proto=PROTO_SCTP; - else if(proto == IPPROTO_ESP) ri->proto=PROTO_WS; - /* fake protocol */ - else { - LM_ERR("unknown protocol [%d]\n",proto); - ri->proto = PROTO_NONE; + sp->pvp.pvn.u.dname = (void *)e; + sp->pvp.pvn.type = PV_NAME_PVAR; } - ri->src_ip = src_ip; - ri->src_port = ntohs(sport); + return 0; +} - ri->dst_ip = dst_ip; - ri->dst_port = ntohs(dport); - if (hep_store_no_script) { - memset(&msg, 0, sizeof(struct sip_msg)); +static int get_hepvar_name(struct sip_msg *msg, pv_param_t *param, + unsigned int *chunk) +{ + pv_spec_p sp; + pv_value_t value; - switch (h->version) { - case 1: - case 2: - msg.buf = h->u.hepv12.payload; - msg.len = strlen(msg.buf); - break; - case 3: - msg.buf = h->u.hepv3.payload_chunk.data; - msg.len = h->u.hepv3.payload_chunk.chunk.length - sizeof(struct hep_chunk); - break; - default: - LM_ERR("unknown hep proto [%d]\n", h->version); + if (param->pvn.type == PV_NAME_PVAR) { + sp = param->pvn.u.dname; + if (pv_get_spec_value(msg, sp, &value) < 0) { + LM_ERR("failed to get name pv value!\n"); return -1; } - msg.rcv = *ri; - - if (parse_msg(msg.buf,msg.len,&msg)!=0) { - LM_ERR("Unable to parse message in hep payload!" - "Hep version %d!\n", h->version); + if (!(value.flags&PV_VAL_STR)) { + LM_ERR("invalid name!\n"); return -1; } - /* if message not parsed ok this helps with debugging */ - LM_DBG("********************************* SIP MESSAGE ******************\n" - "%.*s\n" - "***************************************************************\n", - (int)msg.len, msg.buf); - - /* we basically move the sip_capture() call from the scripts here */ - if (w_sip_capture(&msg, NULL, NULL) < 0) { - LM_ERR("failed to store the message!\n"); + if (parse_hep_name(&value.rs, chunk) < 0) { + LM_ERR("invalid name!\n"); return -1; } - - /* return a special code which will tell hep not to run the script */ - return HEP_SCRIPT_SKIP; + } else { + *chunk = param->pvn.u.isname.name.n; } return 0; } -static int sip_capture_prepare(struct sip_msg* msg) +static int get_hep_chunk(struct hepv3* h3, unsigned int chunk_id, + pv_value_t *res) { - /* We need parse all headers */ - if (parse_headers(msg, HDR_CALLID_F|HDR_EOH_F, 0) != 0) { - LM_ERR("cannot parse headers\n"); - return -1; - } + #define SET_PVAL_INT(__pval__, __ival__) \ + do { \ + __pval__->flags = PV_VAL_STR|PV_VAL_INT; \ + __pval__->ri = __ival__; \ + __pval__->rs.len += \ + snprintf(__pval__->rs.s + __pval__->rs.len, \ + HEPBUF_LEN, "%d", __ival__); \ + } while(0); + + #define SET_PVAL_STR(__pval__, __sval__) \ + do { \ + __pval__->flags = PV_VAL_STR; \ + __pval__->rs.len += \ + snprintf(__pval__->rs.s + __pval__->rs.len, \ + HEPBUF_LEN, "%.*s", __sval__.len, __sval__.s); \ + } while(0); + + + char addr[INET6_ADDRSTRLEN]; + + time_t time; + + str addr_str; + str time_str; + str payload_str; + hep_str.len = 0; + + res->rs = hep_str; + res->flags = PV_VAL_STR; + + switch (chunk_id) { + /* ip family */ + case HEP_PROTO_FAMILY: + if (h3->hg.ip_family.chunk.length == 0) + goto chunk_not_set; + + if (h3->hg.ip_family.data == AF_INET) { + SET_PVAL_STR(res, afinet_str); + } else { + SET_PVAL_STR(res, afinet6_str); + } - return 0; -} + break; + /* ip protocol id */ + case HEP_PROTO_ID: + if (h3->hg.ip_proto.chunk.length == 0) + goto chunk_not_set; -static int sip_capture_store(struct _sipcapture_object *sco, - async_resume_module **resume_f, void **resume_param) -{ - db_val_t db_vals[NR_KEYS]; - int i = 0, ret; + if (h3->hg.ip_proto.datahg.ip_proto.data>PROTO_WS) { + LM_ALERT("Invalid proto!Probably a new one was added %d\n", + h3->hg.ip_proto.data); + return -1; + } + SET_PVAL_STR(res, hep_net_protos[h3->hg.ip_proto.data]); + + break; + /* ipv4/6 source + * no difference between ipv4/ipv6 from script level; it only returns + * the address it the format that it is */ + case HEP_IPV4_SRC: + case HEP_IPV6_SRC: + if (h3->hg.ip_family.data == AF_INET) { + if (h3->addr.ip4_addr.src_ip4.chunk.length == 0) + goto chunk_not_set; + + if (inet_ntop(AF_INET, &h3->addr.ip4_addr.src_ip4.data, + addr, INET_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + } else { + if (h3->addr.ip6_addr.src_ip6.chunk.length == 0) + goto chunk_not_set; + + if (inet_ntop(AF_INET6, &h3->addr.ip6_addr.src_ip6.data, + addr, INET6_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + } - if(sco==NULL) - { - LM_DBG("invalid parameter\n"); - return -1; - } + addr_str.s = addr; + addr_str.len = strlen(addr); - db_vals[0].type = DB_INT; - db_vals[0].val.int_val = 0; + SET_PVAL_STR(res, addr_str); - db_vals[1].type = DB_DATETIME; - db_vals[1].val.time_val = time(NULL); + break; + /* ipv4/6 dest */ + case HEP_IPV4_DST: + case HEP_IPV6_DST: + if (h3->hg.ip_family.data == AF_INET) { + if (h3->addr.ip4_addr.dst_ip4.chunk.length == 0) + goto chunk_not_set; - db_vals[2].type = DB_BIGINT; - db_vals[2].val.bigint_val = sco->tmstamp; + if (inet_ntop(AF_INET, &h3->addr.ip4_addr.dst_ip4.data, + addr, INET_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + } else { + if (h3->addr.ip6_addr.dst_ip6.chunk.length == 0) + goto chunk_not_set; + + if (inet_ntop(AF_INET6, &h3->addr.ip6_addr.dst_ip6.data, + addr, INET6_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + } - db_vals[3].type = DB_STR; - db_vals[3].val.str_val = sco->method; + addr_str.s = addr; + addr_str.len = strlen(addr); - db_vals[4].type = DB_STR; - db_vals[4].val.str_val = sco->reply_reason; + SET_PVAL_STR(res, addr_str); - db_vals[5].type = DB_STR; - db_vals[5].val.str_val = sco->ruri; + break; + /* ipv6 source */ + /* source port */ + case HEP_SRC_PORT: + if (h3->hg.src_port.chunk.length == 0) + goto chunk_not_set; - db_vals[6].type = DB_STR; - db_vals[6].val.str_val = sco->ruri_user; - db_vals[7].type = DB_STR; - db_vals[7].val.str_val = sco->from_user; + SET_PVAL_INT(res, h3->hg.src_port.data); - db_vals[8].type = DB_STR; - db_vals[8].val.str_val = sco->from_tag; + break; + /* destination port */ + case HEP_DST_PORT: + if (h3->hg.dst_port.chunk.length == 0) + goto chunk_not_set; - db_vals[9].type = DB_STR; - db_vals[9].val.str_val = sco->to_user; + SET_PVAL_INT(res, h3->hg.dst_port.data); - db_vals[10].type = DB_STR; - db_vals[10].val.str_val = sco->to_tag; + break; + /* timestamp */ + case HEP_TIMESTAMP: + if (h3->hg.time_sec.chunk.length == 0) + goto chunk_not_set; - db_vals[11].type = DB_STR; - db_vals[11].val.str_val = sco->pid_user; + time = h3->hg.time_sec.data; + time_str.s = ctime(&time); + time_str.len = strlen(time_str.s)-1; - db_vals[12].type = DB_STR; - db_vals[12].val.str_val = sco->contact_user; + SET_PVAL_STR(res, time_str); - db_vals[13].type = DB_STR; - db_vals[13].val.str_val = sco->auth_user; + break; + /* timestamp us offset */ + case HEP_TIMESTAMP_US: + if (h3->hg.time_usec.chunk.length == 0) + goto chunk_not_set; - db_vals[14].type = DB_STR; - db_vals[14].val.str_val = sco->callid; + SET_PVAL_INT(res, h3->hg.time_usec.data); - db_vals[15].type = DB_STR; - db_vals[15].val.str_val = sco->callid_aleg; + break; + /* proto type (SIP, ...) */ + case HEP_PROTO_TYPE: + if (h3->hg.proto_t.chunk.length == 0) + goto chunk_not_set; - db_vals[16].type = DB_STR; - db_vals[16].val.str_val = sco->via_1; + if (h3->hg.proto_t.data < 0 || h3->hg.proto_t.data > + sizeof(hep_app_protos)-1) { + LM_ALERT("Invalid proto!Probably a new one was added %d\n", + h3->hg.ip_proto.data); + } - db_vals[17].type = DB_STR; - db_vals[17].val.str_val = sco->via_1_branch; + SET_PVAL_STR(res, hep_app_protos[h3->hg.proto_t.data]); - db_vals[18].type = DB_STR; - db_vals[18].val.str_val = sco->cseq; + break; + /* capture agent id */ + case HEP_AGENT_ID: + if (h3->hg.capt_id.chunk.length == 0) + goto chunk_not_set; - db_vals[19].type = DB_STR; - db_vals[19].val.str_val = sco->reason; + SET_PVAL_INT(res, h3->hg.capt_id.data); - db_vals[20].type = DB_STR; - db_vals[20].val.str_val = sco->content_type; + break; + /* payload */ + case HEP_PAYLOAD: + case HEP_COMPRESSED_PAYLOAD/* gzipped payload */: + if (h3->payload_chunk.chunk.length == 0) + goto chunk_not_set; - db_vals[21].type = DB_STR; - db_vals[21].val.str_val = sco->authorization; - db_vals[22].type = DB_STR; - db_vals[22].val.str_val = sco->user_agent; + payload_str.s = h3->payload_chunk.data; + payload_str.len = h3->payload_chunk.chunk.length + - sizeof(hep_chunk_t); + SET_PVAL_STR(res, payload_str); - db_vals[23].type = DB_STR; - db_vals[23].val.str_val = sco->source_ip; + break; - db_vals[24].type = DB_INT; - db_vals[24].val.int_val = sco->source_port; + } - db_vals[25].type = DB_STR; - db_vals[25].val.str_val = sco->destination_ip; + return 0; - db_vals[26].type = DB_INT; - db_vals[26].val.int_val = sco->destination_port; +chunk_not_set: + LM_DBG("generic chunk <%d> not set!\n", chunk_id); + return -1; - db_vals[27].type = DB_STR; - db_vals[27].val.str_val = sco->contact_ip; + #undef SET_PVAL_STR + #undef SET_PVAL_INT +} - db_vals[28].type = DB_INT; - db_vals[28].val.int_val = sco->contact_port; +static int del_hep_chunk(struct hepv3* h3, unsigned int chunk_id) +{ - db_vals[29].type = DB_STR; - db_vals[29].val.str_val = sco->originator_ip; + switch (chunk_id) { + /* ip family */ + case HEP_PROTO_FAMILY: + + h3->hg.ip_family.chunk.length = 0; + + break; + /* ip protocol id */ + case HEP_PROTO_ID: + + h3->hg.ip_proto.chunk.length = 0; + + break; + case HEP_IPV4_SRC: + case HEP_IPV6_SRC: + if (h3->hg.ip_family.data == AF_INET) + h3->addr.ip4_addr.src_ip4.chunk.length = 0; + else + h3->addr.ip6_addr.src_ip6.chunk.length = 0; + + break; + /* ipv4/6 dest */ + case HEP_IPV4_DST: + case HEP_IPV6_DST: + if (h3->hg.ip_family.data == AF_INET) + h3->addr.ip4_addr.dst_ip4.chunk.length = 0; + else + h3->addr.ip6_addr.dst_ip6.chunk.length = 0; + + break; + /* ipv6 source */ + /* source port */ + case HEP_SRC_PORT: + h3->hg.src_port.chunk.length = 0; + + break; + /* destination port */ + case HEP_DST_PORT: + h3->hg.dst_port.chunk.length = 0; + + break; + /* timestamp */ + case HEP_TIMESTAMP: + h3->hg.time_sec.chunk.length = 0; + + break; + /* timestamp us offset */ + case HEP_TIMESTAMP_US: + h3->hg.time_usec.chunk.length = 0; + + break; + /* proto type (SIP, ...) */ + case HEP_PROTO_TYPE: + h3->hg.proto_t.chunk.length = 0; + + break; + /* capture agent id */ + case HEP_AGENT_ID: + h3->hg.capt_id.chunk.length = 0; + + break; + /* payload */ + case HEP_PAYLOAD: + case HEP_COMPRESSED_PAYLOAD/* gzipped payload */: + h3->payload_chunk.chunk.length = 0; + + break; + } - db_vals[30].type = DB_INT; - db_vals[30].val.int_val = sco->originator_port; + return 1; +} - db_vals[31].type = DB_INT; - db_vals[31].val.int_val = sco->proto; - db_vals[32].type = DB_INT; - db_vals[32].val.int_val = sco->family; - db_vals[33].type = DB_STR; - db_vals[33].val.str_val = sco->rtp_stat; - db_vals[34].type = DB_INT; - db_vals[34].val.int_val = sco->type; +static int pv_get_hep_net(struct sip_msg *msg, pv_param_t *param, + pv_value_t *res) +{ + #define SET_PVAL_INT(__pval__, __ival__) \ + do { \ + __pval__->flags = PV_VAL_STR|PV_VAL_INT; \ + __pval__->ri = __ival__; \ + __pval__->rs.len += \ + snprintf(__pval__->rs.s + __pval__->rs.len, \ + HEPBUF_LEN, "%d", __ival__); \ + } while(0); - db_vals[35].type = DB_STR; - db_vals[35].val.str_val = sco->node; + #define SET_PVAL_STR(__pval__, __sval__) \ + do { \ + __pval__->flags = PV_VAL_STR; \ + __pval__->rs.len += \ + snprintf(__pval__->rs.s + __pval__->rs.len, \ + HEPBUF_LEN, "%.*s", __sval__.len, __sval__.s); \ + } while(0); - db_vals[36].type = DB_BLOB; - db_vals[36].val.blob_val = sco->msg; - /* no field can be null */ - for (i=0;istat, 1); - #endif + ctx = HEP_GET_CONTEXT(hep_api); + if (ctx == NULL) { + LM_ERR("Hep context not there!"); + return -1; + } - return ret; -} + if (ctx->h.version != 3) { + LM_ERR("hep version 3 or more required for all hep variables!\n"); + return -1; + } + ri = &ctx->ri; -static int db_sync_store(db_val_t* db_vals) -{ - LM_DBG("storing info...\n"); + if (get_hepvar_name(msg, param, &net_info_type) < 0) { + LM_ERR("failed to get variable index/name!\n"); + return -1; + } - if (con_set_inslist(&db_funcs,db_con,&ins_list,db_keys,NR_KEYS) < 0 ) - CON_RESET_INSLIST(db_con); - CON_PS_REFERENCE(db_con) = &sipcapture_ps; + if (net_info_type < HEP_PROTO_FAMILY || net_info_type > HEP_DST_PORT) { + LM_ERR("Invalid hep net var name!\n"); + return -1; + } - if (db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0) { - LM_ERR("failed to insert into database\n"); - goto error; + + hep_str.len = 0; + memset(hep_str.s, 0, HEPBUF_LEN); + + res->rs = hep_str; + res->flags = PV_VAL_STR; + + + /* FIXME TODO FIXME TODO replace with recieve_info from extended hep struct */ + switch (net_info_type) { + /* ip family */ + case HEP_PROTO_FAMILY: + if (ri->src_ip.af == AF_INET) { + SET_PVAL_STR(res, afinet_str); + } else { + SET_PVAL_STR(res, afinet6_str); + } + break; + /* ip protocol id */ + case HEP_PROTO_ID: + if (ri->proto < PROTO_UDP || ri->proto >= PROTO_OTHER) { + LM_ALERT("Invalid proto!Maybe a new one was added %d\n", + ri->proto); + return -1; + } + SET_PVAL_STR(res, hep_net_protos[ri->proto]); + + break; + /* ipv4 source */ + case HEP_IPV4_SRC: + case HEP_IPV6_SRC: + if (ri->src_ip.af == AF_INET) { + if (inet_ntop(AF_INET, &ri->src_ip.u.addr, + addr, INET_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + } else { + if (inet_ntop(AF_INET6, &ri->src_ip.u.addr, + addr, INET6_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + } + + addr_str.s = addr; + addr_str.len = strlen(addr); + + SET_PVAL_STR(res, addr_str); + + break; + /* ipv4 dest */ + case HEP_IPV4_DST: + case HEP_IPV6_DST: + if (ri->dst_ip.af == AF_INET) { + if (inet_ntop(AF_INET, &ri->dst_ip.u.addr, + addr, INET_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + } else { + if (inet_ntop(AF_INET6, &ri->dst_ip.u.addr, + addr, INET6_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + } + + addr_str.s = addr; + addr_str.len = strlen(addr); + + SET_PVAL_STR(res, addr_str); + + break; + /* source port */ + case HEP_SRC_PORT: + SET_PVAL_INT(res, ri->src_port); + + break; + /* destination port */ + case HEP_DST_PORT: + SET_PVAL_INT(res, ri->dst_port); + + break; + default: + break; } - return 1; -error: - return -1; + return 0; + + #undef SET_PVAL_STR + #undef SET_PVAL_INT } -static int db_async_store(db_val_t* db_vals, - async_resume_module **resume_f, void **resume_param) +static int +set_generic_hep_chunk(struct hepv3* h3, unsigned chunk_id, str *data) { - int ret; - int read_fd; - str query_str; + #define CHECK_LEN(_str, _len, _fail_fmt, ...) \ + do { \ + if (_str->len < _len) { \ + LM_ERR("invalid "#_fail_fmt, __VA_ARGS__); \ + return -1; \ + } \ + } while(0); - sc_async_param_t as_param; + #define CHECK_PROTO_LEN(_str, _len) CHECK_LEN(_str, _len, \ + "invalid protocol <%.*s>!\n", _str->len, _str->s); - if (!DB_CAPABILITY(db_funcs, DB_CAP_ASYNC_RAW_QUERY)) { - LM_WARN("This database module does not have async queries!" - "Using sync insert!\n"); - *resume_f = NULL; - *resume_param = NULL; - async_status = ASYNC_NO_IO; - return db_sync_store(db_vals); - } + #define CHECK_PROTOT_LEN(_str, _len) CHECK_LEN(_str, _len, \ + "invalid prot_t <%.*s>!\n", _str->len, _str->s); - lock_get(&query_lock); + #define RETURN_ERROR(_format, ...) \ + do { \ + LM_ERR(_format, __VA_ARGS__); \ + return -1; \ + } while (0); - if (curr_queries == 0) { - query_len = base_query_len; - } else { - /* VALUES delimiter*/ - query_buf[query_len++]=','; - } + unsigned int port; + unsigned int capture_id; - ret = snprintf(query_buf+query_len, MAX_QUERY-query_len, VALUES_STR, - VAL_INT(db_vals+0), VAL_TIME(db_vals+1), VAL_BIGINT(db_vals+2), - VAL_STR(db_vals+3).len, VAL_STR(db_vals+3).s, - VAL_STR(db_vals+4).len, VAL_STR(db_vals+4).s, - VAL_STR(db_vals+5).len, VAL_STR(db_vals+5).s, - VAL_STR(db_vals+6).len, VAL_STR(db_vals+6).s, - VAL_STR(db_vals+7).len, VAL_STR(db_vals+7).s, - VAL_STR(db_vals+8).len, VAL_STR(db_vals+8).s, - VAL_STR(db_vals+9).len, VAL_STR(db_vals+9).s, - VAL_STR(db_vals+10).len, VAL_STR(db_vals+10).s, - VAL_STR(db_vals+11).len, VAL_STR(db_vals+11).s, - VAL_STR(db_vals+12).len, VAL_STR(db_vals+12).s, - VAL_STR(db_vals+13).len, VAL_STR(db_vals+13).s, - VAL_STR(db_vals+14).len, VAL_STR(db_vals+14).s, - VAL_STR(db_vals+15).len, VAL_STR(db_vals+15).s, - VAL_STR(db_vals+16).len, VAL_STR(db_vals+16).s, - VAL_STR(db_vals+17).len, VAL_STR(db_vals+17).s, - VAL_STR(db_vals+18).len, VAL_STR(db_vals+18).s, - VAL_STR(db_vals+19).len, VAL_STR(db_vals+19).s, - VAL_STR(db_vals+20).len, VAL_STR(db_vals+20).s, - VAL_STR(db_vals+21).len, VAL_STR(db_vals+21).s, - VAL_STR(db_vals+22).len, VAL_STR(db_vals+22).s, - VAL_STR(db_vals+23).len, VAL_STR(db_vals+23).s, - VAL_INT(db_vals+24), - VAL_STR(db_vals+25).len, VAL_STR(db_vals+25).s, - VAL_INT(db_vals+26), - VAL_STR(db_vals+27).len, VAL_STR(db_vals+27).s, - VAL_INT(db_vals+28), - VAL_STR(db_vals+29).len, VAL_STR(db_vals+29).s, - VAL_INT(db_vals+30), VAL_INT(db_vals+31), VAL_INT(db_vals+30), - VAL_STR(db_vals+33).len, VAL_STR(db_vals+33).s, - VAL_INT(db_vals+34), - VAL_STR(db_vals+35).len, VAL_STR(db_vals+35).s, - VAL_BLOB(db_vals+36).len, VAL_BLOB(db_vals+36).s - ); - if (ret < 0) - goto no_buffer; + switch (chunk_id) { + /* ip family - this can't be set; it will be automatically set + * if you change ip addresses */ + case HEP_PROTO_FAMILY: + h3->hg.ip_family.chunk.length = sizeof(hep_chunk_uint8_t); - query_len += ret; + LM_DBG("Proto family can't be set!" + " It shall be automatically updated when you change addresses!\n"); + return 0; + /* ip protocol id */ + case HEP_PROTO_ID: + /** possible values(string) + * UDP + * TCP + * TLS + * SCTP + * WS + */ + h3->hg.ip_proto.chunk.length = sizeof(hep_chunk_uint8_t); + + CHECK_PROTO_LEN(data, 2); + + switch (LOWER_WORD(data->s[0], data->s[1])) { + case LOWER_WORD('u','d'): + CHECK_PROTO_LEN(data, 3); + if (LOWER_BYTE(data->s[2]) != 'p') + RETURN_ERROR("invalid proto %.*s\n", data->len, data->s); + + h3->hg.ip_proto.data = PROTO_UDP; + break; + case LOWER_WORD('t','c'): + CHECK_PROTO_LEN(data, 3); + if (LOWER_BYTE(data->s[2]) != 'p') + RETURN_ERROR("invalid proto %.*s\n", data->len, data->s); + + h3->hg.ip_proto.data = PROTO_TCP; + break; + case LOWER_WORD('t','l'): + if (LOWER_BYTE(data->s[2]) != 's') + RETURN_ERROR("invalid proto %.*s\n", data->len, data->s); + + h3->hg.ip_proto.data = PROTO_TLS; + break; + case LOWER_WORD('s','c'): + if (LOWER_WORD(data->s[2], data->s[3]) != LOWER_WORD('t', 'p')) + RETURN_ERROR("invalid proto %.*s\n", data->len, data->s); + + h3->hg.ip_proto.data = PROTO_SCTP; + break; + case LOWER_WORD('w','s'): + h3->hg.ip_proto.data = PROTO_WS; + break; + default: + LM_ERR("invalid protocol <%.*s>!\n", data->len, data->s); + return -1; + } + break; + /* ipv4 source */ + case HEP_IPV4_SRC: + case HEP_IPV6_SRC: + /** possible values(string) + * ip address in human readable format + */ + if (inet_pton(AF_INET, data->s, &h3->addr.ip4_addr.src_ip4.data) == 0) { + /* check if it's ipV6*/ + if (inet_pton(AF_INET6, data->s, &h3->addr.ip6_addr.src_ip6.data) == 0) { + RETURN_ERROR("address <<%.*s>> it's neither IPv4 nor IPv6!\n", + data->len, data->s); + } else { + /* it's IPv6 change ip family*/ + if (h3->hg.ip_family.data == AF_INET) { + LM_DBG("You changed source address in hep header to IPv6!" + " You also have to change destination IP in order to work!\n"); + h3->hg.ip_family.data = AF_INET6; + } + h3->addr.ip6_addr.src_ip6.chunk.length = sizeof(hep_chunk_ip6_t); - if ((++curr_queries) == max_async_queries) { - curr_queries = 0; + } + } else { + if (h3->hg.ip_family.data == AF_INET6) { + LM_DBG("You changed source address in hep header to IPv6!" + " You also have to change destination IP in order to work!\n"); + h3->hg.ip_family.data = AF_INET; + } + h3->addr.ip4_addr.src_ip4.chunk.length = sizeof(hep_chunk_ip4_t); + } - query_str.s = query_buf; - query_str.len = query_len; - read_fd = db_funcs.async_raw_query(db_con, &query_str, &as_param); + break; + /* ipv4 dest */ + case HEP_IPV4_DST: + case HEP_IPV6_DST: + /** possible values(string) + * ip address in human readable format + */ + if (inet_pton(AF_INET, data->s, &h3->addr.ip4_addr.dst_ip4.data) == 0) { + /* check if it's ipV6*/ + if (inet_pton(AF_INET6, data->s, &h3->addr.ip6_addr.dst_ip6.data) == 0) { + RETURN_ERROR("address <<%.*s>> it's neither IPv4 nor IPv6!\n", + data->len, data->s); + } else { + /* it's IPv6 change ip family*/ + if (h3->hg.ip_family.data == AF_INET) { + LM_DBG("You changed source address in hep header to IPv6!" + " You also have to change destination IP in order to work!\n"); + h3->hg.ip_family.data = AF_INET6; + } + h3->addr.ip6_addr.dst_ip6.chunk.length = sizeof(hep_chunk_ip6_t); - lock_release(&query_lock); + } + } else { + if (h3->hg.ip_family.data == AF_INET6) { + LM_DBG("You changed source address in hep header to IPv6!" + " You also have to change destination IP in order to work!\n"); + h3->hg.ip_family.data = AF_INET; + } + h3->addr.ip4_addr.dst_ip4.chunk.length = sizeof(hep_chunk_ip4_t); + } - if (read_fd < 0) { - *resume_param = NULL; - *resume_f = NULL; - return -1; + break; + /* source port */ + case HEP_SRC_PORT: + /** possible values(string/int) + * valid port + */ + if (str2int(data, &port) < 0) + RETURN_ERROR("invalid port <%.*s>!\n", data->len, data->s); + + if (port > 65535) + RETURN_ERROR("port not in range <%d>!\n", port); + + h3->hg.src_port.data = port; + h3->hg.src_port.chunk.length = sizeof(hep_chunk_uint16_t); + + break; + /* destination port */ + case HEP_DST_PORT: + /** possible values(string/int) + * valid port + */ + if (str2int(data, &port) < 0) + RETURN_ERROR("invalid port <%.*s>!\n", data->len, data->s); + + if (port > 65535) + RETURN_ERROR("port not in range <%d>!\n", port); + + h3->hg.dst_port.data = port; + h3->hg.dst_port.chunk.length = sizeof(hep_chunk_uint16_t); + + break; + case HEP_TIMESTAMP: + case HEP_TIMESTAMP_US: + LM_WARN("Timestamp can't be set!\n"); + return 0; + case HEP_PROTO_TYPE: + /** possible values(string) + * SIP | XMPP | SDP | RTP | RTCP | MGCP | MEGACO + * | M2UA | M3UA | IAX | H322 | H321 + */ + + h3->hg.proto_t.chunk.length = sizeof(hep_chunk_uint8_t); + + CHECK_PROTOT_LEN(data, 3); + + switch (LOWER_DWORD(data->s[0], data->s[1], data->s[2], + ((data->len > 3) ? data->s[3] : 0))) { + case LOWER_DWORD('s','i','p',0): + h3->hg.proto_t.data = 0x01; + break; + case LOWER_DWORD('x','m','p','p'): + h3->hg.proto_t.data = 0x02; + break; + case LOWER_DWORD('s','d','p',0): + h3->hg.proto_t.data = 0x03; + break; + case LOWER_DWORD('r','t','p',0): + h3->hg.proto_t.data = 0x04; + break; + case LOWER_DWORD('r','t','c','p'): + h3->hg.proto_t.data = 0x05; + break; + case LOWER_DWORD('m','g','c','p'): + h3->hg.proto_t.data = 0x06; + break; + case LOWER_DWORD('m','e','g','a'): + CHECK_PROTOT_LEN(data, 6) + if ((LOWER_BYTE(data->s[4]) != 'c' + && LOWER_BYTE(data->s[5]) != 'o')) + RETURN_ERROR("invalid prot_t type <%.*s>!\n", + data->len, data->s); + h3->hg.proto_t.data = 0x07; + break; + case LOWER_DWORD('m','2','u','a'): + h3->hg.proto_t.data = 0x08; + break; + case LOWER_DWORD('m','3','u','a'): + h3->hg.proto_t.data = 0x09; + break; + case LOWER_DWORD('i','a','x',0): + h3->hg.proto_t.data = 0x0A; + break; + case LOWER_DWORD('h','3','2','2'): + h3->hg.proto_t.data = 0x0B; + break; + case LOWER_DWORD('h','3','2','1'): + h3->hg.proto_t.data = 0x0C; + break; + default: + RETURN_ERROR("invalid prot_t type <%.*s>!\n", + data->len, data->s); } + break; + /* capture agent id */ + case HEP_AGENT_ID: + /* DATA here */ + if (str2int(data, &capture_id) < 0) + RETURN_ERROR("invalid capture id <%.*s>!\n", + data->len, data->s); + + h3->hg.capt_id.data = capture_id; + h3->hg.capt_id.chunk.length = sizeof(hep_chunk_uint32_t); + + break; + /* payload */ + case HEP_PAYLOAD: + case HEP_COMPRESSED_PAYLOAD: + if (data->len>MAX_PAYLOAD) { + LM_ERR("payload too big! Might be a message from an attacker!\n"); + return -1; + } - *resume_param = as_param; - *resume_f = resume_async_dbquery; - async_status = read_fd; + memcpy(payload_buf, data->s, data->len); + h3->payload_chunk.data = payload_buf; + h3->payload_chunk.chunk.length = data->len + sizeof(hep_chunk_t); - return 1; + break; + /* internal correlation id */ + case HEP_CORRELATION_ID: + LM_WARN("not implemented yet!won't set\n"); + break; + /* vlan ID */ } - lock_release(&query_lock); + return 1; - LM_DBG("no query executed!\n"); - async_status = ASYNC_NO_IO; + #undef CHECK_LEN + #undef PROTO_LEN + #undef PROTOT_LEN + #undef RETURN_ERROR - return 1; -no_buffer: - LM_ERR("buffer size exceeded\n"); - return -1; } -int resume_async_dbquery(int fd, struct sip_msg *msg, void *_param) -{ - int rc; - rc = db_funcs.async_raw_resume(db_con, fd, NULL, (sc_async_param_t)_param); - if (async_status == ASYNC_CONTINUE || async_status == ASYNC_CHANGE_FD) - return rc; +int extract_host_port(void) +{ + if(raw_socket_listen.len) { + char *p1,*p2; + p1 = raw_socket_listen.s; - if (rc != 0) { - LM_ERR("async query returned error!\n"); + if( (p1 = strrchr(p1, ':')) != 0 ) { + *p1 = '\0'; + p1++; + p2=p1; + if((p2 = strrchr(p2, '-')) != 0 ) { + p2++; + moni_port_end = atoi(p2); + p1[strlen(p1)-strlen(p2)-1]='\0'; + } + moni_port_start = atoi(p1); + raw_socket_listen.len = strlen(raw_socket_listen.s); + } + return 1; + } + return 0; +} + + +static int child_init(int rank) +{ + + if (rank==PROC_MAIN || rank==PROC_TCP_MAIN) + return 0; /* do nothing for the main process */ + + if (db_url.s) + return sipcapture_db_init(&db_url); + + LM_ERR("db_url is empty\n"); + + return 0; +} + + +int sipcapture_db_init(const str* db_url) { + + + if(db_funcs.init == 0) { + LM_CRIT("null dbf\n"); + goto error; + } + + db_con = db_funcs.init(db_url); + if (!db_con) { + LM_ERR("unable to connect database\n"); return -1; } - LM_DBG("Async query executed with success!\n"); - async_status = ASYNC_DONE; + if (db_funcs.use_table(db_con, &table_name) < 0) { + LM_ERR("use_table failed\n"); + return -1; + } - return 1; + return 0; + +error: + return -1; } -static int sip_capture(struct sip_msg *msg, char* s1, char* s2) +void sipcapture_db_close(void) { - return w_sip_capture(msg, NULL, NULL); + if (db_con && db_funcs.close){ + db_funcs.close(db_con); + db_con=0; + } + } -static int async_sip_capture(struct sip_msg* msg, async_resume_module **resume_f, - void **resume_param, str* s1, str* s2) +static void raw_socket_process(int rank) { - return w_sip_capture(msg, resume_f, resume_param); + if (sipcapture_db_init(&db_url) < 0 ){ + LM_ERR("unable to open database connection\n"); + return; + } + + raw_capture_rcv_loop(raw_sock_desc, moni_port_start, moni_port_end, + moni_capture_on ? 0 : 1); + + /* Destroy DB socket */ + sipcapture_db_close(); +} + + +static void destroy(void) +{ + str query_str; + + /* execute the uninserted queries */ + if (DB_CAPABILITY(db_funcs, DB_CAP_ASYNC_RAW_QUERY)) { + if (curr_queries) { + if (!db_con) { + db_con = db_funcs.init(&db_url); + if (!db_con) { + LM_ERR("unable to connect database\n"); + goto destroy_continue; + } + + if (db_funcs.use_table(db_con, &table_name) < 0) { + LM_ERR("use_table failed\n"); + goto destroy_continue; + } + } + + query_str.s = query_buf; + query_str.len = query_len; + + if (db_funcs.raw_query(db_con, &query_str, NULL)) { + LM_ERR("failed to insert remaining queries\n"); + } + lock_destroy(&query_lock); + } + + shm_free(async_query); + } + + /* Destroy DB socket */ + sipcapture_db_close(); + +destroy_continue: + + if (capture_on_flag) + shm_free(capture_on_flag); + + if(raw_sock_desc > 0) { + if(promisc_on && raw_interface.len) { +#ifdef __OS_linux + ifr.ifr_flags &= ~(IFF_PROMISC); + + if (ioctl(raw_sock_desc, SIOCSIFFLAGS, &ifr) < 0) { + LM_ERR("could not remove PROMISC flag from interface [%.*s]:" + " %s (%d)\n", raw_interface.len, raw_interface.s, strerror(errno), errno); + } +#endif + } + close(raw_sock_desc); + } +} + +/** + * HEP message + */ +int hep_msg_received(struct hep_desc *h, struct receive_info *ri) +{ + + struct sip_msg msg; + + if(!hep_capture_on) { + LM_ERR("HEP is not enabled\n"); + return 0; + } + if (hep_store_no_script) { + memset(&msg, 0, sizeof(struct sip_msg)); + + switch (h->version) { + case 1: + case 2: + msg.buf = h->u.hepv12.payload; + msg.len = h->u.hepv12.hdr.hp_l - + (sizeof(struct hepv12)-sizeof(char*)); + break; + case 3: + msg.buf = h->u.hepv3.payload_chunk.data; + msg.len = h->u.hepv3.payload_chunk.chunk.length - sizeof(struct hep_chunk); + break; + default: + LM_ERR("unknown hep proto [%d]\n", h->version); + return -1; + } + + if (parse_msg(msg.buf,msg.len,&msg)!=0) { + LM_ERR("Unable to parse message in hep payload!" + "Hep version %d!\n", h->version); + return -1; + } + + #if 0 + /* if message not parsed ok this helps with debugging */ + LM_DBG("********************************* SIP MESSAGE ******************\n" + "%.*s\n" + "***************************************************************\n", + (int)msg.len, msg.buf); + #endif + + /* we basically move the sip_capture() call from the scripts here */ + if (w_sip_capture(&msg, NULL, NULL) < 0) { + LM_ERR("failed to store the message!\n"); + return -1; + } + + /* return a special code which will tell hep not to run the script */ + return HEP_SCRIPT_SKIP; + } + + return 0; +} + + +static int sip_capture_prepare(struct sip_msg* msg) +{ + /* We need parse all headers */ + if (parse_headers(msg, HDR_CALLID_F|HDR_EOH_F, 0) != 0) { + LM_ERR("cannot parse headers\n"); + return -1; + } + + return 0; +} + +static int sip_capture_store(struct _sipcapture_object *sco, + async_resume_module **resume_f, void **resume_param) +{ + db_val_t db_vals[NR_KEYS]; + int i = 0, ret; + + if(sco==NULL) + { + LM_DBG("invalid parameter\n"); + return -1; + } + + db_vals[0].type = DB_INT; + db_vals[0].val.int_val = 0; + + db_vals[1].type = DB_DATETIME; + db_vals[1].val.time_val = time(NULL); + + db_vals[2].type = DB_BIGINT; + db_vals[2].val.bigint_val = sco->tmstamp; + + db_vals[3].type = DB_STR; + db_vals[3].val.str_val = sco->method; + + db_vals[4].type = DB_STR; + db_vals[4].val.str_val = sco->reply_reason; + + db_vals[5].type = DB_STR; + db_vals[5].val.str_val = sco->ruri; + + db_vals[6].type = DB_STR; + db_vals[6].val.str_val = sco->ruri_user; + + db_vals[7].type = DB_STR; + db_vals[7].val.str_val = sco->from_user; + + db_vals[8].type = DB_STR; + db_vals[8].val.str_val = sco->from_tag; + + db_vals[9].type = DB_STR; + db_vals[9].val.str_val = sco->to_user; + + db_vals[10].type = DB_STR; + db_vals[10].val.str_val = sco->to_tag; + + db_vals[11].type = DB_STR; + db_vals[11].val.str_val = sco->pid_user; + + db_vals[12].type = DB_STR; + db_vals[12].val.str_val = sco->contact_user; + + db_vals[13].type = DB_STR; + db_vals[13].val.str_val = sco->auth_user; + + db_vals[14].type = DB_STR; + db_vals[14].val.str_val = sco->callid; + + db_vals[15].type = DB_STR; + db_vals[15].val.str_val = sco->callid_aleg; + + db_vals[16].type = DB_STR; + db_vals[16].val.str_val = sco->via_1; + + db_vals[17].type = DB_STR; + db_vals[17].val.str_val = sco->via_1_branch; + + db_vals[18].type = DB_STR; + db_vals[18].val.str_val = sco->cseq; + + db_vals[19].type = DB_STR; + db_vals[19].val.str_val = sco->reason; + + db_vals[20].type = DB_STR; + db_vals[20].val.str_val = sco->content_type; + + db_vals[21].type = DB_STR; + db_vals[21].val.str_val = sco->authorization; + + db_vals[22].type = DB_STR; + db_vals[22].val.str_val = sco->user_agent; + + db_vals[23].type = DB_STR; + db_vals[23].val.str_val = sco->source_ip; + + db_vals[24].type = DB_INT; + db_vals[24].val.int_val = sco->source_port; + + db_vals[25].type = DB_STR; + db_vals[25].val.str_val = sco->destination_ip; + + db_vals[26].type = DB_INT; + db_vals[26].val.int_val = sco->destination_port; + + db_vals[27].type = DB_STR; + db_vals[27].val.str_val = sco->contact_ip; + + db_vals[28].type = DB_INT; + db_vals[28].val.int_val = sco->contact_port; + + db_vals[29].type = DB_STR; + db_vals[29].val.str_val = sco->originator_ip; + + db_vals[30].type = DB_INT; + db_vals[30].val.int_val = sco->originator_port; + + db_vals[31].type = DB_INT; + db_vals[31].val.int_val = sco->proto; + + db_vals[32].type = DB_INT; + db_vals[32].val.int_val = sco->family; + + db_vals[33].type = DB_INT; + db_vals[33].val.int_val = sco->proto_type; + + db_vals[34].type = DB_STR; + db_vals[34].val.str_val = sco->rtp_stat; + + db_vals[35].type = DB_INT; + db_vals[35].val.int_val = sco->type; + + db_vals[36].type = DB_STR; + db_vals[36].val.str_val = sco->node; + + db_vals[37].type = DB_BLOB; + db_vals[37].val.blob_val = sco->msg; + + /* no field can be null */ + for (i=0;istat, 1); + #endif + + return ret; +} + + +static int db_sync_store(db_val_t* db_vals) +{ + LM_DBG("storing info...\n"); + + if (con_set_inslist(&db_funcs,db_con,&ins_list,db_keys,NR_KEYS) < 0 ) + CON_RESET_INSLIST(db_con); + CON_PS_REFERENCE(db_con) = &sipcapture_ps; + + if (db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0) { + LM_ERR("failed to insert into database\n"); + goto error; + } + + return 1; +error: + return -1; +} + +static int db_async_store(db_val_t* db_vals, + async_resume_module **resume_f, void **resume_param) +{ + int ret; + int read_fd; + str query_str; + + sc_async_param_t as_param; + if (!DB_CAPABILITY(db_funcs, DB_CAP_ASYNC_RAW_QUERY)) { + LM_WARN("This database module does not have async queries!" + "Using sync insert!\n"); + *resume_f = NULL; + *resume_param = NULL; + async_status = ASYNC_NO_IO; + return db_sync_store(db_vals); + } + + lock_get(&query_lock); + + if (curr_queries == 0) { + query_len = base_query_len; + } else { + /* VALUES delimiter*/ + query_buf[query_len++]=','; + } + + ret = snprintf(query_buf+query_len, MAX_QUERY-query_len, VALUES_STR, + VAL_INT(db_vals+0), VAL_TIME(db_vals+1), VAL_BIGINT(db_vals+2), + VAL_STR(db_vals+3).len, VAL_STR(db_vals+3).s, + VAL_STR(db_vals+4).len, VAL_STR(db_vals+4).s, + VAL_STR(db_vals+5).len, VAL_STR(db_vals+5).s, + VAL_STR(db_vals+6).len, VAL_STR(db_vals+6).s, + VAL_STR(db_vals+7).len, VAL_STR(db_vals+7).s, + VAL_STR(db_vals+8).len, VAL_STR(db_vals+8).s, + VAL_STR(db_vals+9).len, VAL_STR(db_vals+9).s, + VAL_STR(db_vals+10).len, VAL_STR(db_vals+10).s, + VAL_STR(db_vals+11).len, VAL_STR(db_vals+11).s, + VAL_STR(db_vals+12).len, VAL_STR(db_vals+12).s, + VAL_STR(db_vals+13).len, VAL_STR(db_vals+13).s, + VAL_STR(db_vals+14).len, VAL_STR(db_vals+14).s, + VAL_STR(db_vals+15).len, VAL_STR(db_vals+15).s, + VAL_STR(db_vals+16).len, VAL_STR(db_vals+16).s, + VAL_STR(db_vals+17).len, VAL_STR(db_vals+17).s, + VAL_STR(db_vals+18).len, VAL_STR(db_vals+18).s, + VAL_STR(db_vals+19).len, VAL_STR(db_vals+19).s, + VAL_STR(db_vals+20).len, VAL_STR(db_vals+20).s, + VAL_STR(db_vals+21).len, VAL_STR(db_vals+21).s, + VAL_STR(db_vals+22).len, VAL_STR(db_vals+22).s, + VAL_STR(db_vals+23).len, VAL_STR(db_vals+23).s, + VAL_INT(db_vals+24), + VAL_STR(db_vals+25).len, VAL_STR(db_vals+25).s, + VAL_INT(db_vals+26), + VAL_STR(db_vals+27).len, VAL_STR(db_vals+27).s, + VAL_INT(db_vals+28), + VAL_STR(db_vals+29).len, VAL_STR(db_vals+29).s, + VAL_INT(db_vals+30), VAL_INT(db_vals+31), VAL_INT(db_vals+30), + VAL_STR(db_vals+33).len, VAL_STR(db_vals+33).s, + VAL_INT(db_vals+34), + VAL_STR(db_vals+35).len, VAL_STR(db_vals+35).s, + VAL_BLOB(db_vals+36).len, VAL_BLOB(db_vals+36).s + ); + + if (ret < 0) + goto no_buffer; + + query_len += ret; + + + if ((++curr_queries) == max_async_queries) { + curr_queries = 0; + + query_str.s = query_buf; + query_str.len = query_len; + read_fd = db_funcs.async_raw_query(db_con, &query_str, &as_param); + + lock_release(&query_lock); + + if (read_fd < 0) { + *resume_param = NULL; + *resume_f = NULL; + return -1; + } + *resume_param = as_param; + *resume_f = resume_async_dbquery; + async_status = read_fd; + + return 1; + } + + lock_release(&query_lock); + + LM_DBG("no query executed!\n"); + async_status = ASYNC_NO_IO; + + return 1; +no_buffer: + LM_ERR("buffer size exceeded\n"); + return -1; +} + + +int resume_async_dbquery(int fd, struct sip_msg *msg, void *_param) +{ + int rc; + + + rc = db_funcs.async_raw_resume(db_con, fd, NULL, (sc_async_param_t)_param); + if (async_status == ASYNC_CONTINUE || async_status == ASYNC_CHANGE_FD) + return rc; + + if (rc != 0) { + LM_ERR("async query returned error!\n"); + return -1; + } + + LM_DBG("Async query executed with success!\n"); + async_status = ASYNC_DONE; + + return 1; +} + +static int sip_capture(struct sip_msg *msg, char* s1, char* s2) +{ + return w_sip_capture(msg, NULL, NULL); +} + +static int async_sip_capture(struct sip_msg* msg, async_resume_module **resume_f, + void **resume_param, str* s1, str* s2) +{ + return w_sip_capture(msg, resume_f, resume_param); +} + + +static int w_sip_capture(struct sip_msg *msg, + async_resume_module **resume_f, void **resume_param) +{ + struct _sipcapture_object sco; + struct sip_uri from, to, pai, contact; + struct hdr_field *hook1 = NULL; + struct hdr_field *tmphdr[4]; + contact_body_t* cb=0; + char src_buf_ip[IP_ADDR_MAX_STR_SIZE+12]; + char dst_buf_ip[IP_ADDR_MAX_STR_SIZE+12]; + char *port_str = NULL, *tmp = NULL; + struct timeval tvb; + struct timezone tz; + char tmp_node[100]; + + struct hep_desc *h=NULL; + struct hep_context* ctx; + + gettimeofday( &tvb, &tz ); + + if(msg==NULL) { + LM_DBG("nothing to capture\n"); + return -1; + } + memset(&sco, 0, sizeof(struct _sipcapture_object)); + + if (hep_capture_on) { + if ((ctx=HEP_GET_CONTEXT(hep_api))==NULL) { + LM_WARN("not a hep message!\n"); + return -1; + } + + h = &ctx->h; + } + + + if(capture_on_flag==NULL || *capture_on_flag==0) { + LM_DBG("capture off...\n"); + return -1; + } + + if(sip_capture_prepare(msg)<0) return -1; + + if (h && h->version==3) { + /*hepv3; struct might have been modified in script */ + sco.tmstamp = + (unsigned long long)h->u.hepv3.hg.time_sec.data*1000000 + + h->u.hepv3.hg.time_usec.data; + snprintf(tmp_node, 100, "%.*s:%i", capture_node.len, + capture_node.s, h->u.hepv3.hg.capt_id.data); + sco.node.s = tmp_node; + sco.node.len = strlen(tmp_node); + } + else if(h && h->version==2) { + sco.tmstamp = + (unsigned long long)h->u.hepv12.hep_time.tv_sec*1000000+ + h->u.hepv12.hep_time.tv_usec; /* micro ts */ + snprintf(tmp_node, 100, "%.*s:%i", capture_node.len, capture_node.s, + h->u.hepv12.hep_time.captid); + sco.node.s = tmp_node; + sco.node.len = strlen(tmp_node); + } + else { + sco.tmstamp = (unsigned long long)tvb.tv_sec*1000000+tvb.tv_usec; /* micro ts */ + sco.node = capture_node; + } + + if(msg->first_line.type == SIP_REQUEST) { + + if (parse_sip_msg_uri(msg)<0) return -1; + + sco.method = msg->first_line.u.request.method; + EMPTY_STR(sco.reply_reason); + + sco.ruri = msg->first_line.u.request.uri; + sco.ruri_user = msg->parsed_uri.user; + } + else if(msg->first_line.type == SIP_REPLY) { + sco.method = msg->first_line.u.reply.status; + sco.reply_reason = msg->first_line.u.reply.reason; + + EMPTY_STR(sco.ruri); + EMPTY_STR(sco.ruri_user); + } + else { + LM_ERR("unknow type [%i]\n", msg->first_line.type); + EMPTY_STR(sco.method); + EMPTY_STR(sco.reply_reason); + EMPTY_STR(sco.ruri); + EMPTY_STR(sco.ruri_user); + } + + /* Parse FROM */ + if(msg->from) { + + if (parse_from_header(msg)!=0){ + LM_ERR("bad or missing" " From: header\n"); + return -1; + } + + if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len, &from)<0){ + LM_ERR("bad from dropping"" packet\n"); + return -1; + } + + sco.from_user = from.user; + sco.from_tag = get_from(msg)->tag_value; + } + else { + EMPTY_STR(sco.from_user); + EMPTY_STR(sco.from_tag); + } + + /* Parse TO */ + if(msg->to) { + + if (parse_uri(get_to(msg)->uri.s, get_to(msg)->uri.len, &to)<0){ + LM_ERR("bad to dropping"" packet\n"); + return -1; + } + + sco.to_user = to.user; + if(get_to(msg)->tag_value.len) + sco.to_tag = get_to(msg)->tag_value; + else { EMPTY_STR(sco.to_tag); } + } + else { + EMPTY_STR(sco.to_user); + 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 && (parse_pai_header(msg) == 0)) { + + if (parse_uri(get_pai(msg)->uri.s, get_pai(msg)->uri.len, &pai)<0){ + LM_DBG("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; + } + } + else if(msg->ppi && (parse_ppi_header(msg) == 0)) { + + if (parse_uri(get_ppi(msg)->uri.s, get_ppi(msg)->uri.len, &pai)<0){ + LM_DBG("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; + } + } + else { EMPTY_STR(sco.pid_user); } + + /* Auth headers */ + if(msg->proxy_auth != NULL) hook1 = msg->proxy_auth; + else if(msg->authorization != NULL) hook1 = msg->authorization; + + if(hook1) { + if(parse_credentials(hook1) == 0) sco.auth_user = ((auth_body_t*)(hook1->parsed))->digest.username.user; + else { EMPTY_STR(sco.auth_user); } + } + else { EMPTY_STR(sco.auth_user);} + + if(msg->contact) { + + if (msg->contact->parsed == 0 && parse_contact(msg->contact) == -1) { + LM_ERR("while parsing header\n"); + return -1; + } + + cb = (contact_body_t*)msg->contact->parsed; + + if(cb && cb->contacts) { + if(parse_uri( cb->contacts->uri.s, cb->contacts->uri.len, &contact)<0){ + LM_ERR("bad contact dropping packet\n"); + return -1; + } + } + } + + /* get header x-cid: */ + /* callid_aleg X-CID */ + if((tmphdr[0] = get_header_by_static_name(msg,"X-CID")) != NULL) { + sco.callid_aleg = tmphdr[0]->body; + } + else { EMPTY_STR(sco.callid_aleg);} + + /* VIA 1 */ + sco.via_1 = msg->h_via1->body; + + /* Via branch */ + if(msg->via1->branch) sco.via_1_branch = msg->via1->branch->value; + else { EMPTY_STR(sco.via_1_branch); } + + /* CSEQ */ + if(msg->cseq) sco.cseq = msg->cseq->body; + else { EMPTY_STR(sco.cseq); } + + /* Reason */ + if((tmphdr[1] = get_header_by_static_name(msg,"Reason")) != NULL) { + sco.reason = tmphdr[1]->body; + } + else { EMPTY_STR(sco.reason); } + + /* Diversion */ + if(msg->diversion) sco.diversion = msg->diversion->body; + else { EMPTY_STR(sco.diversion);} + + /* Content-type */ + if(msg->content_type) sco.content_type = msg->content_type->body; + else { EMPTY_STR(sco.content_type);} + + /* User-Agent */ + if(msg->user_agent) sco.user_agent = msg->user_agent->body; + else { EMPTY_STR(sco.user_agent);} + + /* Contact */ + if(msg->contact && cb) { + sco.contact_ip = contact.host; + str2int(&contact.port, (unsigned int*)&sco.contact_port); + } + else { + EMPTY_STR(sco.contact_ip); + sco.contact_port = 0; + } + + /* X-OIP */ + if((tmphdr[2] = get_header_by_static_name(msg,"X-OIP")) != NULL) { + sco.originator_ip = tmphdr[2]->body; + /* Originator port. Should be parsed from XOIP header as ":" param */ + tmp = strchr(tmphdr[2]->body.s, ':'); + if (tmp) { + *tmp = '\0'; + port_str = tmp + 1; + sco.originator_port = strtol(port_str, NULL, 10); + } + else sco.originator_port = 0; + } + else { + EMPTY_STR(sco.originator_ip); + sco.originator_port = 0; + } + + /* X-RTP-Stat */ + if((tmphdr[3] = get_header_by_static_name(msg,"X-RTP-Stat")) != NULL) { + sco.rtp_stat = tmphdr[3]->body; + } + /* P-RTP-Stat */ + else if((tmphdr[3] = get_header_by_static_name(msg,"P-RTP-Stat")) != NULL) { + sco.rtp_stat = tmphdr[3]->body; + } + else { EMPTY_STR(sco.rtp_stat); } + + + /* PROTO TYPE + * FAMILY TYPE */ + if (h && h->version==3) { + sco.proto = h->u.hepv3.hg.ip_proto.data; + sco.family = h->u.hepv3.hg.ip_family.data; + /*SIP, XMPP... */ + sco.proto_type = h->u.hepv3.hg.proto_t.data; + + if (h->u.hepv3.hg.ip_family.data == AF_INET) { + if (inet_ntop(AF_INET, &h->u.hepv3.addr.ip4_addr.src_ip4.data, + src_buf_ip, INET_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + + if (inet_ntop(AF_INET, &h->u.hepv3.addr.ip4_addr.dst_ip4.data, + dst_buf_ip, INET_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + } else { + if (inet_ntop(AF_INET6, &h->u.hepv3.addr.ip6_addr.src_ip6.data, + src_buf_ip, INET6_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + + if (inet_ntop(AF_INET6, &h->u.hepv3.addr.ip6_addr.dst_ip6.data, + dst_buf_ip, INET6_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + } + + sco.source_ip.s = src_buf_ip; + sco.source_ip.len = strlen(src_buf_ip); + sco.source_port = h->u.hepv3.hg.src_port.data; + + sco.destination_ip.s = dst_buf_ip; + sco.destination_ip.len = strlen(dst_buf_ip); + sco.destination_port = h->u.hepv3.hg.dst_port.data; + } else if (h && (h->version == 1 || h->version == 2)) { + sco.proto = h->u.hepv12.hdr.hp_p; + sco.family = h->u.hepv12.hdr.hp_f; + /* default SIP; hepv12 doesn't have proto type */ + sco.proto_type = 0x01; + + if (sco.family == AF_INET) { + if (inet_ntop(AF_INET, + &h->u.hepv12.addr.hep_ipheader.hp_src, + src_buf_ip, INET_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + + if (inet_ntop(AF_INET, + &h->u.hepv12.addr.hep_ipheader.hp_dst, + dst_buf_ip, INET_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + } else { + if (inet_ntop(AF_INET6, + &h->u.hepv12.addr.hep_ip6header.hp6_src, + src_buf_ip, INET6_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + + if (inet_ntop(AF_INET6, + &h->u.hepv12.addr.hep_ip6header.hp6_dst, + dst_buf_ip, INET6_ADDRSTRLEN) == NULL) { + LM_ERR("failed to convert ipv4 address!\n"); + return -1; + } + } + + sco.source_ip.s = src_buf_ip; + sco.source_ip.len = strlen(src_buf_ip); + sco.source_port = h->u.hepv12.hdr.hp_sport; + + sco.destination_ip.s = dst_buf_ip; + sco.destination_ip.len = strlen(dst_buf_ip); + sco.destination_port = h->u.hepv12.hdr.hp_dport; + } else { + sco.proto = msg->rcv.proto; + sco.family = msg->rcv.src_ip.af; + + /* IP source and destination */ + + /*source ip*/ + memcpy(src_buf_ip, ip_addr2a(&msg->rcv.src_ip), + sizeof(&msg->rcv.src_ip)); + ip_addr2a((struct ip_addr*)src_buf_ip); + sco.source_ip.s = src_buf_ip; + sco.source_ip.len = strlen(src_buf_ip); + sco.source_port = msg->rcv.src_port; + + + /*destination ip*/ + memcpy(dst_buf_ip, ip_addr2a(&msg->rcv.dst_ip), + sizeof(&msg->rcv.dst_ip)); + ip_addr2a((struct ip_addr*)dst_buf_ip); + sco.destination_ip.s = dst_buf_ip; + sco.destination_ip.len = strlen(sco.destination_ip.s); + sco.destination_port = msg->rcv.dst_port; + } + + if(sco.proto == PROTO_UDP) sco.proto=IPPROTO_UDP; + else if(sco.proto == PROTO_TCP) sco.proto=IPPROTO_TCP; + else if(sco.proto == PROTO_TLS) sco.proto=IPPROTO_IDP; + /* fake protocol */ + else if(sco.proto == PROTO_SCTP) sco.proto=IPPROTO_SCTP; + else if(sco.proto == PROTO_WS) sco.proto=IPPROTO_ESP; + /* fake protocol */ + else { + LM_ERR("unknown protocol [%d]\n",sco.proto); + sco.proto = PROTO_NONE; + } + + + LM_DBG("src_ip: [%.*s]\n", sco.source_ip.len, sco.source_ip.s); + LM_DBG("dst_ip: [%.*s]\n", sco.destination_ip.len, sco.destination_ip.s); + + LM_DBG("dst_port: [%d]\n", sco.destination_port); + LM_DBG("src_port: [%d]\n", sco.source_port); + + /* PROTO */ + + /* MESSAGE TYPE */ + sco.type = msg->first_line.type; + + /* MSG */ + if (h && h->version == 3) { + sco.msg.s = h->u.hepv3.payload_chunk.data; + sco.msg.len = h->u.hepv3.payload_chunk.chunk.length - sizeof(hep_chunk_t); + } else if (h && (h->version == 1 || h->version == 2)) { + sco.msg.s = h->u.hepv12.payload; + sco.msg.len = h->u.hepv12.hdr.hp_l - + /* in the struct we have a pointer for the payload; + * anything else is the size of the packet without the payload*/ + (sizeof(struct hepv12) - sizeof(char*)); + } else { + sco.msg.s = msg->buf; + sco.msg.len = msg->len; + } + //EMPTY_STR(sco.msg); + +#ifdef STATISTICS + if(msg->first_line.type==SIP_REPLY) { + sco.stat = sipcapture_rpl; + } else { + sco.stat = sipcapture_req; + } +#endif + LM_DBG("DONE\n"); + return sip_capture_store(&sco, resume_f, resume_param); +} + +/* + * resolve data type in chunk + */ +enum hep_chunk_value_type {TYPE_ERROR=0,TYPE_UINT8=1, + TYPE_UINT16=2, TYPE_UINT32=4, TYPE_INET_ADDR, + TYPE_INET6_ADDR=16, TYPE_UTF8, TYPE_BLOB}; +static int fix_hep_value_type(str *s) { + static const str type_uint_s={"uint", sizeof("uint")-1}; + static const str type_utf_string_s=str_init("utf8-string"); + static const str type_octet_string_s=str_init("octet-string"); + static const str type_inet_addr_s=str_init("inet4-addr"); + static const str type_inet6_addr_s=str_init("inet6-addr"); + + int diff; + + diff = s->len - type_uint_s.len; /* also applies to 'str' - same len as 'int' */ + + /* uintX or uintXX */ + if (diff > 0 && diff <=2 && + !strncasecmp(s->s, type_uint_s.s, type_uint_s.len)) { + if (diff == 1) { /* should be int8 */ + if (s->s[s->len-1] == '8') + return TYPE_UINT8; + else + goto error; + } else { + if (s->s[s->len-2] == '1' && s->s[s->len-1] =='6') + return TYPE_UINT16; + else if (s->s[s->len-2] == '3' && s->s[s->len-1] =='2') + return TYPE_UINT32; + else + goto error; + } + } else if (s->len==type_utf_string_s.len && + !strncasecmp(s->s, type_utf_string_s.s, type_utf_string_s.len)) { + return TYPE_UTF8; + } else if (s->len == type_octet_string_s.len && + !strncasecmp(s->s, type_octet_string_s.s, type_octet_string_s.len)) { + return TYPE_BLOB; + } else if (s->len == type_inet_addr_s.len && + !strncasecmp(s->s, type_inet_addr_s.s, type_inet_addr_s.len)) { + return TYPE_INET_ADDR; + } else if (s->len == type_inet6_addr_s.len && + !strncasecmp(s->s, type_inet6_addr_s.s, type_inet6_addr_s.len)) { + return TYPE_INET6_ADDR; + } else { + goto error; + } + +error: + return TYPE_ERROR; +} + +/* + * get int value from int or hex value in string format + */ +static int fix_hex_int(str *s) +{ + + int retval; + + if (!s->len || !s->s) + goto error; + + if (s->len > 2) + if ((s->s[0] == '0') && ((s->s[1]|0x20) == 'x')) { + if (string2hex((unsigned char *)s->s+2, s->len-2, (char*)&retval)!=0) + goto error; + else + return retval; + } + + if (str2int(s, (unsigned int*)&retval)<0) + goto error; + + + return retval; + + +error: + LM_ERR("Invalid value for vendor_id: <%*s>!\n", s->len, s->s); + return -1; + +} + +static int set_hep_generic_fixup(void** param, int param_no) +{ + int type; + gparam_p gp; + + switch (param_no) { + case 1: + /* chunk id */ + if (fixup_sgp(param) < 0) { + LM_ERR("fixup for chunk type failed!\n"); + return -1; + } + + gp = *param; + if (gp->type == GPARAM_TYPE_STR) { + if ((type=fix_hex_int(&gp->v.sval)) < 0) { + LM_ERR("Invalid chunk value type <%.*s>!\n", + gp->v.sval.len, gp->v.sval.s); + return -1; + } + gp->v.ival = type; + gp->type = GPARAM_TYPE_INT; + } + + return 0; + /* data */ + case 2: + return fixup_sgp(param); + } + + return 0; +} + + + +static int set_hep_fixup(void** param, int param_no) +{ + int type; + gparam_p gp; + + switch (param_no) { + /* type */ + case 1: + if (fixup_sgp(param) < 0) { + LM_ERR("fixup for chunk type failed!\n"); + return -1; + } + + gp = *param; + if (gp->type == GPARAM_TYPE_STR) { + if ((type=fix_hep_value_type(&gp->v.sval)) == TYPE_ERROR) { + LM_ERR("Invalid chunk value type <%.*s>!\n", + gp->v.sval.len, gp->v.sval.s); + return -1; + } + gp->v.ival = type; + gp->type = GPARAM_TYPE_INT; + } + + return 0; + + /* chunk id */ + case 2: + /* vendor*/ + case 3: + if (fixup_sgp(param) < 0) { + LM_ERR("fixup for chunk type failed!\n"); + return -1; + } + + gp = *param; + if (gp->type == GPARAM_TYPE_STR) { + if ((type=fix_hex_int(&gp->v.sval)) < 0) { + LM_ERR("Invalid chunk value type <%.*s>!\n", + gp->v.sval.len, gp->v.sval.s); + return -1; + } + gp->v.ival = type; + gp->type = GPARAM_TYPE_INT; + } + + return 0; + /* data */ + case 4: + return fixup_sgp(param); + } + + return 0; +} + +static int get_hep_generic_fixup(void** param, int param_no) +{ + int type; + gparam_p gp; + + switch (param_no) { + case 1: + if (fixup_sgp(param) < 0) { + LM_ERR("fixup for chunk type failed!\n"); + return -1; + } + + gp = *param; + if (gp->type == GPARAM_TYPE_STR) { + if ((type=fix_hex_int(&gp->v.sval)) < 0) { + LM_ERR("Invalid chunk value type <%.*s>!\n", + gp->v.sval.len, gp->v.sval.s); + return -1; + } + gp->v.ival = type; + gp->type = GPARAM_TYPE_INT; + } + + return 0; + + /* vendor pvar */ + case 2: + /* data pvar */ + case 3: + return fixup_pvar(param); + default: + LM_ERR("Invalid param number <%d>\n", param_no); + return -1; + } + + return 0; +} + + + +static int get_hep_fixup(void** param, int param_no) +{ + int type; + gparam_p gp; + + switch (param_no) { + /* type */ + case 1: + if (fixup_sgp(param) < 0) { + LM_ERR("fixup for chunk type failed!\n"); + return -1; + } + + gp = *param; + if (gp->type == GPARAM_TYPE_STR) { + if ((type=fix_hep_value_type(&gp->v.sval)) == TYPE_ERROR) { + LM_ERR("Invalid chunk value type <%.*s>!\n", + gp->v.sval.len, gp->v.sval.s); + return -1; + } + gp->v.ival = type; + gp->type = GPARAM_TYPE_INT; + } + + return 0; + /* chunk id */ + case 2: + if (fixup_sgp(param) < 0) { + LM_ERR("fixup for chunk type failed!\n"); + return -1; + } + + gp = *param; + if (gp->type == GPARAM_TYPE_STR) { + if ((type=fix_hex_int(&gp->v.sval)) < 0) { + LM_ERR("Invalid chunk value type <%.*s>!\n", + gp->v.sval.len, gp->v.sval.s); + return -1; + } + gp->v.ival = type; + gp->type = GPARAM_TYPE_INT; + } + + return 0; + + /* vendor pvar */ + case 3: + /* data pvar */ + case 4: + return fixup_pvar(param); + default: + LM_ERR("Invalid param number <%d>\n", param_no); + return -1; + } + + return 0; +} + +static int del_hep_fixup(void** param, int param_no) +{ + int type; + gparam_p gp; + + if (param_no == 1) { + if (fixup_sgp(param) < 0) { + LM_ERR("fixup for chunk type failed!\n"); + return -1; + } + + gp = *param; + if (gp->type == GPARAM_TYPE_STR) { + if ((type=fix_hex_int(&gp->v.sval)) < 0) { + LM_ERR("Invalid chunk value type <%.*s>!\n", + gp->v.sval.len, gp->v.sval.s); + return -1; + } + gp->v.ival = type; + gp->type = GPARAM_TYPE_INT; + } + + return 0; + } + + LM_ERR("Invalid param number <%d>\n", param_no); + return -1; +} + + + + +static int w_set_hep_generic(struct sip_msg* msg, char* id, char* data) +{ + return w_set_hep(msg, NULL, id, NULL, data); +} + +static int +w_set_hep(struct sip_msg* msg, char* type, char* id, char* vid, char* data) +{ + int data_len; + int data_type=TYPE_UTF8; + int vendor_id=HEP_OPENSIPS_VENDOR_ID; + unsigned int chunk_id; + + unsigned int idata; + + struct in_addr addr4; + struct in6_addr addr6; + + str s; + str data_s; + + gparam_p gp; + + struct hep_desc *h; + struct hep_context *ctx; + + generic_chunk_t* ch; + generic_chunk_t* it; + + if (id==NULL || data==NULL) { + LM_ERR("Chunk id and chunk data can't be NULL!\n"); + return -1; + } + + if ((ctx=HEP_GET_CONTEXT(hep_api)) == NULL) { + LM_WARN("not a hep message!\n"); + return -1; + } + + h = &ctx->h; + if (h->version < 3) { + LM_ERR("set chunk only available in HEPv3(EEP)!\n"); + return -1; + } + + if (type != NULL) { + gp = (gparam_p)type; + if (gp->type == GPARAM_TYPE_INT) { + data_type = gp->v.ival; + } else { + if (fixup_get_svalue(msg, gp, &s) < 0) { + LM_ERR("Getting vendor id value from pvar failed!\n"); + return -1; + } + + if ((data_type=fix_hep_value_type(&s))==TYPE_ERROR) { + LM_ERR("Invalid data_type vlaue <%.*s>!\n", s.len, s.s); + return -1; + } + } + } + + + gp = (gparam_p)id; + if (gp->type == GPARAM_TYPE_INT) { + chunk_id = gp->v.ival; + } else { + if (fixup_get_svalue(msg, gp, &s) < 0) { + LM_ERR("Getting vendor id value from pvar failed!\n"); + return -1; + } + + if (parse_hep_name(&s, &chunk_id) < 0) { + LM_ERR("Invalid chunk id/name!\n"); + } + } + + if (vid) { + gp = (gparam_p)vid; + if (gp->type == GPARAM_TYPE_INT) { + vendor_id = gp->v.ival; + } else { + if (fixup_get_svalue(msg, gp, &s) < 0) { + LM_ERR("Getting vendor id value from pvar failed!\n"); + return -1; + } + + if ((vendor_id=fix_hex_int(&s)) < 0) { + LM_ERR("Invalid vendor id value <%.*s>!\n", s.len, s.s); + return -1; + } + } + } + + + + if (fixup_get_svalue(msg, (gparam_p)data, &data_s) < 0) { + LM_ERR("failed to get chunk data value!\n"); + return -1; + } + + if (CHUNK_IS_IN_HEPSTRUCT(chunk_id)) { + return set_generic_hep_chunk(&h->u.hepv3, chunk_id, &data_s); + } + + it = NULL; + for (it=h->u.hepv3.chunk_list; it; it = it->next) { + if (it->chunk.type_id == chunk_id) + break; + } + + if (it == NULL){ + ch = shm_malloc(sizeof(generic_chunk_t)); + if (ch == NULL) + goto shm_err; + + memset(ch, 0, sizeof(generic_chunk_t)); + } else { + ch = it; + } + + if (data_type == TYPE_UTF8 || data_type == TYPE_BLOB) { + data_len = data_s.len; + } else if (data_type == TYPE_INET_ADDR) { + data_len = sizeof(struct in_addr); + if (inet_pton(AF_INET, data_s.s, &addr4)==0) { + LM_ERR("not an IPv4 address <<%.*s>>!\n", + data_s.len, data_s.s); + return -1; + } + } else if (data_type == TYPE_INET6_ADDR) { + data_len = sizeof(struct in6_addr); + if (inet_pton(AF_INET6, data_s.s, &addr6)==0) { + LM_ERR("not an IPv6 address <<%.*s>>!\n", + data_s.len, data_s.s); + return -1; + } + } else { + data_len = data_type; + if (str2int(&data_s, &idata) < 0) { + LM_ERR("Invalid int value for chunk <%*.s>!\n", + data_s.len, data_s.s); + } + + /* keep values in big endian */ + if (data_type == TYPE_UINT32) + idata = htonl(idata); + else if (data_type == TYPE_UINT16) + idata = htons(idata); + } + + /* if new chunk data is same length as the old one no problem there; + * else we need to alloc new memory or delete some of the old one :( */ + if (it && (it->chunk.length - sizeof(hep_chunk_t)) != data_len) { + ch->data=shm_realloc(ch->data, data_len); + if (ch->data == NULL) + goto shm_err; + } else if (it == NULL) { + ch->data = shm_malloc(data_len); + if (ch->data == NULL) + goto shm_err; + } + + if (data_type == TYPE_UTF8 || data_type == TYPE_BLOB) { + memcpy(ch->data, data_s.s, data_len); + } else if (data_type == TYPE_INET_ADDR) { + memcpy(ch->data, &addr4, sizeof(struct in_addr)); + } else if (data_type == TYPE_INET6_ADDR) { + memcpy(ch->data, &addr6, sizeof(struct in6_addr)); + } else { + memcpy(ch->data, &idata, data_len); + } + + ch->chunk.vendor_id = vendor_id; + ch->chunk.type_id = chunk_id; + ch->chunk.length = sizeof(hep_chunk_t) + data_len; + + + /* if it's not a new chunk don't put it in the list */ + if (it == NULL) { + if (h->u.hepv3.chunk_list == NULL) { + h->u.hepv3.chunk_list = ch; + } else { + for (it=h->u.hepv3.chunk_list; it->next; it=it->next); + it->next=ch; + } + } + + return 1; + + shm_err: + LM_ERR("no more shm!\n"); + return -1; +} + +static int +w_get_hep_generic(struct sip_msg* msg, char* id, char* vid, char* data) +{ + return w_get_hep(msg, NULL, id, vid, data); } - -static int w_sip_capture(struct sip_msg *msg, - async_resume_module **resume_f, void **resume_param) +static int +w_get_hep(struct sip_msg* msg, char* type, char* id, char* vid, char* data) { - struct _sipcapture_object sco; - struct sip_uri from, to, pai, contact; - struct hdr_field *hook1 = NULL; - struct hdr_field *tmphdr[4]; - contact_body_t* cb=0; - char buf_ip[IP_ADDR_MAX_STR_SIZE+12]; - char *port_str = NULL, *tmp = NULL; - struct timeval tvb; - struct timezone tz; - char tmp_node[100]; - gettimeofday( &tvb, &tz ); + int data_type; - if(msg==NULL) { - LM_DBG("nothing to capture\n"); - return -1; - } - memset(&sco, 0, sizeof(struct _sipcapture_object)); + unsigned int net_data; + unsigned int chunk_id; + struct hep_desc *h; + struct hep_context *ctx; - if(capture_on_flag==NULL || *capture_on_flag==0) { - LM_DBG("capture off...\n"); - return -1; - } + str s; - if(sip_capture_prepare(msg)<0) return -1; + pv_spec_p data_pv, vendor_pv; + pv_value_t data_val, vendor_val; - if(heptime && heptime->tv_sec != 0) { - sco.tmstamp = (unsigned long long)heptime->tv_sec*1000000+heptime->tv_usec; /* micro ts */ - snprintf(tmp_node, 100, "%.*s:%i", capture_node.len, capture_node.s, heptime->captid); - sco.node.s = tmp_node; - sco.node.len = strlen(tmp_node); - } - else { - sco.tmstamp = (unsigned long long)tvb.tv_sec*1000000+tvb.tv_usec; /* micro ts */ - sco.node = capture_node; - } + gparam_p gp; - if(msg->first_line.type == SIP_REQUEST) { + generic_chunk_t* it; - if (parse_sip_msg_uri(msg)<0) return -1; + data_pv = (pv_spec_p)data; + vendor_pv = (pv_spec_p)vid; - sco.method = msg->first_line.u.request.method; - EMPTY_STR(sco.reply_reason); + if (id == NULL) { + LM_ERR("No chunk id given!\n"); + return -1; + } - sco.ruri = msg->first_line.u.request.uri; - sco.ruri_user = msg->parsed_uri.user; + if (vid == NULL && data == NULL) { + LM_ERR("No output vars provided!\n"); + return -1; } - else if(msg->first_line.type == SIP_REPLY) { - sco.method = msg->first_line.u.reply.status; - sco.reply_reason = msg->first_line.u.reply.reason; - EMPTY_STR(sco.ruri); - EMPTY_STR(sco.ruri_user); + if ((ctx=HEP_GET_CONTEXT(hep_api)) == NULL) { + LM_WARN("not a hep message!\n"); + return -1; } - else { - LM_ERR("unknown type [%i]\n", msg->first_line.type); - EMPTY_STR(sco.method); - EMPTY_STR(sco.reply_reason); - EMPTY_STR(sco.ruri); - EMPTY_STR(sco.ruri_user); + + h = &ctx->h; + if (h->version < 3) { + LM_ERR("get chunk only available in HEPv3(EEP)!\n"); + return -1; } - /* Parse FROM */ - if(msg->from) { + gp = (gparam_p)id; + if (gp->type == GPARAM_TYPE_INT) { + chunk_id = gp->v.ival; + } else { + if (fixup_get_svalue(msg, gp, &s) < 0) { + LM_ERR("Getting vendor id value from pvar failed!\n"); + return -1; + } - if (parse_from_header(msg)!=0){ - LM_ERR("bad or missing" " From: header\n"); - return -1; - } + if (parse_hep_name(&s, &chunk_id) < 0) { + LM_ERR("Invalid chunk id/name!\n"); + } + } - if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len, &from)<0){ - LM_ERR("bad from dropping"" packet\n"); - return -1; - } + if (CHUNK_IS_IN_HEPSTRUCT(chunk_id)) { + /* don't need type for these; we already know it */ + if (data) { + if (get_hep_chunk(&h->u.hepv3, chunk_id, &data_val) < 0) + goto set_pv_null; + } - sco.from_user = from.user; - sco.from_tag = get_from(msg)->tag_value; - } - else { - EMPTY_STR(sco.from_user); - EMPTY_STR(sco.from_tag); - } + if (vid) { + vendor_val.ri = 0; + vendor_val.flags = PV_TYPE_INT; + } - /* Parse TO */ - if(msg->to) { + goto set_pv_values; + } - if (parse_uri(get_to(msg)->uri.s, get_to(msg)->uri.len, &to)<0){ - LM_ERR("bad to dropping"" packet\n"); - return -1; - } + if (type == NULL) { + LM_ERR("no type given! Don't know what to return!\n"); + return -1; + } - sco.to_user = to.user; - if(get_to(msg)->tag_value.len) - sco.to_tag = get_to(msg)->tag_value; - else { EMPTY_STR(sco.to_tag); } - } - else { - EMPTY_STR(sco.to_user); - EMPTY_STR(sco.to_tag); - } + gp = (gparam_p)type; + if (gp->type == GPARAM_TYPE_INT) { + data_type = gp->v.ival; + } else { + if (fixup_get_svalue(msg, gp, &s) < 0) { + LM_ERR("Getting vendor id value from pvar failed!\n"); + return -1; + } - /* Call-id */ - if(msg->callid) sco.callid = msg->callid->body; - else { EMPTY_STR(sco.callid); } + if ((data_type=fix_hep_value_type(&s))==TYPE_ERROR) { + LM_ERR("Invalid data_type vlaue <%.*s>!\n", s.len, s.s); + return -1; + } + } - /* P-Asserted-Id */ - if(msg->pai && (parse_pai_header(msg) == 0)) { + for (it=h->u.hepv3.chunk_list; it; it=it->next) { + if (it->chunk.type_id == chunk_id) { + vendor_val.ri = it->chunk.vendor_id; + vendor_val.flags = PV_TYPE_INT; - if (parse_uri(get_pai(msg)->uri.s, get_pai(msg)->uri.len, &pai)<0){ - LM_DBG("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; - } - } - else if(msg->ppi && (parse_ppi_header(msg) == 0)) { + switch (data_type) { + /* all int types are in big endian */ + case TYPE_UINT8: + data_val.ri = ((char*)it->data)[0]; + data_val.flags = PV_TYPE_INT; - if (parse_uri(get_ppi(msg)->uri.s, get_ppi(msg)->uri.len, &pai)<0){ - LM_DBG("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; - } - } - else { EMPTY_STR(sco.pid_user); } + break; + case TYPE_UINT16: + net_data = ((unsigned short*)it->data)[0]; + data_val.ri = htons(net_data); + data_val.flags = PV_TYPE_INT; - /* Auth headers */ - if(msg->proxy_auth != NULL) hook1 = msg->proxy_auth; - else if(msg->authorization != NULL) hook1 = msg->authorization; + break; + case TYPE_UINT32: + net_data = ((unsigned int*)it->data)[0]; + data_val.ri = htonl(net_data); + data_val.flags = PV_TYPE_INT; - if(hook1) { - if(parse_credentials(hook1) == 0) sco.auth_user = ((auth_body_t*)(hook1->parsed))->digest.username.user; - else { EMPTY_STR(sco.auth_user); } - } - else { EMPTY_STR(sco.auth_user);} + break; + case TYPE_INET_ADDR: + hep_str.len = 0; + memset(hep_str.s, 0, HEPBUF_LEN); - if(msg->contact) { + if (inet_ntop(AF_INET, it->data, + hep_str.s, INET_ADDRSTRLEN) == NULL) { + LM_ERR("Not an IPv4 address!\n"); + return -1; + } - if (msg->contact->parsed == 0 && parse_contact(msg->contact) == -1) { - LM_ERR("while parsing header\n"); - return -1; - } + hep_str.len = strlen(hep_str.s); - cb = (contact_body_t*)msg->contact->parsed; + data_val.rs = hep_str; + data_val.flags = PV_VAL_STR; - if(cb && cb->contacts) { - if(parse_uri( cb->contacts->uri.s, cb->contacts->uri.len, &contact)<0){ - LM_ERR("bad contact dropping packet\n"); - return -1; - } - } - } + break; + case TYPE_INET6_ADDR: + hep_str.len = 0; + memset(hep_str.s, 0, HEPBUF_LEN); - /* get header x-cid: */ - /* callid_aleg X-CID */ - if((tmphdr[0] = get_header_by_static_name(msg,"X-CID")) != NULL) { - sco.callid_aleg = tmphdr[0]->body; - } - else { EMPTY_STR(sco.callid_aleg);} + if (inet_ntop(AF_INET6, it->data, + hep_str.s, INET6_ADDRSTRLEN) == NULL) { + LM_ERR("Not an IPv4 address!\n"); + return -1; + } - /* VIA 1 */ - sco.via_1 = msg->h_via1->body; + hep_str.len = strlen(hep_str.s); - /* Via branch */ - if(msg->via1->branch) sco.via_1_branch = msg->via1->branch->value; - else { EMPTY_STR(sco.via_1_branch); } + data_val.rs = hep_str; + data_val.flags = PV_VAL_STR; - /* CSEQ */ - if(msg->cseq) sco.cseq = msg->cseq->body; - else { EMPTY_STR(sco.cseq); } + break; + case TYPE_UTF8: + case TYPE_BLOB: + data_val.rs.s = (char*)it->data; + data_val.rs.len = it->chunk.length - sizeof(hep_chunk_t); + data_val.flags = PV_VAL_STR; - /* Reason */ - if((tmphdr[1] = get_header_by_static_name(msg,"Reason")) != NULL) { - sco.reason = tmphdr[1]->body; + break; + } + break; + } } - else { EMPTY_STR(sco.reason); } - /* Diversion */ - if(msg->diversion) sco.diversion = msg->diversion->body; - else { EMPTY_STR(sco.diversion);} + if (it == NULL) + goto set_pv_null; - /* Content-type */ - if(msg->content_type) sco.content_type = msg->content_type->body; - else { EMPTY_STR(sco.content_type);} +set_pv_values: - /* User-Agent */ - if(msg->user_agent) sco.user_agent = msg->user_agent->body; - else { EMPTY_STR(sco.user_agent);} + if (data) { + if (pv_set_value(msg, data_pv, 0, &data_val) < 0) { + LM_ERR("Failed setting data pvar value!\n"); + return -1; + } + } - /* Contact */ - if(msg->contact && cb) { - sco.contact_ip = contact.host; - str2int(&contact.port, (unsigned int*)&sco.contact_port); + if (vid) { + if (pv_set_value(msg, vendor_pv, 0, &vendor_val) < 0) { + LM_ERR("Failed setting data pvar value!\n"); + return -1; + } } - else { - EMPTY_STR(sco.contact_ip); - sco.contact_port = 0; + + return 1; + +set_pv_null: + if (data) { + if (pv_set_value(msg, data_pv, 0, NULL) < 0) { + LM_ERR("Failed setting data pvar value!\n"); + return -1; + } } - /* X-OIP */ - if((tmphdr[2] = get_header_by_static_name(msg,"X-OIP")) != NULL) { - sco.originator_ip = tmphdr[2]->body; - /* Originator port. Should be parsed from XOIP header as ":" param */ - tmp = strchr(tmphdr[2]->body.s, ':'); - if (tmp) { - *tmp = '\0'; - port_str = tmp + 1; - sco.originator_port = strtol(port_str, NULL, 10); + if (vid) { + if (pv_set_value(msg, vendor_pv, 0, NULL) < 0) { + LM_ERR("Failed setting data pvar value!\n"); + return -1; } - else sco.originator_port = 0; } - else { - EMPTY_STR(sco.originator_ip); - sco.originator_port = 0; + + return -1; +} + +static int w_del_hep(struct sip_msg* msg, char *id) +{ + unsigned int chunk_id; + + struct hep_desc *h; + struct hep_context *ctx; + + str s; + + gparam_p gp; + + generic_chunk_t* it; + generic_chunk_t* foo; + + if (id==NULL) { + LM_ERR("No chunk id provided!\n"); + return -1; } - /* X-RTP-Stat */ - if((tmphdr[3] = get_header_by_static_name(msg,"X-RTP-Stat")) != NULL) { - sco.rtp_stat = tmphdr[3]->body; + if ((ctx=HEP_GET_CONTEXT(hep_api)) == NULL) { + LM_WARN("not a hep message!\n"); + return -1; } - /* P-RTP-Stat */ - else if((tmphdr[3] = get_header_by_static_name(msg,"P-RTP-Stat")) != NULL) { - sco.rtp_stat = tmphdr[3]->body; + + h = &ctx->h; + if (h->version < 3) { + LM_ERR("del chunk only available in HEPv3(EEP)!\n"); + return -1; } - else { EMPTY_STR(sco.rtp_stat); } + gp = (gparam_p)id; + if (gp->type == GPARAM_TYPE_INT) { + chunk_id = gp->v.ival; + } else { + if (fixup_get_svalue(msg, gp, &s) < 0) { + LM_ERR("Getting vendor id value from pvar failed!\n"); + return -1; + } - /* PROTO TYPE */ - sco.proto = msg->rcv.proto; + if (parse_hep_name(&s, &chunk_id) < 0) { + LM_ERR("Invalid chunk id/name!\n"); + } + } - /* FAMILY TYPE */ - sco.family = msg->rcv.src_ip.af; - /* MESSAGE TYPE */ - sco.type = msg->first_line.type; + if (CHUNK_IS_IN_HEPSTRUCT(chunk_id)) + return del_hep_chunk(&h->u.hepv3, chunk_id); - /* MSG */ - sco.msg.s = msg->buf; - sco.msg.len = msg->len; - //EMPTY_STR(sco.msg); - /* IP source and destination */ + it=h->u.hepv3.chunk_list; - strcpy(buf_ip, ip_addr2a(&msg->rcv.src_ip)); - sco.source_ip.s = buf_ip; - sco.source_ip.len = strlen(buf_ip); - sco.source_port = msg->rcv.src_port; + if (it->chunk.type_id == chunk_id) { + h->u.hepv3.chunk_list = it->next; + foo = it; + goto free_chunk; + } - /*source ip*/ - sco.destination_ip.s = ip_addr2a(&msg->rcv.dst_ip); - sco.destination_ip.len = strlen(sco.destination_ip.s); - sco.destination_port = msg->rcv.dst_port; + while (it->next) { + if (it->next->chunk.type_id == chunk_id) { + foo = it->next; + it->next = it->next->next; + goto free_chunk; + } - LM_DBG("src_ip: [%.*s]\n", sco.source_ip.len, sco.source_ip.s); - LM_DBG("dst_ip: [%.*s]\n", sco.destination_ip.len, sco.destination_ip.s); + it = it->next; + } - LM_DBG("dst_port: [%d]\n", sco.destination_port); - LM_DBG("src_port: [%d]\n", sco.source_port); + return -1; -#ifdef STATISTICS - if(msg->first_line.type==SIP_REPLY) { - sco.stat = sipcapture_rpl; - } else { - sco.stat = sipcapture_req; - } -#endif - LM_DBG("DONE\n"); - return sip_capture_store(&sco, resume_f, resume_param); +free_chunk: + shm_free(foo->data); + shm_free(foo); + + return 1; } #define capture_is_off(_msg) \ @@ -1813,7 +3786,7 @@ int raw_capture_rcv_loop(int rsock, int port1, int port2, int ipip) { if((!port1 && !port2) || (src_port >= port1 && src_port <= port2) || (dst_port >= port1 && dst_port <= port2) || (!port2 && (src_port == port1 || dst_port == port1))) - receive_msg(buf+offset, len, &ri); + receive_msg(buf+offset, len, &ri, NULL); } return 0; diff --git a/modules/sipcapture/sql/sipcapture.sql b/modules/sipcapture/sql/sipcapture.sql index 7d2b6ede0e2..6dc9f1b6659 100644 --- a/modules/sipcapture/sql/sipcapture.sql +++ b/modules/sipcapture/sql/sipcapture.sql @@ -39,6 +39,7 @@ CREATE TABLE `sip_capture` ( `originator_port` int(10) NOT NULL, `proto` int(5) NOT NULL, `family` int(1) DEFAULT NULL, + `proto_type` int(8) DEFAULT NULL, `rtp_stat` varchar(256) NOT NULL, `type` int(2) NOT NULL, `node` varchar(125) NOT NULL, From 419c9dc481fed12877a18aaebaa54141cae8a792 Mon Sep 17 00:00:00 2001 From: ionutrazvanionita Date: Tue, 23 Feb 2016 18:00:55 +0200 Subject: [PATCH 4/5] [sipcapture]updated docs --- modules/sipcapture/README | 225 +++++++++++- modules/sipcapture/doc/sipcapture_admin.xml | 371 +++++++++++++++++++- 2 files changed, 584 insertions(+), 12 deletions(-) diff --git a/modules/sipcapture/README b/modules/sipcapture/README index 7d6b2ca150b..910f8279456 100644 --- a/modules/sipcapture/README +++ b/modules/sipcapture/README @@ -45,17 +45,28 @@ Alexandr Dubovikov 1.4. Exported Functions 1.4.1. sip_capture() + 1.4.2. hep_set([data_type,] chunk_id, [vendor_id,] + chunk_data) + + 1.4.3. hep_get([data_type,] chunk_id, vendor_id_pv, + chunk_data_pv) + + 1.4.4. hep_del(chunk_id) 1.5. Exported Async Functions 1.5.1. sip_capture() - 1.6. MI Commands + 1.6. Exported PseudoVariables + + 1.6.1. hep_net + + 1.7. MI Commands - 1.6.1. sip_capture + 1.7.1. sip_capture - 1.7. Database setup - 1.8. Limitation + 1.8. Database setup + 1.9. Limitation List of Examples @@ -74,7 +85,11 @@ Alexandr Dubovikov 1.13. Set capture_node parameter 1.14. Set hep_store_no_script parameter 1.15. sip_capture usage - 1.16. sip_capture usage + 1.16. hep_set usage + 1.17. hep_set usage + 1.18. hep_set usage + 1.19. sip_capture usage + 1.20. hep_net usage Chapter 1. Admin Guide @@ -86,7 +101,12 @@ Chapter 1. Admin Guide OpenSIPs can capture SIP messages in three mode * IPIP encapsulation. (ETHHDR+IPHDR+IPHDR+UDPHDR). * Monitoring/mirroring port. - * Homer encapsulation protocl mode (HEP v1). + * Homer encapsulation protocl mode (HEP v1/2/3). With version + 2.2 comes the new HEPv3 support using the proto _hep + module. Also header manipulation support for HEPv3 has been + added. See Section 1.4.2, “ hep_set([data_type,] chunk_id, + [vendor_id,] chunk_data) ” for more details. If you want + more information about hep protocol check this link. The capturing can be turned on/off using fifo commad. @@ -100,6 +120,7 @@ Chapter 1. Admin Guide The following modules must be loaded before this module: * database module - mysql, postrgress, dbtext, unixodbc... + * proto_hep module - if hep capturing used 1.2.2. External Libraries or Applications @@ -310,6 +331,152 @@ if (is_method("REGISTER")) sip_capture(); ... +1.4.2. hep_set([data_type,] chunk_id, [vendor_id,] chunk_data) + + Set a hep chunk. If not exists, it shall be added. + + This function can be used from + REQUEST_ROUTE,FAILURE_ROUTE,ONREPLY_ROUTE,BRANCH_ROUTE,LOCAL_RO + UTE. + + Meaning of the parameters is as follows: + * data_type - data type of the data in the chunk. It can have + the following values: + + uint8 - byte unsigned integer + + uint16 - word unsigned integer + + uint32 - 4 byte unsigned integer + + inet4-addr - IPv4 address in human readable format + + inet6-addr - IPv6 address in human readable format + + utf8-string - UTF8 encoded character sequence + + octet-string - byte array + * chunk_id(string value with hex/int or string identifiere of + chunk) - id of the chunk to be added; most of the generic + chunks are in the internal hep structure. For these you can + skip the data_type and vendor_id since they are already + known. Generic chunks that don't have built in support are + the followinig: 0x000d(keep alive timer), + 0x000e(authenticate key), 0x0011(internal correltion id), + 0x0012(vlan ID). You can set these chunks, but only with + vendor id 0x0000, other values shall result in an error. + Timestamp(0x0009) and timestamp_us(0x000A) chunks can't be + set. For chunks that have built-in support you can also use + strings instead of chunk ids as follows: + + 0x0001 - proto_family(CAN'T BE SET; it shall be + automatically updated if you change the type of the + source/destination address from IPv4 to IPv6 or else) + + 0x0002 - proto_id; since it's quite hard to know the + int values for the protocol one can change this value + using the following string values: + o UDP + o TCP + o TLS + o SCTP + o WS + o WSS + o BIN + o HEP + + 0x0003 - src_ip + + 0x0004 - dst_ip + + 0x0005 - src_ip + + 0x0006 - dst_ip + + 0x0007 - src_port + + 0x0008 - dst_port + + 0x0009 - timestamp(CAN'T BE SET) + + 0x000A - timestamp_us(CAN'T BE SET) + + 0x000B - proto_type; for this variable there are + predefined strings which can be set: + o SIP + o XMPP + o SDP + o RTP + o RTCP + o MGCP + o MEGACO + o M2UA + o M3UA + o IAX + o H322 + o H321 + + 0x000C - captagent_id + + 0x000f - payload + + 0x0010 - payload + * vendor id(string value with hex or int) - there are some + vendor ids already defined; check hep proto docs for more + details. + * data(string) - data that the chunk shall contain; + internally it shall be converted to the requested data type + + Example 1.16. hep_set usage +... +/* modify/add a generic chunk */ +hep_set("proto_type", "H321"); + +/* add a custom chunk - int */ +hep_set("uint32", "31"/*chk id*/, "3"/*opensips vendor*/, "132") + +/* add a custom chunk - IPv4 address */ +hep_set("inet4-addr", "32"/*chk id*/, "3"/*opensips vendor*/, "192.168.5 +.14") +... + +1.4.3. hep_get([data_type,] chunk_id, vendor_id_pv, chunk_data_pv) + + Set a hep chunk. If not exists, it shall be added. + + This function can be used from + REQUEST_ROUTE,FAILURE_ROUTE,ONREPLY_ROUTE,BRANCH_ROUTE,LOCAL_RO + UTE. + + Meaning of the parameters is as follows: + * data_type(string) - same meaning as in Section 1.4.2, “ + hep_set([data_type,] chunk_id, [vendor_id,] chunk_data) ”; + can miss if it's a generic chunk + * chunk_id - same meaning as in Section 1.4.2, “ + hep_set([data_type,] chunk_id, [vendor_id,] chunk_data) ” + * vendor_id_pv(writable pvar) - will hold the vendor id(int + value) of the chunk + * chunk_data_pv(writable pvar) - will hold the data inside + the chunk; some of the generic chunk data come in specific + format, as following: + + 0x0001 - proto_family(string) - AF_INET/AF_INET6 + + 0x0002 proto_id(string) - see Section 1.4.2, “ + hep_set([data_type,] chunk_id, [vendor_id,] + chunk_data) ” for possible values + + 0x0003/0x0004/0x0005/0x0006 src/dst_ip(string) - ip + addresses in human readable format + + 0x0009 timestamp(string) - time and date in human + readable format + + 0x000B proto_type(string) - see Section 1.4.2, “ + hep_set([data_type,] chunk_id, [vendor_id,] + chunk_data) ” for possible values + + Example 1.17. hep_set usage +... +/* get a generic chunk */ +hep_get("proto_type", "$var(vid)", "$var(data)"); + +/* get custom chunk - you must know what kind of data is there */ +hep_set("uint32", "31"/*chk id*/, "$var(vid)", "$var(data)") +... + +1.4.4. hep_del(chunk_id) + + Removes a hep chunk. + + This function can be used from + REQUEST_ROUTE,FAILURE_ROUTE,ONREPLY_ROUTE,BRANCH_ROUTE,LOCAL_RO + UTE. + + Meaning of the parameters is as follows: + * chunk_id - same meaning as the chunk_id in Section 1.4.2, “ + hep_set([data_type,] chunk_id, [vendor_id,] chunk_data) ”. + + Example 1.18. hep_set usage +... +/* get a generic chunk */ +hep_del("25"); /* removes chunk with chunk id 25 */ +... + 1.5. Exported Async Functions 1.5.1. sip_capture() @@ -319,7 +486,7 @@ if (is_method("REGISTER")) The query might not be executed exactly at this moment, it depends on the max_async_queries parameter. - Example 1.16. sip_capture usage + Example 1.19. sip_capture usage ... { async(sip_capture(), capture_resume); @@ -331,9 +498,45 @@ route[capture_resume] { } ... -1.6. MI Commands +1.6. Exported PseudoVariables + +1.6.1. hep_net + + Holds layer 3 and 4 information(IP addresses and ports) about + the node from where the hep message was received. The variable + is read-only and can be used only if it's referenced by it's + name. + + Possible values for it's name are the following: + * proto_family - can be AF_INET/AF_INET6 + * proto_id - it's PROTO_HEP since you receive the message as + hep. + * src_ip - IPv4/IPv6 address, depending on the proto_family, + of the sending node. + * dst_ip - IPv4/IPv6 address, depending on the proto_family, + of the receiving node(OpenSIPS hep interface ip on which + the message was received). + * src_port - Sending node port. + * dst_port - Receiving port(OpenSIPS hep interace port on + which the message was received). + + Example 1.20. hep_net usage +... + /* received this hep packet on interface 192.168.2.5*/ + if ($hep_net(dst_ip) == "192.168.2.5") { + /* received this on 192.168.2.5:6060 interface */ + if ($hep_net(dst_port) == 6060) { + ... + /* received this on 192.168.2.5:6061 interface */ + } else if ($hep_net(dst_port) == 6061) { + ... + } + } +... + +1.7. MI Commands -1.6.1. sip_capture +1.7.1. sip_capture Name: sip_capture @@ -351,7 +554,7 @@ route[capture_resume] { capture_mode _empty_line_ -1.7. Database setup +1.8. Database setup Before running OpenSIPS with sipcapture, you have to setup the database tables where the module will store the data. For that, @@ -363,7 +566,7 @@ route[capture_resume] { documentation on the project webpage, http://www.opensips.org/html/docs/db/db-schema-devel.html. -1.8. Limitation +1.9. Limitation 1. Only one capturing mode on RAW socket is supported: IPIP or monitoring/mirroring port. Don't activate both at the same diff --git a/modules/sipcapture/doc/sipcapture_admin.xml b/modules/sipcapture/doc/sipcapture_admin.xml index f98c3d146c1..fae71d2e1a1 100644 --- a/modules/sipcapture/doc/sipcapture_admin.xml +++ b/modules/sipcapture/doc/sipcapture_admin.xml @@ -24,7 +24,13 @@ - Homer encapsulation protocl mode (HEP v1). + Homer encapsulation protocl mode (HEP v1/2/3). With version 2.2 + comes the new HEPv3 support using the proto _hep module. Also + header manipulation support for HEPv3 has been added. See + for more details. If you want more + information about hep protocol check this + + link. @@ -53,6 +59,12 @@ dbtext, unixodbc... + + + proto_hep module - if hep capturing used + + + @@ -397,6 +409,299 @@ if (is_method("REGISTER")) +
+ + <function moreinfo="none">hep_set([data_type,] chunk_id, [vendor_id,] chunk_data)</function> + + + Set a hep chunk. If not exists, it shall be added. + + + This function can be used from REQUEST_ROUTE,FAILURE_ROUTE,ONREPLY_ROUTE,BRANCH_ROUTE,LOCAL_ROUTE. + + Meaning of the parameters is as follows: + + + + data_type - data type of the data in the chunk. It can have + the following values: + + + + uint8 - byte unsigned integer + + + uint16 - word unsigned integer + + + uint32 - 4 byte unsigned integer + + + inet4-addr - IPv4 address in human readable format + + + inet6-addr - IPv6 address in human readable format + + + utf8-string - UTF8 encoded character sequence + + + octet-string - byte array + + + + + + chunk_id(string value with hex/int or string identifiere of chunk) + - id of the chunk to be added; most of the generic + chunks are in the internal hep structure. For these you can skip the data_type + and vendor_id since they are already known. Generic chunks that don't have built + in support are the followinig: 0x000d(keep alive timer), 0x000e(authenticate key), + 0x0011(internal correltion id), 0x0012(vlan ID). You can set these chunks, but + only with vendor id 0x0000, other values shall result in an error. Timestamp(0x0009) + and timestamp_us(0x000A) chunks can't be set. For chunks + that have built-in support you can also use strings instead of chunk ids as + follows: + + + 0x0001 - proto_family(CAN'T BE SET; it shall be automatically updated + if you change the type of the source/destination address from IPv4 to IPv6 + or else) + + + + 0x0002 - proto_id; since it's quite hard to know the int values for the protocol + one can change this value using the following string values: + + + UDP + + + TCP + + + TLS + + + SCTP + + + WS + + + WSS + + + BIN + + + HEP + + + + + 0x0003 - src_ip + + + 0x0004 - dst_ip + + + 0x0005 - src_ip + + + 0x0006 - dst_ip + + + 0x0007 - src_port + + + 0x0008 - dst_port + + + 0x0009 - timestamp(CAN'T BE SET) + + + 0x000A - timestamp_us(CAN'T BE SET) + + + 0x000B - proto_type; for this variable there are predefined + strings which can be set: + + + SIP + + + XMPP + + + SDP + + + RTP + + + RTCP + + + MGCP + + + MEGACO + + + M2UA + + + M3UA + + + IAX + + + H322 + + + H321 + + + + + 0x000C - captagent_id + + + 0x000f - payload + + + 0x0010 - payload + + + + + + vendor id(string value with hex or int) - there are + some vendor ids already defined; check + + hep proto docs + for more details. + + + + data(string) - data that the chunk shall contain; + internally it shall be converted to the requested data type + + + + <function>hep_set</function> usage + +... +/* modify/add a generic chunk */ +hep_set("proto_type", "H321"); + +/* add a custom chunk - int */ +hep_set("uint32", "31"/*chk id*/, "3"/*opensips vendor*/, "132") + +/* add a custom chunk - IPv4 address */ +hep_set("inet4-addr", "32"/*chk id*/, "3"/*opensips vendor*/, "192.168.5.14") +... + + + +
+ +
+ + <function moreinfo="none">hep_get([data_type,] chunk_id, vendor_id_pv, chunk_data_pv)</function> + + + Set a hep chunk. If not exists, it shall be added. + + + This function can be used from REQUEST_ROUTE,FAILURE_ROUTE,ONREPLY_ROUTE,BRANCH_ROUTE,LOCAL_ROUTE. + + Meaning of the parameters is as follows: + + + data_type(string) - same meaning as in + ; can miss if it's a generic chunk + + + chunk_id - same meaning as in + + + + vendor_id_pv(writable pvar) - will hold the vendor id(int value) + of the chunk + + + chunk_data_pv(writable pvar) - will hold the data inside the + chunk; some of the generic chunk data come in specific format, as following: + + + 0x0001 - proto_family(string) - AF_INET/AF_INET6 + + + 0x0002 proto_id(string) - see for possible values + + + 0x0003/0x0004/0x0005/0x0006 src/dst_ip(string) - ip addresses in human readable format + + + 0x0009 timestamp(string) - time and date in human readable format + + + 0x000B proto_type(string) - see for possible values + + + + + + +<function>hep_set</function> usage + +... +/* get a generic chunk */ +hep_get("proto_type", "$var(vid)", "$var(data)"); + +/* get custom chunk - you must know what kind of data is there */ +hep_set("uint32", "31"/*chk id*/, "$var(vid)", "$var(data)") +... + + + +
+ +
+ + <function moreinfo="none">hep_del(chunk_id)</function> + + + Removes a hep chunk. + + + This function can be used from REQUEST_ROUTE,FAILURE_ROUTE,ONREPLY_ROUTE,BRANCH_ROUTE,LOCAL_ROUTE. + + Meaning of the parameters is as follows: + + + chunk_id - same meaning as the chunk_id in + . + + + + +<function>hep_set</function> usage + +... +/* get a generic chunk */ +hep_del("25"); /* removes chunk with chunk id 25 */ +... + + + +
+ + +
@@ -431,6 +736,70 @@ route[capture_resume] {
+ +
+ Exported PseudoVariables + +
+ + <function moreinfo="none">hep_net</function> + + Holds layer 3 and 4 information(IP addresses and ports) about + the node from where the hep message was received. The variable is + read-only and can be used only if it's referenced by it's name. + Possible values for it's name are the following: + + + proto_family - can be AF_INET/AF_INET6 + + + proto_id - it's PROTO_HEP since you receive + the message as hep. + + + + src_ip - IPv4/IPv6 address, depending on the + proto_family, of the sending node. + + + dst_ip - IPv4/IPv6 address, depending on the + proto_family, of the receiving node(&osips; hep interface ip on which + the message was received). + + + src_port - Sending node port. + + + dst_port - Receiving port(&osips; hep interace + port on which the message was received). + + + + <function>hep_net</function> usage + +... + /* received this hep packet on interface 192.168.2.5*/ + if ($hep_net(dst_ip) == "192.168.2.5") { + /* received this on 192.168.2.5:6060 interface */ + if ($hep_net(dst_port) == 6060) { + ... + /* received this on 192.168.2.5:6061 interface */ + } else if ($hep_net(dst_port) == 6061) { + ... + } + } +... + + +
+ + + + + +
+ +
MI Commands
From 3ae18116b51d3cf3648d9006957cfe85befdd255 Mon Sep 17 00:00:00 2001 From: ionutrazvanionita Date: Thu, 3 Mar 2016 15:52:57 +0200 Subject: [PATCH 5/5] [proto_hep]set predefined context memory to 0 before using it --- modules/proto_hep/proto_hep.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/proto_hep/proto_hep.c b/modules/proto_hep/proto_hep.c index 947d5b60e90..5becb6e2fc3 100644 --- a/modules/proto_hep/proto_hep.c +++ b/modules/proto_hep/proto_hep.c @@ -935,6 +935,8 @@ static inline int hep_handle_req(struct tcp_req *req, goto error_free_hep; } + memset(ctx, 0, context_size(CONTEXT_GLOBAL)); + context_put_ptr(CONTEXT_GLOBAL, ctx, hep_ctx_idx, hep_ctx); /* run hep callbacks */ @@ -944,7 +946,7 @@ static inline int hep_handle_req(struct tcp_req *req, goto error_free_hep; } - msg_len = h.u.hepv3.payload_chunk.chunk.length- + msg_len = hep_ctx->h.u.hepv3.payload_chunk.chunk.length- sizeof(hep_chunk_payload_t); /* remove the hep header; leave only the payload */ msg_buf = hep_ctx->h.u.hepv3.payload_chunk.data; @@ -1243,6 +1245,8 @@ static int hep_udp_read_req(struct socket_info *si, int* bytes_read) goto error_free_hep; } + memset(ctx, 0, context_size(CONTEXT_GLOBAL)); + context_put_ptr(CONTEXT_GLOBAL, ctx, hep_ctx_idx, hep_ctx); update_recv_info(&ri, &hep_ctx->h);