Writing an Asterisk security statistics module for statsd

//Writing an Asterisk security statistics module for statsd

Here, after pulling out the payload from the Stasis message, we get the SecurityEvent field out and assign it to an integer, event_type. Note that we know that the value will be one of the AST_SECURITY_EVENT_* values. In my case, I only care when someone:

Fails to provide a valid account
Fails to provide a valid password
Fails a challenge check (rather important for SIP)
So we bail on any of the event types that aren’t one of those.

// res_myres.c file

#include “asterisk.h”

ASTERISK_FILE_VERSION(FILE, “$Revision$”)

#include “asterisk/module.h”
#include “asterisk/stasis.h”
#include “asterisk/security_events.h”
#include “asterisk/json.h”
#include “asterisk/statsd.h”

//MODULEINFO
// <support_level>extended</support_level>
// res_statsd

// Our Stasis subscription to the security topic
static struct stasis_subscription *sub;

#if 0
static void handle_security_event(void *data, struct stasis_subscription *sub,
struct stasis_message *message)
{
struct ast_json_payload *payload;
char *str_json;

if (stasis_message_type(message) != ast_security_event_type()) {
	return;
}

payload = stasis_message_data(message);
if (!payload || !payload->json) {
	return;
}

str_json = ast_json_dump_string_format(payload->json, AST_JSON_PRETTY);
if (str_json) {
	ast_log(LOG_NOTICE, "Security! %s\n", str_json);
}
ast_json_free(str_json);

}
#endif

#if 1
static char *sanitize_address(char *buffer)
{
char *current = buffer;

while ((current = strchr(current, '.'))) {
	*current = '_';
}

current = strrchr(buffer, '/');
*current = '\0';

return buffer;

}

static void handle_security_event(void *data, struct stasis_subscription *sub,
struct stasis_message *message)
{
struct ast_str *remote_msg;
struct ast_str *count_msg;
struct ast_json_payload *payload;
const char *service;
char *remote_address;
int event_type;

if (stasis_message_type(message) != ast_security_event_type()) {
	return;
}

payload = stasis_message_data(message);
if (!payload || !payload->json) {
	return;
}

event_type = ast_json_integer_get(ast_json_object_get(payload->json, "SecurityEvent"));
switch (event_type) {
case AST_SECURITY_EVENT_INVAL_ACCT_ID:
case AST_SECURITY_EVENT_INVAL_PASSWORD:
case AST_SECURITY_EVENT_CHAL_RESP_FAILED:
	break;
default:
	return;
}

remote_msg = ast_str_create(64);
count_msg = ast_str_create(64);
if (!remote_msg || !count_msg) {
	ast_free(remote_msg);
	ast_free(count_msg);
	return;
}

service = ast_json_string_get(ast_json_object_get(payload->json, "Service"));

ast_str_set(&count_msg, 0, "security.failed_auth.%s.count", service);
ast_statsd_log(ast_str_buffer(count_msg), AST_STATSD_METER, 1);

remote_address = ast_strdupa(ast_json_string_get(ast_json_object_get(payload->json, "RemoteAddress")));
remote_address = sanitize_address(remote_address);

ast_str_set(&remote_msg, 0, "security.failed_auth.%s.%s", service, remote_address);
ast_statsd_log(ast_str_buffer(remote_msg), AST_STATSD_METER, 1);

ast_free(remote_msg);
ast_free(count_msg);

}
#endif

static int load_module(void)
{
sub = stasis_subscribe(ast_security_topic(), handle_security_event, NULL);
if (!sub) {
return AST_MODULE_LOAD_FAILURE;
}

return AST_MODULE_LOAD_SUCCESS;

}

static int unload_module(void)
{
stasis_unsubscribe_and_join(sub);
sub = NULL;

return 0;

}

AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "MY OWN RES ");

// end

why it doesn’t run ?
hot to pass arguments to handle_security_event function ??

sub = stasis_subscribe(ast_security_topic(), handle_security_event, NULL);   //  it is right or wrong?

why some function the last statement written like this ?

AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, “Statsd client support”,
.support_level = AST_MODULE_SUPPORT_EXTENDED,
.load = load_module,
.unload = unload_module,
.reload = reload_module,
.load_pri = 0,
);

// I write as follows , is it wrong ?
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "MY OWN RES ");

// You can refer to matthewjordan.net/category/asterisk/

$ telnet 127.0.0.1 5038
Trying 127.0.0.1…
telnet: Unable to connect to remote host: Connection refused

Any help ?