summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2020-01-29 18:40:32 +0100
committerantirez <antirez@gmail.com>2020-01-29 18:40:32 +0100
commit6671032fafc82be04b4ca564790753b26f96780e (patch)
tree1d16492810efd66f0c41ce9a9bedefe8c89c7f13
parent61dffd8669bdc16f26c67c0ec8955a0d8a627ef8 (diff)
downloadredis-6671032fafc82be04b4ca564790753b26f96780e.tar.gz
ACL LOG: group similar entries in a given time delta.
-rw-r--r--src/acl.c61
1 files 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);
+ }
}
/* =============================================================================