From cf398e1a442bc54c05d68837fcad6258cecc7dfe Mon Sep 17 00:00:00 2001
From: Brian West <brian@freeswitch.org>
Date: Mon, 22 Nov 2010 14:59:25 -0600
Subject: [PATCH] FS-535: tested but please test MORE.

---
 src/mod/endpoints/mod_sofia/mod_sofia.h  |  1 +
 src/mod/endpoints/mod_sofia/sofia_glue.c | 36 +++++++++++++++++++++++-
 src/mod/endpoints/mod_sofia/sofia_reg.c  | 33 +++++++++++++++++++---
 3 files changed, 65 insertions(+), 5 deletions(-)

diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h
index 750fb60c15..c1244c05f1 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.h
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.h
@@ -957,6 +957,7 @@ void sofia_presence_event_thread_start(void);
 void sofia_reg_expire_call_id(sofia_profile_t *profile, const char *call_id, int reboot);
 switch_status_t sofia_glue_tech_choose_video_port(private_object_t *tech_pvt, int force);
 switch_status_t sofia_glue_tech_set_video_codec(private_object_t *tech_pvt, int force);
+char *sofia_glue_get_register_host(const char *uri);
 const char *sofia_glue_strip_proto(const char *uri);
 switch_status_t reconfig_sofia(sofia_profile_t *profile);
 void sofia_glue_del_gateway(sofia_gateway_t *gp);
diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c
index fa828607bd..23d3f2904e 100644
--- a/src/mod/endpoints/mod_sofia/sofia_glue.c
+++ b/src/mod/endpoints/mod_sofia/sofia_glue.c
@@ -5734,6 +5734,41 @@ char *sofia_glue_execute_sql2str(sofia_profile_t *profile, switch_mutex_t *mutex
 	return ret;
 }
 
+char *sofia_glue_get_register_host(const char *uri)
+{
+	char *register_host = NULL;
+	const char *s;
+	char *p = NULL;
+
+	if ((s = switch_stristr("sip:", uri))) {
+		s += 4;
+	} else if ((s = switch_stristr("sips:", uri))) {
+		s += 5;
+	}
+
+	if (!s) {
+		return NULL;
+	}
+
+	register_host = strdup(s);
+	
+	/* remove port for register_host for testing nat acl take into account 
+	   ipv6 addresses which are required to have brackets around the addr 
+	*/
+	if ((p = strchr(register_host, ']')) && (*(p + 1) == ':')) {
+		*(p + 1) = '\0';
+	} else { 
+		if ((p = strrchr(register_host, ':'))) {
+			*p = '\0';
+		}
+	}
+	
+	/* register_proxy should always start with "sip:" or "sips:" */
+	assert(register_host);
+
+	return register_host;
+}
+
 const char *sofia_glue_strip_proto(const char *uri)
 {
 	char *p;
@@ -5983,7 +6018,6 @@ void sofia_glue_tech_simplify(private_object_t *tech_pvt)
 	}
 }
 
-
 void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl)
 {
 	switch_core_session_message_t *msg;
diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c
index 4bb879659c..14a7bfdd2c 100644
--- a/src/mod/endpoints/mod_sofia/sofia_reg.c
+++ b/src/mod/endpoints/mod_sofia/sofia_reg.c
@@ -142,16 +142,22 @@ void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now)
 			int ss_state = nua_callstate_authenticating;
 			sub_state_t ostate = gw_sub_ptr->state;
 			char *user_via = NULL;
+			char *register_host = NULL;
 
 			if (!now) {
 				gw_sub_ptr->state = ostate = SUB_STATE_UNSUBED;
 				gw_sub_ptr->expires_str = "0";
 			}
 
-			if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) {
+			register_host = sofia_glue_get_register_host(gateway_ptr->register_proxy);
+
+			/* check for NAT and place a Via header if necessary (hostname or non-local IP) */
+			if (sofia_glue_check_nat(gateway_ptr->profile, register_host)) {
 				user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport);
 			}
 
+			switch_safe_free(register_host);
+
 			switch (ostate) {
 			case SUB_STATE_NOSUB:
 				break;
@@ -189,7 +195,15 @@ void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now)
 				nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private);
 
 				if (now) {
-					nua_subscribe(gateway_ptr->sub_nh, NUTAG_URL(gateway_ptr->register_url), TAG_IF(user_via, SIPTAG_VIA_STR(user_via)), SIPTAG_EVENT_STR(gw_sub_ptr->event), SIPTAG_ACCEPT_STR(gw_sub_ptr->content_type), SIPTAG_TO_STR(gateway_ptr->register_from), SIPTAG_FROM_STR(gateway_ptr->register_from), SIPTAG_CONTACT_STR(gateway_ptr->register_contact), SIPTAG_EXPIRES_STR(gw_sub_ptr->expires_str),	// sofia stack bases its auto-refresh stuff on this
+					nua_subscribe(gateway_ptr->sub_nh,
+								  NUTAG_URL(gateway_ptr->register_url),
+								  TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+								  SIPTAG_EVENT_STR(gw_sub_ptr->event),
+								  SIPTAG_ACCEPT_STR(gw_sub_ptr->content_type),
+								  SIPTAG_TO_STR(gateway_ptr->register_from),
+								  SIPTAG_FROM_STR(gateway_ptr->register_from),
+								  SIPTAG_CONTACT_STR(gateway_ptr->register_contact),
+								  SIPTAG_EXPIRES_STR(gw_sub_ptr->expires_str),	/* sofia stack bases its auto-refresh stuff on this */
 								  TAG_NULL());
 					gw_sub_ptr->retry = now + gw_sub_ptr->retry_seconds;
 				} else {
@@ -266,6 +280,7 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now)
 	for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
 		reg_state_t ostate = gateway_ptr->state;
 		char *user_via = NULL;
+		char *register_host = NULL;
 
 		if (!now) {
 			gateway_ptr->state = ostate = REG_STATE_UNREGED;
@@ -277,10 +292,15 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now)
 			nua_handle_t *nh = nua_handle(profile->nua, NULL, NUTAG_URL(gateway_ptr->register_url), TAG_END());
 			sofia_private_t *pvt;
 
-			if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) {
+			register_host = sofia_glue_get_register_host(gateway_ptr->register_proxy);
+
+			/* check for NAT and place a Via header if necessary (hostname or non-local IP) */
+			if (sofia_glue_check_nat(gateway_ptr->profile, register_host)) {
 				user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport);
 			}
 
+			switch_safe_free(register_host);
+
 			pvt = malloc(sizeof(*pvt));
 			switch_assert(pvt);
 			memset(pvt, 0, sizeof(*pvt));
@@ -335,10 +355,15 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now)
 				sofia_reg_new_handle(gateway_ptr, now ? 1 : 0);
 			}
 
-			if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) {
+			register_host = sofia_glue_get_register_host(gateway_ptr->register_proxy);
+
+			/* check for NAT and place a Via header if necessary (hostname or non-local IP) */
+			if (sofia_glue_check_nat(gateway_ptr->profile, register_host)) {
 				user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport);
 			}
 
+			switch_safe_free(register_host);
+
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Registering %s\n", gateway_ptr->name);
 
 			if (now) {