Revision
16557
Author
rupa
Date
2010-02-02 15:04:41 -0600 (Tue, 02 Feb 2010)

Log Message

BOUNTY-15 - add user-agent-filter and max-registrations-per-extension

Modified Paths

Diff

Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c (16556 => 16557)


--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c	2010-02-02 20:55:09 UTC (rev 16556)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c	2010-02-02 21:04:41 UTC (rev 16557)
@@ -2161,6 +2161,12 @@
 					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 @@
 					stream->write_function(stream, "    <stun-enabled>%s</stun-enabled>\n", sofia_test_pflag(profile, PFLAG_STUN_ENABLED) ? "true" : "false");
 					stream->write_function(stream, "    <stun-auto-disable>%s</stun-auto-disable>\n", 
 										   sofia_test_pflag(profile, PFLAG_STUN_AUTO_DISABLE) ? "true" : "false");
+					stream->write_function(stream, "    <user-agent-filter>%s</user-agent-filter>\n", switch_str_nil(profile->user_agent_filter));
+					stream->write_function(stream, "    <max-registrations-per-extension>%d</max-registrations-per-extension>\n", profile->max_registrations_perext);
 					stream->write_function(stream, "    <calls-in>%d</calls-in>\n", profile->ib_calls);
 					stream->write_function(stream, "    <calls-out>%d</calls-out>\n", profile->ob_calls);
 					stream->write_function(stream, "    <failed-calls-in>%d</failed-calls-in>\n", profile->ib_failed_calls);

Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h (16556 => 16557)


--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h	2010-02-02 20:55:09 UTC (rev 16556)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h	2010-02-02 21:04:41 UTC (rev 16557)
@@ -515,6 +515,8 @@
 	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;

Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c (16556 => 16557)


--- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c	2010-02-02 20:55:09 UTC (rev 16556)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c	2010-02-02 21:04:41 UTC (rev 16557)
@@ -2191,6 +2191,10 @@
 						} 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 @@
 						} 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)) {

Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_reg.c (16556 => 16557)


--- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_reg.c	2010-02-02 20:55:09 UTC (rev 16556)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_reg.c	2010-02-02 21:04:41 UTC (rev 16557)
@@ -1647,6 +1647,15 @@
 	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 @@
 	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 @@
 		}
 	}
 
+	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 @@
 	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 @@
 			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 @@
 			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 @@
 			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 @@
 
 	}
 
+	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))) {