diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index d8e87d3be0..851e583ee0 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -394,6 +394,7 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { nua_bye(tech_pvt->nh, SIPTAG_REASON_STR(reason), + TAG_IF(!switch_strlen_zero(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_IF(!switch_strlen_zero(bye_headers), SIPTAG_HEADER_STR(bye_headers)), TAG_END()); } @@ -407,7 +408,6 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) nua_cancel(tech_pvt->nh, SIPTAG_REASON_STR(reason), TAG_IF(!switch_strlen_zero(bye_headers), SIPTAG_HEADER_STR(bye_headers)), - TAG_IF(!switch_strlen_zero(bye_headers), SIPTAG_HEADER_STR(bye_headers)), TAG_END()); } } else { @@ -2694,6 +2694,8 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session } } + sofia_glue_get_user_host(switch_core_session_strdup(nsession, tech_pvt->dest), NULL, &tech_pvt->remote_ip); + if (dest_to) { if (strchr(dest_to, '@')) { tech_pvt->dest_to = switch_core_session_sprintf(nsession, "sip:%s", dest_to); @@ -3217,6 +3219,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) mod_sofia_globals.running = 1; switch_mutex_unlock(mod_sofia_globals.mutex); + mod_sofia_globals.auto_nat = (switch_core_get_variable("nat_type") ? 1 : 0); + switch_queue_create(&mod_sofia_globals.presence_queue, SOFIA_QUEUE_SIZE, mod_sofia_globals.pool); switch_queue_create(&mod_sofia_globals.mwi_queue, SOFIA_QUEUE_SIZE, mod_sofia_globals.pool); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index fe08c7772f..39da35cb59 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -192,6 +192,7 @@ typedef enum { PFLAG_MESSAGE_QUERY_ON_REGISTER, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE, PFLAG_PROXY_FOLLOW_REDIRECT, + PFLAG_AUTO_NAT, /* No new flags below this line */ PFLAG_MAX } PFLAGS; @@ -272,6 +273,7 @@ struct mod_sofia_globals { char guess_mask_str[16]; int debug_presence; int auto_restart; + int auto_nat; }; extern struct mod_sofia_globals mod_sofia_globals; @@ -408,9 +410,13 @@ struct sofia_profile { char *extsipip; char *username; char *url; + char *public_url; char *bindurl; char *tls_url; + char *tls_public_url; char *tls_bindurl; + char *tcp_public_contact; + char *tls_public_contact; char *tcp_contact; char *tls_contact; char *sla_contact; @@ -430,8 +436,8 @@ struct sofia_profile { sofia_cid_type_t cid_type; sofia_dtmf_t dtmf_type; int auto_restart; - int sip_port; - int tls_sip_port; + switch_port_t sip_port; + switch_port_t tls_sip_port; int tls_version; char *codec_string; int running; @@ -489,6 +495,7 @@ struct sofia_profile { uint32_t timer_t2; uint32_t timer_t4; char *contact_user; + char *local_network; }; struct private_object { @@ -613,6 +620,7 @@ struct private_object { switch_rtp_bug_flag_t rtp_bugs; switch_codec_implementation_t read_impl; switch_codec_implementation_t write_impl; + char *user_via; }; struct callback_t { @@ -822,7 +830,9 @@ sofia_transport_t sofia_glue_str2transport(const char *str); const char *sofia_glue_transport2str(const sofia_transport_t tp); char * sofia_glue_find_parameter(const char *str, const char *param); - +char *sofia_glue_create_via(switch_core_session_t *session, const char *ip, switch_port_t port, sofia_transport_t transport); +char *sofia_glue_create_external_via(switch_core_session_t *session, sofia_profile_t *profile, sofia_transport_t transport); +int sofia_glue_check_nat(sofia_profile_t *profile, const char *network_ip); int sofia_glue_transport_has_tls(const sofia_transport_t tp); const char *sofia_glue_get_unknown_header(sip_t const *sip, const char *name); switch_status_t sofia_glue_build_crypto(private_object_t *tech_pvt, int index, switch_rtp_crypto_key_type_t type, switch_rtp_crypto_direction_t direction); @@ -835,7 +845,7 @@ switch_status_t sofia_glue_tech_set_video_codec(private_object_t *tech_pvt, int 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); -void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const char *host, const char *contact, const char *user_agent); +void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const char *host, const char *contact, const char *user_agent, const char *network_ip); void sofia_glue_restart_all_profiles(void); void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly); const char * sofia_state_string(int state); @@ -877,3 +887,4 @@ int sofia_get_loglevel(const char *name); sofia_cid_type_t sofia_cid_name2type(const char *name); void sofia_glue_tech_set_local_sdp(private_object_t *tech_pvt, const char *sdp_str, switch_bool_t dup); void sofia_glue_set_rtp_stats(private_object_t *tech_pvt); +void sofia_glue_get_addr(msg_t *msg, char *buf, size_t buflen, int *port); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 0ab2723832..e390e1dc1b 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -406,8 +406,7 @@ void sofia_event_callback(nua_event_t event, if (authorization) { char network_ip[80]; - su_addrinfo_t *addrinfo = msg_addrinfo(nua_current_request(nua)); - get_addr(network_ip, sizeof(network_ip), addrinfo->ai_addr, addrinfo->ai_addrlen); + sofia_glue_get_addr(nua_current_request(nua), network_ip, sizeof(network_ip), NULL); auth_res = sofia_reg_parse_auth(profile, authorization, sip, (char *) sip->sip_request->rq_method_name, tech_pvt->key, strlen(tech_pvt->key), network_ip, NULL, 0, REG_INVITE, NULL, NULL); @@ -762,10 +761,23 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void use_timer ? "timer, " : "" ); + if (sofia_test_pflag(profile, PFLAG_AUTO_NAT)) { + if (switch_nat_add_mapping(profile->sip_port, SWITCH_NAT_UDP) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created UDP nat mapping for %s port %d\n", profile->name, profile->sip_port); + } + if (switch_nat_add_mapping(profile->sip_port, SWITCH_NAT_TCP) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created TCP nat mapping for %s port %d\n", profile->name, profile->sip_port); + } + if(sofia_test_pflag(profile, PFLAG_TLS) && switch_nat_add_mapping(profile->tls_sip_port, SWITCH_NAT_TCP) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created TCP/TLS nat mapping for %s port %d\n", profile->name, profile->tls_sip_port); + } + } + profile->nua = nua_create(profile->s_root, /* Event loop */ sofia_event_callback, /* Callback for processing events */ profile, /* Additional data to pass to callback */ NUTAG_URL(profile->bindurl), + NTATAG_USER_VIA(1), TAG_IF(!strchr(profile->sipip, ':'), SOATAG_AF(SOA_AF_IP4_ONLY)), TAG_IF(strchr(profile->sipip, ':'), SOATAG_AF(SOA_AF_IP6_ONLY)), TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), NUTAG_SIPS_URL(profile->tls_bindurl)), @@ -939,6 +951,18 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void switch_event_fire(&s_event); } + if (sofia_test_pflag(profile, PFLAG_AUTO_NAT)) { + if (switch_nat_del_mapping(profile->sip_port, SWITCH_NAT_UDP) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted UDP nat mapping for %s port %d\n", profile->name, profile->sip_port); + } + if (switch_nat_del_mapping(profile->sip_port, SWITCH_NAT_TCP) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted TCP nat mapping for %s port %d\n", profile->name, profile->sip_port); + } + if(sofia_test_pflag(profile, PFLAG_TLS) && switch_nat_del_mapping(profile->tls_sip_port, SWITCH_NAT_TCP) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted TCP/TLS nat mapping for %s port %d\n", profile->name, profile->tls_sip_port); + } + } + sofia_glue_sql_close(profile); su_home_unref(profile->home); su_root_destroy(profile->s_root); @@ -1757,8 +1781,10 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile) } else { sofia_clear_pflag(profile, PFLAG_AUTH_CALLS); } - } else if(!strcasecmp(var, "context")) { + } else if (!strcasecmp(var, "context")) { profile->context = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "local-network-acl")) { + profile->local_network = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "force-register-domain")) { profile->reg_domain = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "force-register-db-domain")) { @@ -2145,7 +2171,7 @@ switch_status_t config_sofia(int reload, char *profile_name) } else if (!strcasecmp(var, "cng-pt") && !sofia_test_pflag(profile, PFLAG_SUPPRESS_CNG)) { profile->cng_pt = (switch_payload_t) atoi(val); } else if (!strcasecmp(var, "sip-port")) { - profile->sip_port = atoi(val); + profile->sip_port = (switch_port_t)atoi(val); } else if (!strcasecmp(var, "vad")) { if (!strcasecmp(val, "in")) { sofia_set_flag(profile, TFLAG_VAD_IN); @@ -2163,9 +2189,12 @@ switch_status_t config_sofia(int reload, char *profile_name) if (!strcmp(val, "0.0.0.0")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n", mod_sofia_globals.guess_ip); + } else if (!strcasecmp(val, "auto-nat")) { + ip = mod_sofia_globals.auto_nat ? switch_core_get_variable("nat_public_addr") : mod_sofia_globals.guess_ip; } else { - ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip; + ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip; } + sofia_set_pflag(profile, PFLAG_AUTO_NAT); profile->extrtpip = switch_core_strdup(profile->pool, ip); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid ext-rtp-ip\n"); @@ -2198,6 +2227,8 @@ switch_status_t config_sofia(int reload, char *profile_name) if (!strcasecmp(val, "0.0.0.0")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n", mod_sofia_globals.guess_ip); + } else if (!strcasecmp(val, "auto-nat")) { + ip = mod_sofia_globals.auto_nat ? switch_core_get_variable("nat_public_addr") : mod_sofia_globals.guess_ip; } else if (strcasecmp(val, "auto")) { switch_port_t port = 0; if (sofia_glue_ext_address_lookup(profile, NULL, &myip, &port, val, profile->pool) == SWITCH_STATUS_SUCCESS) { @@ -2206,10 +2237,13 @@ switch_status_t config_sofia(int reload, char *profile_name) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get external ip.\n"); } } + sofia_set_pflag(profile, PFLAG_AUTO_NAT); profile->extsipip = switch_core_strdup(profile->pool, ip); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid ext-sip-ip\n"); } + } else if (!strcasecmp(var, "local-network-acl")) { + profile->local_network = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "force-register-domain")) { profile->reg_domain = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "force-register-db-domain")) { @@ -2264,7 +2298,7 @@ switch_status_t config_sofia(int reload, char *profile_name) } else if (!strcasecmp(var, "manage-shared-appearance")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE); - profile->sla_contact = switch_core_sprintf(profile->pool, "sip:sla-agent@%s", profile->sipip); + profile->sla_contact = switch_core_sprintf(profile->pool, "sla-agent"); } } else if (!strcasecmp(var, "disable-srv")) { if (switch_true(val)) { @@ -2466,7 +2500,7 @@ switch_status_t config_sofia(int reload, char *profile_name) } else if (!strcasecmp(var, "tls-bind-params")) { profile->tls_bind_params = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "tls-sip-port")) { - profile->tls_sip_port = atoi(val); + profile->tls_sip_port = (switch_port_t)atoi(val); } else if (!strcasecmp(var, "tls-cert-dir")) { profile->tls_cert_dir = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "tls-version")) { @@ -2534,7 +2568,7 @@ switch_status_t config_sofia(int reload, char *profile_name) } if (!profile->sip_port) { - profile->sip_port = atoi(SOFIA_DEFAULT_PORT); + profile->sip_port = (switch_port_t)atoi(SOFIA_DEFAULT_PORT); } if (!profile->dialplan) { @@ -2548,7 +2582,18 @@ switch_status_t config_sofia(int reload, char *profile_name) if (!profile->sipdomain) { profile->sipdomain = switch_core_strdup(profile->pool, profile->sipip); } - if (profile->extsipip) { + if (profile->extsipip && sofia_test_pflag(profile, PFLAG_AUTO_NAT)) { + char *ipv6 = strchr(profile->extsipip, ':'); + profile->public_url = switch_core_sprintf(profile->pool, + "sip:%s@%s%s%s:%d", + profile->contact_user, + ipv6 ? "[" : "", + profile->extsipip, + ipv6 ? "]" : "", + profile->sip_port); + } + + if (profile->extsipip && !sofia_test_pflag(profile, PFLAG_AUTO_NAT)) { char *ipv6 = strchr(profile->extsipip, ':'); profile->url = switch_core_sprintf(profile->pool, "sip:%s@%s%s%s:%d", @@ -2571,7 +2616,11 @@ switch_status_t config_sofia(int reload, char *profile_name) } profile->tcp_contact = switch_core_sprintf(profile->pool, "%s;transport=tcp", profile->url); - + + if (sofia_test_pflag(profile, PFLAG_AUTO_NAT)) { + profile->tcp_public_contact = switch_core_sprintf(profile->pool, "%s;transport=tcp", profile->public_url); + } + if (profile->bind_params) { char *bindurl = profile->bindurl; profile->bindurl = switch_core_sprintf(profile->pool, "%s;%s", bindurl, profile->bind_params); @@ -2582,10 +2631,21 @@ switch_status_t config_sofia(int reload, char *profile_name) */ if (sofia_test_pflag(profile, PFLAG_TLS)) { if (!profile->tls_sip_port) { - profile->tls_sip_port = atoi(SOFIA_DEFAULT_TLS_PORT); + profile->tls_sip_port = (switch_port_t)atoi(SOFIA_DEFAULT_TLS_PORT); } - if (profile->extsipip) { + if (profile->extsipip && sofia_test_pflag(profile, PFLAG_AUTO_NAT)) { + char *ipv6 = strchr(profile->extsipip, ':'); + profile->tls_public_url = switch_core_sprintf(profile->pool, + "sip:%s@%s%s%s:%d", + profile->contact_user, + ipv6 ? "[" : "", + profile->extsipip, + ipv6 ? "]" : "", + profile->tls_sip_port); + } + + if (profile->extsipip && !sofia_test_pflag(profile, PFLAG_AUTO_NAT)) { char *ipv6 = strchr(profile->extsipip, ':'); profile->tls_url = switch_core_sprintf(profile->pool, @@ -2632,6 +2692,9 @@ switch_status_t config_sofia(int reload, char *profile_name) profile->tls_cert_dir = switch_core_sprintf(profile->pool, "%s/ssl", SWITCH_GLOBAL_dirs.conf_dir); } profile->tls_contact = switch_core_sprintf(profile->pool, "%s;transport=tls", profile->tls_url); + if (sofia_test_pflag(profile, PFLAG_AUTO_NAT)) { + profile->tls_public_contact = switch_core_sprintf(profile->pool, "%s;transport=tls", profile->tls_public_url); + } } } if (profile) { @@ -2774,13 +2837,11 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status const char *uuid; switch_core_session_t *other_session; private_object_t *tech_pvt = switch_core_session_get_private(session); - su_addrinfo_t *my_addrinfo = msg_addrinfo(nua_current_request(nua)); char network_ip[80]; int network_port = 0; switch_caller_profile_t *caller_profile = NULL; - get_addr(network_ip, sizeof(network_ip), my_addrinfo->ai_addr, my_addrinfo->ai_addrlen); - network_port = ntohs(((struct sockaddr_in *) msg_addrinfo(nua_current_request(nua))->ai_addr)->sin_port); + sofia_glue_get_addr(nua_current_request(nua), network_ip, sizeof(network_ip), &network_port); switch_channel_set_variable(channel, "sip_reply_host", network_ip); switch_channel_set_variable_printf(channel, "sip_reply_port", "%d", network_port); @@ -4282,10 +4343,10 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ uint32_t sess_count = switch_core_session_count(); uint32_t sess_max = switch_core_session_limit(0); int is_auth = 0, calling_myself = 0; - su_addrinfo_t *my_addrinfo = msg_addrinfo(nua_current_request(nua)); int network_port = 0; char *is_nat = NULL; char acl_token[512] = ""; + sofia_transport_t transport; profile->ib_calls++; @@ -4306,8 +4367,7 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ goto fail; } - get_addr(network_ip, sizeof(network_ip), my_addrinfo->ai_addr, my_addrinfo->ai_addrlen); - network_port = ntohs(((struct sockaddr_in *) msg_addrinfo(nua_current_request(nua))->ai_addr)->sin_port); + sofia_glue_get_addr(nua_current_request(nua), network_ip, sizeof(network_ip), &network_port); if (sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION)) { if (sip && sip->sip_via) { @@ -4444,9 +4504,10 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ if (sip->sip_contact && sip->sip_contact->m_url) { char tmp[35] = ""; - sofia_transport_t transport = sofia_glue_url2transport(sip->sip_contact->m_url); - const char *ipv6 = strchr(tech_pvt->remote_ip, ':'); + + transport = sofia_glue_url2transport(sip->sip_contact->m_url); + tech_pvt->record_route = switch_core_session_sprintf(session, "sip:%s@%s%s%s:%d;transport=%s", @@ -4573,7 +4634,6 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ if (sip->sip_to && sip->sip_to->a_url) { const char *host, *user; int port; - sofia_transport_t transport; url_t *transport_url; if (sip->sip_record_route && sip->sip_record_route->r_url) { @@ -4623,14 +4683,21 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { tech_pvt->reply_contact = switch_core_session_sprintf(session, "", user, host); } else { + const char *url = NULL; - const char *url; - - if ((url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url)) { + if (sofia_glue_check_nat(profile, tech_pvt->remote_ip)) { + url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_public_url : profile->public_url; + } else { + url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url; + } + + if (url) { if (strchr(url, '>')) { - tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;transport=%s", url, sofia_glue_transport2str(transport)); + tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;transport=%s", url, + sofia_glue_transport2str(transport)); } else { - tech_pvt->reply_contact = switch_core_session_sprintf(session, "<%s;transport=%s>", url, sofia_glue_transport2str(transport)); + tech_pvt->reply_contact = switch_core_session_sprintf(session, "<%s;transport=%s>", profile->url, + sofia_glue_transport2str(transport)); } } else { switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); @@ -4638,19 +4705,30 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ } } } else { - const char *url; - - if ((url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url)) { + const char *url = NULL; + if (sofia_glue_check_nat(profile, tech_pvt->remote_ip)) { + url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_public_url : profile->public_url; + } else { + url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url; + } + + if (url) { if (strchr(url, '>')) { - tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;transport=%s", url, sofia_glue_transport2str(transport)); + tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;transport=%s", url, + sofia_glue_transport2str(transport)); } else { - tech_pvt->reply_contact = switch_core_session_sprintf(session, "<%s;transport=%s>", url, sofia_glue_transport2str(transport)); + tech_pvt->reply_contact = switch_core_session_sprintf(session, "<%s;transport=%s>", profile->url, + sofia_glue_transport2str(transport)); } } else { switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); } } } + + if (sofia_glue_check_nat(profile, tech_pvt->remote_ip)) { + tech_pvt->user_via = sofia_glue_create_external_via(session, profile, tech_pvt->transport); + } if (sip->sip_contact && sip->sip_contact->m_url) { const char *contact_uri = url_set_chanvars(session, sip->sip_contact->m_url, sip_contact); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index d8ecb8c4dc..c305a2efd5 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -663,9 +663,14 @@ switch_status_t sofia_glue_tech_choose_port(private_object_t *tech_pvt, int forc return SWITCH_STATUS_FALSE; } } - - tech_pvt->adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, ip); + if (tech_pvt->profile->extrtpip && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { + tech_pvt->adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, tech_pvt->profile->extrtpip); + switch_nat_add_mapping((switch_port_t)sdp_port, SWITCH_NAT_UDP); + } else { + tech_pvt->adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, ip); + } + tech_pvt->adv_sdp_audio_port = sdp_port; switch_snprintf(tmp, sizeof(tmp), "%d", sdp_port); @@ -708,6 +713,10 @@ switch_status_t sofia_glue_tech_choose_video_port(private_object_t *tech_pvt, in tech_pvt->adv_sdp_video_port = sdp_port; + if (sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { + switch_nat_add_mapping((switch_port_t)sdp_port, SWITCH_NAT_UDP); + } + switch_snprintf(tmp, sizeof(tmp), "%d", sdp_port); switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip); switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE, tmp); @@ -806,6 +815,40 @@ const char *sofia_glue_transport2str(const sofia_transport_t tp) } } +char *sofia_glue_create_external_via(switch_core_session_t *session, sofia_profile_t *profile, sofia_transport_t transport) +{ + return sofia_glue_create_via(session, + profile->extsipip, + (sofia_glue_transport_has_tls(transport)) + ? profile->tls_sip_port : profile->sip_port, + transport); +} + +char *sofia_glue_create_via(switch_core_session_t *session, const char *ip, switch_port_t port, sofia_transport_t transport) +{ + if (port && port != 5060) { + if (session) { + return switch_core_session_sprintf(session, "SIP/2.0/%s %s:%d;rport", sofia_glue_transport2str(transport), ip, port); + } else { + return switch_mprintf("SIP/2.0/%s %s:%d;rport", sofia_glue_transport2str(transport), ip, port); + } + } else { + if (session) { + return switch_core_session_sprintf(session, "SIP/2.0/%s %s;rport", sofia_glue_transport2str(transport), ip); + } else { + return switch_mprintf("SIP/2.0/%s %s;rport", sofia_glue_transport2str(transport), ip); + } + } +} + +int sofia_glue_check_nat(sofia_profile_t *profile, const char *network_ip) +{ + return (network_ip && + profile->local_network && + sofia_test_pflag(profile, PFLAG_AUTO_NAT) && + !switch_check_network_list_ip(network_ip, profile->local_network)); +} + int sofia_glue_transport_has_tls(const sofia_transport_t tp) { switch (tp) { @@ -817,6 +860,18 @@ int sofia_glue_transport_has_tls(const sofia_transport_t tp) } } +void sofia_glue_get_addr(msg_t *msg, char *buf, size_t buflen, int *port) { + su_addrinfo_t *addrinfo = msg_addrinfo(msg); + + if (buf) { + get_addr(buf, buflen, addrinfo->ai_addr, addrinfo->ai_addrlen); + } + + if (port) { + *port = get_port(addrinfo->ai_addr); + } +} + char *sofia_overcome_sip_uri_weakness(switch_core_session_t *session, const char *uri, const sofia_transport_t transport, switch_bool_t uri_only, const char *params) { @@ -1257,10 +1312,18 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) check_decode(cid_num, session); if (!tech_pvt->from_str) { - const char* sipip = tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip; - const char* format = strchr(sipip, ':') ? "\"%s\" " : "\"%s\" "; + const char* sipip; + const char* format; const char *alt = NULL; + if (sofia_glue_check_nat(tech_pvt->profile, tech_pvt->profile->local_network)) { + sipip = tech_pvt->profile->extsipip; + } else { + sipip = tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip; + } + + format = strchr(sipip, ':') ? "\"%s\" " : "\"%s\" "; + if ((alt = switch_channel_get_variable(channel, "sip_invite_domain"))) { sipip = alt; } @@ -1365,6 +1428,10 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) tech_pvt->transport = SOFIA_TRANSPORT_UDP; } } + + if (sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { + tech_pvt->user_via = sofia_glue_create_external_via(session, tech_pvt->profile, tech_pvt->transport); + } if (!sofia_test_pflag(tech_pvt->profile, PFLAG_TLS) && sofia_glue_transport_has_tls(tech_pvt->transport)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "TLS not supported by profile\n"); @@ -1374,8 +1441,18 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) if (switch_strlen_zero(tech_pvt->invite_contact)) { const char * contact; if ((contact = switch_channel_get_variable(channel, "sip_contact_user"))) { - char *ip_addr = (tech_pvt->profile->extsipip) ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip; - char *ipv6 = strchr(ip_addr, ':'); + char *ip_addr; + char *ipv6; + + if (sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { + ip_addr = (switch_check_network_list_ip(tech_pvt->remote_ip, tech_pvt->profile->local_network)) + ? tech_pvt->profile->sipip : tech_pvt->profile->extsipip; + } else { + ip_addr = tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip; + } + + ipv6 = strchr(ip_addr, ':'); + if (sofia_glue_transport_has_tls(tech_pvt->transport)) { tech_pvt->invite_contact = switch_core_session_sprintf(session, "sip:%s@%s%s%s:%d", contact, ipv6 ? "[" : "", ip_addr, ipv6 ? "]" : "", @@ -1388,7 +1465,11 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) if (sofia_glue_transport_has_tls(tech_pvt->transport)) { tech_pvt->invite_contact = tech_pvt->profile->tls_url; } else { - tech_pvt->invite_contact = tech_pvt->profile->url; + if (sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { + tech_pvt->invite_contact = tech_pvt->profile->public_url; + } else { + tech_pvt->invite_contact = tech_pvt->profile->url; + } } } } @@ -1603,6 +1684,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) nua_invite(tech_pvt->nh, NUTAG_AUTOANSWER(0), NUTAG_SESSION_TIMER(session_timeout), + TAG_IF(!switch_strlen_zero(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_IF(!switch_strlen_zero(tech_pvt->rpid), SIPTAG_REMOTE_PARTY_ID_STR(tech_pvt->rpid)), TAG_IF(!switch_strlen_zero(tech_pvt->preferred_id), SIPTAG_P_PREFERRED_IDENTITY_STR(tech_pvt->preferred_id)), TAG_IF(!switch_strlen_zero(tech_pvt->asserted_id), SIPTAG_P_ASSERTED_IDENTITY_STR(tech_pvt->asserted_id)), @@ -1630,14 +1712,22 @@ void sofia_glue_do_xfer_invite(switch_core_session_t *session) private_object_t *tech_pvt = switch_core_session_get_private(session); switch_channel_t *channel = switch_core_session_get_channel(session); switch_caller_profile_t *caller_profile; - const char *sipip, *format; + const char *sipip, *format, *contact_url; switch_assert(tech_pvt != NULL); switch_mutex_lock(tech_pvt->sofia_mutex); caller_profile = switch_channel_get_caller_profile(channel); - sipip = tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip; + if (sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { + sipip = tech_pvt->profile->extsipip; + contact_url = tech_pvt->profile->public_url; + } else { + sipip = tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip; + contact_url = tech_pvt->profile->url; + } + format = strchr(sipip, ':') ? "\"%s\" " : "\"%s\" "; + if ((tech_pvt->from_str = switch_core_session_sprintf(session, format, caller_profile->caller_id_name, caller_profile->caller_id_number, sipip))) { @@ -1646,12 +1736,15 @@ void sofia_glue_do_xfer_invite(switch_core_session_t *session) tech_pvt->nh2 = nua_handle(tech_pvt->profile->nua, NULL, SIPTAG_TO_STR(tech_pvt->dest), - SIPTAG_FROM_STR(tech_pvt->from_str), SIPTAG_CONTACT_STR(tech_pvt->profile->url), TAG_END()); + SIPTAG_FROM_STR(tech_pvt->from_str), + SIPTAG_CONTACT_STR(contact_url), + TAG_END()); nua_handle_bind(tech_pvt->nh2, tech_pvt->sofia_private); nua_invite(tech_pvt->nh2, - SIPTAG_CONTACT_STR(tech_pvt->profile->url), + SIPTAG_CONTACT_STR(contact_url), + TAG_IF(!switch_strlen_zero(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), SOATAG_ADDRESS(tech_pvt->adv_sdp_audio_ip), SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_REUSE_REJECTED(1), @@ -1761,12 +1854,20 @@ void sofia_glue_deactivate_rtp(private_object_t *tech_pvt) switch_rtp_release_port(tech_pvt->profile->rtpip, tech_pvt->local_sdp_audio_port); } + if (tech_pvt->local_sdp_audio_port > 0 && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { + switch_nat_del_mapping((switch_port_t)tech_pvt->local_sdp_audio_port, SWITCH_NAT_UDP); + } + if (tech_pvt->video_rtp_session) { switch_rtp_destroy(&tech_pvt->video_rtp_session); } else if (tech_pvt->local_sdp_video_port) { switch_rtp_release_port(tech_pvt->profile->rtpip, tech_pvt->local_sdp_video_port); } + + if (tech_pvt->local_sdp_video_port > 0 && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { + switch_nat_del_mapping((switch_port_t)tech_pvt->local_sdp_video_port, SWITCH_NAT_UDP); + } } switch_status_t sofia_glue_tech_set_video_codec(private_object_t *tech_pvt, int force) @@ -2480,7 +2581,7 @@ void sofia_glue_set_r_sdp_codec_string(switch_channel_t *channel,const char *cod if (map->rm_pt < 96) { match = (map->rm_pt == imp->ianacode) ? 1 : 0; } else { - if(map->rm_encoding) { + if (map->rm_encoding) { match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1; } else { match = 0; @@ -2488,7 +2589,7 @@ void sofia_glue_set_r_sdp_codec_string(switch_channel_t *channel,const char *cod } if (match) { - if(ptime > 0) { + if (ptime > 0) { switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%di", imp->iananame, (unsigned int) map->rm_rate, ptime); } else { switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh", imp->iananame, (unsigned int) map->rm_rate); @@ -3487,7 +3588,8 @@ int sofia_glue_init_sql(sofia_profile_t *profile) " aor VARCHAR(255),\n" " profile_name VARCHAR(255),\n" " hostname VARCHAR(255),\n" - " contact_str VARCHAR(255)\n" + " contact_str VARCHAR(255),\n" + " network_ip VARCHAR(255)\n" ");\n"; char shared_appearance_dialogs_sql[] = @@ -3958,7 +4060,10 @@ int sofia_glue_get_user_host(char *in, char **user, char **host) { char *p, *h, *u = in; - *user = NULL; + if (user) { + *user = NULL; + } + *host = NULL; /* First isolate the host part from the user part */ @@ -3969,7 +4074,7 @@ int sofia_glue_get_user_host(char *in, char **user, char **host) } /* Clean out the user part of its protocol prefix (if any) */ - if ((p = strchr(u, ':'))) { + if (user && (p = strchr(u, ':'))) { *p++ = '\0'; u = p; } @@ -3987,7 +4092,10 @@ int sofia_glue_get_user_host(char *in, char **user, char **host) *p = '\0'; } + if (user) { *user = u; + } + *host = h; return 1; diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 92414688b9..c26b23268c 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -375,11 +375,11 @@ static void actual_sofia_presence_mwi_event_handler(switch_event_t *event) } if (for_everyone) { - sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,'%q' " + sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,network_ip,'%q' " "from sip_registrations where sip_user='%q' and sip_host='%q'", stream.data, user, host); } else if (call_id) { - sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,'%q' " + sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,network_ip,'%q' " "from sip_registrations where sip_user='%q' and sip_host='%q' and call_id='%q'", stream.data, user, host, call_id); } @@ -1401,13 +1401,14 @@ static int sofia_presence_mwi_callback2(void *pArg, int argc, char **argv, char char *event = "message-summary"; char *contact, *o_contact = argv[2]; char *profile_name = argv[3]; - char *body = argv[4]; + char *network_ip = argv[4]; + char *body = argv[5]; char *id = NULL; nua_handle_t *nh; struct mwi_helper *h = (struct mwi_helper *) pArg; sofia_profile_t *ext_profile = NULL, *profile = h->profile; - char *route = NULL, *route_uri = NULL; - char *p; + char *route = NULL, *route_uri = NULL, *user_via = NULL; + char *p, *contact_str; if (profile_name && strcasecmp(profile_name, h->profile->name)) { if ((ext_profile = sofia_glue_find_profile(profile_name))) { @@ -1415,9 +1416,41 @@ static int sofia_presence_mwi_callback2(void *pArg, int argc, char **argv, char } } - id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host); - contact = sofia_glue_get_url_from_contact(o_contact, 1); + + if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) && profile->local_network && + !switch_check_network_list_ip(network_ip, profile->local_network)) { + char *ptr = NULL; + const char *transport_str = NULL; + + id = switch_mprintf("sip:%s@%s", sub_to_user, profile->extsipip); + + if ((ptr = sofia_glue_find_parameter(o_contact, "transport="))) { + sofia_transport_t transport = sofia_glue_str2transport(ptr); + transport_str = sofia_glue_transport2str(transport); + + switch (transport) { + case SOFIA_TRANSPORT_TCP: + contact_str = profile->tcp_public_contact; + break; + case SOFIA_TRANSPORT_TCP_TLS: + contact_str = profile->tls_public_contact; + break; + default: + contact_str = profile->public_url; + break; + } + user_via = sofia_glue_create_external_via(NULL, profile, transport); + } else { + user_via = sofia_glue_create_external_via(NULL, profile, SOFIA_TRANSPORT_UDP); + contact_str = profile->public_url; + } + + } else { + contact_str = profile->url; + id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host); + } + if ((route = strstr(contact, ";fs_path=")) && (route = strdup(route + 9))) { for (p = route; p && *p ; p++) { @@ -1455,17 +1488,24 @@ static int sofia_presence_mwi_callback2(void *pArg, int argc, char **argv, char } } - nh = nua_handle(profile->nua, NULL, NUTAG_URL(contact), SIPTAG_FROM_STR(id), SIPTAG_TO_STR(id), SIPTAG_CONTACT_STR(h->profile->url), TAG_END()); + nh = nua_handle(profile->nua, NULL, NUTAG_URL(contact), + SIPTAG_FROM_STR(id), SIPTAG_TO_STR(id), + SIPTAG_CONTACT_STR(contact_str), TAG_END()); nua_handle_bind(nh, &mod_sofia_globals.destroy_private); nua_notify(nh, NUTAG_NEWSUB(1), TAG_IF(route_uri, NUTAG_PROXY(route_uri)), - SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"), SIPTAG_PAYLOAD_STR(body), TAG_END()); + TAG_IF(user_via, SIPTAG_VIA_STR(user_via)), + SIPTAG_EVENT_STR(event), + SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"), + SIPTAG_PAYLOAD_STR(body), TAG_END()); switch_safe_free(contact); switch_safe_free(id); switch_safe_free(route); + switch_safe_free(user_via); + if (ext_profile) { sofia_glue_release_profile(ext_profile); } @@ -1501,13 +1541,13 @@ void sofia_presence_handle_sip_i_subscribe(int status, switch_event_t *sevent; int sub_state; int sent_reply = 0; - su_addrinfo_t *my_addrinfo = msg_addrinfo(nua_current_request(nua)); int network_port = 0; char network_ip[80]; const char *contact_host, *contact_user; char *port; char new_port[25] = ""; char *is_nat = NULL; + int is_auto_nat = 0; const char *ipv6; if (!(contact && sip->sip_contact->m_url)) { @@ -1515,8 +1555,12 @@ void sofia_presence_handle_sip_i_subscribe(int status, return; } - get_addr(network_ip, sizeof(network_ip), my_addrinfo->ai_addr, my_addrinfo->ai_addrlen); - network_port = ntohs(((struct sockaddr_in *) msg_addrinfo(nua_current_request(nua))->ai_addr)->sin_port); + sofia_glue_get_addr(nua_current_request(nua), network_ip, sizeof(network_ip), &network_port); + + if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) && profile->local_network && + !switch_check_network_list_ip(network_ip, profile->local_network)) { + is_auto_nat = 1; + } tl_gets(tags, NUTAG_SUBSTATE_REF(sub_state), TAG_END()); @@ -1777,19 +1821,35 @@ void sofia_presence_handle_sip_i_subscribe(int status, network_port, params); } - - if (switch_stristr("port=tcp", contact->m_url->url_params)) { - contactstr = profile->tcp_contact; - } else if (switch_stristr("port=tls", contact->m_url->url_params)) { - contactstr = profile->tls_contact; + + if (is_auto_nat) { + contactstr = profile->public_url; + } else { + contactstr = profile->url; } + if (switch_stristr("port=tcp", contact->m_url->url_params)) { + if (is_auto_nat) { + contactstr = profile->tcp_public_contact; + } else { + contactstr = profile->tcp_contact; + } + } else if (switch_stristr("port=tls", contact->m_url->url_params)) { + if (is_auto_nat) { + contactstr = profile->tls_contact; + } else { + contactstr = profile->tls_public_contact; + } + } + if (nh && nh->nh_ds && nh->nh_ds->ds_usage) { nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, exp_delta + SUB_OVERLAP, exp_delta + SUB_OVERLAP); } - nua_respond(nh, SIP_202_ACCEPTED, SIPTAG_CONTACT_STR(contactstr), NUTAG_WITH_THIS(nua), + nua_respond(nh, SIP_202_ACCEPTED, + SIPTAG_CONTACT_STR(contactstr), + NUTAG_WITH_THIS(nua), SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EXPIRES_STR(exp_delta_str), TAG_IF(sticky, NUTAG_PROXY(sticky)), TAG_END()); diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index d9c721368f..ce598c9f86 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -402,11 +402,13 @@ int sofia_sub_del_callback(void *pArg, int argc, char **argv, char **columnNames return 0; } -void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const char *host, const char *contact, const char *user_agent) +void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const char *host, const char *contact, const char *user_agent, const char *network_ip) { const char *event = "check-sync"; nua_handle_t *nh; char *contact_url = NULL; + char *contact_str = NULL; + char *user_via = NULL; char *id = NULL; if (switch_stristr("snom", user_agent)) { @@ -417,22 +419,52 @@ void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const cha if ((contact_url = sofia_glue_get_url_from_contact((char *)contact, 1))) { char *p; - id = switch_mprintf("sip:%s@%s", user, host); + id = switch_mprintf("sip:%s@%s", user, network_ip); if ((p = strstr(contact_url, ";fs_"))) { *p = '\0'; } + if (sofia_glue_check_nat(profile, network_ip)) { + char *ptr = NULL; + const char *transport_str = NULL; + + if ((ptr = sofia_glue_find_parameter(contact_url, "transport="))) { + sofia_transport_t transport = sofia_glue_str2transport(ptr); + transport_str = sofia_glue_transport2str(transport); + + switch (transport) { + case SOFIA_TRANSPORT_TCP: + contact_str = profile->tcp_public_contact; + break; + case SOFIA_TRANSPORT_TCP_TLS: + contact_str = profile->tls_public_contact; + break; + default: + contact_str = profile->public_url; + break; + } + + user_via = sofia_glue_create_external_via(NULL, profile, transport); + } else { + user_via = sofia_glue_create_external_via(NULL, profile, SOFIA_TRANSPORT_UDP); + contact_str = profile->public_url; + } + } else { + contact_str = profile->url; + } + nh = nua_handle(profile->nua, NULL, NUTAG_URL(contact_url), SIPTAG_FROM_STR(id), SIPTAG_TO_STR(id), - SIPTAG_CONTACT_STR(profile->url), + SIPTAG_CONTACT_STR(contact_str), TAG_END()); nua_handle_bind(nh, &mod_sofia_globals.destroy_private); nua_notify(nh, NUTAG_NEWSUB(1), + TAG_IF(user_via, SIPTAG_VIA_STR(user_via)), SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"), SIPTAG_PAYLOAD_STR(""), @@ -442,6 +474,7 @@ void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const cha free(contact_url); } + switch_safe_free(user_via); switch_safe_free(id); } @@ -462,8 +495,8 @@ int sofia_reg_del_callback(void *pArg, int argc, char **argv, char **columnNames switch_event_t *s_event; sofia_profile_t *profile = (sofia_profile_t *) pArg; - if (argc > 11 && atoi(argv[11]) == 1) { - sofia_reg_send_reboot(profile, argv[1], argv[2], argv[3], argv[7]); + if (argc > 12 && atoi(argv[12]) == 1) { + sofia_reg_send_reboot(profile, argv[1], argv[2], argv[3], argv[7], argv[11]); } if (argc >= 3) { @@ -508,7 +541,8 @@ void sofia_reg_expire_call_id(sofia_profile_t *profile, const char *call_id, int switch_snprintf(sqlextra, sizeof(sqlextra), " or (sip_user='%s' and sip_host='%s')", user, host); } - switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,expires,user_agent,server_user,server_host,profile_name" + switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,expires" + ",user_agent,server_user,server_host,profile_name,network_ip" ",%d from sip_registrations where call_id='%s' %s", reboot, call_id, sqlextra); @@ -548,10 +582,12 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot) switch_mutex_lock(profile->ireg_mutex); if (now) { - switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,expires,user_agent,server_user,server_host,profile_name" + switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,expires" + ",user_agent,server_user,server_host,profile_name,network_ip" ",%d from sip_registrations where expires > 0 and expires <= %ld", reboot, (long) now); } else { - switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,expires,user_agent,server_user,server_host,profile_name" + switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,expires" + ",user_agent,server_user,server_host,profile_name,network_ip" ",%d from sip_registrations where expires > 0", reboot); } @@ -725,19 +761,17 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand char *force_user; char received_data[128] = ""; char *path_val = NULL; - su_addrinfo_t *my_addrinfo = msg_addrinfo(nua_current_request(nua)); switch_event_t *auth_params = NULL; int r = 0; /* all callers must confirm that sip, sip->sip_request and sip->sip_contact are not NULL */ switch_assert(sip != NULL && sip->sip_contact != NULL && sip->sip_request != NULL); - get_addr(network_ip, sizeof(network_ip), my_addrinfo->ai_addr,my_addrinfo->ai_addrlen); - network_port = get_port(my_addrinfo->ai_addr); + sofia_glue_get_addr(nua_current_request(nua), network_ip, sizeof(network_ip), &network_port); snprintf(network_port_c, sizeof(network_port_c), "%d", network_port); - snprintf(url_ip, sizeof(url_ip), my_addrinfo->ai_addr->sa_family == AF_INET6 ? "[%s]" : "%s", network_ip); + snprintf(url_ip, sizeof(url_ip), (msg_addrinfo(nua_current_request(nua)))->ai_addr->sa_family == AF_INET6 ? "[%s]" : "%s", network_ip); expires = sip->sip_expires; authorization = sip->sip_authorization; @@ -1249,15 +1283,11 @@ void sofia_reg_handle_sip_i_register(nua_t *nua, sofia_profile_t *profile, nua_h char key[128] = ""; switch_event_t *v_event = NULL; char network_ip[80]; - su_addrinfo_t *my_addrinfo = msg_addrinfo(nua_current_request(nua)); sofia_regtype_t type = REG_REGISTER; int network_port = 0; char *is_nat = NULL; - - get_addr(network_ip, sizeof(network_ip), my_addrinfo->ai_addr, my_addrinfo->ai_addrlen); - network_port = get_port(msg_addrinfo(nua_current_request(nua))->ai_addr); - + sofia_glue_get_addr(nua_current_request(nua), network_ip, sizeof(network_ip), &network_port); if (!(sip->sip_contact && sip->sip_contact->m_url)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n"); diff --git a/src/mod/endpoints/mod_sofia/sofia_sla.c b/src/mod/endpoints/mod_sofia/sofia_sla.c index 66c4553922..c389883113 100644 --- a/src/mod/endpoints/mod_sofia/sofia_sla.c +++ b/src/mod/endpoints/mod_sofia/sofia_sla.c @@ -76,6 +76,10 @@ void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const struct sla_helper sh = { { 0 } }; char *contact_str = strip_uri(full_contact); sofia_transport_t transport = sofia_glue_url2transport(sip->sip_contact->m_url); + char network_ip[80]; + int network_port = 0; + + sofia_glue_get_addr(nua_current_request(nua), network_ip, sizeof(network_ip), &network_port); sql = switch_mprintf("select call_id from sip_shared_appearance_dialogs where hostname='%q' and profile_name='%q' and contact_str='%q'", mod_sofia_globals.hostname, profile->name, contact_str); @@ -99,8 +103,13 @@ void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const nua_handle_bind(nh, &mod_sofia_globals.keep_private); switch_snprintf(exp_str, sizeof(exp_str), "%ld", exptime + 30); - switch_snprintf(my_contact, sizeof(my_contact), "<%s;transport=%s>;expires=%s", profile->sla_contact, sofia_glue_transport2str(transport), exp_str); - + if (sofia_glue_check_nat(profile, network_ip)) { + switch_snprintf(my_contact, sizeof(my_contact), ";expires=%s", profile->sla_contact, + profile->extsipip, sofia_glue_transport2str(transport), exp_str); + } else { + switch_snprintf(my_contact, sizeof(my_contact), ";expires=%s", profile->sla_contact, + profile->sipip, sofia_glue_transport2str(transport), exp_str); + } nua_subscribe(nh, SIPTAG_TO(sip->sip_to), SIPTAG_FROM(sip->sip_to), @@ -125,8 +134,11 @@ void sofia_sla_handle_sip_i_subscribe(nua_t *nua, const char *contact_str, sofia char *sql = NULL; char *route_uri = NULL; char *sla_contact = NULL; + char network_ip[80]; + int network_port = 0; sofia_transport_t transport = sofia_glue_url2transport(sip->sip_contact->m_url); + sofia_glue_get_addr(nua_current_request(nua), network_ip, sizeof(network_ip), &network_port); /* * XXX MTK FIXME - we don't look at the tag to see if NUTAG_SUBSTATE(nua_substate_terminated) or * a Subscription-State header with state "terminated" and/or expiration of 0. So we never forget @@ -141,8 +153,9 @@ void sofia_sla_handle_sip_i_subscribe(nua_t *nua, const char *contact_str, sofia * so we do what openser's pua_bla does and... */ + /* We always store the AOR as the sipip and not the request so SLA works with NAT inside out */ aor = switch_mprintf("sip:%s@%s;transport=%s", sip->sip_contact->m_url->url_user, - sip->sip_from->a_url->url_host, sofia_glue_transport2str(transport)); + profile->sipip, sofia_glue_transport2str(transport)); /* * ok, and now that we HAVE the AOR, we REALLY should go check in the XML config and see if this particular @@ -163,9 +176,9 @@ void sofia_sla_handle_sip_i_subscribe(nua_t *nua, const char *contact_str, sofia } if ((sql = - switch_mprintf("insert into sip_shared_appearance_subscriptions (subscriber, call_id, aor, profile_name, hostname, contact_str) " - "values ('%q','%q','%q','%q','%q','%q')", - subscriber, sip->sip_call_id->i_id, aor, profile->name, mod_sofia_globals.hostname, contact_str))) { + switch_mprintf("insert into sip_shared_appearance_subscriptions (subscriber, call_id, aor, profile_name, hostname, contact_str, network_ip) " + "values ('%q','%q','%q','%q','%q','%q','%q')", + subscriber, sip->sip_call_id->i_id, aor, profile->name, mod_sofia_globals.hostname, contact_str, network_ip))) { sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); } @@ -187,8 +200,11 @@ void sofia_sla_handle_sip_i_subscribe(nua_t *nua, const char *contact_str, sofia *p++ = '\0'; } } - - sla_contact = switch_mprintf("<%s;transport=%s>", profile->sla_contact, sofia_glue_transport2str(transport)); + if (sofia_glue_check_nat(profile, network_ip)) { + sla_contact = switch_mprintf("", profile->sla_contact, profile->extsipip, sofia_glue_transport2str(transport)); + } else { + sla_contact = switch_mprintf("", profile->sla_contact, profile->sipip, sofia_glue_transport2str(transport)); + } nua_respond(nh, SIP_202_ACCEPTED, SIPTAG_CONTACT_STR(sla_contact), NUTAG_WITH_THIS(nua), TAG_IF(route_uri, NUTAG_PROXY(route_uri)), @@ -276,8 +292,9 @@ void sofia_sla_handle_sip_i_notify(nua_t *nua, sofia_profile_t *profile, nua_han } /* calculate the AOR we're trying to tell people about. should probably double-check before derferencing XXX MTK */ + /* We always store the AOR as the sipip and not the request so SLA works with NAT inside out */ aor = switch_mprintf("sip:%s@%s;transport=%s", sip->sip_to->a_url->url_user, - sip->sip_to->a_url->url_host, sofia_glue_transport2str(transport)); + profile->sipip, sofia_glue_transport2str(transport)); /* this isn't sufficient because on things like the polycom, the subscriber is the 'main' ext number, but the * 'main' ext number isn't in ANY of the headers they send us in the notify. of course. @@ -290,10 +307,9 @@ void sofia_sla_handle_sip_i_notify(nua_t *nua, sofia_profile_t *profile, nua_han sip->sip_contact->m_url->url_host, sofia_glue_transport2str(transport)); if (sip->sip_payload && sip->sip_payload->pl_data) { - sql = switch_mprintf("select subscriber,call_id,aor,profile_name,hostname,contact_str from sip_shared_appearance_subscriptions where " - "aor='%q' and subscriber<>'%q' and profile_name='%q' and hostname='%q'", - aor, contact, profile->name, mod_sofia_globals.hostname); - + sql = switch_mprintf("select subscriber,call_id,aor,profile_name,hostname,contact_str,network_ip from sip_shared_appearance_subscriptions where " + "aor='%q' and profile_name='%q' and hostname='%q'", + aor, profile->name, mod_sofia_globals.hostname); helper.profile = profile; helper.payload = sip->sip_payload->pl_data; /* could just send the WHOLE payload. you'd get the type that way. */ @@ -316,10 +332,11 @@ static int sofia_sla_sub_callback(void *pArg, int argc, char **argv, char **colu /* char *profile_name = argv[3]; */ /* char *hostname = argv[4]; */ char *contact_str = argv[5]; + char *network_ip = argv[6]; nua_handle_t *nh; char *route_uri = NULL; - - + char *xml_fixup = NULL; + char *fixup = NULL; nh = nua_handle_by_call_id(helper->profile->nua, call_id); /* that's all you need to find the subscription's nh */ if (nh) { @@ -343,13 +360,27 @@ static int sofia_sla_sub_callback(void *pArg, int argc, char **argv, char **colu } } + if (sofia_test_pflag(helper->profile, PFLAG_AUTO_NAT)) { + if (sofia_glue_check_nat(helper->profile, network_ip)) { + fixup = switch_string_replace(helper->payload, helper->profile->sipip, helper->profile->extsipip); + } else { + fixup = switch_string_replace(helper->payload, helper->profile->extsipip, helper->profile->sipip); + } + xml_fixup = fixup; + } else { + xml_fixup = helper->payload; + } + nua_notify(nh, SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=300"), /* XXX MTK FIXME - this is totally fake calculation */ TAG_IF(route_uri, NUTAG_PROXY(route_uri)), SIPTAG_CONTENT_TYPE_STR("application/dialog-info+xml"), /* could've just kept the type from the payload */ - SIPTAG_PAYLOAD_STR(helper->payload), + SIPTAG_PAYLOAD_STR(xml_fixup), TAG_END()); switch_safe_free(route_uri); + if (fixup && fixup != helper->payload) { + free(fixup); + } } return 0; }