diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index d9730a723c..676eeb7747 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -2161,6 +2161,12 @@ static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t stream->write_function(stream, "AGGRESSIVENAT \t%s\n", sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION) ? "true" : "false"); stream->write_function(stream, "STUN-ENABLED \t%s\n", sofia_test_pflag(profile, PFLAG_STUN_ENABLED) ? "true" : "false"); stream->write_function(stream, "STUN-AUTO-DISABLE\t%s\n", sofia_test_pflag(profile, PFLAG_STUN_AUTO_DISABLE) ? "true" : "false"); + if (profile->user_agent_filter) { + stream->write_function(stream, "USER-AGENT-FILTER\t%s\n", switch_str_nil(profile->user_agent_filter)); + } + if (profile->max_registrations_perext > 0) { + stream->write_function(stream, "MAX-REG-PEREXT \t%d\n", profile->max_registrations_perext); + } stream->write_function(stream, "CALLS-IN \t%d\n", profile->ib_calls); stream->write_function(stream, "FAILED-CALLS-IN \t%d\n", profile->ib_failed_calls); stream->write_function(stream, "CALLS-OUT \t%d\n", profile->ob_calls); @@ -2382,6 +2388,8 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl stream->write_function(stream, " %s\n", sofia_test_pflag(profile, PFLAG_STUN_ENABLED) ? "true" : "false"); stream->write_function(stream, " %s\n", sofia_test_pflag(profile, PFLAG_STUN_AUTO_DISABLE) ? "true" : "false"); + stream->write_function(stream, " %s\n", switch_str_nil(profile->user_agent_filter)); + stream->write_function(stream, " %d\n", profile->max_registrations_perext); stream->write_function(stream, " %d\n", profile->ib_calls); stream->write_function(stream, " %d\n", profile->ob_calls); stream->write_function(stream, " %d\n", profile->ib_failed_calls); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 1c743db4d7..3fd797c746 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -515,6 +515,8 @@ struct sofia_profile { sofia_presence_type_t pres_type; sofia_media_options_t media_options; uint32_t force_subscription_expires; + char *user_agent_filter; + uint32_t max_registrations_perext; switch_rtp_bug_flag_t auto_rtp_bugs; uint32_t ib_calls; uint32_t ob_calls; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index fe321a8faa..31739d4ccc 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -2191,6 +2191,10 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile) } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL); } + } else if (!strcasecmp(var, "user-agent-filter")) { + profile->user_agent_filter = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "max-registrations-per-extension")) { + profile->max_registrations_perext = atoi(val); } else if (!strcasecmp(var, "rfc2833-pt")) { profile->te = (switch_payload_t) atoi(val); } else if (!strcasecmp(var, "cng-pt") && !(sofia_test_pflag(profile, PFLAG_SUPPRESS_CNG))) { @@ -2726,6 +2730,10 @@ switch_status_t config_sofia(int reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_STUN_AUTO_DISABLE); } + } else if (!strcasecmp(var, "user-agent-filter")) { + profile->user_agent_filter = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "max-registrations-per-extension")) { + profile->max_registrations_perext = atoi(val); } else if (!strcasecmp(var, "rfc2833-pt")) { profile->te = (switch_payload_t) atoi(val); } else if (!strcasecmp(var, "cng-pt") && !sofia_test_pflag(profile, PFLAG_SUPPRESS_CNG)) { diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 201ad05810..9f98b243db 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -1647,6 +1647,15 @@ static int sofia_reg_nonce_callback(void *pArg, int argc, char **argv, char **co return 0; } +static int sofia_reg_regcount_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + int *ret = (int *) pArg; + if (argc == 1) { + *ret = atoi(argv[0]); + } + return 0; +} + auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, sip_authorization_t const *authorization, sip_t const *sip, @@ -1682,6 +1691,9 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, const char *auth_acl = NULL; long ncl = 0; sip_unknown_t *un; + const char *user_agent = NULL; + const char *user_agent_filter = profile->user_agent_filter; + uint32_t max_registrations_perext = profile->max_registrations_perext; username = realm = nonce = uri = qop = cnonce = nc = response = NULL; @@ -1741,6 +1753,8 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, } } + user_agent = (sip && sip->sip_user_agent) ? sip->sip_user_agent->g_string : "unknown"; + if (zstr(np)) { nonce_cb_t cb = { 0 }; long nc_long = 0; @@ -1777,8 +1791,7 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, switch_assert(params); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "action", "sip_auth"); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_profile", profile->name); - switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_user_agent", - (sip && sip->sip_user_agent) ? sip->sip_user_agent->g_string : "unknown"); + switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_user_agent", user_agent); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_auth_username", username); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_auth_realm", realm); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_auth_nonce", nonce); @@ -1905,6 +1918,13 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, if (!strcasecmp(var, "mwi-account")) { mwi_account = val; } + + if (!strcasecmp(var, "user-agent-filter")) { + user_agent_filter = val; + } + if (!strcasecmp(var, "max-registrations-per-extension")) { + max_registrations_perext = atoi(val); + } } } @@ -1932,6 +1952,13 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, if (!strcasecmp(var, "mwi-account")) { mwi_account = val; } + + if (!strcasecmp(var, "user-agent-filter")) { + user_agent_filter = val; + } + if (!strcasecmp(var, "max-registrations-per-extension")) { + max_registrations_perext = atoi(val); + } } } @@ -1959,6 +1986,12 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, if (!strcasecmp(var, "mwi-account")) { mwi_account = val; } + if (!strcasecmp(var, "user-agent-filter")) { + user_agent_filter = val; + } + if (!strcasecmp(var, "max-registrations-per-extension")) { + max_registrations_perext = atoi(val); + } } } @@ -2046,6 +2079,41 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, } + if (user_agent_filter) { + if (switch_regex_match(user_agent, user_agent_filter) == SWITCH_STATUS_SUCCESS) { + if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SIP auth OK (REGISTER) due to user-agent-filter. Filter \"%s\" User-Agent \"%s\"\n", user_agent_filter, user_agent); + } + } else { + ret = AUTH_FORBIDDEN; + if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth failure (REGISTER) due to user-agent-filter. Filter \"%s\" User-Agent \"%s\"\n", user_agent_filter, user_agent); + } + goto end; + } + } + + if (max_registrations_perext > 0 && + (sip && sip->sip_contact && + (sip->sip_contact->m_expires == NULL || atol(sip->sip_contact->m_expires) > 0))) { + /* if expires is null still process */ + /* expires == 0 means the phone is going to unregiser, so don't count against max */ + int count = 0; + + sql = switch_mprintf("select count(sip_user) from sip_registrations where sip_user='%q'", username); + switch_assert(sql != NULL); + sofia_glue_execute_sql_callback(profile, NULL, sql, sofia_reg_regcount_callback, &count); + free(sql); + + if (count+1 > max_registrations_perext) { + ret = AUTH_FORBIDDEN; + if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth failure (REGISTER) due to reaching max allowed registrations. Count: %d\n", count); + } + goto end; + } + } + for_the_sake_of_interop: if ((input = switch_mprintf("%s:%q", regstr, uri))) {