modules_k/nathelper: add_contact_alias() now accepts parameters
authorJuha Heinanen <jh@tutpro.com>
Fri, 21 Sep 2012 09:55:36 +0000 (12:55 +0300)
committerJuha Heinanen <jh@tutpro.com>
Fri, 21 Sep 2012 09:55:36 +0000 (12:55 +0300)
- Function add_contact_alias() can now be given ip addr, port, and proto
  as parameters.

modules_k/nathelper/README
modules_k/nathelper/doc/nathelper_admin.xml
modules_k/nathelper/nathelper.c

index 150e38a..a439912 100644 (file)
@@ -24,13 +24,13 @@ Edited by
 
 Ovidiu Sas
 
-   Copyright © 2003-2008 Sippy Software, Inc.
+   Copyright Â© 2003-2008 Sippy Software, Inc.
 
-   Copyright © 2005 Voice Sistem SRL
+   Copyright Â© 2005 Voice Sistem SRL
 
-   Copyright © 2009 TuTPro Inc.
+   Copyright Â© 2009 TuTPro Inc.
 
-   Copyright © 2010 VoIPEmbedded Inc.
+   Copyright Â© 2010 VoIPEmbedded Inc.
      __________________________________________________________________
 
    Table of Contents
@@ -66,7 +66,7 @@ Ovidiu Sas
               5.5. fix_nated_register()
               5.6. nat_uac_test(flags)
               5.7. is_rfc1918(ip_address)
-              5.8. add_contact_alias()
+              5.8. add_contact_alias([ip_addr, port, proto])
               5.9. handle_ruri_alias()
 
         6. Exported Pseudo Variables
@@ -136,7 +136,7 @@ Chapter 1. Admin Guide
         5.5. fix_nated_register()
         5.6. nat_uac_test(flags)
         5.7. is_rfc1918(ip_address)
-        5.8. add_contact_alias()
+        5.8. add_contact_alias([ip_addr, port, proto])
         5.9. handle_ruri_alias()
 
    6. Exported Pseudo Variables
@@ -241,7 +241,7 @@ modparam("nathelper", "natping_interval", 10)
 
 4.2. ping_nated_only (integer)
 
-   If this variable is set then only contacts that have "behind_NAT" flag
+   If this variable is set then only contacts that have “behind_NAT” flag
    in user location database set will get ping.
 
    Default value is 0.
@@ -316,7 +316,7 @@ modparam("nathelper", "sipping_bflag", 7)
    feature, you have to set this parameter. The SIP request pinging will
    be used only for requests marked so.
 
-   Default value is "NULL".
+   Default value is “NULL”.
 
    Example 1.7. Set sipping_from parameter
 ...
@@ -328,7 +328,7 @@ modparam("nathelper", "sipping_from", "sip:pinger@siphub.net")
    The parameter sets the SIP method to be used in generating the SIP
    requests for NAT ping purposes.
 
-   Default value is "OPTIONS".
+   Default value is “OPTIONS”.
 
    Example 1.8. Set sipping_method parameter
 ...
@@ -346,7 +346,7 @@ Note
 
    The string must be a complete SDP line, including the EOH (\r\n).
 
-   Default value is "a=nortpproxy:yes\r\n".
+   Default value is “a=nortpproxy:yes\r\n”.
 
    Example 1.9. Set nortpproxy_str parameter
 ...
@@ -365,7 +365,7 @@ modparam("nathelper", "nortpproxy_str", "a=sdpmangled:yes\r\n")
    Keepalives are sent stateless, not using TM module. The value of this
    parameter has to be few times higher than natping_interval.
 
-   Default value is "0" (feature disabled).
+   Default value is “0” (feature disabled).
 
    Example 1.10. Set keepalive_timeout parameter
 ...
@@ -381,10 +381,10 @@ modparam("nathelper", "keepalive_timeout", 120)
    5.5. fix_nated_register()
    5.6. nat_uac_test(flags)
    5.7. is_rfc1918(ip_address)
-   5.8. add_contact_alias()
+   5.8. add_contact_alias([ip_addr, port, proto])
    5.9. handle_ruri_alias()
 
-5.1. fix_nated_contact()
+5.1.  fix_nated_contact()
 
    Rewrites Contact HF to contain request's source address:port.
 
@@ -396,18 +396,18 @@ modparam("nathelper", "keepalive_timeout", 120)
 if (search("User-Agent: Cisco ATA.*") {fix_nated_contact();};
 ...
 
-5.2. fix_nated_sdp(flags [, ip_address])
+5.2.  fix_nated_sdp(flags [, ip_address])
 
    Alters the SDP information in orer to facilitate NAT traversal. What
-   changes to be performed may be controled via the "flags" parameter.
+   changes to be performed may be controled via the “flags” parameter.
 
    Meaning of the parameters is as follows:
      * flags - the value may be a bitwise OR of the following flags:
-          + 0x01 - adds "a=direction:active" SDP line;
+          + 0x01 - adds “a=direction:active” SDP line;
           + 0x02 - rewrite media IP address (c=) with source address of
             the message or the provided IP address (the provide IP address
             take precedence over the source address).
-          + 0x04 - adds "a=nortpproxy:yes" SDP line;
+          + 0x04 - adds “a=nortpproxy:yes” SDP line;
           + 0x08 - rewrite IP from origin description (o=) with source
             address of the message or the provided IP address (the provide
             IP address take precedence over the source address).
@@ -424,7 +424,7 @@ if (search("User-Agent: Cisco ATA.*") {fix_nated_contact();};
 if (search("User-Agent: Cisco ATA.*") {fix_nated_sdp("3");};
 ...
 
-5.3. set_rtp_proxy_set()
+5.3.  set_rtp_proxy_set()
 
    Sets the Id of the rtpproxy set to be used for the next
    [un]force_rtp_proxy(), rtpproxy_offer() or rtpproxy_answer() command.
@@ -438,7 +438,7 @@ set_rtp_proxy_set("2");
 force_rtp_proxy();
 ...
 
-5.4. add_rcv_param([flag]),
+5.4.  add_rcv_param([flag]),
 
    Add received parameter to Contact header fields or Contact URI. The
    parameter will contain URI created from the source IP, port, and
@@ -462,7 +462,7 @@ add_rcv_param(); # add the parameter to the Contact header
 add_rcv_param("1"); # add the parameter to the Contact URI
 ...
 
-5.5. fix_nated_register()
+5.5.  fix_nated_register()
 
    The function creates a URI consisting of the source IP, port, and
    protocol and stores the URI in an Attribute-Value-Pair. The URI will be
@@ -480,7 +480,7 @@ add_rcv_param("1"); # add the parameter to the Contact URI
 fix_nated_register();
 ...
 
-5.6. nat_uac_test(flags)
+5.6.  nat_uac_test(flags)
 
    Tries to guess if client's request originated behind a nat. The
    parameter determines what heuristics is used.
@@ -503,17 +503,18 @@ fix_nated_register();
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
-5.7. is_rfc1918(ip_address)
+5.7.  is_rfc1918(ip_address)
 
    Determines if the address in the parameter is an rfc1918 address. The
    parameter allows pseudo-variables usage.
 
    This function can be used from ANY_ROUTE.
 
-5.8. add_contact_alias()
+5.8.  add_contact_alias([ip_addr, port, proto])
 
-   Adds ;alias=ip:port parameter to contact URI containing received
-   ip:port if contact uri ip:port does not match received ip:port.
+   Adds ;alias=ip~port~transport parameter to contact URI containing
+   either received ip, port, and transport protocol or those given as
+   parameters.
 
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    BRANCH_ROUTE, and LOCAL_ROUTE.
@@ -521,7 +522,7 @@ fix_nated_register();
    Example 1.16. add_contact_alias usage
 ...
     if (!is_present_hf("Record-Route")) {
-        if (!add_contact_alias()) {
+        if (!add_contact_alias("$var(src_ip)", "$Rp", "tcp")) {
             xlog("L_ERR", "Error in aliasing contact $ct\n");
             send_reply("400", "Bad request");
             exit;
@@ -529,7 +530,7 @@ fix_nated_register();
     };
 ...
 
-5.9. handle_ruri_alias()
+5.9.  handle_ruri_alias()
 
    Checks if Request URI has alias param and if so, removes it and sets
    $du based on its value. Note that this means that routing of request is
@@ -610,45 +611,45 @@ $ kamctl fifo nh_enable_ping 1
 
 Chapter 2. Frequently Asked Questions
 
-   2.1. What happend with "rtpproxy_disable" parameter?
+   2.1. What happend with “rtpproxy_disable” parameter?
    2.2. Where can I find more about Kamailio?
    2.3. Where can I post a question about this module?
    2.4. How can I report a bug?
 
    2.1.
 
-   What happend with "rtpproxy_disable" parameter?
+       What happend with “rtpproxy_disable” parameter?
 
-   It was removed as it became obsolete - now "rtpproxy_sock" can take
-   empty value to disable the rtpproxy functionality.
+       It was removed as it became obsolete - now “rtpproxy_sock” can take
+       empty value to disable the rtpproxy functionality.
 
    2.2.
 
-   Where can I find more about Kamailio?
+       Where can I find more about Kamailio?
 
-   Take a look at http://www.kamailio.org/.
+       Take a look at http://www.kamailio.org/.
 
    2.3.
 
-   Where can I post a question about this module?
+       Where can I post a question about this module?
 
-   First at all check if your question was already answered on one of our
-   mailing lists:
-     * User Mailing List -
-       http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
-     * Developer Mailing List -
-       http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
+       First at all check if your question was already answered on one of our
+       mailing lists:
+         * User Mailing List -
+           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
+         * Developer Mailing List -
+           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
 
-   E-mails regarding any stable Kamailio release should be sent to
-   <sr-users@lists.sip-router.org> and e-mails regarding development
-   versions should be sent to <sr-dev@lists.sip-router.org>.
+       E-mails regarding any stable Kamailio release should be sent to
+       <sr-users@lists.sip-router.org> and e-mails regarding development
+       versions should be sent to <sr-dev@lists.sip-router.org>.
 
-   If you want to keep the mail private, send it to
-   <sr-users@lists.sip-router.org>.
+       If you want to keep the mail private, send it to
+       <sr-users@lists.sip-router.org>.
 
    2.4.
 
-   How can I report a bug?
+       How can I report a bug?
 
-   Please follow the guidelines provided at:
-   http://sip-router.org/tracker.
+       Please follow the guidelines provided at:
+       http://sip-router.org/tracker.
index 18e4470..6dbf243 100644 (file)
@@ -598,12 +598,12 @@ fix_nated_register();
 
        <section>
                <title>
-               <function moreinfo="none">add_contact_alias()</function>
+               <function moreinfo="none">add_contact_alias([ip_addr, port, proto])</function>
                </title>
                <para>
-               Adds ;alias=ip:port parameter to contact URI containing
-               received ip:port if contact uri ip:port does not match
-               received ip:port.
+               Adds ;alias=ip~port~transport parameter to contact URI
+               containing either received ip, port, and transport protocol
+               or those given as parameters.
                </para>
                <para>
                This function can be used from
@@ -614,7 +614,7 @@ fix_nated_register();
                <programlisting format="linespecific">
 ...
     if (!is_present_hf("Record-Route")) {
-        if (!add_contact_alias()) {
+        if (!add_contact_alias("$var(src_ip)", "$Rp", "tcp")) {
             xlog("L_ERR", "Error in aliasing contact $ct\n");
             send_reply("400", "Bad request");
             exit;
index 7b13010..8ff80fe 100644 (file)
@@ -284,7 +284,8 @@ MODULE_VERSION
 #define        CPORT           "22222"
 static int nat_uac_test_f(struct sip_msg* msg, char* str1, char* str2);
 static int fix_nated_contact_f(struct sip_msg *, char *, char *);
-static int add_contact_alias_f(struct sip_msg *, char *, char *);
+static int add_contact_alias_0_f(struct sip_msg *, char *, char *);
+static int add_contact_alias_3_f(struct sip_msg *, char *, char *, char *);
 static int handle_ruri_alias_f(struct sip_msg *, char *, char *);
 static int pv_get_rr_count_f(struct sip_msg *, pv_param_t *, pv_value_t *);
 static int pv_get_rr_top_count_f(struct sip_msg *, pv_param_t *, pv_value_t *);
@@ -295,6 +296,7 @@ static int alter_mediaip(struct sip_msg *, str *, str *, int, str *, int, int);
 static int fix_nated_register_f(struct sip_msg *, char *, char *);
 static int fixup_fix_nated_register(void** param, int param_no);
 static int fixup_fix_sdp(void** param, int param_no);
+static int fixup_add_contact_alias(void** param, int param_no);
 static int add_rcv_param_f(struct sip_msg *, char *, char *);
 static int nh_sip_reply_received(sip_msg_t *msg);
 
@@ -358,9 +360,12 @@ static cmd_export_t cmds[] = {
        {"fix_nated_contact",  (cmd_function)fix_nated_contact_f,    0,
                0, 0,
                REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
-       {"add_contact_alias",  (cmd_function)add_contact_alias_f,    0,
+       {"add_contact_alias",  (cmd_function)add_contact_alias_0_f,  0,
                0, 0,
                REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
+       {"add_contact_alias",  (cmd_function)add_contact_alias_3_f,  3,
+               fixup_add_contact_alias, 0,
+               REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
        {"handle_ruri_alias",  (cmd_function)handle_ruri_alias_f,    0,
                0, 0,
                REQUEST_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
@@ -469,6 +474,13 @@ static int fixup_fix_nated_register(void** param, int param_no)
        return 0;
 }
 
+static int fixup_add_contact_alias(void** param, int param_no)
+{
+    if ((param_no >= 1) && (param_no <= 3)) return fixup_spve_null(param, 1);
+    LM_ERR("invalid parameter number <%d>\n", param_no);
+    return -1;
+}
 
 static struct mi_root* mi_enable_natping(struct mi_root* cmd_tree, 
                                                                                        void* param )
@@ -812,11 +824,12 @@ fix_nated_contact_f(struct sip_msg* msg, char* str1, char* str2)
 #define SALIAS_LEN (sizeof(SALIAS) - 1)
 
 /*
- * Adds ;alias=ip:port param to contact uri containing received ip:port
- * if contact uri ip:port does not match received ip:port.
+ * Adds ;alias=ip~port~proto param to contact uri containing received ip,
+ * port, and transport proto if contact uri ip and port do not match
+ * received ip and port.
  */
 static int
-add_contact_alias_f(struct sip_msg* msg, char* str1, char* str2)
+add_contact_alias_0_f(struct sip_msg* msg, char* str1, char* str2)
 {
     int len, param_len, ip_len;
     contact_t *c;
@@ -855,7 +868,7 @@ add_contact_alias_f(struct sip_msg* msg, char* str1, char* str2)
        
     /* Check if function has been called already */
     if ((c->uri.s < msg->buf) || (c->uri.s > (msg->buf + msg->len))) {
-       LM_ERR("you can't call alias_contact twice, check your config!\n");
+       LM_ERR("you can't call add_contact_alias twice, check your config!\n");
        return -1;
     }
 
@@ -940,6 +953,161 @@ add_contact_alias_f(struct sip_msg* msg, char* str1, char* str2)
 }
 
 
+static int proto_type_to_int(char *proto) {
+    if (strcasecmp(proto, "udp") == 0)
+       return PROTO_UDP;
+    if (strcasecmp(proto, "tcp") == 0)
+       return PROTO_TCP;
+    if (strcasecmp(proto, "tls") == 0)
+       return PROTO_TLS;
+    if (strcasecmp(proto, "sctp") == 0)
+       return PROTO_SCTP;
+    if (strcasecmp(proto, "ws") == 0)
+       return PROTO_WS;
+    if (strcasecmp(proto, "wss") == 0)
+       return PROTO_WSS;
+    return PROTO_OTHER;
+}
+
+
+/*
+ * Adds ;alias=ip~port~proto param to contact uri containing ip, port,
+ * and encoded proto given as parameters.
+ */
+static int
+add_contact_alias_3_f(struct sip_msg* msg, char* _ip, char* _port, char* _proto)
+{
+    int param_len, proto;
+    unsigned int tmp;
+    contact_t *c;
+    struct lump *anchor;
+    struct sip_uri uri;
+    char *bracket, *lt, *param, *at, *start;
+    str ip_str, port_str, proto_str;
+
+    /* Do nothing if Contact header does not exist */
+    if (!msg->contact) {
+       if (parse_headers(msg, HDR_CONTACT_F, 0) == -1)  {
+           LM_ERR("while parsing headers\n");
+           return -1;
+       }
+       if (!msg->contact) {
+           LM_DBG("no contact header\n");
+           return 2;
+       }
+    }
+    if (get_contact_uri(msg, &uri, &c) == -1) {
+       LM_ERR("failed to get contact uri\n");
+       return -1;
+    }
+
+    /* Get and check param values */
+    if (fixup_get_svalue(msg, (gparam_p)_ip, &ip_str) != 0) {
+       LM_ERR("cannot get ip param value\n");
+       return -1;
+    }
+    if ((str2ip(&ip_str) == NULL)
+#ifdef USE_IPV6
+       && (str2ip6(&ip_str) == NULL)
+#endif
+       ) {
+       LM_ERR("ip param value %s is not valid IP address\n", ip_str.s);
+       return -1;
+    }
+    if (fixup_get_svalue(msg, (gparam_p)_port, &port_str) != 0) {
+       LM_ERR("cannot get port param value\n");
+       return -1;
+    }
+    if ((str2int(&port_str, &tmp) == -1) || (tmp == 0) || (tmp > 65535)) {
+       LM_ERR("port param value is not valid port\n");
+       return -1;
+    }
+    if (fixup_get_svalue(msg, (gparam_p)_proto, &proto_str) != 0) {
+       LM_ERR("cannot get proto param value\n");
+       return -1;
+    }
+    proto = proto_type_to_int(proto_str.s);
+    if (proto == PROTO_OTHER) {
+       LM_ERR("proto param value %s is not a known protocol\n", proto_str.s);
+       return -1;
+    }
+
+    /* Check if function has been called already */
+    if ((c->uri.s < msg->buf) || (c->uri.s > (msg->buf + msg->len))) {
+       LM_ERR("you can't call alias_contact twice, check your config!\n");
+       return -1;
+    }
+
+    /* Check if Contact URI needs to be enclosed in <>s */
+    lt = param = NULL;
+    bracket = memchr(msg->contact->body.s, '<', msg->contact->body.len);
+    if (bracket == NULL) {
+       /* add opening < */
+       lt = (char*)pkg_malloc(1);
+       if (!lt) {
+           LM_ERR("no pkg memory left for lt sign\n");
+           goto err;
+       }
+       *lt = '<';
+       anchor = anchor_lump(msg, msg->contact->body.s - msg->buf, 0, 0);
+       if (anchor == NULL) {
+           LM_ERR("anchor_lump for beginning of contact body failed\n");
+           goto err;
+       }
+       if (insert_new_lump_before(anchor, lt, 1, 0) == 0) {
+           LM_ERR("insert_new_lump_before for \"<\" failed\n");
+           goto err;
+       }
+    }
+
+    /* Create  ;alias param */
+    param_len = SALIAS_LEN + IP6_MAX_STR_SIZE + 1 /* ~ */ + 5 /* port */ +
+       1 /* ~ */ + 1 /* proto */ + 1 /* closing > */;
+    param = (char*)pkg_malloc(param_len);
+    if (!param) {
+       LM_ERR("no pkg memory left for alias param\n");
+       goto err;
+    }
+    at = param;
+    /* ip address */
+    append_str(at, SALIAS, SALIAS_LEN);
+    append_str(at, ip_str.s, ip_str.len);
+    /* port */
+    append_chr(at, '~');
+    append_str(at, port_str.s, port_str.len);
+    /* proto */
+    append_chr(at, '~');
+    append_chr(at, proto + '0');
+    /* closing > */
+    if (bracket == NULL) {
+       append_chr(at, '>');
+    }
+    param_len = at - param;
+
+    /* Add  ;alias param */
+    LM_DBG("adding param <%.*s>\n", param_len, param);
+    if (uri.port.len > 0) {
+       start = uri.port.s + uri.port.len;
+    } else {
+       start = uri.host.s + uri.host.len;
+    }
+    anchor = anchor_lump(msg, start - msg->buf, 0, 0);
+    if (anchor == NULL) {
+       LM_ERR("anchor_lump for ;alias param failed\n");
+       goto err;
+    }
+    if (insert_new_lump_after(anchor, param, param_len, 0) == 0) {
+       LM_ERR("insert_new_lump_after for ;alias param failed\n");
+       goto err;
+    }
+    return 1;
+
+ err:
+    if (lt) pkg_free(lt);
+    if (param) pkg_free(param);
+    return -1;
+}
+
 #define ALIAS        "alias="
 #define ALIAS_LEN (sizeof(ALIAS) - 1)