diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index df413013dc..de06c17c9c 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -556,7 +556,7 @@ int sofia_glue_get_user_host(char *in, char **user, char **host); switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status); void sofia_glue_do_xfer_invite(switch_core_session_t *session); uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, - sofia_regtype_t regtype, char *key, uint32_t keylen, switch_event_t **v_event); + sofia_regtype_t regtype, char *key, uint32_t keylen, switch_event_t **v_event, const char *is_nat); extern switch_endpoint_interface_t *sofia_endpoint_interface; void sofia_presence_set_chat_hash(private_object_t *tech_pvt, sip_t const *sip); switch_status_t sofia_on_hangup(switch_core_session_t *session); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index f5b7359906..9c1655f8fa 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -2670,7 +2670,9 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ const char *port = sip->sip_via->v_port; const char *host = sip->sip_via->v_host; - if (host && strcmp(network_ip, host)) { + if (host && sip->sip_via->v_received) { + is_nat = "via received"; + } else if (host && strcmp(network_ip, host)) { is_nat = "via host"; } else if (port && atoi(port) != network_port) { is_nat = "via port"; @@ -2737,7 +2739,7 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ if (!strcmp(network_ip, profile->sipip) && network_port == profile->sip_port) { calling_myself++; } else { - if (sofia_reg_handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key), &v_event)) { + if (sofia_reg_handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key), &v_event, NULL)) { if (v_event) { switch_event_destroy(&v_event); } diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index d414ded6d8..8c5727ef3d 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -1136,7 +1136,7 @@ static int sofia_presence_mwi_callback2(void *pArg, int argc, char **argv, char char *sub_to_user = argv[0]; char *sub_to_host = argv[1]; char *event = "message-summary"; - char *contact = argv[2]; + char *contact, *o_contact = argv[2]; char *body = argv[3]; char *id = NULL; nua_handle_t *nh; @@ -1145,7 +1145,7 @@ 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(contact, 0); + contact = sofia_glue_get_url_from_contact(o_contact, 1); nh = nua_handle(h->profile->nua, NULL, NUTAG_URL(contact), @@ -1156,8 +1156,10 @@ static int sofia_presence_mwi_callback2(void *pArg, int argc, char **argv, char nua_notify(nh, NUTAG_NEWSUB(1), + TAG_IF(strstr(o_contact, ";nat"), NUTAG_PROXY(contact)), 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); return 0; @@ -1189,40 +1191,97 @@ 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; + + if (!(contact && sip->sip_contact->m_url)) { + nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END()); + return; + } + + get_addr(network_ip, sizeof(network_ip), &((struct sockaddr_in *) my_addrinfo->ai_addr)->sin_addr); + network_port = ntohs(((struct sockaddr_in *) msg_addrinfo(nua_current_request(nua))->ai_addr)->sin_port); tl_gets(tags, NUTAG_SUBSTATE_REF(sub_state), TAG_END()); event = sip_header_as_string(profile->home, (void *) sip->sip_event); - if (contact) { - char *port = (char *) contact->m_url->url_port; - char new_port[25] = ""; - - display = contact->m_display; - - if (switch_strlen_zero(display)) { - if (from) { - display = from->a_display; - if (switch_strlen_zero(display)) { - display = "\"user\""; - } - } - } else { - display = "\"user\""; - } - - if (port) { - switch_snprintf(new_port, sizeof(new_port), ":%s", port); - } + port = (char *) contact->m_url->url_port; + contact_host = sip->sip_contact->m_url->url_host; + contact_user = sip->sip_contact->m_url->url_user; - if (contact->m_url->url_params) { - contact_str = switch_mprintf("%s ", - display, contact->m_url->url_user, contact->m_url->url_host, new_port, contact->m_url->url_params); - } else { - contact_str = switch_mprintf("%s ", display, contact->m_url->url_user, contact->m_url->url_host, new_port); + display = contact->m_display; + + if (switch_strlen_zero(display)) { + if (from) { + display = from->a_display; + if (switch_strlen_zero(display)) { + display = "\"user\""; + } + } + } else { + display = "\"user\""; + } + + if ((profile->pflags & PFLAG_AGGRESSIVE_NAT_DETECTION)) { + if (sip && sip->sip_via) { + const char *port = sip->sip_via->v_port; + const char *host = sip->sip_via->v_host; + + if (host && sip->sip_via->v_received) { + is_nat = "via received"; + } else if (host && strcmp(network_ip, host)) { + is_nat = "via host"; + } else if (port && atoi(port) != network_port) { + is_nat = "via port"; + } } } + + if (!is_nat && profile->nat_acl_count) { + uint32_t x = 0; + int ok = 1; + char *last_acl = NULL; + + if (!switch_strlen_zero(contact_host)) { + for (x = 0 ; x < profile->nat_acl_count; x++) { + last_acl = profile->nat_acl[x]; + if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) { + break; + } + } + + if (ok) { + is_nat = last_acl; + } + } + } + + + if (is_nat) { + contact_host = network_ip; + switch_snprintf(new_port, sizeof(new_port), ":%d", network_port); + port = NULL; + } + + + if (port) { + switch_snprintf(new_port, sizeof(new_port), ":%s", port); + } + + if (contact->m_url->url_params) { + contact_str = switch_mprintf("%s %s", + display, contact->m_url->url_user, contact_host, new_port, contact->m_url->url_params, is_nat ? ";nat" : ""); + } else { + contact_str = switch_mprintf("%s %s", display, contact->m_url->url_user, contact_host, new_port, is_nat ? ";nat" : ""); + } + if (to) { to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host); //, to->a_url->url_port); @@ -1336,14 +1395,25 @@ void sofia_presence_handle_sip_i_subscribe(int status, switch_mutex_unlock(profile->ireg_mutex); + if (status < 200) { - nua_respond(nh, SIP_202_ACCEPTED, + char *sticky = NULL; + + if (is_nat) { + sticky = switch_mprintf("sip:%s@%s:%d", contact_user, network_ip, network_port); + } + + nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS(nua), SIPTAG_SUBSCRIPTION_STATE_STR(sstr), + TAG_IF(sticky, NUTAG_PROXY(sticky)), //SIPTAG_FROM(sip->sip_to), //SIPTAG_TO(sip->sip_from), //SIPTAG_CONTACT_STR(contact_str), TAG_END()); + + switch_safe_free(sticky); + } sent_reply++; diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index cf38438fda..1db26a16d0 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -333,7 +333,7 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now) if (now) { - switch_snprintf(sql, sizeof(sql), "select * from sip_registrations where status like '%%NATHACK%%'"); + switch_snprintf(sql, sizeof(sql), "select * from sip_registrations where status like '%%AUTO-NAT%%'"); sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, @@ -414,7 +414,7 @@ void sofia_reg_auth_challange(nua_t *nua, sofia_profile_t *profile, nua_handle_t } uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t *profile, nua_handle_t * nh, sip_t const *sip, sofia_regtype_t regtype, char *key, - uint32_t keylen, switch_event_t **v_event) + uint32_t keylen, switch_event_t **v_event, const char *is_nat) { sip_to_t const *to = NULL; sip_expires_t const *expires = NULL; @@ -466,7 +466,15 @@ uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t *profile, nua_han const char *port = contact->m_url->url_port; char new_port[25] = ""; display = contact->m_display; - + const char *contact_host = contact->m_url->url_host; + + if (is_nat) { + reg_desc = "Registered(AUTO-NAT)"; + contact_host = network_ip; + switch_snprintf(new_port, sizeof(new_port), ":%d", network_port); + port = NULL; + } + if (switch_strlen_zero(display)) { if (to) { display = to->a_display; @@ -481,10 +489,10 @@ uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t *profile, nua_han } if (contact->m_url->url_params) { - switch_snprintf(contact_str, sizeof(contact_str), "%s ", - display, contact->m_url->url_user, contact->m_url->url_host, new_port, contact->m_url->url_params); + switch_snprintf(contact_str, sizeof(contact_str), "%s %s", + display, contact->m_url->url_user, contact_host, new_port, contact->m_url->url_params, is_nat ? ";nat" : ""); } else { - switch_snprintf(contact_str, sizeof(contact_str), "%s ", display, contact->m_url->url_user, contact->m_url->url_host, new_port); + switch_snprintf(contact_str, sizeof(contact_str), "%s %s", display, contact->m_url->url_user, contact_host, new_port, is_nat ? ";nat" : ""); } } @@ -537,7 +545,7 @@ uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t *profile, nua_han if (strstr(v_contact_str, "tls")) { reg_desc = "Registered(TLSHACK)"; } else { - reg_desc = "Registered(NATHACK)"; + reg_desc = "Registered(AUTO-NAT)"; exptime = 20; } nat_hack = 1; @@ -609,8 +617,6 @@ uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t *profile, nua_han sql = switch_mprintf("insert into sip_registrations values ('%q', '%q','%q','%q','%q', '%q', %ld, '%q')", call_id, to_user, to_host, contact_str, reg_desc, rpid, (long) switch_timestamp(NULL) + (long) exptime * 2, agent); - - if (sql) { sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); } @@ -747,6 +753,7 @@ void sofia_reg_handle_sip_i_register(nua_t * nua, sofia_profile_t *profile, nua_ 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), &((struct sockaddr_in *) my_addrinfo->ai_addr)->sin_addr); network_port = ntohs(((struct sockaddr_in *) msg_addrinfo(nua_current_request(nua))->ai_addr)->sin_port); @@ -765,6 +772,45 @@ void sofia_reg_handle_sip_i_register(nua_t * nua, sofia_profile_t *profile, nua_ goto end; } + if ((profile->pflags & PFLAG_AGGRESSIVE_NAT_DETECTION)) { + if (sip && sip->sip_via) { + const char *port = sip->sip_via->v_port; + const char *host = sip->sip_via->v_host; + + if (host && sip->sip_via->v_received) { + is_nat = "via received"; + } else if (host && strcmp(network_ip, host)) { + is_nat = "via host"; + } else if (port && atoi(port) != network_port) { + is_nat = "via port"; + } + } + } + + if (!is_nat && profile->nat_acl_count) { + uint32_t x = 0; + int ok = 1; + char *last_acl = NULL; + const char *contact_host = NULL; + + if (sip && sip->sip_contact && sip->sip_contact->m_url) { + contact_host = sip->sip_contact->m_url->url_host; + } + + if (!switch_strlen_zero(contact_host)) { + for (x = 0 ; x < profile->nat_acl_count; x++) { + last_acl = profile->nat_acl[x]; + if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) { + break; + } + } + + if (ok) { + is_nat = last_acl; + } + } + } + if (profile->reg_acl_count) { uint32_t x = 0; int ok = 1; @@ -796,7 +842,7 @@ void sofia_reg_handle_sip_i_register(nua_t * nua, sofia_profile_t *profile, nua_ goto end; } - sofia_reg_handle_register(nua, profile, nh, sip, type, key, sizeof(key), &v_event); + sofia_reg_handle_register(nua, profile, nh, sip, type, key, sizeof(key), &v_event, is_nat); if (v_event) { switch_event_fire(&v_event);