Browse Source

added support for network io intercept

Muhammad Shahzad Shafi 11 years ago
parent
commit
0640f7cd97

+ 264 - 17
modules/corex/README

@@ -10,7 +10,13 @@ Daniel-Constantin Mierla
 
 
    <[email protected]>
    <[email protected]>
 
 
-   Copyright © 2012 asipto.com
+Edited by
+
+Muhammad Shahzad Shafi
+
+   <[email protected]>
+
+   Copyright © 2012 asipto.com
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -26,6 +32,9 @@ Daniel-Constantin Mierla
         3. Parameters
         3. Parameters
 
 
               3.1. alias_subdomains (string)
               3.1. alias_subdomains (string)
+              3.2. network_io_intercept (int)
+              3.3. msg_min_len (int)
+              3.4. msg_avp (string)
 
 
         4. Functions
         4. Functions
 
 
@@ -33,6 +42,7 @@ Daniel-Constantin Mierla
               4.2. send([ host [ :port ] ])
               4.2. send([ host [ :port ] ])
               4.3. send_tcp([ host [ :port ] ])
               4.3. send_tcp([ host [ :port ] ])
               4.4. send_data(uri, data)
               4.4. send_data(uri, data)
+              4.5. is_incoming()
 
 
         5. RPC Commands
         5. RPC Commands
 
 
@@ -41,12 +51,24 @@ Daniel-Constantin Mierla
               5.3. corex.shm_status
               5.3. corex.shm_status
               5.4. corex.shm_summary
               5.4. corex.shm_summary
 
 
+        6. Event Routes
+
+              6.1. event_route[network:msg]
+
+        7. Examples of Usage
+
    List of Examples
    List of Examples
 
 
    1.1. Set alias_subdomains parameter
    1.1. Set alias_subdomains parameter
-   1.2. append_branch usage
-   1.3. send usage
-   1.4. send_data usage
+   1.2. Set network_io_intercept parameter
+   1.3. Set msg_min_len parameter
+   1.4. Set msg_avp parameter
+   1.5. append_branch usage
+   1.6. send usage
+   1.7. send_data usage
+   1.8. is_incoming usage
+   1.9. event_route[network:msg] use cases
+   1.10. Sample PERL code for do_compress and do_uncompress
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -61,6 +83,9 @@ Chapter 1. Admin Guide
    3. Parameters
    3. Parameters
 
 
         3.1. alias_subdomains (string)
         3.1. alias_subdomains (string)
+        3.2. network_io_intercept (int)
+        3.3. msg_min_len (int)
+        3.4. msg_avp (string)
 
 
    4. Functions
    4. Functions
 
 
@@ -68,6 +93,7 @@ Chapter 1. Admin Guide
         4.2. send([ host [ :port ] ])
         4.2. send([ host [ :port ] ])
         4.3. send_tcp([ host [ :port ] ])
         4.3. send_tcp([ host [ :port ] ])
         4.4. send_data(uri, data)
         4.4. send_data(uri, data)
+        4.5. is_incoming()
 
 
    5. RPC Commands
    5. RPC Commands
 
 
@@ -76,6 +102,12 @@ Chapter 1. Admin Guide
         5.3. corex.shm_status
         5.3. corex.shm_status
         5.4. corex.shm_summary
         5.4. corex.shm_summary
 
 
+   6. Event Routes
+
+        6.1. event_route[network:msg]
+
+   7. Examples of Usage
+
 1. Overview
 1. Overview
 
 
    This module provides reimplementation of a few very old functions that
    This module provides reimplementation of a few very old functions that
@@ -89,6 +121,15 @@ Chapter 1. Admin Guide
    Contributions to this module must be done under the BSD license, to
    Contributions to this module must be done under the BSD license, to
    follow the requirements of the core contributions.
    follow the requirements of the core contributions.
 
 
+   This module now also provides access to network input / output data
+   through event_route[network:msg]. The raw data received from a remote
+   host or about to be sent to a remote host is available in variable $mb.
+   The script writer may manipulate this data and save the final result in
+   an AVP defined by msg_avp module parameter. The content of this AVP
+   will then be processed by SIP worker as normal, i.e. a received message
+   will be parsed and sent to appropriate route block while a sent message
+   is forwarded to remote host.
+
 2. Dependencies
 2. Dependencies
 
 
    2.1. Kamailio Modules
    2.1. Kamailio Modules
@@ -108,15 +149,18 @@ Chapter 1. Admin Guide
 3. Parameters
 3. Parameters
 
 
    3.1. alias_subdomains (string)
    3.1. alias_subdomains (string)
+   3.2. network_io_intercept (int)
+   3.3. msg_min_len (int)
+   3.4. msg_avp (string)
 
 
 3.1. alias_subdomains (string)
 3.1. alias_subdomains (string)
 
 
-   Register a domain and all its sub-domains to match the "myself"
+   Register a domain and all its sub-domains to match the “myself�
    condition. It can be set many times. Its full format is:
    condition. It can be set many times. Its full format is:
    'proto:domain:port', allowing to set restrictions on protocol and port
    'proto:domain:port', allowing to set restrictions on protocol and port
    as well. Protocol and port are optional.
    as well. Protocol and port are optional.
 
 
-   Default value is "NULL".
+   Default value is “NULL�.
 
 
    Example 1.1. Set alias_subdomains parameter
    Example 1.1. Set alias_subdomains parameter
 ...
 ...
@@ -124,14 +168,56 @@ modparam("corex", "alias_subdomains", "kamailio.org")
 modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
 modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
 ...
 ...
 
 
+3.2. network_io_intercept (int)
+
+   If set to non-zero then raw data received from a remote host or about
+   to be sent to a remote host is made available in
+   event_route[network:msg]. The script writer may modify this and save to
+   msg_avp, which will then be processed by SIP worker as normal.
+
+   Default value is 0, i.e. do not allow access to network io data.
+
+   Example 1.2. Set network_io_intercept parameter
+...
+modparam("corex", "network_io_intercept", 1)
+...
+
+3.3. msg_min_len (int)
+
+   Minimum content length of the packet to execute the
+   event_route[network:msg]. This only works if network_io_intercept
+   parameter is set to non-zero.
+
+   Default value is 0.
+
+   Example 1.3. Set msg_min_len parameter
+...
+modparam("corex", "msg_min_len", 32)
+...
+
+3.4. msg_avp (string)
+
+   AVP name to store modified content to be set in the packet. If not set
+   in event_route[network:msg], then all changes are lost and original
+   contents are used. This only works if network_io_intercept parameter is
+   to set non-zero.
+
+   Default value is empty.
+
+   Example 1.4. Set msg_avp parameter
+...
+modparam("corex", "msg_avp", "$avp(msg)")
+...
+
 4. Functions
 4. Functions
 
 
    4.1. append_branch([ uri, [ q ] ])
    4.1. append_branch([ uri, [ q ] ])
    4.2. send([ host [ :port ] ])
    4.2. send([ host [ :port ] ])
    4.3. send_tcp([ host [ :port ] ])
    4.3. send_tcp([ host [ :port ] ])
    4.4. send_data(uri, data)
    4.4. send_data(uri, data)
+   4.5. is_incoming()
 
 
-4.1. append_branch([ uri, [ q ] ])
+4.1.  append_branch([ uri, [ q ] ])
 
 
    Append a new branch to the destination set, useful to build the set of
    Append a new branch to the destination set, useful to build the set of
    destination addresses for parallel forking or redirect replies.
    destination addresses for parallel forking or redirect replies.
@@ -147,13 +233,13 @@ modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
 
 
    This function can be used from REQUEST_ROUTE or FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE or FAILURE_ROUTE.
 
 
-   Example 1.2. append_branch usage
+   Example 1.5. append_branch usage
 ...
 ...
     append_branch();
     append_branch();
     append_branch("$avp(uri)", "0.5");
     append_branch("$avp(uri)", "0.5");
 ...
 ...
 
 
-4.2. send([ host [ :port ] ])
+4.2.  send([ host [ :port ] ])
 
 
    Send the original SIP message to a specific destination in stateless
    Send the original SIP message to a specific destination in stateless
    mode. No changes are applied to received message, no Via header is
    mode. No changes are applied to received message, no Via header is
@@ -167,7 +253,7 @@ modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
 
 
    This function can be used from REQUEST_ROUTE or FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE or FAILURE_ROUTE.
 
 
-   Example 1.3. send usage
+   Example 1.6. send usage
 ...
 ...
         send();
         send();
         send("10.20.15.10");
         send("10.20.15.10");
@@ -175,12 +261,12 @@ modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
         send("$var(res)");
         send("$var(res)");
 ...
 ...
 
 
-4.3. send_tcp([ host [ :port ] ])
+4.3.  send_tcp([ host [ :port ] ])
 
 
    This function is identical to send() described above, except that it
    This function is identical to send() described above, except that it
    sends the SIP message using the TCP protocol instead of UDP.
    sends the SIP message using the TCP protocol instead of UDP.
 
 
-4.4. send_data(uri, data)
+4.4.  send_data(uri, data)
 
 
    Send the data to address specified by uri. Both parameters can contain
    Send the data to address specified by uri. Both parameters can contain
    pseudo-variables. The uri parameter has to be a valid SIP URI. The data
    pseudo-variables. The uri parameter has to be a valid SIP URI. The data
@@ -188,11 +274,33 @@ modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.4. send_data usage
+   Example 1.7. send_data usage
 ...
 ...
         send("sip:example.com:5070;transport=sctp", "Message at $Ts");
         send("sip:example.com:5070;transport=sctp", "Message at $Ts");
 ...
 ...
 
 
+4.5.  is_incoming()
+
+   Returns true if contents of message buffer $mb are the data received
+   from remote host, otherwise false indicating that the contents of $mb
+   are data that is about to be sent out to remote host. This only works
+   if network_io_intercept parameter is set to non-zero.
+
+   This function can be used from event_route[network:msg].
+
+   Example 1.8. is_incoming usage
+...
+event_route[network:msg] {
+    if (is_incoming()) {
+        xlog("L_INFO", "Received message '$mb' \n");
+        $avp(msg) = $mb;
+    } else {
+        xlog("L_INFO", "Sending message '$mb' \n");
+        $avp(msg) = $mb;
+    };
+}
+...
+
 5. RPC Commands
 5. RPC Commands
 
 
    5.1. corex.list_sockets
    5.1. corex.list_sockets
@@ -200,30 +308,169 @@ modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
    5.3. corex.shm_status
    5.3. corex.shm_status
    5.4. corex.shm_summary
    5.4. corex.shm_summary
 
 
-5.1. corex.list_sockets
+5.1.  corex.list_sockets
 
 
    Print the list of sockets the application is listening on.
    Print the list of sockets the application is listening on.
 
 
    Example:
    Example:
                 kamcmd corex.list_sockets
                 kamcmd corex.list_sockets
 
 
-5.2. corex.list_aliases
+5.2.  corex.list_aliases
 
 
    Print the list of hostname aliases used to match the myself condition.
    Print the list of hostname aliases used to match the myself condition.
 
 
    Example:
    Example:
                 kamcmd corex.list_aliases
                 kamcmd corex.list_aliases
 
 
-5.3. corex.shm_status
+5.3.  corex.shm_status
 
 
    Trigger shm status dump to syslog.
    Trigger shm status dump to syslog.
 
 
    Example:
    Example:
                 kamcmd corex.shm_status
                 kamcmd corex.shm_status
 
 
-5.4. corex.shm_summary
+5.4.  corex.shm_summary
 
 
    Trigger shm summary dump to syslog.
    Trigger shm summary dump to syslog.
 
 
    Example:
    Example:
                 kamcmd corex.shm_summary
                 kamcmd corex.shm_summary
+
+6. Event Routes
+
+   6.1. event_route[network:msg]
+
+6.1.  event_route[network:msg]
+
+   Event route block to be executed when new data is received from network
+   or the data that is about to be sent to a remote host by a SIP worker
+   process.
+
+   The kamailio script writer can check which type of data triggered this
+   event route using is_incoming method.
+
+   After executing of this event route, if msg_avp was defined and set
+   then its value is used for further processing, otherwise, original
+   value of $mb is used. If message was received from remote host, then it
+   is parsed and proceeds to appropriate route. Oterhwise if message set
+   to send out, then is sent to remote host per configured SIP timers in
+   config script.
+
+   Please note this event route is meant to prepare the message for
+   on-wire communication, e.g. to do custom encryption or decryption,
+   compression/decompression etc. of the message sent to or received from
+   remote host. Therefore, except text operations, no module fucntions or
+   pseudo variables are available in this event route.
+
+7. Examples of Usage
+
+   To use network event_route[network:msg] the remote SIP UA must also
+   implement and understand the encoding / decoding done in this event
+   route. It is up to Kamailio config script writer to define and
+   implement how encoding and decoding is done. Any language module such
+   as app_perl or app_lua can be called in in event_route[network:msg] to
+   implement desired logic.
+
+   The most simple use case is to compress the SIP packet on-wire. As SIP
+   is a text based protocol, so it is highly compressable. Using this
+   module, one can compress entire SIP message, including headers and
+   message body before sending it to remote host using any compression
+   algorithm of choice, thus saving significant bandwidth on mobile data
+   networks.
+
+   A useful case is to use this function between SIP edge proxy and SIP
+   application server. The SIP messages received from end-user at SIP edge
+   proxy may be decrypted and sent to SIP application server at remote
+   location unencrypted, where they are processed as normal. One the way
+   back, the messages received from SIP application server at edge proxy
+   can be encrpyted before being sent to actual destination. The edge
+   proxy can check whether received message came from end-user or SIP
+   application server by using simple regular expressions.
+
+   Another use case is to implement a virtual HTTP tunnel for SIP
+   messages. The SIP client app can convert SIP message to binary e.g. by
+   doing XOR, Base64 etc., then prepend some fake HTTP headers to make it
+   look like an HTTP request before sending it to kamailio over SIP TCP
+   socket. At kamailio, the fake headers are removed and data is decoded
+   back to normal SIP and processed per config script logic. For the data
+   that is to be sent to SIP client app, one can prepend fake HTTP reply
+   headers to encoded data before sending it to client app.
+
+   More advance use cases may involve custom encryption algorithms such as
+   ITV encryption algorithm, https://github.com/mshary/itv
+
+   For example, the client app running on Android or iPhone, may send
+   device UUID along with ITV key, encrypted using RSA or AES256 with
+   pre-shared secret, as first packet, which is set as cookie by server in
+   e.g. memcache. This cookie is referred by client app in each next
+   packet, so server can retrive encyption key from cache and use that for
+   decryption. Same can be done for server at client app side, so messages
+   encrypted by server can be decrypted at client app.
+
+   Next is a basic usage example where encoding and decoding is done using
+   PERL,
+
+   Example 1.9. event_route[network:msg] use cases
+...
+loadmodule "app_perl.so"
+loadmodule "corex.so"
+...
+# ----- app_perl params -----
+modparam("app_perl", "filename", "/usr/local/etc/kamailio/custom_compress.pl")
+modparam("app_perl", "modpath", "/usr/local/lib64/kamailio/perl")
+
+# ----- corex params -----
+modparam("corex", "network_io_intercept", 32)
+modparam("corex", "min_msg_len", 32)
+modparam("corex", "msg_avp", "$avp(msg)")
+...
+event_route[network:msg] {
+        if (is_incoming()) {
+                if (perl_exec_simple("do_uncompress", "" + $mb + "")) {
+                        xlog("L_INFO", "Received message '$avp(msg)' \n");
+                } else {
+                        xlog("L_INFO", "Received message '$mb' \n");
+                        $avp(msg) = $mb;
+                };
+        } else {
+                xlog("L_INFO", "Sending message '$mb' \n");
+                if (!perl_exec_simple("do_compress", "" + $mb + "")) {
+                        $avp(msg) = $mb;
+                };
+        };
+}
+...
+
+   Example 1.10. Sample PERL code for do_compress and do_uncompress
+...
+use strict;
+use warnings;
+use IO::Compress::Gzip qw(gzip $GzipError) ;
+use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ;
+
+sub do_compress() {
+        my $input = shift;
+        my $output;
+
+        gzip \$input => \$output
+                or eval {
+                        Kamailio::log(L_WARN, "GZIP failed: $GzipError\n");
+                        $output = $input;
+                };
+
+        Kamailio::AVP::add("msg", $output);
+}
+
+sub do_uncompress() {
+        my $input = shift;
+        my $output;
+
+        gunzip \$input => \$output
+                or eval {
+                        Kamailio::log(L_WARN, "GUNZIP failed: $GzipError\n");
+                        $output = $input;
+                };
+
+        Kamailio::AVP::add("msg", $output);
+}
+...

+ 15 - 2
modules/corex/corex_mod.c

@@ -31,9 +31,11 @@
 #include "corex_lib.h"
 #include "corex_lib.h"
 #include "corex_rpc.h"
 #include "corex_rpc.h"
 #include "corex_var.h"
 #include "corex_var.h"
+#include "corex_nio.h"
 
 
 MODULE_VERSION
 MODULE_VERSION
 
 
+static int nio_intercept = 0;
 static int w_append_branch(sip_msg_t *msg, char *su, char *sq);
 static int w_append_branch(sip_msg_t *msg, char *su, char *sq);
 static int w_send(sip_msg_t *msg, char *su, char *sq);
 static int w_send(sip_msg_t *msg, char *su, char *sq);
 static int w_send_tcp(sip_msg_t *msg, char *su, char *sq);
 static int w_send_tcp(sip_msg_t *msg, char *su, char *sq);
@@ -69,14 +71,19 @@ static cmd_export_t cmds[]={
 			0, REQUEST_ROUTE | FAILURE_ROUTE },
 			0, REQUEST_ROUTE | FAILURE_ROUTE },
 	{"send_data", (cmd_function)w_send_data, 2, fixup_spve_spve,
 	{"send_data", (cmd_function)w_send_data, 2, fixup_spve_spve,
 			0, ANY_ROUTE },
 			0, ANY_ROUTE },
-
+	{"is_incoming",    (cmd_function)nio_check_incoming, 0, 0,
+    	    0, ANY_ROUTE },
 
 
 	{0, 0, 0, 0, 0, 0}
 	{0, 0, 0, 0, 0, 0}
 };
 };
 
 
 static param_export_t params[]={
 static param_export_t params[]={
-	{"alias_subdomains",  PARAM_STRING|USE_FUNC_PARAM,
+	{"alias_subdomains",		STR_PARAM|USE_FUNC_PARAM,
 								(void*)corex_alias_subdomains_param},
 								(void*)corex_alias_subdomains_param},
+    {"network_io_intercept",	INT_PARAM, &nio_intercept},
+    {"min_msg_len",				INT_PARAM, &nio_min_msg_len},
+    {"msg_avp",			  		PARAM_STR, &nio_msg_avp_param},
+
 	{0, 0, 0}
 	{0, 0, 0}
 };
 };
 
 
@@ -114,6 +121,12 @@ static int mod_init(void)
 		return -1;
 		return -1;
 	}
 	}
 
 
+	if((nio_intercept > 0) && (nio_intercept_init() < 0))
+	{
+		LM_ERR("failed to register network io intercept callback\n");
+		return -1;
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 199 - 0
modules/corex/corex_nio.c

@@ -0,0 +1,199 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009 SIP-Router.org
+ *
+ * This file is part of Extensible SIP Router, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "corex_nio.h"
+
+/**
+ * init nio function
+ */
+int nio_intercept_init(void)
+{
+	int route_no;
+	pv_spec_t avp_spec;
+
+	route_no=route_get(&event_rt, "network:msg");
+
+	if (route_no==-1)
+	{
+		LM_ERR("failed to find event_route[network:msg]\n");
+		return -1;
+	}
+
+	if (event_rt.rlist[route_no]==0)
+	{
+		LM_ERR("event_route[network:msg] is empty\n");
+		return -1;
+	}
+
+	nio_route_no=route_no;
+	
+	if (nio_min_msg_len < 0)
+	{
+		LM_WARN("min_msg_len is less then zero, setting it to zero");
+		nio_min_msg_len = 0;
+	}
+
+	if (nio_msg_avp_param.s && nio_msg_avp_param.len > 0) 
+	{
+		if (pv_parse_spec(&nio_msg_avp_param, &avp_spec)==0
+				|| avp_spec.type!=PVT_AVP)
+		{
+			LM_ERR("malformed or non AVP %.*s AVP definition\n",
+					nio_msg_avp_param.len, nio_msg_avp_param.s);
+			return -1;
+		}
+
+		if(pv_get_avp_name(0, &(avp_spec.pvp), &nio_msg_avp_name,
+					&nio_msg_avp_type)!=0)
+		{
+			LM_ERR("[%.*s]- invalid AVP definition\n",
+					nio_msg_avp_param.len, nio_msg_avp_param.s);
+			return -1;
+		}
+	} else {
+		LM_WARN("no AVP defined to store modified message\n");
+	}
+
+    /* register network hooks */
+    sr_event_register_cb(SREV_NET_DATA_IN, nio_msg_received);
+    sr_event_register_cb(SREV_NET_DATA_OUT, nio_msg_sent);
+#ifdef USE_TCP
+    tcp_set_clone_rcvbuf(1);
+#endif
+    return 0;
+}
+
+/**
+ *
+ */
+int nio_msg_received(void *data)
+{
+    sip_msg_t msg;
+    str *obuf;
+    char *nbuf = NULL;
+    int_str avp_value;
+    struct usr_avp *avp;
+    struct run_act_ctx ra_ctx;
+
+    obuf = (str*)data;
+
+    if (obuf->len < nio_min_msg_len) {
+        return -1;
+    }
+
+    memset(&msg, 0, sizeof(sip_msg_t));
+    msg.buf = obuf->s;
+    msg.len = obuf->len;
+
+    nio_is_incoming = 1;
+    init_run_actions_ctx(&ra_ctx);
+    run_actions(&ra_ctx, event_rt.rlist[nio_route_no], &msg);
+
+    if(nio_msg_avp_name.n!=0) {
+        avp = NULL;
+        avp=search_first_avp(nio_msg_avp_type, nio_msg_avp_name,
+            &avp_value, 0);
+        if(avp!=NULL && is_avp_str_val(avp)) {
+            msg.buf = avp_value.s.s;
+            msg.len = avp_value.s.len;
+            nbuf = nio_msg_update(&msg, (unsigned int*)&obuf->len);
+            if(obuf->len>=BUF_SIZE) {
+                LM_ERR("new buffer overflow (%d)\n", obuf->len);
+                pkg_free(nbuf);
+                return -1;
+            }
+            memcpy(obuf->s, nbuf, obuf->len);
+            obuf->s[obuf->len] = '\0';
+        } else {
+            LM_WARN("no value set for AVP %.*s, using unmodified message\n",
+                nio_msg_avp_param.len, nio_msg_avp_param.s);
+        }
+    }
+
+    if(nbuf!=NULL)
+        pkg_free(nbuf);
+    free_sip_msg(&msg);
+    return 0;
+}
+
+/**
+ *
+ */
+int nio_msg_sent(void *data)
+{
+    sip_msg_t msg;
+    str *obuf;
+    int_str avp_value;
+    struct usr_avp *avp;
+    struct run_act_ctx ra_ctx;
+
+    obuf = (str*)data;
+
+    if (obuf->len < nio_min_msg_len) {
+        return -1;
+    }
+
+    memset(&msg, 0, sizeof(sip_msg_t));
+    msg.buf = obuf->s;
+    msg.len = obuf->len;
+
+    nio_is_incoming = 0;
+    init_run_actions_ctx(&ra_ctx);
+    run_actions(&ra_ctx, event_rt.rlist[nio_route_no], &msg);
+
+    if(nio_msg_avp_name.n!=0) {
+        avp = NULL;
+        avp=search_first_avp(nio_msg_avp_type, nio_msg_avp_name,
+                &avp_value, 0);
+        if(avp!=NULL && is_avp_str_val(avp)) {
+            msg.buf = avp_value.s.s;
+            msg.len = avp_value.s.len;
+            obuf->s = nio_msg_update(&msg, (unsigned int*)&obuf->len);
+        } else {
+            LM_WARN("no value set for AVP %.*s, using unmodified message\n",
+                nio_msg_avp_param.len, nio_msg_avp_param.s);
+        }
+    }
+
+    free_sip_msg(&msg);
+    return 0;
+}
+
+/**
+ *
+ */
+int nio_check_incoming(void)
+{
+    return (nio_is_incoming) ? 1 : -1;
+}
+
+/**
+ *
+ */
+char* nio_msg_update(sip_msg_t *msg, unsigned int *olen)
+{
+    struct dest_info dst;
+
+    init_dest_info(&dst);
+    dst.proto = PROTO_UDP;
+    return build_req_buf_from_sip_req(msg,
+            olen, &dst, BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE);
+}
+

+ 53 - 0
modules/corex/corex_nio.h

@@ -0,0 +1,53 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009 SIP-Router.org
+ *
+ * This file is part of Extensible SIP Router, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _COREX_NIO_H_
+#define _COREX_NIO_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../events.h"
+#include "../../ut.h"
+
+#include "../../tcp_options.h"
+#include "../../msg_translator.h"
+
+int nio_route_no;
+int nio_min_msg_len;
+int nio_is_incoming;
+
+str nio_msg_avp_param;
+int_str nio_msg_avp_name;
+unsigned short nio_msg_avp_type;
+
+int nio_msg_received(void *data);
+int nio_msg_sent(void *data);
+
+int nio_check_incoming(void);
+char* nio_msg_update(sip_msg_t *msg, unsigned int *olen);
+
+int nio_intercept_init(void);
+
+#endif

+ 5 - 0
modules/corex/doc/corex.xml

@@ -23,6 +23,11 @@
 		<surname>Mierla</surname>
 		<surname>Mierla</surname>
 		<email>[email protected]</email>
 		<email>[email protected]</email>
 	    </editor>
 	    </editor>
+	    <editor>
+		<firstname>Muhammad Shahzad</firstname>
+		<surname>Shafi</surname>
+		<email>[email protected]</email>
+	    </editor>
 	</authorgroup>
 	</authorgroup>
 	<copyright>
 	<copyright>
 	    <year>2012</year>
 	    <year>2012</year>

+ 257 - 0
modules/corex/doc/corex_admin.xml

@@ -29,6 +29,15 @@
 		Contributions to this module must be done under the BSD license, to
 		Contributions to this module must be done under the BSD license, to
 		follow the requirements of the core contributions.
 		follow the requirements of the core contributions.
 	</para>
 	</para>
+	<para>
+		This module now also provides access to network input / output data through
+		event_route[network:msg]. The raw data received from a remote host or about to
+		be sent to a remote host is available in variable $mb. The script writer may
+		manipulate this data and save the final result in an AVP defined by msg_avp
+		module parameter. The content of this AVP will then be processed by SIP worker
+		as normal, i.e. a received message will be parsed and sent to appropriate
+		route block while a sent message is forwarded to remote host.
+	</para>
 	</section>
 	</section>
 
 
 	<section>
 	<section>
@@ -87,6 +96,69 @@ modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
 </programlisting>
 </programlisting>
 	    </example>
 	    </example>
 	</section>
 	</section>
+    <section>
+        <title><varname>network_io_intercept</varname> (int)</title>
+        <para>
+            If set to non-zero then raw data received from a remote host or about to
+			be sent to a remote host is made available in event_route[network:msg].
+			The script writer may modify this and save to msg_avp, which will then
+			be processed by SIP worker as normal.
+        </para>
+        <para>
+        <emphasis>
+            Default value is 0, i.e. do not allow access to network io data.
+        </emphasis>
+        </para>
+        <example>
+        <title>Set <varname>network_io_intercept</varname> parameter</title>
+        <programlisting format="linespecific">
+...
+modparam("corex", "network_io_intercept", 1)
+...
+</programlisting>
+        </example>
+    </section>
+    <section>
+        <title><varname>msg_min_len</varname> (int)</title>
+        <para>
+            Minimum content length of the packet to execute the event_route[network:msg].
+			This only works if network_io_intercept parameter is set to non-zero.
+        </para>
+        <para>
+        <emphasis>
+            Default value is 0.
+        </emphasis>
+        </para>
+        <example>
+        <title>Set <varname>msg_min_len</varname> parameter</title>
+        <programlisting format="linespecific">
+...
+modparam("corex", "msg_min_len", 32)
+...
+</programlisting>
+        </example>
+    </section>
+    <section>
+        <title><varname>msg_avp</varname> (string)</title>
+        <para>
+            AVP name to store modified content to be set in the packet. If not set in
+            event_route[network:msg], then all changes are lost and original contents
+            are used. This only works if network_io_intercept parameter is to set non-zero.
+        </para>
+        <para>
+        <emphasis>
+            Default value is empty.
+        </emphasis>
+        </para>
+        <example>
+        <title>Set <varname>msg_avp</varname> parameter</title>
+        <programlisting format="linespecific">
+...
+modparam("corex", "msg_avp", "$avp(msg)")
+...
+</programlisting>
+        </example>
+    </section>
 	</section>
 	</section>
 
 
 	<section>
 	<section>
@@ -200,6 +272,36 @@ modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
+    <section>
+		<title>
+			<function moreinfo="none">is_incoming()</function>
+		</title>
+        <para>
+            Returns true if contents of message buffer $mb are the data received from
+            remote host, otherwise false indicating that the contents of $mb are data
+            that is about to be sent out to remote host. This only works if 
+			network_io_intercept parameter is set to non-zero.
+        </para>
+        <para>
+        This function can be used from event_route[network:msg].
+        </para>
+        <example>
+        <title><function>is_incoming</function> usage</title>
+        <programlisting format="linespecific">
+...
+event_route[network:msg] {
+    if (is_incoming()) {
+        xlog("L_INFO", "Received message '$mb' \n");
+        $avp(msg) = $mb;
+    } else {
+        xlog("L_INFO", "Sending message '$mb' \n");
+        $avp(msg) = $mb;
+    };
+}
+...
+</programlisting>
+        </example>
+    </section>
 
 
 	</section>
 	</section>
 
 
@@ -263,5 +365,160 @@ modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
 		</programlisting>
 		</programlisting>
     </section>
     </section>
     </section>
     </section>
+
+    <section>
+    <title>Event Routes</title>
+    <section id="async.evr.network_io">
+        <title>
+        <function moreinfo="none">event_route[network:msg]</function>
+        </title>
+        <para>
+            Event route block to be executed when new data is received from network
+            or the data that is about to be sent to a remote host by a SIP worker
+            process.
+        </para>
+        <para>
+            The kamailio script writer can check which type of data triggered this
+            event route using is_incoming method.
+        </para>
+        <para>
+            After executing of this event route, if msg_avp was defined and set then
+            its value is used for further processing, otherwise, original value of
+            $mb is used. If message was received from remote host, then it is parsed
+            and proceeds to appropriate route. Oterhwise if message set to send out,
+            then is sent to remote host per configured SIP timers in config script.
+        </para>
+        <para>
+            Please note this event route is meant to <emphasis>prepare</emphasis>
+            the message for on-wire communication, e.g. to do custom encryption or
+            decryption, compression/decompression etc. of the message sent to or 
+			received from remote host. Therefore, except text operations,
+			no module fucntions or pseudo variables are available in this event route.
+        </para>
+    </section>
+    </section>
+
+    <section>
+    <title>Examples of Usage</title>
+        <para>
+			To use network event_route[network:msg] the remote SIP UA must also implement and 
+			understand the encoding / decoding done in this event route. It is up to  &kamailio;
+			config script writer to define and implement how encoding and decoding is done. 
+			Any language module such as app_perl or app_lua can be called in
+			in event_route[network:msg] to implement desired logic.
+        </para>
+        <para>
+			The most simple use case is to compress the SIP packet on-wire. As SIP is a
+			text based protocol, so it is highly compressable. Using this module, one can
+			compress entire SIP message, including headers and message body before sending
+			it to remote host using any compression algorithm of choice, thus saving
+			significant bandwidth on mobile data networks.
+        </para>
+        <para>
+			A useful case is to use this function between SIP edge proxy and SIP application
+			server. The SIP messages received from end-user at SIP edge proxy may be decrypted
+			and sent to SIP application server at remote location unencrypted, where they are
+			processed as normal. One the way back, the messages received from SIP application
+			server at edge proxy can be encrpyted before being sent to actual destination.
+			The edge proxy can check whether received message came from end-user or SIP 
+			application server by using simple regular expressions.
+        </para>
+        <para>
+			Another use case is to implement a virtual HTTP tunnel for SIP messages. The SIP
+			client app can convert SIP message to binary e.g. by doing XOR, Base64 etc., then
+			prepend some fake HTTP headers to make it look like an HTTP request before sending
+			it to kamailio over SIP TCP socket. At kamailio, the fake headers are removed and data
+			is decoded back to normal SIP and processed per config script logic. For the data that
+			is to be sent to SIP client app, one can prepend fake HTTP reply headers to encoded
+			data before sending it to client app.
+        </para>
+        <para>
+			More advance use cases may involve custom encryption algorithms such as
+			ITV encryption algorithm,
+			<ulink url="https://github.com/mshary/itv"></ulink>
+        </para>
+        <para>
+			For example, the client app running on Android or iPhone, may send device UUID along
+			with ITV key, encrypted using RSA or AES256 with pre-shared secret, as first packet,
+			which is set as cookie by server in e.g. memcache. This cookie is referred by client
+			app in each next packet, so server can retrive encyption key from cache and use that
+			for decryption. Same can be done for server at client app side, so messages encrypted
+			by server can be decrypted at client app.
+        </para>
+        <para>
+			Next is a basic usage example where encoding and decoding is done using PERL,
+        </para>
+        <example>
+        <title><function>event_route[network:msg]</function> use cases</title>
+        <programlisting format="linespecific">
+...
+loadmodule "app_perl.so"
+loadmodule "corex.so"
+...
+# ----- app_perl params -----
+modparam("app_perl", "filename", "/usr/local/etc/kamailio/custom_compress.pl")
+modparam("app_perl", "modpath", "/usr/local/lib64/kamailio/perl")
+
+# ----- corex params -----
+modparam("corex", "network_io_intercept", 32)
+modparam("corex", "min_msg_len", 32)
+modparam("corex", "msg_avp", "$avp(msg)")
+...
+event_route[network:msg] {
+	if (is_incoming()) {
+		if (perl_exec_simple("do_uncompress", "" + $mb + "")) {
+			xlog("L_INFO", "Received message '$avp(msg)' \n");
+		} else {
+			xlog("L_INFO", "Received message '$mb' \n");
+			$avp(msg) = $mb;
+		};
+	} else {
+		xlog("L_INFO", "Sending message '$mb' \n");
+		if (!perl_exec_simple("do_compress", "" + $mb + "")) {
+			$avp(msg) = $mb;
+		};
+	};
+}
+...
+</programlisting>
+        </example>
+        <example>
+        <title>Sample PERL code for do_compress and do_uncompress</title>
+        <programlisting format="linespecific">
+...
+use strict;
+use warnings;
+use IO::Compress::Gzip qw(gzip $GzipError) ;
+use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ;
+
+sub do_compress() {
+	my $input = shift;
+	my $output;
+
+	gzip \$input => \$output
+		or eval {
+			Kamailio::log(L_WARN, "GZIP failed: $GzipError\n");
+			$output = $input;
+		};
+
+	Kamailio::AVP::add("msg", $output);
+}
+
+sub do_uncompress() {
+	my $input = shift;
+	my $output;
+
+	gunzip \$input => \$output
+		or eval {
+			Kamailio::log(L_WARN, "GUNZIP failed: $GzipError\n");
+			$output = $input;
+		};
+
+	Kamailio::AVP::add("msg", $output);
+}
+...
+</programlisting>
+        </example>
+    </section>
 </chapter>
 </chapter>