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 Timer_init(&ban->startTime);
86 list_add_tail(&ban->node, &banlist);
88 banlist_changed = true;
89 if(getBoolConf(SYNC_BANFILE))
92 SSLi_hash2hex(ban->hash, hexhash);
94 Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
95 ban->reason, hexhash, Util_clientAddressToString(client), ban->duration);
99 void Ban_pruneBanned()
103 uint64_t bantime_long;
105 list_iterate(itr, &banlist) {
106 ban = list_get_entry(itr, ban_t, node);
107 bantime_long = ban->duration * 1000000LL;
109 SSLi_hash2hex(ban->hash, hexhash);
110 Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
111 ban->name, ban->reason, hexhash, Util_addressToString(&ban->address)),
112 bantime_long / 1000000LL - Timer_elapsed(&ban->startTime) / 1000000LL);
114 /* Duration of 0 = forever */
115 if (ban->duration != 0 && Timer_isElapsed(&ban->startTime, bantime_long)) {
118 list_del(&ban->node);
121 banlist_changed = true;
122 if(getBoolConf(SYNC_BANFILE))
128 bool_t Ban_isBanned(client_t *client)
132 list_iterate(itr, &banlist) {
133 ban = list_get_entry(itr, ban_t, node);
134 if (memcmp(ban->hash, client->hash, 20) == 0)
141 bool_t Ban_isBannedAddr(struct sockaddr_storage *address)
145 uint64_t clientAddressBytes[2] = {0};
146 uint64_t banAddressBytes[2] = {0};
147 uint64_t banMaskBits[2] = {UINT64_MAX};
149 if (address->ss_family == AF_INET) {
150 memcpy(clientAddressBytes, &((struct sockaddr_in *)address)->sin_addr, 4);
152 memcpy(clientAddressBytes, &((struct sockaddr_in6 *)address)->sin6_addr, 16);
155 list_iterate(itr, &banlist) {
156 ban = list_get_entry(itr, ban_t, node);
158 if(address->ss_len == ban->address.ss_family) {
159 if (ban->address.ss_family == AF_INET) {
160 memcpy(banAddressBytes, &((struct sockaddr_in *)&ban->address)->sin_addr, 4);
162 memcpy(banAddressBytes, &((struct sockaddr_in6 *)&ban->address)->sin6_addr, 16);
165 banMaskBits[0] <<= (ban->mask >= 64) ? 0 : 64 - ban->mask;
166 banMaskBits[1] <<= (ban->mask > 64) ? 128 - ban->mask : 64;
168 clientAddressBytes[0] &= banMaskBits[0];
169 clientAddressBytes[1] &= banMaskBits[1];
171 banAddressBytes[0] &= banMaskBits[0];
172 banAddressBytes[1] &= banMaskBits[1];
174 if (memcmp(clientAddressBytes, banAddressBytes, 16) == 0) {
185 int Ban_getBanCount(void)
190 message_t *Ban_getBanList(void)
201 msg = Msg_banList_create(bancount);
202 list_iterate(itr, &banlist) {
203 ban = list_get_entry(itr, ban_t, node);
204 gmtime_r(&ban->time, ×pec);
205 strftime(timestr, 32, "%Y-%m-%dT%H:%M:%S", ×pec);
206 SSLi_hash2hex(ban->hash, hexhash);
207 memset(address, 0, 16);
209 if(ban->address.ss_family == AF_INET) {
210 memcpy(&address[12], &((struct sockaddr_in *)&ban->address)->sin_addr, 4);
211 memset(&address[10], 0xff, 2);
212 Msg_banList_addEntry(msg, i++, address, ban->mask + 96, ban->name, hexhash, ban->reason, timestr, ban->duration);
214 memcpy(&address, &((struct sockaddr_in6 *)&ban->address)->sin6_addr, 16);
215 Msg_banList_addEntry(msg, i++, address, ban->mask, ban->name, hexhash, ban->reason, timestr, ban->duration);
222 void Ban_clearBanList(void)
225 struct dlist *itr, *save;
226 list_iterate_safe(itr, save, &banlist) {
227 ban = list_get_entry(itr, ban_t, node);
230 list_del(&ban->node);
236 void Ban_putBanList(message_t *msg, int n_bans)
241 char *hexhash, *name, *reason, *start;
242 uint32_t duration, mask;
244 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);
267 strptime(start, "%Y-%m-%dT%H:%M:%S", ×pec);
268 ban->time = mktime(×pec);
269 ban->startTime = ban->time * 1000000LL;
270 ban->duration = duration;
271 list_add_tail(&ban->node, &banlist);
274 banlist_changed = true;
275 if(getBoolConf(SYNC_BANFILE))
279 static void Ban_saveBanFile(void)
286 if (!banlist_changed)
288 file = fopen(getStrConf(BANFILE), "w");
290 Log_warn("Could not save banlist to file %s: %s", getStrConf(BANFILE), strerror(errno));
293 list_iterate(itr, &banlist) {
294 ban = list_get_entry(itr, ban_t, node);
295 SSLi_hash2hex(ban->hash, hexhash);
297 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);
300 banlist_changed = false;
301 Log_info("Banlist file '%s': %d entries written", getStrConf(BANFILE), bancount);
304 static void Ban_readBanFile(void)
307 char line[1024], *hexhash, *address, *name, *reason;
308 uint32_t mask, duration;
313 file = fopen(getStrConf(BANFILE), "r");
315 Log_warn("Could not read banlist file %s: %s", getStrConf(BANFILE), strerror(errno));
318 while (fgets(line, 1024, file) != NULL) {
319 p = strtok(line, ",");
321 p = strtok(NULL, ",");
322 if (p == NULL) break;
324 p = strtok(NULL, ",");
325 if (p == NULL) break;
326 mask = strtoul(p, NULL, 0);
327 p = strtok(NULL, ",");
328 if (p == NULL) break;
329 time = strtoul(p, NULL, 0);
330 p = strtok(NULL, ",");
331 if (p == NULL) break;
332 duration = strtoul(p, NULL, 0);
333 p = strtok(NULL, ",");
334 if (p == NULL) break;
336 p = strtok(NULL, "\n");
337 if (p == NULL) break;
340 ban = malloc(sizeof(ban_t));
342 Log_fatal("Out of memory");
343 memset(ban, 0, sizeof(ban_t));
344 SSLi_hex2hash(hexhash, ban->hash);
345 if (inet_pton(AF_INET, address, &ban->address) == 0) {
346 if (inet_pton(AF_INET6, address, &ban->address) == 0) {
347 Log_warn("Address \"%s\" is illegal!", address);
349 ban->address.ss_family = AF_INET6;
352 ban->address.ss_family = AF_INET;
354 ban->name = strdup(name);
355 ban->reason = strdup(reason);
356 if (ban->name == NULL || ban->reason == NULL)
357 Log_fatal("Out of memory");
359 ban->duration = duration;
361 ban->startTime = ban->time * 1000000LL;
362 list_add_tail(&ban->node, &banlist);
364 Log_debug("Banfile: H = '%s' A = '%s' M = %d U = '%s' R = '%s'", hexhash, address, ban->mask, ban->name, ban->reason);
367 Log_info("Banlist file '%s': %d entries read", getStrConf(BANFILE), bancount);