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 Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
113 ban->name, ban->reason, hexhash, Util_addressToString(&ban->address),
114 ban->time + ban->duration - time(NULL));
116 /* Duration of 0 = forever */
117 if (ban->duration != 0 && ban->time + ban->duration - time(NULL) <= 0) {
120 list_del(&ban->node);
123 banlist_changed = true;
124 if(getBoolConf(SYNC_BANFILE))
130 bool_t Ban_isBanned(client_t *client)
134 list_iterate(itr, &banlist) {
135 ban = list_get_entry(itr, ban_t, node);
136 if (memcmp(ban->hash, client->hash, 20) == 0)
143 bool_t Ban_isBannedAddr(struct sockaddr_storage *address)
148 list_iterate(itr, &banlist) {
149 ban = list_get_entry(itr, ban_t, node);
150 if (ban->address.ss_family == address->ss_family) {
151 if (address->ss_family == AF_INET) {
152 uint32_t a1, a2, mask;
153 mask = (ban->mask == 32) ? UINT32_MAX : (1u << ban->mask) - 1;
154 a1 = (uint32_t)((struct sockaddr_in *)&ban->address)->sin_addr.s_addr & mask;
155 a2 = (uint32_t)((struct sockaddr_in *)address)->sin_addr.s_addr & mask;
160 uint64_t *a1 = (uint64_t *) &((struct sockaddr_in6 *)&ban->address)->sin6_addr.s6_addr;
161 uint64_t *a2 = (uint64_t *) &((struct sockaddr_in6 *)address)->sin6_addr.s6_addr;
163 if (ban->mask == 128)
164 mask[0] = mask[1] = 0xffffffffffffffffULL;
165 else if (ban->mask > 64) {
166 mask[0] = 0xffffffffffffffffULL;
167 mask[1] = SWAPPED(~((1ULL << (128 - ban->mask)) - 1));
169 mask[0] = SWAPPED(~((1ULL << (64 - ban->mask)) - 1));
172 if ((a1[0] & mask[0]) == (a2[0] & mask[0]) &&
173 (a1[1] & mask[1]) == (a2[1] & mask[1]))
182 int Ban_getBanCount(void)
187 message_t *Ban_getBanList(void)
198 msg = Msg_banList_create(bancount);
199 list_iterate(itr, &banlist) {
200 ban = list_get_entry(itr, ban_t, node);
201 gmtime_r(&ban->time, ×pec);
202 strftime(timestr, 32, "%Y-%m-%dT%H:%M:%SZ", ×pec);
203 SSLi_hash2hex(ban->hash, hexhash);
204 memset(address, 0, 16);
206 if(ban->address.ss_family == AF_INET) {
207 memcpy(&address[12], &((struct sockaddr_in *)&ban->address)->sin_addr, 4);
208 memset(&address[10], 0xff, 2);
209 Msg_banList_addEntry(msg, i++, address, ban->mask + 96, ban->name, hexhash, ban->reason, timestr, ban->duration);
211 memcpy(&address, &((struct sockaddr_in6 *)&ban->address)->sin6_addr, 16);
212 Msg_banList_addEntry(msg, i++, address, ban->mask, ban->name, hexhash, ban->reason, timestr, ban->duration);
219 void Ban_clearBanList(void)
222 struct dlist *itr, *save;
223 list_iterate_safe(itr, save, &banlist) {
224 ban = list_get_entry(itr, ban_t, node);
227 list_del(&ban->node);
233 void Ban_putBanList(message_t *msg, int n_bans)
238 char *hexhash, *name, *reason, *start;
239 uint32_t duration, mask;
241 char mappedBytes[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff};
244 for (i = 0; i < n_bans; i++) {
245 Msg_banList_getEntry(msg, i, &address, &mask, &name, &hexhash, &reason, &start, &duration);
246 ban = malloc(sizeof(ban_t));
248 Log_fatal("Out of memory");
249 SSLi_hex2hash(hexhash, ban->hash);
251 if(memcmp(address, mappedBytes, 12) == 0) {
252 memcpy(&((struct sockaddr_in *)&ban->address)->sin_addr, &address[12], 4);
253 ban->address.ss_family = AF_INET;
258 memcpy(&((struct sockaddr_in6 *)&ban->address)->sin6_addr, address, 16);
259 ban->address.ss_family = AF_INET6;
263 ban->reason = strdup(reason);
264 ban->name = strdup(name);
267 * Parse the timestring. We need to set TZ to UTC so that mktime() knows that the info in
268 * struct tm indeed is given in UTC. Otherwise it will use the current locale. There's
269 * apparently no other way to do this...
271 memset(×pec, 0, sizeof(struct tm));
272 strptime(start, "%Y-%m-%dT%H:%M:%S", ×pec);
274 setenv("TZ", "UTC", 1);
276 ban->time = mktime(×pec);
283 ban->duration = duration;
284 list_add_tail(&ban->node, &banlist);
287 banlist_changed = true;
288 if(getBoolConf(SYNC_BANFILE))
292 static void Ban_saveBanFile(void)
299 if (!banlist_changed)
301 file = fopen(getStrConf(BANFILE), "w");
303 Log_warn("Could not save banlist to file %s: %s", getStrConf(BANFILE), strerror(errno));
306 list_iterate(itr, &banlist) {
307 ban = list_get_entry(itr, ban_t, node);
308 SSLi_hash2hex(ban->hash, hexhash);
310 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);
313 banlist_changed = false;
314 Log_info("Banlist file '%s': %d entries written", getStrConf(BANFILE), bancount);
317 static void Ban_readBanFile(void)
320 char line[1024], *hexhash, *address, *name, *reason;
321 uint32_t mask, duration;
326 file = fopen(getStrConf(BANFILE), "r");
328 Log_warn("Could not read banlist file %s: %s", getStrConf(BANFILE), strerror(errno));
331 while (fgets(line, 1024, file) != NULL) {
332 p = strtok(line, ",");
334 p = strtok(NULL, ",");
335 if (p == NULL) break;
337 p = strtok(NULL, ",");
338 if (p == NULL) break;
339 mask = strtoul(p, NULL, 0);
340 p = strtok(NULL, ",");
341 if (p == NULL) break;
342 time = strtoul(p, NULL, 0);
343 p = strtok(NULL, ",");
344 if (p == NULL) break;
345 duration = strtoul(p, NULL, 0);
346 p = strtok(NULL, ",");
347 if (p == NULL) break;
349 p = strtok(NULL, "\n");
350 if (p == NULL) break;
353 ban = malloc(sizeof(ban_t));
355 Log_fatal("Out of memory");
356 memset(ban, 0, sizeof(ban_t));
357 SSLi_hex2hash(hexhash, ban->hash);
358 if (inet_pton(AF_INET, address, &ban->address) == 0) {
359 if (inet_pton(AF_INET6, address, &ban->address) == 0) {
360 Log_warn("Address \"%s\" is illegal!", address);
362 ban->address.ss_family = AF_INET6;
365 ban->address.ss_family = AF_INET;
367 ban->name = strdup(name);
368 ban->reason = strdup(reason);
369 if (ban->name == NULL || ban->reason == NULL)
370 Log_fatal("Out of memory");
372 ban->duration = duration;
374 list_add_tail(&ban->node, &banlist);
376 Log_debug("Banfile: H = '%s' A = '%s' M = %d U = '%s' R = '%s'", hexhash, address, ban->mask, ban->name, ban->reason);
379 Log_info("Banlist file '%s': %d entries read", getStrConf(BANFILE), bancount);