From e9cf88f8c2c6d79a23e1c504853d78e2ba4c93de Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sat, 11 Mar 2017 22:03:35 +0100 Subject: [PATCH] main: store additional statistics globally That is, store: * number of timed out sessions * number of timed out due being idle sessions * number of errored sessions * total number of session handled (closed) * total number of kbytes sent * total number of kbytes received * minimum MTU seen * maximum MTU seen * total authentication failures * average/max authentication time (in secs) * average/max session time (in minutes) Signed-off-by: Nikos Mavrogiannopoulos --- src/ipc.proto | 3 ++ src/main-ctl-unix.c | 8 ++--- src/main-proc.c | 4 +-- src/main-sec-mod-cmd.c | 80 +++++++++++++++++++++++++++++++++++++++--- src/main.c | 6 ++-- src/main.h | 35 ++++++++++++++---- src/sec-mod-auth.c | 31 +++++++++++++++- src/sec-mod.h | 4 +++ 8 files changed, 150 insertions(+), 21 deletions(-) diff --git a/src/ipc.proto b/src/ipc.proto index 4fd0a662..62f879ca 100644 --- a/src/ipc.proto +++ b/src/ipc.proto @@ -137,6 +137,9 @@ message cli_stats_msg optional uint32 discon_reason = 8; optional uint32 secmod_client_entries = 9; /* from sec-mod to main only */ optional uint32 secmod_tlsdb_entries = 10; /* from sec-mod to main only */ + optional uint64 secmod_auth_failures = 11; /* failures since last update - sec-mod to main only */ + optional uint32 secmod_avg_auth_time = 12; /* average auth time in seconds - sec-mod to main only */ + optional uint32 secmod_max_auth_time = 13; /* max auth time in seconds - sec-mod to main only */ } /* UDP_FD */ diff --git a/src/main-ctl-unix.c b/src/main-ctl-unix.c index 6cf74711..a673e885 100644 --- a/src/main-ctl-unix.c +++ b/src/main-ctl-unix.c @@ -179,11 +179,11 @@ static void method_status(method_ctx *ctx, int cfd, uint8_t * msg, rep.status = 1; rep.pid = getpid(); - rep.start_time = ctx->s->start_time; + rep.start_time = ctx->s->stats.start_time; rep.sec_mod_pid = ctx->s->sec_mod_pid; - rep.active_clients = ctx->s->active_clients; - rep.secmod_client_entries = ctx->s->secmod_client_entries; - rep.stored_tls_sessions = ctx->s->tlsdb_entries; + rep.active_clients = ctx->s->stats.active_clients; + rep.secmod_client_entries = ctx->s->stats.secmod_client_entries; + rep.stored_tls_sessions = ctx->s->stats.tlsdb_entries; rep.banned_ips = main_ban_db_elems(ctx->s); ret = send_msg(ctx->pool, cfd, CTL_CMD_STATUS_REP, &rep, diff --git a/src/main-proc.c b/src/main-proc.c index f64cb28b..3a4f55ae 100644 --- a/src/main-proc.c +++ b/src/main-proc.c @@ -85,7 +85,7 @@ struct proc_st *ctmp; list_add(&s->proc_list.head, &(ctmp->list)); put_into_cgroup(s, s->config->cgroup, pid); - s->active_clients++; + s->stats.active_clients++; return ctmp; } @@ -100,7 +100,7 @@ void remove_proc(main_server_st * s, struct proc_st *proc, unsigned flags) ev_child_stop(EV_A_ &proc->ev_child); list_del(&proc->list); - s->active_clients--; + s->stats.active_clients--; if ((flags&RPROC_KILL) && proc->pid != -1 && proc->pid != 0) kill(proc->pid, SIGTERM); diff --git a/src/main-sec-mod-cmd.c b/src/main-sec-mod-cmd.c index 1f435d99..30d64cda 100644 --- a/src/main-sec-mod-cmd.c +++ b/src/main-sec-mod-cmd.c @@ -402,6 +402,16 @@ void apply_default_config(main_server_st *s, proc_st *proc, GroupCfgSt *gc) (*proc->config_usage_count)++; } +static void update_auth_failures(main_server_st * s, uint64_t auth_failures) +{ + if (s->stats.auth_failures + auth_failures < s->stats.auth_failures) { + mslog(s, NULL, LOG_INFO, "overflow on updating authentication failures; resetting"); + s->stats.auth_failures = 0; + return; + } + s->stats.auth_failures += auth_failures; +} + int session_open(main_server_st * s, struct proc_st *proc, const uint8_t *cookie, unsigned cookie_size) { int ret, e; @@ -449,7 +459,8 @@ int session_open(main_server_st * s, struct proc_st *proc, const uint8_t *cookie } if (msg->reply != AUTH__REP__OK) { - mslog(s, proc, LOG_DEBUG, "could not initiate session"); + mslog(s, proc, LOG_DEBUG, "session initiation was rejected"); + update_auth_failures(s, 1); return -1; } @@ -495,6 +506,64 @@ int session_open(main_server_st * s, struct proc_st *proc, const uint8_t *cookie return 0; } +static void update_main_stats(main_server_st * s, struct proc_st *proc, uint64_t auth_failures, uint32_t avg_auth_time, uint32_t max_auth_time) +{ + uint64_t kb_in, kb_out; + time_t now = time(0), stime; + + if (proc->discon_reason == REASON_IDLE_TIMEOUT) + s->stats.session_idle_timeouts++; + else if (proc->discon_reason == REASON_SESSION_TIMEOUT) + s->stats.session_timeouts++; + else if (proc->discon_reason == REASON_ERROR) + s->stats.session_errors++; + + s->stats.sessions_closed++; + if (s->stats.sessions_closed == 0) { /* overflow */ + goto reset; + } + + kb_in = proc->bytes_in/1000; + kb_out = proc->bytes_out/1000; + + if (s->stats.kbytes_in + kb_in < s->stats.kbytes_in) + goto reset; + + if (s->stats.kbytes_out + kb_out < s->stats.kbytes_out) + goto reset; + + update_auth_failures(s, auth_failures); + + s->stats.kbytes_in += kb_in; + s->stats.kbytes_out += kb_out; + + if (s->stats.min_mtu == 0 || proc->mtu < s->stats.min_mtu) + s->stats.min_mtu = proc->mtu; + if (s->stats.max_mtu == 0 || proc->mtu > s->stats.min_mtu) + s->stats.max_mtu = proc->mtu; + + /* connection time in minutes */ + stime = (now - proc->conn_time)/60; + if (stime > 0) { + s->stats.avg_session_mins = ((s->stats.sessions_closed-1) * s->stats.avg_session_mins + stime) / s->stats.sessions_closed; + if (stime > s->stats.max_session_mins) + s->stats.max_session_mins = stime; + } + + s->stats.avg_auth_time = avg_auth_time; + s->stats.max_auth_time = max_auth_time; + + return; + reset: + mslog(s, NULL, LOG_INFO, "overflow on updating server statistics, resetting stats"); + s->stats.session_idle_timeouts = 0; + s->stats.session_timeouts = 0; + s->stats.session_errors = 0; + s->stats.last_reset = now; + s->stats.kbytes_in = 0; + s->stats.kbytes_out = 0; +} + int session_close(main_server_st * s, struct proc_st *proc) { int ret, e; @@ -533,11 +602,14 @@ int session_close(main_server_st * s, struct proc_st *proc) proc->bytes_in = msg->bytes_in; proc->bytes_out = msg->bytes_out; if (msg->has_secmod_client_entries) - s->secmod_client_entries = msg->secmod_client_entries; + s->stats.secmod_client_entries = msg->secmod_client_entries; if (msg->has_secmod_tlsdb_entries) - s->tlsdb_entries = msg->secmod_tlsdb_entries; - if (msg->has_discon_reason) + s->stats.tlsdb_entries = msg->secmod_tlsdb_entries; + if (msg->has_discon_reason) { proc->discon_reason = msg->discon_reason; + } + + update_main_stats(s, proc, msg->secmod_auth_failures, msg->secmod_avg_auth_time, msg->secmod_max_auth_time); cli_stats_msg__free_unpacked(msg, &pa); diff --git a/src/main.c b/src/main.c index 0c980d3a..a42f07b1 100644 --- a/src/main.c +++ b/src/main.c @@ -1080,9 +1080,9 @@ static void listen_watcher_cb (EV_P_ ev_io *w, int revents) set_block(fd); #endif - if (s->config->max_clients > 0 && s->active_clients >= s->config->max_clients) { + if (s->config->max_clients > 0 && s->stats.active_clients >= s->config->max_clients) { close(fd); - mslog(s, NULL, LOG_INFO, "reached maximum client limit (active: %u)", s->active_clients); + mslog(s, NULL, LOG_INFO, "reached maximum client limit (active: %u)", s->stats.active_clients); return; } @@ -1262,7 +1262,7 @@ int main(int argc, char** argv) } s->main_pool = main_pool; s->creds = &creds; - s->start_time = time(0); + s->stats.start_time = s->stats.last_reset = time(0); s->top_fd = -1; s->ctl_fd = -1; diff --git a/src/main.h b/src/main.h index 5ec782e7..10406f26 100644 --- a/src/main.h +++ b/src/main.h @@ -171,6 +171,32 @@ struct proc_hash_db_st { unsigned total; }; +struct main_stats_st { + uint64_t session_timeouts; /* sessions with timeout */ + uint64_t session_idle_timeouts; /* sessions with idle timeout */ + uint64_t session_errors; /* sessions closed with error */ + uint64_t sessions_closed; /* sessions closed */ + uint64_t kbytes_in; + uint64_t kbytes_out; + unsigned min_mtu; + unsigned max_mtu; + + unsigned active_clients; + /* updated on the cli_stats_msg from sec-mod. + * Holds the number of entries in secmod list of users */ + unsigned secmod_client_entries; + unsigned tlsdb_entries; + time_t start_time; + time_t last_reset; + + uint64_t auth_failures; /* authentication failures */ + uint32_t avg_auth_time; /* in seconds */ + uint32_t max_auth_time; /* in seconds */ + uint32_t avg_session_mins; /* in minutes */ + uint32_t max_session_mins; + +}; + typedef struct main_server_st { struct cfg_st *config; /* pointer inside perm_config */ struct perm_cfg_st *perm_config; @@ -193,13 +219,8 @@ typedef struct main_server_st { struct sockaddr_un secmod_addr; unsigned secmod_addr_len; - - unsigned active_clients; - /* updated on the cli_stats_msg from sec-mod. - * Holds the number of entries in secmod list of users */ - unsigned secmod_client_entries; - unsigned tlsdb_entries; - time_t start_time; + + struct main_stats_st stats; void * auth_extra; diff --git a/src/sec-mod-auth.c b/src/sec-mod-auth.c index 67a9ab77..bffddecf 100644 --- a/src/sec-mod-auth.c +++ b/src/sec-mod-auth.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2016 Nikos Mavrogiannopoulos + * Copyright (C) 2013-2017 Nikos Mavrogiannopoulos * Copyright (C) 2014-2016 Red Hat * * This program is free software; you can redistribute it and/or modify @@ -109,6 +109,22 @@ void sec_mod_add_score_to_ip(sec_mod_st *sec, client_entry_st *e, const char *ip return; } +static void update_auth_time_stats(sec_mod_st * sec, time_t secs) +{ + if (secs < 0) + return; + + sec->total_authentications++; + if (sec->total_authentications == 0) { /* reset stats */ + sec->avg_auth_time = 0; + return; + } + + if (secs > sec->max_auth_time) + sec->max_auth_time = secs; + sec->avg_auth_time = (sec->avg_auth_time*(sec->total_authentications-1)+secs) / sec->total_authentications; +} + static int send_sec_auth_reply(int cfd, sec_mod_st * sec, client_entry_st * entry, AUTHREP r) { @@ -125,6 +141,9 @@ int send_sec_auth_reply(int cfd, sec_mod_st * sec, client_entry_st * entry, AUTH msg.msg = entry->msg_str; } + /* calculate time in auth for this client */ + update_auth_time_stats(sec, time(0) - entry->time); + msg.has_sid = 1; msg.sid.data = entry->sid; msg.sid.len = sizeof(entry->sid); @@ -139,6 +158,8 @@ int send_sec_auth_reply(int cfd, sec_mod_st * sec, client_entry_st * entry, AUTH sec_auth_reply_msg__get_packed_size, (pack_func) sec_auth_reply_msg__pack); } else { + sec->auth_failures++; + msg.reply = AUTH__REP__FAILED; ret = send_msg(entry, cfd, CMD_SEC_AUTH_REPLY, @@ -554,6 +575,14 @@ int handle_secm_session_close_cmd(sec_mod_st *sec, int fd, const SecmSessionClos rep.secmod_tlsdb_entries = sec->tls_db.entries; rep.has_secmod_tlsdb_entries = 1; + rep.secmod_auth_failures = sec->auth_failures; + rep.has_secmod_auth_failures = 1; + sec->auth_failures = 0; + rep.secmod_avg_auth_time = sec->avg_auth_time; + rep.secmod_max_auth_time = sec->max_auth_time; + rep.has_secmod_avg_auth_time = 1; + rep.has_secmod_max_auth_time = 1; + ret = send_msg(e, fd, CMD_SECM_CLI_STATS, &rep, (pack_size_func) cli_stats_msg__get_packed_size, (pack_func) cli_stats_msg__pack); diff --git a/src/sec-mod.h b/src/sec-mod.h index 8b862b3a..d7d6ee6b 100644 --- a/src/sec-mod.h +++ b/src/sec-mod.h @@ -40,6 +40,10 @@ typedef struct sec_mod_st { int cmd_fd_sync; tls_sess_db_st tls_db; + uint64_t auth_failures; /* auth failures since the last update (SECM_CLI_STATS) we sent to main */ + uint32_t max_auth_time; /* the maximum time spent in (sucessful) authentication */ + uint32_t avg_auth_time; /* the average time spent in (sucessful) authentication */ + uint32_t total_authentications; /* successful authentications: to calculate the average above */ struct config_mod_st *config_module; } sec_mod_st;