Add banlist message handling. Bans can now be edited, added and removed via the banli...
[umurmur.git] / src / ban.c
index fbf711ac22a6762cf66013e9cbec07774fd6a667..710148508e2be5bb4f49a1bf9799dc53ef50db42 100644 (file)
--- a/src/ban.c
+++ b/src/ban.c
@@ -30,6 +30,7 @@
 */
 
 #include <stdlib.h>
+#include <time.h>
 #include "log.h"
 #include "list.h"
 #include "ban.h"
 
 declare_list(banlist);
 static int bancount; /* = 0 */
+static int ban_duration;
 
+void Ban_init(void)
+{
+       ban_duration = getIntConf(BAN_LENGTH);
+       /* Read ban file here */
+}
+
+void Ban_deinit(void)
+{
+       /* Save banlist */
+}
 void Ban_UserBan(client_t *client, char *reason)
 {
        ban_t *ban;
        char hexhash[41];
 
        ban = malloc(sizeof(ban_t));
+       if (ban == NULL)
+               Log_fatal("Out of memory");
+       memset(ban, 0, sizeof(ban_t));
+       
        memcpy(ban->hash, client->hash, 20);
        memcpy(&ban->address, &client->remote_tcp.sin_addr, sizeof(in_addr_t));
+       ban->mask = 128;
        ban->reason = strdup(reason);
        ban->name = strdup(client->username);
+       ban->time = time(NULL);
+       ban->duration = ban_duration;
        Timer_init(&ban->startTime);
        list_add_tail(&ban->node, &banlist);
+       bancount++;
        
        SSLi_hash2hex(ban->hash, hexhash);
        Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
                        ban->name, ban->reason, hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
-                       getIntConf(BAN_LENGTH));
+                       ban->duration);
 }
 
 
 void Ban_pruneBanned()
 {
        struct dlist *itr;
-       static int64_t bantime = 0;
        ban_t *ban;
        char hexhash[41];
-       
-       if (bantime == 0) {
-               bantime = getIntConf(BAN_LENGTH) * 1000000LL;
-       }
-       
+       uint64_t bantime_long;
+               
        list_iterate(itr, &banlist) {
                ban = list_get_entry(itr, ban_t, node);
+               bantime_long = ban->duration * 1000000LL;
 #ifdef DEBUG
                SSLi_hash2hex(ban->hash, hexhash);
                Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
                          ban->name, ban->reason, hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
-                         bantime / 1000000LL - Timer_elapsed(&ban->startTime) / 1000000LL);
+                         bantime_long / 1000000LL - Timer_elapsed(&ban->startTime) / 1000000LL);
 #endif
-               if (Timer_isElapsed(&ban->startTime, bantime)) {
+               /* Duration of 0 = forever */
+               if (ban->duration != 0 && Timer_isElapsed(&ban->startTime, bantime_long)) {
                        free(ban->name);
                        free(ban->reason);
                        list_del(&ban->node);
                        free(ban);
+                       bancount--;
                }
        }
 }
@@ -104,11 +123,95 @@ bool_t Ban_isBannedAddr(in_addr_t *addr)
 {
        struct dlist *itr;
        ban_t *ban;
+       int mask;
+       in_addr_t tempaddr1, tempaddr2;
+       
        list_iterate(itr, &banlist) {
                ban = list_get_entry(itr, ban_t, node);
-               if (memcmp(&ban->address, addr, sizeof(in_addr_t)) == 0) 
+               mask = ban->mask - 96;
+               if (mask < 32) { /* XXX - only ipv4 support */
+                       memcpy(&tempaddr1, addr, sizeof(in_addr_t));
+                       memcpy(&tempaddr2, &ban->address, sizeof(in_addr_t));
+                       tempaddr1 &= (2 ^ mask) - 1;
+                       tempaddr2 &= (2 ^ mask) - 1;
+               }
+               if (memcmp(&tempaddr1, &tempaddr2, sizeof(in_addr_t)) == 0) 
                        return true;
        }
        return false;
 }
 
+int Ban_getBanCount(void)
+{
+       return bancount;
+}
+
+message_t *Ban_getBanList(void)
+{
+       int i = 0;
+       struct dlist *itr;
+       ban_t *ban;
+       message_t *msg;
+       struct tm timespec;
+       char timestr[32];
+       char hexhash[41];
+       uint8_t address[16];
+       
+       msg = Msg_banList_create(bancount);
+       list_iterate(itr, &banlist) {
+               ban = list_get_entry(itr, ban_t, node);
+               gmtime_r(&ban->time, &timespec);
+               strftime(timestr, 32, "%Y-%m-%dT%H:%M:%S", &timespec);
+               SSLi_hash2hex(ban->hash, hexhash);
+               /* ipv4 representation as ipv6 address. */
+               memset(address, 0, 16);
+               memcpy(&address[12], &ban->address, 4);
+               memset(&address[10], 0xff, 2); /* IPv4 */
+               Msg_banList_addEntry(msg, i++, address, ban->mask, ban->name,
+                                    hexhash, ban->reason, timestr, ban->duration);
+       }
+       return msg;
+}
+
+void Ban_clearBanList()
+{
+       ban_t *ban;
+       struct dlist *itr, *save;
+       list_iterate_safe(itr, save, &banlist) {
+               ban = list_get_entry(itr, ban_t, node);
+               free(ban->name);
+               free(ban->reason);
+               list_del(&ban->node);
+               free(ban);
+               bancount--;
+       }
+}
+
+void Ban_putBanList(message_t *msg, int n_bans)
+{
+       int i = 0;
+       struct tm timespec;
+       ban_t *ban;
+       char *hexhash, *name, *reason, *start;
+       uint32_t duration, mask;
+       uint8_t *address;
+       
+       for (i = 0; i < n_bans; i++) {
+               Msg_banList_getEntry(msg, i, &address, &mask, &name, &hexhash, &reason, &start, &duration);
+               ban = malloc(sizeof(ban_t));
+               if (ban == NULL)
+                       Log_fatal("Out of memory");
+               memset(ban, 0, sizeof(ban_t));
+               SSLi_hex2hash(hexhash, ban->hash);
+               memcpy(&ban->address, &address[12], 4);
+               ban->mask = mask;
+               ban->reason = strdup(reason);
+               ban->name = strdup(name);
+               strptime(start, "%Y-%m-%dT%H:%M:%S", &timespec);
+               ban->time = mktime(&timespec);
+               Timer_init(&ban->startTime);
+               ban->duration = duration;
+               list_add_tail(&ban->node, &banlist);
+               bancount++;
+       }
+}