Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 331633) +++ channels/chan_sip.c (working copy) @@ -276,6 +276,7 @@ #include "asterisk/xml.h" #include "sip/include/dialog.h" #include "sip/include/dialplan_functions.h" +#include "asterisk/security_events.h" /*** DOCUMENTATION @@ -1622,6 +1623,206 @@ */ struct ast_channel_tech sip_tech_info; +/*------- Generate Security Events -------- */ + +static enum ast_security_event_transport_type security_event_get_transport(struct sip_pvt *p) +{ + int res = 0; + + switch(p->socket.type) + { + case SIP_TRANSPORT_UDP: + return AST_SECURITY_EVENT_TRANSPORT_UDP; + case SIP_TRANSPORT_TCP: + return AST_SECURITY_EVENT_TRANSPORT_TCP; + case SIP_TRANSPORT_TLS: + return AST_SECURITY_EVENT_TRANSPORT_TLS; + } + + return res; +} + +static struct sockaddr_in *security_event_encode_sin_local(struct sip_pvt *p, struct sockaddr_in *sin_local) +{ + ast_sockaddr_to_sin(&p->ourip, sin_local); + + return sin_local; +} + +static struct sockaddr_in *security_event_encode_sin_remote(struct sip_pvt *p, struct sockaddr_in *sin_remote) +{ + ast_sockaddr_to_sin(&p->sa, sin_remote); + + return sin_remote; +} + +static void report_invalid_peer(struct sip_pvt *p) +{ + char session_id[32]; + struct sockaddr_in sin_local; + struct sockaddr_in sin_remote; + + struct ast_security_event_inval_acct_id inval_acct_id = { + .common.event_type = AST_SECURITY_EVENT_INVAL_ACCT_ID, + .common.version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION, + .common.service = "SIP", + .common.account_id = p->exten, + .common.local_addr = { + .sin = security_event_encode_sin_local(p, &sin_local), + .transport = security_event_get_transport(p) + }, + .common.remote_addr = { + .sin = security_event_encode_sin_remote(p, &sin_remote), + .transport = security_event_get_transport(p) + }, + .common.session_id = session_id + }; + + snprintf(session_id, sizeof(session_id), "%p", p); + + ast_security_event_report(AST_SEC_EVT(&inval_acct_id)); +} + +static void report_failed_acl(struct sip_pvt *p) +{ + char session_id[32]; + struct sockaddr_in sin_local; + struct sockaddr_in sin_remote; + + struct ast_security_event_failed_acl failed_acl_event = { + .common.event_type = AST_SECURITY_EVENT_FAILED_ACL, + .common.version = AST_SECURITY_EVENT_FAILED_ACL_VERSION, + .common.service = "SIP", + .common.account_id = p->exten, + .common.local_addr = { + .sin = security_event_encode_sin_local(p, &sin_local), + .transport = security_event_get_transport(p) + }, + .common.remote_addr = { + .sin = security_event_encode_sin_remote(p, &sin_remote), + .transport = security_event_get_transport(p) + }, + .common.session_id = session_id + }; + + snprintf(session_id, sizeof(session_id), "%p", p); + + ast_security_event_report(AST_SEC_EVT(&failed_acl_event)); +} + +static void report_inval_password(struct sip_pvt *p) +{ + char session_id[32]; + struct sockaddr_in sin_local; + struct sockaddr_in sin_remote; + + struct ast_security_event_inval_password inval_password = { + .common.event_type = AST_SECURITY_EVENT_INVAL_PASSWORD, + .common.version = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION, + .common.service = "SIP", + .common.account_id = p->exten, + .common.local_addr = { + .sin = security_event_encode_sin_local(p, &sin_local), + .transport = security_event_get_transport(p) + }, + .common.remote_addr = { + .sin = security_event_encode_sin_remote(p, &sin_remote), + .transport = security_event_get_transport(p) + }, + .common.session_id = session_id + }; + + snprintf(session_id, sizeof(session_id), "%p", p); + + ast_security_event_report(AST_SEC_EVT(&inval_password)); +} + +static void report_auth_success(struct sip_pvt *p) +{ + char session_id[32]; + struct sockaddr_in sin_local; + struct sockaddr_in sin_remote; + + struct ast_security_event_successful_auth successful_auth = { + .common.event_type = AST_SECURITY_EVENT_SUCCESSFUL_AUTH, + .common.version = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION, + .common.service = "SIP", + .common.account_id = p->exten, + .common.local_addr = { + .sin = security_event_encode_sin_local(p, &sin_local), + .transport = security_event_get_transport(p) + }, + .common.remote_addr = { + .sin = security_event_encode_sin_remote(p, &sin_remote), + .transport = security_event_get_transport(p) + }, + .common.session_id = session_id + }; + + snprintf(session_id, sizeof(session_id), "%p", p); + + ast_security_event_report(AST_SEC_EVT(&successful_auth)); +} + +static void report_session_limit(struct sip_pvt *p) +{ + char session_id[32]; + struct sockaddr_in sin_local; + struct sockaddr_in sin_remote; + + struct ast_security_event_session_limit session_limit = { + .common.event_type = AST_SECURITY_EVENT_SESSION_LIMIT, + .common.version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION, + .common.service = "SIP", + .common.account_id = p->exten, + .common.local_addr = { + .sin = security_event_encode_sin_local(p, &sin_local), + .transport = security_event_get_transport(p) + }, + .common.remote_addr = { + .sin = security_event_encode_sin_remote(p, &sin_remote), + .transport = security_event_get_transport(p) + }, + .common.session_id = session_id + }; + + snprintf(session_id, sizeof(session_id), "%p", p); + + ast_security_event_report(AST_SEC_EVT(&session_limit)); +} + +static void report_failed_challenge_response(struct sip_pvt *p, const char *response, const char *expected_response) +{ + char session_id[32]; + struct sockaddr_in sin_local; + struct sockaddr_in sin_remote; + + struct ast_security_event_chal_resp_failed chal_resp_failed = { + .common.event_type = AST_SECURITY_EVENT_CHAL_RESP_FAILED, + .common.version = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION, + .common.service = "SIP", + .common.account_id = p->exten, + .common.local_addr = { + .sin = security_event_encode_sin_local(p, &sin_local), + .transport = security_event_get_transport(p) + }, + .common.remote_addr = { + .sin = security_event_encode_sin_remote(p, &sin_remote), + .transport = security_event_get_transport(p) + }, + .common.session_id = session_id, + + .challenge = p->randdata, + .response = response, + .expected_response = expected_response + }; + + snprintf(session_id, sizeof(session_id), "%p", p); + + ast_security_event_report(AST_SEC_EVT(&chal_resp_failed)); +} + +/*------- CC Support -------- */ static int sip_cc_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan); static int sip_cc_agent_start_offer_timer(struct ast_cc_agent *agent); static int sip_cc_agent_stop_offer_timer(struct ast_cc_agent *agent); @@ -5871,6 +6072,7 @@ if (*call_limit > 0 ) { if (*inuse >= *call_limit) { ast_log(LOG_NOTICE, "Call %s %s '%s' rejected due to usage limit of %d\n", outgoing ? "to" : "from", "peer", name, *call_limit); + report_session_limit(fup); unref_peer(p, "update_call_counter: unref peer p, call limit exceeded"); return -1; } @@ -14208,6 +14410,7 @@ if (strcmp(username, keys[K_USER].s)) { ast_log(LOG_WARNING, "username mismatch, have <%s>, digest has <%s>\n", username, keys[K_USER].s); + report_failed_challenge_response(p, keys[K_USER].s, username); /* Oops, we're trying something here */ return AUTH_USERNAME_MISMATCH; } @@ -14217,6 +14420,12 @@ if (strcasecmp(p->randdata, keys[K_NONCE].s) || p->stalenonce) { /* XXX it was 'n'casecmp ? */ wrongnonce = TRUE; usednonce = keys[K_NONCE].s; + + if (!p->stalenonce) + { + report_failed_challenge_response(p, keys[K_NONCE].s, p->randdata); + } + } else { p->stalenonce = 1; /* now, since the nonce has a response, mark it as stale so it can't be sent or responded to again */ } @@ -14751,6 +14960,7 @@ break; } } + if (peer) { unref_peer(peer, "register_verify: unref_peer: tossing stack peer pointer at end of func"); } @@ -24858,12 +25068,14 @@ switch (res) { case AUTH_SECRET_FAILED: reason = "Wrong password"; + report_inval_password(p); break; case AUTH_USERNAME_MISMATCH: reason = "Username/auth name mismatch"; break; case AUTH_NOT_FOUND: reason = "No matching peer found"; + report_invalid_peer(p); break; case AUTH_UNKNOWN_DOMAIN: reason = "Not a local domain"; @@ -24873,6 +25085,7 @@ break; case AUTH_ACL_FAILED: reason = "Device does not match ACL"; + report_failed_acl(p); break; case AUTH_BAD_TRANSPORT: reason = "Device not configured to use this transport type"; @@ -24887,6 +25100,7 @@ append_history(p, "RegRequest", "Failed : Account %s : %s", get_header(req, "To"), reason); } else { req->authenticated = 1; + report_auth_success(p); append_history(p, "RegRequest", "Succeeded : Account %s", get_header(req, "To")); } Index: CHANGES =================================================================== --- CHANGES (revision 331633) +++ CHANGES (working copy) @@ -179,6 +179,7 @@ SIP Changes ----------- * Add T38 support for REJECTED state where T.38 Negotiation is explicitly rejected. + * SIP now generates security events using the Security Events Framework Queue changes ------------- Index: configs/logger.conf.sample =================================================================== --- configs/logger.conf.sample (revision 331633) +++ configs/logger.conf.sample (working copy) @@ -109,6 +109,11 @@ messages => notice,warning,error ;full => notice,warning,error,debug,verbose,dtmf,fax +; If you would like to log security events by using res_security_log +; use the level security +; +;securitylog => security + ;syslog keyword : This special keyword logs to syslog facility ; ;syslog.local0 => notice,warning,error