Use Memory_safeCalloc() to allocate zeroed memory.
[umurmur.git] / src / ban.c
index 667bdc8ecec353114b7e8a65e9db2c2b39f45795..84e95dc174e7a3ed881b616a70f4a75d39f573b6 100644 (file)
--- a/src/ban.c
+++ b/src/ban.c
@@ -33,6 +33,7 @@
 #include <time.h>
 #include <string.h>
 #include "log.h"
+#include "memory.h"
 #include "list.h"
 #include "ban.h"
 #include "conf.h"
@@ -70,9 +71,7 @@ void Ban_UserBan(client_t *client, char *reason)
        ban_t *ban;
        char hexhash[41];
 
-       ban = calloc(1, sizeof(ban_t));
-       if (ban == NULL)
-               Log_fatal("Out of memory");
+       ban = Memory_safeCalloc(1, sizeof(ban_t));
 
        memcpy(ban->hash, client->hash, 20);
 
@@ -82,7 +81,6 @@ void Ban_UserBan(client_t *client, char *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;
@@ -91,8 +89,12 @@ void Ban_UserBan(client_t *client, char *reason)
 
        SSLi_hash2hex(ban->hash, hexhash);
 
+       char *clientAddressString = Util_clientAddressToString(client);
+
        Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
-               ban->reason, hexhash, Util_clientAddressToString(client), ban->duration);
+               ban->reason, hexhash, clientAddressString, ban->duration);
+
+       free(clientAddressString);
 }
 
 
@@ -100,19 +102,20 @@ void Ban_pruneBanned()
 {
        struct dlist *itr;
        ban_t *ban;
-       uint64_t bantime_long;
 
        list_iterate(itr, &banlist) {
                ban = list_get_entry(itr, ban_t, node);
-               bantime_long = ban->duration * 1000000LL;
 #ifdef DEBUG
+               char hexhash[41];
                SSLi_hash2hex(ban->hash, hexhash);
+               char *addressString = Util_addressToString(&ban->address);
                Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
-                       ban->name, ban->reason, hexhash, Util_addressToString(&ban->address)),
-                       bantime_long / 1000000LL - Timer_elapsed(&ban->startTime) / 1000000LL);
+                       ban->name, ban->reason, hexhash, addressString,
+                       ban->time + ban->duration - time(NULL));
+               free(addressString);
 #endif
                /* Duration of 0 = forever */
-               if (ban->duration != 0 && Timer_isElapsed(&ban->startTime, bantime_long)) {
+               if (ban->duration != 0 && ban->time + ban->duration - time(NULL) <= 0) {
                        free(ban->name);
                        free(ban->reason);
                        list_del(&ban->node);
@@ -142,41 +145,36 @@ bool_t Ban_isBannedAddr(struct sockaddr_storage *address)
 {
        struct dlist *itr;
        ban_t *ban;
-       uint64_t clientAddressBytes[2] = {0};
-       uint64_t banAddressBytes[2] = {0};
-       uint64_t banMaskBits[2] = {UINT64_MAX};
-
-       if (address->ss_family == AF_INET) {
-               memcpy(clientAddressBytes, &((struct sockaddr_in *)address)->sin_addr, 4);
-       } else {
-               memcpy(clientAddressBytes, &((struct sockaddr_in6 *)address)->sin6_addr, 16);
-       }
 
        list_iterate(itr, &banlist) {
                ban = list_get_entry(itr, ban_t, node);
-
-               if(address->ss_len == ban->address.ss_family) {
-                       if (ban->address.ss_family == AF_INET) {
-                               memcpy(banAddressBytes, &((struct sockaddr_in *)&ban->address)->sin_addr, 4);
+               if (ban->address.ss_family == address->ss_family) {
+                       if (address->ss_family == AF_INET) {
+                               uint32_t a1, a2, mask;
+                               mask = (ban->mask == 32) ? UINT32_MAX : (1u << ban->mask) - 1;
+                               a1 = (uint32_t)((struct sockaddr_in *)&ban->address)->sin_addr.s_addr & mask;
+                               a2 = (uint32_t)((struct sockaddr_in *)address)->sin_addr.s_addr & mask;
+                               if (a1 == a2)
+                                       return true;
                        } else {
-                               memcpy(banAddressBytes, &((struct sockaddr_in6 *)&ban->address)->sin6_addr, 16);
+                               uint64_t mask[2];
+                               uint64_t *a1 = (uint64_t *) &((struct sockaddr_in6 *)&ban->address)->sin6_addr.s6_addr;
+                               uint64_t *a2 = (uint64_t *) &((struct sockaddr_in6 *)address)->sin6_addr.s6_addr;
+
+                               if (ban->mask == 128)
+                                       mask[0] = mask[1] = 0xffffffffffffffffULL;
+                               else if (ban->mask > 64) {
+                                       mask[0] = 0xffffffffffffffffULL;
+                                       mask[1] = SWAPPED(~((1ULL << (128 - ban->mask)) - 1));
+                               } else {
+                                       mask[0] = SWAPPED(~((1ULL << (64 - ban->mask)) - 1));
+                                       mask[1] = 0ULL;
+                               }
+                               if ((a1[0] & mask[0]) == (a2[0] & mask[0]) &&
+                                   (a1[1] & mask[1]) == (a2[1] & mask[1]))
+                                   return true;
                        }
-
-                       banMaskBits[0] <<= (ban->mask >= 64) ? 0 : 64 - ban->mask;
-                       banMaskBits[1] <<= (ban->mask > 64) ? 128 - ban->mask : 64;
-
-                       clientAddressBytes[0] &= banMaskBits[0];
-                       clientAddressBytes[1] &= banMaskBits[1];
-
-                       banAddressBytes[0] &= banMaskBits[0];
-                       banAddressBytes[1] &= banMaskBits[1];
-
-                       if (memcmp(clientAddressBytes, banAddressBytes, 16) == 0) {
-                               return true;
-                       }
-
                }
-
        }
 
        return false;
@@ -202,7 +200,7 @@ message_t *Ban_getBanList(void)
        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);
+               strftime(timestr, 32, "%Y-%m-%dT%H:%M:%SZ", &timespec);
                SSLi_hash2hex(ban->hash, hexhash);
                memset(address, 0, 16);
 
@@ -242,12 +240,11 @@ void Ban_putBanList(message_t *msg, int n_bans)
        uint32_t duration, mask;
        uint8_t *address;
        char mappedBytes[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff};
+       char *tz;
 
        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");
+               ban = Memory_safeMalloc(1, sizeof(ban_t));
                SSLi_hex2hash(hexhash, ban->hash);
 
                if(memcmp(address, mappedBytes, 12) == 0) {
@@ -264,9 +261,24 @@ void Ban_putBanList(message_t *msg, int n_bans)
                ban->mask = mask;
                ban->reason = strdup(reason);
                ban->name = strdup(name);
+
+               /*
+                * Parse the timestring. We need to set TZ to UTC so that mktime() knows that the info in
+                * struct tm indeed is given in UTC. Otherwise it will use the current locale. There's
+                * apparently no other way to do this...
+                */
+               memset(&timespec, 0, sizeof(struct tm));
                strptime(start, "%Y-%m-%dT%H:%M:%S", &timespec);
+               tz = getenv("TZ");
+               setenv("TZ", "UTC", 1);
+               tzset();
                ban->time = mktime(&timespec);
-               ban->startTime = ban->time * 1000000LL;
+               if (tz)
+                       setenv("TZ", tz, 1);
+               else
+                       unsetenv("TZ");
+               tzset();
+
                ban->duration = duration;
                list_add_tail(&ban->node, &banlist);
                bancount++;
@@ -294,7 +306,9 @@ static void Ban_saveBanFile(void)
                ban = list_get_entry(itr, ban_t, node);
                SSLi_hash2hex(ban->hash, hexhash);
 
-               fprintf(file, "%s,%s,%d,%ld,%d,%s,%s\n", hexhash, Util_addressToString(&ban->address),ban->mask, (long int)ban->time, ban->duration, ban->name, ban->reason);
+               char *addressString = Util_addressToString(&ban->address);
+               fprintf(file, "%s,%s,%d,%ld,%d,%s,%s\n", hexhash, addressString,ban->mask, (long int)ban->time, ban->duration, ban->name, ban->reason);
+               free(addressString);
        }
        fclose(file);
        banlist_changed = false;
@@ -337,10 +351,7 @@ static void Ban_readBanFile(void)
                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));
+               ban = Memory_safeCalloc(1, sizeof(ban_t));
                SSLi_hex2hash(hexhash, ban->hash);
                if (inet_pton(AF_INET, address, &ban->address) == 0) {
                        if (inet_pton(AF_INET6, address, &ban->address) == 0) {
@@ -358,7 +369,6 @@ static void Ban_readBanFile(void)
                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);