1 /* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2014, Thorvald Natvig <thorvald@natvig.com>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 - Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 - Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15 - Neither the name of the Developers nor the names of its contributors may
16 be used to endorse or promote products derived from this software without
17 specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 static void Ban_saveBanFile(void);
43 static void Ban_readBanFile(void);
46 declare_list(banlist);
47 static int bancount; /* = 0 */
48 static int ban_duration;
49 static bool_t banlist_changed;
53 ban_duration = getIntConf(BAN_LENGTH);
54 /* Read ban file here */
55 if (getStrConf(BANFILE) != NULL)
62 if (getStrConf(BANFILE) != NULL)
68 void Ban_UserBan(client_t *client, char *reason)
73 ban = calloc(1, sizeof(ban_t));
75 Log_fatal("Out of memory");
77 memcpy(ban->hash, client->hash, 20);
79 ban->address = client->remote_tcp;
80 ban->mask = (ban->address.ss_family == AF_INET) ? 32 : 128;
81 ban->reason = strdup(reason);
82 ban->name = strdup(client->username);
83 ban->time = time(NULL);
84 ban->duration = ban_duration;
85 list_add_tail(&ban->node, &banlist);
87 banlist_changed = true;
88 if(getBoolConf(SYNC_BANFILE))
91 SSLi_hash2hex(ban->hash, hexhash);
93 char *clientAddressString = Util_clientAddressToString(client);
95 Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
96 ban->reason, hexhash, clientAddressString, ban->duration);
98 free(clientAddressString);
102 void Ban_pruneBanned()
107 list_iterate(itr, &banlist) {
108 ban = list_get_entry(itr, ban_t, node);
110 SSLi_hash2hex(ban->hash, hexhash);
111 Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
112 ban->name, ban->reason, hexhash, Util_addressToString(&ban->address)),
113 ban->time + ban->duration - time(NULL));
115 /* Duration of 0 = forever */
116 if (ban->duration != 0 && ban->time + ban->duration - time(NULL) <= 0) {
119 list_del(&ban->node);
122 banlist_changed = true;
123 if(getBoolConf(SYNC_BANFILE))
129 bool_t Ban_isBanned(client_t *client)
133 list_iterate(itr, &banlist) {
134 ban = list_get_entry(itr, ban_t, node);
135 if (memcmp(ban->hash, client->hash, 20) == 0)
142 bool_t Ban_isBannedAddr(struct sockaddr_storage *address)
147 list_iterate(itr, &banlist) {
148 ban = list_get_entry(itr, ban_t, node);
149 if (ban->address.ss_family == address->ss_family) {
150 if (address->ss_family == AF_INET) {
151 uint32_t a1, a2, mask;
152 mask = (ban->mask == 32) ? UINT32_MAX : (1u << ban->mask) - 1;
153 a1 = (uint32_t)((struct sockaddr_in *)&ban->address)->sin_addr.s_addr & mask;
154 a2 = (uint32_t)((struct sockaddr_in *)address)->sin_addr.s_addr & mask;
159 uint64_t *a1 = (uint64_t *) &((struct sockaddr_in6 *)&ban->address)->sin6_addr.s6_addr;
160 uint64_t *a2 = (uint64_t *) &((struct sockaddr_in6 *)address)->sin6_addr.s6_addr;
162 if (ban->mask == 128)
163 mask[0] = mask[1] = 0xffffffffffffffffULL;
164 else if (ban->mask > 64) {
165 mask[0] = 0xffffffffffffffffULL;
166 mask[1] = SWAPPED(~((1ULL << (128 - ban->mask)) - 1));
168 mask[0] = SWAPPED(~((1ULL << (64 - ban->mask)) - 1));
171 if ((a1[0] & mask[0]) == (a2[0] & mask[0]) &&
172 (a1[1] & mask[1]) == (a2[1] & mask[1]))
181 int Ban_getBanCount(void)
186 message_t *Ban_getBanList(void)
197 msg = Msg_banList_create(bancount);
198 list_iterate(itr, &banlist) {
199 ban = list_get_entry(itr, ban_t, node);
200 gmtime_r(&ban->time, ×pec);
201 strftime(timestr, 32, "%Y-%m-%dT%H:%M:%SZ", ×pec);
202 SSLi_hash2hex(ban->hash, hexhash);
203 memset(address, 0, 16);
205 if(ban->address.ss_family == AF_INET) {
206 memcpy(&address[12], &((struct sockaddr_in *)&ban->address)->sin_addr, 4);
207 memset(&address[10], 0xff, 2);
208 Msg_banList_addEntry(msg, i++, address, ban->mask + 96, ban->name, hexhash, ban->reason, timestr, ban->duration);
210 memcpy(&address, &((struct sockaddr_in6 *)&ban->address)->sin6_addr, 16);
211 Msg_banList_addEntry(msg, i++, address, ban->mask, ban->name, hexhash, ban->reason, timestr, ban->duration);
218 void Ban_clearBanList(void)
221 struct dlist *itr, *save;
222 list_iterate_safe(itr, save, &banlist) {
223 ban = list_get_entry(itr, ban_t, node);
226 list_del(&ban->node);
232 void Ban_putBanList(message_t *msg, int n_bans)
237 char *hexhash, *name, *reason, *start;
238 uint32_t duration, mask;
240 char mappedBytes[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff};
243 for (i = 0; i < n_bans; i++) {
244 Msg_banList_getEntry(msg, i, &address, &mask, &name, &hexhash, &reason, &start, &duration);
245 ban = malloc(sizeof(ban_t));
247 Log_fatal("Out of memory");
248 SSLi_hex2hash(hexhash, ban->hash);
250 if(memcmp(address, mappedBytes, 12) == 0) {
251 memcpy(&((struct sockaddr_in *)&ban->address)->sin_addr, &address[12], 4);
252 ban->address.ss_family = AF_INET;
257 memcpy(&((struct sockaddr_in6 *)&ban->address)->sin6_addr, address, 16);
258 ban->address.ss_family = AF_INET6;
262 ban->reason = strdup(reason);
263 ban->name = strdup(name);
266 * Parse the timestring. We need to set TZ to UTC so that mktime() knows that the info in
267 * struct tm indeed is given in UTC. Otherwise it will use the current locale. There's
268 * apparently no other way to do this...
270 memset(×pec, 0, sizeof(struct tm));
271 strptime(start, "%Y-%m-%dT%H:%M:%S", ×pec);
273 setenv("TZ", "UTC", 1);
275 ban->time = mktime(×pec);
282 ban->duration = duration;
283 list_add_tail(&ban->node, &banlist);
286 banlist_changed = true;
287 if(getBoolConf(SYNC_BANFILE))
291 static void Ban_saveBanFile(void)
298 if (!banlist_changed)
300 file = fopen(getStrConf(BANFILE), "w");
302 Log_warn("Could not save banlist to file %s: %s", getStrConf(BANFILE), strerror(errno));
305 list_iterate(itr, &banlist) {
306 ban = list_get_entry(itr, ban_t, node);
307 SSLi_hash2hex(ban->hash, hexhash);
309 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);
312 banlist_changed = false;
313 Log_info("Banlist file '%s': %d entries written", getStrConf(BANFILE), bancount);
316 static void Ban_readBanFile(void)
319 char line[1024], *hexhash, *address, *name, *reason;
320 uint32_t mask, duration;
325 file = fopen(getStrConf(BANFILE), "r");
327 Log_warn("Could not read banlist file %s: %s", getStrConf(BANFILE), strerror(errno));
330 while (fgets(line, 1024, file) != NULL) {
331 p = strtok(line, ",");
333 p = strtok(NULL, ",");
334 if (p == NULL) break;
336 p = strtok(NULL, ",");
337 if (p == NULL) break;
338 mask = strtoul(p, NULL, 0);
339 p = strtok(NULL, ",");
340 if (p == NULL) break;
341 time = strtoul(p, NULL, 0);
342 p = strtok(NULL, ",");
343 if (p == NULL) break;
344 duration = strtoul(p, NULL, 0);
345 p = strtok(NULL, ",");
346 if (p == NULL) break;
348 p = strtok(NULL, "\n");
349 if (p == NULL) break;
352 ban = malloc(sizeof(ban_t));
354 Log_fatal("Out of memory");
355 memset(ban, 0, sizeof(ban_t));
356 SSLi_hex2hash(hexhash, ban->hash);
357 if (inet_pton(AF_INET, address, &ban->address) == 0) {
358 if (inet_pton(AF_INET6, address, &ban->address) == 0) {
359 Log_warn("Address \"%s\" is illegal!", address);
361 ban->address.ss_family = AF_INET6;
364 ban->address.ss_family = AF_INET;
366 ban->name = strdup(name);
367 ban->reason = strdup(reason);
368 if (ban->name == NULL || ban->reason == NULL)
369 Log_fatal("Out of memory");
371 ban->duration = duration;
373 list_add_tail(&ban->node, &banlist);
375 Log_debug("Banfile: H = '%s' A = '%s' M = %d U = '%s' R = '%s'", hexhash, address, ban->mask, ban->name, ban->reason);
378 Log_info("Banlist file '%s': %d entries read", getStrConf(BANFILE), bancount);