Browse Source

registrar(s): set send socket if uri includes received info

- set send socket when the contact includes received info
  (replication for NATed contacts)
- use contact received information only if the trust_received_flag
  is set for the message (the flag actually used can be set with
  the modparam with the same name).
Andrei Pelinescu-Onciul 15 years ago
parent
commit
a7d84df08c
3 changed files with 142 additions and 12 deletions
  1. 14 0
      modules_s/registrar/reg_mod.c
  2. 1 0
      modules_s/registrar/reg_mod.h
  3. 127 12
      modules_s/registrar/save.c

+ 14 - 0
modules_s/registrar/reg_mod.c

@@ -54,6 +54,7 @@ MODULE_VERSION
 static int mod_init(void);                           /* Module init function */
 static int fix_save_nat_flag( modparam_t type, void* val);
 static int fix_load_nat_flag( modparam_t type, void* val);
+static int fix_trust_received_flag( modparam_t type, void* val);
 static int domain_fixup(void** param, int param_no); /* Fixup that converts domain name */
 static int domain2_fixup(void** param, int param_no); /* Fixup that converts domain name */
 static void mod_destroy(void);
@@ -66,6 +67,9 @@ int append_branches = 1;              /* If set to 1, lookup will put all contac
 int case_sensitive  = 0;              /* If set to 1, username in aor will be case sensitive */
 int save_nat_flag   = 4;              /* The contact will be marked as behind NAT if this flag is set before calling save */
 int load_nat_flag   = 4;              /* This flag will be set by lookup if a contact is behind NAT*/
+int trust_received_flag = -1;         /* if this flag is set, a contact
+										 received param. will be trusted
+										 (otherwise it will be ignored) */
 int min_expires     = 60;             /* Minimum expires the phones are allowed to use in seconds,
 			               * use 0 to switch expires checking off */
 int max_expires     = 0;              /* Minimum expires the phones are allowed to use in seconds,
@@ -140,6 +144,9 @@ static param_export_t params[] = {
 	{"contact_attr",      PARAM_STR, &contact_attr},
 	{"aor_attr",          PARAM_STR, &aor_attr},
 	{"server_id_attr",    PARAM_STR, &server_id_attr},
+	{"trust_received_flag",  PARAM_INT, &trust_received_flag},
+	{"trust_received_flag",  PARAM_STRING|PARAM_USE_FUNC,
+										fix_trust_received_flag},
 	{0, 0, 0}
 };
 
@@ -260,6 +267,13 @@ static int fix_load_nat_flag( modparam_t type, void* val)
 	return fix_flag(type, val, "registrar", "load_nat_flag", &load_nat_flag);
 }
 
+/* fixes trust_received_flag param (resolves possible named flags) */
+static int fix_trust_received_flag( modparam_t type, void* val)
+{
+	return fix_flag(type, val, "registrar", "trust_received_flag",
+					&trust_received_flag);
+}
+
 
 /*
  * Convert char* parameter to udomain_t* pointer

+ 1 - 0
modules_s/registrar/reg_mod.h

@@ -42,6 +42,7 @@ extern qvalue_t default_q;
 extern int append_branches;
 extern int load_nat_flag;
 extern int save_nat_flag;
+extern int trust_received_flag;
 extern int min_expires;
 extern int max_expires;
 extern int received_avp;

+ 127 - 12
modules_s/registrar/save.c

@@ -33,13 +33,20 @@
  * 2003-03-21 save_noreply added, patch provided by 
  *            Maxim Sobolev <[email protected]> (janakj)
  * 2005-02-25 incoming socket is saved in USRLOC (bogdan)
+ * 2010-09-30 trust received info only if trust_received_flag is set (andrei)
+ * 2010-10-01 if received info is available try to set the incoming socket
+ *            to the information saved in received.
  */
 
 
 #include "../../comp_defs.h"
 #include "../../str.h"
-#include "../../parser/parse_to.h"
 #include "../../dprint.h"
+#include "../../parser/parse_to.h"
+#include "../../parser/parse_param.h"
+#include "../../parser/parse_uri.h"
+#include "../../resolve.h"
+#include "../../socket_info.h"
 #include "../../trim.h"
 #include "../../ut.h"
 #include "../usrloc/usrloc.h"
@@ -256,6 +263,96 @@ static int create_rcv_uri(str** uri, struct sip_msg* m)
 }
 
 
+
+/** find send socket based on dst_ip saved in rcv_uri.
+ * Based on usrloc(s) find_socket() (modules_s/usrloc/udomain.c),
+ * but will try only IPs (no DNS lookups) and it is quiet on errors.
+ *
+ * @param received - received uri in the format:
+ *                   sip:src_host:src_port;dstip=IP;dstport=port
+ * @param ip - filled with the ip in dst_ip.
+ * @param port - filled with the port in dst_ip (if present)
+ * @param proto - filled with the uri protocol.
+ * @return <0 on error, 0 on success
+ */
+int parse_uri_dstip(str* received, struct ip_addr* ip, unsigned short* port,
+						unsigned short* proto)
+{
+	struct sip_uri puri;
+	param_hooks_t hooks;
+	struct ip_addr* p;
+	param_t* params;
+	int error;
+
+	if (unlikely(!received)) return 0;
+	if (unlikely(parse_uri(received->s, received->len, &puri) < 0))
+		goto error_uri;
+	*proto = puri.proto;
+	if (unlikely(parse_params(&puri.params, CLASS_URI, &hooks, &params) < 0))
+		goto error_uri_params;
+	if (unlikely(hooks.uri.dstip == 0 || hooks.uri.dstip->body.s == 0 ||
+				 hooks.uri.dstip->body.len == 0))
+		goto end; /* no dst_ip param */
+	/* check if it's ipv4 or ipv6 */
+	if (likely(((p = str2ip(&hooks.uri.dstip->body)) != 0) ||
+#ifdef USE_IPV6
+				((p = str2ip6(&hooks.uri.dstip->body)) != 0)
+#endif /* USE_IPV6 */
+				)) {
+		*ip = *p;
+	} else
+		goto error_no_ip; /* no ip */
+	if (likely(hooks.uri.dstport != 0 && hooks.uri.dstport->body.s  != 0 &&
+			hooks.uri.dstport->body.len !=0)) {
+		*port = str2s(hooks.uri.dstport->body.s, hooks.uri.dstport->body.len,
+					&error);
+		if (unlikely(error != 0))
+			goto error_port;
+	} else {
+		*port = 0;
+	}
+	
+end:
+	if (params) free_params(params);
+	return 0;
+error_uri:
+error_uri_params:
+error_no_ip:
+error_port:
+	if (params) free_params(params);
+	return -1;
+}
+
+
+
+/** try to find the send socket based on saved received information in uri.
+ * @param received - received uri in the format:
+ *                   sip:src_host:src_port;dstip=IP;dstport=port
+ * @return 0 on error or not found, socket_info pointer on success.
+ */
+static struct socket_info* find_send_socket(str* received)
+{
+	struct ip_addr ip;
+	unsigned short port;
+	unsigned short proto;
+	struct socket_info* si;
+
+	if (unlikely(parse_uri_dstip(received, &ip, &port, &proto) < 0))
+		return 0;
+	si = find_si(&ip, port, proto);
+#if 0
+	/* FIXME: which would be the best fallback procedure, proto:ip:*
+	   (try to keep the ip, although unlikely to be possible for replication)
+	   or proto:*: port (try to keep the same port, usefull for proxies
+	   behind transparent proxies /LBs) */
+	if (si == 0)
+		si = find_si(&ip, 0, proto);
+#endif
+	return si;
+}
+
+
+
 /*
  * Message contained some contacts, but record with same address of record was
  * not found so we have to create a new record and insert all contacts from
@@ -272,6 +369,7 @@ static inline int insert(struct sip_msg* _m, str* aor, contact_t* _c, udomain_t*
 	str callid;
 	unsigned int flags;
 	str *recv, *inst;
+	struct socket_info* send_sock;
 
 	if (isflagset(_m, save_nat_flag) == 1) flags = FL_NAT;
 	else flags = FL_NONE;
@@ -320,9 +418,12 @@ static inline int insert(struct sip_msg* _m, str* aor, contact_t* _c, udomain_t*
 			ul.delete_urecord(_d, _u);
 			return -4;
 		}
-
-		if (_c->received) {
+		
+		send_sock = 0;
+		if (_c->received && (trust_received_flag >=0) &&
+				(isflagset(_m, trust_received_flag) == 1)) {
 			recv = &_c->received->body;
+			send_sock = find_send_socket(recv);
 		} else if (flags & FL_NAT && _m->first_line.type == SIP_REQUEST) {
 			if (create_rcv_uri(&recv, _m) < 0) {
 				ERR("Error while creating rcv URI\n");
@@ -339,8 +440,11 @@ static inline int insert(struct sip_msg* _m, str* aor, contact_t* _c, udomain_t*
 			inst = 0;
 		}
 
-		if (ul.insert_ucontact(r, aor, &_c->uri, e, q, &callid, cseq, flags, &c, ua, recv, 
-							   _m->rcv.bind_address, inst, sid) < 0) {
+		if (ul.insert_ucontact(r, aor, &_c->uri, e, q, &callid, cseq,
+								flags, &c, ua, recv,
+								send_sock?send_sock:_m->rcv.bind_address,
+								inst, sid) < 0)
+		{
 			rerrno = R_UL_INS_C;
 			LOG(L_ERR, "insert(): Error while inserting contact\n");
 			ul.delete_urecord(_d, _u);
@@ -430,6 +534,7 @@ static inline int update(struct sip_msg* _m, urecord_t* _r, str* aor, contact_t*
 	qvalue_t q;
 	unsigned int nated;
 	str* recv, *inst;
+	struct socket_info* send_sock;
 	
 	if (isflagset(_m, save_nat_flag) == 1) {
 		nated = FL_NAT;
@@ -485,9 +590,13 @@ static inline int update(struct sip_msg* _m, urecord_t* _r, str* aor, contact_t*
 					return -3;
 				}
 				
-				if (_c->received) {
+				send_sock = 0;
+				if (_c->received && (trust_received_flag >=0) &&
+						(isflagset(_m, trust_received_flag) == 1)) {
 					recv = &_c->received->body;
-				} else if (nated & FL_NAT && _m->first_line.type == SIP_REQUEST) {
+					send_sock = find_send_socket(recv);
+				} else if (nated & FL_NAT && 
+							_m->first_line.type == SIP_REQUEST) {
 					if (create_rcv_uri(&recv, _m) < 0) {
 						ERR("Error while creating rcv URI\n");
 						rerrno = R_UL_INS_C;
@@ -497,10 +606,10 @@ static inline int update(struct sip_msg* _m, urecord_t* _r, str* aor, contact_t*
 					recv = 0;
 				}
 
-				if (ul.insert_ucontact(_r, aor, &_c->uri, e, q, &callid, cseq, 
+				if (ul.insert_ucontact(_r, aor, &_c->uri, e, q, &callid, cseq,
 						       nated | mem_only,
-						       &c2, _ua, recv, 
-						       _m->rcv.bind_address,
+						       &c2, _ua, recv,
+								send_sock?send_sock:_m->rcv.bind_address,
 									   inst, sid) < 0) {
 					rerrno = R_UL_INS_C;
 					LOG(L_ERR, "update(): Error while inserting contact\n");
@@ -539,8 +648,11 @@ static inline int update(struct sip_msg* _m, urecord_t* _r, str* aor, contact_t*
 					return -7;
 				}
 				
-				if (_c->received) {
+				send_sock = 0;
+				if (_c->received && (trust_received_flag >=0) &&
+						(isflagset(_m, trust_received_flag) == 1)) {
 					recv = &_c->received->body;
+					send_sock = find_send_socket(recv);
 				} else if (nated & FL_NAT && _m->first_line.type == SIP_REQUEST) {
 					if (create_rcv_uri(&recv, _m) < 0) {
 						ERR("Error while creating rcv URI\n");
@@ -553,7 +665,10 @@ static inline int update(struct sip_msg* _m, urecord_t* _r, str* aor, contact_t*
 
 				set = nated | mem_only;
 				reset = ~(nated | mem_only) & (FL_NAT | FL_MEM);
-				if (ul.update_ucontact(c, &_c->uri, aor, e, q, &callid, cseq, set, reset, _ua, recv, _m->rcv.bind_address, inst, sid) < 0) {
+				if (ul.update_ucontact(c, &_c->uri, aor, e, q, &callid, cseq,
+							set, reset, _ua, recv,
+							send_sock?send_sock:_m->rcv.bind_address,
+							inst, sid) < 0) {
 					rerrno = R_UL_UPD_C;
 					LOG(L_ERR, "update(): Error while updating contact\n");
 					return -8;