storage.c.patch   [plain text]


--- /tmp/jabberd-2.2.13/sm/storage.c	2011-02-23 08:24:34.000000000 -0800
+++ ./jabberd2/sm/storage.c	2011-02-24 16:25:21.000000000 -0800
@@ -486,3 +486,46 @@ int storage_match(st_filter_t filter, os
 
     return _storage_match(filter, o, os);
 }
+
+// Rate limit check:  Prevent denial-of-service due to excessive database queries
+// Make sure owner is responsible for the query!
+st_ret_t storage_rate_limit(storage_t st, const char *owner) {
+    rate_t rt;
+    user_t user;
+    sess_t sess;
+    item_t item;
+
+    if (owner == NULL)
+    return st_SUCCESS;
+
+    user = xhash_get(st->sm->users, owner);
+    if (user != NULL) {
+        rt = (rate_t) xhash_get(st->sm->query_rates, owner);
+        if (rt == NULL) {
+            rt = rate_new(st->sm->query_rate_total, st->sm->query_rate_seconds, st->sm->query_rate_wait);
+            xhash_put(st->sm->query_rates, pstrdup(xhash_pool(st->sm->query_rates), owner), (void *) rt);
+            pool_cleanup(xhash_pool(st->sm->query_rates), (void (*)(void *)) rate_free, rt);
+        }
+
+        if(rate_check(rt) == 0) {
+            log_write(st->sm->log, LOG_WARNING, "[%s] is being disconnected, too many database queries within %d seconds", owner, st->sm->query_rate_seconds);
+            user = xhash_get(st->sm->users, owner);
+            for (sess = user->sessions; sess != NULL; sess = sess->next) {
+                sm_c2s_action(sess, "ended", NULL);
+            }
+            if(xhash_iter_first(user->roster))
+                do {
+                    xhash_iter_get(user->roster, NULL, NULL, (void *) &item);
+                    if(item->to) {
+                        pkt_router(pkt_create(user->sm, "presence", "unavailable", jid_full(item->jid), jid_full(user->jid)));
+                    }
+                } while(xhash_iter_next(user->roster));
+            return st_RATELIMITED;
+            } else {
+                rate_add(rt, 1);
+            }
+        } else {
+            log_debug(ZONE, "Error: could not get user data for %s", owner);
+    }
+    return st_SUCCESS;
+}