From 6671032fafc82be04b4ca564790753b26f96780e Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 29 Jan 2020 18:40:32 +0100 Subject: [PATCH] ACL LOG: group similar entries in a given time delta. --- src/acl.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/src/acl.c b/src/acl.c index 5937c069c..d03599a79 100644 --- a/src/acl.c +++ b/src/acl.c @@ -1465,6 +1465,7 @@ void ACLLoadUsersAtStartup(void) { #define ACL_LOG_CTX_TOPLEVEL 0 #define ACL_LOG_CTX_LUA 1 #define ACL_LOG_CTX_MULTI 2 +#define ACL_LOG_GROUPING_MAX_TIME_DELTA 60000 /* This structure defines an entry inside the ACL log. */ typedef struct ACLLogEntry { @@ -1477,6 +1478,28 @@ typedef struct ACLLogEntry { sds cinfo; /* Client info (last client if updated). */ } ACLLogEntry; +/* This function will check if ACL entries 'a' and 'b' are similar enough + * that we should actually update the existing entry in our ACL log instead + * of creating a new one. */ +int ACLLogMatchEntry(ACLLogEntry *a, ACLLogEntry *b) { + if (a->reason != b->reason) return 0; + if (a->context != b->context) return 0; + mstime_t delta = a->ctime - b->ctime; + if (delta < 0) delta = -delta; + if (delta > ACL_LOG_GROUPING_MAX_TIME_DELTA) return 0; + if (sdscmp(a->object,b->object) != 0) return 0; + if (sdscmp(a->username,b->username) != 0) return 0; + return 1; +} + +/* Release an ACL log entry. */ +void ACLFreeLogEntry(ACLLogEntry *le) { + sdsfree(le->object); + sdsfree(le->username); + sdsfree(le->cinfo); + zfree(le); +} + /* Adds a new entry in the ACL log, making sure to delete the old entry * if we reach the maximum length allowed for the log. This function attempts * to find similar entries in the current log in order to bump the counter of @@ -1504,9 +1527,41 @@ void addACLLogEntry(client *c, int reason, int keypos) { le->context = ACL_LOG_CTX_TOPLEVEL; } - /* Add it to our list of entires. We'll have to trim the list - * to its maximum size. */ - listAddNodeHead(ACLLog, le); + /* Try to match this entry with past ones, to see if we can just + * update an existing entry instead of creating a new one. */ + long toscan = 10; /* Do a limited work trying to find duplicated. */ + listIter li; + listNode *ln; + listRewind(ACLLog,&li); + ACLLogEntry *match = NULL; + while (toscan-- && (ln = listNext(&li)) != NULL) { + ACLLogEntry *current = listNodeValue(ln); + if (ACLLogMatchEntry(current,le)) { + match = current; + listDelNode(ACLLog,ln); + listAddNodeHead(ACLLog,current); + break; + } + } + + /* If there is a match update the entry, otherwise add it as a + * new one. */ + if (match) { + /* We update a few fields of the existing entry and bump the + * counter of events for this entry. */ + sdsfree(match->cinfo); + match->cinfo = le->cinfo; + match->ctime = le->ctime; + match->count++; + + /* Release the old entry. */ + le->cinfo = NULL; + ACLFreeLogEntry(le); + } else { + /* Add it to our list of entires. We'll have to trim the list + * to its maximum size. */ + listAddNodeHead(ACLLog, le); + } } /* ============================================================================= -- GitLab