소스 검색

* modules_k/nathelper

Added two new functions add_contact_alias() and handle_ruri_alias() and
two new pseudo variables $rr_count and $rr_top_count that can be used to
implement tcp connection sharing and produce correct Request URI for
in-dialog requests to NATed UAs.
(cherry picked from commit a85444180860da454831c5c0b366a6cc2f7f189f)
Juha Heinanen 16 년 전
부모
커밋
accf708dc5
4개의 변경된 파일852개의 추가작업 그리고 330개의 파일을 삭제
  1. 414 325
      modules_k/nathelper/README
  2. 19 0
      modules_k/nathelper/doc/nathelper.xml
  3. 123 4
      modules_k/nathelper/doc/nathelper_admin.xml
  4. 296 1
      modules_k/nathelper/nathelper.c

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 414 - 325
modules_k/nathelper/README


+ 19 - 0
modules_k/nathelper/doc/nathelper.xml

@@ -21,6 +21,14 @@
 			<email>[email protected]</email>
 		</address>
 		</author>
+		<author>
+		<firstname>Juha</firstname>
+		<surname>Heinanen</surname>
+		<affiliation><orgname>TuTPro, Inc.</orgname></affiliation>
+		<address>
+			<email>[email protected]</email>
+		</address>
+		</author>
 		<editor>
 		<firstname>Maxim</firstname>
 		<surname>Sobolev</surname>
@@ -35,6 +43,13 @@
 			<email>[email protected]</email>
 		</address>
 		</editor>
+		<editor>
+		<firstname>Juha</firstname>
+		<surname>Heinanen</surname>
+		<address>
+			<email>[email protected]</email>
+		</address>
+		</editor>
 	</authorgroup>
 	<copyright>
 		<year>2003-2008</year>
@@ -44,6 +59,10 @@
 		<year>2005</year>
 		<holder>&voicesystem;</holder>
 	</copyright>
+	<copyright>
+		<year>2009</year>
+		<holder>TuTPro Inc.</holder>
+	</copyright>
 	<revhistory>
 		<revision>
 		<revnumber>$Revision$</revnumber>

+ 123 - 4
modules_k/nathelper/doc/nathelper_admin.xml

@@ -17,13 +17,25 @@
 	<section>
 	<title>Overview</title>
 	<para>
-		This is a module to help with &nat; traversal. In particular, 
+		This is a module to help with &nat; traversal and reuse
+	of tcp connections.  In particular, 
 		it helps symmetric &ua;s that don't advertise they are symmetric 
-		and are not able to determine their public address. fix_nated_contact 
-		rewrites Contact header field with request's source address:port pair. 
-		fix_nated_sdp adds the active direction indication to &sdp; (flag
+		and are not able to determine their public
+	address. 
+	</para>
+	<para>
+	Function fix_nated_contact() 
+		rewrites Contact header field with request's source
+	address:port pair.  
+		Function fix_nated_sdp() adds the active direction
+	indication to &sdp; (flag 
 		0x01) and updates source &ip; address too (flag 0x02).
 	</para>
+	<para>
+	Alternative to fix_nated_contact() is add_contact_alias() that
+	together with handle_ruri_alias() also supports reuse of tcp
+	connections.
+	</para>
 	<para>
 		Known devices that get along over &nat;s with nathelper are ATAs 
 		(as clients) and Cisco Gateways (since 12.2(T)) as servers.  See <ulink
@@ -983,8 +995,115 @@ start_recording();
 		</programlisting>
 		</example>
 	</section>
+
+	<section>
+		<title>
+		<function moreinfo="none">add_contact_alias()</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.
+		</para>
+		<para>
+		This function can be used from
+		REQUEST_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE, and LOCAL_ROUTE.
+		</para>
+		<example>
+		<title><function>add_contact_alias</function> usage</title>
+		<programlisting format="linespecific">
+...
+    if (!is_present_hf("Record-Route")) {
+        if (!add_contact_alias()) {
+            xlog("L_ERR", "Error in aliasing contact $ct\n");
+            send_reply("400", "Bad request");
+            exit;
+        };
+    };
+...
+		</programlisting>
+		</example>
 	</section>
 
+	<section>
+		<title>
+		<function moreinfo="none">handle_ruri_alias()</function>
+		</title>
+		<para>
+		Checks if Request URI has alias param and if so, removes
+		it and sets $du based on its value.
+		</para>
+		<para>
+		This function can be used from
+		REQUEST_ROUTE, BRANCH_ROUTE, and LOCAL_ROUTE.
+		</para>
+		<example>
+		<title><function>handle_ruri_alias</function> usage</title>
+		<programlisting format="linespecific">
+...
+    if ($du == "") {
+        handle_ruri_alias();
+        switch ($rc) {
+        case -1:
+            xlog("L_ERR", "Failed to handle alias of R-URI $ru\n");
+            send_reply("400", "Bad request");
+            exit;
+        case 1:
+            xlog("L_INFO", "Routing in-dialog $rm from $fu to $du\n");
+            break;
+        case 2:
+            xlog("L_INFO", "Routing in-dialog $rm from $fu to $ru\n");
+            break;
+         };
+    };
+...
+		</programlisting>
+		</example>
+	</section>
+
+	</section>
+
+	<section>
+		<title>Exported Pseudo Variables</title>
+		<section>
+			<title><function moreinfo="none">$rr_count</function></title>
+			<para>
+			Number of Record Routes in received SIP request
+			or reply.
+			</para>
+		<example>
+		<title>$rr_count usage</title>
+		<programlisting format="linespecific">
+...
+    $avp(rr_count) = $rr_count;
+...
+		</programlisting>
+		</example>
+	        </section>
+
+		<section>
+			<title><function moreinfo="none">$rr_top_count</function></title>
+			<para>
+			If topmost Record Route in received SIP request
+			or reply is a double Record Route, value of
+			$rr_top_count is 2.  If it a single Record
+			Route, value of $rr_top_count 
+			is 1.  If there is no Record Route(s), value of
+			$rr_top_count is 0.
+			</para>
+		<example>
+		<title>$rr_top_count usage</title>
+		<programlisting format="linespecific">
+...
+    if ($rr_count == $avp(rr_count) + $rr_top_count) {
+        route(ADD_CONTACT_ALIAS);
+    };
+...
+		</programlisting>
+		</example>
+	        </section>
+
+	</section>
 
 	<section>
 		<title><acronym>MI</acronym> Commands</title>

+ 296 - 1
modules_k/nathelper/nathelper.c

@@ -210,10 +210,12 @@
 #include "../../lib/kcore/km_ut.h"
 #include "../../lib/kcore/parser_helpers.h"
 #include "../../pvar.h"
+#include "../../lvalue.h"
 #include "../../msg_translator.h"
 #include "../../usr_avp.h"
 #include "../../socket_info.h"
 #include "../../mod_fix.h"
+#include "../../dset.h"
 #include "../registrar/sip_msg.h"
 #include "../usrloc/usrloc.h"
 #include "nathelper.h"
@@ -277,6 +279,12 @@ 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 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 *);
+static int rr_count_f(struct sip_msg *, char *, char *);
+static int rr_top_count_f(struct sip_msg *, char *, char *);
 static int fix_nated_sdp_f(struct sip_msg *, char *, char *);
 static int extract_mediaip(str *, str *, int *, char *);
 static int extract_mediainfo(str *, str *, str *);
@@ -406,6 +414,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,
+		0, 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},
 	{"fix_nated_sdp",      (cmd_function)fix_nated_sdp_f,        1,
 		fixup_fix_sdp,  0,
 		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
@@ -475,6 +489,14 @@ static cmd_export_t cmds[] = {
 	{0, 0, 0, 0, 0, 0}
 };
 
+static pv_export_t mod_pvs[] = {
+    {{"rr_count", (sizeof("rr_count")-1)}, /* number of records routes */
+     PVT_CONTEXT, pv_get_rr_count_f, 0, 0, 0, 0, 0},
+    {{"rr_top_count", (sizeof("rr_top_count")-1)}, /* number of topmost rrs */
+     PVT_CONTEXT, pv_get_rr_top_count_f, 0, 0, 0, 0, 0},
+    {{0, 0}, 0, 0, 0, 0, 0, 0, 0}
+};
+
 static param_export_t params[] = {
 	{"natping_interval",      INT_PARAM, &natping_interval      },
 	{"ping_nated_only",       INT_PARAM, &ping_nated_only       },
@@ -509,7 +531,7 @@ struct module_exports exports = {
 	params,
 	0,           /* exported statistics */
 	mi_cmds,     /* exported MI functions */
-	0,           /* exported pseudo-variables */
+	mod_pvs,     /* exported pseudo-variables */
 	0,           /* extra processes */
 	mod_init,
 	0,           /* reply processing */
@@ -1371,6 +1393,279 @@ fix_nated_contact_f(struct sip_msg* msg, char* str1, char* str2)
 }
 
 
+#define SALIAS        ";alias="
+#define SALIAS_LEN (sizeof(SALIAS) - 1)
+
+/*
+ * Adds ;alias=ip:port param to cotact uri containing received ip:port
+ * if contact uri ip:port does not match received ip:port.
+ */
+static int
+add_contact_alias_f(struct sip_msg* msg, char* str1, char* str2)
+{
+    int len, param_len, ip_len;
+    contact_t *c;
+    struct lump *anchor;
+    struct sip_uri uri;
+    struct ip_addr *ip;
+    char *param, *at, *port, *start;
+
+    /* 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;
+    }
+
+    /* Compare source ip and port against contact uri */
+    if ((ip = str2ip(&(uri.host))) == NULL) {
+	LM_ERR("contact uri host is not an ip address\n");
+	return -1;
+    }
+    if (ip_addr_cmp(ip, &(msg->rcv.src_ip)) &&
+	((msg->rcv.src_port == uri.port_no) ||
+	 ((uri.port.len == 0) && (msg->rcv.src_port == 5060)))) {
+	LM_DBG("no need to add alias param\n");
+	return 2;
+    }
+	
+    /* Add alias param */
+    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;
+    }
+    param_len = SALIAS_LEN + IP6_MAX_STR_SIZE + 1 /* : */ + 5 /* port */ +
+	1 /* t */ + 1 /* proto */;
+    param = (char*)pkg_malloc(param_len);
+    if (!param) {
+	LM_ERR("no pkg memory left for alias param\n");
+	return -1;
+    }
+    at = param;
+    append_str(at, SALIAS, SALIAS_LEN);
+    ip_len = ip_addr2sbuf(&(msg->rcv.src_ip), at, param_len - SALIAS_LEN);
+    if (ip_len <= 0) {
+	pkg_free(param);
+	LM_ERR("failed to copy source ip\n");
+	return -1;
+    }
+    at = at + ip_len;
+    append_chr(at, ':');
+    port = int2str(msg->rcv.src_port, &len);
+    append_str(at, port, len);
+    append_chr(at, 't');
+    if ((msg->rcv.proto < PROTO_UDP) || (msg->rcv.proto > PROTO_SCTP)) {
+	pkg_free(param);
+	LM_ERR("invalid transport protocol\n");
+	return -1;
+    }
+    append_chr(at, msg->rcv.proto + '0');
+    param_len = at - 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) {
+	pkg_free(param);
+	LM_ERR("anchor_lump failed\n");
+	return -1;
+    }
+    if (insert_new_lump_after(anchor, param, param_len, 0) == 0) {
+	LM_ERR("insert_new_lump_after failed\n");
+	pkg_free(param);
+	return -1;
+    }
+    return 1;
+}
+
+
+#define ALIAS        "alias="
+#define ALIAS_LEN (sizeof(ALIAS) - 1)
+
+/*
+ * Checks if r-uri has alias param and if so, removes it and sets $du
+ * based on its value.
+ */
+static int
+handle_ruri_alias_f(struct sip_msg* msg, char* str1, char* str2)
+{
+    str params, uri, proto;
+    char buf[MAX_URI_SIZE], *val, *sep, *trans, *at, *next, *cur_uri;
+    unsigned int len, plen, alias_len, proto_type, cur_uri_len;
+
+    if ((msg->parsed_uri_ok == 0) && (parse_sip_msg_uri(msg) < 0)) {
+	LM_ERR("while parsing Request-URI\n");
+	return -1;
+    }
+    params = msg->parsed_uri.params;
+    if (params.len == 0) {
+	LM_DBG("no params\n");
+	return 2;
+    }
+    if ((params.len < ALIAS_LEN) ||
+	(strncmp(params.s, ALIAS, ALIAS_LEN) != 0)) {
+	LM_DBG("no alias param\n");
+	return 2;
+    }
+
+    /* set dst uri based on alias param value */
+    val = params.s + ALIAS_LEN;
+    plen = params.len - ALIAS_LEN;
+    sep = memchr(val, 116 /* t */, plen);
+    if (sep == NULL) {
+	LM_ERR("no 't' in alias param\n");
+	return -1;
+    }
+    at = &(buf[0]);
+    append_str(at, "sip:", 4);
+    len = sep - val;
+    alias_len = SALIAS_LEN + len + 2 /* tn */;
+    memcpy(at, val, len);
+    at = at + len;
+    trans = sep + 1;
+    if ((len + 2 > plen) || (*trans == ';') || (*trans == '?')) {
+	LM_ERR("no proto in alias param\n");
+	return -1;
+    }
+    proto_type = *trans - 48 /* char 0 */;
+    if (proto_type != PROTO_UDP) {
+	proto_type_to_str(proto_type, &proto);
+	if (proto.len == 0) {
+	    LM_ERR("unkown proto in alias param\n");
+	    return -1;
+	}
+	append_str(at, ";transport=", 11);
+	memcpy(at, proto.s, proto.len);
+	at = at + proto.len;
+    }
+    next = trans + 1;
+    if ((len + 2 < plen) && (*next != ';') && (*next != '?')) {
+	LM_ERR("invalid alias param value\n");
+	return -1;
+    }
+    uri.s = &(buf[0]);
+    uri.len = at - &(buf[0]);
+    LM_DBG("setting dst_uri to <%.*s>\n", uri.len, uri.s);
+    if (set_dst_uri(msg, &uri) == -1) {
+	LM_ERR("failed to set dst uri\n");
+	return -1;
+    }
+    
+    /* remove alias param */
+    if (msg->new_uri.s) {
+	cur_uri = msg->new_uri.s;
+	cur_uri_len = msg->new_uri.len;
+    } else {
+	cur_uri = msg->first_line.u.request.uri.s;
+	cur_uri_len = msg->first_line.u.request.uri.len;
+    }
+    at = &(buf[0]);
+    len = params.s - 1 /* ; */ - cur_uri;
+    memcpy(at, cur_uri, len);
+    at = at + len;
+    len = cur_uri_len - alias_len - len;
+    memcpy(at, params.s + alias_len - 1, len);
+    uri.s = &(buf[0]);
+    uri.len = cur_uri_len - alias_len;
+    LM_DBG("rewriting r-uri to <%.*s>\n", uri.len, uri.s);
+    return rewrite_uri(msg, &uri);
+}
+
+
+/*
+ * Counts and return the number of record routes in rr headers of the message.
+ */
+static int
+pv_get_rr_count_f(struct sip_msg *msg, pv_param_t *param,
+		  pv_value_t *res)
+{
+    unsigned int count;
+    struct hdr_field *header;
+    rr_t *body;
+
+    if (msg == NULL) return -1;
+
+    if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
+	LM_ERR("while parsing message\n");
+	return -1;
+    }
+
+    count = 0;
+    header = msg->record_route;
+
+    while (header) {
+	if (header->type == HDR_RECORDROUTE_T) {
+	    if (parse_rr(header) == -1) {
+		LM_ERR("while parsing rr header\n");
+		return -1;
+	    }
+	    body = (rr_t *)header->parsed;
+	    while (body) {
+		count++;
+		body = body->next;
+	    }
+	}
+	header = header->next;
+    }
+
+    return pv_get_uintval(msg, param, res, (unsigned int)count);
+}
+
+/*
+ * Return count of topmost record routes in rr headers of the message.
+ */
+static int
+pv_get_rr_top_count_f(struct sip_msg *msg, pv_param_t *param,
+		      pv_value_t *res)
+{
+    unsigned int count;
+    struct hdr_field *header;
+    str uri;
+    struct sip_uri puri;
+
+    if (msg == NULL) return -1;
+
+    if (!msg->record_route &&
+	(parse_headers(msg, HDR_RECORDROUTE_F, 0) == -1)) {
+	LM_ERR("while parsing Record-Route header\n");
+	return -1;
+    }
+
+    if (!msg->record_route) {
+	return pv_get_uintval(msg, param, res, 0);
+    }
+    
+    if (parse_rr(msg->record_route) == -1) {
+	LM_ERR("while parsing rr header\n");
+	return -1;
+    }
+
+    uri = ((rr_t *)msg->record_route->parsed)->nameaddr.uri;
+    if (parse_uri(uri.s, uri.len, &puri) < 0) {
+	LM_ERR("while parsing rr uri\n");
+	return -1;
+    }
+	
+    if (puri.r2.len > 0) {
+	return pv_get_uintval(msg, param, res, 2);
+    } else {
+	return pv_get_uintval(msg, param, res, 1);
+    }
+}
+
+
 /*
  * Test if IP address pointed to by saddr belongs to RFC1918 networks
  */

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.