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 Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
94 ban->reason, hexhash, Util_clientAddressToString(client), ban->duration);
98 void Ban_pruneBanned()
103 list_iterate(itr, &banlist) {
104 ban = list_get_entry(itr, ban_t, node);
106 SSLi_hash2hex(ban->hash, hexhash);
107 Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
108 ban->name, ban->reason, hexhash, Util_addressToString(&ban->address)),
109 ban->time + ban->duration - time(NULL));
111 /* Duration of 0 = forever */
112 if (ban->duration != 0 && ban->time + ban->duration - time(NULL) <= 0) {
115 list_del(&ban->node);
118 banlist_changed = true;
119 if(getBoolConf(SYNC_BANFILE))
125 bool_t Ban_isBanned(client_t *client)
129 list_iterate(itr, &banlist) {
130 ban = list_get_entry(itr, ban_t, node);
131 if (memcmp(ban->hash, client->hash, 20) == 0)
138 bool_t Ban_isBannedAddr(struct sockaddr_storage *address)
143 list_iterate(itr, &banlist) {
144 ban = list_get_entry(itr, ban_t, node);
145 if (ban->address.ss_family == address->ss_family) {
146 if (address->ss_family == AF_INET) {
147 uint32_t a1, a2, mask;
148 mask = (ban->mask == 32) ? UINT32_MAX : (1u << ban->mask) - 1;
149 a1 = (uint32_t)((struct sockaddr_in *)&ban->address)->sin_addr.s_addr & mask;
150 a2 = (uint32_t)((struct sockaddr_in *)address)->sin_addr.s_addr & mask;
155 uint64_t *a1 = (uint64_t *) &((struct sockaddr_in6 *)&ban->address)->sin6_addr.s6_addr;
156 uint64_t *a2 = (uint64_t *) &((struct sockaddr_in6 *)address)->sin6_addr.s6_addr;
158 if (ban->mask == 128)
159 mask[0] = mask[1] = 0xffffffffffffffffULL;
160 else if (ban->mask > 64) {
161 mask[0] = 0xffffffffffffffffULL;
162 mask[1] = SWAPPED(~((1ULL << (128 - ban->mask)) - 1));
164 mask[0] = SWAPPED(~((1ULL << (64 - ban->mask)) - 1));
167 if ((a1[0] & mask[0]) == (a2[0] & mask[0]) &&
168 (a1[1] & mask[1]) == (a2[1] & mask[1]))
177 int Ban_getBanCount(void)
182 message_t *Ban_getBanList(void)
193 msg = Msg_banList_create(bancount);
194 list_iterate(itr, &banlist) {
195 ban = list_get_entry(itr, ban_t, node);
196 gmtime_r(&ban->time, ×pec);
197 strftime(timestr, 32, "%Y-%m-%dT%H:%M:%SZ", ×pec);
198 SSLi_hash2hex(ban->hash, hexhash);
199 memset(address, 0, 16);
201 if(ban->address.ss_family == AF_INET) {
202 memcpy(&address[12], &((struct sockaddr_in *)&ban->address)->sin_addr, 4);
203 memset(&address[10], 0xff, 2);
204 Msg_banList_addEntry(msg, i++, address, ban->mask + 96, ban->name, hexhash, ban->reason, timestr, ban->duration);
206 memcpy(&address, &((struct sockaddr_in6 *)&ban->address)->sin6_addr, 16);
207 Msg_banList_addEntry(msg, i++, address, ban->mask, ban->name, hexhash, ban->reason, timestr, ban->duration);
214 void Ban_clearBanList(void)
217 struct dlist *itr, *save;
218 list_iterate_safe(itr, save, &banlist) {
219 ban = list_get_entry(itr, ban_t, node);
222 list_del(&ban->node);
228 void Ban_putBanList(message_t *msg, int n_bans)
233 char *hexhash, *name, *reason, *start;
234 uint32_t duration, mask;
236 char mappedBytes[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff};
239 for (i = 0; i < n_bans; i++) {
240 Msg_banList_getEntry(msg, i, &address, &mask, &name, &hexhash, &reason, &start, &duration);
241 ban = malloc(sizeof(ban_t));
243 Log_fatal("Out of memory");
244 SSLi_hex2hash(hexhash, ban->hash);
246 if(memcmp(address, mappedBytes, 12) == 0) {
247 memcpy(&((struct sockaddr_in *)&ban->address)->sin_addr, &address[12], 4);
248 ban->address.ss_family = AF_INET;
253 memcpy(&((struct sockaddr_in6 *)&ban->address)->sin6_addr, address, 16);
254 ban->address.ss_family = AF_INET6;
258 ban->reason = strdup(reason);
259 ban->name = strdup(name);
262 * Parse the timestring. We need to set TZ to UTC so that mktime() knows that the info in
263 * struct tm indeed is given in UTC. Otherwise it will use the current locale. There's
264 * apparently no other way to do this...
266 memset(×pec, 0, sizeof(struct tm));
267 strptime(start, "%Y-%m-%dT%H:%M:%S", ×pec);
269 setenv("TZ", "UTC", 1);
271 ban->time = mktime(×pec);
278 ban->duration = duration;
279 list_add_tail(&ban->node, &banlist);
282 banlist_changed = true;
283 if(getBoolConf(SYNC_BANFILE))
287 static void Ban_saveBanFile(void)
294 if (!banlist_changed)
296 file = fopen(getStrConf(BANFILE), "w");
298 Log_warn("Could not save banlist to file %s: %s", getStrConf(BANFILE), strerror(errno));
301 list_iterate(itr, &banlist) {
302 ban = list_get_entry(itr, ban_t, node);
303 SSLi_hash2hex(ban->hash, hexhash);
305 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);
308 banlist_changed = false;
309 Log_info("Banlist file '%s': %d entries written", getStrConf(BANFILE), bancount);
312 static void Ban_readBanFile(void)
315 char line[1024], *hexhash, *address, *name, *reason;
316 uint32_t mask, duration;
321 file = fopen(getStrConf(BANFILE), "r");
323 Log_warn("Could not read banlist file %s: %s", getStrConf(BANFILE), strerror(errno));
326 while (fgets(line, 1024, file) != NULL) {
327 p = strtok(line, ",");
329 p = strtok(NULL, ",");
330 if (p == NULL) break;
332 p = strtok(NULL, ",");
333 if (p == NULL) break;
334 mask = strtoul(p, NULL, 0);
335 p = strtok(NULL, ",");
336 if (p == NULL) break;
337 time = strtoul(p, NULL, 0);
338 p = strtok(NULL, ",");
339 if (p == NULL) break;
340 duration = strtoul(p, NULL, 0);
341 p = strtok(NULL, ",");
342 if (p == NULL) break;
344 p = strtok(NULL, "\n");
345 if (p == NULL) break;
348 ban = malloc(sizeof(ban_t));
350 Log_fatal("Out of memory");
351 memset(ban, 0, sizeof(ban_t));
352 SSLi_hex2hash(hexhash, ban->hash);
353 if (inet_pton(AF_INET, address, &ban->address) == 0) {
354 if (inet_pton(AF_INET6, address, &ban->address) == 0) {
355 Log_warn("Address \"%s\" is illegal!", address);
357 ban->address.ss_family = AF_INET6;
360 ban->address.ss_family = AF_INET;
362 ban->name = strdup(name);
363 ban->reason = strdup(reason);
364 if (ban->name == NULL || ban->reason == NULL)
365 Log_fatal("Out of memory");
367 ban->duration = duration;
369 list_add_tail(&ban->node, &banlist);
371 Log_debug("Banfile: H = '%s' A = '%s' M = %d U = '%s' R = '%s'", hexhash, address, ban->mask, ban->name, ban->reason);
374 Log_info("Banlist file '%s': %d entries read", getStrConf(BANFILE), bancount);