Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 56 additions & 8 deletions src/mod/endpoints/mod_sofia/mod_sofia.c
Original file line number Diff line number Diff line change
Expand Up @@ -1352,6 +1352,53 @@ static switch_status_t sofia_send_dtmf(switch_core_session_t *session, const swi
return SWITCH_STATUS_SUCCESS;
}

/* True when the deflect target already carries a URI scheme or is a name-addr */
static switch_bool_t sofia_deflect_target_is_uri(const char *target)
{
const char *p = target;

if (strchr(target, '<')) {
return SWITCH_TRUE;
}

/* A scheme is a letter followed by letters, digits, '+', '-' or '.', terminated by ':' */
if (!isalpha((unsigned char)*p)) {
return SWITCH_FALSE;
}

for (p++; *p; p++) {
if (*p == ':') {
return SWITCH_TRUE;
}

if (!isalnum((unsigned char)*p) && *p != '+' && *p != '-' && *p != '.') {
break;
}
}

return SWITCH_FALSE;
}

/* Builds the Refer-To for a deflect target; fails for an empty target */
switch_status_t sofia_deflect_build_refer_to(const char *target, const char *sipip, char *buf, switch_size_t buflen)
{
if (zstr(target)) {
return SWITCH_STATUS_FALSE;
}

if (sofia_deflect_target_is_uri(target)) {
switch_copy_string(buf, target, buflen);
} else if (strchr(target, '@')) {
switch_snprintf(buf, buflen, "sip:%s", target);
} else {
const char *format = strchr(sipip, ':') ? "sip:%s@[%s]" : "sip:%s@%s";

switch_snprintf(buf, buflen, format, target, sipip);
}

return SWITCH_STATUS_SUCCESS;
}

static switch_status_t sofia_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
Expand Down Expand Up @@ -1563,19 +1610,20 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi

case SWITCH_MESSAGE_INDICATE_DEFLECT: {

char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX);
char *extra_headers;
char ref_to[1024] = "";
const char *var;
const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);

if (strncasecmp(msg->string_arg, "sip:", 4)) {
const char *format = strchr(tech_pvt->profile->sipip, ':') ? "sip:%s@[%s]" : "sip:%s@%s";
const char *session_id_header;

switch_snprintf(ref_to, sizeof(ref_to), format, msg->string_arg, tech_pvt->profile->sipip);
} else {
switch_set_string(ref_to, msg->string_arg);
if (sofia_deflect_build_refer_to(msg->string_arg, tech_pvt->profile->sipip, ref_to, sizeof(ref_to)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Deflect requires a target\n");
msg->string_reply = "no target";
break;
}

extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX);
session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);

nua_refer(tech_pvt->nh, SIPTAG_REFER_TO_STR(ref_to), SIPTAG_REFERRED_BY_STR(tech_pvt->contact_url),
TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
Expand Down
72 changes: 72 additions & 0 deletions src/mod/endpoints/mod_sofia/test/test_sofia_funcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <test/switch_test.h>

int protect_dest_uri(switch_caller_profile_t *cp);
switch_status_t sofia_deflect_build_refer_to(const char *target, const char *sipip, char *buf, switch_size_t buflen);

static int timeout_sec = 10;
static switch_interval_time_t delay_start_ms = 5000;
Expand Down Expand Up @@ -122,6 +123,77 @@ FST_TEST_BEGIN(originate_test)
}
FST_TEST_END()

FST_TEST_BEGIN(test_sofia_deflect_build_refer_to)
{
char ref_to[1024];
char short_buf[12];
size_t i;
const char *sipip = "203.0.113.5";
/* expect NULL means the target is rejected */
struct {
const char *target;
const char *expect;
} cases[] = {
{ NULL, NULL },
{ "", NULL },
/* a bare user or number is addressed at the profile */
{ "1234", switch_core_sprintf(fst_pool, "sip:1234@%s", sipip) },
{ "+15551234567", switch_core_sprintf(fst_pool, "sip:+15551234567@%s", sipip) },
/* user@host only gains the scheme, including a host port or an IPv6 literal */
{ "bob@example.com", "sip:bob@example.com" },
{ "bob@198.51.100.7:2222", "sip:bob@198.51.100.7:2222" },
{ "bob@[2001:db8::7]", "sip:bob@[2001:db8::7]" },
/* a URI with a scheme goes out as given */
{ "sip:bob@example.com", "sip:bob@example.com" },
{ "sips:bob@example.com", "sips:bob@example.com" },
{ "SIPS:bob@example.com", "SIPS:bob@example.com" },
{ "sip:bob@198.51.100.7:2222", "sip:bob@198.51.100.7:2222" },
{ "tel:+15551234567", "tel:+15551234567" },
{ "urn:service:sos", "urn:service:sos" },
/* a name-addr goes out as given */
{ "<sip:bob@example.com>", "<sip:bob@example.com>" },
{ "<sip:bob@example.com;user=phone>", "<sip:bob@example.com;user=phone>" },
{ "\"Bob\" <sip:bob@example.com>", "\"Bob\" <sip:bob@example.com>" },
{ "<sip:bob@example.com?Replaces=xfer-42%3Bto-tag%3Dt1%3Bfrom-tag%3Df1>", "<sip:bob@example.com?Replaces=xfer-42%3Bto-tag%3Dt1%3Bfrom-tag%3Df1>" },
{ "<sip:bob@example.com>;x-leg=b", "<sip:bob@example.com>;x-leg=b" },
/* Known limitations: a host:port without a user, or a user:password, reads as a scheme or is
* addressed at the profile, and none of these is a valid Refer-To */
{ "pbx.example.com:5060", "pbx.example.com:5060" },
{ "198.51.100.7:5060", switch_core_sprintf(fst_pool, "sip:198.51.100.7:5060@%s", sipip) },
{ "bob:secret@example.com", "bob:secret@example.com" },
};

for (i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
switch_status_t status;

ref_to[0] = '\0';
status = sofia_deflect_build_refer_to(cases[i].target, sipip, ref_to, sizeof(ref_to));

if (!cases[i].expect) {
fst_xcheck(status == SWITCH_STATUS_FALSE, "an empty deflect target must be rejected");
continue;
}

fst_xcheck(status == SWITCH_STATUS_SUCCESS, cases[i].target);
fst_check_string_equals(ref_to, cases[i].expect);
}

/* An IPv6 profile address is bracketed */
sofia_deflect_build_refer_to("1234", "2001:db8:cafe::5", ref_to, sizeof(ref_to));
fst_check_string_equals(ref_to, "sip:1234@[2001:db8:cafe::5]");

/* The result is truncated to buflen on every branch */
sofia_deflect_build_refer_to("1234567", sipip, short_buf, sizeof(short_buf));
fst_check_string_equals(short_buf, "sip:1234567");

sofia_deflect_build_refer_to("bob@example.com", sipip, short_buf, sizeof(short_buf));
fst_check_string_equals(short_buf, "sip:bob@exa");

sofia_deflect_build_refer_to("sip:bob@example.com", sipip, short_buf, sizeof(short_buf));
fst_check_string_equals(short_buf, "sip:bob@exa");
}
FST_TEST_END()

#if HAVE_STIRSHAKEN
FST_TEST_BEGIN(sofia_verify_identity_test_no_identity)
{
Expand Down
Loading