Code cleanup
[umurmur.git] / src / ban.c
index 29ad8a3639e58a2f39772a3a1c549bb93017888a..3c7c4ffa656ea26c2ab285192b03f9466d4f08d5 100644 (file)
--- a/src/ban.c
+++ b/src/ban.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2009-2011, Martin Johansson <martin@fatbob.nu>
-   Copyright (C) 2005-2011, Thorvald Natvig <thorvald@natvig.com>
+/* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2014, Thorvald Natvig <thorvald@natvig.com>
 
    All rights reserved.
 
 */
 
 #include <stdlib.h>
+#include <time.h>
 #include "log.h"
 #include "list.h"
 #include "ban.h"
 #include "conf.h"
 #include "ssl.h"
+#include "util.h"
+
+static void Ban_saveBanFile(void);
+static void Ban_readBanFile(void);
+
 
 declare_list(banlist);
 static int bancount; /* = 0 */
+static int ban_duration;
+static bool_t banlist_changed;
+
+void Ban_init(void)
+{
+       ban_duration = getIntConf(BAN_LENGTH);
+       /* Read ban file here */
+       if (getStrConf(BANFILE) != NULL)
+               Ban_readBanFile();
+}
+
+void Ban_deinit(void)
+{
+       /* Save banlist */
+       if (getStrConf(BANFILE) != NULL)
+               Ban_saveBanFile();
+
+       Ban_clearBanList();
+}
 
 void Ban_UserBan(client_t *client, char *reason)
 {
@@ -45,44 +70,62 @@ void Ban_UserBan(client_t *client, char *reason)
        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));
+       if (client->remote_tcp.ss_family == AF_INET) {
+               memcpy(&ban->address, &(((struct sockaddr_in*)&client->remote_tcp)->sin_addr), sizeof(in_addr_t));
+               ban->mask = sizeof(in_addr_t);
+       } else {
+               memcpy(&ban->address, &(((struct sockaddr_in6*)&client->remote_tcp)->sin6_addr), 4 * sizeof(in_addr_t));
+               ban->mask = 4 * sizeof(in_addr_t);
+       }
        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++;
+       banlist_changed = true;
+       if(getBoolConf(SYNC_BANFILE))
+               Ban_saveBanFile();
+
        SSLi_hash2hex(ban->hash, hexhash);
-       Log_info("User %s 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));
+
+       Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
+               ban->reason, hexhash, Util_clientAddressToString(client), 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);
+                       ban->name, ban->reason, hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
+                       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--;
+                       banlist_changed = true;
+                       if(getBoolConf(SYNC_BANFILE))
+                               Ban_saveBanFile();
                }
        }
 }
@@ -93,22 +136,192 @@ bool_t Ban_isBanned(client_t *client)
        ban_t *ban;
        list_iterate(itr, &banlist) {
                ban = list_get_entry(itr, ban_t, node);
-               if (memcmp(ban->hash, client->hash, 20) == 0) 
+               if (memcmp(ban->hash, client->hash, 20) == 0)
                        return true;
        }
        return false;
-       
+
 }
 
-bool_t Ban_isBannedAddr(in_addr_t *addr)
+bool_t Ban_isBannedAddr(struct sockaddr_storage *address)
 {
        struct dlist *itr;
        ban_t *ban;
+       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) 
-                       return true;
+
+               if(ban->mask == sizeof(in_addr_t)) {
+                       if(memcmp(ban->address, &((struct sockaddr_in *)address)->sin_addr, ban->mask) == 0)
+                               return true;
+               }
+               else {
+                       if(memcmp(ban->address, &((struct sockaddr_in6 *)address)->sin6_addr, ban->mask) == 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(void)
+{
+       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);
+               ban->startTime = ban->time * 1000000LL;
+               ban->duration = duration;
+               list_add_tail(&ban->node, &banlist);
+               bancount++;
+       }
+       banlist_changed = true;
+       if(getBoolConf(SYNC_BANFILE))
+               Ban_saveBanFile();
+}
+
+static void Ban_saveBanFile(void)
+{
+       struct dlist *itr;
+       ban_t *ban;
+       char hexhash[41];
+       FILE *file;
+
+       if (!banlist_changed)
+               return;
+       file = fopen(getStrConf(BANFILE), "w");
+       if (file == NULL) {
+               Log_warn("Could not save banlist to file %s: %s", getStrConf(BANFILE), strerror(errno));
+               return;
+       }
+       list_iterate(itr, &banlist) {
+               ban = list_get_entry(itr, ban_t, node);
+               SSLi_hash2hex(ban->hash, hexhash);
+               fprintf(file, "%s,%s,%d,%ld,%d,%s,%s\n", hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
+                       ban->mask, (long int)ban->time, ban->duration, ban->name, ban->reason);
+       }
+       fclose(file);
+       banlist_changed = false;
+       Log_info("Banlist file '%s': %d entries written", getStrConf(BANFILE), bancount);
+}
+
+static void Ban_readBanFile(void)
+{
+       struct dlist *itr;
+       ban_t *ban;
+       char line[1024], *hexhash, *address, *name, *reason;
+       uint32_t mask, duration;
+       time_t time;
+       char *p;
+       FILE *file;
+
+       file = fopen(getStrConf(BANFILE), "r");
+       if (file == NULL) {
+               Log_warn("Could not read banlist file %s: %s", getStrConf(BANFILE), strerror(errno));
+               return;
+       }
+       while (fgets(line, 1024, file) != NULL) {
+               p = strtok(line, ",");
+               hexhash = p;
+               p = strtok(NULL, ",");
+               if (p == NULL) break;
+               address = p;
+               p = strtok(NULL, ",");
+               if (p == NULL) break;
+               mask = strtoul(p, NULL, 0);
+               p = strtok(NULL, ",");
+               if (p == NULL) break;
+               time = strtoul(p, NULL, 0);
+               p = strtok(NULL, ",");
+               if (p == NULL) break;
+               duration = strtoul(p, NULL, 0);
+               p = strtok(NULL, ",");
+               if (p == NULL) break;
+               name = p;
+               p = strtok(NULL, "\n");
+               if (p == NULL) break;
+               reason = p;
+
+               ban = malloc(sizeof(ban_t));
+               if (ban == NULL)
+                       Log_fatal("Out of memory");
+               memset(ban, 0, sizeof(ban_t));
+               SSLi_hex2hash(hexhash, ban->hash);
+               inet_aton(address, (struct in_addr *)&ban->address);
+               ban->name = strdup(name);
+               ban->reason = strdup(reason);
+               if (ban->name == NULL || ban->reason == NULL)
+                       Log_fatal("Out of memory");
+               ban->time = time;
+               ban->duration = duration;
+               ban->mask = mask;
+               ban->startTime = ban->time * 1000000LL;
+               list_add_tail(&ban->node, &banlist);
+               bancount++;
+               Log_debug("Banfile: H = '%s' A = '%s' M = %d U = '%s' R = '%s'", hexhash, address, ban->mask, ban->name, ban->reason);
+       }
+       fclose(file);
+       Log_info("Banlist file '%s': %d entries read", getStrConf(BANFILE), bancount);
+}