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.
43 static void Ban_saveBanFile(void);
44 static void Ban_readBanFile(void);
47 declare_list(banlist);
48 static int bancount; /* = 0 */
49 static int ban_duration;
50 static bool_t banlist_changed;
54 ban_duration = getIntConf(BAN_LENGTH);
55 /* Read ban file here */
56 if (getStrConf(BANFILE) != NULL)
63 if (getStrConf(BANFILE) != NULL)
69 void Ban_UserBan(client_t *client, char *reason)
74 ban = Memory_safeCalloc(1, sizeof(ban_t));
76 memcpy(ban->hash, client->hash, 20);
78 ban->address = client->remote_tcp;
79 ban->mask = (ban->address.ss_family == AF_INET) ? 32 : 128;
80 ban->reason = strdup(reason);
81 ban->name = strdup(client->username);
82 ban->time = time(NULL);
83 ban->duration = ban_duration;
84 list_add_tail(&ban->node, &banlist);
86 banlist_changed = true;
87 if(getBoolConf(SYNC_BANFILE))
90 SSLi_hash2hex(ban->hash, hexhash);
92 char *clientAddressString = Util_clientAddressToString(client);
94 Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
95 ban->reason, hexhash, clientAddressString, ban->duration);
97 free(clientAddressString);
101 void Ban_pruneBanned()
106 list_iterate(itr, &banlist) {
107 ban = list_get_entry(itr, ban_t, node);
110 SSLi_hash2hex(ban->hash, hexhash);
111 char *addressString = Util_addressToString(&ban->address);
112 Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
113 ban->name, ban->reason, hexhash, addressString,
114 ban->time + ban->duration - time(NULL));
117 /* Duration of 0 = forever */
118 if (ban->duration != 0 && ban->time + ban->duration - time(NULL) <= 0) {
121 list_del(&ban->node);
124 banlist_changed = true;
125 if(getBoolConf(SYNC_BANFILE))
131 bool_t Ban_isBanned(client_t *client)
135 list_iterate(itr, &banlist) {
136 ban = list_get_entry(itr, ban_t, node);
137 if (memcmp(ban->hash, client->hash, 20) == 0)
144 bool_t Ban_isBannedAddr(struct sockaddr_storage *address)
149 list_iterate(itr, &banlist) {
150 ban = list_get_entry(itr, ban_t, node);
151 if (ban->address.ss_family == address->ss_family) {
152 if (address->ss_family == AF_INET) {
153 uint32_t a1, a2, mask;
154 mask = (ban->mask == 32) ? UINT32_MAX : (1u << ban->mask) - 1;
155 a1 = (uint32_t)((struct sockaddr_in *)&ban->address)->sin_addr.s_addr & mask;
156 a2 = (uint32_t)((struct sockaddr_in *)address)->sin_addr.s_addr & mask;
161 uint64_t *a1 = (uint64_t *) &((struct sockaddr_in6 *)&ban->address)->sin6_addr.s6_addr;
162 uint64_t *a2 = (uint64_t *) &((struct sockaddr_in6 *)address)->sin6_addr.s6_addr;
164 if (ban->mask == 128)
165 mask[0] = mask[1] = 0xffffffffffffffffULL;
166 else if (ban->mask > 64) {
167 mask[0] = 0xffffffffffffffffULL;
168 mask[1] = SWAPPED(~((1ULL << (128 - ban->mask)) - 1));
170 mask[0] = SWAPPED(~((1ULL << (64 - ban->mask)) - 1));
173 if ((a1[0] & mask[0]) == (a2[0] & mask[0]) &&
174 (a1[1] & mask[1]) == (a2[1] & mask[1]))
183 int Ban_getBanCount(void)
188 message_t *Ban_getBanList(void)
199 msg = Msg_banList_create(bancount);
200 list_iterate(itr, &banlist) {
201 ban = list_get_entry(itr, ban_t, node);
202 gmtime_r(&ban->time, ×pec);
203 strftime(timestr, 32, "%Y-%m-%dT%H:%M:%SZ", ×pec);
204 SSLi_hash2hex(ban->hash, hexhash);
205 memset(address, 0, 16);
207 if(ban->address.ss_family == AF_INET) {
208 memcpy(&address[12], &((struct sockaddr_in *)&ban->address)->sin_addr, 4);
209 memset(&address[10], 0xff, 2);
210 Msg_banList_addEntry(msg, i++, address, ban->mask + 96, ban->name, hexhash, ban->reason, timestr, ban->duration);
212 memcpy(&address, &((struct sockaddr_in6 *)&ban->address)->sin6_addr, 16);
213 Msg_banList_addEntry(msg, i++, address, ban->mask, ban->name, hexhash, ban->reason, timestr, ban->duration);
220 void Ban_clearBanList(void)
223 struct dlist *itr, *save;
224 list_iterate_safe(itr, save, &banlist) {
225 ban = list_get_entry(itr, ban_t, node);
228 list_del(&ban->node);
234 void Ban_putBanList(message_t *msg, int n_bans)
239 char *hexhash, *name, *reason, *start;
240 uint32_t duration, mask;
242 char mappedBytes[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff};
245 for (i = 0; i < n_bans; i++) {
246 Msg_banList_getEntry(msg, i, &address, &mask, &name, &hexhash, &reason, &start, &duration);
247 ban = Memory_safeMalloc(1, sizeof(ban_t));
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 char *addressString = Util_addressToString(&ban->address);
310 fprintf(file, "%s,%s,%d,%ld,%d,%s,%s\n", hexhash, addressString,ban->mask, (long int)ban->time, ban->duration, ban->name, ban->reason);
314 banlist_changed = false;
315 Log_info("Banlist file '%s': %d entries written", getStrConf(BANFILE), bancount);
318 static void Ban_readBanFile(void)
321 char line[1024], *hexhash, *address, *name, *reason;
322 uint32_t mask, duration;
327 file = fopen(getStrConf(BANFILE), "r");
329 Log_warn("Could not read banlist file %s: %s", getStrConf(BANFILE), strerror(errno));
332 while (fgets(line, 1024, file) != NULL) {
333 p = strtok(line, ",");
335 p = strtok(NULL, ",");
336 if (p == NULL) break;
338 p = strtok(NULL, ",");
339 if (p == NULL) break;
340 mask = strtoul(p, NULL, 0);
341 p = strtok(NULL, ",");
342 if (p == NULL) break;
343 time = strtoul(p, NULL, 0);
344 p = strtok(NULL, ",");
345 if (p == NULL) break;
346 duration = strtoul(p, NULL, 0);
347 p = strtok(NULL, ",");
348 if (p == NULL) break;
350 p = strtok(NULL, "\n");
351 if (p == NULL) break;
354 ban = Memory_safeCalloc(1, sizeof(ban_t));
355 SSLi_hex2hash(hexhash, ban->hash);
356 if (inet_pton(AF_INET, address, &ban->address) == 0) {
357 if (inet_pton(AF_INET6, address, &ban->address) == 0) {
358 Log_warn("Address \"%s\" is illegal!", address);
360 ban->address.ss_family = AF_INET6;
363 ban->address.ss_family = AF_INET;
365 ban->name = strdup(name);
366 ban->reason = strdup(reason);
367 if (ban->name == NULL || ban->reason == NULL)
368 Log_fatal("Out of memory");
370 ban->duration = duration;
372 list_add_tail(&ban->node, &banlist);
374 Log_debug("Banfile: H = '%s' A = '%s' M = %d U = '%s' R = '%s'", hexhash, address, ban->mask, ban->name, ban->reason);
377 Log_info("Banlist file '%s': %d entries read", getStrConf(BANFILE), bancount);