[asterisk-commits] file: branch file/pimp_sip_nat r381845 - in /team/file/pimp_sip_nat: include/...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Feb 21 08:37:49 CST 2013
Author: file
Date: Thu Feb 21 08:37:45 2013
New Revision: 381845
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=381845
Log:
Add support for specifying localnet and external signaling address information on a per-transport basis.
This also adds support for specifying a media address on a per-endpoint basis.
Modified:
team/file/pimp_sip_nat/include/asterisk/res_sip.h
team/file/pimp_sip_nat/res/res_sip/config_transport.c
team/file/pimp_sip_nat/res/res_sip/sip_configuration.c
team/file/pimp_sip_nat/res/res_sip_nat.c
team/file/pimp_sip_nat/res/res_sip_sdp_audio.c
Modified: team/file/pimp_sip_nat/include/asterisk/res_sip.h
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/include/asterisk/res_sip.h?view=diff&rev=381845&r1=381844&r2=381845
==============================================================================
--- team/file/pimp_sip_nat/include/asterisk/res_sip.h (original)
+++ team/file/pimp_sip_nat/include/asterisk/res_sip.h Thu Feb 21 08:37:45 2013
@@ -28,6 +28,8 @@
#include "asterisk/channel.h"
/* Needed for ast_sorcery */
#include "asterisk/sorcery.h"
+/* Needed for ast_dnsmgr */
+#include "asterisk/dnsmgr.h"
/* Needed for pj_sockaddr */
#include "pjlib.h"
@@ -96,6 +98,8 @@
AST_STRING_FIELD(privkey_file);
/*! Password to open the private key */
AST_STRING_FIELD(password);
+ /*! External signaling address */
+ AST_STRING_FIELD(external_signaling_address);
);
/*! Type of transport */
enum ast_sip_transport_type type;
@@ -103,10 +107,18 @@
pj_sockaddr host;
/*! Number of simultaneous asynchronous operations */
unsigned int async_operations;
+ /*! Optional external port for signaling */
+ unsigned int external_signaling_port;
/*! TLS settings */
pjsip_tls_setting tls;
/*! Configured TLS ciphers */
pj_ssl_cipher ciphers[SIP_TLS_MAX_CIPHERS];
+ /*! Optional local network information, used for NAT purposes */
+ struct ast_ha *localnet;
+ /*! DNS manager for refreshing the external address */
+ struct ast_dnsmgr_entry *external_address_refresher;
+ /*! Optional external address information */
+ struct ast_sockaddr external_address;
/*! Transport state information */
struct ast_sip_transport_state *state;
};
@@ -218,8 +230,10 @@
AST_STRING_FIELD(context);
/*! Name of an explicit transport to use */
AST_STRING_FIELD(transport);
- /*! Musiconhold class to suggest that the other side use when placing on hold */
- AST_STRING_FIELD(mohsuggest);
+ /*! Musiconhold class to suggest that the other side use when placing on hold */
+ AST_STRING_FIELD(mohsuggest);
+ /*! Optional external media address to use in SDP */
+ AST_STRING_FIELD(external_media_address);
);
/*! Identification information for this endpoint */
struct ast_party_id id;
Modified: team/file/pimp_sip_nat/res/res_sip/config_transport.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/res/res_sip/config_transport.c?view=diff&rev=381845&r1=381844&r2=381845
==============================================================================
--- team/file/pimp_sip_nat/res/res_sip/config_transport.c (original)
+++ team/file/pimp_sip_nat/res/res_sip/config_transport.c Thu Feb 21 08:37:45 2013
@@ -26,6 +26,7 @@
#include "asterisk/logger.h"
#include "asterisk/astobj2.h"
#include "asterisk/sorcery.h"
+#include "asterisk/acl.h"
static int destroy_transport_state(void *data)
{
@@ -55,6 +56,11 @@
struct ast_sip_transport *transport = obj;
ast_string_field_free_memory(transport);
+ ast_free_ha(transport->localnet);
+
+ if (transport->external_address_refresher) {
+ ast_dnsmgr_release(transport->external_address_refresher);
+ }
ao2_cleanup(transport->state);
}
@@ -104,6 +110,24 @@
/* Set default port if not present */
if (!pj_sockaddr_get_port(&transport->host)) {
pj_sockaddr_set_port(&transport->host, (transport->type == AST_SIP_TRANSPORT_TLS) ? 5061 : 5060);
+ }
+
+ /* Now that we know what address family we can set up a dnsmgr refresh for the external media address if present */
+ if (!ast_strlen_zero(transport->external_signaling_address)) {
+ if (transport->host.addr.sa_family == pj_AF_INET()) {
+ transport->external_address.ss.ss_family = AF_INET;
+ } else if (transport->host.addr.sa_family == pj_AF_INET6()) {
+ transport->external_address.ss.ss_family = AF_INET6;
+ } else {
+ ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n",
+ ast_sorcery_object_get_id(obj));
+ return -1;
+ }
+
+ if (ast_dnsmgr_lookup(transport->external_signaling_address, &transport->external_address, &transport->external_address_refresher, NULL) < 0) {
+ ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", ast_sorcery_object_get_id(obj));
+ return -1;
+ }
}
/* TODO: Upgrade pjproject so we get IPv6 TCP and TLS */
@@ -235,6 +259,22 @@
}
}
+/*! \brief Custom handler for localnet setting */
+static int transport_localnet_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_transport *transport = obj;
+ struct ast_ha *ha;
+ int error = 0;
+
+ if (!(ha = ast_append_ha("d", var->value, transport->localnet, &error))) {
+ return -1;
+ }
+
+ transport->localnet = ha;
+
+ return error;
+}
+
/*! \brief Initialize sorcery with transport support */
int ast_sip_initialize_sorcery_transport(struct ast_sorcery *sorcery)
{
@@ -252,11 +292,14 @@
ast_sorcery_object_field_register(sorcery, "transport", "cert_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, cert_file));
ast_sorcery_object_field_register(sorcery, "transport", "privkey_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, privkey_file));
ast_sorcery_object_field_register(sorcery, "transport", "password", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, password));
+ ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_signaling_address));
+ ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_port", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, external_signaling_port));
ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_server", "", transport_tls_bool_handler, NULL, 0, 0);
ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_client", "", transport_tls_bool_handler, NULL, 0, 0);
ast_sorcery_object_field_register_custom(sorcery, "transport", "require_client_cert", "", transport_tls_bool_handler, NULL, 0, 0);
ast_sorcery_object_field_register_custom(sorcery, "transport", "method", "", transport_tls_method_handler, NULL, 0, 0);
ast_sorcery_object_field_register_custom(sorcery, "transport", "cipher", "", transport_tls_cipher_handler, NULL, 0, 0);
-
- return 0;
-}
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "localnet", "", transport_localnet_handler, NULL, 0, 0);
+
+ return 0;
+}
Modified: team/file/pimp_sip_nat/res/res_sip/sip_configuration.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/res/res_sip/sip_configuration.c?view=diff&rev=381845&r1=381844&r2=381845
==============================================================================
--- team/file/pimp_sip_nat/res/res_sip/sip_configuration.c (original)
+++ team/file/pimp_sip_nat/res/res_sip/sip_configuration.c Thu Feb 21 08:37:45 2013
@@ -287,6 +287,7 @@
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "timers_min_se", "90", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, min_se));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "timers_sess_expires", "1800", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, sess_expires));
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "auth", "", auth_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "external_media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, external_media_address));
if (ast_sip_initialize_sorcery_transport(sip_sorcery)) {
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
Modified: team/file/pimp_sip_nat/res/res_sip_nat.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/res/res_sip_nat.c?view=diff&rev=381845&r1=381844&r2=381845
==============================================================================
--- team/file/pimp_sip_nat/res/res_sip_nat.c (original)
+++ team/file/pimp_sip_nat/res/res_sip_nat.c Thu Feb 21 08:37:45 2013
@@ -29,6 +29,7 @@
#include "asterisk/res_sip.h"
#include "asterisk/module.h"
+#include "asterisk/acl.h"
static pj_bool_t nat_on_rx_request(pjsip_rx_data *rdata)
{
@@ -46,11 +47,116 @@
return PJ_FALSE;
}
+/*! \brief Structure which contains information about a transport */
+struct request_transport_details {
+ /*! \brief Type of transport */
+ enum ast_sip_transport_type type;
+ /*! \brief Potential pointer to the transport itself, if UDP */
+ pjsip_transport *transport;
+ /*! \brief Potential pointer to the transport factory itself, if TCP/TLS */
+ pjsip_tpfactory *factory;
+ /*! \brief Local address for transport */
+ pj_str_t local_address;
+ /*! \brief Local port for transport */
+ int local_port;
+};
+
+/*! \brief Callback function for finding the transport the request is going out on */
+static int find_transport_in_use(void *obj, void *arg, int flags)
+{
+ struct ast_sip_transport *transport = obj;
+ struct request_transport_details *details = arg;
+
+ /* If an explicit transport or factory matches then this is what is in use, if we are unavailable
+ * to compare based on that we make sure that the type is the same and the source IP address/port are the same
+ */
+ if ((details->transport && details->transport == transport->state->transport) ||
+ (details->factory && details->factory == transport->state->factory) ||
+ ((details->type == transport->type) && (transport->state->factory) &&
+ !pj_strcmp(&transport->state->factory->addr_name.host, &details->local_address) &&
+ transport->state->factory->addr_name.port == details->local_port)) {
+ return CMP_MATCH | CMP_STOP;
+ }
+
+ return 0;
+}
+
+/*! \brief Helper function which returns the SIP URI of a Contact header */
+static pjsip_sip_uri *nat_get_contact_sip_uri(pjsip_tx_data *tdata)
+{
+ pjsip_contact_hdr *contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
+
+ if (!contact || (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
+ return NULL;
+ }
+
+ return pjsip_uri_get_uri(contact->uri);
+}
+
+static pj_status_t nat_on_tx_request(pjsip_tx_data *tdata)
+{
+ RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
+ struct request_transport_details details = { 0, };
+ pjsip_sip_uri *uri = NULL;
+ struct ast_sockaddr addr = { { 0, } };
+
+ /* If a transport selector is in use we know the transport or factory, so explicitly find it */
+ if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) {
+ details.transport = tdata->tp_sel.u.transport;
+ } else if (tdata->tp_sel.type == PJSIP_TPSELECTOR_LISTENER) {
+ details.factory = tdata->tp_sel.u.listener;
+ } else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP || tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
+ /* Connectionless uses the same transport for all requests */
+ details.type = AST_SIP_TRANSPORT_UDP;
+ details.transport = tdata->tp_info.transport;
+ } else {
+ if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TCP) {
+ details.type = AST_SIP_TRANSPORT_TCP;
+ } else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS) {
+ details.type = AST_SIP_TRANSPORT_TLS;
+ } else {
+ /* Unknown transport type, we can't map and thus can't apply NAT changes */
+ return PJ_SUCCESS;
+ }
+
+ if (!(uri = nat_get_contact_sip_uri(tdata))) {
+ return PJ_SUCCESS;
+ }
+
+ details.local_address = uri->host;
+ details.local_port = uri->port;
+ }
+
+ if (!(transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) ||
+ !(transport = ao2_callback(transports, 0, find_transport_in_use, &details)) || !transport->localnet ||
+ ast_sockaddr_isnull(&transport->external_address)) {
+ return PJ_SUCCESS;
+ }
+
+ ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID);
+ ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port);
+
+ /* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */
+ if ((ast_apply_ha(transport->localnet, &addr) != AST_SENSE_ALLOW) || (!uri && !(uri = nat_get_contact_sip_uri(tdata)))) {
+ return PJ_SUCCESS;
+ }
+
+ /* Update the contact header with the external address */
+ pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport->external_address));
+ if (transport->external_signaling_port) {
+ uri->port = transport->external_signaling_port;
+ }
+
+ return PJ_SUCCESS;
+}
+
static pjsip_module nat_module = {
.name = { "NAT", 3 },
.id = -1,
- .priority = PJSIP_MOD_PRIORITY_TSX_LAYER,
+ .priority = PJSIP_MOD_PRIORITY_TRANSPORT_LAYER + 4,
.on_rx_request = nat_on_rx_request,
+ .on_tx_request = nat_on_tx_request,
};
static int load_module(void)
Modified: team/file/pimp_sip_nat/res/res_sip_sdp_audio.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/res/res_sip_sdp_audio.c?view=diff&rev=381845&r1=381844&r2=381845
==============================================================================
--- team/file/pimp_sip_nat/res/res_sip_sdp_audio.c (original)
+++ team/file/pimp_sip_nat/res/res_sip_sdp_audio.c Thu Feb 21 08:37:45 2013
@@ -177,7 +177,8 @@
ast_rtp_instance_get_local_address(session->media[AST_SIP_MEDIA_AUDIO].rtp, &addr);
media->conn->net_type = STR_IN;
media->conn->addr_type = (ast_sockaddr_is_ipv6(&addr) && !ast_sockaddr_is_ipv4_mapped(&addr)) ? STR_IP6 : STR_IP4;
- pj_strdup2(pool, &media->conn->addr, ast_sockaddr_stringify_addr_remote(&addr));
+ pj_strdup2(pool, &media->conn->addr, !ast_sockaddr_is_ipv6(&addr) ? S_OR(session->endpoint->external_media_address, ast_sockaddr_stringify_addr_remote(&addr)) :
+ ast_sockaddr_stringify_addr_remote(&addr));
media->desc.port = (pj_uint16_t) ast_sockaddr_port(&addr);
media->desc.port_count = 1;
@@ -451,7 +452,7 @@
/* Find all of the candidates */
for (attr_i = 0; attr_i < remote_stream->attr_count; ++attr_i) {
- char foundation[32], transport[4], address[46], cand_type[6], relay_address[46] = "";
+ char foundation[32], transport[4], address[PJ_INET6_ADDRSTRLEN + 1], cand_type[6], relay_address[46] = "";
int port, relay_port = 0;
struct ast_rtp_engine_ice_candidate candidate = { 0, };
@@ -464,7 +465,7 @@
ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
- if (sscanf(attr_value, "%31s %30u %3s %30u %23s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport,
+ if (sscanf(attr_value, "%31s %30u %3s %30u %46s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport,
&candidate.priority, address, &port, cand_type, relay_address, &relay_port) < 7) {
/* Candidate did not parse properly */
continue;
@@ -497,6 +498,7 @@
ice->add_remote_candidate(session->media[AST_SIP_MEDIA_AUDIO].rtp, &candidate);
}
+ ice->start(session->media[AST_SIP_MEDIA_AUDIO].rtp);
}
if (session->media[AST_SIP_MEDIA_AUDIO].held && (!ast_sockaddr_isnull(addrs) ||
@@ -509,7 +511,6 @@
/* The remote side has put us on hold */
ast_queue_control_data(session->channel, AST_CONTROL_HOLD, S_OR(session->endpoint->mohsuggest, NULL),
!ast_strlen_zero(session->endpoint->mohsuggest) ? strlen(session->endpoint->mohsuggest) + 1 : 0);
- ast_rtp_instance_stop(session->media[AST_SIP_MEDIA_AUDIO].rtp);
ast_queue_frame(session->channel, &ast_null_frame);
session->media[AST_SIP_MEDIA_AUDIO].held = 1;
} else {
More information about the asterisk-commits
mailing list