diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 63697dbbda..1ffd39dc6e 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -527,6 +527,9 @@ struct sofia_gateway { char *register_proxy; char *register_sticky_proxy; char *outbound_sticky_proxy; + char *register_proxy_host_cfg; /* hold only the IP or the hostname, no port, no "sip:" or "sips:" prefix */ + char *outbound_proxy_host_cfg; + char *proxy_host_cfg; char *register_context; char *expires_str; char *register_url; @@ -1258,6 +1261,7 @@ void sofia_glue_pause_jitterbuffer(switch_core_session_t *session, switch_bool_t void sofia_process_dispatch_event(sofia_dispatch_event_t **dep); void sofia_process_dispatch_event_in_thread(sofia_dispatch_event_t **dep); char *sofia_glue_get_host(const char *str, switch_memory_pool_t *pool); +char *sofia_glue_get_host_from_cfg(const char *str, switch_memory_pool_t *pool); void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now); void sofia_msg_thread_start(int idx); void crtp_init(switch_loadable_module_interface_t *module_interface); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 54d0dbdfe8..a752a4a8f4 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -3950,8 +3950,10 @@ static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag, contact_host = val; } else if (!strcmp(var, "register-proxy")) { register_proxy = val; + gateway->register_proxy_host_cfg = sofia_glue_get_host_from_cfg(register_proxy, gateway->pool); } else if (!strcmp(var, "outbound-proxy")) { outbound_proxy = val; + gateway->outbound_proxy_host_cfg = sofia_glue_get_host_from_cfg(outbound_proxy, gateway->pool); } else if (!strcmp(var, "distinct-to")) { distinct_to = switch_true(val); } else if (!strcmp(var, "destination-prefix")) { @@ -4025,6 +4027,8 @@ static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag, proxy = realm; } + gateway->proxy_host_cfg = sofia_glue_get_host_from_cfg(proxy, gateway->pool); + if (!switch_true(register_str)) { gateway->state = REG_STATE_NOREG; gateway->status = SOFIA_GATEWAY_UP; diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 10282383d2..1f2afef85c 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -3539,6 +3539,42 @@ char *sofia_glue_get_profile_url(sofia_profile_t *profile, char *remote_ip, cons return url; } +/* gets the IP or HOST from a sip uri or from x.x.x.x:port format */ +char *sofia_glue_get_host_from_cfg(const char *uri, switch_memory_pool_t *pool) +{ + char *host = NULL; + const char *s; + char *p = NULL; + + if (zstr(uri)) { + return NULL; + } + + if ((s = switch_stristr("sip:", uri)) && s == uri) { + s += 4; + } else if ((s = switch_stristr("sips:", uri)) && s == uri) { + s += 5; + } + + if (!s) { + s = uri; + } + + host = switch_core_strdup(pool, s); + + if ((p = strchr(host, ']'))) { + if (*(p + 1) == ':') { + *(p + 1) = '\0'; + } + } else { + if ((p = strrchr(host, ':'))) { + *p = '\0'; + } + } + + return host; +} + /* For Emacs: * Local Variables: * mode:c diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 03cb0fb6d0..49dc8feeda 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -2508,12 +2508,11 @@ switch_bool_t sip_resolve_compare(const char *domainname, const char *ip, sofia_ if (strchr(ip, ':')) { ipv6 = SWITCH_TRUE; } + ret = dig_all_srvs_simple(dig, domainname, ip, ipv6); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "verify 1\n"); if (!ret) { answers = dig_addr_simple(dig, host, ipv6?sres_type_aaaa:sres_type_a); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "verify 2\n"); ret = verify_ip(answers, ip, ipv6); } @@ -2524,6 +2523,36 @@ out: return ret; } +static switch_bool_t is_host_from_gateway(const char *remote_ip, sofia_gateway_t *gateway) +{ + switch_bool_t ret = SWITCH_FALSE; + char *hosts[3]; /* check the 3 places where we keep IP/hostname */ + int i; + + hosts[0] = gateway->proxy_host_cfg; + hosts[1] = gateway->register_proxy_host_cfg; + hosts[2] = gateway->outbound_proxy_host_cfg; + + for (i = 0; i < 3; i++) { + if (zstr(hosts[i])) { + continue; + } + + if (host_is_ip_address(hosts[i])) { + if (!strcmp(hosts[i], remote_ip)) { + ret = SWITCH_TRUE; + } + + if (ret) break; + } else { + ret = sip_resolve_compare(hosts[i], remote_ip, gateway->register_transport); + if (ret) break; + } + } + + return ret; +} + static switch_bool_t is_legitimate_gateway(sofia_dispatch_event_t *de, sofia_gateway_t *gateway) { char remote_ip[80] = { 0 }; @@ -2531,27 +2560,16 @@ static switch_bool_t is_legitimate_gateway(sofia_dispatch_event_t *de, sofia_gat sofia_glue_get_addr(de->data->e_msg, remote_ip, sizeof(remote_ip), NULL); + /* setting param "gw-auth-acl" supersedes everything */ if (gateway->gw_auth_acl) { ret = switch_check_network_list_ip(remote_ip, gateway->gw_auth_acl); if (!ret) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Challange from [%s] denied by gw-auth-acl.\n", remote_ip); } + return ret; } else { - char *register_host = sofia_glue_get_register_host(gateway->register_proxy); - const char *host = sofia_glue_strip_proto(register_host); - - if (host_is_ip_address(host)) { - if (host && !strcmp(host, remote_ip)) { - ret = SWITCH_TRUE; - } - switch_safe_free(register_host); - return ret; - } else { - ret = sip_resolve_compare(host, remote_ip, gateway->register_transport); - switch_safe_free(register_host); - return ret; - } + return is_host_from_gateway(remote_ip, gateway); } } diff --git a/src/mod/endpoints/mod_sofia/test/conf-sipp/freeswitch.xml b/src/mod/endpoints/mod_sofia/test/conf-sipp/freeswitch.xml index 088a7a545c..dee105561b 100644 --- a/src/mod/endpoints/mod_sofia/test/conf-sipp/freeswitch.xml +++ b/src/mod/endpoints/mod_sofia/test/conf-sipp/freeswitch.xml @@ -322,11 +322,41 @@ + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -365,7 +395,7 @@ - + diff --git a/src/mod/endpoints/mod_sofia/test/sipp-based-tests.c b/src/mod/endpoints/mod_sofia/test/sipp-based-tests.c index 382dbc2970..03a0e4a654 100644 --- a/src/mod/endpoints/mod_sofia/test/sipp-based-tests.c +++ b/src/mod/endpoints/mod_sofia/test/sipp-based-tests.c @@ -57,6 +57,22 @@ static switch_bool_t has_ipv6() return SWITCH_TRUE; } +static void register_gw() +{ + switch_stream_handle_t stream = { 0 }; + SWITCH_STANDARD_STREAM(stream); + switch_api_execute("sofia", "profile external register testgw", NULL, &stream); + switch_safe_free(stream.data); +} + +static void unregister_gw() +{ + switch_stream_handle_t stream = { 0 }; + SWITCH_STANDARD_STREAM(stream); + switch_api_execute("sofia", "profile external unregister testgw", NULL, &stream); + switch_safe_free(stream.data); +} + static int start_sipp_uac(const char *ip, int remote_port,const char *scenario_uac, const char *extra) { char *cmd = switch_mprintf("sipp %s:%d -nr -p 5062 -m 1 -s 1001 -recv_timeout 10000 -timeout 10s -sf %s -bg %s", ip, remote_port, scenario_uac, extra); @@ -65,24 +81,29 @@ static int start_sipp_uac(const char *ip, int remote_port,const char *scenario_u printf("%s\n", cmd); switch_safe_free(cmd); switch_sleep(1000 * 1000); + return sys_ret; } +static int start_sipp_uas(const char *ip, int listen_port, const char *scenario_uas, const char *extra) +{ + char *cmd = switch_mprintf("sipp %s -p %d -nr -m 1 -s 1001 -recv_timeout 10000 -timeout 10s -sf %s -bg %s", ip, listen_port, scenario_uas, extra); + int sys_ret = switch_system(cmd, SWITCH_TRUE); + + printf("%s\n", cmd); + switch_safe_free(cmd); + switch_sleep(1000 * 1000); + + return sys_ret; +} static void kill_sipp(void) { switch_system("pkill -x sipp", SWITCH_TRUE); switch_sleep(1000 * 1000); } -static void event_handler(switch_event_t *event) -{ - const char *new_ev = switch_event_get_header(event, "Event-Subclass"); +static void show_event(switch_event_t *event) { char *str; - - if (new_ev && !strcmp(new_ev, "sofia::gateway_invalid_digest_req")) { - test_success = 1; - } - /*print the event*/ switch_event_serialize_json(event, &str); if (str) { @@ -91,6 +112,45 @@ static void event_handler(switch_event_t *event) } } +static void event_handler(switch_event_t *event) +{ + const char *new_ev = switch_event_get_header(event, "Event-Subclass"); + + if (new_ev && !strcmp(new_ev, "sofia::gateway_invalid_digest_req")) { + test_success = 1; + } + + show_event(event); +} + +static void event_handler_reg_ok(switch_event_t *event) +{ + const char *new_ev = switch_event_get_header(event, "Event-Subclass"); + + if (new_ev && !strcmp(new_ev, "sofia::gateway_state")) { + const char *state = switch_event_get_header(event, "State"); + if (state && !strcmp(state, "REGED")) { + test_success++; + } + } + + show_event(event); +} + +static void event_handler_reg_fail(switch_event_t *event) +{ + const char *new_ev = switch_event_get_header(event, "Event-Subclass"); + + if (new_ev && !strcmp(new_ev, "sofia::gateway_state")) { + const char *state = switch_event_get_header(event, "State"); + if (state && !strcmp(state, "FAIL_WAIT")) { + test_success++; + } + } + + show_event(event); +} + FST_CORE_EX_BEGIN("./conf-sipp", SCF_VG | SCF_USE_SQL) { FST_MODULE_BEGIN(mod_sofia, uac-uas) @@ -289,6 +349,132 @@ skiptest: } FST_TEST_END() + FST_TEST_BEGIN(register_ok) + { + const char *local_ip_v4 = switch_core_get_variable("local_ip_v4"); + int sipp_ret; + + switch_event_bind("sofia", SWITCH_EVENT_CUSTOM, NULL, event_handler_reg_ok, NULL); + + sipp_ret = start_sipp_uas(local_ip_v4, 6080, "sipp-scenarios/uas_register.xml", ""); + if (sipp_ret < 0 || sipp_ret == 127) { + fst_requires(0); /* sipp not found */ + } + + switch_sleep(1000 * 1000); + + register_gw(); + + switch_sleep(5000 * 1000); + + switch_event_unbind_callback(event_handler_reg_ok); + /* sipp should timeout, attempt kill, just in case.*/ + kill_sipp(); + fst_check(test_success); + test_success = 0; + } + FST_TEST_END() + + FST_TEST_BEGIN(register_403) + { + const char *local_ip_v4 = switch_core_get_variable("local_ip_v4"); + int sipp_ret; + + switch_event_bind("sofia", SWITCH_EVENT_CUSTOM, NULL, event_handler_reg_fail, NULL); + + sipp_ret = start_sipp_uas(local_ip_v4, 6080, "sipp-scenarios/uas_register_403.xml", ""); + if (sipp_ret < 0 || sipp_ret == 127) { + fst_requires(0); /* sipp not found */ + } + + switch_sleep(1000 * 1000); + + register_gw(); + + switch_sleep(5000 * 1000); + + switch_event_unbind_callback(event_handler_reg_fail); + /* sipp should timeout, attempt kill, just in case.*/ + kill_sipp(); + fst_check(test_success); + test_success = 0; + } + FST_TEST_END() + + FST_TEST_BEGIN(register_no_challange) + { + const char *local_ip_v4 = switch_core_get_variable("local_ip_v4"); + int sipp_ret; + + switch_event_bind("sofia", SWITCH_EVENT_CUSTOM, NULL, event_handler_reg_ok, NULL); + + sipp_ret = start_sipp_uas(local_ip_v4, 6080, "sipp-scenarios/uas_register_no_challange.xml", ""); + if (sipp_ret < 0 || sipp_ret == 127) { + fst_requires(0); /* sipp not found */ + } + + switch_sleep(1000 * 1000); + + register_gw(); + + switch_sleep(5000 * 1000); + + /*the REGISTER with Expires 0 */ + unregister_gw(); + + switch_sleep(1000 * 1000); + + register_gw(); + + switch_sleep(1000 * 1000); + + switch_event_unbind_callback(event_handler_reg_ok); + + /* sipp should timeout, attempt kill, just in case.*/ + kill_sipp(); + fst_check(test_success); + test_success = 0; + } + FST_TEST_END() + + FST_TEST_BEGIN(invite_407) + { + const char *local_ip_v4 = switch_core_get_variable("local_ip_v4"); + int sipp_ret; + switch_core_session_t *session; + switch_call_cause_t cause; + switch_status_t status; + switch_channel_t *channel; + char *to; + const int inv_sipp_port = 6082; + + sipp_ret = start_sipp_uas(local_ip_v4, inv_sipp_port, "sipp-scenarios/uas_407.xml", ""); + if (sipp_ret < 0 || sipp_ret == 127) { + fst_requires(0); /* sipp not found */ + } + + switch_sleep(1000 * 1000); + to = switch_mprintf("sofia/gateway/testgw-noreg/sipp@%s:%d", local_ip_v4, inv_sipp_port); + /*originate will fail if the 407 we get from sipp is dropped due to wrong IP.*/ + status = switch_ivr_originate(NULL, &session, &cause, to, 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL); + fst_check(status == SWITCH_STATUS_SUCCESS); + + /*test is considered PASSED if we get a session*/ + if (!session) { + fst_requires(session); + } + + switch_sleep(1000 * 1000); + + channel = switch_core_session_get_channel(session); + switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + switch_core_session_rwunlock(session); + switch_safe_free(to); + /* sipp should timeout, attempt kill, just in case.*/ + kill_sipp(); + } + FST_TEST_END() + } FST_MODULE_END() } diff --git a/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uas_407.xml b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uas_407.xml new file mode 100644 index 0000000000..62ac17babc --- /dev/null +++ b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uas_407.xml @@ -0,0 +1,72 @@ + + + + + + + + Proxy-Authenticate: Digest realm="freeswitch.org", nonce="47ebe028cda119c35d4877b383027d28da013815" + Content-Length: [len] + + ]]> + + + + + + + + + Content-Length: 0 + + ]]> + + + + + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] + s=- + c=IN IP[media_ip_type] [media_ip] + t=0 0 + m=audio [media_port] RTP/AVP 0 + a=rtpmap:0 PCMU/8000 + + ]]> + + + + + + + + + + diff --git a/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uas_register.xml b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uas_register.xml new file mode 100644 index 0000000000..ae9681663d --- /dev/null +++ b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uas_register.xml @@ -0,0 +1,43 @@ + + + + + + + + WWW-Authenticate: Digest realm="freeswitch.org", nonce="47ebe028cda119c35d4877b383027d28da013815" + Content-Length: [len] + + ]]> + + + + + + Content-Length: 0 + Expires: 60 + + ]]> + + + + + + + diff --git a/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uas_register_403.xml b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uas_register_403.xml new file mode 100644 index 0000000000..9a42f1a7a4 --- /dev/null +++ b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uas_register_403.xml @@ -0,0 +1,42 @@ + + + + + + + + WWW-Authenticate: Digest realm="freeswitch.org", nonce="81dc9bdb52d04dc20036dbd8313ed055" + Content-Length: [len] + + ]]> + + + + + + Content-Length: 0 + + ]]> + + + + + + + diff --git a/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uas_register_no_challange.xml b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uas_register_no_challange.xml new file mode 100644 index 0000000000..175149a026 --- /dev/null +++ b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uas_register_no_challange.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + +