diff --git a/src/include/switch_nat.h b/src/include/switch_nat.h index 38bf23c8db..ebcbf2f090 100644 --- a/src/include/switch_nat.h +++ b/src/include/switch_nat.h @@ -59,9 +59,22 @@ typedef enum { \note Generally called by the core_init */ SWITCH_DECLARE(void) switch_nat_init(switch_memory_pool_t *pool); +/*! + \brief Shuts down the NAT Traversal System +*/ SWITCH_DECLARE(void) switch_nat_shutdown(void); -SWITCH_DECLARE(switch_status_t) switch_nat_add_mapping(switch_port_t port, switch_nat_ip_proto_t proto); +/*! + \brief Maps a port through the NAT Traversal System + \param port Internal port to map + \param proto Protocol + \param external_port [out] Mapped external port +*/ +SWITCH_DECLARE(switch_status_t) switch_nat_add_mapping(switch_port_t port, switch_nat_ip_proto_t proto, switch_port_t *external_port); +/*! + \brief Deletes a NAT mapping + \param proto Protocol +*/ SWITCH_DECLARE(switch_status_t) switch_nat_del_mapping(switch_port_t port, switch_nat_ip_proto_t proto); diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 98f3df894f..8288fa6f24 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -49,6 +49,7 @@ SWITCH_STANDARD_API(nat_map_function) int argc; char *mydata = NULL, *argv[4]; switch_nat_ip_proto_t proto = SWITCH_NAT_UDP; + switch_port_t external_port = 0; if (!cmd) { goto error; @@ -70,8 +71,8 @@ SWITCH_STANDARD_API(nat_map_function) } if (argv[0] && switch_stristr("add", argv[0])) { - if (switch_nat_add_mapping((switch_port_t)atoi(argv[1]), proto) == SWITCH_STATUS_SUCCESS) { - stream->write_function(stream, "true"); + if (switch_nat_add_mapping((switch_port_t)atoi(argv[1]), proto, &external_port) == SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "%d", (int)external_port); goto ok; } } else if (argv[0] && switch_stristr("del", argv[0])) { diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index af813ad975..ea895f19c4 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -762,13 +762,13 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void ); if (sofia_test_pflag(profile, PFLAG_AUTO_NAT)) { - if (switch_nat_add_mapping(profile->sip_port, SWITCH_NAT_UDP) == SWITCH_STATUS_SUCCESS) { + if (switch_nat_add_mapping(profile->sip_port, SWITCH_NAT_UDP, NULL) == 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) { + if (switch_nat_add_mapping(profile->sip_port, SWITCH_NAT_TCP, NULL) == 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) { + if(sofia_test_pflag(profile, PFLAG_TLS) && switch_nat_add_mapping(profile->tls_sip_port, SWITCH_NAT_TCP, NULL) == 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); } } diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index a83336304e..993c002919 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -630,6 +630,7 @@ switch_status_t sofia_glue_tech_choose_port(private_object_t *tech_pvt, int forc switch_port_t sdp_port; char tmp[50]; const char *use_ip = NULL; + switch_port_t external_port = 0; if (!force) { if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) || @@ -667,12 +668,12 @@ switch_status_t sofia_glue_tech_choose_port(private_object_t *tech_pvt, int forc 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); + switch_nat_add_mapping((switch_port_t)sdp_port, SWITCH_NAT_UDP, &external_port); } else { tech_pvt->adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, ip); } - tech_pvt->adv_sdp_audio_port = sdp_port; + tech_pvt->adv_sdp_audio_port = external_port != 0 ? external_port : sdp_port; switch_snprintf(tmp, sizeof(tmp), "%d", sdp_port); switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip); @@ -686,6 +687,7 @@ switch_status_t sofia_glue_tech_choose_video_port(private_object_t *tech_pvt, in char *ip = tech_pvt->profile->rtpip; switch_port_t sdp_port; char tmp[50]; + switch_port_t external_port = 0; if (!force) { if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) || switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) @@ -712,11 +714,11 @@ 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_nat_add_mapping((switch_port_t)sdp_port, SWITCH_NAT_UDP, &external_port); } + + tech_pvt->adv_sdp_video_port = external_port != 0 ? external_port : sdp_port; 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); diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c index 7e3bd13d43..f6b0095fc1 100644 --- a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c @@ -2291,7 +2291,7 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_socket_runtime) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Socket up listening on %s:%u\n", prefs.ip, prefs.port); if (prefs.nat_map) { - switch_nat_add_mapping(prefs.port, SWITCH_NAT_TCP); + switch_nat_add_mapping(prefs.port, SWITCH_NAT_TCP, NULL); } break; diff --git a/src/switch_nat.c b/src/switch_nat.c index 68b897e6e0..a59533f36f 100644 --- a/src/switch_nat.c +++ b/src/switch_nat.c @@ -170,7 +170,7 @@ SWITCH_DECLARE(void) switch_nat_init(switch_memory_pool_t *pool) } } -static switch_status_t switch_nat_add_mapping_pmp(switch_port_t port, switch_nat_ip_proto_t proto) +static switch_status_t switch_nat_add_mapping_pmp(switch_port_t port, switch_nat_ip_proto_t proto, switch_port_t *external_port) { switch_status_t status = SWITCH_STATUS_FALSE; natpmpresp_t response; @@ -198,6 +198,16 @@ static switch_status_t switch_nat_add_mapping_pmp(switch_port_t port, switch_nat response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" : (response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" : "UNKNOWN"), response.pnu.newportmapping.privateport); + if (external_port) { + *external_port = response.pnu.newportmapping.mappedpublicport; + } else if (response.pnu.newportmapping.mappedpublicport != response.pnu.newportmapping.privateport) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "External port %hu protocol %s was not available, it was instead mapped to %hu", + response.pnu.newportmapping.privateport, + response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" : + (response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" : "UNKNOWN"), + response.pnu.newportmapping.mappedpublicport); + } + status = SWITCH_STATUS_SUCCESS; } @@ -285,16 +295,20 @@ static switch_status_t switch_nat_del_mapping_upnp(switch_port_t port, switch_na return status; } -SWITCH_DECLARE(switch_status_t) switch_nat_add_mapping(switch_port_t port, switch_nat_ip_proto_t proto) +SWITCH_DECLARE(switch_status_t) switch_nat_add_mapping(switch_port_t port, switch_nat_ip_proto_t proto, switch_port_t *external_port) { switch_status_t status = SWITCH_STATUS_FALSE; switch (nat_globals.nat_type) { case SWITCH_NAT_TYPE_PMP: - status = switch_nat_add_mapping_pmp(port, proto); + status = switch_nat_add_mapping_pmp(port, proto, external_port); break; case SWITCH_NAT_TYPE_UPNP: - status = switch_nat_add_mapping_upnp(port, proto); + if ((status = switch_nat_add_mapping_upnp(port, proto)) && status == SWITCH_STATUS_SUCCESS) { + if (external_port) { + *external_port = port; + } + } break; default: break;