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);
111 SSLi_hash2hex(ban->hash, hexhash);
112 char *addressString = Util_addressToString(&ban->address);
113 Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
114 ban->name, ban->reason, hexhash, addressString,
115 ban->time + ban->duration - time(NULL));
118 /* Duration of 0 = forever */
119 if (ban->duration != 0 && ban->time + ban->duration - time(NULL) <= 0) {
122 list_del(&ban->node);
125 banlist_changed = true;
126 if(getBoolConf(SYNC_BANFILE))
132 bool_t Ban_isBanned(client_t *client)
136 list_iterate(itr, &banlist) {
137 ban = list_get_entry(itr, ban_t, node);
138 if (memcmp(ban->hash, client->hash, 20) == 0)
145 bool_t Ban_isBannedAddr(struct sockaddr_storage *address)
150 list_iterate(itr, &banlist) {
151 ban = list_get_entry(itr, ban_t, node);
152 if (ban->address.ss_family == address->ss_family) {
153 if (address->ss_family == AF_INET) {
154 uint32_t a1, a2, mask;
155 mask = (ban->mask == 32) ? UINT32_MAX : (1u << ban->mask) - 1;
156 a1 = (uint32_t)((struct sockaddr_in *)&ban->address)->sin_addr.s_addr & mask;
157 a2 = (uint32_t)((struct sockaddr_in *)address)->sin_addr.s_addr & mask;
162 uint64_t *a1 = (uint64_t *) &((struct sockaddr_in6 *)&ban->address)->sin6_addr.s6_addr;
163 uint64_t *a2 = (uint64_t *) &((struct sockaddr_in6 *)address)->sin6_addr.s6_addr;
165 if (ban->mask == 128)
166 mask[0] = mask[1] = 0xffffffffffffffffULL;
167 else if (ban->mask > 64) {
168 mask[0] = 0xffffffffffffffffULL;
169 mask[1] = SWAPPED(~((1ULL << (128 - ban->mask)) - 1));
171 mask[0] = SWAPPED(~((1ULL << (64 - ban->mask)) - 1));
174 if ((a1[0] & mask[0]) == (a2[0] & mask[0]) &&
175 (a1[1] & mask[1]) == (a2[1] & mask[1]))
184 int Ban_getBanCount(void)
189 message_t *Ban_getBanList(void)
200 msg = Msg_banList_create(bancount);
201 list_iterate(itr, &banlist) {
202 ban = list_get_entry(itr, ban_t, node);
203 gmtime_r(&ban->time, ×pec);
204 strftime(timestr, 32, "%Y-%m-%dT%H:%M:%SZ", ×pec);
205 SSLi_hash2hex(ban->hash, hexhash);
206 memset(address, 0, 16);
208 if(ban->address.ss_family == AF_INET) {
209 memcpy(&address[12], &((struct sockaddr_in *)&ban->address)->sin_addr, 4);
210 memset(&address[10], 0xff, 2);
211 Msg_banList_addEntry(msg, i++, address, ban->mask + 96, ban->name, hexhash, ban->reason, timestr, ban->duration);
213 memcpy(&address, &((struct sockaddr_in6 *)&ban->address)->sin6_addr, 16);
214 Msg_banList_addEntry(msg, i++, address, ban->mask, ban->name, hexhash, ban->reason, timestr, ban->duration);
221 void Ban_clearBanList(void)
224 struct dlist *itr, *save;
225 list_iterate_safe(itr, save, &banlist) {
226 ban = list_get_entry(itr, ban_t, node);
229 list_del(&ban->node);
235 void Ban_putBanList(message_t *msg, int n_bans)
240 char *hexhash, *name, *reason, *start;
241 uint32_t duration, mask;
243 char mappedBytes[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff};
246 for (i = 0; i < n_bans; i++) {
247 Msg_banList_getEntry(msg, i, &address, &mask, &name, &hexhash, &reason, &start, &duration);
248 ban = malloc(sizeof(ban_t));
250 Log_fatal("Out of memory");
251 SSLi_hex2hash(hexhash, ban->hash);
253 if(memcmp(address, mappedBytes, 12) == 0) {
254 memcpy(&((struct sockaddr_in *)&ban->address)->sin_addr, &address[12], 4);
255 ban->address.ss_family = AF_INET;
260 memcpy(&((struct sockaddr_in6 *)&ban->address)->sin6_addr, address, 16);
261 ban->address.ss_family = AF_INET6;
265 ban->reason = strdup(reason);
266 ban->name = strdup(name);
269 * Parse the timestring. We need to set TZ to UTC so that mktime() knows that the info in
270 * struct tm indeed is given in UTC. Otherwise it will use the current locale. There's
271 * apparently no other way to do this...
273 memset(×pec, 0, sizeof(struct tm));
274 strptime(start, "%Y-%m-%dT%H:%M:%S", ×pec);
276 setenv("TZ", "UTC", 1);
278 ban->time = mktime(×pec);
285 ban->duration = duration;
286 list_add_tail(&ban->node, &banlist);
289 banlist_changed = true;
290 if(getBoolConf(SYNC_BANFILE))
294 static void Ban_saveBanFile(void)
301 if (!banlist_changed)
303 file = fopen(getStrConf(BANFILE), "w");
305 Log_warn("Could not save banlist to file %s: %s", getStrConf(BANFILE), strerror(errno));
308 list_iterate(itr, &banlist) {
309 ban = list_get_entry(itr, ban_t, node);
310 SSLi_hash2hex(ban->hash, hexhash);
312 char *addressString = Util_addressToString(&ban->address);
313 fprintf(file, "%s,%s,%d,%ld,%d,%s,%s\n", hexhash, addressString,ban->mask, (long int)ban->time, ban->duration, ban->name, ban->reason);
317 banlist_changed = false;
318 Log_info("Banlist file '%s': %d entries written", getStrConf(BANFILE), bancount);
321 static void Ban_readBanFile(void)
324 char line[1024], *hexhash, *address, *name, *reason;
325 uint32_t mask, duration;
330 file = fopen(getStrConf(BANFILE), "r");
332 Log_warn("Could not read banlist file %s: %s", getStrConf(BANFILE), strerror(errno));
335 while (fgets(line, 1024, file) != NULL) {
336 p = strtok(line, ",");
338 p = strtok(NULL, ",");
339 if (p == NULL) break;
341 p = strtok(NULL, ",");
342 if (p == NULL) break;
343 mask = strtoul(p, NULL, 0);
344 p = strtok(NULL, ",");
345 if (p == NULL) break;
346 time = strtoul(p, NULL, 0);
347 p = strtok(NULL, ",");
348 if (p == NULL) break;
349 duration = strtoul(p, NULL, 0);
350 p = strtok(NULL, ",");
351 if (p == NULL) break;
353 p = strtok(NULL, "\n");
354 if (p == NULL) break;
357 ban = malloc(sizeof(ban_t));
359 Log_fatal("Out of memory");
360 memset(ban, 0, sizeof(ban_t));
361 SSLi_hex2hash(hexhash, ban->hash);
362 if (inet_pton(AF_INET, address, &ban->address) == 0) {
363 if (inet_pton(AF_INET6, address, &ban->address) == 0) {
364 Log_warn("Address \"%s\" is illegal!", address);
366 ban->address.ss_family = AF_INET6;
369 ban->address.ss_family = AF_INET;
371 ban->name = strdup(name);
372 ban->reason = strdup(reason);
373 if (ban->name == NULL || ban->reason == NULL)
374 Log_fatal("Out of memory");
376 ban->duration = duration;
378 list_add_tail(&ban->node, &banlist);
380 Log_debug("Banfile: H = '%s' A = '%s' M = %d U = '%s' R = '%s'", hexhash, address, ban->mask, ban->name, ban->reason);
383 Log_info("Banlist file '%s': %d entries read", getStrConf(BANFILE), bancount);